[
  {
    "path": ".codecov.yml",
    "content": "ignore:\n  - \"cmd\"  # ignore cmd folders and all its contents"
  },
  {
    "path": ".gitattributes",
    "content": "*.js linguist-language=GO\n*.css linguist-language=GO\n*.html linguist-language=GO"
  },
  {
    "path": ".gitee/ISSUE_TEMPLATE",
    "content": "<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！ -->\n<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！ -->\n<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！ -->\n<!-- 重要的事情说三遍！ -->\n\n### 1. 您当前使用的`Go`版本，及系统版本、系统架构？\n\n<!-- 使用 `go version` 命令查看，期望的结果如：`go 1.12, linux/amd64` -->\n\n\n### 2. 您当前使用的`GoFrame`框架版本？\n\n<!-- 框架版本可以查看自己项目下的 `go.mod`，或者框架文件 `version.go` -->\n\n\n### 3. 更新到最新的框架版本是否能够解决问题？\n\n<!-- 务必检查是否相同问题已在新版本中已修复 -->\n\n\n### 4. 问题描述？\n\n<!--\n请您尽可能地提供一份最短的，可复现问题的代码。\n代码尽可能地完整，最好是可以直接编译运行。\n-->\n\n\n\n### 5. 您期望得到的结果？\n\n\n\n### 6. 您实际得到的结果？\n\n\n\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [gogf] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # custom\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/00-bug.yml",
    "content": "# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms\n# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Bugs\ndescription: GoFrame command, module, or anything else\ntitle: \"os/gtime: issue title\"\nlabels:\n  - bug\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.\n        \n        The issue title uses the format of the package name goes before the colon. Thanks!\n        \n        标题使用包名在冒号前的格式！谢谢！ \n\n  - type: input\n    id: go-version\n    attributes:\n      label: Go version\n      description: |\n        What version of Go are you using (`go version`)?\n      placeholder: ex. go version go1.20.7 darwin/arm64\n    validations:\n      required: true\n\n  - type: input\n    id: gf-version\n    attributes:\n      label: GoFrame version\n      description: |\n        What version of GoFrame are you using (`gf version`)?\n      placeholder: ex. 2.7.0\n    validations:\n      required: true\n\n  - type: dropdown\n    id: is-reproducible\n    attributes:\n      label: Can this bug be reproduced with the latest release?\n      options:\n        - Option Yes\n        - Option No\n    validations:\n      required: true\n\n  - type: textarea\n    id: what-did-you-do\n    attributes:\n      label: \"What did you do?\"\n      description: \"If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is best.\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: actual-behavior\n    attributes:\n      label: \"What did you see happen?\"\n      description: Command invocations and their associated output, functions with their arguments and return results, full stacktraces for panics (upload a file if it is very long), etc. Prefer copying text output over using screenshots.\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: \"What did you expect to see?\"\n      description: Why is the current output incorrect, and any additional context we may need to understand the issue.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-enhance.yml",
    "content": "# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms\n# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Enhancements\ndescription: Enhance an idea for this project\ntitle: \"os/gtime: issue title\"\nlabels:\n  - enhancement\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.\n        \n        The issue title uses the format of the package name goes before the colon. Thanks!\n        \n        标题使用包名在冒号前的格式！谢谢！ \n\n  - type: textarea\n    id: description\n    attributes:\n      label: \"Description\"\n      description: \"Please describe your idea in detail.\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: \"Additional\"\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-feature.yml",
    "content": "# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms\n# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Features\ndescription: Suggest an idea for this project\ntitle: \"os/gtime: issue title\"\nlabels:\n  - feature\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.\n        \n        The issue title uses the format of the package name goes before the colon. Thanks!\n        \n        标题使用包名在冒号前的格式！谢谢！ \n\n  - type: dropdown\n    id: is-problem\n    attributes:\n      label: Is your feature request related to a problem?\n      options:\n        - Option Yes\n        - Option No\n    validations:\n      required: true\n\n  - type: textarea\n    id: description-solution\n    attributes:\n      label: \"Describe the solution you'd like\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: description-considered\n    attributes:\n      label: \"Describe alternatives you've considered\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: \"Additional\"\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/03-question.yml",
    "content": "# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms\n# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Questions\ndescription: I want to ask a question\ntitle: \"os/gtime: issue title\"\nlabels:\n  - question\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please read the document carefully. 请先仔细阅读文档\n  \n        The issue title uses the format of the package name goes before the colon. Thanks!\n\n        标题使用包名在冒号前的格式！谢谢！ \n\n  - type: textarea\n    id: ask\n    attributes:\n      label: \"What do you want to ask?\"\n      description: \"Please describe the details of your questions. 请详细描述你的问题。\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.MD",
    "content": "**Please ensure you adhere to every item in this list.**\n+ The PR title is formatted as follows: `<type>[optional scope]: <description>` For example, `fix(os/gtime): fix time zone issue`\n  + `<type>` is mandatory and can be one of `fix`, `feat`, `build`, `ci`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`\n    + `fix`: Used when a bug has been fixed.\n    + `feat`: Used when a new feature has been added.\n    + `build`: Used for modifications to the project build system, such as changes to dependencies, external interfaces, or upgrading Node version.\n    + `ci`: Used for modifications to continuous integration processes, such as changes to Travis, Jenkins workflow configurations.\n    + `docs`: Used for modifications to documentation, such as changes to README files, API documentation, etc.\n    + `style`: Used for changes to code style, such as adjustments to indentation, spaces, blank lines, etc.\n    + `refactor`: Used for code refactoring, such as changes to code structure, variable names, function names, without altering functionality.\n    + `perf`: Used for performance optimization, such as improving code performance, reducing memory usage, etc.\n    + `test`: Used for modifications to test cases, such as adding, deleting, or modifying test cases for code.\n    + `chore`: Used for modifications to non-business-related code, such as changes to build processes or tool configurations.\n  + After `<type>`, specify the affected package name or scope in parentheses, for example, `(os/gtime)`.\n  + The part after the colon uses the verb tense + phrase that completes the blank in\n  + Lowercase verb after the colon\n  + No trailing period\n  + Keep the title as short as possible. ideally under 76 characters or shorter\n  + [Reference Documentation](https://www.conventionalcommits.org/en/v1.0.0/)\n+ If there is a corresponding issue, add either `Fixes #1234` or `Updates #1234`\n  (the latter if this is not a complete fix) to this comment\n+ Delete these instructions once you have read and applied them\n\n**提交前请遵守每个事项，感谢！**\n+ PR 标题格式如下：`<类型>[可选 范围]: <描述>` 例如 `fix(os/gtime): fix time zone issue`\n  + `<类型>`是必须的，可以是 `fix`、`feat`、`build`、`ci`、`docs`、`style`、`refactor`、`perf`、`test`、`chore` 中的一个\n    + fix: 用于修复了一个 bug\n    + feat: 用于新增了一个功能\n    + build: 用于修改项目构建系统，例如修改依赖库、外部接口或者升级 Node 版本等\n    + ci: 用于修改持续集成流程，例如修改 Travis、Jenkins 等工作流配置\n    + docs: 用于修改文档，例如修改 README 文件、API 文档等\n    + style: 用于修改代码的样式，例如调整缩进、空格、空行等\n    + refactor: 用于重构代码，例如修改代码结构、变量名、函数名等但不修改功能逻辑\n    + perf: 用于优化性能，例如提升代码的性能、减少内存占用等\n    + test: 用于修改测试用例，例如添加、删除、修改代码的测试用例等\n    + chore: 用于对非业务性代码进行修改，例如修改构建流程或者工具配置等\n  + `<类型>`后在括号中填写受影响的包名或范围，例如 `(os/gtime)`\n  + 冒号后使用动词时态 + 短语\n  + 冒号后的动词小写\n  + 不要有结尾句号\n  + 标题尽量保持简短，最好在 76 个字符或更短\n  + [参考文档](https://www.conventionalcommits.org/zh-hans/v1.0.0/)\n+ 如果有对应的 issue，请在此评论中添加 `Fixes #1234`，如果不是完全修复则添加 `Updates #1234`\n+ 应用这些规则后删除所有的说明\n"
  },
  {
    "path": ".github/workflows/apollo/docker-compose.yml",
    "content": "version: '2'\n\nservices:\n  apollo-quick-start:\n    image: \"loads/apollo-quick-start:latest\"\n    container_name: apollo-quick-start\n    depends_on:\n      - apollo-db\n    ports:\n      - \"8080:8080\"\n      - \"8070:8070\"\n      - \"8060:8060\"\n    links:\n      - apollo-db\n    #environment:\n      #JAVA_OPTS: '-Xms100m -Xmx1000m -Xmn100m -Xss256k -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=250m'\n      #APOLLO_CONFIG_DB_USERNAME: 'root'\n      #APOLLO_CONFIG_DB_PASSWORD: 'apollo'\n      #APOLLO_PORTAL_DB_USERNAME: 'root'\n      #APOLLO_PORTAL_DB_PASSWORD: 'apollo'\n\n  apollo-db:\n    image: \"mysql:5.7\"\n    container_name: apollo-db\n    environment:\n      TZ: Asia/Shanghai\n      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'\n      #MYSQL_ROOT_PASSWORD: 'apollo'\n    depends_on:\n      - apollo-dbdata\n    ports:\n      - \"13306:3306\"\n    volumes:\n      - ./sql:/docker-entrypoint-initdb.d\n    volumes_from:\n      - apollo-dbdata\n\n  apollo-dbdata:\n    image: \"alpine:3.8\"\n    container_name: apollo-dbdata\n    volumes:\n      - /var/lib/mysql\n"
  },
  {
    "path": ".github/workflows/apollo/sql/apolloconfigdb.sql",
    "content": "--\n-- Copyright 2022 Apollo Authors\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n-- http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n/*!40101 SET NAMES utf8 */;\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n# Create Database\n# ------------------------------------------------------------\nCREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;\n\nUse ApolloConfigDB;\n\n# Dump of table app\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `App`;\n\nCREATE TABLE `App` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',\n  `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',\n  `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',\n  `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',\n  `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_Name` (`Name`(191))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';\n\n\n\n# Dump of table appnamespace\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `AppNamespace`;\n\nCREATE TABLE `AppNamespace` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字，注意，需要全局唯一',\n  `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id',\n  `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',\n  `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',\n  `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),\n  KEY `Name_AppId` (`Name`,`AppId`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';\n\n\n\n# Dump of table audit\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Audit`;\n\nCREATE TABLE `Audit` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',\n  `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',\n  `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',\n  `Comment` varchar(500) DEFAULT NULL COMMENT '备注',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';\n\n\n\n# Dump of table cluster\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Cluster`;\n\nCREATE TABLE `Cluster` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',\n  `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id',\n  `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),\n  KEY `IX_ParentClusterId` (`ParentClusterId`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';\n\n\n\n# Dump of table commit\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Commit`;\n\nCREATE TABLE `Commit` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `ChangeSets` longtext NOT NULL COMMENT '修改变更集',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',\n  `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',\n  `Comment` varchar(500) DEFAULT NULL COMMENT '备注',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `AppId` (`AppId`(191)),\n  KEY `ClusterName` (`ClusterName`(191)),\n  KEY `NamespaceName` (`NamespaceName`(191))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';\n\n# Dump of table grayreleaserule\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `GrayReleaseRule`;\n\nCREATE TABLE `GrayReleaseRule` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',\n  `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',\n  `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',\n  `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',\n  `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',\n  `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2：全量发布',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';\n\n\n# Dump of table instance\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Instance`;\n\nCREATE TABLE `Instance` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',\n  `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',\n  `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),\n  KEY `IX_IP` (`Ip`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';\n\n\n\n# Dump of table instanceconfig\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `InstanceConfig`;\n\nCREATE TABLE `InstanceConfig` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',\n  `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',\n  `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',\n  `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',\n  `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',\n  `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),\n  KEY `IX_ReleaseKey` (`ReleaseKey`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';\n\n\n\n# Dump of table item\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Item`;\n\nCREATE TABLE `Item` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',\n  `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',\n  `Value` longtext NOT NULL COMMENT '配置项值',\n  `Comment` varchar(1024) DEFAULT '' COMMENT '注释',\n  `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `IX_GroupId` (`NamespaceId`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';\n\n\n\n# Dump of table namespace\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Namespace`;\n\nCREATE TABLE `Namespace` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',\n  `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191),`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_NamespaceName` (`NamespaceName`(191))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';\n\n\n\n# Dump of table namespacelock\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `NamespaceLock`;\n\nCREATE TABLE `NamespaceLock` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',\n  `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';\n\n\n\n# Dump of table release\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Release`;\n\nCREATE TABLE `Release` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',\n  `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',\n  `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',\n  `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',\n  `Configurations` longtext NOT NULL COMMENT '发布配置',\n  `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`),\n  KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';\n\n\n# Dump of table releasehistory\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ReleaseHistory`;\n\nCREATE TABLE `ReleaseHistory` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',\n  `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',\n  `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',\n  `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',\n  `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',\n  `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型，0: 普通发布，1: 回滚，2: 灰度发布，3: 灰度规则更新，4: 灰度合并回主分支发布，5: 主分支发布灰度自动发布，6: 主分支回滚灰度自动发布，7: 放弃灰度',\n  `OperationContext` longtext NOT NULL COMMENT '发布上下文信息',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),\n  KEY `IX_ReleaseId` (`ReleaseId`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';\n\n\n# Dump of table releasemessage\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ReleaseMessage`;\n\nCREATE TABLE `ReleaseMessage` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',\n  `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_Message` (`Message`(191))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';\n\n\n\n# Dump of table serverconfig\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ServerConfig`;\n\nCREATE TABLE `ServerConfig` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',\n  `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群，default为不针对特定的集群',\n  `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',\n  `Comment` varchar(1024) DEFAULT '' COMMENT '注释',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';\n\n# Dump of table accesskey\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `AccessKey`;\n\nCREATE TABLE `AccessKey` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret',\n  `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥';\n\n# Config\n# ------------------------------------------------------------\nINSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)\nVALUES\n    ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url，多个service以英文逗号分隔'),\n    ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),\n    ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),\n    ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存，开启后能提高性能，但是会增大内存消耗！'),\n    ('item.key.length.limit', 'default', '128', 'item key 最大长度限制');\n\n# Sample Data\n# ------------------------------------------------------------\nINSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`)\nVALUES\n  ('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com');\n\nINSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`)\nVALUES\n  ('application', 'SampleApp', 'properties', 0, 'default app namespace');\n\nINSERT INTO `Cluster` (`Name`, `AppId`)\nVALUES\n  ('default', 'SampleApp');\n\nINSERT INTO `Namespace` (`Id`, `AppId`, `ClusterName`, `NamespaceName`)\nVALUES\n  (1, 'SampleApp', 'default', 'application');\n\n\nINSERT INTO `Item` VALUES (1,1,'timeout','100','sample timeout配置',1,_binary '\\0',0,'default','2022-09-28 15:43:17','','2022-09-28 15:43:17'),\n                          (2,1,'','','',2,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (3,1,'server.address',':8000','',3,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (4,1,'server.dumpRouterMap','true','',4,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (5,1,'server.routeOverWrite','true','',5,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (6,1,'server.accessLogEnabled','true','',6,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (7,1,'server.openapiPath','/api.json','',7,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (8,1,'server.swaggerPath','/swagger','',8,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (9,1,'','','',9,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (10,1,'','','# Global logging.',10,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (11,1,'logger.level','all','',11,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),\n                          (12,1,'logger.stdout','true','',12,_binary '\\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55');\n\nINSERT INTO `Release` VALUES (1,'20161009155425-d3a0749c6e20bc15','20161009155424-release','Sample发布','SampleApp','default','application','{\\\"timeout\\\":\\\"100\\\"}',_binary '\\0',_binary '\\0',0,'default','2022-09-28 15:59:38','','2022-09-28 15:59:38'),\n                             (2,'20220929000151-1dc5634459e19171','20220929000148-release','','SampleApp','default','application','{\\\"timeout\\\":\\\"100\\\",\\\"server.address\\\":\\\":8000\\\",\\\"server.dumpRouterMap\\\":\\\"true\\\",\\\"server.routeOverWrite\\\":\\\"true\\\",\\\"server.accessLogEnabled\\\":\\\"true\\\",\\\"server.openapiPath\\\":\\\"/api.json\\\",\\\"server.swaggerPath\\\":\\\"/swagger\\\",\\\"logger.level\\\":\\\"all\\\",\\\"logger.stdout\\\":\\\"true\\\"}',_binary '\\0',_binary '\\0',0,'apollo','2022-09-28 16:01:51','apollo','2022-09-28 16:01:51');\n\nINSERT INTO `ReleaseHistory` VALUES (1,'SampleApp','default','application','default',1,0,0,'{}',_binary '\\0',0,'apollo','2022-09-28 15:59:38','apollo','2022-09-28 15:59:38'),\n                                    (2,'SampleApp','default','application','default',2,1,0,'{\\\"isEmergencyPublish\\\":false}',_binary '\\0',0,'apollo','2022-09-28 16:01:51','apollo','2022-09-28 16:01:51');\n\nINSERT INTO `ReleaseMessage` VALUES (1,'SampleApp+default+application','2022-09-28 15:59:38'),\n                                    (2,'SampleApp+default+application','2022-09-28 16:01:51');\n\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"
  },
  {
    "path": ".github/workflows/apollo/sql/apolloportaldb.sql",
    "content": "--\n-- Copyright 2022 Apollo Authors\n--\n-- Licensed under the Apache License, Version 2.0 (the \"License\");\n-- you may not use this file except in compliance with the License.\n-- You may obtain a copy of the License at\n--\n-- http://www.apache.org/licenses/LICENSE-2.0\n--\n-- Unless required by applicable law or agreed to in writing, software\n-- distributed under the License is distributed on an \"AS IS\" BASIS,\n-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-- See the License for the specific language governing permissions and\n-- limitations under the License.\n--\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n/*!40101 SET NAMES utf8 */;\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n# Create Database\n# ------------------------------------------------------------\nCREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4;\n\nUse ApolloPortalDB;\n\n# Dump of table app\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `App`;\n\nCREATE TABLE `App` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',\n  `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',\n  `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',\n  `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',\n  `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_Name` (`Name`(191))\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';\n\n\n\n# Dump of table appnamespace\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `AppNamespace`;\n\nCREATE TABLE `AppNamespace` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字，注意，需要全局唯一',\n  `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id',\n  `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',\n  `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',\n  `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),\n  KEY `Name_AppId` (`Name`,`AppId`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';\n\n\n\n# Dump of table consumer\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Consumer`;\n\nCREATE TABLE `Consumer` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',\n  `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',\n  `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',\n  `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',\n  `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者';\n\n\n\n# Dump of table consumeraudit\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ConsumerAudit`;\n\nCREATE TABLE `ConsumerAudit` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',\n  `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri',\n  `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_ConsumerId` (`ConsumerId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表';\n\n\n\n# Dump of table consumerrole\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ConsumerRole`;\n\nCREATE TABLE `ConsumerRole` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',\n  `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_RoleId` (`RoleId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表';\n\n\n\n# Dump of table consumertoken\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ConsumerToken`;\n\nCREATE TABLE `ConsumerToken` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId',\n  `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token',\n  `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表';\n\n# Dump of table favorite\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Favorite`;\n\nCREATE TABLE `Favorite` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户',\n  `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',\n  `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`),\n  KEY `AppId` (`AppId`(191)),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表';\n\n# Dump of table permission\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Permission`;\n\nCREATE TABLE `Permission` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型',\n  `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表';\n\n\n\n# Dump of table role\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Role`;\n\nCREATE TABLE `Role` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';\n\n\n\n# Dump of table rolepermission\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `RolePermission`;\n\nCREATE TABLE `RolePermission` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',\n  `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_PermissionId` (`PermissionId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表';\n\n\n\n# Dump of table serverconfig\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `ServerConfig`;\n\nCREATE TABLE `ServerConfig` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',\n  `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',\n  `Comment` varchar(1024) DEFAULT '' COMMENT '注释',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`),\n  KEY `DataChange_LastTime` (`DataChange_LastTime`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';\n\n\n\n# Dump of table userrole\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `UserRole`;\n\nCREATE TABLE `UserRole` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识',\n  `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',\n  `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',\n  `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',\n  `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',\n  `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',\n  `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`),\n  KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),\n  KEY `IX_RoleId` (`RoleId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表';\n\n# Dump of table Users\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Users`;\n\nCREATE TABLE `Users` (\n  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户',\n  `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码',\n  `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称',\n  `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址',\n  `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效',\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `UK_Username` (`Username`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';\n\n\n# Dump of table Authorities\n# ------------------------------------------------------------\n\nDROP TABLE IF EXISTS `Authorities`;\n\nCREATE TABLE `Authorities` (\n  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',\n  `Username` varchar(64) NOT NULL,\n  `Authority` varchar(50) NOT NULL,\n  PRIMARY KEY (`Id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\n\n# Config\n# ------------------------------------------------------------\nINSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`)\nVALUES\n    ('apollo.portal.envs', 'dev', '可支持的环境列表'),\n    ('organizations', '[{\\\"orgId\\\":\\\"TEST1\\\",\\\"orgName\\\":\\\"样例部门1\\\"},{\\\"orgId\\\":\\\"TEST2\\\",\\\"orgName\\\":\\\"样例部门2\\\"}]', '部门列表'),\n    ('superAdmin', 'apollo', 'Portal超级管理员'),\n    ('api.readTimeout', '10000', 'http接口read timeout'),\n    ('consumer.token.salt', 'someSalt', 'consumer token salt'),\n    ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'),\n    ('configView.memberOnly.envs', 'dev', '只对项目成员显示配置信息的环境列表，多个env以英文逗号分隔'),\n    ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表');\n\nINSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`)\nVALUES\n    ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1);\n\nINSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user');\n\n# Sample Data\n# ------------------------------------------------------------\nINSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`)\nVALUES\n  ('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com');\n\nINSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`)\nVALUES\n  ('application', 'SampleApp', 'properties', 0, 'default app namespace');\n\nINSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`)\nVALUES\n  (1, 'CreateCluster', 'SampleApp'),\n  (2, 'CreateNamespace', 'SampleApp'),\n  (3, 'AssignRole', 'SampleApp'),\n  (4, 'ModifyNamespace', 'SampleApp+application'),\n  (5, 'ReleaseNamespace', 'SampleApp+application');\n\nINSERT INTO `Role` (`Id`, `RoleName`)\nVALUES\n  (1, 'Master+SampleApp'),\n  (2, 'ModifyNamespace+SampleApp+application'),\n  (3, 'ReleaseNamespace+SampleApp+application');\n\nINSERT INTO `RolePermission` (`RoleId`, `PermissionId`)\nVALUES\n  (1, 1),\n  (1, 2),\n  (1, 3),\n  (2, 4),\n  (3, 5);\n\nINSERT INTO `UserRole` (`UserId`, `RoleId`)\nVALUES\n  ('apollo', 1),\n  ('apollo', 2),\n  ('apollo', 3);\n\n-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql)\nCREATE TABLE SPRING_SESSION (\n  PRIMARY_ID CHAR(36) NOT NULL,\n  SESSION_ID CHAR(36) NOT NULL,\n  CREATION_TIME BIGINT NOT NULL,\n  LAST_ACCESS_TIME BIGINT NOT NULL,\n  MAX_INACTIVE_INTERVAL INT NOT NULL,\n  EXPIRY_TIME BIGINT NOT NULL,\n  PRINCIPAL_NAME VARCHAR(100),\n  CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)\n) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;\n\nCREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);\nCREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);\nCREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);\n\nCREATE TABLE SPRING_SESSION_ATTRIBUTES (\n  SESSION_PRIMARY_ID CHAR(36) NOT NULL,\n  ATTRIBUTE_NAME VARCHAR(200) NOT NULL,\n  ATTRIBUTE_BYTES BLOB NOT NULL,\n  CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),\n  CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE\n) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;\n\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"
  },
  {
    "path": ".github/workflows/ci-main.yml",
    "content": "# The main codes build and unit testing running workflow.\nname: GoFrame Main CI\n\n\non:\n  push:\n    branches:\n    - master\n    - develop\n    - personal/**\n    - feature/**\n    - enhance/**\n    - fix/**\n\n  pull_request:\n    branches:\n    - master\n    - develop\n    - personal/**\n    - feature/**\n    - enhance/**\n    - fix/**\n  workflow_dispatch:\n    inputs:\n      debug:\n        type: boolean\n        description: 'Enable tmate Debug'\n        required: false\n        default: false\n\n# This allows a subsequently queued workflow run to interrupt previous runs\nconcurrency:\n  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'\n  cancel-in-progress: true\n\nenv:\n  TZ: \"Asia/Shanghai\"\n  # for unit testing cases of some components that only execute on the latest go version.\n  LATEST_GO_VERSION: \"1.25\"\n\njobs:\n  code-test:\n    strategy:\n      matrix:\n        # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n        # When adding new go version to the list, make sure:\n        # 1. Update the `LATEST_GO_VERSION` env variable.\n        # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n        go-version: [ \"1.23\", \"1.24\", \"1.25\" ]\n        goarch: [ \"386\", \"amd64\" ]\n\n    runs-on: ubuntu-latest\n\n    # Service containers to run with `code-test`\n    services:\n      # Etcd service.\n      # docker run -p 2379:2379 -e ALLOW_NONE_AUTHENTICATION=yes bitnamilegacy/etcd:3.4.24\n      etcd:\n        image: bitnamilegacy/etcd:3.4.24\n        env:\n          ALLOW_NONE_AUTHENTICATION: yes\n        ports:\n          - 2379:2379\n\n      # Redis backend server.\n      redis:\n        image  : redis:7.0\n        options: >-\n          --health-cmd      \"redis-cli ping\"\n          --health-interval 10s\n          --health-timeout  5s\n          --health-retries  5\n        ports:\n          # Maps tcp port 6379 on service container to the host\n          - 6379:6379\n\n      # MySQL backend server.\n      # docker run \\\n      # -p 3306:3306 \\\n      # -e MYSQL_DATABASE=test \\\n      # -e MYSQL_ROOT_PASSWORD=12345678 \\\n      # mysql:5.7\n      mysql:\n        image: mysql:5.7\n        env:\n          MYSQL_DATABASE     : test\n          MYSQL_ROOT_PASSWORD: 12345678\n        ports:\n          - 3306:3306\n\n      # MariaDb backend server.\n      # docker run \\\n      # -p 3307:3306 \\\n      # -e MYSQL_DATABASE=test \\\n      # -e MYSQL_ROOT_PASSWORD=12345678 \\\n      # mariadb:11.4\n      mariadb:\n        image: mariadb:11.4\n        env:\n          MARIADB_DATABASE: test\n          MARIADB_ROOT_PASSWORD: 12345678\n        ports:\n          - 3307:3306\n\n      # PostgreSQL backend server.\n      # docker run \\\n      # -p 5432:5432 \\\n      # -e POSTGRES_PASSWORD=12345678 \\\n      # -e POSTGRES_USER=postgres \\\n      # -e POSTGRES_DB=test \\\n      # -v postgres:/Users/john/Temp/postgresql/data \\\n      # postgres:17-alpine\n      postgres:\n        image: postgres:17-alpine\n        env:\n          POSTGRES_PASSWORD: 12345678\n          POSTGRES_USER:     postgres\n          POSTGRES_DB:       test\n          TZ:                Asia/Shanghai\n        ports:\n          - 5432:5432\n        # Set health checks to wait until postgres has started\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n\n      # MSSQL backend server.\n      # docker run \\\n      # -p 1433:1433 \\\n      # -e ACCEPT_EULA=Y \\\n      # -e SA_PASSWORD=LoremIpsum86 \\\n      # -e MSSQL_USER=root \\\n      # -e MSSQL_PASSWORD=LoremIpsum86 \\\n      # mcr.microsoft.com/mssql/server:2022-latest\n      mssql:\n        image: mcr.microsoft.com/mssql/server:2022-latest\n        env:\n          TZ: Asia/Shanghai\n          ACCEPT_EULA: Y\n          MSSQL_SA_PASSWORD: LoremIpsum86\n        ports:\n          - 1433:1433\n        options: >-\n          --health-cmd=\"/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P ${MSSQL_SA_PASSWORD} -N -C -l 30 -Q \\\"SELECT 1\\\" || exit 1\"\n          --health-start-period 10s\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 10\n\n      # ClickHouse backend server.\n      # docker run \\\n      # -p 9000:9000 -p 8123:8123 -p 9001:9001 \\\n      # clickhouse/clickhouse-server:24.11.1.2557-alpine\n      clickhouse-server:\n        image: clickhouse/clickhouse-server:24.11.1.2557-alpine\n        ports:\n          - 9000:9000\n          - 8123:8123\n          - 9001:9001\n\n      # Polaris backend server.\n      # docker run \\\n      # -p 8090:8090 -p 8091:8091 -p 8093:8093 -p 9090:9090 -p 9091:9091 \\\n      # polarismesh/polaris-standalone:v1.17.2\n      polaris:\n        image: polarismesh/polaris-standalone:v1.17.2\n        ports:\n          - 8090:8090\n          - 8091:8091\n          - 8093:8093\n          - 9090:9090\n          - 9091:9091\n\n      # Oracle 11g server.\n      # docker run \\\n      # -e ORACLE_ALLOW_REMOTE=true \\\n      # -e ORACLE_SID=XE \\\n      # -e ORACLE_DB_USER_NAME=system \\\n      # -e ORACLE_DB_PASSWORD=oracle \\\n      # -p 1521:1521 \\\n      # loads/oracle-xe-11g-r2:11.2.0\n      oracle-server:\n        image: loads/oracle-xe-11g-r2:11.2.0\n        env:\n          ORACLE_ALLOW_REMOTE: true\n          ORACLE_SID: XE\n          ORACLE_DB_USER_NAME: system\n          ORACLE_DB_PASSWORD: oracle\n        ports:\n          - 1521:1521\n\n      # dm8 server\n      # docker run -p 5236:5236 loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4\n      dm-server:\n        image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4\n        ports:\n          - 5236:5236\n\n      # openGauss server\n      # docker run --privileged=true -e GS_PASSWORD=UTpass@1234 -p 9950:5432 opengauss/opengauss:7.0.0-RC1.B023\n      gaussdb:\n        image: opengauss/opengauss:7.0.0-RC1.B023\n        env:\n          GS_PASSWORD: UTpass@1234\n          TZ: Asia/Shanghai\n        ports:\n          - 9950:5432\n\n\n      zookeeper:\n        image: zookeeper:3.8\n        ports:\n          - 2181:2181\n\n    steps:\n    # TODO: szenius/set-timezone update to node16\n    # sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime\n    - name: Setup Timezone\n      uses: szenius/set-timezone@v2.0\n      with:\n        timezoneLinux: \"Asia/Shanghai\"\n\n    - name: Checkout Repository\n      uses: actions/checkout@v5\n\n    - name: Setup tmate Session\n      uses: mxschmitt/action-tmate@v3\n      if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug }}\n      with:\n        detached: true\n        limit-access-to-actor: false\n\n    - name: Free Disk Space\n      run: |\n        df -h /\n        sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/hostedtoolcache/CodeQL /opt/hostedtoolcache/Python || true\n        df -h /\n\n    - name: Start Apollo Containers\n      run:  docker compose -f \".github/workflows/apollo/docker-compose.yml\" up -d --build\n      \n    - name: Start Nacos Containers\n      run:  docker compose -f \".github/workflows/nacos/docker-compose.yml\" up -d --build\n\n    - name: Start Redis Cluster Containers\n      run:  docker compose -f \".github/workflows/redis/docker-compose.yml\" up -d --build\n\n    - name: Start Consul Containers\n      run:  docker compose -f \".github/workflows/consul/docker-compose.yml\" up -d --build\n\n    - name: Setup Golang ${{ matrix.go-version }}\n      uses: actions/setup-go@v5\n      with:\n        go-version: ${{ matrix.go-version }}\n        cache-dependency-path: '**/go.sum'\n\n    - name: Install Protoc\n      uses: arduino/setup-protoc@v3\n      with:\n        version: \"31.x\"\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Install the protocol compiler plugins for Go\n      run: |\n        go install google.golang.org/protobuf/cmd/protoc-gen-go@latest\n        go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest\n        export PATH=\"$PATH:$(go env GOPATH)/bin\"\n\n    - name: Before Script\n      run:  bash .github/workflows/scripts/before_script.sh\n\n    - name: Build & Test\n      if: ${{ (github.event_name == 'push' && github.ref != 'refs/heads/master') || github.event_name == 'pull_request' }}\n      run: bash .github/workflows/scripts/ci-main.sh\n\n    - name: Build & Test & Coverage\n      if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}\n      run: bash .github/workflows/scripts/ci-main.sh coverage\n\n    - name: Stop Redis Cluster Containers\n      run:  docker compose -f \".github/workflows/redis/docker-compose.yml\" down\n\n    - name: Stop Apollo Containers\n      run:  docker compose -f \".github/workflows/apollo/docker-compose.yml\" down\n\n    - name: Stop Nacos Containers\n      run:  docker compose -f \".github/workflows/nacos/docker-compose.yml\" down\n\n    - name: Stop Consul Containers\n      run:  docker compose -f \".github/workflows/consul/docker-compose.yml\" down\n\n    - name: Report Coverage\n      uses: codecov/codecov-action@v4\n      # Only report coverage on the latest go version\n      if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == env.LATEST_GO_VERSION }}\n      with:\n        flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}\n        token: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/ci-sub.yml",
    "content": "# The sub codes build and unit testing running workflow.\n# It maintains the ci of unimportant packages.\nname: GoFrame Sub CI\n\n\non:\n  push:\n    branches:\n    - master\n    - develop\n    - personal/**\n    - feature/**\n    - enhance/**\n    - fix/**\n\n  pull_request:\n    branches:\n    - master\n    - develop\n    - personal/**\n    - feature/**\n    - enhance/**\n    - fix/**\n\n# This allows a subsequently queued workflow run to interrupt previous runs\nconcurrency:\n  group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'\n  cancel-in-progress: true\n\nenv:\n  TZ: \"Asia/Shanghai\"\n  # for unit testing cases of some components that only execute on the latest go version.\n  LATEST_GO_VERSION: \"1.25\"\n\njobs:\n  code-test:\n    strategy:\n      matrix:\n        # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n        # When adding new go version to the list, make sure:\n        # 1. Update the `LATEST_GO_VERSION` env variable.\n        # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥\n        go-version: [ \"1.23\", \"1.24\", \"1.25\" ]\n        goarch: [ \"386\", \"amd64\" ]\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Setup Timezone\n      uses: szenius/set-timezone@v2.0\n      with:\n        timezoneLinux: \"Asia/Shanghai\"\n\n    - name: Checkout Repository\n      uses: actions/checkout@v5\n\n    - name: Start Minikube\n      uses: medyagh/setup-minikube@master\n\n    - name: Setup Golang ${{ matrix.go-version }}\n      uses: actions/setup-go@v5\n      with:\n        go-version: ${{ matrix.go-version }}\n        cache-dependency-path: '**/go.sum' \n\n    - name: Before Script\n      run:  bash .github/workflows/scripts/before_script.sh\n\n    - name: Build & Test\n      run: bash .github/workflows/scripts/ci-sub.sh\n\n\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL Advanced\"\n\non:\n  push:\n    branches: [ \"master\", \"develop\" ]\n  pull_request:\n    branches: [ \"master\", \"develop\" ]\n  schedule:\n    - cron: '0 21 * * *'\n\njobs:\n  analyze:\n    name: Analyze (${{ matrix.language }})\n    # Runner size impacts CodeQL analysis time. To learn more, please see:\n    #   - https://gh.io/recommended-hardware-resources-for-running-codeql\n    #   - https://gh.io/supported-runners-and-hardware-resources\n    #   - https://gh.io/using-larger-runners (GitHub.com only)\n    # Consider using larger runners or machines with greater resources for possible analysis time improvements.\n    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}\n    permissions:\n      # required for all workflows\n      security-events: write\n\n      # required to fetch internal or private CodeQL packs\n      packages: read\n\n      # only required for workflows in private repositories\n      actions: read\n      contents: read\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n        - language: actions\n          build-mode: none\n        - language: go\n          build-mode: autobuild\n        # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'\n        # Use `c-cpp` to analyze code written in C, C++ or both\n        # Use 'java-kotlin' to analyze code written in Java, Kotlin or both\n        # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both\n        # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,\n        # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.\n        # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how\n        # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Add any setup steps before running the `github/codeql-action/init` action.\n    # This includes steps like installing compilers or runtimes (`actions/setup-node`\n    # or others). This is typically only required for manual builds.\n    # - name: Setup runtime (example)\n    #   uses: actions/setup-example@v1\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        build-mode: ${{ matrix.build-mode }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs\n        # queries: security-extended,security-and-quality\n\n    # If the analyze step fails for one of the languages you are analyzing with\n    # \"We were unable to automatically build your code\", modify the matrix above\n    # to set the build mode to \"manual\" for that language. Then modify this step\n    # to build your code.\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n    - if: matrix.build-mode == 'manual'\n      shell: bash\n      run: |\n        echo 'If you are using a \"manual\" build mode for one or more of the' \\\n          'languages you are analyzing, replace this with the commands to build' \\\n          'your code, for example:'\n        echo '  make bootstrap'\n        echo '  make release'\n        exit 1\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n      with:\n        category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/consul/client.json",
    "content": "{\n    \"node_name\": \"consul-client\",\n    \"data_dir\": \"/consul/data\",\n    \"retry_join\":[\n        \"consul-server\"\n     ]\n}"
  },
  {
    "path": ".github/workflows/consul/docker-compose.yml",
    "content": "version: '3.7'\n\nservices:\n\n  consul-server:\n    image: consul:1.15\n    container_name: consul-server\n    restart: always\n    volumes:\n     - ./server.json:/consul/config/server.json:ro\n    networks:\n      - consul\n    ports:\n      - \"8500:8500\"\n      - \"8600:8600/tcp\"\n      - \"8600:8600/udp\"\n    command: \"agent\"\n\n  consul-client:\n    image: consul:1.15\n    container_name: consul-client\n    restart: always\n    volumes:\n     - ./client.json:/consul/config/client.json:ro\n    networks:\n      - consul\n    command: \"agent\"\n\nnetworks:\n  consul:\n    driver: bridge"
  },
  {
    "path": ".github/workflows/consul/server.json",
    "content": "{\n    \"node_name\": \"consul-server\",\n    \"server\": true,\n    \"bootstrap\" : true,\n    \"ui_config\": {\n        \"enabled\" : true\n    },\n    \"data_dir\": \"/consul/data\",\n    \"addresses\": {\n        \"http\" : \"0.0.0.0\"\n    }\n}"
  },
  {
    "path": ".github/workflows/format-code-on-push.yml",
    "content": "name: Format Code on Push\n\non:\n  push\n\njobs:\n  format-code:\n    strategy:\n      matrix:\n        go-version: [ 'stable' ]\n    name: format-code-by-gci\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v5\n      - name: Setup Golang ${{ matrix.go-version }}\n        uses: actions/setup-go@v5\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: Install gci\n        run: go install github.com/daixiang0/gci@latest\n      - name: Run gci\n        run: |\n          gci write --custom-order \\\n          --skip-generated \\\n          --skip-vendor \\\n          -s standard \\\n          -s blank \\\n          -s default \\\n          -s dot \\\n          -s \"prefix(github.com/gogf/gf/v2)\" \\\n          -s \"prefix(github.com/gogf/gf/cmd)\" \\\n          -s \"prefix(github.com/gogf/gf/contrib)\" \\\n          -s \"prefix(github.com/gogf/gf/example)\" \\\n          ./\n      - name: Check for changes\n        run: |\n          if [[ -n \"$(git status --porcelain)\" ]]; then\n            echo \"HAS_CHANGES=true\" >> $GITHUB_ENV\n          else\n            echo \"HAS_CHANGES=false\" >> $GITHUB_ENV\n          fi         \n      - name: Configure Git\n        run: |\n          if [[ \"$HAS_CHANGES\" == 'true' ]]; then\n            git config --global user.name \"github-actions[bot]\"\n            git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          else\n            echo \"HAS_CHANGES= $HAS_CHANGES \"\n          fi\n      - name: Commit and push changes\n        run: |\n          if [[ \"$HAS_CHANGES\" == 'true' ]]; then\n            git add .\n            git commit -m \"Apply gci import order changes\"\n            git push origin ${{ github.event.pull_request.head.ref }}\n          else\n            echo \"No change to commit push\"\n          fi\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
  },
  {
    "path": ".github/workflows/gitee-sync.yml",
    "content": "on:\n  push:\n    branches:\n      - master\n    tags:\n      - \"*\"\n\nname: Sync to Gitee\njobs:\n  run:\n    name: Run\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout source code\n        uses: actions/checkout@v5\n      - name: Mirror GitHub to Gitee\n        uses: Yikun/hub-mirror-action@v1.4\n        with:\n          src: github/gogf\n          dst: gitee/johng\n          dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}\n          dst_token: ${{ secrets.GITEE_TOKEN }}\n          src_account_type: org\n          dst_account_type: user\n          timeout: 600\n          debug: true\n          force_update: true\n          static_list: \"gf\""
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "content": "# Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n#\n# This Source Code Form is subject to the terms of the MIT License.\n# If a copy of the MIT was not distributed with this file,\n# You can obtain one at https://github.com/gogf/gf.\n\nname: golangci-lint\non:\n  push:\n    branches:\n      - master\n      - develop\n      - personal/**\n      - feature/**\n      - enhance/**\n      - fix/**\n      - feat/**\n  pull_request:\n    branches:\n      - master\n      - develop\n      - personal/**\n      - feature/**\n      - enhance/**\n      - fix/**\n      - feat/**\n\njobs:\n  golang-ci:\n    strategy:\n      matrix:\n        go-version: [ \"stable\" ]\n\n    name: golang-ci-lint\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n        with:\n          fetch-depth: 0\n      - name: Setup Golang ${{ matrix.go-version }}\n        uses: actions/setup-go@v5\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: golang-ci-lint\n        uses: golangci/golangci-lint-action@v8\n        with:\n          # Required: specify the golangci-lint version without the patch version to always use the latest patch.\n          only-new-issues: true\n          skip-cache: true\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          args: --config=.golangci.yml -v\n"
  },
  {
    "path": ".github/workflows/issue-check-inactive.yml",
    "content": "# Rule description: Execute the ISSUE once a day at 3 a.m. (GMT+8) and set the non-bug issue that has not been active in the last 7 days to inactive\nname: Issue Check Inactive\n\non:\n  schedule:\n    - cron: \"0 19 * * *\"\n\nenv: # Set environment variables\n  TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)\n\npermissions:\n  contents: read\n\njobs:\n  issue-check-inactive:\n    permissions:\n      issues: write # for actions-cool/issues-helper to update issues\n     # pull-requests: write # for actions-cool/issues-helper to update PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: check-inactive\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: 'check-inactive'\n          inactive-label: 'inactive'\n          inactive-day: 30\n          issue-state: open\n          exclude-labels: 'bug,planned,$exclude-empty'"
  },
  {
    "path": ".github/workflows/issue-close-inactive.yml",
    "content": "# RULE DESCRIPTION: EXECUTED ONCE A DAY AT 4 A.M. (GMT+8) TO CLOSE NON-BUG ISSUES THAT HAVE NOT BEEN ACTIVE IN THE LAST 30 DAYS\nname: Issue Close Inactive\n\non:\n  schedule:\n    - cron: \"0 20 * * *\"\n\nenv: # Set environment variables\n  TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)\n\njobs:\n  close-issues:\n    runs-on: ubuntu-latest\n    steps:\n      - name: need close\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: \"close-issues\"\n#          token: ${{ secrets.GF_TOKEN }}\n          labels: 'inactive'\n          inactive-day: 30\n          exclude-labels: 'bug,$exclude-empty'\n          close-reason: 'not active'"
  },
  {
    "path": ".github/workflows/issue-labeled.yml",
    "content": "## Rule description: Add comments when an issue is marked as help wanted\n\nname: Issue Labeled\n\non:\n  issues:\n    types: [labeled]\n\nenv: # Set environment variables\n  TZ: Asia/Shanghai # Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)\n\njobs:\n  reply-labeled:\n    runs-on: ubuntu-latest\n    steps:\n      - name: contribution welcome\n        if: github.event.label.name == 'help wanted'\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: \"create-comment, remove-labels\"\n#          token: ${{ secrets.GF_TOKEN }}\n          issue-number: ${{ github.event.issue.number }}\n          body: |\n            Hello @${{ github.event.issue.user.login }}. We like your proposal/feedback and would appreciate a contribution via a Pull Request by you or another community member. We thank you in advance for your contribution and are looking forward to reviewing it!\n            你好 @${{ github.event.issue.user.login }}。我们喜欢您的提案/反馈，并希望您或其他社区成员通过拉取请求做出贡献。我们提前感谢您的贡献，并期待对其进行审查。\n"
  },
  {
    "path": ".github/workflows/issue-remove-inactive.yml",
    "content": "# Rule description: If an issue author updates or comments on an issue while it is not active and has not been closed, the inactive tag will be removed\nname: Issue Remove Inactive\n\non:\n  issues:\n    types: [edited]\n  issue_comment:\n    types: [created, edited]\n\nenv: # Set environment variables\n  TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)\n\npermissions:\n  contents: read\n\njobs:\n  issue-remove-inactive:\n    permissions:\n      issues: write  # for actions-cool/issues-helper to update issues\n     # pull-requests: write # for actions-cool/issues-helper to update PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: remove inactive\n        if: github.event.issue.state == 'open'\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: 'remove-labels'\n          issue-number: ${{ github.event.issue.number }}\n          labels: 'inactive'\n"
  },
  {
    "path": ".github/workflows/issue-remove-need-more-details.yml",
    "content": "# Rule Description: For issues that need more details and are not yet closed, remove the \"need more details\" tag after the issue author comments\nname: Issue Remove Need More Details\n\non:\n  issues:\n    types: [edited]\n  issue_comment:\n    types: [created, edited]\n\nenv: # Set environment variables\n  TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)\n\npermissions:\n  contents: read\n\njobs:\n  issue-remove-need-more-details:\n    permissions:\n      issues: write # for actions-cool/issues-helper to update issues\n     # pull-requests: write # for actions-cool/issues-helper to update PRs\n    runs-on: ubuntu-latest\n    steps:\n      - name: remove need more details\n        if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: 'remove-labels'\n          issue-number: ${{ github.event.issue.number }}\n          labels: 'need more details'"
  },
  {
    "path": ".github/workflows/issue-translator.yml",
    "content": "# https://github.com/usthe/issues-translate-action\nname: 'Issue Translator'\non:\n  issue_comment:\n    types: [created]\n  issues:\n    types: [opened]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: usthe/issues-translate-action@v2.7\n        with:\n          IS_MODIFY_TITLE: true\n          # not require, default false. Decide whether to modify the issue title\n          # if true, the robot account @Issues-translate-bot must have modification permissions,\n          # invite @Issues-translate-bot to your project or use your custom bot.\n          CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿"
  },
  {
    "path": ".github/workflows/nacos/docker-compose.yml",
    "content": "version: \"3.8\"\n\nservices:\n  nacos:\n    image: nacos/nacos-server:v2.1.2\n    container_name: nacos\n    env_file:\n      - ./env/nacos.env\n    ports:\n      - \"8848:8848\"\n      - \"9848:9848\"\n      - \"9555:9555\"\n    healthcheck:\n      test: [ \"CMD\", \"curl\" ,\"http://localhost:8848/nacos\" ]\n      interval: 5s\n      timeout: 3s\n      retries: 10\n\n  initializer:\n    image: alpine/curl:latest\n    depends_on:\n      nacos:\n        condition: service_healthy\n    command: [ \"sh\", \"-c\", \"curl -X POST 'http://nacos:8848/nacos/v1/cs/configs?dataId=config.toml&group=test&content=%5Bserver%5D%0A%09address%3D%22%3A8000%22'\" ]\n"
  },
  {
    "path": ".github/workflows/nacos/env/nacos.env",
    "content": "PREFER_HOST_MODE=hostname\nMODE=standalone\n"
  },
  {
    "path": ".github/workflows/redis/docker-compose.yml",
    "content": "version: \"2\"\n\nservices:\n  redis-master:\n    container_name: redis-master\n    image: \"loads/redis:7.0-sentinel\"\n    environment:\n      - REDIS_REPLICATION_MODE=master\n      - REDIS_PASSWORD=111111\n    ports:\n      - 6380:6379\n\n  redis-slave1:\n    container_name: redis-slave1\n    image: \"loads/redis:7.0-sentinel\"\n    environment:\n      - REDIS_REPLICATION_MODE=slave\n      - REDIS_MASTER_HOST=redis-master\n      - REDIS_MASTER_PASSWORD=111111\n      - REDIS_PASSWORD=111111\n    ports:\n      - 6381:6379\n    depends_on:\n      - redis-master\n    links:\n      - redis-master\n\n  redis-slave2:\n    container_name: redis-slave2\n    image: \"loads/redis:7.0-sentinel\"\n    environment:\n      - REDIS_REPLICATION_MODE=slave\n      - REDIS_MASTER_HOST=redis-master\n      - REDIS_MASTER_PASSWORD=111111\n      - REDIS_PASSWORD=111111\n    ports:\n      - 6382:6379\n    depends_on:\n      - redis-master\n    links:\n      - redis-master\n\n  redis-sentinel-1:\n    container_name: redis-sentinel-1\n    image: \"loads/redis-sentinel:7.0\"\n    environment:\n      - REDIS_MASTER_HOST=redis-master\n      - REDIS_MASTER_PORT_NUMBER=6379\n      - REDIS_MASTER_PASSWORD=111111\n    depends_on:\n      - redis-master\n      - redis-slave1\n      - redis-slave2\n    ports:\n      - 26379:26379\n    links:\n      - redis-master\n      - redis-slave1\n      - redis-slave2\n\n  redis-sentinel-2:\n    container_name: redis-sentinel-2\n    image: \"loads/redis-sentinel:7.0\"\n    environment:\n      - REDIS_MASTER_HOST=redis-master\n      - REDIS_MASTER_PORT_NUMBER=6379\n      - REDIS_MASTER_PASSWORD=111111\n    depends_on:\n      - redis-master\n      - redis-slave1\n      - redis-slave2\n    links:\n      - redis-master\n      - redis-slave1\n      - redis-slave2\n    ports:\n      - 26380:26379\n\n  redis-sentinel-3:\n    container_name: redis-sentinel-3\n    image: \"loads/redis-sentinel:7.0\"\n    environment:\n      - REDIS_MASTER_HOST=redis-master\n      - REDIS_MASTER_PORT_NUMBER=6379\n      - REDIS_MASTER_PASSWORD=111111\n    depends_on:\n      - redis-master\n      - redis-slave1\n      - redis-slave2\n    ports:\n      - 26381:26379\n    links:\n      - redis-master\n      - redis-slave1\n      - redis-slave2"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: GoFrame Release\n\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n    - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\nenv:\n  TZ: Asia/Shanghai\n\n\njobs:\n  build:\n    name: Build And Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Github Code\n        uses: actions/checkout@v5\n\n      - name: Set Up Golang Environment\n        uses: actions/setup-go@v5\n        with:\n          go-version: 1.25\n          cache: false\n      \n      - name: Build CLI Binary\n        run: |\n          echo \"Building linux amd64 binary...\"\n          cd cmd/gf\n          GOOS=linux GOARCH=amd64 go build main.go\n          chmod +x main\n          ./main install -y\n\n      - name: Build CLI Binary For All Platform\n        run: |\n          cd cmd/gf\n          gf build main.go -n gf -a all -s linux,windows,darwin,freebsd,netbsd,openbsd -p temp\n\n      - name: Move Files Before Release\n        run: |\n          cd cmd/gf/temp\n          for OS in *;do for FILE in $OS/*;\\\n          do if [[ ${OS} =~ 'windows' ]];\\\n          then mv $FILE gf_$OS.exe && rm -rf $OS;\\\n          else mv $FILE gf_$OS && rm -rf $OS;\\\n          fi;done;done\n\n      - name: Create Github Release\n        id: create_release\n        uses: softprops/action-gh-release@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name:     ${{ github.ref }}\n          name: GoFrame Release ${{ github.ref_name }}\n          draft:        false\n          prerelease:   false\n      \n      - name: Upload Release Asset\n        id:   upload-release-asset\n        uses: alexellis/upload-assets@0.4.0\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          asset_paths: '[\"cmd/gf/temp/gf_*\"]'\n"
  },
  {
    "path": ".github/workflows/scorecard.yml",
    "content": "# This workflow uses actions that are not certified by GitHub. They are provided\n# by a third-party and are governed by separate terms of service, privacy\n# policy, and support documentation.\n\nname: Scorecard supply-chain security\non:\n  # For Branch-Protection check. Only the default branch is supported. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection\n  branch_protection_rule:\n  # To guarantee Maintained check is occasionally updated. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained\n  schedule:\n    - cron: '0 21 * * *'\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\n# Declare default permissions as read only.\npermissions: read-all\n\njobs:\n  analysis:\n    name: Scorecard analysis\n    runs-on: ubuntu-latest\n    # `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.\n    if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'\n    permissions:\n      # Needed to upload the results to code-scanning dashboard.\n      security-events: write\n      # Needed to publish results and get a badge (see publish_results below).\n      id-token: write\n      # Uncomment the permissions below if installing in a private repository.\n      # contents: read\n      # actions: read\n\n    steps:\n      - name: \"Checkout code\"\n        uses: actions/checkout@v4.2.2\n        with:\n          persist-credentials: false\n\n      - name: \"Run analysis\"\n        uses: ossf/scorecard-action@v2.4.1\n        with:\n          results_file: results.sarif\n          results_format: sarif\n          # (Optional) \"write\" PAT token. Uncomment the `repo_token` line below if:\n          # - you want to enable the Branch-Protection check on a *public* repository, or\n          # - you are installing Scorecard on a *private* repository\n          # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.\n          # repo_token: ${{ secrets.SCORECARD_TOKEN }}\n\n          # Public repositories:\n          #   - Publish results to OpenSSF REST API for easy access by consumers\n          #   - Allows the repository to include the Scorecard badge.\n          #   - See https://github.com/ossf/scorecard-action#publishing-results.\n          # For private repositories:\n          #   - `publish_results` will always be set to `false`, regardless\n          #     of the value entered here.\n          publish_results: true\n\n          # (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore\n          # file_mode: git\n\n      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF\n      # format to the repository Actions tab.\n      - name: \"Upload artifact\"\n        uses: actions/upload-artifact@v4.6.1\n        with:\n          name: SARIF file\n          path: results.sarif\n          retention-days: 5\n\n      # Upload the results to GitHub's code scanning dashboard (optional).\n      # Commenting out will disable upload of results to your repo's Code Scanning dashboard\n      - name: \"Upload to code-scanning\"\n        uses: github/codeql-action/upload-sarif@v3\n        with:\n          sarif_file: results.sarif\n"
  },
  {
    "path": ".github/workflows/scripts/before_script.sh",
    "content": "#!/usr/bin/env bash\n\n# Install gci\necho \"Installing gci...\"\ngo install github.com/daixiang0/gci@latest\n\n# Check if the GCI is installed successfully\nif ! command -v gci &> /dev/null\nthen\n    echo \"gci could not be installed. Please check your Go setup.\"\n    exit 1\nfi\n\n# Use GCI to format the code\necho \"Running gci to format code...\"\ngci write \\\n      --custom-order \\\n      --skip-generated \\\n      --skip-vendor \\\n      -s standard \\\n      -s blank \\\n      -s default \\\n      -s dot \\\n      -s \"prefix(github.com/gogf/gf/v2)\" \\\n      -s \"prefix(github.com/gogf/gf/cmd)\" \\\n      -s \"prefix(github.com/gogf/gf/contrib)\" \\\n      -s \"prefix(github.com/gogf/gf/example)\" \\\n      ./\n\n# Check the code for changes\ngit diff --name-only --exit-code || if [ $? != 0 ]; then echo \"Notice: gci check failed, please gci before pr.\" && exit 1; fi\necho \"gci check pass.\"\n\n# Add the local domain name to `/etc/hosts`\necho \"Adding local domain to /etc/hosts...\"\nsudo echo \"127.0.0.1   local\" | sudo tee -a /etc/hosts"
  },
  {
    "path": ".github/workflows/scripts/ci-main-clean.sh",
    "content": "#!/usr/bin/env bash\n\ndirpath=$1\n\n# Extract the base directory name for pattern matching\nif [ -n \"$dirpath\" ]; then\n    dirname=$(basename \"$dirpath\")\n    echo \"Cleaning Docker resources for path: $dirpath (pattern: $dirname)\"\n    df -h /\n    \n    # Process containers and images based on the directory\n    case \"$dirname\" in\n        # \"mysql\")\n        #     echo \"Cleaning mysql resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing mysql containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q mysql 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        \"mssql\")\n            echo \"Cleaning mssql resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing mssql containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q mcr.microsoft.com/mssql/server 2>/dev/null) 2>/dev/null || true\n        ;;\n        \"pgsql\")\n            echo \"Cleaning postgres resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing postgres containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q postgres 2>/dev/null) 2>/dev/null || true\n        ;;\n        \"oracle\")\n            echo \"Cleaning oracle resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing oracle containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q loads/oracle-xe-11g-r2 2>/dev/null) 2>/dev/null || true\n        ;;\n        \"dm\")\n            echo \"Cleaning dm resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing dm containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q loads/dm 2>/dev/null) 2>/dev/null || true\n        ;;\n        \"clickhouse\")\n            echo \"Cleaning clickhouse resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing clickhouse containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q clickhouse/clickhouse-server 2>/dev/null) 2>/dev/null || true\n        ;;\n        # \"redis\")\n        #     echo \"Cleaning redis resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing redis containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q redis loads/redis loads/redis-sentinel 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        \"etcd\")\n            echo \"Cleaning etcd resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing etcd containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q bitnamilegacy/etcd 2>/dev/null) 2>/dev/null || true\n        ;;\n        # \"consul\")\n        #     echo \"Cleaning consul resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing consul containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q consul 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        # \"nacos\")\n        #     echo \"Cleaning nacos resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing nacos containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q nacos/nacos-server 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        # \"polaris\")\n        #     echo \"Cleaning polaris resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing polaris containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q polarismesh/polaris-standalone 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        \"zookeeper\")\n            echo \"Cleaning zookeeper resources...\"\n            containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n            if [ -n \"$containers\" ]; then\n                echo \"Stopping and removing zookeeper containers...\"\n                docker stop $containers 2>/dev/null || true\n                docker rm -f $containers 2>/dev/null || true\n            fi\n            docker rmi -f $(docker images -q zookeeper 2>/dev/null) 2>/dev/null || true\n        ;;\n        # \"apollo\")\n        #     echo \"Cleaning apollo resources...\"\n        #     containers=$(docker ps -aq --filter \"name=$dirname\" 2>/dev/null)\n        #     if [ -n \"$containers\" ]; then\n        #         echo \"Stopping and removing apollo containers...\"\n        #         docker stop $containers 2>/dev/null || true\n        #         docker rm -f $containers 2>/dev/null || true\n        #     fi\n        #     docker rmi -f $(docker images -q loads/apollo-quick-start 2>/dev/null) 2>/dev/null || true\n        #     ;;\n        *)\n            # No matching pattern, skip cleanup\n            echo \"No specific Docker cleanup rule for '$dirname', skipping cleanup\"\n        ;;\n    esac\n    \n    # Remove dangling images and volumes to free up space\n    echo \"Removing dangling images and unused volumes...\"\n    docker image prune -f 2>/dev/null || true\n    docker volume prune -f 2>/dev/null || true\n    \n    echo \"Docker cleanup completed for $dirname\"\n    docker system df\n    df -h /\nfi\n\n# df -h /\n# Filesystem      Size  Used Avail Use% Mounted on\n# /dev/root        72G   67G  5.4G  93% /\n# tmpfs           7.9G   84K  7.9G   1% /dev/shm\n# tmpfs           3.2G  2.6M  3.2G   1% /run\n# tmpfs           5.0M     0  5.0M   0% /run/lock\n# /dev/sdb16      881M   62M  758M   8% /boot\n# /dev/sdb15      105M  6.2M   99M   6% /boot/efi\n# /dev/sda1        74G  4.1G   66G   6% /mnt\n# tmpfs           1.6G   12K  1.6G   1% /run/user/1001\n\n# runner@runnervmg1sw1:~/work/gf/gf$ docker system df\n# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE\n# Images          18        11        8.326GB   1.644GB (19%)\n# Containers      11        11        2.692GB   0B (0%)\n# Local Volumes   11        8         665.7MB   211.9MB (31%)\n# Build Cache     0         0         0B        0B\n\n# runner@runnervmg1sw1:~/work/gf/gf$ docker images\n# REPOSITORY                       TAG                               IMAGE ID       CREATED         SIZE\n# alpine/curl                      latest                            99fd43792a61   2 days ago      13.5MB\n# postgres                         17-alpine                         b6bf692a8125   9 days ago      278MB\n# zookeeper                        3.8                               2f26c02b94ca   10 days ago     306MB\n# mariadb                          11.4                              063fb6684f96   10 days ago     332MB\n# mcr.microsoft.com/mssql/server   2022-latest                       a2fbff321505   4 weeks ago     1.61GB\n# clickhouse/clickhouse-server     24.11.1.2557-alpine               2eee9fd3ae74   12 months ago   539MB\n# redis                            7.0                               7705dd2858c1   18 months ago   109MB\n# consul                           1.15                              686495461132   20 months ago   155MB\n# mysql                            5.7                               5107333e08a8   23 months ago   501MB\n# polarismesh/polaris-standalone   v1.17.2                           b7a8cf0a8438   2 years ago     545MB\n# bitnamilegacy/etcd               3.4.24                            74ae5e205ac5   2 years ago     134MB\n# nacos/nacos-server               v2.1.2                            a978644d9246   2 years ago     1.06GB\n# loads/redis                      7.0-sentinel                      6f12d40540ba   3 years ago     114MB\n# loads/dm                         v8.1.2.128_ent_x86_64_ctm_pack4   ccb727ce9dce   3 years ago     432MB\n# loads/redis-sentinel             7.0                               6818c626f5ca   3 years ago     104MB\n# loads/apollo-quick-start         latest                            8490de672148   3 years ago     190MB\n# alpine                           3.8                               c8bccc0af957   5 years ago     4.41MB\n# loads/oracle-xe-11g-r2           11.2.0                            0d19fd2e072e   6 years ago     2.1GB\n\n# runner@runnervmg1sw1:~/work/gf/gf$ docker ps -s\n# CONTAINER ID   IMAGE                                              COMMAND                  CREATED         STATUS                   PORTS                                                                                                                                                                                                                         NAMES                                                                               SIZE\n# 8214f83420c6   zookeeper:3.8                                      \"/docker-entrypoint.…\"   6 minutes ago   Up 6 minutes             2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, [::]:2181->2181/tcp, 8080/tcp                                                                                                                                                     d66bac92ae9646f688f70ed4b5176f14_zookeeper38_3a22ef                                 33kB (virtual 306MB)\n# 8938d73842e8   loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4           \"/bin/bash /opt/star…\"   6 minutes ago   Up 6 minutes             0.0.0.0:5236->5236/tcp, [::]:5236->5236/tcp                                                                                                                                                                                   ca280fbdb86f40c2acf86d7d526c6285_loadsdmv812128_ent_x86_64_ctm_pack4_770a59         844MB (virtual 1.28GB)\n# 0d3a653fe1f2   loads/oracle-xe-11g-r2:11.2.0                      \"/bin/sh -c '/usr/sb…\"   6 minutes ago   Up 6 minutes             22/tcp, 8080/tcp, 0.0.0.0:1521->1521/tcp, [::]:1521->1521/tcp                                                                                                                                                                 2048856d428c4967b1c35193eb8c9192_loadsoraclexe11gr21120_295d54                      1.3GB (virtual 3.4GB)\n# ca3936189166   polarismesh/polaris-standalone:v1.17.2             \"/bin/bash run.sh\"       6 minutes ago   Up 6 minutes             0.0.0.0:8090-8091->8090-8091/tcp, [::]:8090-8091->8090-8091/tcp, 8080/tcp, 8100-8101/tcp, 0.0.0.0:8093->8093/tcp, [::]:8093->8093/tcp, 8761/tcp, 15010/tcp, 0.0.0.0:9090-9091->9090-9091/tcp, [::]:9090-9091->9090-9091/tcp   cbd43dceef754e2d8aab507e33167be7_polarismeshpolarisstandalonev1172_ca40b6           299MB (virtual 844MB)\n# 26169dad485e   clickhouse/clickhouse-server:24.11.1.2557-alpine   \"/entrypoint.sh\"         6 minutes ago   Up 6 minutes             0.0.0.0:8123->8123/tcp, [::]:8123->8123/tcp, 0.0.0.0:9000-9001->9000-9001/tcp, [::]:9000-9001->9000-9001/tcp, 9009/tcp                                                                                                        f1c7766fbe36401792a6f735d7acf123_clickhouseclickhouseserver241112557alpine_cfc034   338kB (virtual 539MB)\n# 04689a1d581f   mcr.microsoft.com/mssql/server:2022-latest         \"/opt/mssql/bin/laun…\"   6 minutes ago   Up 6 minutes (healthy)   0.0.0.0:1433->1433/tcp, [::]:1433->1433/tcp                                                                                                                                                                                   41d685349a7640b28230db8d0f60efe7_mcrmicrosoftcommssqlserver2022latest_fe29fb        108MB (virtual 1.72GB)\n# d5fbc5f811af   postgres:17-alpine                                 \"docker-entrypoint.s…\"   6 minutes ago   Up 6 minutes (healthy)   0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp                                                                                                                                                                                   2783be71b5ce417ab9a31428e7b4d8f2_postgres17alpine_c60840                            63B (virtual 278MB)\n# da96a7ad7a01   mariadb:11.4                                       \"docker-entrypoint.s…\"   7 minutes ago   Up 7 minutes             0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp                                                                                                                                                                                   45eed646fa6c4a698893ee11cda95a4c_mariadb114_3a9cd6                                  2B (virtual 332MB)\n# 27ba1904ba3a   mysql:5.7                                          \"docker-entrypoint.s…\"   7 minutes ago   Up 7 minutes             0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp                                                                                                                                                                        ea6d7a4c207d427a95b5ae0db91fdf56_mysql57_c21053                                     4B (virtual 501MB)\n# 518e785d1bb6   redis:7.0                                          \"docker-entrypoint.s…\"   7 minutes ago   Up 7 minutes (healthy)   0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp                                                                                                                                                                                   af6044fc849e441bbc6c48f7a5ec5fec_redis70_b11994                                     0B (virtual 109MB)\n# 7495ec2cd8e3   bitnamilegacy/etcd:3.4.24                          \"/opt/bitnami/script…\"   7 minutes ago   Up 7 minutes             0.0.0.0:2379->2379/tcp, [::]:2379->2379/tcp, 2380/tcp                                                                                                                                                                         49f2a2a6bf3a4fae842cc950bbc3658a_bitnamilegacyetcd3424_1265e1                       145MB (virtual 279MB)\n\n# runner@runnervmg1sw1:~/work/gf/gf$ du -ah --max-depth=1 /usr | sort -n\n# 4.0K    /usr/games\n# 4.0K    /usr/lib64\n# 6.6G    /usr/lib\n# 9.3G    /usr/share\n# 15M     /usr/lib32\n# 24G     /usr/local\n# 41G     /usr\n# 95M     /usr/sbin\n# 156M    /usr/include\n# 158M    /usr/src\n# 402M    /usr/libexec\n# 841M    /usr/bin\n\n# runner@runnervmg1sw1:~/work/gf/gf$ du -ah --max-depth=1 /opt | sort -n                                                                        \n# 4.0K    /opt/pipx_bin\n# 5.8G    /opt/hostedtoolcache\n# 8.5G    /opt\n# 12K     /opt/containerd\n# 14M     /opt/hca\n# 16K     /opt/post-generation\n# 217M    /opt/runner-cache\n# 243M    /opt/actionarchivecache\n# 374M    /opt/google\n# 515M    /opt/pipx\n# 655M    /opt/az\n# 783M    /opt/microsoft\n\n# runner@runnervmg1sw1:~/work/gf/gf$ du -ah --max-depth=1 /opt/hostedtoolcache/ | sort -n\n# 1.1G    /opt/hostedtoolcache/go\n# 1.6G    /opt/hostedtoolcache/CodeQL\n# 1.9G    /opt/hostedtoolcache/Python\n# 5.8G    /opt/hostedtoolcache/\n# 9.9M    /opt/hostedtoolcache/protoc\n# 24K     /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk\n# 217M    /opt/hostedtoolcache/Ruby\n# 520M    /opt/hostedtoolcache/PyPy\n# 574M    /opt/hostedtoolcache/node\n\n"
  },
  {
    "path": ".github/workflows/scripts/ci-main.sh",
    "content": "#!/usr/bin/env bash\n\ncoverage=$1\n\n# find all path that contains go.mod.\nfor file in `find . -name go.mod`; do\n    dirpath=$(dirname $file)\n    echo $dirpath\n    \n    # package kubecm was moved to sub ci procedure.\n    if [ \"kubecm\" = $(basename $dirpath) ]; then\n        continue 1\n    fi\n    \n    # examples directory was moved to sub ci procedure.\n    if [[ $dirpath =~ \"/examples/\" ]]; then\n        continue 1\n    fi\n    \n    if [[ $file =~ \"/testdata/\" ]]; then\n        echo \"ignore testdata path $file\"\n        continue 1\n    fi\n    \n    # Check if it's a contrib directory\n    if [[ $dirpath =~ \"/contrib/\" ]]; then\n        # Check if go version meets the requirement\n        if ! go version | grep -qE \"go${LATEST_GO_VERSION}\"; then\n            echo \"ignore path $dirpath as go version is not ${LATEST_GO_VERSION}: $(go version)\"\n            # clean docker containers and images to free disk space\n            # bash .github/workflows/scripts/ci-main-clean.sh \"$dirpath\"\n            continue 1\n        fi\n    fi\n    \n    # if [[ $dirpath = \".\" ]]; then\n    #     # No space left on device error sometimes occurs in CI pipelines, so clean the cache before tests.\n    #     go clean -cache\n    # fi\n    \n    cd $dirpath\n    go mod tidy\n    go build ./...\n    \n    # test with coverage\n    if [ \"${coverage}\" = \"coverage\" ]; then\n        go test ./... -count=1 -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1\n        \n        if grep -q \"/gogf/gf/.*/v2\" go.mod; then\n            sed -i \"s/gogf\\/gf\\(\\/.*\\)\\/v2/gogf\\/gf\\/v2\\1/g\" coverage.out\n        fi\n    else\n        go test ./... -count=1 -race || exit 1\n    fi\n    \n    cd -\n    # clean docker containers and images to free disk space\n    # bash .github/workflows/scripts/ci-main-clean.sh \"$dirpath\"\ndone\n"
  },
  {
    "path": ".github/workflows/scripts/ci-sub.sh",
    "content": "#!/usr/bin/env bash\n\ncoverage=$1\n\n# update code of submodules\ngit clone https://github.com/gogf/examples\n\n# update go.mod in examples directory to replace github.com/gogf/gf packages with local directory\nbash .github/workflows/scripts/replace_examples_gomod.sh\n\n# Function to compare version numbers\nversion_compare() {\n    local ver1=$1\n    local ver2=$2\n    \n    # Remove 'go' prefix and 'v' if present\n    ver1=$(echo \"$ver1\" | sed 's/^go//; s/^v//')\n    ver2=$(echo \"$ver2\" | sed 's/^go//; s/^v//')\n    \n    # Split versions into major.minor format\n    local major1=$(echo \"$ver1\" | cut -d. -f1)\n    local minor1=$(echo \"$ver1\" | cut -d. -f2)\n    local major2=$(echo \"$ver2\" | cut -d. -f1)\n    local minor2=$(echo \"$ver2\" | cut -d. -f2)\n    \n    # Compare versions: return 0 if ver1 <= ver2, 1 otherwise\n    if [ \"$major1\" -lt \"$major2\" ]; then\n        return 0\n    elif [ \"$major1\" -eq \"$major2\" ] && [ \"$minor1\" -le \"$minor2\" ]; then\n        return 0\n    else\n        return 1\n    fi\n}\n\n# Get current Go version\ncurrent_go_version=$(go version | grep -oE 'go[0-9]+\\.[0-9]+')\n\n# find all path that contains go.mod.\nfor file in `find . -name go.mod`; do\n    dirpath=$(dirname $file)\n    echo \"Processing: $dirpath\"\n\n    # Only process examples and kubecm directories  \n\n    # Process examples directory (only build, no tests)\n    if [[ $dirpath =~ \"/examples/\" ]]; then\n        echo \"  the examples directory only needs to be built, not unit tests.\"\n        cd $dirpath\n        go mod tidy\n        go build ./...\n        cd -\n        continue 1\n    fi\n    \n    # Process kubecm directory\n    if [ \"kubecm\" != $(basename $dirpath) ]; then\n        echo \"  Skipping: not kubecm directory\"\n        continue\n    fi\n\n    cd $dirpath\n\n    # Read Go version requirement from go.mod\n    if [ -f \"go.mod\" ]; then\n        go_mod_version=$(grep '^go ' go.mod | awk '{print $2}' | head -1)\n        \n        if [ -n \"$go_mod_version\" ]; then\n            echo \"  go.mod requires: go$go_mod_version\"\n            echo \"  current version: $current_go_version\"\n            \n            # Check if go.mod version requirement is satisfied by current Go version\n            if version_compare \"$go_mod_version\" \"$current_go_version\"; then\n                echo \"  ✓ Version requirement satisfied, proceeding with build and test\"\n                \n                go mod tidy\n                go build ./...\n                go test ./... -race || exit 1\n            else\n                echo \"  ✗ Current Go version ($current_go_version) does not meet requirement (go$go_mod_version), skipping\"\n            fi\n        fi\n    fi\n\n    cd -\ndone\n"
  },
  {
    "path": ".github/workflows/scripts/docker-services.sh",
    "content": "#!/usr/bin/env bash\n#\n# GoFrame Docker Services Manager\n# For managing Docker services used in local development and testing\n#\n\nset -e\n\n# Container name prefix\nPREFIX=\"goframe\"\n\n# Color definitions\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nCYAN='\\033[0;36m'\nNC='\\033[0m' # No Color\n\n# Service definitions\ndeclare -A SERVICES\ndeclare -A SERVICE_PORTS\ndeclare -A SERVICE_ENVS\ndeclare -A SERVICE_OPTS\n\n# Basic services\nSERVICES[\"etcd\"]=\"bitnamilegacy/etcd:3.4.24\"\nSERVICE_PORTS[\"etcd\"]=\"2379:2379\"\nSERVICE_ENVS[\"etcd\"]=\"-e ALLOW_NONE_AUTHENTICATION=yes\"\n\nSERVICES[\"redis\"]=\"redis:7.0\"\nSERVICE_PORTS[\"redis\"]=\"6379:6379\"\nSERVICE_OPTS[\"redis\"]=\"--health-cmd 'redis-cli ping' --health-interval 10s --health-timeout 5s --health-retries 5\"\n\nSERVICES[\"mysql\"]=\"mysql:5.7\"\nSERVICE_PORTS[\"mysql\"]=\"3306:3306\"\nSERVICE_ENVS[\"mysql\"]=\"-e MYSQL_DATABASE=test -e MYSQL_ROOT_PASSWORD=12345678\"\n\nSERVICES[\"mariadb\"]=\"mariadb:11.4\"\nSERVICE_PORTS[\"mariadb\"]=\"3307:3306\"\nSERVICE_ENVS[\"mariadb\"]=\"-e MARIADB_DATABASE=test -e MARIADB_ROOT_PASSWORD=12345678\"\n\nSERVICES[\"postgres\"]=\"postgres:17-alpine\"\nSERVICE_PORTS[\"postgres\"]=\"5432:5432\"\nSERVICE_ENVS[\"postgres\"]=\"-e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test -e TZ=Asia/Shanghai\"\nSERVICE_OPTS[\"postgres\"]=\"--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5\"\n\nSERVICES[\"mssql\"]=\"mcr.microsoft.com/mssql/server:2022-latest\"\nSERVICE_PORTS[\"mssql\"]=\"1433:1433\"\nSERVICE_ENVS[\"mssql\"]=\"-e TZ=Asia/Shanghai -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD=LoremIpsum86\"\n\nSERVICES[\"clickhouse\"]=\"clickhouse/clickhouse-server:24.11.1.2557-alpine\"\nSERVICE_PORTS[\"clickhouse\"]=\"9000:9000 -p 8123:8123 -p 9001:9001\"\n\nSERVICES[\"polaris\"]=\"polarismesh/polaris-standalone:v1.17.2\"\nSERVICE_PORTS[\"polaris\"]=\"8090:8090 -p 8091:8091 -p 8093:8093 -p 9090:9090 -p 9091:9091\"\n\nSERVICES[\"oracle\"]=\"loads/oracle-xe-11g-r2:11.2.0\"\nSERVICE_PORTS[\"oracle\"]=\"1521:1521\"\nSERVICE_ENVS[\"oracle\"]=\"-e ORACLE_ALLOW_REMOTE=true -e ORACLE_SID=XE -e ORACLE_DB_USER_NAME=system -e ORACLE_DB_PASSWORD=oracle\"\n\nSERVICES[\"dm\"]=\"loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4\"\nSERVICE_PORTS[\"dm\"]=\"5236:5236\"\n\nSERVICES[\"gaussdb\"]=\"opengauss/opengauss:7.0.0-RC1.B023\"\nSERVICE_PORTS[\"gaussdb\"]=\"9950:5432\"\nSERVICE_ENVS[\"gaussdb\"]=\"-e GS_PASSWORD=UTpass@1234 -e TZ=Asia/Shanghai\"\nSERVICE_OPTS[\"gaussdb\"]=\"--privileged=true\"\n\nSERVICES[\"zookeeper\"]=\"zookeeper:3.8\"\nSERVICE_PORTS[\"zookeeper\"]=\"2181:2181\"\n\n# Service groups\nGROUP_DB=\"mysql mariadb postgres mssql oracle dm gaussdb clickhouse\"\nGROUP_CACHE=\"redis etcd\"\nGROUP_REGISTRY=\"polaris zookeeper\"\nGROUP_ALL=\"etcd redis mysql mariadb postgres mssql clickhouse polaris oracle dm gaussdb zookeeper\"\n\n# Working directories\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(dirname \"$SCRIPT_DIR\")\"\nWORKFLOW_DIR=\"$PROJECT_ROOT/.github/workflows\"\n\n# Print colored messages\nprint_info() {\n    echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nprint_success() {\n    echo -e \"${GREEN}[OK]${NC} $1\"\n}\n\nprint_warning() {\n    echo -e \"${YELLOW}[WARN]${NC} $1\"\n}\n\nprint_error() {\n    echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\n# Check if Docker is available\ncheck_docker() {\n    if ! command -v docker &> /dev/null; then\n        print_error \"Docker is not installed or not in PATH\"\n        exit 1\n    fi\n    if ! docker info &> /dev/null; then\n        print_error \"Docker service is not running\"\n        exit 1\n    fi\n}\n\n# Get container name\nget_container_name() {\n    echo \"${PREFIX}-$1\"\n}\n\n# Start a single service\nstart_service() {\n    local service=$1\n    local container_name=$(get_container_name \"$service\")\n    local image=\"${SERVICES[$service]}\"\n    local ports=\"${SERVICE_PORTS[$service]}\"\n    local envs=\"${SERVICE_ENVS[$service]}\"\n    local opts=\"${SERVICE_OPTS[$service]}\"\n\n    if [ -z \"$image\" ]; then\n        print_error \"Unknown service: $service\"\n        return 1\n    fi\n\n    # Check if container already exists\n    if docker ps -a --format '{{.Names}}' | grep -q \"^${container_name}$\"; then\n        if docker ps --format '{{.Names}}' | grep -q \"^${container_name}$\"; then\n            print_warning \"$service is already running\"\n            return 0\n        else\n            print_info \"Starting existing container $service...\"\n            docker start \"$container_name\" > /dev/null\n            print_success \"$service started\"\n            return 0\n        fi\n    fi\n\n    print_info \"Starting $service...\"\n    \n    # Build docker run command\n    local cmd=\"docker run -d --name $container_name\"\n    \n    # Add port mappings\n    for port in $ports; do\n        cmd=\"$cmd -p $port\"\n    done\n    \n    # Add environment variables\n    if [ -n \"$envs\" ]; then\n        cmd=\"$cmd $envs\"\n    fi\n    \n    # Add other options\n    if [ -n \"$opts\" ]; then\n        cmd=\"$cmd $opts\"\n    fi\n    \n    cmd=\"$cmd $image\"\n    \n    if eval \"$cmd\" > /dev/null 2>&1; then\n        print_success \"$service started (container: $container_name)\"\n    else\n        print_error \"Failed to start $service\"\n        return 1\n    fi\n}\n\n# Stop a single service\nstop_service() {\n    local service=$1\n    local container_name=$(get_container_name \"$service\")\n\n    if docker ps --format '{{.Names}}' | grep -q \"^${container_name}$\"; then\n        print_info \"Stopping $service...\"\n        docker stop \"$container_name\" > /dev/null\n        print_success \"$service stopped\"\n    else\n        print_warning \"$service is not running\"\n    fi\n}\n\n# Remove a single service\nremove_service() {\n    local service=$1\n    local container_name=$(get_container_name \"$service\")\n\n    if docker ps -a --format '{{.Names}}' | grep -q \"^${container_name}$\"; then\n        print_info \"Removing $service...\"\n        docker rm -f \"$container_name\" > /dev/null\n        print_success \"$service removed\"\n    else\n        print_warning \"$service container does not exist\"\n    fi\n}\n\n# View service logs\nlogs_service() {\n    local service=$1\n    local container_name=$(get_container_name \"$service\")\n    local lines=${2:-100}\n\n    if docker ps -a --format '{{.Names}}' | grep -q \"^${container_name}$\"; then\n        docker logs --tail \"$lines\" -f \"$container_name\"\n    else\n        print_error \"$service container does not exist\"\n        return 1\n    fi\n}\n\n# Start docker-compose service\nstart_compose_service() {\n    local service=$1\n    local compose_file=\"\"\n    \n    case $service in\n        apollo)\n            compose_file=\"$WORKFLOW_DIR/apollo/docker-compose.yml\"\n            ;;\n        nacos)\n            compose_file=\"$WORKFLOW_DIR/nacos/docker-compose.yml\"\n            ;;\n        redis-cluster)\n            compose_file=\"$WORKFLOW_DIR/redis/docker-compose.yml\"\n            ;;\n        consul)\n            compose_file=\"$WORKFLOW_DIR/consul/docker-compose.yml\"\n            ;;\n        *)\n            print_error \"Unknown compose service: $service\"\n            return 1\n            ;;\n    esac\n    \n    if [ -f \"$compose_file\" ]; then\n        print_info \"Starting $service (docker-compose)...\"\n        docker compose -f \"$compose_file\" up -d\n        print_success \"$service started\"\n    else\n        print_error \"Compose file does not exist: $compose_file\"\n        return 1\n    fi\n}\n\n# Stop docker-compose service\nstop_compose_service() {\n    local service=$1\n    local compose_file=\"\"\n    \n    case $service in\n        apollo)\n            compose_file=\"$WORKFLOW_DIR/apollo/docker-compose.yml\"\n            ;;\n        nacos)\n            compose_file=\"$WORKFLOW_DIR/nacos/docker-compose.yml\"\n            ;;\n        redis-cluster)\n            compose_file=\"$WORKFLOW_DIR/redis/docker-compose.yml\"\n            ;;\n        consul)\n            compose_file=\"$WORKFLOW_DIR/consul/docker-compose.yml\"\n            ;;\n        *)\n            print_error \"Unknown compose service: $service\"\n            return 1\n            ;;\n    esac\n    \n    if [ -f \"$compose_file\" ]; then\n        print_info \"Stopping $service (docker-compose)...\"\n        docker compose -f \"$compose_file\" down\n        print_success \"$service stopped\"\n    else\n        print_error \"Compose file does not exist: $compose_file\"\n        return 1\n    fi\n}\n\n# Show service status\nshow_status() {\n    echo \"\"\n    echo -e \"${CYAN}========== GoFrame Docker Services Status ==========${NC}\"\n    echo \"\"\n    printf \"%-15s %-12s %-30s %s\\n\" \"SERVICE\" \"STATUS\" \"CONTAINER\" \"PORTS\"\n    echo \"--------------------------------------------------------------------------------\"\n    \n    for service in $GROUP_ALL; do\n        local container_name=$(get_container_name \"$service\")\n        local status=\"stopped\"\n        local ports=\"-\"\n        \n        if docker ps --format '{{.Names}}' 2>/dev/null | grep -q \"^${container_name}$\"; then\n            status=\"${GREEN}running${NC}\"\n            ports=$(docker port \"$container_name\" 2>/dev/null | tr '\\n' ' ' || echo \"-\")\n        elif docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q \"^${container_name}$\"; then\n            status=\"${YELLOW}stopped${NC}\"\n        else\n            status=\"${RED}not created${NC}\"\n        fi\n        \n        printf \"%-15s %-22b %-30s %s\\n\" \"$service\" \"$status\" \"$container_name\" \"$ports\"\n    done\n    \n    echo \"\"\n    echo -e \"${CYAN}========== Compose Services ==========${NC}\"\n    echo \"\"\n    \n    for compose_svc in apollo nacos redis-cluster consul; do\n        local running=0\n        case $compose_svc in\n            apollo)\n                running=$(docker ps --filter \"name=apollo\" --format '{{.Names}}' 2>/dev/null | wc -l)\n                ;;\n            nacos)\n                running=$(docker ps --filter \"name=nacos\" --format '{{.Names}}' 2>/dev/null | wc -l)\n                ;;\n            redis-cluster)\n                running=$(docker ps --filter \"name=redis-\" --format '{{.Names}}' 2>/dev/null | wc -l)\n                ;;\n            consul)\n                running=$(docker ps --filter \"name=consul\" --format '{{.Names}}' 2>/dev/null | wc -l)\n                ;;\n        esac\n        \n        if [ \"$running\" -gt 0 ]; then\n            printf \"%-15s ${GREEN}running${NC} (%d containers)\\n\" \"$compose_svc\" \"$running\"\n        else\n            printf \"%-15s ${RED}stopped${NC}\\n\" \"$compose_svc\"\n        fi\n    done\n    \n    echo \"\"\n}\n\n# Show service information\nshow_service_info() {\n    echo \"\"\n    echo -e \"${CYAN}========== Available Services ==========${NC}\"\n    echo \"\"\n    echo -e \"${YELLOW}Basic Services (standalone containers):${NC}\"\n    echo \"\"\n    printf \"%-15s %-50s %s\\n\" \"SERVICE\" \"IMAGE\" \"PORTS\"\n    echo \"--------------------------------------------------------------------------------\"\n    \n    for service in $GROUP_ALL; do\n        printf \"%-15s %-50s %s\\n\" \"$service\" \"${SERVICES[$service]}\" \"${SERVICE_PORTS[$service]}\"\n    done\n    \n    echo \"\"\n    echo -e \"${YELLOW}Compose Services (multi-container):${NC}\"\n    echo \"  apollo        - Apollo Config Center (8080, 8070, 8060, 13306)\"\n    echo \"  nacos         - Nacos Registry (8848, 9848, 9555)\"\n    echo \"  redis-cluster - Redis Primary-Replica + Sentinel Cluster (6380-6382, 26379-26381)\"\n    echo \"  consul        - Consul Service Discovery (8500, 8600)\"\n    echo \"\"\n    echo -e \"${YELLOW}Service Groups:${NC}\"\n    echo \"  db       - Databases: $GROUP_DB\"\n    echo \"  cache    - Cache: $GROUP_CACHE\"\n    echo \"  registry - Registry: $GROUP_REGISTRY\"\n    echo \"  all      - All basic services\"\n    echo \"\"\n}\n\n# Show help\nshow_help() {\n    echo \"\"\n    echo -e \"${CYAN}GoFrame Docker Services Manager${NC}\"\n    echo \"\"\n    echo \"Usage: $0 <command> [service|group] [options]\"\n    echo \"\"\n    echo \"Commands:\"\n    echo \"  start <service|group>    Start service or service group\"\n    echo \"  stop <service|group>     Stop service or service group\"\n    echo \"  restart <service|group>  Restart service or service group\"\n    echo \"  remove <service|group>   Remove service container\"\n    echo \"  logs <service> [lines]   View service logs (default 100 lines)\"\n    echo \"  status                   Show all service status\"\n    echo \"  info                     Show available service information\"\n    echo \"  clean                    Remove all goframe containers\"\n    echo \"  pull [service]           Pull images\"\n    echo \"\"\n    echo \"Services:\"\n    echo \"  Basic: etcd, redis, mysql, mariadb, postgres, mssql,\"\n    echo \"         clickhouse, polaris, oracle, dm, gaussdb, zookeeper\"\n    echo \"  Compose: apollo, nacos, redis-cluster, consul\"\n    echo \"\"\n    echo \"Service Groups:\"\n    echo \"  db       - All database services\"\n    echo \"  cache    - Cache services (redis, etcd)\"\n    echo \"  registry - Registry services (polaris, zookeeper)\"\n    echo \"  all      - All basic services\"\n    echo \"\"\n    echo \"Examples:\"\n    echo \"  $0 start mysql           # Start MySQL\"\n    echo \"  $0 start db              # Start all databases\"\n    echo \"  $0 start all             # Start all basic services\"\n    echo \"  $0 start apollo          # Start Apollo (compose)\"\n    echo \"  $0 stop all              # Stop all basic services\"\n    echo \"  $0 logs mysql 50         # View last 50 lines of MySQL logs\"\n    echo \"  $0 status                # View service status\"\n    echo \"\"\n}\n\n# Parse service groups\nparse_services() {\n    local input=$1\n    case $input in\n        db)\n            echo \"$GROUP_DB\"\n            ;;\n        cache)\n            echo \"$GROUP_CACHE\"\n            ;;\n        registry)\n            echo \"$GROUP_REGISTRY\"\n            ;;\n        all)\n            echo \"$GROUP_ALL\"\n            ;;\n        *)\n            echo \"$input\"\n            ;;\n    esac\n}\n\n# Check if it's a compose service\nis_compose_service() {\n    local service=$1\n    case $service in\n        apollo|nacos|redis-cluster|consul)\n            return 0\n            ;;\n        *)\n            return 1\n            ;;\n    esac\n}\n\n# Pull images\npull_images() {\n    local services=$1\n    \n    if [ -z \"$services\" ]; then\n        services=\"$GROUP_ALL\"\n    fi\n    \n    for service in $services; do\n        if [ -n \"${SERVICES[$service]}\" ]; then\n            print_info \"Pulling image: ${SERVICES[$service]}\"\n            docker pull \"${SERVICES[$service]}\"\n        fi\n    done\n}\n\n# Clean all goframe containers\nclean_all() {\n    print_info \"Removing all $PREFIX containers...\"\n    local containers=$(docker ps -a --filter \"name=$PREFIX\" --format '{{.Names}}')\n    \n    if [ -n \"$containers\" ]; then\n        for container in $containers; do\n            docker rm -f \"$container\" > /dev/null\n            print_success \"Removed: $container\"\n        done\n    else\n        print_info \"No $PREFIX containers found\"\n    fi\n}\n\n# Get service status mark\nget_service_status_mark() {\n    local service=$1\n    local container_name=$(get_container_name \"$service\")\n    \n    if docker ps --format '{{.Names}}' 2>/dev/null | grep -q \"^${container_name}$\"; then\n        echo -e \"${GREEN}*${NC}\"\n    else\n        echo \" \"\n    fi\n}\n\n# Get compose service status mark\nget_compose_status_mark() {\n    local service=$1\n    local running=0\n    \n    case $service in\n        apollo)\n            running=$(docker ps --filter \"name=apollo\" --format '{{.Names}}' 2>/dev/null | wc -l)\n            ;;\n        nacos)\n            running=$(docker ps --filter \"name=nacos\" --format '{{.Names}}' 2>/dev/null | wc -l)\n            ;;\n        redis-cluster)\n            running=$(docker ps --filter \"name=redis-\" --format '{{.Names}}' 2>/dev/null | wc -l)\n            ;;\n        consul)\n            running=$(docker ps --filter \"name=consul\" --format '{{.Names}}' 2>/dev/null | wc -l)\n            ;;\n    esac\n    \n    if [ \"$running\" -gt 0 ]; then\n        echo -e \"${GREEN}*${NC}\"\n    else\n        echo \" \"\n    fi\n}\n\n# Service selection menu\nselect_service_menu() {\n    local action=$1\n    local action_name=$2\n    \n    echo \"\"\n    echo -e \"${CYAN}========== Select Service to ${action_name} ==========${NC}\"\n    \n    # Show running status for stop/restart/logs operations\n    if [[ \"$action\" == \"stop\" || \"$action\" == \"restart\" || \"$action\" == \"logs\" ]]; then\n        echo -e \"  (${GREEN}*${NC} indicates running)\"\n    fi\n    echo \"\"\n    echo -e \"${YELLOW}Basic Services:${NC}\"\n    printf \"  %b1) etcd         %b2) redis        %b3) mysql\\n\" \\\n        \"$(get_service_status_mark etcd)\" \"$(get_service_status_mark redis)\" \"$(get_service_status_mark mysql)\"\n    printf \"  %b4) mariadb      %b5) postgres     %b6) mssql\\n\" \\\n        \"$(get_service_status_mark mariadb)\" \"$(get_service_status_mark postgres)\" \"$(get_service_status_mark mssql)\"\n    printf \"  %b7) clickhouse   %b8) polaris      %b9) oracle\\n\" \\\n        \"$(get_service_status_mark clickhouse)\" \"$(get_service_status_mark polaris)\" \"$(get_service_status_mark oracle)\"\n    printf \" %b10) dm          %b11) gaussdb     %b12) zookeeper\\n\" \\\n        \"$(get_service_status_mark dm)\" \"$(get_service_status_mark gaussdb)\" \"$(get_service_status_mark zookeeper)\"\n    echo \"\"\n    echo -e \"${YELLOW}Compose Services:${NC}\"\n    printf \" %b13) apollo      %b14) nacos       %b15) redis-cluster\\n\" \\\n        \"$(get_compose_status_mark apollo)\" \"$(get_compose_status_mark nacos)\" \"$(get_compose_status_mark redis-cluster)\"\n    printf \" %b16) consul\\n\" \"$(get_compose_status_mark consul)\"\n    echo \"\"\n    echo -e \"${YELLOW}Service Groups:${NC}\"\n    echo \"  17) db (all databases)    18) cache (cache services)\"\n    echo \"  19) registry (registry services) 20) all (all basic services)\"\n    echo \"\"\n    echo \"   0) Back to main menu\"\n    echo \"\"\n    read -p \"Select [0-20]: \" svc_choice\n    \n    local svc=\"\"\n    case $svc_choice in\n        1) svc=\"etcd\" ;;\n        2) svc=\"redis\" ;;\n        3) svc=\"mysql\" ;;\n        4) svc=\"mariadb\" ;;\n        5) svc=\"postgres\" ;;\n        6) svc=\"mssql\" ;;\n        7) svc=\"clickhouse\" ;;\n        8) svc=\"polaris\" ;;\n        9) svc=\"oracle\" ;;\n        10) svc=\"dm\" ;;\n        11) svc=\"gaussdb\" ;;\n        12) svc=\"zookeeper\" ;;\n        13) svc=\"apollo\" ;;\n        14) svc=\"nacos\" ;;\n        15) svc=\"redis-cluster\" ;;\n        16) svc=\"consul\" ;;\n        17) svc=\"db\" ;;\n        18) svc=\"cache\" ;;\n        19) svc=\"registry\" ;;\n        20) svc=\"all\" ;;\n        0) return ;;\n        *)\n            print_error \"Invalid selection\"\n            return\n            ;;\n    esac\n    \n    case $action in\n        start)\n            if is_compose_service \"$svc\"; then\n                start_compose_service \"$svc\"\n            else\n                for s in $(parse_services \"$svc\"); do\n                    start_service \"$s\"\n                done\n            fi\n            ;;\n        stop)\n            if is_compose_service \"$svc\"; then\n                stop_compose_service \"$svc\"\n            else\n                for s in $(parse_services \"$svc\"); do\n                    stop_service \"$s\"\n                done\n            fi\n            ;;\n        restart)\n            if is_compose_service \"$svc\"; then\n                stop_compose_service \"$svc\"\n                start_compose_service \"$svc\"\n            else\n                for s in $(parse_services \"$svc\"); do\n                    stop_service \"$s\"\n                    start_service \"$s\"\n                done\n            fi\n            ;;\n        remove)\n            for s in $(parse_services \"$svc\"); do\n                remove_service \"$s\"\n            done\n            ;;\n        logs)\n            if is_compose_service \"$svc\"; then\n                print_error \"For Compose services, please use 'docker compose logs'\"\n            else\n                read -p \"Number of lines (default 100): \" lines\n                lines=${lines:-100}\n                logs_service \"$svc\" \"$lines\"\n            fi\n            ;;\n        pull)\n            pull_images \"$(parse_services \"$svc\")\"\n            ;;\n    esac\n}\n\n# Interactive menu\ninteractive_menu() {\n    while true; do\n        echo \"\"\n        echo -e \"${CYAN}========== GoFrame Docker Services Manager ==========${NC}\"\n        echo \"\"\n        echo \"  1) Start Service\"\n        echo \"  2) Stop Service\"\n        echo \"  3) Restart Service\"\n        echo \"  4) Remove Service\"\n        echo \"  5) View Logs\"\n        echo \"  6) View Status\"\n        echo \"  7) Service Info\"\n        echo \"  8) Clean All Containers\"\n        echo \"  9) Pull Images\"\n        echo \"  0) Exit\"\n        echo \"\"\n        read -p \"Select operation [0-9]: \" choice\n        \n        case $choice in\n            1)\n                select_service_menu \"start\" \"Start\"\n                ;;\n            2)\n                select_service_menu \"stop\" \"Stop\"\n                ;;\n            3)\n                select_service_menu \"restart\" \"Restart\"\n                ;;\n            4)\n                select_service_menu \"remove\" \"Remove\"\n                ;;\n            5)\n                select_service_menu \"logs\" \"View Logs\"\n                ;;\n            6)\n                show_status\n                ;;\n            7)\n                show_service_info\n                ;;\n            8)\n                read -p \"Confirm removing all goframe containers? [y/N]: \" confirm\n                if [[ \"$confirm\" =~ ^[Yy]$ ]]; then\n                    clean_all\n                fi\n                ;;\n            9)\n                select_service_menu \"pull\" \"Pull Images\"\n                ;;\n            0)\n                echo \"Goodbye!\"\n                exit 0\n                ;;\n            *)\n                print_error \"Invalid selection\"\n                ;;\n        esac\n    done\n}\n\n# Main function\nmain() {\n    check_docker\n    \n    if [ $# -eq 0 ]; then\n        interactive_menu\n        exit 0\n    fi\n    \n    local command=$1\n    local target=$2\n    local extra=$3\n    \n    case $command in\n        start)\n            if [ -z \"$target\" ]; then\n                print_error \"Please specify service name or service group\"\n                exit 1\n            fi\n            if is_compose_service \"$target\"; then\n                start_compose_service \"$target\"\n            else\n                for service in $(parse_services \"$target\"); do\n                    start_service \"$service\"\n                done\n            fi\n            ;;\n        stop)\n            if [ -z \"$target\" ]; then\n                print_error \"Please specify service name or service group\"\n                exit 1\n            fi\n            if is_compose_service \"$target\"; then\n                stop_compose_service \"$target\"\n            else\n                for service in $(parse_services \"$target\"); do\n                    stop_service \"$service\"\n                done\n            fi\n            ;;\n        restart)\n            if [ -z \"$target\" ]; then\n                print_error \"Please specify service name or service group\"\n                exit 1\n            fi\n            if is_compose_service \"$target\"; then\n                stop_compose_service \"$target\"\n                start_compose_service \"$target\"\n            else\n                for service in $(parse_services \"$target\"); do\n                    stop_service \"$service\"\n                    start_service \"$service\"\n                done\n            fi\n            ;;\n        remove|rm)\n            if [ -z \"$target\" ]; then\n                print_error \"Please specify service name or service group\"\n                exit 1\n            fi\n            for service in $(parse_services \"$target\"); do\n                remove_service \"$service\"\n            done\n            ;;\n        logs)\n            if [ -z \"$target\" ]; then\n                print_error \"Please specify service name\"\n                exit 1\n            fi\n            logs_service \"$target\" \"${extra:-100}\"\n            ;;\n        status|ps)\n            show_status\n            ;;\n        info|list)\n            show_service_info\n            ;;\n        clean)\n            clean_all\n            ;;\n        pull)\n            pull_images \"$target\"\n            ;;\n        help|--help|-h)\n            show_help\n            ;;\n        *)\n            print_error \"Unknown command: $command\"\n            show_help\n            exit 1\n            ;;\n    esac\n}\n\nmain \"$@\"\n"
  },
  {
    "path": ".github/workflows/scripts/replace_examples_gomod.sh",
    "content": "#!/usr/bin/env bash\n\n# Get the absolute path to the repository root\nrepo_root=$(pwd)\nworkdir=$repo_root/examples\n\necho \"Prepare to process go.mod files in the ${workdir} directory\"\n\n# Check if examples directory exists\nif [ ! -d \"${workdir}\" ]; then\n    echo \"Error: examples directory not found at ${workdir}\"\n    exit 1\nfi\n\n# Check if find command is available\nif ! command -v find &> /dev/null; then\n    echo \"Error: find command not found!\"\n    exit 1\nfi\n\nfor file in `find ${workdir} -name go.mod`; do\n    goModPath=$(dirname $file)\n    echo \"\"\n    echo \"Processing dir: $goModPath\"\n\n    # Calculate relative path to root\n    # First get the relative path from go.mod to repo root\n    relativePath=\"\"\n    current=\"$goModPath\"\n    while [ \"$current\" != \"$repo_root\" ]; do\n        relativePath=\"../$relativePath\"\n        current=$(dirname \"$current\")\n    done\n    relativePath=${relativePath%/}  # Remove trailing slash\n    echo \"Relative path to root: $relativePath\"\n\n    # Get all github.com/gogf/gf dependencies\n    # Use awk to get package names without version numbers\n    dependencies=$(awk '/^[[:space:]]*github\\.com\\/gogf\\/gf\\// {print $1}' \"$file\" | sort -u)\n    \n    if [ -n \"$dependencies\" ]; then\n        echo \"Found GoFrame dependencies:\"\n        echo \"$dependencies\"\n        echo \"Adding replace directives...\"\n\n        # Create temporary file\n        temp_file=\"${file}.tmp\"\n        # Remove existing replace directives and copy to temp file\n        sed '/^replace.*github\\.com\\/gogf\\/gf.*/d' \"$file\" > \"$temp_file\"\n        \n        # Add new replace block\n        echo \"\" >> \"$temp_file\"\n        echo \"replace (\" >> \"$temp_file\"\n        \n        while IFS= read -r dep; do\n            # Skip empty lines\n            [ -z \"$dep\" ] && continue\n            \n            # Calculate the relative path for the replacement\n            if [[ \"$dep\" == \"github.com/gogf/gf/v2\" ]]; then\n                replacement=\"$relativePath\"\n            else\n                # Extract the path after v2 and remove trailing version\n                subpath=$(echo \"$dep\" | sed -E 's/github\\.com\\/gogf\\/gf\\/(contrib\\/[^/]+\\/[^/]+)\\/v2.*/\\1/')\n                replacement=\"$relativePath/$subpath\"\n            fi\n            \n            echo \"    $dep => $replacement/\" >> \"$temp_file\"\n        done <<< \"$dependencies\"\n        \n        echo \")\" >> \"$temp_file\"\n        \n        # Replace original file with temporary file\n        mv \"$temp_file\" \"$file\"\n        echo \"Replace directives added to $file\"\n    else\n        echo \"No GoFrame dependencies found in $file\"\n    fi\ndone\n\necho \"\\nAll go.mod files have been processed successfully.\"\n"
  },
  {
    "path": ".github/workflows/scripts/update_version.sh",
    "content": "#!/usr/bin/env bash\n\n# Check if the number of parameters is 2\nif [ $# -ne 2 ]; then\n    echo \"Invalid parameters, please execute in format: version.sh [directory] [version]\"\n    echo \"Example: version.sh ./contrib v1.0.0\"\n    exit 1\nfi\n\n# Check if the first parameter is a directory and exists\nif [ ! -d \"$1\" ]; then\n    echo \"Error: Directory does not exist\"\n    exit 1\nfi\n\n# Check if the second parameter starts with 'v'\nif [[ \"$2\" != v* ]]; then\n    echo \"Error: Version number does not start with 'v'\"\n    exit 1\nfi\n\nworkdir=$1\nnewVersion=$2\necho \"Preparing to replace version numbers in all go.mod files under ${workdir} directory to ${newVersion}\"\n\n\n# Check if file exists\nif [ -f \"go.work\" ]; then\n    # File exists, rename it\n    mv go.work go.work.${newVersion}\n    echo \"Backup go.work file to avoid affecting the upgrade\"\nfi\n\nfor file in `find ${workdir} -name go.mod`; do\n    goModPath=$(dirname $file)\n    echo \"\"\n    echo \"processing dir: $goModPath\"\n    cd $goModPath\n    go mod tidy\n    go list -f \"{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}\" -m all | grep \"^github.com/gogf/gf\"\n    go list -f \"{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}\" -m all | grep \"^github.com/gogf/gf\" | xargs -L1 go get -v \n    go mod tidy\n    cd -\ndone\n\nif [ -f \"go.work.${newVersion}\" ]; then\n    # File exists, rename it back\n    mv go.work.${newVersion} go.work\n    echo \"Restore go.work file\"\nfi\n"
  },
  {
    "path": ".github/workflows/tag.yml",
    "content": "name: GoFrame AutoCreating SubMod Tags\n\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\nenv:\n  TZ: Asia/Shanghai\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n  build:\n    name: Auto Creating Tags\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Github Code\n        uses: actions/checkout@v5\n      - name: Auto Creating Tags For Contrib Packages\n        run: |\n          git config --global user.email \"tagrobot@goframe.org\"\n          git config --global user.name  \"TagRobot\"\n          # auto create tags for contrib packages.\n          for file in `find contrib -name go.mod`; do\n              tag=$(dirname $file)/${{ github.ref_name }}\n              git tag $tag\n              git push origin $tag\n          done\n      - name: update dependencies\n        run: |\n          go env -w GOPRIVATE=github.com/gogf/gf\n          .github/workflows/scripts/update_version.sh ./cmd/gf ${{ github.ref_name }}\n      - name: Create Pull Request\n        uses: peter-evans/create-pull-request@v4\n        with:\n          commit-message: 'update gf cli to ${{ github.ref_name }}'\n          title: 'fix: update gf cli to ${{ github.ref_name }}'\n          base: master\n          branch: fix/${{ github.ref_name }}\n          delete-branch: true\n      - name: Commit & Push changes\n        uses: actions-js/push@master\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          branch: fix/${{ github.ref_name }}\n          author_name: TagRobot\n          author_email: tagrobot@goframe.org\n          message: 'fix: update gf cli to ${{ github.ref_name }}'\n      - name: Auto Creating Tags For cli tool\n        run: |\n          git config --global user.email \"tagrobot@goframe.org\"\n          git config --global user.name  \"TagRobot\"\n          # auto create tag for cli tool\n          for file in `find cmd -name go.mod -not -path \"*/testdata/*\"`; do\n              tag=$(dirname $file)/${{ github.ref_name }}\n              git tag $tag\n              git push origin $tag\n          done\n"
  },
  {
    "path": ".gitignore",
    "content": ".buildpath\n.hgignore.swp\n.project\n.orig\n.swp\n.idea/\n.settings/\n.vscode/\nvendor/\nbin/\n**/.DS_Store\n.test/\ncmd/gf/main\ncmd/gf/gf\ntemp/\nexample/log\ngo.work\ngo.work.sum\n!cmd/gf/go.work\n.windsurfrules\n\n# Ignore for docs\nnode_modules\n.docusaurus\noutput\n.example/\n.golangci.bck.yml\n*.exe"
  },
  {
    "path": ".gitmodules",
    "content": ""
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\nrun:\n  concurrency: 4\n  modules-download-mode: readonly\n  issues-exit-code: 2\n  tests: false\n  allow-parallel-runners: true\n  allow-serial-runners: true\nlinters:\n  default: none\n  enable:\n    - errcheck\n    - errchkjson\n    - funlen\n    - goconst\n    - gocritic\n    - govet\n    - misspell\n    - nolintlint\n    - revive\n    - staticcheck\n    - usestdlibvars\n    - whitespace\n  settings:\n    funlen:\n      lines: 340\n      statements: -1\n    goconst:\n      match-constant: false\n      min-len: 4\n      min-occurrences: 30\n      numbers: true\n      min: 5\n      max: 20\n      ignore-calls: false\n    gocritic:\n      disabled-checks:\n        - ifElseChain\n        - assignOp\n        - appendAssign\n        - singleCaseSwitch\n        - regexpMust\n        - typeSwitchVar\n        - elseif\n    govet:\n      disable:\n        - asmdecl\n        - assign\n        - atomic\n        - atomicalign\n        - bools\n        - buildtag\n        - cgocall\n        - composites\n        - copylocks\n        - deepequalerrors\n        - errorsas\n        - fieldalignment\n        - findcall\n        - framepointer\n        - httpresponse\n        - ifaceassert\n        - loopclosure\n        - lostcancel\n        - nilfunc\n        - nilness\n        - reflectvaluecompare\n        - shift\n        - shadow\n        - sigchanyzer\n        - sortslice\n        - stdmethods\n        - stringintconv\n        - structtag\n        - testinggoroutine\n        - tests\n        - unmarshal\n        - unreachable\n        - unsafeptr\n        - unusedwrite\n      enable-all: true\n      settings:\n        printf:\n          funcs:\n            - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof\n            - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf\n            - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf\n            - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf\n        unusedresult:\n          funcs:\n            - pkg.MyFunc\n            - context.WithCancel\n          stringmethods:\n            - MyMethod\n    misspell:\n      locale: US\n      ignore-rules:\n        - cancelled\n    revive:\n      severity: error\n      rules:\n        - name: atomic\n        - name: line-length-limit\n          arguments:\n            - 380\n          severity: error\n        - name: unhandled-error\n          severity: warning\n          disabled: true\n        - name: var-naming\n          arguments:\n            - - ID\n              - URL\n              - IP\n              - HTTP\n              - JSON\n              - API\n              - UID\n              - Id\n              - Api\n              - Uid\n              - Http\n              - Json\n              - Ip\n              - Url\n            - - VM\n          severity: warning\n          disabled: true\n        - name: string-format\n          arguments:\n            - - core.WriteError[1].Message\n              - /^([^A-Z]|$)/\n              - must not start with a capital letter\n            - - fmt.Errorf[0]\n              - /(^|[^\\.!?])$/\n              - must not end in punctuation\n            - - panic\n              - /^[^\\n]*$/\n              - must not contain line breaks\n          severity: warning\n          disabled: false\n        - name: function-result-limit\n          arguments:\n            - 4\n          severity: warning\n          disabled: false\n    staticcheck:\n      checks: [ \"all\",\"-S1000\",\"-S1009\",\"-S1016\",\"-S1023\",\"-S1025\",\"-S1029\",\"-S1034\",\"-S1040\",\"-SA1016\",\"-SA1019\",\"-SA1029\",\"-SA4006\",\"-SA4015\",\"-SA6003\",\"-SA9003\",\"-ST1003\",\"-QF1001\",\"-QF1002\",\"-QF1003\",\"-QF1006\",\"-QF1007\",\"-QF1008\",\"-QF1011\",\"-QF1012\",\"-ST1011\" ]\n      initialisms: [ \"ACL\", \"API\", \"ASCII\", \"CPU\", \"CSS\", \"DNS\", \"EOF\", \"GUID\", \"HTML\", \"HTTP\", \"HTTPS\", \"ID\", \"IP\", \"JSON\", \"QPS\", \"RAM\", \"RPC\", \"SLA\", \"SMTP\", \"SQL\", \"SSH\", \"TCP\", \"TLS\", \"TTL\", \"UDP\", \"UI\", \"GID\", \"UID\", \"UUID\", \"URI\", \"URL\", \"UTF8\", \"VM\", \"XML\", \"XMPP\", \"XSRF\", \"XSS\", \"SIP\", \"RTP\", \"AMQP\", \"DB\", \"TS\" ]\n      dot-import-whitelist: [ \"fmt\" ]\n      http-status-code-whitelist: [ \"200\", \"400\", \"404\", \"500\" ]\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    rules:\n      - linters:\n          - revive\n        path: _test\\.go\n        text: context.Context should be the first parameter of a function\n      - linters:\n          - revive\n        path: _test\\.go\n        text: exported func.*returns unexported type.*which can be annoying to use\n      - linters:\n          - gocritic\n        text: 'unnecessaryDefer:'\n      - linters:\n          - goconst\n        path: (.+)_test\\.go\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\nformatters:\n  enable:\n    - gci\n    - gofmt\n    - goimports\n  settings:\n    gci:\n      sections:\n        - standard\n        - blank\n        - default\n        - dot\n        - prefix(github.com/gogf/gf/v2)\n        - prefix(github.com/gogf/gf/cmd)\n        - prefix(github.com/gogf/gfcontrib)\n        - prefix(github.com/gogf/gf/example)\n      custom-order: true\n      no-lex-order: false\n    gofmt:\n      simplify: true\n      rewrite-rules:\n        - pattern: 'interface{}'\n          replacement: 'any'\n        - pattern: 'reflect.Ptr'\n          replacement: 'reflect.Pointer'\n        - pattern: 'ioutil.ReadAll'\n          replacement: 'io.ReadAll'\n        - pattern: 'ioutil.WriteFile'\n          replacement: 'os.WriteFile'\n        - pattern: 'ioutil.ReadFile'\n          replacement: 'os.ReadFile'\n        - pattern: 'ioutil.NopCloser'\n          replacement: 'io.NopCloser'\n    goimports:\n      local-prefixes:\n        - github.com/gogf/gf/v2\n  exclusions:\n    generated: lax\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": ".make_tidy.sh",
    "content": "#!/usr/bin/env bash\n\n# Function to run sed in-place with OS-specific options\nsed_replace() {\n    if [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n        # macOS - requires empty string after -i\n        sed -i '' \"$@\"\n    else\n        # Linux/Windows Git Bash\n        sed -i \"$@\"\n    fi\n}\n\nworkdir=.\necho \"Prepare to tidy all go.mod files in the ${workdir} directory\"\n\n# check find command support or not\noutput=$(find \"${workdir}\" -name go.mod 2>&1)\nif [[ $? -ne 0 ]]; then\n    echo \"Error: please use bash or zsh to run!\"\n    exit 1\nfi\n\nfor file in `find ${workdir} -name go.mod`; do\n    goModPath=$(dirname $file)\n    echo \"\"\n    echo \"processing dir: $goModPath\"\n\n    if [[ $goModPath =~ \"/testdata/\" ]]; then\n        echo \"ignore testdata path $goModPath\"\n        continue 1\n    fi\n\n    if [[ $goModPath =~ \"/examples/\" ]]; then\n        echo \"ignore examples path $goModPath\"\n        continue 1\n    fi\n\n    cd $goModPath\n    # Remove indirect dependencies\n    sed_replace '/\\/\\/ indirect/d' go.mod\n    go mod tidy\n    # Remove toolchain line if exists\n    sed_replace '/^toolchain/d' go.mod\n    cd - > /dev/null\ndone\n"
  },
  {
    "path": ".make_version.sh",
    "content": "#!/usr/bin/env bash\n\n# Function to run sed in-place with OS-specific options\nsed_replace() {\n    if [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n        # macOS - requires empty string after -i\n        sed -i '' \"$@\"\n    else\n        # Linux/Windows Git Bash\n        sed -i \"$@\"\n    fi\n}\n\nif [ $# -ne 2 ]; then\n    echo \"Parameter exception, please execute in the format of $0 [directory] [version number]\"\n    echo \"PS：$0 ./ v2.4.0\"\n    exit 1\nfi\n\nif [ ! -d \"$1\" ]; then\n    echo \"Error: Directory does not exist\"\n    exit 1\nfi\n\nif [[ \"$2\" != v* ]]; then\n    echo \"Error: Version number must start with v\"\n    exit 1\nfi\n\nworkdir=.\nnewVersion=$2\necho \"Prepare to replace the GoFrame library version numbers in all go.mod files in the ${workdir} directory with ${newVersion}\"\n\n# check find command support or not\noutput=$(find \"${workdir}\" -name go.mod 2>&1)\nif [[ $? -ne 0 ]]; then\n    echo \"Error: please use bash or zsh to run!\"\n    exit 1\nfi\n\nif [[ true ]]; then\n    # Use sed to replace the version number in version.go\n    sed_replace 's/VERSION = \".*\"/VERSION = \"'${newVersion}'\"/' version.go\n\n    # Use sed to replace the version number in README.MD\n    sed_replace 's/version=[^\"]*/version='${newVersion}'/' README.MD\n    sed_replace 's/version=[^\"]*/version='${newVersion}'/' README.zh_CN.MD\nfi\n\nif [ -f \"go.work\" ]; then\n    mv go.work go.work.version.bak\n    echo \"Back up the go.work file to avoid affecting the upgrade\"\nfi\n\nfor file in `find ${workdir} -name go.mod`; do\n    goModPath=$(dirname $file)\n    echo \"\"\n    echo \"processing dir: $goModPath\"\n\n    if [[ $goModPath =~ \"/testdata/\" ]]; then\n        echo \"ignore testdata path $goModPath\"\n        continue 1\n    fi\n\n    if [[ $goModPath =~ \"/examples/\" ]]; then\n        echo \"ignore examples path $goModPath\"\n        continue 1\n    fi\n\n    cd $goModPath\n\n    # Add replace directive for local development.\n    if [ $goModPath = \"./cmd/gf\" ]; then\n        mv go.work go.work.version.bak\n        go mod edit -replace github.com/gogf/gf/v2=../../\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/clickhouse/v2=../../contrib/drivers/clickhouse\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/mssql/v2=../../contrib/drivers/mssql\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/mysql/v2=../../contrib/drivers/mysql\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/oracle/v2=../../contrib/drivers/oracle\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/pgsql/v2=../../contrib/drivers/pgsql\n        go mod edit -replace github.com/gogf/gf/contrib/drivers/sqlite/v2=../../contrib/drivers/sqlite\n    fi\n    # Remove indirect dependencies\n    sed_replace '/\\/\\/ indirect/d' go.mod\n    go mod tidy\n    # Remove toolchain line if exists\n    sed_replace '/^toolchain/d' go.mod\n\n    # Upgrading only GoFrame related libraries, sometimes even if a version number is specified,\n    # it may not be possible to successfully upgrade. Please confirm before submitting the code\n    go list -f \"{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}\" -m all | grep \"^github.com/gogf/gf\"\n    go list -f \"{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}\" -m all | grep \"^github.com/gogf/gf\" | xargs -L1 go get -v\n    # Remove indirect dependencies\n    sed_replace '/\\/\\/ indirect/d' go.mod\n    go mod tidy\n    # Remove toolchain line if exists\n    sed_replace '/^toolchain/d' go.mod\n    if [ $goModPath = \"./cmd/gf\" ]; then\n        go mod edit -dropreplace github.com/gogf/gf/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/clickhouse/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/mssql/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/mysql/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/oracle/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/pgsql/v2\n        go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/sqlite/v2\n        mv go.work.version.bak go.work\n    fi\n    cd -\ndone\n\nif [ -f \"go.work.version.bak\" ]; then\n    mv go.work.version.bak go.work\n    echo \"Restore the go.work file\"\nfi"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for taking the time to join our community and start contributing!\n\n## With issues\n\n- Use the search tool before opening a new issue.\n- Please provide source code and commit sha if you found a bug.\n- Review existing issues and provide feedback or react to them.\n\n## With pull requests\n\n- Open your pull request against `master`\n- Your pull request should have no more than two commits, if not you should squash them.\n- It should pass all tests in the available continuous integrations systems such as GitHub CI.\n- You should add/modify tests to cover your proposed code changes.\n- If your pull request contains a new feature, please document it on the README.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 GoFrame Team https://goframe.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "SHELL := /bin/bash\n\n# execute \"go mod tidy\" on all folders that have go.mod file\n.PHONY: tidy\ntidy:\n\t./.make_tidy.sh\n\n# execute \"golangci-lint\" to check code style\n# go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest\n.PHONY: lint\nlint:\n\tgolangci-lint run -c .golangci.yml\n\n# make branch to=v2.4.0\n.PHONY: branch\nbranch:\n\t@set -e; \\\n\tnewVersion=$(to); \\\n\tif [ -z \"$$newVersion\" ]; then \\\n\t\techo \"Error: 'to' variable is required. Usage: make branch to=vX.Y.Z\"; \\\n\t\texit 1; \\\n\tfi; \\\n\tbranchName=fix/$$newVersion; \\\n\techo \"Switching to master branch...\"; \\\n\tgit checkout master; \\\n\techo \"Pulling latest changes from master...\"; \\\n\tgit pull origin master; \\\n\techo \"Creating and switching to branch $$branchName from master...\"; \\\n\tgit checkout -b $$branchName; \\\n\techo \"Branch $$branchName created successfully!\"\n\n# make version to=v2.4.0\n.PHONY: version\nversion:\n\t@set -e; \\\n\tnewVersion=$(to); \\\n\t./.make_version.sh ./ $$newVersion; \\\n\techo \"make version to=$(to) done\"\n\n# make tag to=v2.4.0\n.PHONY: tag\ntag:\n\t@set -e; \\\n\tnewVersion=$(to); \\\n\techo \"Switching to master branch...\"; \\\n\tgit checkout master; \\\n\techo \"Pulling latest changes from master...\"; \\\n\tgit pull origin master; \\\n\techo \"Creating annotated tag $$newVersion...\"; \\\n\tgit tag -a $$newVersion -m \"Release $$newVersion\"; \\\n\techo \"Pushing tag $$newVersion...\"; \\\n\tgit push origin $$newVersion; \\\n\techo \"Tag $$newVersion created and pushed successfully!\"\n\n# manage docker services for local development\n# usage: make docker or make docker cmd=start svc=mysql\n.PHONY: docker\ndocker:\n\t@if [ -z \"$(cmd)\" ]; then \\\n\t\t./.github/workflows/scripts/docker-services.sh; \\\n\telse \\\n\t\t./.github/workflows/scripts/docker-services.sh $(cmd) $(svc) $(extra); \\\n\tfi\n"
  },
  {
    "path": "README.MD",
    "content": "English | [简体中文](README.zh_CN.MD)\n\n<div align=center>\n<img src=\"https://goframe.org/img/logo_full.png\" width=\"300\" alt=\"goframe logo\"/>\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/gogf/gf/v2.svg)](https://pkg.go.dev/github.com/gogf/gf/v2)\n[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/ci-main.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/ci-main.yml)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/gogf/gf/badge)](https://scorecard.dev/viewer/?uri=github.com/gogf/gf)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9233/badge)](https://bestpractices.coreinfrastructure.org/projects/9233)\n[![Go Report Card](https://goreportcard.com/badge/github.com/gogf/gf/v2)](https://goreportcard.com/report/github.com/gogf/gf/v2)\n[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf)\n[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg?style=flat)](https://github.com/gogf/gf)\n[![License](https://img.shields.io/github/license/gogf/gf.svg?style=flat)](https://github.com/gogf/gf)\n\n[![Release](https://img.shields.io/github/v/release/gogf/gf?style=flat)](https://github.com/gogf/gf/releases)\n[![GitHub pull requests](https://img.shields.io/github/issues-pr/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls)\n[![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls?q=is%3Apr+is%3Aclosed)\n[![GitHub issues](https://img.shields.io/github/issues/gogf/gf?style=flat)](https://github.com/gogf/gf/issues)\n[![GitHub closed issues](https://img.shields.io/github/issues-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/issues?q=is%3Aissue+is%3Aclosed)\n![Stars](https://img.shields.io/github/stars/gogf/gf?style=flat)\n![Forks](https://img.shields.io/github/forks/gogf/gf?style=flat)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/gogf/gf)\n\n</div>\n\nA powerful framework for faster, easier, and more efficient project development.\n\n## Installation\n\n```bash\ngo get -u github.com/gogf/gf/v2\n```\n\n## Documentation\n\n- Official Site: [https://goframe.org](https://goframe.org)\n- Official Site(en): [https://goframe.org/en](https://goframe.org/en)\n- 国内镜像: [https://goframe.org.cn](https://goframe.org.cn)\n- Mirror Site: [https://pages.goframe.org](https://pages.goframe.org)\n- Mirror Site: [Offline Docs](https://github.com/gogf/goframe.org-pdf?tab=readme-ov-file#%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC)\n- GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)\n- Doc Source: [https://github.com/gogf/gf-site](https://github.com/gogf/gf-site)\n\n## Contributors\n\n💖 [Thanks to all the contributors who made GoFrame possible](https://github.com/gogf/gf/graphs/contributors) 💖\n\n<a href=\"https://github.com/gogf/gf/graphs/contributors\">\n<img src=\"https://goframe.org/img/contributors.svg?version=v2.10.0\" alt=\"goframe contributors\"/>\n</a>\n\n## License\n\n`GoFrame` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.\n"
  },
  {
    "path": "README.zh_CN.MD",
    "content": "[English](README.MD) | 简体中文\n\n<div align=center>\n<img src=\"https://goframe.org/img/logo_full.png\" width=\"300\" alt=\"goframe logo\"/>\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/gogf/gf/v2.svg)](https://pkg.go.dev/github.com/gogf/gf/v2)\n[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/ci-main.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/ci-main.yml)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/gogf/gf/badge)](https://scorecard.dev/viewer/?uri=github.com/gogf/gf)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9233/badge)](https://bestpractices.coreinfrastructure.org/projects/9233)\n[![Go Report Card](https://goreportcard.com/badge/github.com/gogf/gf/v2)](https://goreportcard.com/report/github.com/gogf/gf/v2)\n[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf)\n[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg?style=flat)](https://github.com/gogf/gf)\n[![License](https://img.shields.io/github/license/gogf/gf.svg?style=flat)](https://github.com/gogf/gf)\n\n[![Release](https://img.shields.io/github/v/release/gogf/gf?style=flat)](https://github.com/gogf/gf/releases)\n[![GitHub pull requests](https://img.shields.io/github/issues-pr/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls)\n[![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls?q=is%3Apr+is%3Aclosed)\n[![GitHub issues](https://img.shields.io/github/issues/gogf/gf?style=flat)](https://github.com/gogf/gf/issues)\n[![GitHub closed issues](https://img.shields.io/github/issues-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/issues?q=is%3Aissue+is%3Aclosed)\n![Stars](https://img.shields.io/github/stars/gogf/gf?style=flat)\n![Forks](https://img.shields.io/github/forks/gogf/gf?style=flat)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/gogf/gf)\n\n</div>\n\n一款强大的框架，为了更快、更轻松、更高效的项目开发。\n\n## 安装\n\n```bash\ngo get -u github.com/gogf/gf/v2\n```\n\n## 文档\n\n- 官方网站: [https://goframe.org](https://goframe.org)\n- 官方网站(en): [https://goframe.org/en](https://goframe.org/en)\n- 国内镜像: [https://goframe.org.cn](https://goframe.org.cn)\n- 镜像网站: [https://pages.goframe.org](https://pages.goframe.org)\n- 镜像网站: [离线文档](https://github.com/gogf/goframe.org-pdf?tab=readme-ov-file#%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC)\n- Go包文档: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)\n- 文档源码: [https://github.com/gogf/gf-site](https://github.com/gogf/gf-site)\n\n## 贡献者\n\n💖 [感谢所有使 GoFrame 成为可能的贡献者](https://github.com/gogf/gf/graphs/contributors) 💖\n\n<a href=\"https://github.com/gogf/gf/graphs/contributors\">\n<img src=\"https://goframe.org/img/contributors.svg?version=v2.10.0\" alt=\"goframe contributors\"/>\n</a>\n\n## 许可证\n\n`GoFrame` 采用 [MIT License](LICENSE) 许可，100%开源和免费。\n"
  },
  {
    "path": "cmd/gf/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 john@goframe.org https://goframe.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "cmd/gf/Makefile",
    "content": ".DEFAULT_GOAL := pack\n\npack: pack.template-single pack.template-mono pack.template-mono-app\n\npack.template-single:\n\t@rm -fr temp\n\t@mkdir temp || exit 0\n\t@cd temp && git clone https://github.com/gogf/template-single\n\t@rm -fr temp/template-single/.git\n\t@cd temp && gf pack template-single ../internal/packed/template-single.go -n=packed -y\n\t@rm -fr temp\n\npack.template-mono:\n\t@rm -fr temp\n\t@mkdir temp || exit 0\n\t@cd temp && git clone https://github.com/gogf/template-mono\n\t@rm -fr temp/template-mono/.git\n\t@cd temp && gf pack template-mono ../internal/packed/template-mono.go -n=packed -y\n\t@rm -fr temp\n\n# Note:\n# command `sed` only works on MacOS.\n# use `grep -irl 'template-single' temp| xargs sed -i'' -e 's/template-single/template-mono-app/g'` on other platforms.\npack.template-mono-app:\n\t@rm -fr temp\n\t@mkdir temp || exit 0\n\t@cd temp && git clone https://github.com/gogf/template-single\n\t@cd temp && mv template-single template-mono-app\n\t@rm -fr temp/template-mono-app/.git\n\t@rm -fr temp/template-mono-app/.gitattributes\n\t@rm -fr temp/template-mono-app/.gitignore\n\t@rm -fr temp/template-mono-app/go.mod\n\t@rm -fr temp/template-mono-app/go.sum\n\t@grep -irl 'template-single' temp| xargs sed -i '' -e 's/template-single/template-mono-app/g'\n\t@cd temp && gf pack template-mono-app ../internal/packed/template-mono-app.go -n=packed -y\n\t@rm -fr temp"
  },
  {
    "path": "cmd/gf/README.MD",
    "content": "English | [简体中文](README.zh_CN.MD)\n\n# gf\n\n`gf` is a powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.\n\n## 1. Install\n\n## 1) PreCompiled Binary\n\nYou can also install `gf` tool using pre-built binaries: <https://github.com/gogf/gf/releases>\n\n1. `Mac` & `Linux`\n\n   ```shell\n    wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf\n   ```\n\n   > If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.\n\n2. `Windows`\n   Manually download, execute in command line it and then follow the instruction.\n\n3. Database support\n\n   |     DB     | builtin support |                                                                             remarks                                                                             |\n   | :--------: | :-------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: |\n   |   mysql    |       yes       |                                                                                -                                                                                |\n   |  mariadb   |       yes       |                                                                                -                                                                                |\n   |    tidb    |       yes       |                                                                                -                                                                                |\n   |   mssql    |       yes       |                                                                                -                                                                                |\n   |   oracle   |       yes       |                                                                                -                                                                                |\n   |   pgsql    |       yes       |                                                                                -                                                                                |\n   |   sqlite   |       yes       |                                                                                -                                                                                |\n   | sqlitecgo  |       no        | to support sqlite database on 32bit architecture systems, manually add package import to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |\n   | clickhouse |       yes       |                                                                                -                                                                                |\n   |     dm     |       no        |                              manually add package import to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building.                              |\n\n## 2) Manually Install\n\n```shell\ngo install github.com/gogf/gf/cmd/gf/v2@latest # latest version\ngo install github.com/gogf/gf/cmd/gf/v2@v2.5.5 # certain version(should be >= v2.5.5)\n```\n\n## 2. Commands\n\n```shell\n$ gf -h\nUSAGE\n    gf COMMAND [OPTION]\n\nCOMMAND\n    up         upgrade GoFrame version/tool to latest one in current project\n    env        show current Golang environment variables\n    fix        auto fixing codes after upgrading to new GoFrame version\n    run        running go codes with hot-compiled-like feature\n    gen        automatically generate go files for dao/do/entity/pb/pbentity\n    tpl        template parsing and building commands\n    init       create and initialize an empty GoFrame project\n    pack       packing any file/directory to a resource file, or a go file\n    build      cross-building go project for lots of platforms\n    docker     build docker image for current GoFrame project\n    install    install gf binary to system (might need root/admin permission)\n    version    show version information of current binary\n    doc        download https://pages.goframe.org/ to run locally\n\nOPTION\n    -y, --yes       all yes for all command without prompt ask\n    -v, --version   show version information of current binary\n    -d, --debug     show internal detailed debugging information\n    -h, --help      more information about this command\n\nADDITIONAL\n    Use \"gf COMMAND -h\" for details about a command.\n```\n\n## 3. FAQ\n\n### 1). Command `gf run` returns `pipe: too many open files`\n\nPlease use `ulimit -n 65535` to enlarge your system configuration for max open files for current terminal shell session, and then `gf run`.\n"
  },
  {
    "path": "cmd/gf/README.zh_CN.MD",
    "content": "[English](README.MD) | 简体中文\n\n# gf\n\n`gf` 是一个强大的 CLI 工具，用于便捷地构建 [GoFrame](https://goframe.org) 应用程序。\n\n## 1. 安装\n\n## 1) 预编译二进制文件\n\n您也可以使用预构建的二进制文件安装 `gf` 工具：<https://github.com/gogf/gf/releases>\n\n1. `Mac` & `Linux`\n\n   ```shell\n    wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf\n   ```\n\n   > 如果您使用 `zsh`，您可能需要通过命令 `alias gf=gf` 重命名别名以解决 `gf` 和 `git fetch` 之间的冲突。\n\n2. `Windows`\n   手动下载，在命令行中执行，然后按照说明操作。\n\n3. 数据库支持\n\n   |     数据库     | 内置支持 |                                                                             说明                                                                             |\n   | :--------: | :-------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: |\n   |   mysql    |       是       |                                                                                -                                                                                |\n   |  mariadb   |       是       |                                                                                -                                                                                |\n   |    tidb    |       是       |                                                                                -                                                                                |\n   |   mssql    |       是       |                                                                                -                                                                                |\n   |   oracle   |       是       |                                                                                -                                                                                |\n   |   pgsql    |       是       |                                                                                -                                                                                |\n   |   sqlite   |       是       |                                                                                -                                                                                |\n   | sqlitecgo  |       否        | 要在 32 位架构系统上支持 sqlite 数据库，请手动向[源代码](./internal/cmd/cmd_gen_dao.go)添加包导入并进行构建。 |\n   | clickhouse |       是        |                                                                                -                                                                                |\n   |     dm     |       否        |                              手动向[源代码](./internal/cmd/cmd_gen_dao.go)添加包导入并进行构建。                              |\n\n## 2) 手动安装\n\n```shell\ngo install github.com/gogf/gf/cmd/gf/v2@latest # 最新版本\ngo install github.com/gogf/gf/cmd/gf/v2@v2.5.5 # 特定版本(应该 >= v2.5.5)\n```\n\n## 2. 命令\n\n```shell\n$ gf -h\n用法\n    gf 命令 [选项]\n\n命令\n    up         升级项目中的 GoFrame 版本/工具到最新版本\n    env        显示当前 Golang 环境变量\n    fix        升级到新 GoFrame 版本后自动修复代码\n    run        运行 go 代码，具有热编译功能\n    gen        自动生成 dao/do/entity/pb/pbentity 的 go 文件\n    tpl        模板解析和构建命令\n    init       创建并初始化一个空的 GoFrame 项目\n    pack       将任何文件/目录打包到资源文件或 go 文件\n    build      为多个平台交叉编译 go 项目\n    docker     为当前 GoFrame 项目构建 docker 镜像\n    install    将 gf 二进制文件安装到系统(可能需要 root/admin 权限)\n    version    显示当前二进制文件的版本信息\n    doc        下载 https://pages.goframe.org/ 本地运行\n\n选项\n    -y, --yes       对所有命令都使用 yes，不再提示\n    -v, --version   显示当前二进制文件的版本信息\n    -d, --debug     显示内部详细的调试信息\n    -h, --help      显示此命令的更多信息\n\n附加信息\n    使用 \"gf 命令 -h\" 获取有关命令的详细信息。\n```\n\n## 3. 常见问题\n\n### 1). 命令 `gf run` 返回 `pipe: too many open files`\n\n请使用 `ulimit -n 65535` 扩大系统配置以增加当前终端 shell 会话的最大打开文件数，然后再运行 `gf run`。\n"
  },
  {
    "path": "cmd/gf/gfcmd/gfcmd.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gfcmd provides the management of CLI commands for `gf` tool.\npackage gfcmd\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/packed\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nconst cliFolderName = `hack`\n\n// Command manages the CLI command of `gf`.\n// This struct can be globally accessible and extended with custom struct.\ntype Command struct {\n\t*gcmd.Command\n}\n\n// Run starts running the command according the command line arguments and options.\nfunc (c *Command) Run(ctx context.Context) {\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif err, ok := exception.(error); ok {\n\t\t\t\tmlog.Print(err.Error())\n\t\t\t} else {\n\t\t\t\tpanic(gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception))\n\t\t\t}\n\t\t}\n\t}()\n\n\t// CLI configuration, using the `hack/config.yaml` in priority.\n\tif path, _ := gfile.Search(cliFolderName); path != \"\" {\n\t\tif adapter, ok := g.Cfg().GetAdapter().(*gcfg.AdapterFile); ok {\n\t\t\tif err := adapter.SetPath(path); err != nil {\n\t\t\t\tmlog.Fatal(err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// zsh alias \"git fetch\" conflicts checks.\n\thandleZshAlias()\n\n\t// -y option checks.\n\tallyes.Init()\n\n\t// just run.\n\tif err := c.RunWithError(ctx); err != nil {\n\t\t// Exit with error message and exit code 1.\n\t\t// It is very important to exit the command process with code 1.\n\t\tmlog.Fatalf(`%+v`, err)\n\t}\n}\n\n// GetCommand retrieves and returns the root command of CLI `gf`.\nfunc GetCommand(ctx context.Context) (*Command, error) {\n\troot, err := gcmd.NewFromObject(cmd.GF)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = root.AddObject(\n\t\tcmd.Up,\n\t\tcmd.Env,\n\t\tcmd.Fix,\n\t\tcmd.Run,\n\t\tcmd.Gen,\n\t\tcmd.Tpl,\n\t\tcmd.Init,\n\t\tcmd.Pack,\n\t\tcmd.Build,\n\t\tcmd.Docker,\n\t\tcmd.Install,\n\t\tcmd.Version,\n\t\tcmd.Doc,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcommand := &Command{\n\t\troot,\n\t}\n\treturn command, nil\n}\n\n// zsh alias \"git fetch\" conflicts checks.\nfunc handleZshAlias() {\n\tif runtime.GOOS == \"windows\" {\n\t\treturn\n\t}\n\tif home, err := gfile.Home(); err == nil {\n\t\tzshPath := gfile.Join(home, \".zshrc\")\n\t\tif gfile.Exists(zshPath) {\n\t\t\tvar (\n\t\t\t\taliasCommand = `alias gf=gf`\n\t\t\t\tcontent      = gfile.GetContents(zshPath)\n\t\t\t)\n\t\t\tif !gstr.Contains(content, aliasCommand) {\n\t\t\t\t_ = gfile.PutContentsAppend(zshPath, \"\\n\"+aliasCommand+\"\\n\")\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/go.mod",
    "content": "module github.com/gogf/gf/cmd/gf/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.10.0\n\tgithub.com/gogf/gf/contrib/drivers/mssql/v2 v2.10.0\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0\n\tgithub.com/gogf/gf/contrib/drivers/oracle/v2 v2.10.0\n\tgithub.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0\n\tgithub.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f\n\tgithub.com/olekukonko/tablewriter v1.1.0\n\tgithub.com/schollz/progressbar/v3 v3.15.0\n\tgolang.org/x/mod v0.25.0\n\tgolang.org/x/tools v0.26.0\n)\n\nrequire (\n\taead.dev/minisign v0.2.0 // indirect\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/ClickHouse/clickhouse-go/v2 v2.0.15 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/dustin/go-humanize v1.0.1 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/glebarez/go-sqlite v1.21.2 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-sql-driver/mysql v1.7.1 // indirect\n\tgithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect\n\tgithub.com/golang-sql/sqlexp v0.1.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/lib/pq v1.10.9 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/microsoft/go-mssqldb v1.7.1 // indirect\n\tgithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/paulmach/orb v0.7.1 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.14 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/shopspring/decimal v1.3.1 // indirect\n\tgithub.com/sijms/go-ora/v2 v2.7.10 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/crypto v0.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sync v0.14.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/term v0.32.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tmodernc.org/libc v1.22.5 // indirect\n\tmodernc.org/mathutil v1.5.0 // indirect\n\tmodernc.org/memory v1.5.0 // indirect\n\tmodernc.org/sqlite v1.23.1 // indirect\n)\n"
  },
  {
    "path": "cmd/gf/go.sum",
    "content": "aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=\naead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.0.15 h1:lLAZliqrZEygkxosLaW1qHyeTb4Ho7fVCZ0WKCpLocU=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.0.15/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=\ngithub.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=\ngithub.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=\ngithub.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=\ngithub.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.10.0 h1:9PTchr92xIJej4tq5c+HOHSU7LGOHr3YfD7tuf23LW4=\ngithub.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.10.0/go.mod h1:eKtLMs9uccxFvmoKOUCRQ/Se3nxhzEZwF0Ir13qbk5g=\ngithub.com/gogf/gf/contrib/drivers/mssql/v2 v2.10.0 h1:mBs6XpNM34IdZPZv4Kv3LA8yhP2UisbONMLfnQVFvKM=\ngithub.com/gogf/gf/contrib/drivers/mssql/v2 v2.10.0/go.mod h1:mChbF9FrmiYMSE2rG3zdxI/oSTwaHsR5KbINAgt3KcY=\ngithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0 h1:UvqxwinkelKxwdwnKUfdy51/ls4RL7MCeJqAZOVAy0I=\ngithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0/go.mod h1:6v7oGBF9wv59WERJIOJxXmLhkUcxwON3tPYW3AZ7wbY=\ngithub.com/gogf/gf/contrib/drivers/oracle/v2 v2.10.0 h1:MvhoMaz8YYj4WJuYzKGDdzJYiieiYiqp0vjoOshfOF4=\ngithub.com/gogf/gf/contrib/drivers/oracle/v2 v2.10.0/go.mod h1:vb2fx33RGhjhOaocOTEFvlEuBSGHss5S0lZ4sS3XK6E=\ngithub.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 h1:39+jbTenm7KBj4hO2C8ANAxVHpX/7OuRDs1VcGC9ylA=\ngithub.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0/go.mod h1:B0s0fVzn0W220E8UTpSGzrrGKsop5KcB90twBeLCiz0=\ngithub.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0 h1:OyAH7Ls2c9Un7CJiAq7G6eY1jWIICRkN8C5SyM94rnY=\ngithub.com/gogf/gf/contrib/drivers/sqlite/v2 v2.10.0/go.mod h1:fwhAMG0qZpeHbbP2JE78rJRfV7eBbu9jXkxTMM1lwyo=\ngithub.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=\ngithub.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=\ngithub.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=\ngithub.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=\ngithub.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=\ngithub.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=\ngithub.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=\ngithub.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=\ngithub.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=\ngithub.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/microsoft/go-mssqldb v1.7.1 h1:KU/g8aWeM3Hx7IMOFpiwYiUkU+9zeISb4+tx3ScVfsM=\ngithub.com/microsoft/go-mssqldb v1.7.1/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=\ngithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=\ngithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=\ngithub.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU=\ngithub.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=\ngithub.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=\ngithub.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/schollz/progressbar/v3 v3.15.0 h1:cNZmcNiVyea6oofBTg80ZhVXxf3wG/JoAhqCCwopkQo=\ngithub.com/schollz/progressbar/v3 v3.15.0/go.mod h1:ncBdc++eweU0dQoeZJ3loXoAc+bjaallHRIm8pVVeQM=\ngithub.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=\ngithub.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/sijms/go-ora/v2 v2.7.10 h1:GSLdj0PYYgSndhsnm7b6p32OqgnwnUZSkFb3j+htfhI=\ngithub.com/sijms/go-ora/v2 v2.7.10/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=\ngithub.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=\ngolang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=\ngolang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=\ngolang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=\ngolang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=\ngolang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=\ngolang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nmodernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=\nmodernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=\nmodernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=\nmodernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=\nmodernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=\nmodernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=\nmodernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=\n"
  },
  {
    "path": "cmd/gf/go.work",
    "content": "go 1.23.0\n\nuse ./\n\n// =====================================================================================================\n// NOTE:\n// Please update associated commands in ../../.set_version.sh if any of the follows replacements change.\n// =====================================================================================================\n\nreplace (\n\tgithub.com/gogf/gf/contrib/drivers/clickhouse/v2 => ../../contrib/drivers/clickhouse\n\tgithub.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql\n\tgithub.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle\n\tgithub.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql\n\tgithub.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite\n\tgithub.com/gogf/gf/contrib/drivers/mariadb/v2 => ../../contrib/drivers/mariadb\n\tgithub.com/gogf/gf/contrib/drivers/tidb/v2 => ../../contrib/drivers/tidb\n\tgithub.com/gogf/gf/contrib/drivers/oceanbase/v2 => ../../contrib/drivers/oceanbase\n\tgithub.com/gogf/gf/contrib/drivers/gaussdb/v2 => ../../contrib/drivers/gaussdb\n\tgithub.com/gogf/gf/v2 => ../../\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package cmd provides the management of CLI commands for `gf` tool.\npackage cmd\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/service\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// GF is the management object for `gf` command line tool.\nvar GF = cGF{}\n\ntype cGF struct {\n\tg.Meta `name:\"gf\" ad:\"{cGFAd}\"`\n}\n\nconst (\n\tcGFAd = `\nADDITIONAL\n    Use \"gf COMMAND -h\" for details about a command.\n`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cGFAd`: cGFAd,\n\t})\n}\n\ntype cGFInput struct {\n\tg.Meta  `name:\"gf\"`\n\tYes     bool `short:\"y\" name:\"yes\"     brief:\"all yes for all command without prompt ask\"   orphan:\"true\"`\n\tVersion bool `short:\"v\" name:\"version\" brief:\"show version information of current binary\"   orphan:\"true\"`\n\tDebug   bool `short:\"d\" name:\"debug\"   brief:\"show internal detailed debugging information\" orphan:\"true\"`\n}\n\ntype cGFOutput struct{}\n\nfunc (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error) {\n\t// Version.\n\tif in.Version {\n\t\t_, err = Version.Index(ctx, cVersionInput{})\n\t\treturn\n\t}\n\n\tanswer := \"n\"\n\t// No argument or option, do installation checks.\n\tif data, isInstalled := service.Install.IsInstalled(); !isInstalled {\n\t\tmlog.Print(\"hi, it seems it's the first time you installing gf cli.\")\n\t\tanswer = gcmd.Scanf(\"do you want to install gf(%s) binary to your system? [y/n]: \", gf.VERSION)\n\t} else if !data.IsSelf {\n\t\tmlog.Print(\"hi, you have installed gf cli.\")\n\t\tanswer = gcmd.Scanf(\"do you want to install gf(%s) binary to your system? [y/n]: \", gf.VERSION)\n\t}\n\tif strings.EqualFold(answer, \"y\") {\n\t\tif err = service.Install.Run(ctx); err != nil {\n\t\t\treturn\n\t\t}\n\t\tgcmd.Scan(\"press `Enter` to exit...\")\n\t\treturn\n\t}\n\n\t// Print help content.\n\tgcmd.CommandFromCtx(ctx).Print()\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_build.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gbuild\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar Build = cBuild{\n\tnodeNameInConfigFile: \"gfcli.build\",\n\tpackedGoFileName:     \"internal/packed/build_pack_data.go\",\n}\n\ntype cBuild struct {\n\tg.Meta               `name:\"build\" brief:\"{cBuildBrief}\" dc:\"{cBuildDc}\" eg:\"{cBuildEg}\" ad:\"{cBuildAd}\"`\n\tnodeNameInConfigFile string // nodeNameInConfigFile is the node name for compiler configurations in configuration file.\n\tpackedGoFileName     string // packedGoFileName specifies the file name for packing common folders into one single go file.\n}\n\nconst (\n\tcBuildDefaultFile = \"main.go\"\n\tcBuildBrief       = `cross-building go project for lots of platforms`\n\tcBuildEg          = `\ngf build main.go\ngf build main.go --ps public,template\ngf build main.go --cgo\ngf build main.go -m none \ngf build main.go -n my-app -a all -s all\ngf build main.go -n my-app -a amd64,386 -s linux -p .\ngf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin\n`\n\tcBuildDc = `\nThe \"build\" command is most commonly used command, which is designed as a powerful wrapper for \n\"go build\" command for convenience cross-compiling usage. \nIt provides much more features for building binary:\n1. Cross-Compiling for many platforms and architectures.\n2. Configuration file support for compiling.\n3. Build-In Variables.\n`\n\tcBuildAd = `\nPLATFORMS\n    aix       ppc64\n    android   386,amd64,arm,arm64\n    darwin    amd64,arm64\n    dragonfly amd64\n    freebsd   386,amd64,arm\n    illumos   amd64\n    ios       arm64\n    js        wasm\n    linux     386,amd64,arm,arm64,loong64,mips,mipsle,mips64,mips64le,ppc64,ppc64le,riscv64,s390x\n    netbsd    386,amd64,arm\n    openbsd   386,amd64,arm,arm64\n    plan9     386,amd64,arm\n    solaris   amd64\n    wasip1    wasm\n    windows   386,amd64,arm,arm64\n`\n\t// https://golang.google.cn/doc/install/source\n\tcBuildPlatforms = `\naix       ppc64\nandroid   386\nandroid   amd64\nandroid   arm\nandroid   arm64\ndarwin    amd64\ndarwin    arm64\ndragonfly amd64\nfreebsd   386\nfreebsd   amd64\nfreebsd   arm\nillumos   amd64\nios       arm64\njs        wasm\nlinux     386\nlinux     amd64\nlinux     arm\nlinux     arm64\nlinux     loong64\nlinux     mips\nlinux     mipsle\nlinux     mips64\nlinux     mips64le\nlinux     ppc64\nlinux     ppc64le\nlinux     riscv64\nlinux     s390x\nnetbsd    386\nnetbsd    amd64\nnetbsd    arm\nopenbsd   386\nopenbsd   amd64\nopenbsd   arm\nopenbsd   arm64\nplan9     386\nplan9     amd64\nplan9     arm\nsolaris   amd64\nwasip1    wasm\nwindows   386\nwindows   amd64\nwindows   arm\nwindows   arm64\n`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cBuildBrief`: cBuildBrief,\n\t\t`cBuildDc`:    cBuildDc,\n\t\t`cBuildEg`:    cBuildEg,\n\t\t`cBuildAd`:    cBuildAd,\n\t})\n}\n\ntype cBuildInput struct {\n\tg.Meta        `name:\"build\" config:\"gfcli.build\"`\n\tFile          string `name:\"FILE\" arg:\"true\"    brief:\"building file path\"`\n\tName          string `short:\"n\"  name:\"name\"    brief:\"output binary name\"`\n\tVersion       string `short:\"v\"  name:\"version\" brief:\"output binary version\"`\n\tArch          string `short:\"a\"  name:\"arch\"    brief:\"output binary architecture, multiple arch separated with ','\"`\n\tSystem        string `short:\"s\"  name:\"system\"  brief:\"output binary system, multiple os separated with ','\"`\n\tOutput        string `short:\"o\"  name:\"output\"  brief:\"output binary path, used when building single binary file\"`\n\tPath          string `short:\"p\"  name:\"path\"    brief:\"output binary directory path, default is '.'\" d:\".\"`\n\tExtra         string `short:\"e\"  name:\"extra\"   brief:\"extra custom \\\"go build\\\" options\"`\n\tMod           string `short:\"m\"  name:\"mod\"     brief:\"like \\\"-mod\\\" option of \\\"go build\\\", use \\\"-m none\\\" to disable go module\"`\n\tCgo           bool   `short:\"c\"  name:\"cgo\"     brief:\"enable or disable cgo feature, it's disabled in default\" orphan:\"true\"`\n\tVarMap        g.Map  `short:\"r\"  name:\"varMap\"  brief:\"custom built embedded variable into binary\"`\n\tPackSrc       string `short:\"ps\" name:\"packSrc\" brief:\"pack one or more folders into one go file before building\"`\n\tPackDst       string `short:\"pd\" name:\"packDst\" brief:\"temporary go file path for pack, this go file will be automatically removed after built\" d:\"internal/packed/build_pack_data.go\"`\n\tExitWhenError bool   `short:\"ew\" name:\"exitWhenError\" brief:\"exit building when any error occurs, specially for multiple arch and system buildings. default is false\" orphan:\"true\"`\n\tDumpENV       bool   `short:\"de\" name:\"dumpEnv\" brief:\"dump current go build environment before building binary\" orphan:\"true\"`\n}\n\ntype cBuildOutput struct{}\n\nfunc (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {\n\tmlog.SetHeaderPrint(true)\n\n\tmlog.Debugf(`build command input: %+v`, in)\n\t// Necessary check.\n\tif gproc.SearchBinary(\"go\") == \"\" {\n\t\tmlog.Fatalf(`command \"go\" not found in your environment, please install golang first to proceed this command`)\n\t}\n\n\tvar (\n\t\tparser = gcmd.ParserFromCtx(ctx)\n\t\tfile   = in.File\n\t)\n\tif file == \"\" {\n\t\tfile = parser.GetArg(2).String()\n\t\t// Check and use the main.go file.\n\t\tif gfile.Exists(cBuildDefaultFile) {\n\t\t\tfile = cBuildDefaultFile\n\t\t} else {\n\t\t\tmlog.Fatal(\"build file path is empty or main.go not found in current working directory\")\n\t\t}\n\t}\n\tif in.Name == \"\" {\n\t\tin.Name = gfile.Name(file)\n\t}\n\tif len(in.Name) < 1 || in.Name == \"*\" {\n\t\tmlog.Fatal(\"name cannot be empty\")\n\t}\n\tif in.Mod != \"\" && in.Mod != \"none\" {\n\t\tmlog.Debugf(`mod is %s`, in.Mod)\n\t\tif in.Extra == \"\" {\n\t\t\tin.Extra = fmt.Sprintf(`-mod=%s`, in.Mod)\n\t\t} else {\n\t\t\tin.Extra = fmt.Sprintf(`-mod=%s %s`, in.Mod, in.Extra)\n\t\t}\n\t}\n\tif in.Extra != \"\" {\n\t\tin.Extra += \" \"\n\t}\n\tvar (\n\t\tcustomSystems = gstr.SplitAndTrim(in.System, \",\")\n\t\tcustomArches  = gstr.SplitAndTrim(in.Arch, \",\")\n\t)\n\tif len(in.Version) > 0 {\n\t\tin.Path += \"/\" + in.Version\n\t}\n\t// System and arch checks.\n\tvar (\n\t\tspaceRegex  = regexp.MustCompile(`\\s+`)\n\t\tplatformMap = make(map[string]map[string]bool)\n\t)\n\tfor _, line := range strings.Split(strings.TrimSpace(cBuildPlatforms), \"\\n\") {\n\t\tline = gstr.Trim(line)\n\t\tline = spaceRegex.ReplaceAllString(line, \" \")\n\t\tvar (\n\t\t\tarray  = strings.Split(line, \" \")\n\t\t\tsystem = strings.TrimSpace(array[0])\n\t\t\tarch   = strings.TrimSpace(array[1])\n\t\t)\n\t\tif platformMap[system] == nil {\n\t\t\tplatformMap[system] = make(map[string]bool)\n\t\t}\n\t\tplatformMap[system][arch] = true\n\t}\n\t// Auto packing.\n\tif in.PackSrc != \"\" {\n\t\tif in.PackDst == \"\" {\n\t\t\tmlog.Fatal(`parameter \"packDst\" should not be empty when \"packSrc\" is used`)\n\t\t}\n\t\tif gfile.Exists(in.PackDst) && !gfile.IsFile(in.PackDst) {\n\t\t\tmlog.Fatalf(`parameter \"packDst\" path \"%s\" should be type of file not directory`, in.PackDst)\n\t\t}\n\t\tif !gfile.Exists(in.PackDst) {\n\t\t\t// Remove the go file that is automatically packed resource.\n\t\t\tdefer func() {\n\t\t\t\t_ = gfile.RemoveFile(in.PackDst)\n\t\t\t\tmlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)\n\t\t\t}()\n\t\t}\n\t\t// remove black space in separator.\n\t\tin.PackSrc, _ = gregex.ReplaceString(`,\\s+`, `,`, in.PackSrc)\n\t\tpackCmd := fmt.Sprintf(`gf pack %s %s --keepPath=true`, in.PackSrc, in.PackDst)\n\t\tmlog.Print(packCmd)\n\t\tgproc.MustShellRun(ctx, packCmd)\n\t}\n\n\t// Injected information by building flags.\n\tldFlags := fmt.Sprintf(\n\t\t`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`,\n\t\tc.getBuildInVarStr(ctx, in),\n\t)\n\n\t// start building\n\tmlog.Print(\"start building...\")\n\tif in.Cgo {\n\t\tgenv.MustSet(\"CGO_ENABLED\", \"1\")\n\t} else {\n\t\tgenv.MustSet(\"CGO_ENABLED\", \"0\")\n\t}\n\t// print used go env\n\tif in.DumpENV {\n\t\t_, _ = Env.Index(ctx, cEnvInput{})\n\t}\n\tfor system, item := range platformMap {\n\t\tif len(customSystems) > 0 && customSystems[0] != \"all\" && !gstr.InArray(customSystems, system) {\n\t\t\tcontinue\n\t\t}\n\t\tfor arch := range item {\n\t\t\tif len(customArches) > 0 && customArches[0] != \"all\" && !gstr.InArray(customArches, arch) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(customSystems) == 0 && len(customArches) == 0 {\n\t\t\t\t// Single binary building, output the binary to current working folder.\n\t\t\t\t// For example:\n\t\t\t\t// `gf build`\n\t\t\t\t// `gf build -o main.exe`\n\t\t\t\tc.doBinaryBuild(\n\t\t\t\t\tctx, file,\n\t\t\t\t\tin.Output, in.Path,\n\t\t\t\t\truntime.GOOS, runtime.GOARCH, in.Name, ldFlags, in.Extra,\n\t\t\t\t\tin.ExitWhenError,\n\t\t\t\t\ttrue,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tc.doBinaryBuild(\n\t\t\t\t\tctx, file,\n\t\t\t\t\tin.Output, in.Path,\n\t\t\t\t\tsystem, arch, in.Name, ldFlags, in.Extra,\n\t\t\t\t\tin.ExitWhenError,\n\t\t\t\t\tfalse,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// single binary building.\n\t\t\tif len(customSystems) == 0 && len(customArches) == 0 {\n\t\t\t\tgoto buildDone\n\t\t\t}\n\t\t}\n\t}\n\nbuildDone:\n\tmlog.Print(\"done!\")\n\treturn\n}\n\nfunc (c cBuild) doBinaryBuild(\n\tctx context.Context,\n\tfilePath string,\n\toutputPath, dirPath string,\n\tsystem, arch, name, ldFlags, extra string,\n\texitWhenError bool,\n\tsingleBuild bool,\n) {\n\tvar (\n\t\tcmd string\n\t\text string\n\t)\n\t// Cross-building, output the compiled binary to specified path.\n\tif system == \"windows\" {\n\t\text = \".exe\"\n\t}\n\tgenv.MustSet(\"GOOS\", system)\n\tgenv.MustSet(\"GOARCH\", arch)\n\n\tif outputPath != \"\" {\n\t\toutputPath = \"-o \" + outputPath\n\t} else {\n\t\tif dirPath == \"\" {\n\t\t\tdirPath = \".\"\n\t\t} else {\n\t\t\tdirPath = gstr.TrimRight(dirPath, \"/\")\n\t\t}\n\t\tif singleBuild {\n\t\t\toutputPath = fmt.Sprintf(\n\t\t\t\t\"-o %s/%s%s\",\n\t\t\t\tdirPath, name, ext,\n\t\t\t)\n\t\t} else {\n\t\t\toutputPath = fmt.Sprintf(\n\t\t\t\t\"-o %s/%s/%s%s\",\n\t\t\t\tdirPath, system+\"_\"+arch, name, ext,\n\t\t\t)\n\t\t}\n\t}\n\tcmd = fmt.Sprintf(\n\t\t`go build %s -ldflags \"%s\" %s%s`,\n\t\toutputPath, ldFlags, extra, filePath,\n\t)\n\tmlog.Debug(fmt.Sprintf(\"build for GOOS=%s GOARCH=%s\", system, arch))\n\tmlog.Debug(cmd)\n\t// It's not necessary printing the complete command string, filtering ldFlags.\n\tcmdShow, _ := gregex.ReplaceString(`\\s+(-ldflags \".+?\")\\s+`, \" \", cmd)\n\tmlog.Print(cmdShow)\n\tif result, err := gproc.ShellExec(ctx, cmd); err != nil {\n\t\tmlog.Printf(\n\t\t\t\"failed to build, os:%s, arch:%s, error:\\n%s\\n\\n%s\\n\",\n\t\t\tsystem, arch, gstr.Trim(result),\n\t\t\t`you may use command option \"--debug\" to enable debug info and check the details`,\n\t\t)\n\t\tif exitWhenError {\n\t\t\tos.Exit(1)\n\t\t}\n\t} else {\n\t\tmlog.Debug(gstr.Trim(result))\n\t}\n}\n\n// getBuildInVarStr retrieves and returns the custom build-in variables in configuration\n// file as json.\nfunc (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {\n\tbuildInVarMap := in.VarMap\n\tif buildInVarMap == nil {\n\t\tbuildInVarMap = make(g.Map)\n\t}\n\tbuildInVarMap[gbuild.BuiltGit] = c.getGitCommit(ctx)\n\tbuildInVarMap[gbuild.BuiltTime] = gtime.Now().String()\n\tbuildInVarMap[gbuild.BuiltVersion] = in.Version\n\tb, err := json.Marshal(buildInVarMap)\n\tif err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\treturn gbase64.EncodeToString(b)\n}\n\n// getGitCommit retrieves and returns the latest git commit hash string if present.\nfunc (c cBuild) getGitCommit(ctx context.Context) string {\n\tif gproc.SearchBinary(\"git\") == \"\" {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tcmd  = `git log -1 --format=\"%cd %H\" --date=format:\"%Y-%m-%d %H:%M:%S\"`\n\t\ts, _ = gproc.ShellExec(ctx, cmd)\n\t)\n\tmlog.Debug(cmd)\n\tif s != \"\" {\n\t\tif !gstr.Contains(s, \"fatal\") {\n\t\t\treturn gstr.Trim(s)\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_doc.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nconst (\n\tGitName    = \"gf-site\"\n\tBranchName = \"gh-pages\"\n\n\tSiteFileName = GitName + \"-\" + BranchName\n\t// DocURL is the download address of the document\n\tDocURL = \"https://github.com/gogf/\" + GitName + \"/archive/refs/heads/\" + BranchName + \".zip\"\n)\n\nvar (\n\tDoc = cDoc{}\n)\n\ntype cDoc struct {\n\tg.Meta `name:\"doc\" brief:\"download https://pages.goframe.org/ to run locally\"`\n}\n\ntype cDocInput struct {\n\tg.Meta `name:\"doc\" config:\"gfcli.doc\"`\n\tPath   string `short:\"p\"  name:\"path\"    brief:\"download docs directory path, default is \\\"%temp%/goframe\\\"\"`\n\tPort   int    `short:\"o\"  name:\"port\"    brief:\"http server port, default is 8080\" d:\"8080\"`\n\tUpdate bool   `short:\"u\"  name:\"update\"  brief:\"clean docs directory and update docs\"`\n\tClean  bool   `short:\"c\"  name:\"clean\"   brief:\"clean docs directory\"`\n\tProxy  string `short:\"x\"  name:\"proxy\"   brief:\"proxy for download, such as https://hub.gitmirror.com/;https://ghproxy.com/;https://ghproxy.net/;https://ghps.cc/\"`\n}\n\ntype cDocOutput struct{}\n\nfunc (c cDoc) Index(ctx context.Context, in cDocInput) (out *cDocOutput, err error) {\n\tdocs := NewDocSetting(ctx, in)\n\tmlog.Print(\"Directory where the document is downloaded:\", docs.TempDir)\n\tif in.Clean {\n\t\tmlog.Print(\"Cleaning document directory\")\n\t\terr = docs.Clean()\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to clean document directory:\", err)\n\t\t\treturn\n\t\t}\n\t\treturn\n\t}\n\tif in.Update {\n\t\tmlog.Print(\"Cleaning old document directory\")\n\t\terr = docs.Clean()\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to clean old document directory:\", err)\n\t\t\treturn\n\t\t}\n\t}\n\terr = docs.DownloadDoc()\n\tif err != nil {\n\t\tmlog.Print(\"Failed to download document:\", err)\n\t\treturn\n\t}\n\n\thttp.Handle(\"/\", http.FileServer(http.Dir(docs.DocDir)))\n\tmlog.Printf(\"Access address http://127.0.0.1:%d in %s\", in.Port, docs.DocDir)\n\terr = http.ListenAndServe(fmt.Sprintf(\":%d\", in.Port), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn\n}\n\n// DocSetting doc setting\ntype DocSetting struct {\n\tTempDir    string\n\tDocURL     string\n\tDocDir     string\n\tDocZipFile string\n}\n\n// NewDocSetting new DocSetting\nfunc NewDocSetting(ctx context.Context, in cDocInput) *DocSetting {\n\tfileName := SiteFileName + \".zip\"\n\ttempDir := in.Path\n\tif tempDir == \"\" {\n\t\ttempDir = gfile.Temp(\"goframe/docs\")\n\t} else {\n\t\ttempDir = gfile.Abs(path.Join(tempDir, \"docs\"))\n\t}\n\n\treturn &DocSetting{\n\t\tTempDir:    filepath.FromSlash(tempDir),\n\t\tDocDir:     filepath.FromSlash(path.Join(tempDir, SiteFileName)),\n\t\tDocURL:     in.Proxy + DocURL,\n\t\tDocZipFile: filepath.FromSlash(path.Join(tempDir, fileName)),\n\t}\n\n}\n\n// Clean cleans the temporary directory\nfunc (d *DocSetting) Clean() error {\n\tif _, err := os.Stat(d.TempDir); err == nil {\n\t\terr = gfile.RemoveAll(d.TempDir)\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to delete temporary directory:\", err)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// DownloadDoc download the document\nfunc (d *DocSetting) DownloadDoc() error {\n\tif _, err := os.Stat(d.TempDir); err != nil {\n\t\terr = gfile.Mkdir(d.TempDir)\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to create temporary directory:\", err)\n\t\t\treturn nil\n\t\t}\n\t}\n\t// Check if the file exists\n\tif _, err := os.Stat(d.DocDir); err == nil {\n\t\tmlog.Print(\"Document already exists, no need to download and unzip\")\n\t\treturn nil\n\t}\n\n\tif _, err := os.Stat(d.DocZipFile); err == nil {\n\t\tmlog.Print(\"File already exists, no need to download\")\n\t} else {\n\t\tmlog.Printf(\"File does not exist, start downloading: %s\", d.DocURL)\n\t\tstartTime := time.Now()\n\t\t// Download the file\n\t\tresp, err := http.Get(d.DocURL)\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to download file:\", err)\n\t\t\treturn err\n\t\t}\n\t\tdefer resp.Body.Close()\n\n\t\t// Create the file\n\t\tout, err := os.Create(d.DocZipFile)\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to create file:\", err)\n\t\t\treturn err\n\t\t}\n\t\tdefer out.Close()\n\n\t\t// Write the response body to the file\n\t\t_, err = io.Copy(out, resp.Body)\n\t\tif err != nil {\n\t\t\tmlog.Print(\"Failed to write file:\", err)\n\t\t\treturn err\n\t\t}\n\t\tmlog.Printf(\"Download successful, time-consuming: %v\", time.Since(startTime))\n\t}\n\n\tmlog.Print(\"Start unzipping the file...\")\n\t// Unzip the file\n\terr := gcompress.UnZipFile(d.DocZipFile, d.TempDir)\n\tif err != nil {\n\t\tmlog.Print(\"Failed to unzip the file, please run again:\", err)\n\t\t_ = gfile.RemoveFile(d.DocZipFile)\n\t\treturn err\n\t}\n\n\tmlog.Print(\"Download and unzip successful\")\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_docker.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tDocker = cDocker{}\n)\n\ntype cDocker struct {\n\tg.Meta `name:\"docker\" usage:\"{cDockerUsage}\" brief:\"{cDockerBrief}\" eg:\"{cDockerEg}\" dc:\"{cDockerDc}\"`\n}\n\nconst (\n\tcDockerUsage = `gf docker [MAIN] [OPTION]`\n\tcDockerBrief = `build docker image for current GoFrame project`\n\tcDockerEg    = `\ngf docker \ngf docker -t hub.docker.com/john/image:tag\ngf docker -p -t hub.docker.com/john/image:tag\ngf docker main.go\ngf docker main.go -t hub.docker.com/john/image:tag\ngf docker main.go -t hub.docker.com/john/image:tag\ngf docker main.go -p -t hub.docker.com/john/image:tag\ngf docker main.go -p -tp [\"hub.docker.com/john\",\"hub.docker.com/smith\"] -tn image:tag\n`\n\tcDockerDc = `\nThe \"docker\" command builds the GF project to a docker images.\nIt runs \"gf build\" firstly to compile the project to binary file.\nIt then runs \"docker build\" command automatically to generate the docker image.\nYou should have docker installed, and there must be a Dockerfile in the root of the project.\n`\n\tcDockerMainBrief        = `main file path for \"gf build\", it's \"main.go\" in default. empty string for no binary build`\n\tcDockerBuildBrief       = `binary build options before docker image build, it's \"-a amd64 -s linux\" in default`\n\tcDockerFileBrief        = `file path of the Dockerfile. it's \"manifest/docker/Dockerfile\" in default`\n\tcDockerShellBrief       = `path of the shell file which is executed before docker build`\n\tcDockerPushBrief        = `auto push the docker image to docker registry if \"-t\" option passed`\n\tcDockerTagBrief         = `full tag for this docker, pattern like \"xxx.xxx.xxx/image:tag\"`\n\tcDockerTagNameBrief     = `tag name for this docker, pattern like \"image:tag\". this option is required with TagPrefixes`\n\tcDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`\n\tcDockerExtraBrief       = `extra build options passed to \"docker image\"`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cDockerUsage`:            cDockerUsage,\n\t\t`cDockerBrief`:            cDockerBrief,\n\t\t`cDockerEg`:               cDockerEg,\n\t\t`cDockerDc`:               cDockerDc,\n\t\t`cDockerMainBrief`:        cDockerMainBrief,\n\t\t`cDockerFileBrief`:        cDockerFileBrief,\n\t\t`cDockerShellBrief`:       cDockerShellBrief,\n\t\t`cDockerBuildBrief`:       cDockerBuildBrief,\n\t\t`cDockerPushBrief`:        cDockerPushBrief,\n\t\t`cDockerTagBrief`:         cDockerTagBrief,\n\t\t`cDockerTagNameBrief`:     cDockerTagNameBrief,\n\t\t`cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,\n\t\t`cDockerExtraBrief`:       cDockerExtraBrief,\n\t})\n}\n\ntype cDockerInput struct {\n\tg.Meta      `name:\"docker\" config:\"gfcli.docker\"`\n\tMain        string   `name:\"MAIN\" arg:\"true\" brief:\"{cDockerMainBrief}\" d:\"main.go\"`\n\tFile        string   `name:\"file\"        short:\"f\"  brief:\"{cDockerFileBrief}\"  d:\"manifest/docker/Dockerfile\"`\n\tShell       string   `name:\"shell\"       short:\"s\"  brief:\"{cDockerShellBrief}\" d:\"manifest/docker/docker.sh\"`\n\tBuild       string   `name:\"build\"       short:\"b\"  brief:\"{cDockerBuildBrief}\"`\n\tTag         string   `name:\"tag\"         short:\"t\"  brief:\"{cDockerTagBrief}\"`\n\tTagName     string   `name:\"tagName\"     short:\"tn\" brief:\"{cDockerTagNameBrief}\"     v:\"required-with:TagPrefixes\"`\n\tTagPrefixes []string `name:\"tagPrefixes\" short:\"tp\" brief:\"{cDockerTagPrefixesBrief}\" v:\"required-with:TagName\"`\n\tPush        bool     `name:\"push\"        short:\"p\"  brief:\"{cDockerPushBrief}\" orphan:\"true\"`\n\tExtra       string   `name:\"extra\"       short:\"e\"  brief:\"{cDockerExtraBrief}\"`\n}\n\ntype cDockerOutput struct{}\n\nfunc (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput, err error) {\n\t// Necessary check.\n\tif gproc.SearchBinary(\"docker\") == \"\" {\n\t\tmlog.Fatalf(`command \"docker\" not found in your environment, please install docker first to proceed this command`)\n\t}\n\n\tmlog.Debugf(`docker command input: %+v`, in)\n\n\t// Binary build.\n\tif in.Main != \"\" && in.Build != \"\" {\n\t\tin.Build += \" --exitWhenError\"\n\t\tif in.Main != \"\" {\n\t\t\tif err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {\n\t\t\t\tmlog.Debugf(`build binary failed with error: %+v`, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Shell executing.\n\tif in.Shell != \"\" && gfile.Exists(in.Shell) {\n\t\tif err = c.exeDockerShell(ctx, in.Shell); err != nil {\n\t\t\tmlog.Debugf(`build docker failed with error: %+v`, err)\n\t\t\treturn\n\t\t}\n\t}\n\t// Docker build.\n\tvar (\n\t\tdockerBuildOptions string\n\t\tdockerTags         []string\n\t\tdockerTagBase      string\n\t)\n\tif len(in.TagPrefixes) > 0 {\n\t\tfor _, tagPrefix := range in.TagPrefixes {\n\t\t\ttagPrefix = gstr.TrimRight(tagPrefix, \"/\")\n\t\t\tdockerTags = append(dockerTags, fmt.Sprintf(`%s/%s`, tagPrefix, in.TagName))\n\t\t}\n\t}\n\tif len(dockerTags) == 0 {\n\t\tdockerTags = []string{in.Tag}\n\t}\n\tfor i, dockerTag := range dockerTags {\n\t\tif i > 0 {\n\t\t\terr = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tdockerTagBase = dockerTag\n\t\tdockerBuildOptions = \"\"\n\t\tif dockerTag != \"\" {\n\t\t\tdockerBuildOptions = fmt.Sprintf(`-t %s`, dockerTag)\n\t\t}\n\t\tif in.Extra != \"\" {\n\t\t\tdockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)\n\t\t}\n\t\terr = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Docker push.\n\tif !in.Push {\n\t\treturn\n\t}\n\tfor _, dockerTag := range dockerTags {\n\t\tif dockerTag == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\terr = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c cDocker) exeDockerShell(ctx context.Context, shellFilePath string) error {\n\tif gfile.ExtName(shellFilePath) == \"sh\" && runtime.GOOS == \"windows\" {\n\t\tmlog.Debugf(`ignore shell file \"%s\", as it cannot be run on windows system`, shellFilePath)\n\t\treturn nil\n\t}\n\treturn gproc.ShellRun(ctx, gfile.GetContents(shellFilePath))\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_env.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\t\"github.com/olekukonko/tablewriter/renderer\"\n\t\"github.com/olekukonko/tablewriter/tw\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tEnv = cEnv{}\n)\n\ntype cEnv struct {\n\tg.Meta `name:\"env\" brief:\"show current Golang environment variables\"`\n}\n\ntype cEnvInput struct {\n\tg.Meta `name:\"env\"`\n}\n\ntype cEnvOutput struct{}\n\nfunc (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err error) {\n\tresult, execErr := gproc.ShellExec(ctx, \"go env\")\n\t// Note: go env may return non-zero exit code when there are warnings (e.g., invalid characters in env vars),\n\t// but it still outputs valid environment variables. So we only fail if result is empty.\n\tif result == \"\" {\n\t\tif execErr != nil {\n\t\t\tmlog.Fatal(execErr)\n\t\t}\n\t\tmlog.Fatal(`retrieving Golang environment variables failed, did you install Golang?`)\n\t}\n\tvar (\n\t\tlines  = gstr.Split(result, \"\\n\")\n\t\tbuffer = bytes.NewBuffer(nil)\n\t)\n\tarray := make([][]string, 0)\n\tfor _, line := range lines {\n\t\tline = gstr.Trim(line)\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif gstr.Pos(line, \"set \") == 0 {\n\t\t\tline = line[4:]\n\t\t}\n\t\tmatch, _ := gregex.MatchString(`(.+?)=(.*)`, line)\n\t\tif len(match) < 3 {\n\t\t\t// Skip lines that don't match key=value format (e.g., warning messages from go env)\n\t\t\tmlog.Debugf(`invalid Golang environment variable: \"%s\"`, line)\n\t\t\tcontinue\n\t\t}\n\t\tarray = append(array, []string{gstr.Trim(match[1]), gstr.Trim(match[2])})\n\t}\n\ttable := tablewriter.NewTable(buffer,\n\t\ttablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{\n\t\t\tSettings: tw.Settings{\n\t\t\t\tSeparators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.On},\n\t\t\t},\n\t\t\tSymbols: tw.NewSymbols(tw.StyleASCII),\n\t\t})),\n\t\ttablewriter.WithConfig(tablewriter.Config{\n\t\t\tRow: tw.CellConfig{\n\t\t\t\tFormatting:   tw.CellFormatting{AutoWrap: tw.WrapNone},\n\t\t\t\tAlignment:    tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft}},\n\t\t\t\tColMaxWidths: tw.CellWidth{Global: 84},\n\t\t\t},\n\t\t}),\n\t)\n\ttable.Bulk(array)\n\ttable.Render()\n\tmlog.Print(buffer.String())\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_fix.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tFix = cFix{}\n)\n\ntype cFix struct {\n\tg.Meta `name:\"fix\" brief:\"auto fixing codes after upgrading to new GoFrame version\" usage:\"gf fix\" `\n}\n\ntype cFixInput struct {\n\tg.Meta  `name:\"fix\"`\n\tPath    string `name:\"path\"    short:\"p\" brief:\"directory path, it uses current working directory in default\"`\n\tVersion string `name:\"version\" short:\"v\" brief:\"custom specified version to fix, leave it empty to auto detect\"`\n}\n\ntype cFixOutput struct{}\n\ntype cFixItem struct {\n\tVersion string\n\tFunc    func(version string) error\n}\n\nfunc (c cFix) Index(ctx context.Context, in cFixInput) (out *cFixOutput, err error) {\n\n\tif in.Path == \"\" {\n\t\tin.Path = gfile.Pwd()\n\t}\n\tif in.Version == \"\" {\n\t\tin.Version, err = c.autoDetectVersion(in)\n\t\tif err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t\tif in.Version == \"\" {\n\t\t\tmlog.Print(`no GoFrame usage found, exit fixing`)\n\t\t\treturn\n\t\t}\n\t\tmlog.Debugf(`current GoFrame version auto detect \"%s\"`, in.Version)\n\t}\n\n\tif !gproc.IsChild() {\n\t\tmlog.Printf(`start auto fixing directory path \"%s\"...`, in.Path)\n\t\tdefer mlog.Print(`done!`)\n\t}\n\n\terr = c.doFix(in)\n\treturn\n}\n\nfunc (c cFix) doFix(in cFixInput) (err error) {\n\n\tvar items = []cFixItem{\n\t\t{Version: \"v2.3\", Func: c.doFixV23},\n\t\t{Version: \"v2.5\", Func: c.doFixV25},\n\t}\n\tfor _, item := range items {\n\t\tif gstr.CompareVersionGo(in.Version, item.Version) < 0 {\n\t\t\tmlog.Debugf(\n\t\t\t\t`current GoFrame or contrib package version \"%s\" is lesser than \"%s\", nothing to do`,\n\t\t\t\tin.Version, item.Version,\n\t\t\t)\n\t\t\tcontinue\n\t\t}\n\t\tif err = item.Func(in.Version); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// doFixV23 fixes code when upgrading to GoFrame v2.3.\nfunc (c cFix) doFixV23(version string) error {\n\treplaceFunc := func(path, content string) string {\n\t\t// gdb.TX from struct to interface.\n\t\tcontent = gstr.Replace(content, \"*gdb.TX\", \"gdb.TX\")\n\t\t// function name changes for package gtcp/gudp.\n\t\tif gstr.Contains(content, \"/gf/v2/net/gtcp\") || gstr.Contains(content, \"/gf/v2/net/gudp\") {\n\t\t\tcontent = gstr.ReplaceByMap(content, g.MapStrStr{\n\t\t\t\t\".SetSendDeadline\":      \".SetDeadlineSend\",\n\t\t\t\t\".SetReceiveDeadline\":   \".SetDeadlineRecv\",\n\t\t\t\t\".SetReceiveBufferWait\": \".SetBufferWaitRecv\",\n\t\t\t})\n\t\t}\n\t\treturn content\n\t}\n\treturn gfile.ReplaceDirFunc(replaceFunc, \".\", \"*.go\", true)\n}\n\n// doFixV25 fixes code when upgrading to GoFrame v2.5.\nfunc (c cFix) doFixV25(version string) (err error) {\n\treplaceFunc := func(path, content string) string {\n\t\tcontent, err = c.doFixV25Content(content)\n\t\treturn content\n\t}\n\treturn gfile.ReplaceDirFunc(replaceFunc, \".\", \"*.go\", true)\n}\n\nfunc (c cFix) doFixV25Content(content string) (newContent string, err error) {\n\tnewContent = content\n\tif gstr.Contains(content, `.BindHookHandlerByMap(`) {\n\t\tvar pattern = `\\.BindHookHandlerByMap\\((.+?), map\\[string\\]ghttp\\.HandlerFunc`\n\t\tnewContent, err = gregex.ReplaceString(\n\t\t\tpattern,\n\t\t\t`.BindHookHandlerByMap($1, map[ghttp.HookName]ghttp.HandlerFunc`,\n\t\t\tcontent,\n\t\t)\n\t}\n\treturn\n}\n\nfunc (c cFix) autoDetectVersion(in cFixInput) (string, error) {\n\tvar (\n\t\terr     error\n\t\tpath    = gfile.Join(in.Path, \"go.mod\")\n\t\tversion string\n\t)\n\tif !gfile.Exists(path) {\n\t\treturn \"\", gerror.Newf(`\"%s\" not found in current working directory`, path)\n\t}\n\terr = gfile.ReadLines(path, func(line string) error {\n\t\tarray := gstr.SplitAndTrim(line, \" \")\n\t\tif len(array) > 0 {\n\t\t\tif gstr.HasPrefix(array[0], gfPackage) {\n\t\t\t\tversion = array[1]\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\treturn version, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nvar (\n\tGen = cGen{}\n)\n\ntype cGen struct {\n\tg.Meta `name:\"gen\" brief:\"{cGenBrief}\" dc:\"{cGenDc}\"`\n\tcGenDao\n\tcGenEnums\n\tcGenCtrl\n\tcGenPb\n\tcGenPbEntity\n\tcGenService\n}\n\nconst (\n\tcGenBrief = `automatically generate go files for dao/do/entity/pb/pbentity`\n\tcGenDc    = `\nThe \"gen\" command is designed for multiple generating purposes. \nIt's currently supporting generating go files for ORM models, protobuf and protobuf entity files.\nPlease use \"gf gen dao -h\" for specified type help.\n`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cGenBrief`: cGenBrief,\n\t\t`cGenDc`:    cGenDc,\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_ctrl.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl\"\n)\n\ntype (\n\tcGenCtrl = genctrl.CGenCtrl\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_dao.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t_ \"github.com/gogf/gf/contrib/drivers/clickhouse/v2\"\n\t_ \"github.com/gogf/gf/contrib/drivers/mssql/v2\"\n\t_ \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n\t_ \"github.com/gogf/gf/contrib/drivers/oracle/v2\"\n\t_ \"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n\t_ \"github.com/gogf/gf/contrib/drivers/sqlite/v2\"\n\n\t// do not add dm in cli pre-compilation,\n\t// the dm driver does not support certain target platforms.\n\t// _ \"github.com/gogf/gf/contrib/drivers/dm/v2\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao\"\n)\n\ntype (\n\tcGenDao = gendao.CGenDao\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_enums.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genenums\"\n)\n\ntype (\n\tcGenEnums = genenums.CGenEnums\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_pb.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb\"\n\ntype (\n\tcGenPb = genpb.CGenPb\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_pbentity.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity\"\n\ntype (\n\tcGenPbEntity = genpbentity.CGenPbEntity\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_gen_service.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genservice\"\n)\n\ntype (\n\tcGenService = genservice.CGenService\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_init.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/geninit\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nvar (\n\t// Init .\n\tInit = cInit{}\n)\n\ntype cInit struct {\n\tg.Meta `name:\"init\" brief:\"{cInitBrief}\" eg:\"{cInitEg}\"`\n}\n\nconst (\n\tcInitRepoPrefix  = `github.com/gogf/`\n\tcInitMonoRepo    = `template-mono`\n\tcInitMonoRepoApp = `template-mono-app`\n\tcInitSingleRepo  = `template-single`\n\tcInitBrief       = `create and initialize an empty GoFrame project`\n\tcInitEg          = `\ngf init my-project\ngf init my-mono-repo -m\ngf init my-mono-repo -a\ngf init my-project -u\ngf init my-project -g \"github.com/myorg/myproject\"\ngf init -r github.com/gogf/template-single my-project\ngf init -r github.com/gogf/examples/httpserver/jwt my-jwt\ngf init -r github.com/gogf/gf/cmd/gf/v2@v2.9.7 mygf\ngf init -r github.com/gogf/gf/cmd/gf/v2 mygf -s\ngf init -i\n`\n\tcInitNameBrief = `\nname for the project. It will create a folder with NAME in current directory.\nThe NAME will also be the module name for the project.\n`\n\t// cInitGitDir the git directory\n\tcInitGitDir = \".git\"\n\t// cInitGitignore the gitignore file\n\tcInitGitignore = \".gitignore\"\n)\n\n// defaultTemplates is the list of predefined templates for interactive selection\nvar defaultTemplates = []struct {\n\tName string\n\tRepo string\n\tDesc string\n}{\n\t{\"template-single\", \"github.com/gogf/template-single\", \"Single project template\"},\n\t{\"template-mono\", \"github.com/gogf/template-mono\", \"Mono-repo project template\"},\n}\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cInitBrief`:     cInitBrief,\n\t\t`cInitEg`:        cInitEg,\n\t\t`cInitNameBrief`: cInitNameBrief,\n\t})\n}\n\ntype cInitInput struct {\n\tg.Meta      `name:\"init\"`\n\tName        string `name:\"NAME\" arg:\"true\" brief:\"{cInitNameBrief}\"`\n\tMono        bool   `name:\"mono\" short:\"m\" brief:\"initialize a mono-repo instead a single-repo\" orphan:\"true\"`\n\tMonoApp     bool   `name:\"monoApp\" short:\"a\" brief:\"initialize a mono-repo-app instead a single-repo\" orphan:\"true\"`\n\tUpdate      bool   `name:\"update\" short:\"u\" brief:\"update to the latest goframe version\" orphan:\"true\"`\n\tModule      string `name:\"module\" short:\"g\" brief:\"custom go module\"`\n\tRepo        string `name:\"repo\" short:\"r\" brief:\"remote repository URL for template download\"`\n\tSelectVer   bool   `name:\"select\" short:\"s\" brief:\"enable interactive version selection for remote template\" orphan:\"true\"`\n\tInteractive bool   `name:\"interactive\" short:\"i\" brief:\"enable interactive mode to select template\" orphan:\"true\"`\n}\n\ntype cInitOutput struct{}\n\nfunc (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {\n\t// Check if using remote template mode\n\tif in.Repo != \"\" || in.Interactive {\n\t\treturn c.initFromRemote(ctx, in)\n\t}\n\n\t// If no name provided and no remote mode, enter interactive mode\n\tif in.Name == \"\" {\n\t\treturn c.initInteractive(ctx, in)\n\t}\n\n\t// Default: use built-in template\n\treturn c.initFromBuiltin(ctx, in)\n}\n\n// initFromRemote initializes project from remote repository\nfunc (c cInit) initFromRemote(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {\n\trepo := in.Repo\n\tname := in.Name\n\n\t// If interactive mode and no repo specified, let user select\n\tif in.Interactive && repo == \"\" {\n\t\tvar modPath string\n\t\tvar upgradeDeps bool\n\t\trepo, name, modPath, upgradeDeps, err = interactiveSelectTemplate()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif modPath != \"\" {\n\t\t\tin.Module = modPath\n\t\t}\n\t\tif upgradeDeps {\n\t\t\tin.Update = true\n\t\t}\n\t}\n\n\tif repo == \"\" {\n\t\treturn nil, fmt.Errorf(\"repository URL is required for remote template mode\")\n\t}\n\n\t// Default name to repo basename if empty\n\tif name == \"\" {\n\t\tname = gfile.Basename(repo)\n\t\tmlog.Printf(\"Using repository basename as project name: %s\", name)\n\t}\n\n\tmlog.Print(\"initializing from remote template...\")\n\n\topts := &geninit.ProcessOptions{\n\t\tSelectVersion: in.SelectVer,\n\t\tModulePath:    in.Module,\n\t\tUpgradeDeps:   in.Update,\n\t}\n\n\tif err = geninit.Process(ctx, repo, name, opts); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmlog.Print(\"initialization done!\")\n\tif name != \"\" && name != \".\" {\n\t\tmlog.Printf(`you can now run \"cd %s && gf run main.go\" to start your journey, enjoy!`, name)\n\t}\n\treturn\n}\n\n// initFromBuiltin initializes project from built-in template\nfunc (c cInit) initFromBuiltin(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {\n\tvar overwrote = false\n\tif !gfile.IsEmpty(in.Name) && !allyes.Check() {\n\t\ts := gcmd.Scanf(`the folder \"%s\" is not empty, files might be overwrote, continue? [y/n]: `, in.Name)\n\t\tif strings.EqualFold(s, \"n\") {\n\t\t\treturn\n\t\t}\n\t\toverwrote = true\n\t}\n\tmlog.Print(\"initializing...\")\n\n\t// Create project folder and files.\n\tvar (\n\t\ttemplateRepoName string\n\t\tgitignoreFile    = in.Name + \"/\" + cInitGitignore\n\t)\n\n\tif in.Mono {\n\t\ttemplateRepoName = cInitMonoRepo\n\t} else if in.MonoApp {\n\t\ttemplateRepoName = cInitMonoRepoApp\n\t} else {\n\t\ttemplateRepoName = cInitSingleRepo\n\t}\n\n\terr = gres.Export(templateRepoName, in.Name, gres.ExportOption{\n\t\tRemovePrefix: templateRepoName,\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// build ignoreFiles from the .gitignore file\n\tignoreFiles := make([]string, 0, 10)\n\tignoreFiles = append(ignoreFiles, cInitGitDir)\n\t// in.MonoApp is a mono-repo-app, it should ignore the .gitignore file\n\tif overwrote && !in.MonoApp {\n\t\terr = gfile.ReadLines(gitignoreFile, func(line string) error {\n\t\t\t// Add only hidden files or directories\n\t\t\t// If other directories are added, it may cause the entire directory to be ignored\n\t\t\t// such as 'main' in the .gitignore file, but the path is ' D:\\main\\my-project '\n\t\t\tif line != \"\" && strings.HasPrefix(line, \".\") {\n\t\t\t\tignoreFiles = append(ignoreFiles, line)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\n\t\t// if not found the .gitignore file will skip os.ErrNotExist error\n\t\tif err != nil && !os.IsNotExist(err) {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Get template name and module name.\n\tif in.Module == \"\" {\n\t\tin.Module = gfile.Basename(gfile.RealPath(in.Name))\n\t}\n\tif in.MonoApp {\n\t\tpwd := gfile.Pwd() + string(os.PathSeparator) + in.Name\n\t\tin.Module = utils.GetImportPath(pwd)\n\t}\n\n\t// Replace template name to project name.\n\terr = gfile.ReplaceDirFunc(func(path, content string) string {\n\t\tfor _, ignoreFile := range ignoreFiles {\n\t\t\tif strings.Contains(path, ignoreFile) {\n\t\t\t\treturn content\n\t\t\t}\n\t\t}\n\t\treturn gstr.Replace(gfile.GetContents(path), cInitRepoPrefix+templateRepoName, in.Module)\n\t}, in.Name, \"*\", true)\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// Format the generated Go files.\n\tutils.GoFmt(in.Name)\n\n\t// Update the GoFrame version.\n\tif in.Update {\n\t\tmlog.Print(\"update goframe...\")\n\t\t// go get -u github.com/gogf/gf/v2@latest\n\t\tupdateCommand := `go get -u github.com/gogf/gf/v2@latest`\n\t\tif in.Name != \".\" {\n\t\t\tupdateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand)\n\t\t}\n\t\tif err = gproc.ShellRun(ctx, updateCommand); err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t\t// go mod tidy\n\t\tgomModTidyCommand := `go mod tidy`\n\t\tif in.Name != \".\" {\n\t\t\tgomModTidyCommand = fmt.Sprintf(`cd %s && %s`, in.Name, gomModTidyCommand)\n\t\t}\n\t\tif err = gproc.ShellRun(ctx, gomModTidyCommand); err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t}\n\n\tmlog.Print(\"initialization done! \")\n\tif !in.Mono {\n\t\tenjoyCommand := `gf run main.go`\n\t\tif in.Name != \".\" {\n\t\t\tenjoyCommand = fmt.Sprintf(`cd %s && %s`, in.Name, enjoyCommand)\n\t\t}\n\t\tmlog.Printf(`you can now run \"%s\" to start your journey, enjoy!`, enjoyCommand)\n\t}\n\treturn\n}\n\n// initInteractive enters interactive mode when no arguments provided\nfunc (c cInit) initInteractive(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {\n\treader := bufio.NewReader(os.Stdin)\n\n\t// Ask user which mode to use\n\tfmt.Println(\"\\nPlease select initialization mode:\")\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\tfmt.Println(\"  [1] Built-in template (default)\")\n\tfmt.Println(\"  [2] Remote template\")\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\n\tfmt.Print(\"Select mode [1-2] (default: 1): \")\n\tinput, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\tmlog.Fatalf(\"failed to read input: %v\", err)\n\t\treturn\n\t}\n\tinput = strings.TrimSpace(input)\n\n\tif input == \"2\" {\n\t\tin.Interactive = true\n\t\treturn c.initFromRemote(ctx, in)\n\t}\n\n\t// Built-in template mode\n\tfmt.Println(\"\\nPlease select project type:\")\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\tfmt.Println(\"  [1] Single project (default)\")\n\tfmt.Println(\"  [2] Mono-repo project\")\n\tfmt.Println(\"  [3] Mono-repo app\")\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\n\tfmt.Print(\"Select type [1-3] (default: 1): \")\n\tinput, err = reader.ReadString('\\n')\n\tif err != nil {\n\t\tmlog.Fatalf(\"failed to read input: %v\", err)\n\t\treturn\n\t}\n\tinput = strings.TrimSpace(input)\n\n\tswitch input {\n\tcase \"2\":\n\t\tin.Mono = true\n\tcase \"3\":\n\t\tin.MonoApp = true\n\t}\n\n\t// Get project name\n\tfor {\n\t\tfmt.Print(\"Enter project name: \")\n\t\tinput, err = reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"failed to read input: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tin.Name = strings.TrimSpace(input)\n\t\tif in.Name != \"\" {\n\t\t\tbreak\n\t\t}\n\t\tfmt.Println(\"Project name cannot be empty\")\n\t}\n\n\t// Get module path (optional)\n\tfmt.Printf(\"Enter Go module path (leave empty to use \\\"%s\\\"): \", in.Name)\n\tinput, err = reader.ReadString('\\n')\n\tif err != nil {\n\t\tmlog.Fatalf(\"failed to read input: %v\", err)\n\t\treturn\n\t}\n\tin.Module = strings.TrimSpace(input)\n\n\t// Ask about update\n\tfmt.Print(\"Update to latest GoFrame version? [y/N]: \")\n\tinput, err = reader.ReadString('\\n')\n\tif err != nil {\n\t\tmlog.Fatalf(\"failed to read input: %v\", err)\n\t\treturn\n\t}\n\tinput = strings.TrimSpace(strings.ToLower(input))\n\tin.Update = input == \"y\" || input == \"yes\"\n\n\tfmt.Println()\n\treturn c.initFromBuiltin(ctx, in)\n}\n\n// interactiveSelectTemplate prompts user to select a template interactively\nfunc interactiveSelectTemplate() (repo, name, modPath string, upgradeDeps bool, err error) {\n\treader := bufio.NewReader(os.Stdin)\n\n\t// 1. Select template\n\tfmt.Println(\"\\nPlease select a project template:\")\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\tfor i, t := range defaultTemplates {\n\t\tfmt.Printf(\"  [%d] %s - %s\\n\", i+1, t.Name, t.Desc)\n\t}\n\tfmt.Printf(\"  [%d] Custom repository URL\\n\", len(defaultTemplates)+1)\n\tfmt.Println(strings.Repeat(\"-\", 50))\n\n\tfor {\n\t\tfmt.Printf(\"Select template [1-%d]: \", len(defaultTemplates)+1)\n\t\tinput, err := reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", \"\", false, fmt.Errorf(\"failed to read template selection: %w\", err)\n\t\t}\n\t\tinput = strings.TrimSpace(input)\n\n\t\tidx, e := strconv.Atoi(input)\n\t\tif e != nil || idx < 1 || idx > len(defaultTemplates)+1 {\n\t\t\tfmt.Printf(\"Invalid selection, please enter a number between 1-%d\\n\", len(defaultTemplates)+1)\n\t\t\tcontinue\n\t\t}\n\n\t\tif idx <= len(defaultTemplates) {\n\t\t\trepo = defaultTemplates[idx-1].Repo\n\t\t\tfmt.Printf(\"Selected: %s\\n\\n\", repo)\n\t\t} else {\n\t\t\t// Custom URL\n\t\t\tfmt.Print(\"Enter repository URL: \")\n\t\t\tinput, err = reader.ReadString('\\n')\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", \"\", \"\", false, fmt.Errorf(\"failed to read repository URL: %w\", err)\n\t\t\t}\n\t\t\trepo = strings.TrimSpace(input)\n\t\t\tif repo == \"\" {\n\t\t\t\tfmt.Println(\"Repository URL cannot be empty\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tbreak\n\t}\n\n\t// 2. Enter project name\n\tfor {\n\t\tfmt.Print(\"Enter project name: \")\n\t\tinput, err := reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", \"\", false, fmt.Errorf(\"failed to read project name: %w\", err)\n\t\t}\n\t\tname = strings.TrimSpace(input)\n\t\tif name == \"\" {\n\t\t\tfmt.Println(\"Project name cannot be empty\")\n\t\t\tcontinue\n\t\t}\n\t\tbreak\n\t}\n\n\t// 3. Enter module path (optional)\n\tfmt.Printf(\"Enter Go module path (leave empty to use \\\"%s\\\"): \", name)\n\tinput, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", false, fmt.Errorf(\"failed to read module path: %w\", err)\n\t}\n\tmodPath = strings.TrimSpace(input)\n\n\t// 4. Ask about upgrade\n\tfmt.Print(\"Upgrade dependencies to latest (go get -u)? [y/N]: \")\n\tinput, err = reader.ReadString('\\n')\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", false, fmt.Errorf(\"failed to read upgrade confirmation: %w\", err)\n\t}\n\tinput = strings.TrimSpace(strings.ToLower(input))\n\tupgradeDeps = input == \"y\" || input == \"yes\"\n\n\tfmt.Println()\n\treturn repo, name, modPath, upgradeDeps, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_install.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/service\"\n)\n\nvar (\n\tInstall = cInstall{}\n)\n\ntype cInstall struct {\n\tg.Meta `name:\"install\" brief:\"install gf binary to system (might need root/admin permission)\"`\n}\n\ntype cInstallInput struct {\n\tg.Meta `name:\"install\"`\n}\n\ntype cInstallOutput struct{}\n\nfunc (c cInstall) Index(ctx context.Context, in cInstallInput) (out *cInstallOutput, err error) {\n\terr = service.Install.Run(ctx)\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_pack.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tPack = cPack{}\n)\n\ntype cPack struct {\n\tg.Meta `name:\"pack\" usage:\"{cPackUsage}\" brief:\"{cPackBrief}\" eg:\"{cPackEg}\"`\n}\n\nconst (\n\tcPackUsage = `gf pack SRC DST`\n\tcPackBrief = `packing any file/directory to a resource file, or a go file`\n\tcPackEg    = `\ngf pack public data.bin\ngf pack public,template data.bin\ngf pack public,template packed/data.go\ngf pack public,template,config packed/data.go\ngf pack public,template,config packed/data.go -n=packed -p=/var/www/my-app\ngf pack /var/www/public packed/data.go -n=packed\n`\n\tcPackSrcBrief = `source path for packing, which can be multiple source paths.`\n\tcPackDstBrief = `\ndestination file path for packed file. if extension of the filename is \".go\" and \"-n\" option is given, \nit enables packing SRC to go file, or else it packs SRC into a binary file.\n`\n\tcPackNameBrief     = `package name for output go file, it's set as its directory name if no name passed`\n\tcPackPrefixBrief   = `prefix for each file packed into the resource file`\n\tcPackKeepPathBrief = `keep the source path from system to resource file, usually for relative path`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cPackUsage`:         cPackUsage,\n\t\t`cPackBrief`:         cPackBrief,\n\t\t`cPackEg`:            cPackEg,\n\t\t`cPackSrcBrief`:      cPackSrcBrief,\n\t\t`cPackDstBrief`:      cPackDstBrief,\n\t\t`cPackNameBrief`:     cPackNameBrief,\n\t\t`cPackPrefixBrief`:   cPackPrefixBrief,\n\t\t`cPackKeepPathBrief`: cPackKeepPathBrief,\n\t})\n}\n\ntype cPackInput struct {\n\tg.Meta   `name:\"pack\" config:\"gfcli.pack\"`\n\tSrc      string `name:\"SRC\" arg:\"true\" v:\"required\" brief:\"{cPackSrcBrief}\"`\n\tDst      string `name:\"DST\" arg:\"true\" v:\"required\" brief:\"{cPackDstBrief}\"`\n\tName     string `name:\"name\"     short:\"n\" brief:\"{cPackNameBrief}\"`\n\tPrefix   string `name:\"prefix\"   short:\"p\" brief:\"{cPackPrefixBrief}\"`\n\tKeepPath bool   `name:\"keepPath\" short:\"k\" brief:\"{cPackKeepPathBrief}\" orphan:\"true\"`\n}\n\ntype cPackOutput struct{}\n\nfunc (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err error) {\n\tif gfile.Exists(in.Dst) && gfile.IsDir(in.Dst) {\n\t\tmlog.Fatalf(\"DST path '%s' cannot be a directory\", in.Dst)\n\t}\n\tif !gfile.IsEmpty(in.Dst) && !allyes.Check() {\n\t\ts := gcmd.Scanf(\"path '%s' is not empty, files might be overwrote, continue? [y/n]: \", in.Dst)\n\t\tif strings.EqualFold(s, \"n\") {\n\t\t\treturn\n\t\t}\n\t}\n\tif in.Name == \"\" && gfile.ExtName(in.Dst) == \"go\" {\n\t\tin.Name = gfile.Basename(gfile.Dir(in.Dst))\n\t}\n\tvar option = gres.Option{\n\t\tPrefix:   in.Prefix,\n\t\tKeepPath: in.KeepPath,\n\t}\n\tif in.Name != \"\" {\n\t\tif err = gres.PackToGoFileWithOption(in.Src, in.Dst, in.Name, option); err != nil {\n\t\t\tmlog.Fatalf(\"pack failed: %v\", err)\n\t\t}\n\t} else {\n\t\tif err = gres.PackToFileWithOption(in.Src, in.Dst, option); err != nil {\n\t\t\tmlog.Fatalf(\"pack failed: %v\", err)\n\t\t}\n\t}\n\tmlog.Print(\"done!\")\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_run.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar Run = cRun{}\n\ntype cRun struct {\n\tg.Meta `name:\"run\" usage:\"{cRunUsage}\" brief:\"{cRunBrief}\" eg:\"{cRunEg}\" dc:\"{cRunDc}\"`\n}\n\ntype watchPath struct {\n\tPath      string\n\tRecursive bool\n}\n\ntype cRunApp struct {\n\tFile           string   // Go run file name.\n\tPath           string   // Directory storing built binary.\n\tOptions        string   // Extra \"go run\" options.\n\tArgs           string   // Custom arguments.\n\tWatchPaths     []string // Watch paths for live reload.\n\tIgnorePatterns []string // Custom ignore patterns.\n}\n\nconst (\n\tcRunUsage = `gf run FILE [OPTION]`\n\tcRunBrief = `running go codes with hot-compiled-like feature`\n\tcRunEg    = `\ngf run main.go\ngf run main.go --args \"server -p 8080\"\ngf run main.go -mod=vendor\ngf run main.go -w internal,api\ngf run main.go -i \".git,node_modules\"\n`\n\tcRunDc = `\nThe \"run\" command is used for running go codes with hot-compiled-like feature,\nwhich compiles and runs the go codes asynchronously when codes change.\n`\n\tcRunFileBrief          = `building file path.`\n\tcRunPathBrief          = `output directory path for built binary file. it's \"./\" in default`\n\tcRunExtraBrief         = `the same options as \"go run\"/\"go build\" except some options as follows defined`\n\tcRunArgsBrief          = `custom arguments for your process`\n\tcRunWatchPathsBrief    = `watch additional paths for live reload, separated by \",\". i.e. \"internal,api\"`\n\tcRunIgnorePatternBrief = `custom ignore patterns for watch, separated by \",\". i.e. \".git,node_modules\". default patterns: node_modules, vendor, .*, _*. Glob syntax: \"*\" matches any chars, \"?\" matches single char, \"[abc]\" matches char class. Note: patterns match directory names only, not paths`\n)\n\nvar process *gproc.Process\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cRunUsage`:              cRunUsage,\n\t\t`cRunBrief`:              cRunBrief,\n\t\t`cRunEg`:                 cRunEg,\n\t\t`cRunDc`:                 cRunDc,\n\t\t`cRunFileBrief`:          cRunFileBrief,\n\t\t`cRunPathBrief`:          cRunPathBrief,\n\t\t`cRunExtraBrief`:         cRunExtraBrief,\n\t\t`cRunArgsBrief`:          cRunArgsBrief,\n\t\t`cRunWatchPathsBrief`:    cRunWatchPathsBrief,\n\t\t`cRunIgnorePatternBrief`: cRunIgnorePatternBrief,\n\t})\n}\n\ntype (\n\tcRunInput struct {\n\t\tg.Meta         `name:\"run\" config:\"gfcli.run\"`\n\t\tFile           string   `name:\"FILE\"           arg:\"true\" brief:\"{cRunFileBrief}\" v:\"required\"`\n\t\tPath           string   `name:\"path\"           short:\"p\"  brief:\"{cRunPathBrief}\" d:\"./\"`\n\t\tExtra          string   `name:\"extra\"          short:\"e\"  brief:\"{cRunExtraBrief}\"`\n\t\tArgs           string   `name:\"args\"           short:\"a\"  brief:\"{cRunArgsBrief}\"`\n\t\tWatchPaths     []string `name:\"watchPaths\"     short:\"w\"  brief:\"{cRunWatchPathsBrief}\"`\n\t\tIgnorePatterns []string `name:\"ignorePatterns\" short:\"i\"  brief:\"{cRunIgnorePatternBrief}\"`\n\t}\n\tcRunOutput struct{}\n)\n\nfunc (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err error) {\n\tif !gfile.Exists(in.File) {\n\t\tmlog.Fatalf(`given file \"%s\" not found`, in.File)\n\t}\n\tif !gfile.IsFile(in.File) {\n\t\tmlog.Fatalf(`given \"%s\" is not a file`, in.File)\n\t}\n\t// Necessary check.\n\tif gproc.SearchBinary(\"go\") == \"\" {\n\t\tmlog.Fatalf(`command \"go\" not found in your environment, please install golang first to proceed this command`)\n\t}\n\n\t// Parse comma-separated values in WatchPaths\n\tif len(in.WatchPaths) > 0 {\n\t\tin.WatchPaths = parseCommaSeparatedArgs(in.WatchPaths)\n\t\tmlog.Printf(\"watchPaths: %v\", in.WatchPaths)\n\t}\n\n\t// Parse comma-separated values in IgnorePatterns\n\tif len(in.IgnorePatterns) > 0 {\n\t\tin.IgnorePatterns = parseCommaSeparatedArgs(in.IgnorePatterns)\n\t\tmlog.Printf(\"ignorePatterns: %v\", in.IgnorePatterns)\n\t}\n\n\tapp := &cRunApp{\n\t\tFile:           in.File,\n\t\tPath:           filepath.FromSlash(in.Path),\n\t\tOptions:        in.Extra,\n\t\tArgs:           in.Args,\n\t\tWatchPaths:     in.WatchPaths,\n\t\tIgnorePatterns: in.IgnorePatterns,\n\t}\n\tdirty := gtype.NewBool()\n\n\toutputPath := app.genOutputPath()\n\tcallbackFunc := func(event *gfsnotify.Event) {\n\t\tif !event.IsWrite() && !event.IsCreate() && !event.IsRemove() && !event.IsRename() {\n\t\t\treturn\n\t\t}\n\n\t\t// Check if the file extension is 'go'.\n\t\tif gfile.ExtName(event.Path) != \"go\" {\n\t\t\treturn\n\t\t}\n\n\t\t// Variable `dirty` is used for running the changes only one in one second.\n\t\tif !dirty.Cas(false, true) {\n\t\t\treturn\n\t\t}\n\n\t\t// With some delay in case of multiple code changes in very short interval.\n\t\tgtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {\n\t\t\tdefer dirty.Set(false)\n\t\t\tmlog.Printf(`watched file changes: %s`, event.String())\n\t\t\tapp.Run(ctx, outputPath)\n\t\t})\n\t}\n\n\t// Get directories to watch (recursive or non-recursive monitoring).\n\twatchPaths := app.getWatchPaths()\n\tfor _, wp := range watchPaths {\n\t\toption := gfsnotify.WatchOption{NoRecursive: !wp.Recursive}\n\t\t_, err = gfsnotify.Add(wp.Path, callbackFunc, option)\n\t\tif err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t}\n\n\tgo app.Run(ctx, outputPath)\n\n\tgproc.AddSigHandlerShutdown(func(sig os.Signal) {\n\t\tapp.End(ctx, sig, outputPath)\n\t\tos.Exit(0)\n\t})\n\tgproc.Listen()\n\n\tselect {}\n}\n\nfunc (app *cRunApp) Run(ctx context.Context, outputPath string) {\n\t// Rebuild and run the codes.\n\tmlog.Printf(\"build: %s\", app.File)\n\n\t// In case of `pipe: too many open files` error.\n\t// Build the app.\n\tbuildCommand := fmt.Sprintf(\n\t\t`go build -o %s %s %s`,\n\t\toutputPath,\n\t\tapp.Options,\n\t\tapp.File,\n\t)\n\tmlog.Print(buildCommand)\n\tresult, err := gproc.ShellExec(ctx, buildCommand)\n\tif err != nil {\n\t\tmlog.Printf(\"build error: \\n%s%s\", result, err.Error())\n\t\treturn\n\t}\n\t// Kill the old process if build successfully.\n\tif process != nil {\n\t\tif err := process.Kill(); err != nil {\n\t\t\tmlog.Debugf(\"kill process error: %s\", err.Error())\n\t\t}\n\t}\n\t// Run the binary file.\n\trunCommand := fmt.Sprintf(`%s %s`, outputPath, app.Args)\n\tmlog.Print(runCommand)\n\tif runtime.GOOS == \"windows\" {\n\t\t// Special handling for windows platform.\n\t\t// DO NOT USE \"cmd /c\" command.\n\t\tprocess = gproc.NewProcess(outputPath, strings.Fields(app.Args))\n\t} else {\n\t\tprocess = gproc.NewProcessCmd(runCommand, nil)\n\t}\n\tif pid, err := process.Start(ctx); err != nil {\n\t\tmlog.Printf(\"build running error: %s\", err.Error())\n\t} else {\n\t\tmlog.Printf(\"build running pid: %d\", pid)\n\t}\n}\n\nfunc (app *cRunApp) End(ctx context.Context, sig os.Signal, outputPath string) {\n\t// Delete the binary file.\n\t// firstly, kill the process.\n\tif process != nil {\n\t\tif sig != nil && runtime.GOOS != \"windows\" {\n\t\t\tif err := process.Signal(sig); err != nil {\n\t\t\t\tmlog.Debugf(\"send signal to process error: %s\", err.Error())\n\t\t\t\tif err := process.Kill(); err != nil {\n\t\t\t\t\tmlog.Debugf(\"kill process error: %s\", err.Error())\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twaitCtx, cancel := context.WithTimeout(ctx, 30*time.Second)\n\t\t\t\tdefer cancel()\n\t\t\t\tdone := make(chan error, 1)\n\t\t\t\tgo func() {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-waitCtx.Done():\n\t\t\t\t\t\tdone <- waitCtx.Err()\n\t\t\t\t\tcase done <- process.Wait():\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\terr := <-done\n\t\t\t\tif err != nil {\n\t\t\t\t\tmlog.Debugf(\"process wait error: %s\", err.Error())\n\t\t\t\t\tif err := process.Kill(); err != nil {\n\t\t\t\t\t\tmlog.Debugf(\"kill process error: %s\", err.Error())\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmlog.Debug(\"process exited gracefully\")\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif err := process.Kill(); err != nil {\n\t\t\t\tmlog.Debugf(\"kill process error: %s\", err.Error())\n\t\t\t}\n\t\t}\n\t}\n\tif err := gfile.RemoveFile(outputPath); err != nil {\n\t\tmlog.Printf(\"delete binary file error: %s\", err.Error())\n\t} else {\n\t\tmlog.Printf(\"deleted binary file: %s\", outputPath)\n\t}\n}\n\nfunc (app *cRunApp) genOutputPath() (outputPath string) {\n\toutputPath = gfile.Join(app.Path, gfile.Name(app.File))\n\tif runtime.GOOS == \"windows\" {\n\t\toutputPath += \".exe\"\n\t\tif gfile.Exists(outputPath) {\n\t\t\trenamePath := outputPath + \"~\"\n\t\t\tif err := gfile.Rename(outputPath, renamePath); err != nil {\n\t\t\t\tmlog.Print(err)\n\t\t\t}\n\t\t\t// Clean up the renamed old binary file\n\t\t\tdefer func() {\n\t\t\t\tif gfile.Exists(renamePath) {\n\t\t\t\t\t_ = gfile.Remove(renamePath)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\treturn filepath.FromSlash(outputPath)\n}\n\n// getWatchPaths uses DFS to find the minimal set of directories to watch.\n// Rule: if a directory and all its descendants have no ignored subdirectories, watch it;\n// otherwise, recurse into valid children and watch the current directory non-recursively.\nfunc (app *cRunApp) getWatchPaths() []watchPath {\n\troots := []string{\".\"}\n\tif len(app.WatchPaths) > 0 {\n\t\troots = app.WatchPaths\n\t}\n\n\t// Use custom ignore patterns if provided, otherwise use default.\n\tignorePatterns := defaultIgnorePatterns\n\tif len(app.IgnorePatterns) > 0 {\n\t\tignorePatterns = app.IgnorePatterns\n\t}\n\n\tvar watchPaths []watchPath\n\n\tfor _, root := range roots {\n\t\tabsRoot := gfile.RealPath(root)\n\t\tif absRoot == \"\" {\n\t\t\tmlog.Printf(\"watch path '%s' not found, skipping\", root)\n\t\t\tcontinue\n\t\t}\n\t\tif isIgnoredDirName(absRoot, ignorePatterns) {\n\t\t\tcontinue\n\t\t}\n\t\tapp.collectWatchPaths(absRoot, ignorePatterns, &watchPaths)\n\t}\n\n\tif len(watchPaths) == 0 {\n\t\tmlog.Printf(\"no directories to watch, using current directory\")\n\t\tif absCur := gfile.RealPath(\".\"); absCur != \"\" {\n\t\t\treturn []watchPath{{Path: absCur, Recursive: true}}\n\t\t}\n\t\treturn []watchPath{{Path: \".\", Recursive: true}}\n\t}\n\n\tmlog.Printf(\"watching %d paths\", len(watchPaths))\n\tfor _, wp := range watchPaths {\n\t\trecursiveStr := \"recursive\"\n\t\tif !wp.Recursive {\n\t\t\trecursiveStr = \"non-recursive\"\n\t\t}\n\t\tmlog.Debugf(\"  - %s (%s)\", wp.Path, recursiveStr)\n\t}\n\treturn watchPaths\n}\n\n// collectWatchPaths performs a DFS traversal to collect the minimal set of directories to watch.\n// Returns true if the directory or any of its descendants contains ignored directories.\n// Rule: if a directory has no ignored descendants at any depth, watch it recursively;\n// otherwise, watch it non-recursively and recurse into valid children.\nfunc (app *cRunApp) collectWatchPaths(dir string, ignorePatterns []string, watchPaths *[]watchPath) bool {\n\tentries, err := gfile.ScanDir(dir, \"*\", false)\n\tif err != nil {\n\t\tmlog.Printf(\"scan directory '%s' error: %s\", dir, err.Error())\n\t\t// If we can't scan the directory, add it to watch list as fallback\n\t\t*watchPaths = append(*watchPaths, watchPath{Path: dir, Recursive: true})\n\t\treturn false\n\t}\n\n\t// First pass: identify valid subdirectories and check for directly ignored children\n\tvar validSubDirs []string\n\thasIgnoredChild := false\n\tfor _, entry := range entries {\n\t\tif !gfile.IsDir(entry) {\n\t\t\tcontinue\n\t\t}\n\t\tif isIgnoredDirName(entry, ignorePatterns) {\n\t\t\thasIgnoredChild = true\n\t\t} else {\n\t\t\tvalidSubDirs = append(validSubDirs, entry)\n\t\t}\n\t}\n\n\t// If already has ignored child, we know this dir needs non-recursive watch\n\tif hasIgnoredChild {\n\t\t*watchPaths = append(*watchPaths, watchPath{Path: dir, Recursive: false})\n\t\tfor _, subDir := range validSubDirs {\n\t\t\tapp.collectWatchPaths(subDir, ignorePatterns, watchPaths)\n\t\t}\n\t\treturn true\n\t}\n\n\t// No ignored children, but need to check descendants recursively\n\t// Collect results from all subdirectories first\n\tsubResults := make([]bool, len(validSubDirs))\n\tsubWatchPaths := make([][]watchPath, len(validSubDirs))\n\thasIgnoredDescendant := false\n\n\tfor i, subDir := range validSubDirs {\n\t\tvar subPaths []watchPath\n\t\tsubResults[i] = app.collectWatchPaths(subDir, ignorePatterns, &subPaths)\n\t\tsubWatchPaths[i] = subPaths\n\t\tif subResults[i] {\n\t\t\thasIgnoredDescendant = true\n\t\t}\n\t}\n\n\tif !hasIgnoredDescendant {\n\t\t// No ignored descendants at any depth, watch this directory recursively\n\t\t*watchPaths = append(*watchPaths, watchPath{Path: dir, Recursive: true})\n\t\treturn false\n\t}\n\n\t// Has ignored descendants, watch current directory non-recursively\n\t// and add all collected subdirectory watch paths\n\t*watchPaths = append(*watchPaths, watchPath{Path: dir, Recursive: false})\n\tfor _, subPaths := range subWatchPaths {\n\t\t*watchPaths = append(*watchPaths, subPaths...)\n\t}\n\treturn true\n}\n\n// defaultIgnorePatterns contains glob patterns for directory names that should be ignored when watching.\n// These directories typically contain third-party code or non-source files.\n// Supported glob syntax (filepath.Match):\n//   - \"*\" matches any sequence of non-separator characters\n//   - \"?\" matches any single non-separator character\n//   - \"[abc]\" matches any character in the bracket\n//   - \"[a-z]\" matches any character in the range\n//   - \"[^abc]\" or \"[!abc]\" matches any character not in the bracket\n//\n// Note: patterns match directory base names only, not full paths (no \"/\" or path separators allowed).\nvar defaultIgnorePatterns = []string{\n\t\"node_modules\",\n\t\"vendor\",\n\t\".*\", // All hidden directories (covers .git, .svn, .hg, .idea, .vscode, etc.)\n\t\"_*\", // Directories starting with underscore\n}\n\n// isIgnoredDirName checks if a directory name matches any ignored pattern.\n// It accepts either a full path or just the directory name, but only matches against the base name.\n// Note: patterns should not contain \"/\" as they only match directory names, not paths.\nfunc isIgnoredDirName(name string, ignorePatterns []string) bool {\n\tbaseName := gfile.Basename(name)\n\tfor _, pattern := range ignorePatterns {\n\t\tif matched, _ := filepath.Match(pattern, baseName); matched {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// parseCommaSeparatedArgs parses command line arguments that may contain comma-separated values.\n// It handles both single argument with commas (e.g., \"a,b,c\") and multiple arguments.\nfunc parseCommaSeparatedArgs(args []string) []string {\n\tvar result []string\n\tfor _, arg := range args {\n\t\tparts := strings.Split(arg, \",\")\n\t\tfor _, part := range parts {\n\t\t\ttrimmed := strings.TrimSpace(part)\n\t\t\tif trimmed != \"\" {\n\t\t\t\tresult = append(result, trimmed)\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_tpl.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tTpl = cTpl{}\n)\n\ntype cTpl struct {\n\tg.Meta `name:\"tpl\" brief:\"{cTplBrief}\" dc:\"{cTplDc}\"`\n}\n\nconst (\n\tcTplBrief = `template parsing and building commands`\n\tcTplDc    = `\nThe \"tpl\" command is used for template parsing and building purpose.\nIt can parse either template file or folder with multiple types of values support,\nlike json/xml/yaml/toml/ini.\n`\n\tcTplParseBrief = `parse either template file or folder with multiple types of values`\n\tcTplParseEg    = `\ngf tpl parse -p ./template -v values.json -r\ngf tpl parse -p ./template -v values.json -n *.tpl -r\ngf tpl parse -p ./template -v values.json -d '${{,}}' -r\ngf tpl parse -p ./template -v values.json -o ./template.parsed\n`\n\tcTplSupportValuesFilePattern = `*.json,*.xml,*.yaml,*.yml,*.toml,*.ini`\n)\n\ntype (\n\tcTplParseInput struct {\n\t\tg.Meta     `name:\"parse\" config:\"gfcli.tpl.parse\" brief:\"{cTplParseBrief}\" eg:\"{cTplParseEg}\"`\n\t\tPath       string `name:\"path\"       short:\"p\" brief:\"template file or folder path\" v:\"required\"`\n\t\tPattern    string `name:\"pattern\"    short:\"n\" brief:\"template file pattern when path is a folder, default is:*\" d:\"*\"`\n\t\tRecursive  bool   `name:\"recursive\"  short:\"c\" brief:\"recursively parsing files if path is folder, default is:true\" d:\"true\"`\n\t\tValues     string `name:\"values\"     short:\"v\" brief:\"template values file/folder, support file types like: json/xml/yaml/toml/ini\" v:\"required\"`\n\t\tOutput     string `name:\"output\"     short:\"o\" brief:\"output file/folder path\"`\n\t\tDelimiters string `name:\"delimiters\" short:\"d\" brief:\"delimiters for template content parsing, default is:{{,}}\" d:\"{{,}}\"`\n\t\tReplace    bool   `name:\"replace\"    short:\"r\" brief:\"replace original files\" orphan:\"true\"`\n\t}\n\tcTplParseOutput struct{}\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cTplBrief`:      cTplBrief,\n\t\t`cTplDc`:         cTplDc,\n\t\t`cTplParseEg`:    cTplParseEg,\n\t\t`cTplParseBrief`: cTplParseBrief,\n\t})\n}\n\nfunc (c *cTpl) Parse(ctx context.Context, in cTplParseInput) (out *cTplParseOutput, err error) {\n\tif in.Output == \"\" && !in.Replace {\n\t\treturn nil, gerror.New(`parameter output and replace should not be both empty`)\n\t}\n\tdelimiters := gstr.SplitAndTrim(in.Delimiters, \",\")\n\tmlog.Debugf(\"delimiters input:%s, parsed:%#v\", in.Delimiters, delimiters)\n\tif len(delimiters) != 2 {\n\t\treturn nil, gerror.Newf(`invalid delimiters: %s`, in.Delimiters)\n\t}\n\tg.View().SetDelimiters(delimiters[0], delimiters[1])\n\tvaluesMap, err := c.loadValues(ctx, in.Values)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(valuesMap) == 0 {\n\t\treturn nil, gerror.Newf(`empty values loaded from values file/folder \"%s\"`, in.Values)\n\t}\n\terr = c.parsePath(ctx, valuesMap, in)\n\tif err == nil {\n\t\tmlog.Print(\"done!\")\n\t}\n\treturn\n}\n\nfunc (c *cTpl) parsePath(ctx context.Context, values g.Map, in cTplParseInput) (err error) {\n\tif !gfile.Exists(in.Path) {\n\t\treturn gerror.Newf(`path \"%s\" does not exist`, in.Path)\n\t}\n\tvar (\n\t\tpath         string\n\t\tfiles        []string\n\t\trelativePath string\n\t\toutputPath   string\n\t)\n\tpath = gfile.RealPath(in.Path)\n\tif gfile.IsDir(path) {\n\t\tfiles, err = gfile.ScanDirFile(path, in.Pattern, in.Recursive)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, file := range files {\n\t\t\trelativePath = gstr.Replace(file, path, \"\")\n\t\t\tif in.Output != \"\" {\n\t\t\t\toutputPath = gfile.Join(in.Output, relativePath)\n\t\t\t}\n\t\t\tif err = c.parseFile(ctx, file, outputPath, values, in); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tif in.Output != \"\" {\n\t\toutputPath = in.Output\n\t}\n\terr = c.parseFile(ctx, path, outputPath, values, in)\n\treturn\n}\n\nfunc (c *cTpl) parseFile(ctx context.Context, file string, output string, values g.Map, in cTplParseInput) (err error) {\n\toutput = gstr.ReplaceByMap(output, g.MapStrStr{\n\t\t`\\\\`: `\\`,\n\t\t`//`: `/`,\n\t})\n\tcontent, err := g.View().Parse(ctx, file, values)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif output != \"\" {\n\t\tmlog.Printf(`parse file \"%s\" to \"%s\"`, file, output)\n\t\treturn gfile.PutContents(output, content)\n\t}\n\tif in.Replace {\n\t\tmlog.Printf(`parse and replace file \"%s\"`, file)\n\t\treturn gfile.PutContents(file, content)\n\t}\n\treturn nil\n}\n\nfunc (c *cTpl) loadValues(ctx context.Context, valuesPath string) (data g.Map, err error) {\n\tif !gfile.Exists(valuesPath) {\n\t\treturn nil, gerror.Newf(`values file/folder \"%s\" does not exist`, valuesPath)\n\t}\n\tvar j *gjson.Json\n\tif gfile.IsDir(valuesPath) {\n\t\tvar valueFiles []string\n\t\tvalueFiles, err = gfile.ScanDirFile(valuesPath, cTplSupportValuesFilePattern, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata = make(g.Map)\n\t\tfor _, file := range valueFiles {\n\t\t\tif j, err = gjson.Load(file); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tgutil.MapMerge(data, j.Map())\n\t\t}\n\t\treturn\n\t}\n\tif j, err = gjson.Load(valuesPath); err != nil {\n\t\treturn nil, err\n\t}\n\tdata = j.Map()\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_up.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\n\t\"github.com/gogf/selfupdate\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nvar (\n\tUp = cUp{}\n)\n\ntype cUp struct {\n\tg.Meta `name:\"up\" brief:\"upgrade GoFrame version/tool to latest one in current project\" eg:\"{cUpEg}\" `\n}\n\nconst (\n\tgfPackage = `github.com/gogf/gf/`\n\tcUpEg     = `\ngf up\ngf up -a\ngf up -c\ngf up -cf\ngf up -a -m=install\ngf up -a -m=install -p=github.com/gogf/gf/cmd/gf/v2@latest\n`\n\tcliMethodHttpDownload = \"http\"\n\tcliMethodGoInstall    = \"install\"\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`cUpEg`: cUpEg,\n\t})\n}\n\ntype cUpInput struct {\n\tg.Meta               `name:\"up\" config:\"gfcli.up\"`\n\tAll                  bool   `name:\"all\" short:\"a\" brief:\"upgrade both version and cli, auto fix codes\" orphan:\"true\"`\n\tCli                  bool   `name:\"cli\" short:\"c\" brief:\"also upgrade CLI tool\" orphan:\"true\"`\n\tFix                  bool   `name:\"fix\" short:\"f\" brief:\"auto fix codes(it only make sense if cli is to be upgraded)\" orphan:\"true\"`\n\tCliDownloadingMethod string `name:\"cli-download-method\" short:\"m\" brief:\"cli upgrade method: http=download binary via HTTP GET, install=upgrade via go install\" d:\"http\"`\n\t// CliModulePath specifies the module path for CLI installation via go install.\n\t// This is used when CliDownloadingMethod is set to \"install\".\n\tCliModulePath string `name:\"cli-module-path\" short:\"p\" brief:\"custom cli module path for upgrade CLI tool with go install method\" d:\"github.com/gogf/gf/cmd/gf/v2@latest\"`\n}\n\ntype cUpOutput struct{}\n\nfunc (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error) {\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tmlog.Print()\n\t\t\tmlog.Print(`👏congratulations! you've upgraded to the latest version of GoFrame! enjoy it!👏`)\n\t\t\tmlog.Print()\n\t\t}\n\t}()\n\n\tvar doUpgradeVersionOut *doUpgradeVersionOutput\n\tif in.All {\n\t\tin.Cli = true\n\t\tin.Fix = true\n\t}\n\tif doUpgradeVersionOut, err = c.doUpgradeVersion(ctx, in); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif in.Cli {\n\t\tif err = c.doUpgradeCLI(ctx, in); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif in.Cli && in.Fix {\n\t\tif doUpgradeVersionOut != nil && len(doUpgradeVersionOut.Items) > 0 {\n\t\t\tupgradedPathSet := gset.NewStrSet()\n\t\t\tfor _, item := range doUpgradeVersionOut.Items {\n\t\t\t\tif !upgradedPathSet.AddIfNotExist(item.DirPath) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err = c.doAutoFixing(ctx, item.DirPath, item.Version); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\ntype doUpgradeVersionOutput struct {\n\tItems []doUpgradeVersionOutputItem\n}\n\ntype doUpgradeVersionOutputItem struct {\n\tDirPath string\n\tVersion string\n}\n\nfunc (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeVersionOutput, err error) {\n\tmlog.Print(`start upgrading version...`)\n\tout = &doUpgradeVersionOutput{\n\t\tItems: make([]doUpgradeVersionOutputItem, 0),\n\t}\n\ttype Package struct {\n\t\tName    string\n\t\tVersion string\n\t}\n\n\tvar (\n\t\ttemp      string\n\t\tdirPath   = gfile.Pwd()\n\t\tgoModPath = gfile.Join(dirPath, \"go.mod\")\n\t)\n\t// It recursively upgrades the go.mod from sub folder to its parent folders.\n\tfor {\n\t\tif gfile.Exists(goModPath) {\n\t\t\tvar packages []Package\n\t\t\terr = gfile.ReadLines(goModPath, func(line string) error {\n\t\t\t\tline = gstr.Trim(line)\n\t\t\t\tline = gstr.TrimLeftStr(line, \"require \")\n\t\t\t\tline = gstr.Trim(line)\n\t\t\t\tif gstr.HasPrefix(line, gfPackage) {\n\t\t\t\t\tarray := gstr.SplitAndTrim(line, \" \")\n\t\t\t\t\tpackages = append(packages, Package{\n\t\t\t\t\t\tName:    array[0],\n\t\t\t\t\t\tVersion: array[1],\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfor _, pkg := range packages {\n\t\t\t\tmlog.Printf(`upgrading \"%s\" from \"%s\" to \"latest\"`, pkg.Name, pkg.Version)\n\t\t\t\tmlog.Printf(`running command: go get %s@latest`, pkg.Name)\n\t\t\t\t// go get @latest\n\t\t\t\tcommand := fmt.Sprintf(`cd %s && go get %s@latest`, dirPath, pkg.Name)\n\t\t\t\tif err = gproc.ShellRun(ctx, command); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// go mod tidy\n\t\t\t\tif err = utils.GoModTidy(ctx, dirPath); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tout.Items = append(out.Items, doUpgradeVersionOutputItem{\n\t\t\t\t\tDirPath: dirPath,\n\t\t\t\t\tVersion: pkg.Version,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\ttemp = gfile.Dir(dirPath)\n\t\tif temp == \"\" || temp == dirPath {\n\t\t\treturn\n\t\t}\n\t\tdirPath = temp\n\t\tgoModPath = gfile.Join(dirPath, \"go.mod\")\n\t}\n}\n\n// doUpgradeCLI downloads the new version binary with process.\nfunc (c cUp) doUpgradeCLI(ctx context.Context, in cUpInput) (err error) {\n\tmlog.Print(`start upgrading cli...`)\n\tfmt.Println(` cli upgrade method:`, in.CliDownloadingMethod)\n\tswitch in.CliDownloadingMethod {\n\tcase cliMethodHttpDownload:\n\t\treturn c.doUpgradeCLIWithHttpDownload(ctx)\n\tcase cliMethodGoInstall:\n\t\treturn c.doUpgradeCLIWithGoInstall(ctx, in)\n\tdefault:\n\t\tmlog.Fatalf(`invalid cli upgrade method: \"%s\", please use \"http\" or \"install\"`, in.CliDownloadingMethod)\n\t}\n\treturn\n}\n\nfunc (c cUp) doUpgradeCLIWithHttpDownload(ctx context.Context) (err error) {\n\tmlog.Print(`start upgrading cli with http get download...`)\n\tvar (\n\t\tdownloadUrl = fmt.Sprintf(\n\t\t\t`https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,\n\t\t\truntime.GOOS, runtime.GOARCH,\n\t\t)\n\t\tlocalSaveFilePath = gfile.SelfPath() + \"~\"\n\t)\n\n\tif runtime.GOOS == \"windows\" {\n\t\tdownloadUrl += \".exe\"\n\t}\n\n\tmlog.Printf(`start downloading \"%s\" to \"%s\", it may take some time`, downloadUrl, localSaveFilePath)\n\terr = utils.HTTPDownloadFileWithPercent(downloadUrl, localSaveFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tmlog.Printf(`new version cli binary is successfully installed to \"%s\"`, gfile.SelfPath())\n\t\tmlog.Printf(`remove temporary buffer file \"%s\"`, localSaveFilePath)\n\t\t_ = gfile.RemoveFile(localSaveFilePath)\n\t}()\n\n\t// It fails if file not exist or its size is less than 1MB.\n\tif !gfile.Exists(localSaveFilePath) || gfile.Size(localSaveFilePath) < 1024*1024 {\n\t\tmlog.Fatalf(`download \"%s\" to \"%s\" failed`, downloadUrl, localSaveFilePath)\n\t}\n\n\tnewFile, err := gfile.Open(localSaveFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// selfupdate\n\terr = selfupdate.Apply(newFile, selfupdate.Options{})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn\n}\n\nfunc (c cUp) doUpgradeCLIWithGoInstall(ctx context.Context, in cUpInput) (err error) {\n\tmlog.Print(`upgrading cli with go install...`)\n\tif !genv.Contains(\"GOPATH\") {\n\t\tmlog.Fatal(`\"GOPATH\" environment variable does not exist, please check your go installation`)\n\t}\n\n\tcommand := fmt.Sprintf(`go install %s`, in.CliModulePath)\n\tmlog.Printf(`running command: %s`, command)\n\terr = gproc.ShellRun(ctx, command)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcliFilePath := gfile.Join(genv.Get(\"GOPATH\").String(), \"bin/gf\")\n\tif runtime.GOOS == \"windows\" {\n\t\tcliFilePath += \".exe\"\n\t}\n\n\t// It fails if file not exist or its size is less than 1MB.\n\tif !gfile.Exists(cliFilePath) || gfile.Size(cliFilePath) < 1024*1024 {\n\t\tmlog.Fatalf(`go install %s failed, \"%s\" does not exist or its size is less than 1MB`, in.CliModulePath, cliFilePath)\n\t}\n\n\tnewFile, err := gfile.Open(cliFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// selfupdate\n\terr = selfupdate.Apply(newFile, selfupdate.Options{})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn\n}\n\nfunc (c cUp) doAutoFixing(ctx context.Context, dirPath string, version string) (err error) {\n\tmlog.Printf(`auto fixing directory path \"%s\" from version \"%s\" ...`, dirPath, version)\n\tcommand := fmt.Sprintf(`gf fix -p %s`, dirPath)\n\t_ = gproc.ShellRun(ctx, command)\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_version.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gbuild\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tVersion = cVersion{}\n)\n\nconst (\n\tdefaultIndent = \"{{indent}}\"\n)\n\ntype cVersion struct {\n\tg.Meta `name:\"version\" brief:\"show version information of current binary\"`\n}\n\ntype cVersionInput struct {\n\tg.Meta `name:\"version\"`\n}\n\ntype cVersionOutput struct{}\n\nfunc (c cVersion) Index(ctx context.Context, in cVersionInput) (*cVersionOutput, error) {\n\tdetailBuffer := &detailBuffer{}\n\tdetailBuffer.WriteString(fmt.Sprintf(\"%s\", gf.VERSION))\n\n\tdetailBuffer.appendLine(0, \"Welcome to GoFrame!\")\n\n\tdetailBuffer.appendLine(0, \"Env Detail:\")\n\tgoVersion, ok := getGoVersion()\n\tif ok {\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Go Version: %s\", goVersion))\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"GF Version(go.mod): %s\", getGoFrameVersion(2)))\n\t} else {\n\t\tv, err := c.getGFVersionOfCurrentProject()\n\t\tif err == nil {\n\t\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"GF Version(go.mod): %s\", v))\n\t\t} else {\n\t\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"GF Version(go.mod): %s\", err.Error()))\n\t\t}\n\t}\n\n\tdetailBuffer.appendLine(0, \"CLI Detail:\")\n\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Installed At: %s\", gfile.SelfPath()))\n\tinfo := gbuild.Info()\n\tif info.GoFrame == \"\" {\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Built Go Version: %s\", runtime.Version()))\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Built GF Version: %s\", gf.VERSION))\n\t} else {\n\t\tif info.Git == \"\" {\n\t\t\tinfo.Git = \"none\"\n\t\t}\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Built Go Version: %s\", info.Golang))\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Built GF Version: %s\", info.GoFrame))\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Git Commit: %s\", info.Git))\n\t\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Built Time: %s\", info.Time))\n\t}\n\n\tdetailBuffer.appendLine(0, \"Others Detail:\")\n\tdetailBuffer.appendLine(1, \"Docs: https://goframe.org\")\n\tdetailBuffer.appendLine(1, fmt.Sprintf(\"Now : %s\", time.Now().Format(time.RFC3339)))\n\n\tmlog.Print(detailBuffer.replaceAllIndent(\"  \"))\n\treturn nil, nil\n}\n\n// detailBuffer is a buffer for detail information.\ntype detailBuffer struct {\n\tbytes.Buffer\n}\n\n// appendLine appends a line to the buffer with given indent level.\nfunc (d *detailBuffer) appendLine(indentLevel int, line string) {\n\td.WriteString(fmt.Sprintf(\"\\n%s%s\", strings.Repeat(defaultIndent, indentLevel), line))\n}\n\n// replaceAllIndent replaces the tab with given indent string and prints the buffer content.\nfunc (d *detailBuffer) replaceAllIndent(indentStr string) string {\n\treturn strings.ReplaceAll(d.String(), defaultIndent, indentStr)\n}\n\n// getGoFrameVersion returns the goframe version of current project using.\nfunc getGoFrameVersion(indentLevel int) (gfVersion string) {\n\tpkgInfo, err := gproc.ShellExec(context.Background(), `go list -f \"{{if (not .Main)}}{{.Path}}@{{.Version}}{{end}}\" -m all`)\n\tif err != nil {\n\t\treturn \"cannot find go.mod\"\n\t}\n\tpkgList := gstr.Split(pkgInfo, \"\\n\")\n\tfor _, v := range pkgList {\n\t\tif strings.HasPrefix(v, \"github.com/gogf/gf\") {\n\t\t\tgfVersion += fmt.Sprintf(\"\\n%s%s\", strings.Repeat(defaultIndent, indentLevel), v)\n\t\t}\n\t}\n\treturn\n}\n\n// getGoVersion returns the go version\nfunc getGoVersion() (goVersion string, ok bool) {\n\tgoVersion, err := gproc.ShellExec(context.Background(), \"go version\")\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\tgoVersion = gstr.TrimLeftStr(goVersion, \"go version \")\n\tgoVersion = gstr.TrimRightStr(goVersion, \"\\n\")\n\treturn goVersion, true\n}\n\n// getGFVersionOfCurrentProject checks and returns the GoFrame version current project using.\nfunc (c cVersion) getGFVersionOfCurrentProject() (string, error) {\n\tgoModPath := gfile.Join(gfile.Pwd(), \"go.mod\")\n\tif gfile.Exists(goModPath) {\n\t\tlines := gstr.SplitAndTrim(gfile.GetContents(goModPath), \"\\n\")\n\t\tfor _, line := range lines {\n\t\t\tline = gstr.Trim(line)\n\t\t\tline = gstr.TrimLeftStr(line, \"require \")\n\t\t\tline = gstr.Trim(line)\n\t\t\t// Version 1.\n\t\t\tmatch, err := gregex.MatchString(`^github\\.com/gogf/gf\\s+(.+)$`, line)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tif len(match) <= 1 {\n\t\t\t\t// Version > 1.\n\t\t\t\tmatch, err = gregex.MatchString(`^github\\.com/gogf/gf/v\\d\\s+(.+)$`, line)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(match) > 1 {\n\t\t\t\treturn gstr.Trim(match[1]), nil\n\t\t\t}\n\t\t}\n\n\t\treturn \"\", gerror.New(\"cannot find goframe requirement in go.mod\")\n\t} else {\n\t\treturn \"\", gerror.New(\"cannot find go.mod\")\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_init_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tctx      = context.Background()\n\ttestDB   gdb.DB\n\ttestPgDB gdb.DB\n\tlink     = \"mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true\"\n\tlinkPg   = \"pgsql:postgres:12345678@tcp(127.0.0.1:5432)/test\"\n)\n\nfunc init() {\n\tvar err error\n\ttestDB, err = gdb.New(gdb.ConfigNode{\n\t\tLink: link,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// PostgreSQL connection (optional, may not be available in all environments)\n\ttestPgDB, _ = gdb.New(gdb.ConfigNode{\n\t\tLink: linkPg,\n\t})\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tdropTableStmt := fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)\n\tif _, err := db.Exec(ctx, dropTableStmt); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\n// dropTableStd uses standard SQL syntax compatible with MySQL and PostgreSQL.\nfunc dropTableStd(db gdb.DB, table string) {\n\tdropTableStmt := fmt.Sprintf(\"DROP TABLE IF EXISTS %s\", table)\n\tif _, err := db.Exec(ctx, dropTableStmt); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_build_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Build_Single(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbuildPath  = gtest.DataPath(`build`, `single`)\n\t\t\tpwd        = gfile.Pwd()\n\t\t\tbinaryName = `t.test`\n\t\t\tbinaryPath = gtest.DataPath(`build`, `single`, binaryName)\n\t\t\tf          = cBuild{}\n\t\t)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.Remove(binaryPath)\n\t\terr := gfile.Chdir(buildPath)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(binaryPath), false)\n\t\t_, err = f.Index(ctx, cBuildInput{\n\t\t\tFile: cBuildDefaultFile,\n\t\t\tName: binaryName,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(binaryPath), true)\n\t})\n}\n\nfunc Test_Build_Single_Output(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbuildPath     = gtest.DataPath(`build`, `single`)\n\t\t\tpwd           = gfile.Pwd()\n\t\t\tbinaryName    = `tt`\n\t\t\tbinaryDirPath = gtest.DataPath(`build`, `single`, `tt`)\n\t\t\tbinaryPath    = gtest.DataPath(`build`, `single`, `tt`, binaryName)\n\t\t\tf             = cBuild{}\n\t\t)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.Remove(binaryDirPath)\n\t\terr := gfile.Chdir(buildPath)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(binaryPath), false)\n\t\t_, err = f.Index(ctx, cBuildInput{\n\t\t\tOutput: \"./tt/tt\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(binaryPath), true)\n\t})\n}\n\nfunc Test_Build_Single_Path(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbuildPath     = gtest.DataPath(`build`, `single`)\n\t\t\tpwd           = gfile.Pwd()\n\t\t\tdirName       = \"ttt\"\n\t\t\tbinaryName    = `main`\n\t\t\tbinaryDirPath = gtest.DataPath(`build`, `single`, dirName)\n\t\t\tbinaryPath    = gtest.DataPath(`build`, `single`, dirName, binaryName)\n\t\t\tf             = cBuild{}\n\t\t)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.Remove(binaryDirPath)\n\t\terr := gfile.Chdir(buildPath)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(binaryPath), false)\n\t\t_, err = f.Index(ctx, cBuildInput{\n\t\t\tPath: \"ttt\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(binaryPath), true)\n\t})\n}\n\nfunc Test_Build_Single_VarMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbuildPath  = gtest.DataPath(`build`, `varmap`)\n\t\t\tpwd        = gfile.Pwd()\n\t\t\tbinaryName = `main`\n\t\t\tbinaryPath = gtest.DataPath(`build`, `varmap`, binaryName)\n\t\t\tf          = cBuild{}\n\t\t)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.Remove(binaryPath)\n\t\terr := gfile.Chdir(buildPath)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(binaryPath), false)\n\t\t_, err = f.Index(ctx, cBuildInput{\n\t\t\tVarMap: map[string]any{\n\t\t\t\t\"a\": \"1\",\n\t\t\t\t\"b\": \"2\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(binaryPath), true)\n\n\t\tresult, err := gproc.ShellExec(ctx, binaryPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(result, `a: 1`), true)\n\t\tt.Assert(gstr.Contains(result, `b: 2`), true)\n\t})\n}\n\nfunc Test_Build_Multiple(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbuildPath         = gtest.DataPath(`build`, `multiple`)\n\t\t\tpwd               = gfile.Pwd()\n\t\t\tbinaryDirPath     = gtest.DataPath(`build`, `multiple`, `temp`)\n\t\t\tbinaryPathLinux   = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `linux_amd64`, `ttt`)\n\t\t\tbinaryPathWindows = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `windows_amd64`, `ttt.exe`)\n\t\t\tf                 = cBuild{}\n\t\t)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.Remove(binaryDirPath)\n\t\terr := gfile.Chdir(buildPath)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(binaryPathLinux), false)\n\t\tt.Assert(gfile.Exists(binaryPathWindows), false)\n\t\t_, err = f.Index(ctx, cBuildInput{\n\t\t\tFile:    \"multiple.go\",\n\t\t\tName:    \"ttt\",\n\t\t\tVersion: \"v1.1\",\n\t\t\tArch:    \"amd64\",\n\t\t\tSystem:  \"linux, windows\",\n\t\t\tPath:    \"temp\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(binaryPathLinux), true)\n\t\tt.Assert(gfile.Exists(binaryPathWindows), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_env_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Env_Index(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test that env command runs without error\n\t\t_, err := Env.Index(ctx, cEnvInput{})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Env_ParseGoEnvOutput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test parsing normal go env output\n\t\tlines := []string{\n\t\t\t\"set GOPATH=C:\\\\Users\\\\test\\\\go\",\n\t\t\t\"set GOROOT=C:\\\\Go\",\n\t\t\t\"set GOOS=windows\",\n\t\t\t\"GOARCH=amd64\", // Unix format without \"set \" prefix\n\t\t\t\"CGO_ENABLED=0\",\n\t\t}\n\n\t\tfor _, line := range lines {\n\t\t\tline = gstr.Trim(line)\n\t\t\tif gstr.Pos(line, \"set \") == 0 {\n\t\t\t\tline = line[4:]\n\t\t\t}\n\t\t\tmatch, _ := gregex.MatchString(`(.+?)=(.*)`, line)\n\t\t\tt.Assert(len(match) >= 3, true)\n\t\t}\n\t})\n}\n\nfunc Test_Env_ParseGoEnvOutput_WithWarnings(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test parsing go env output that contains warning messages\n\t\t// These lines should be skipped without causing errors\n\t\tlines := []string{\n\t\t\t\"go: stripping unprintable or unescapable characters from %\\\"GOPROXY\\\"%\",\n\t\t\t\"go: warning: some warning message\",\n\t\t\t\"# this is a comment\",\n\t\t\t\"\",\n\t\t\t\"set GOPATH=C:\\\\Users\\\\test\\\\go\",\n\t\t\t\"set GOOS=windows\",\n\t\t}\n\n\t\tarray := make([][]string, 0)\n\t\tfor _, line := range lines {\n\t\t\tline = gstr.Trim(line)\n\t\t\tif line == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif gstr.Pos(line, \"set \") == 0 {\n\t\t\t\tline = line[4:]\n\t\t\t}\n\t\t\tmatch, _ := gregex.MatchString(`(.+?)=(.*)`, line)\n\t\t\tif len(match) < 3 {\n\t\t\t\t// Skip lines that don't match key=value format (e.g., warning messages)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tarray = append(array, []string{gstr.Trim(match[1]), gstr.Trim(match[2])})\n\t\t}\n\n\t\t// Should have parsed 2 valid environment variables\n\t\tt.Assert(len(array), 2)\n\t\tt.Assert(array[0][0], \"GOPATH\")\n\t\tt.Assert(array[0][1], \"C:\\\\Users\\\\test\\\\go\")\n\t\tt.Assert(array[1][0], \"GOOS\")\n\t\tt.Assert(array[1][1], \"windows\")\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_fix_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Fix_doFixV25Content(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcontent = gtest.DataContent(`fix`, `fix25_content.go`)\n\t\t\tf       = cFix{}\n\t\t)\n\t\t_, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Fix_doFixV25Content_WithReplacement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tf       = cFix{}\n\t\t\tcontent = `s.BindHookHandlerByMap(\"/path\", map[string]ghttp.HandlerFunc{\n\t\t\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {},\n\t\t\t})`\n\t\t)\n\t\tnewContent, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t\t// Verify the replacement was made\n\t\tt.Assert(gstr.Contains(newContent, \"map[ghttp.HookName]ghttp.HandlerFunc\"), true)\n\t\tt.Assert(gstr.Contains(newContent, \"map[string]ghttp.HandlerFunc\"), false)\n\t})\n}\n\nfunc Test_Fix_doFixV25Content_NoMatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tf       = cFix{}\n\t\t\tcontent = `package main\n\nfunc main() {\n\tfmt.Println(\"Hello World\")\n}\n`\n\t\t)\n\t\tnewContent, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t\t// Content should remain unchanged\n\t\tt.Assert(newContent, content)\n\t})\n}\n\nfunc Test_Fix_doFixV25Content_MultipleMatches(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tf       = cFix{}\n\t\t\tcontent = `\ns.BindHookHandlerByMap(\"/path1\", map[string]ghttp.HandlerFunc{})\ns.BindHookHandlerByMap(\"/path2\", map[string]ghttp.HandlerFunc{})\n`\n\t\t)\n\t\tnewContent, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t\t// Both should be replaced\n\t\tcount := gstr.Count(newContent, \"map[ghttp.HookName]ghttp.HandlerFunc\")\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_Fix_doFixV25Content_EmptyContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tf       = cFix{}\n\t\t\tcontent = \"\"\n\t\t)\n\t\tnewContent, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newContent, \"\")\n\t})\n}\n\nfunc Test_Fix_doFixV25Content_ComplexPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tf       = cFix{}\n\t\t\tcontent = `s.BindHookHandlerByMap(\"/api/v1/user/{id}/profile\", map[string]ghttp.HandlerFunc{\n\t\t\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\t\t\tr.Response.Write(\"before\")\n\t\t\t\t},\n\t\t\t})`\n\t\t)\n\t\tnewContent, err := f.doFixV25Content(content)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(newContent, \"map[ghttp.HookName]ghttp.HandlerFunc\"), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_ctrl_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl\"\n)\n\nfunc Test_Gen_Ctrl_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tapiFolder = gtest.DataPath(\"genctrl\", \"default\", \"api\")\n\t\t\tin        = genctrl.CGenCtrlInput{\n\t\t\t\tSrcFolder:     apiFolder,\n\t\t\t\tDstFolder:     path,\n\t\t\t\tWatchFile:     \"\",\n\t\t\t\tSdkPath:       \"\",\n\t\t\t\tSdkStdVersion: false,\n\t\t\t\tSdkNoV1:       false,\n\t\t\t\tClear:         false,\n\t\t\t\tMerge:         false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// apiInterface file\n\t\tvar (\n\t\t\tgenApi       = apiFolder + filepath.FromSlash(\"/article/article.go\")\n\t\t\tgenApiExpect = apiFolder + filepath.FromSlash(\"/article/article_expect.go\")\n\t\t)\n\t\tdefer gfile.RemoveAll(genApi)\n\t\tt.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/article/article.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_new.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v1_create.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v1_get_list.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v1_get_one.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v1_update.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v2_create.go\"),\n\t\t\tpath + filepath.FromSlash(\"/article/article_v2_update.go\"),\n\t\t})\n\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"genctrl\", \"default\", \"controller\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/article/article.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_new.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v1_create.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v1_get_list.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v1_get_one.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v1_update.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v2_create.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/article/article_v2_update.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Gen_Ctrl_Default_Multi(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tapiFolder = gtest.DataPath(\"genctrl\", \"multi\", \"api\")\n\t\t\tin        = genctrl.CGenCtrlInput{\n\t\t\t\tSrcFolder:     apiFolder,\n\t\t\t\tDstFolder:     path,\n\t\t\t\tWatchFile:     \"\",\n\t\t\t\tSdkPath:       \"\",\n\t\t\t\tSdkStdVersion: false,\n\t\t\t\tSdkNoV1:       false,\n\t\t\t\tClear:         false,\n\t\t\t\tMerge:         false,\n\t\t\t}\n\t\t)\n\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// apiInterface file\n\t\tvar (\n\t\t\tgenApiSlice = []string{\n\t\t\t\tapiFolder + filepath.FromSlash(\"/admin/article/article.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/admin/user/user.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/app/user/user.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/app/user/user_ext/user_ext.go\"),\n\t\t\t}\n\t\t\tgenApiSliceExpect = []string{\n\t\t\t\tapiFolder + filepath.FromSlash(\"/admin/article/article_expect.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/admin/user/user_expect.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/app/user/user_expect.go\"),\n\t\t\t\tapiFolder + filepath.FromSlash(\"/app/user/user_ext/user_ext_expect.go\"),\n\t\t\t}\n\t\t)\n\n\t\tfor i := range genApiSlice {\n\t\t\tt.Assert(gfile.GetContents(genApiSlice[i]), gfile.GetContents(genApiSliceExpect[i]))\n\t\t\tgfile.RemoveAll(genApiSlice[i])\n\t\t}\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/admin/article/article.go\"),\n\t\t\tpath + filepath.FromSlash(\"/admin/article/article_new.go\"),\n\t\t\tpath + filepath.FromSlash(\"/admin/article/article_v1_create.go\"),\n\n\t\t\tpath + filepath.FromSlash(\"/admin/user/user.go\"),\n\t\t\tpath + filepath.FromSlash(\"/admin/user/user_new.go\"),\n\t\t\tpath + filepath.FromSlash(\"/admin/user/user_v1_create.go\"),\n\n\t\t\tpath + filepath.FromSlash(\"/app/user/user.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_ext/user_ext.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_ext/user_ext_new.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_ext/user_ext_v1_create.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_ext/user_ext_v1_update.go\"),\n\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_new.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_v1_create.go\"),\n\t\t\tpath + filepath.FromSlash(\"/app/user/user_v1_update.go\"),\n\t\t})\n\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"genctrl\", \"multi\", \"controller\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/admin/article/article.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/admin/article/article_new.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/admin/article/article_v1_create.go\"),\n\n\t\t\ttestPath + filepath.FromSlash(\"/admin/user/user.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/admin/user/user_new.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/admin/user/user_v1_create.go\"),\n\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_ext/user_ext.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_ext/user_ext_new.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_ext/user_ext_v1_create.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_ext/user_ext_v1_update.go\"),\n\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_new.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_v1_create.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/app/user/user_v1_update.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc expectFilesContent(t *gtest.T, paths []string, expectPaths []string) {\n\tfor i, expectFile := range expectPaths {\n\t\tval := gfile.GetContents(paths[i])\n\t\texpect := gfile.GetContents(expectFile)\n\t\tt.Assert(val, expect)\n\t}\n}\n\n// gf gen ctrl -m\n// In the same module, different API files are added\nfunc Test_Gen_Ctrl_UseMerge_AddNewFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctrlPath = gfile.Temp(guid.S())\n\t\t\t// ctrlPath  = gtest.DataPath(\"issue\", \"3460\", \"controller\")\n\t\t\tapiFolder = gtest.DataPath(\"genctrl\", \"merge\", \"add_new_file\", \"api\")\n\t\t\tin        = genctrl.CGenCtrlInput{\n\t\t\t\tSrcFolder: apiFolder,\n\t\t\t\tDstFolder: ctrlPath,\n\t\t\t\tMerge:     true,\n\t\t\t}\n\t\t)\n\t\tconst testNewApiFile = `\npackage v1\nimport \"github.com/gogf/gf/v2/frame/g\"\ntype DictTypeAddReq struct {\n\tg.Meta\n}\ntype DictTypeAddRes struct {\n}\n`\n\n\t\terr := gfile.Mkdir(ctrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(ctrlPath)\n\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tvar (\n\t\t\tgenApi       = filepath.Join(apiFolder, \"/dict/dict.go\")\n\t\t\tgenApiExpect = filepath.Join(apiFolder, \"/dict/dict_expect.go\")\n\t\t)\n\t\tdefer gfile.RemoveAll(genApi)\n\t\tt.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))\n\n\t\tgenCtrlFiles, err := gfile.ScanDir(ctrlPath, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(genCtrlFiles, []string{\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict_new.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict_v1_dict_type.go\"),\n\t\t})\n\n\t\texpectCtrlPath := gtest.DataPath(\"genctrl\", \"merge\", \"add_new_file\", \"controller\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict_new.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict_v1_dict_type.go\"),\n\t\t}\n\n\t\t// Line Feed maybe \\r\\n or \\n\n\t\texpectFilesContent(t, genCtrlFiles, expectFiles)\n\n\t\t// Add a new API file\n\t\tnewApiFilePath := filepath.Join(apiFolder, \"/dict/v1/test_new.go\")\n\t\terr = gfile.PutContents(newApiFilePath, testNewApiFile)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(newApiFilePath)\n\n\t\t// Then execute the command\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tgenApi = filepath.Join(apiFolder, \"/dict.go\")\n\t\tgenApiExpect = filepath.Join(apiFolder, \"/dict_add_new_ctrl_expect.gotest\")\n\n\t\tt.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))\n\n\t\tgenCtrlFiles = append(genCtrlFiles, filepath.Join(ctrlPath, \"/dict/dict_v1_test_new.go\"))\n\t\t// Use the gotest suffix, otherwise the IDE will delete the import\n\t\texpectFiles = append(expectFiles, filepath.Join(expectCtrlPath, \"/dict/dict_v1_test_new.gotest\"))\n\t\t// Line Feed maybe \\r\\n or \\n\n\t\texpectFilesContent(t, genCtrlFiles, expectFiles)\n\n\t})\n\n}\n\n// gf gen ctrl -m\n// In the same module, Add the same file to the API\nfunc Test_Gen_Ctrl_UseMerge_AddNewCtrl(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctrlPath = gfile.Temp(guid.S())\n\t\t\t// ctrlPath  = gtest.DataPath(\"issue\", \"3460\", \"controller\")\n\t\t\tapiFolder = gtest.DataPath(\"genctrl\", \"merge\", \"add_new_ctrl\", \"api\")\n\t\t\tin        = genctrl.CGenCtrlInput{\n\t\t\t\tSrcFolder: apiFolder,\n\t\t\t\tDstFolder: ctrlPath,\n\t\t\t\tMerge:     true,\n\t\t\t}\n\t\t)\n\n\t\terr := gfile.Mkdir(ctrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(ctrlPath)\n\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tvar (\n\t\t\tgenApi       = filepath.Join(apiFolder, \"/dict/dict.go\")\n\t\t\tgenApiExpect = filepath.Join(apiFolder, \"/dict/dict_expect.go\")\n\t\t)\n\t\tdefer gfile.RemoveAll(genApi)\n\t\tt.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))\n\n\t\tgenCtrlFiles, err := gfile.ScanDir(ctrlPath, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(genCtrlFiles, []string{\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict_new.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/dict/dict_v1_dict_type.go\"),\n\t\t})\n\n\t\texpectCtrlPath := gtest.DataPath(\"genctrl\", \"merge\", \"add_new_ctrl\", \"controller\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict_new.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/dict/dict_v1_dict_type.go\"),\n\t\t}\n\n\t\t// Line Feed maybe \\r\\n or \\n\n\t\texpectFilesContent(t, genCtrlFiles, expectFiles)\n\n\t\tconst testNewApiFile = `\n\ntype DictTypeAddReq struct {\n\tg.Meta\n}\ntype DictTypeAddRes struct {\n}\n`\n\t\tdictModuleFileName := filepath.Join(apiFolder, \"/dict/v1/dict_type.go\")\n\t\t// Save the contents of the file before the changes\n\t\tapiFileContents := gfile.GetContents(dictModuleFileName)\n\n\t\t// Add a new API file\n\t\terr = gfile.PutContentsAppend(dictModuleFileName, testNewApiFile)\n\t\tt.AssertNil(err)\n\n\t\t// ==================================\n\t\t// Then execute the command\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tgenApi = filepath.Join(apiFolder, \"/dict.go\")\n\t\tgenApiExpect = filepath.Join(apiFolder, \"/dict_add_new_ctrl_expect.gotest\")\n\t\tt.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))\n\n\t\t// Use the gotest suffix, otherwise the IDE will delete the import\n\t\texpectFiles[2] = filepath.Join(expectCtrlPath, \"/dict/dict_v1_test_new.gotest\")\n\t\t// Line Feed maybe \\r\\n or \\n\n\t\texpectFilesContent(t, genCtrlFiles, expectFiles)\n\n\t\t// Restore the contents of the original API file\n\t\terr = gfile.PutContents(dictModuleFileName, apiFileContents)\n\t\tt.AssertNil(err)\n\t})\n\n}\n\n// https://github.com/gogf/gf/issues/3460\nfunc Test_Gen_Ctrl_UseMerge_Issue3460(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctrlPath = gfile.Temp(guid.S())\n\t\t\t// ctrlPath  = gtest.DataPath(\"issue\", \"3460\", \"controller\")\n\t\t\tapiFolder = gtest.DataPath(\"issue\", \"3460\", \"api\")\n\t\t\tin        = genctrl.CGenCtrlInput{\n\t\t\t\tSrcFolder:     apiFolder,\n\t\t\t\tDstFolder:     ctrlPath,\n\t\t\t\tWatchFile:     \"\",\n\t\t\t\tSdkPath:       \"\",\n\t\t\t\tSdkStdVersion: false,\n\t\t\t\tSdkNoV1:       false,\n\t\t\t\tClear:         false,\n\t\t\t\tMerge:         true,\n\t\t\t}\n\t\t)\n\n\t\terr := gfile.Mkdir(ctrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveAll(ctrlPath)\n\n\t\t_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tfiles, err := gfile.ScanDir(ctrlPath, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.Join(ctrlPath, \"/hello/hello.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/hello/hello_new.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/hello/hello_v1_req.go\"),\n\t\t\tfilepath.Join(ctrlPath, \"/hello/hello_v2_req.go\"),\n\t\t})\n\n\t\texpectCtrlPath := gtest.DataPath(\"issue\", \"3460\", \"controller\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.Join(expectCtrlPath, \"/hello/hello.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/hello/hello_new.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/hello/hello_v1_req.go\"),\n\t\t\tfilepath.Join(expectCtrlPath, \"/hello/hello_v2_req.go\"),\n\t\t}\n\n\t\t// Line Feed maybe \\r\\n or \\n\n\t\tfor i, expectFile := range expectFiles {\n\t\t\tval := gfile.GetContents(files[i])\n\t\t\texpect := gfile.GetContents(expectFile)\n\t\t\tt.Assert(val, expect)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao\"\n)\n\n// https://github.com/gogf/gf/issues/2572\nfunc Test_Gen_Dao_Issue2572(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr          error\n\t\t\tdb           = testDB\n\t\t\ttable1       = \"user1\"\n\t\t\ttable2       = \"user2\"\n\t\t\tissueDirPath = gtest.DataPath(`issue`, `2572`)\n\t\t)\n\t\tt.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql1.sql`)))\n\t\tt.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql2.sql`)))\n\t\tdefer dropTableWithDb(db, table1)\n\t\tdefer dropTableWithDb(db, table2)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               \"\",\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"SnakeScreaming\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping:        nil,\n\t\t\t\tFieldMapping:       nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Copy(issueDirPath, path)\n\t\tt.AssertNil(err)\n\n\t\tdefer gfile.Remove(path)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\n\t\tdefer gfile.Chdir(pwd)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tgeneratedFiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 8)\n\t\tfor i, generatedFile := range generatedFiles {\n\t\t\tgeneratedFiles[i] = gstr.TrimLeftStr(generatedFile, path)\n\t\t}\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/internal/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/internal/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/do/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/do/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/entity/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/entity/user_2.go\")), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2616\nfunc Test_Gen_Dao_Issue2616(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr          error\n\t\t\tdb           = testDB\n\t\t\ttable1       = \"user1\"\n\t\t\ttable2       = \"user2\"\n\t\t\tissueDirPath = gtest.DataPath(`issue`, `2616`)\n\t\t)\n\t\tt.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql1.sql`)))\n\t\tt.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql2.sql`)))\n\t\tdefer dropTableWithDb(db, table1)\n\t\tdefer dropTableWithDb(db, table2)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               \"\",\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"SnakeScreaming\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping:        nil,\n\t\t\t\tFieldMapping:       nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Copy(issueDirPath, path)\n\t\tt.AssertNil(err)\n\n\t\tdefer gfile.Remove(path)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\n\t\tdefer gfile.Chdir(pwd)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tgeneratedFiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 8)\n\t\tfor i, generatedFile := range generatedFiles {\n\t\t\tgeneratedFiles[i] = gstr.TrimLeftStr(generatedFile, path)\n\t\t}\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/internal/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/internal/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/dao/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/do/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/do/user_2.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/entity/user_1.go\")), true)\n\t\tt.Assert(gstr.InArray(generatedFiles,\n\t\t\tfilepath.FromSlash(\"/model/entity/user_2.go\")), true)\n\n\t\t// Key string to check if overwrite the dao files.\n\t\t// dao user1 is not be overwritten as configured in config.yaml.\n\t\t// dao user2 is to  be overwritten as configured in config.yaml.\n\t\tvar (\n\t\t\tkeyStr          = `// I am not overwritten.`\n\t\t\tdaoUser1Content = gfile.GetContents(path + \"/dao/user_1.go\")\n\t\t\tdaoUser2Content = gfile.GetContents(path + \"/dao/user_2.go\")\n\t\t)\n\t\tt.Assert(gstr.Contains(daoUser1Content, keyStr), true)\n\t\tt.Assert(gstr.Contains(daoUser2Content, keyStr), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2746\nfunc Test_Gen_Dao_Issue2746(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tmdb        gdb.DB\n\t\t\tlink2746   = \"mariadb:root:12345678@tcp(127.0.0.1:3307)/test?loc=Local&parseTime=true\"\n\t\t\ttable      = \"issue2746\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`issue`, `2746`, `sql.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tmdb, err = gdb.New(gdb.ConfigNode{\n\t\t\tLink: link2746,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = mdb.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(mdb, table)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               link2746,\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"SnakeScreaming\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       true,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping:        nil,\n\t\t\t\tFieldMapping:       nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tvar (\n\t\t\tfile          = filepath.FromSlash(path + \"/model/entity/issue_2746.go\")\n\t\t\texpectContent = gtest.DataContent(`issue`, `2746`, `issue_2746.go`)\n\t\t)\n\t\tt.Assert(expectContent, gfile.GetContents(file))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3459\nfunc Test_Gen_Dao_Issue3459(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`gendao`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tconfDir = gtest.DataPath(\"issue\", \"3459\")\n\t\t\tpath    = gfile.Temp(guid.S())\n\t\t\tgroup   = \"test\"\n\t\t\tin      = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               link,\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"SnakeScreaming\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping:        nil,\n\t\t\t}\n\t\t)\n\t\terr = g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetPath(confDir)\n\t\tt.AssertNil(err)\n\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"gendao\", \"generated_user\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\t//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3749\nfunc Test_Gen_Dao_Issue3749(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`issue`, `3749`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:  path,\n\t\t\t\tLink:  link,\n\t\t\t\tGroup: group,\n\t\t\t}\n\t\t)\n\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(`issue`, `3749`)\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\t//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test tables pattern matching with * wildcard.\nfunc Test_Gen_Dao_Issue4629_TablesPattern_Star(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: \"trade_*\", // Should match trade_order, trade_item\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 2 dao files: trade_order.go, trade_item.go\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 2)\n\n\t\t// Verify the correct files are generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_order.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_item.go\")), true)\n\t\t// user_* and config should NOT be generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_info.go\")), false)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_log.go\")), false)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"config.go\")), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test tables pattern matching with multiple patterns.\nfunc Test_Gen_Dao_Issue4629_TablesPattern_Multiple(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: \"trade_*,user_*\", // Should match trade_order, trade_item, user_info, user_log\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 4 dao files\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 4)\n\n\t\t// Verify the correct files are generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_order.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_item.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_info.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_log.go\")), true)\n\t\t// config should NOT be generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"config.go\")), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test tables pattern mixed with exact table name.\nfunc Test_Gen_Dao_Issue4629_TablesPattern_Mixed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: \"trade_*,config\", // Pattern + exact name\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 3 dao files: trade_order.go, trade_item.go, config.go\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 3)\n\n\t\t// Verify the correct files are generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_order.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_item.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"config.go\")), true)\n\t\t// user_* should NOT be generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_info.go\")), false)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_log.go\")), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test tables pattern with ? wildcard (single character match).\nfunc Test_Gen_Dao_Issue4629_TablesPattern_Question(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: \"user_???\", // ? matches single char: user_log (3 chars) but not user_info (4 chars)\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 1 dao file: user_log.go (3 chars after user_)\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 1)\n\n\t\t// Verify only user_log is generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_log.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_info.go\")), false) // 4 chars, doesn't match\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test that exact table names still work (backward compatibility).\nfunc Test_Gen_Dao_Issue4629_TablesPattern_ExactNames(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: \"trade_order,config\", // Exact names, no patterns\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 2 dao files\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 2)\n\n\t\t// Verify exactly the specified tables are generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_order.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"config.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_item.go\")), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4629\n// Test tables pattern matching with PostgreSQL.\nfunc Test_Gen_Dao_Issue4629_TablesPattern_PgSql(t *testing.T) {\n\tif testPgDB == nil {\n\t\tt.Skip(\"PostgreSQL database not available, skipping test\")\n\t\treturn\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testPgDB\n\t\t\ttable1      = \"trade_order\"\n\t\t\ttable2      = \"trade_item\"\n\t\t\ttable3      = \"user_info\"\n\t\t\ttable4      = \"user_log\"\n\t\t\ttable5      = \"config\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`)\n\t\t)\n\t\tdropTableStd(db, table1)\n\t\tdropTableStd(db, table2)\n\t\tdropTableStd(db, table3)\n\t\tdropTableStd(db, table4)\n\t\tdropTableStd(db, table5)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableStd(db, table1)\n\t\tdefer dropTableStd(db, table2)\n\t\tdefer dropTableStd(db, table3)\n\t\tdefer dropTableStd(db, table4)\n\t\tdefer dropTableStd(db, table5)\n\n\t\t// Test tables pattern with tablesEx pattern\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:     path,\n\t\t\t\tLink:     linkPg,\n\t\t\t\tGroup:    group,\n\t\t\t\tTables:   \"trade_*,user_*,config\", // Match only our test tables\n\t\t\t\tTablesEx: \"user_*\",                // Exclude user_* tables\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 3 dao files: trade_order, trade_item, config (user_* excluded by tablesEx)\n\t\tgeneratedFiles, err := gfile.ScanDir(gfile.Join(path, \"dao\"), \"*.go\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 3)\n\n\t\t// Verify the correct files are generated\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_order.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"trade_item.go\")), true)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"config.go\")), true)\n\t\t// user_* should NOT be generated (excluded by tablesEx)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_info.go\")), false)\n\t\tt.Assert(gfile.Exists(gfile.Join(path, \"dao\", \"user_log.go\")), false)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_dao_sharding_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao\"\n)\n\n// Test_Gen_Dao_Sharding_Overlapping tests the fix for issue #4603.\n// When sharding patterns have overlapping prefixes (like \"a_?\", \"a_b_?\", \"a_c_?\"),\n// longer (more specific) patterns should be matched first.\n// https://github.com/gogf/gf/issues/4603\nfunc Test_Gen_Dao_Sharding_Overlapping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttableA1     = \"a_1\"\n\t\t\ttableA2     = \"a_2\"\n\t\t\ttableAB1    = \"a_b_1\"\n\t\t\ttableAB2    = \"a_b_2\"\n\t\t\ttableAC1    = \"a_c_1\"\n\t\t\ttableAC2    = \"a_c_2\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `sharding`, `sharding_overlapping.sql`)\n\t\t)\n\t\tdropTableWithDb(db, tableA1)\n\t\tdropTableWithDb(db, tableA2)\n\t\tdropTableWithDb(db, tableAB1)\n\t\tdropTableWithDb(db, tableAB2)\n\t\tdropTableWithDb(db, tableAC1)\n\t\tdropTableWithDb(db, tableAC2)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableWithDb(db, tableA1)\n\t\tdefer dropTableWithDb(db, tableA2)\n\t\tdefer dropTableWithDb(db, tableAB1)\n\t\tdefer dropTableWithDb(db, tableAB2)\n\t\tdefer dropTableWithDb(db, tableAC1)\n\t\tdefer dropTableWithDb(db, tableAC2)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tPrefix: \"\",\n\t\t\t\t// Patterns with overlapping prefixes - order should not matter due to sorting fix\n\t\t\t\tShardingPattern: []string{\n\t\t\t\t\t`a_?`,   // shortest, matches a_1, a_2 but also a_b_1, a_c_1 without fix\n\t\t\t\t\t`a_b_?`, // longer, should match a_b_1, a_b_2\n\t\t\t\t\t`a_c_?`, // longer, should match a_c_1, a_c_2\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Should generate 3 dao files: a.go, a_b.go, a_c.go (plus internal versions)\n\t\tgeneratedFiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\t// 3 sharding groups * 4 files each (dao, internal, do, entity) = 12 files\n\t\tt.Assert(len(generatedFiles), 12)\n\n\t\tvar (\n\t\t\tdaoAContent  = gfile.GetContents(gfile.Join(path, \"dao\", \"a.go\"))\n\t\t\tdaoABContent = gfile.GetContents(gfile.Join(path, \"dao\", \"a_b.go\"))\n\t\t\tdaoACContent = gfile.GetContents(gfile.Join(path, \"dao\", \"a_c.go\"))\n\t\t)\n\n\t\t// Verify each sharding group has correct dao file generated\n\t\tt.Assert(gstr.Contains(daoAContent, \"aShardingHandler\"), true)\n\t\tt.Assert(gstr.Contains(daoAContent, \"m.Sharding(gdb.ShardingConfig{\"), true)\n\n\t\tt.Assert(gstr.Contains(daoABContent, \"aBShardingHandler\"), true)\n\t\tt.Assert(gstr.Contains(daoABContent, \"m.Sharding(gdb.ShardingConfig{\"), true)\n\n\t\tt.Assert(gstr.Contains(daoACContent, \"aCShardingHandler\"), true)\n\t\tt.Assert(gstr.Contains(daoACContent, \"m.Sharding(gdb.ShardingConfig{\"), true)\n\t})\n}\n\nfunc Test_Gen_Dao_Sharding(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttableSingle = \"single_table\"\n\t\t\ttable1      = \"users_0001\"\n\t\t\ttable2      = \"users_0002\"\n\t\t\ttable3      = \"orders_0001\"\n\t\t\ttable4      = \"orders_0002\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `sharding`, `sharding.sql`)\n\t\t)\n\t\tdropTableWithDb(db, tableSingle)\n\t\tdropTableWithDb(db, table1)\n\t\tdropTableWithDb(db, table2)\n\t\tdropTableWithDb(db, table3)\n\t\tdropTableWithDb(db, table4)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableWithDb(db, tableSingle)\n\t\tdefer dropTableWithDb(db, table1)\n\t\tdefer dropTableWithDb(db, table2)\n\t\tdefer dropTableWithDb(db, table3)\n\t\tdefer dropTableWithDb(db, table4)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\t// path  = \"/Users/john/Temp/gen_dao_sharding\"\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   link,\n\t\t\t\tGroup:  group,\n\t\t\t\tPrefix: \"\",\n\t\t\t\tShardingPattern: []string{\n\t\t\t\t\t`users_?`,\n\t\t\t\t\t`orders_?`,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\tpwd := gfile.Pwd()\n\t\terr = gfile.Chdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\t\tdefer gfile.RemoveAll(path)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tgeneratedFiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(generatedFiles), 12)\n\t\tvar (\n\t\t\tdaoSingleTableContent = gfile.GetContents(gfile.Join(path, \"dao\", \"single_table.go\"))\n\t\t\tdaoUsersContent       = gfile.GetContents(gfile.Join(path, \"dao\", \"users.go\"))\n\t\t\tdaoOrdersContent      = gfile.GetContents(gfile.Join(path, \"dao\", \"orders.go\"))\n\t\t)\n\t\tt.Assert(gstr.Contains(daoSingleTableContent, \"SingleTable = singleTableDao{internal.NewSingleTableDao()}\"), true)\n\t\tt.Assert(gstr.Contains(daoUsersContent, \"Users = usersDao{internal.NewUsersDao(usersShardingHandler)}\"), true)\n\t\tt.Assert(gstr.Contains(daoUsersContent, \"m.Sharding(gdb.ShardingConfig{\"), true)\n\t\tt.Assert(gstr.Contains(daoOrdersContent, \"Orders = ordersDao{internal.NewOrdersDao(ordersShardingHandler)}\"), true)\n\t\tt.Assert(gstr.Contains(daoOrdersContent, \"m.Sharding(gdb.ShardingConfig{\"), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao\"\n)\n\nfunc Test_Gen_Dao_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`gendao`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               link,\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"SnakeScreaming\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping:        nil,\n\t\t\t\tFieldMapping:       nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"gendao\", \"generated_user\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Gen_Dao_TypeMapping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`gendao`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdefer dropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               link,\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{\n\t\t\t\t\t\"int\": {\n\t\t\t\t\t\tType:   \"int64\",\n\t\t\t\t\t\tImport: \"\",\n\t\t\t\t\t},\n\t\t\t\t\t\"decimal\": {\n\t\t\t\t\t\tType:   \"decimal.Decimal\",\n\t\t\t\t\t\tImport: \"github.com/shopspring/decimal\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tFieldMapping: nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"gendao\", \"generated_user_type_mapping\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\t//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Gen_Dao_FieldMapping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`gendao`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdefer dropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath  = gfile.Temp(guid.S())\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:               path,\n\t\t\t\tLink:               link,\n\t\t\t\tTables:             \"\",\n\t\t\t\tTablesEx:           \"\",\n\t\t\t\tGroup:              group,\n\t\t\t\tPrefix:             \"\",\n\t\t\t\tRemovePrefix:       \"\",\n\t\t\t\tJsonCase:           \"\",\n\t\t\t\tImportPrefix:       \"\",\n\t\t\t\tDaoPath:            \"\",\n\t\t\t\tDoPath:             \"\",\n\t\t\t\tEntityPath:         \"\",\n\t\t\t\tTplDaoIndexPath:    \"\",\n\t\t\t\tTplDaoInternalPath: \"\",\n\t\t\t\tTplDaoDoPath:       \"\",\n\t\t\t\tTplDaoEntityPath:   \"\",\n\t\t\t\tStdTime:            false,\n\t\t\t\tWithTime:           false,\n\t\t\t\tGJsonSupport:       false,\n\t\t\t\tOverwriteDao:       false,\n\t\t\t\tDescriptionTag:     false,\n\t\t\t\tNoJsonTag:          false,\n\t\t\t\tNoModelComment:     false,\n\t\t\t\tClear:              false,\n\t\t\t\tGenTable:           false,\n\t\t\t\tTypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{\n\t\t\t\t\t\"int\": {\n\t\t\t\t\t\tType:   \"int64\",\n\t\t\t\t\t\tImport: \"\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tFieldMapping: map[gendao.DBTableFieldName]gendao.CustomAttributeType{\n\t\t\t\t\t\"table_user.score\": {\n\t\t\t\t\t\tType:   \"decimal.Decimal\",\n\t\t\t\t\t\tImport: \"github.com/shopspring/decimal\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"gendao\", \"generated_user_field_mapping\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\t//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc execSqlFile(db gdb.DB, filePath string, args ...any) error {\n\tsqlContent := fmt.Sprintf(\n\t\tgfile.GetContents(filePath),\n\t\targs...,\n\t)\n\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc Test_Gen_Dao_Sqlite3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\ttable       = \"table_user\"\n\t\t\tpath        = gfile.Temp(guid.S())\n\t\t\tlinkSqlite3 = fmt.Sprintf(\"sqlite::@file(%s/db.sqlite3)\", path)\n\t\t\tsqlContent  = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`gendao`, `sqlite3`, `user.sqlite3.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tdbSqlite3, err := gdb.New(gdb.ConfigNode{\n\t\t\tLink: linkSqlite3,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif v == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif _, err = dbSqlite3.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\n\t\tvar (\n\t\t\tgroup = \"test\"\n\t\t\tin    = gendao.CGenDaoInput{\n\t\t\t\tPath:   path,\n\t\t\t\tLink:   linkSqlite3,\n\t\t\t\tGroup:  group,\n\t\t\t\tTables: table,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\t// for go mod import path auto retrieve.\n\t\terr = gfile.Copy(\n\t\t\tgtest.DataPath(\"gendao\", \"go.mod.txt\"),\n\t\t\tgfile.Join(path, \"go.mod\"),\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gendao.CGenDao{}.Dao(ctx, in)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tfilepath.FromSlash(path + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(path + \"/model/entity/table_user.go\"),\n\t\t})\n\t\t// content\n\t\ttestPath := gtest.DataPath(\"gendao\", \"generated_user_sqlite3\")\n\t\texpectFiles := []string{\n\t\t\tfilepath.FromSlash(testPath + \"/dao/internal/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/dao/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/do/table_user.go\"),\n\t\t\tfilepath.FromSlash(testPath + \"/model/entity/table_user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\t//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_enums_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genenums\"\n)\n\n// https://github.com/gogf/gf/issues/4387\n// Test that the output path is relative to the original working directory,\n// not the source directory after Chdir.\nfunc Test_Gen_Enums_Issue4387_RelativePath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\t// Create temp directory to simulate user's project\n\t\t\ttempPath = gfile.Temp(guid.S())\n\t\t\t// Copy testdata to temp directory\n\t\t\tsrcTestData = gtest.DataPath(\"issue\", \"4387\")\n\t\t)\n\n\t\t// Setup: create temp project structure\n\t\terr := gfile.CopyDir(srcTestData, tempPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempPath)\n\n\t\t// Save original working directory\n\t\toriginalWd := gfile.Pwd()\n\n\t\t// Change to temp directory (simulate user being in project root)\n\t\terr = gfile.Chdir(tempPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(originalWd) // Restore original working directory\n\n\t\t// Run gen enums with relative paths\n\t\tvar (\n\t\t\tsrcFolder  = \"api\"\n\t\t\toutputPath = filepath.FromSlash(\"internal/packed/packed_enums.go\")\n\t\t\tin         = genenums.CGenEnumsInput{\n\t\t\t\tSrc:  srcFolder,\n\t\t\t\tPath: outputPath,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\t_, err = genenums.CGenEnums{}.Enums(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Expected: file should be created at tempPath/internal/packed/packed_enums.go\n\t\texpectedPath := filepath.Join(tempPath, \"internal\", \"packed\", \"packed_enums.go\")\n\t\t// Bug: file is created at tempPath/api/internal/packed/packed_enums.go\n\t\twrongPath := filepath.Join(tempPath, \"api\", \"internal\", \"packed\", \"packed_enums.go\")\n\n\t\t// Assert the file is at the expected location\n\t\tt.Assert(gfile.Exists(expectedPath), true)\n\t\t// Assert the file is NOT at the wrong location\n\t\tt.Assert(gfile.Exists(wrongPath), false)\n\t})\n}\n\n// Test gen enums with absolute output path (should work correctly)\nfunc Test_Gen_Enums_AbsolutePath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttempPath    = gfile.Temp(guid.S())\n\t\t\tsrcTestData = gtest.DataPath(\"issue\", \"4387\")\n\t\t)\n\n\t\terr := gfile.CopyDir(srcTestData, tempPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempPath)\n\n\t\toriginalWd := gfile.Pwd()\n\t\terr = gfile.Chdir(tempPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(originalWd)\n\n\t\t// Use absolute path for output\n\t\tvar (\n\t\t\tsrcFolder  = \"api\"\n\t\t\toutputPath = filepath.Join(tempPath, \"internal\", \"packed\", \"packed_enums.go\")\n\t\t\tin         = genenums.CGenEnumsInput{\n\t\t\t\tSrc:  srcFolder,\n\t\t\t\tPath: outputPath,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\t_, err = genenums.CGenEnums{}.Enums(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Assert the file exists at absolute path\n\t\tt.Assert(gfile.Exists(outputPath), true)\n\t})\n}\n\n// Test gen enums in monorepo mode (cd app/xxx/ then run command)\nfunc Test_Gen_Enums_Issue4387_Monorepo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\t// Simulate monorepo structure\n\t\t\ttempPath    = gfile.Temp(guid.S())\n\t\t\tsrcTestData = gtest.DataPath(\"issue\", \"4387\")\n\t\t\t// app/myapp is the subdirectory in monorepo\n\t\t\tappPath = filepath.Join(tempPath, \"app\", \"myapp\")\n\t\t)\n\n\t\t// Create monorepo structure: tempPath/app/myapp/api/...\n\t\terr := gfile.Mkdir(appPath)\n\t\tt.AssertNil(err)\n\t\t// Copy testdata into app/myapp\n\t\terr = gfile.CopyDir(srcTestData, appPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempPath)\n\n\t\toriginalWd := gfile.Pwd()\n\n\t\t// cd app/myapp (simulate user in monorepo subdirectory)\n\t\terr = gfile.Chdir(appPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(originalWd)\n\n\t\tvar (\n\t\t\tsrcFolder  = \"api\"\n\t\t\toutputPath = filepath.FromSlash(\"internal/packed/packed_enums.go\")\n\t\t\tin         = genenums.CGenEnumsInput{\n\t\t\t\tSrc:  srcFolder,\n\t\t\t\tPath: outputPath,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\t_, err = genenums.CGenEnums{}.Enums(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Expected: file at app/myapp/internal/packed/packed_enums.go\n\t\texpectedPath := filepath.Join(appPath, \"internal\", \"packed\", \"packed_enums.go\")\n\t\t// Bug: file at app/myapp/api/internal/packed/packed_enums.go\n\t\twrongPath := filepath.Join(appPath, \"api\", \"internal\", \"packed\", \"packed_enums.go\")\n\n\t\tt.Assert(gfile.Exists(expectedPath), true)\n\t\tt.Assert(gfile.Exists(wrongPath), false)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_pb_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb\"\n)\n\nfunc TestGenPbIssue3882(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\toutputPath     = gfile.Temp(guid.S())\n\t\t\toutputApiPath  = filepath.Join(outputPath, \"api\")\n\t\t\toutputCtrlPath = filepath.Join(outputPath, \"controller\")\n\n\t\t\tprotobufFolder = gtest.DataPath(\"issue\", \"3882\")\n\t\t\tin             = genpb.CGenPbInput{\n\t\t\t\tPath:       protobufFolder,\n\t\t\t\tOutputApi:  outputApiPath,\n\t\t\t\tOutputCtrl: outputCtrlPath,\n\t\t\t}\n\t\t\terr error\n\t\t)\n\t\terr = gfile.Mkdir(outputApiPath)\n\t\tt.AssertNil(err)\n\t\terr = gfile.Mkdir(outputCtrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(outputPath)\n\n\t\t_, err = genpb.CGenPb{}.Pb(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tvar (\n\t\t\tgenContent = gfile.GetContents(filepath.Join(outputApiPath, \"issue3882.pb.go\"))\n\t\t\texceptText = `dc:\"Some comment on field with 'one' 'two' 'three' in the comment.\"`\n\t\t)\n\t\tt.Assert(gstr.Contains(genContent, exceptText), true)\n\t})\n}\n\n// This issue only occurs when executing multiple times\n// and the subsequent OutputApi is the parent directory of the previous execution\nfunc TestGenPbIssue3953(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\toutputPath     = gfile.Temp(\"f\" + guid.S())\n\t\t\toutputApiPath  = filepath.Join(outputPath, \"api\")\n\t\t\toutputCtrlPath = filepath.Join(outputPath, \"controller\")\n\n\t\t\tprotobufFolder = gtest.DataPath(\"issue\", \"3953\")\n\t\t\tin             = genpb.CGenPbInput{\n\t\t\t\tPath:       protobufFolder,\n\t\t\t\tOutputApi:  outputApiPath,\n\t\t\t\tOutputCtrl: outputCtrlPath,\n\t\t\t}\n\t\t\terr error\n\t\t)\n\t\terr = gfile.Mkdir(outputApiPath)\n\t\tt.AssertNil(err)\n\t\terr = gfile.Mkdir(outputCtrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(outputPath)\n\n\t\t_, err = genpb.CGenPb{}.Pb(ctx, in)\n\t\t// do twice,and set outputApi to outputPath\n\t\tin.OutputApi = outputPath\n\t\t_, err = genpb.CGenPb{}.Pb(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tvar (\n\t\t\tgenContent = gfile.GetContents(filepath.Join(outputApiPath, \"issue3953.pb.go\"))\n\t\t\t// The old version would have appeared `v:\"required\" v:\"required\"`\n\t\t\t// but the new version of the code will appear `v:\"required\"` only once\n\t\t\tnotExceptText = `v:\"required\" v:\"required\"`\n\t\t)\n\t\tt.Assert(gstr.Contains(genContent, notExceptText), false)\n\t})\n}\n\nfunc TestGenPb_MultipleTags(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\toutputPath     = gfile.Temp(guid.S())\n\t\t\toutputApiPath  = filepath.Join(outputPath, \"api\")\n\t\t\toutputCtrlPath = filepath.Join(outputPath, \"controller\")\n\n\t\t\tprotobufFolder = gtest.DataPath(\"genpb\")\n\t\t\tin             = genpb.CGenPbInput{\n\t\t\t\tPath:       protobufFolder,\n\t\t\t\tOutputApi:  outputApiPath,\n\t\t\t\tOutputCtrl: outputCtrlPath,\n\t\t\t}\n\t\t\terr error\n\t\t)\n\t\terr = gfile.Mkdir(outputApiPath)\n\t\tt.AssertNil(err)\n\t\terr = gfile.Mkdir(outputCtrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(outputPath)\n\n\t\t_, err = genpb.CGenPb{}.Pb(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Test multiple_tags.proto output\n\t\tgenContent := gfile.GetContents(filepath.Join(outputApiPath, \"multiple_tags.pb.go\"))\n\t\t// Id field should have combined validation tags: v:\"required#Id > 0\"\n\t\tt.Assert(gstr.Contains(genContent, `v:\"required#Id > 0\"`), true)\n\t\t// Name field should have dc tag from plain comment\n\t\tt.Assert(gstr.Contains(genContent, `dc:\"User name for login\"`), true)\n\t\t// Email field should have combined validation and dc tag\n\t\tt.Assert(gstr.Contains(genContent, `v:\"requiredemail\"`), true)\n\t\tt.Assert(gstr.Contains(genContent, `dc:\"User email address\"`), true)\n\t})\n}\n\nfunc TestGenPb_NestedMessage(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\toutputPath     = gfile.Temp(guid.S())\n\t\t\toutputApiPath  = filepath.Join(outputPath, \"api\")\n\t\t\toutputCtrlPath = filepath.Join(outputPath, \"controller\")\n\n\t\t\tprotobufFolder = gtest.DataPath(\"genpb\")\n\t\t\tin             = genpb.CGenPbInput{\n\t\t\t\tPath:       protobufFolder,\n\t\t\t\tOutputApi:  outputApiPath,\n\t\t\t\tOutputCtrl: outputCtrlPath,\n\t\t\t}\n\t\t\terr error\n\t\t)\n\t\terr = gfile.Mkdir(outputApiPath)\n\t\tt.AssertNil(err)\n\t\terr = gfile.Mkdir(outputCtrlPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(outputPath)\n\n\t\t_, err = genpb.CGenPb{}.Pb(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Test nested_message.proto output\n\t\tgenContent := gfile.GetContents(filepath.Join(outputApiPath, \"nested_message.pb.go\"))\n\t\t// Order.OrderId should have v:\"required\"\n\t\tt.Assert(gstr.Contains(genContent, `v:\"required\"`), true)\n\t\t// Order.Detail should have dc:\"Order details\"\n\t\tt.Assert(gstr.Contains(genContent, `dc:\"Order details\"`), true)\n\t\t// OrderDetail.Quantity should have v:\"min:1\"\n\t\tt.Assert(gstr.Contains(genContent, `v:\"min:1\"`), true)\n\t\t// OrderDetail.Price should have v:\"min:0.01\"\n\t\tt.Assert(gstr.Contains(genContent, `v:\"min:0.01\"`), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_pbentity_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity\"\n)\n\nfunc Test_Gen_Pbentity_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`genpbentity`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"unittest\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping:       nil,\n\t\t\t\tFieldMapping:      nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"genpbentity\", \"generated\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Gen_Pbentity_NameCase_SnakeScreaming(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`genpbentity`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"unittest\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"SnakeScreaming\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping:       nil,\n\t\t\t\tFieldMapping:      nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"genpbentity\", \"generated\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/table_user_snake_screaming.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3545\nfunc Test_Issue_3545(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`genpbentity`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping:       nil,\n\t\t\t\tFieldMapping:      nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"issue\", \"3545\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3685\nfunc Test_Issue_3685(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`issue`, `3685`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping: map[genpbentity.DBFieldTypeName]genpbentity.CustomAttributeType{\n\t\t\t\t\t\"json\": {\n\t\t\t\t\t\tType:   \"google.protobuf.Value\",\n\t\t\t\t\t\tImport: \"google/protobuf/struct.proto\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tFieldMapping: nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"issue\", \"3685\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3955\nfunc Test_Issue_3955(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable1     = \"table_user_a\"\n\t\t\ttable2     = \"table_user_b\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`genpbentity`, `user.tpl.sql`),\n\t\t\t\ttable1,\n\t\t\t)\n\t\t\tsqlContent2 = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`genpbentity`, `user.tpl.sql`),\n\t\t\t\ttable2,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table1)\n\t\tdropTableWithDb(db, table2)\n\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\n\t\tarray = gstr.SplitAndTrim(sqlContent2, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\n\t\tdefer dropTableWithDb(db, table1)\n\t\tdefer dropTableWithDb(db, table2)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"unittest\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTablesEx:          \"table_user_a\",\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\n\t\tt.AssertEQ(len(files), 1)\n\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user_b.proto\"),\n\t\t})\n\n\t\texpectFiles := []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user_b.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Issue_4330_TypeMapping_Ineffective(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr        error\n\t\t\tdb         = testDB\n\t\t\ttable      = \"table_user\"\n\t\t\tsqlContent = fmt.Sprintf(\n\t\t\t\tgtest.DataContent(`issue`, `3685`, `user.tpl.sql`),\n\t\t\t\ttable,\n\t\t\t)\n\t\t)\n\t\tdropTableWithDb(db, table)\n\t\tarray := gstr.SplitAndTrim(sqlContent, \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err = db.Exec(ctx, v); err != nil {\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTableWithDb(db, table)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tPrefix:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping: map[genpbentity.DBFieldTypeName]genpbentity.CustomAttributeType{\n\t\t\t\t\t\"json\": {\n\t\t\t\t\t\tType:   \"google.protobuf.Value\",\n\t\t\t\t\t\tImport: \"google/protobuf/struct.proto\",\n\t\t\t\t\t},\n\t\t\t\t\t\"decimal\": {\n\t\t\t\t\t\tType: \"double\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tFieldMapping: nil,\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(path, \"*.proto\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tpath + filepath.FromSlash(\"/table_user.proto\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"issue\", \"4330\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/issue4330_double.proto\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\nfunc Test_Gen_Pbentity_Sharding(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr         error\n\t\t\tdb          = testDB\n\t\t\ttableSingle = \"single_table\"\n\t\t\ttable1      = \"users_0001\"\n\t\t\ttable2      = \"users_0002\"\n\t\t\ttable3      = \"orders_0001\"\n\t\t\ttable4      = \"orders_0002\"\n\t\t\tsqlFilePath = gtest.DataPath(`gendao`, `sharding`, `sharding.sql`)\n\t\t)\n\t\tdropTableWithDb(db, tableSingle)\n\t\tdropTableWithDb(db, table1)\n\t\tdropTableWithDb(db, table2)\n\t\tdropTableWithDb(db, table3)\n\t\tdropTableWithDb(db, table4)\n\t\tt.AssertNil(execSqlFile(db, sqlFilePath))\n\t\tdefer dropTableWithDb(db, tableSingle)\n\t\tdefer dropTableWithDb(db, table1)\n\t\tdefer dropTableWithDb(db, table2)\n\t\tdefer dropTableWithDb(db, table3)\n\t\tdefer dropTableWithDb(db, table4)\n\n\t\tvar (\n\t\t\tpath = gfile.Temp(guid.S())\n\t\t\tin   = genpbentity.CGenPbEntityInput{\n\t\t\t\tPath:              path,\n\t\t\t\tPackage:           \"unittest\",\n\t\t\t\tLink:              link,\n\t\t\t\tTables:            \"\",\n\t\t\t\tRemovePrefix:      \"\",\n\t\t\t\tRemoveFieldPrefix: \"\",\n\t\t\t\tNameCase:          \"\",\n\t\t\t\tJsonCase:          \"\",\n\t\t\t\tOption:            \"\",\n\t\t\t\tTypeMapping:       nil,\n\t\t\t\tFieldMapping:      nil,\n\t\t\t\tShardingPattern: []string{\n\t\t\t\t\t`users_?`,\n\t\t\t\t\t`orders_?`,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr = gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// files\n\t\tt.AssertNil(err)\n\t\tgeneratedFiles, err := gfile.ScanDir(path, \"*.proto\", true)\n\t\tt.Assert(len(generatedFiles), 3)\n\t\tvar (\n\t\t\tmsgSingleTableContent = gfile.GetContents(gfile.Join(path, \"single_table.proto\"))\n\t\t\tmsgUsersContent       = gfile.GetContents(gfile.Join(path, \"users.proto\"))\n\t\t\tmsgOrdersContent      = gfile.GetContents(gfile.Join(path, \"orders.proto\"))\n\t\t)\n\t\tt.Assert(gstr.Contains(msgSingleTableContent, \"message SingleTable {\"), true)\n\t\tt.Assert(gstr.Contains(msgUsersContent, \"message Users {\"), true)\n\t\tt.Assert(gstr.Contains(msgOrdersContent, \"message Orders {\"), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_gen_service_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genservice\"\n)\n\nfunc Test_Gen_Service_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tdstFolder = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder = gtest.DataPath(\"genservice\", \"logic\")\n\t\t\tin        = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Snake\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        nil,\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// logic file\n\t\tvar (\n\t\t\tgenSrv       = srvFolder + filepath.FromSlash(\"/logic.go\")\n\t\t\tgenSrvExpect = srvFolder + filepath.FromSlash(\"/logic_expect.go\")\n\t\t)\n\t\tdefer gfile.Remove(genSrv)\n\t\tt.Assert(gfile.GetContents(genSrv), gfile.GetContents(genSrvExpect))\n\n\t\t// files\n\t\tfiles, err := gfile.ScanDir(dstFolder, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tdstFolder + filepath.FromSlash(\"/article.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/base.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/delivery.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/user.go\"),\n\t\t})\n\n\t\t// contents\n\t\ttestPath := gtest.DataPath(\"genservice\", \"service\")\n\t\texpectFiles := []string{\n\t\t\ttestPath + filepath.FromSlash(\"/article.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/base.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/delivery.go\"),\n\t\t\ttestPath + filepath.FromSlash(\"/user.go\"),\n\t\t}\n\t\tfor i := range files {\n\t\t\tt.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3328\nfunc Test_Issue3328(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath        = gfile.Temp(guid.S())\n\t\t\tdstFolder   = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder   = gtest.DataPath(\"issue\", \"3328\", \"logic\")\n\t\t\tlogicGoPath = srvFolder + filepath.FromSlash(\"/logic.go\")\n\t\t\tin          = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Snake\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        nil,\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\tgfile.Remove(logicGoPath)\n\t\tdefer gfile.Remove(logicGoPath)\n\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\tfiles, err := gfile.ScanDir(srvFolder, \"*\", true)\n\t\tfor _, file := range files {\n\t\t\tif file == logicGoPath {\n\t\t\t\tif gfile.IsDir(logicGoPath) {\n\t\t\t\t\tt.Fatalf(\"%s should not is folder\", logicGoPath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3835\nfunc Test_Issue3835(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tdstFolder = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder = gtest.DataPath(\"issue\", \"3835\", \"logic\")\n\t\t\tin        = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Snake\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        nil,\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// contents\n\t\tvar (\n\t\t\tgenFile    = dstFolder + filepath.FromSlash(\"/issue_3835.go\")\n\t\t\texpectFile = gtest.DataPath(\"issue\", \"3835\", \"service\", \"issue_3835.go\")\n\t\t)\n\t\tt.Assert(gfile.GetContents(genFile), gfile.GetContents(expectFile))\n\t})\n}\n\nfunc Test_Gen_Service_CamelCase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tdstFolder = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder = gtest.DataPath(\"genservice\", \"logic\")\n\t\t\tin        = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Camel\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        nil,\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// Clean up generated logic.go\n\t\tgenSrv := srvFolder + filepath.FromSlash(\"/logic.go\")\n\t\tdefer gfile.Remove(genSrv)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Files should be in CamelCase\n\t\tfiles, err := gfile.ScanDir(dstFolder, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(files, []string{\n\t\t\tdstFolder + filepath.FromSlash(\"/Article.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/Base.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/Delivery.go\"),\n\t\t\tdstFolder + filepath.FromSlash(\"/User.go\"),\n\t\t})\n\t})\n}\n\nfunc Test_Gen_Service_PackagesFilter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tdstFolder = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder = gtest.DataPath(\"genservice\", \"logic\")\n\t\t\tin        = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Snake\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        []string{\"user\"},\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t// Clean up generated logic.go\n\t\tgenSrv := srvFolder + filepath.FromSlash(\"/logic.go\")\n\t\tdefer gfile.Remove(genSrv)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Only user.go should be generated\n\t\tfiles, err := gfile.ScanDir(dstFolder, \"*.go\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 1)\n\t\tt.Assert(files[0], dstFolder+filepath.FromSlash(\"/user.go\"))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4242\n// Test that versioned imports and aliased imports are correctly preserved.\n// The issue is that imports like \"github.com/minio/minio-go/v7\" were being\n// incorrectly handled because the package name (minio) differs from\n// the directory name (minio-go).\nfunc Test_Issue4242(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath      = gfile.Temp(guid.S())\n\t\t\tdstFolder = path + filepath.FromSlash(\"/service\")\n\t\t\tsrvFolder = gtest.DataPath(\"issue\", \"4242\", \"logic\")\n\t\t\tin        = genservice.CGenServiceInput{\n\t\t\t\tSrcFolder:       srvFolder,\n\t\t\t\tDstFolder:       dstFolder,\n\t\t\t\tDstFileNameCase: \"Snake\",\n\t\t\t\tWatchFile:       \"\",\n\t\t\t\tStPattern:       \"\",\n\t\t\t\tPackages:        nil,\n\t\t\t\tImportPrefix:    \"\",\n\t\t\t\tClear:           false,\n\t\t\t}\n\t\t)\n\t\terr := gutil.FillStructWithDefault(&in)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\t_, err = genservice.CGenService{}.Service(ctx, in)\n\t\tt.AssertNil(err)\n\n\t\t// Test versioned imports\n\t\tt.Assert(\n\t\t\tgfile.GetContents(dstFolder+filepath.FromSlash(\"/issue_4242.go\")),\n\t\t\tgfile.GetContents(gtest.DataPath(\"issue\", \"4242\", \"service\", \"issue_4242.go\")),\n\t\t)\n\t\t// Test aliased imports\n\t\tt.Assert(\n\t\t\tgfile.GetContents(dstFolder+filepath.FromSlash(\"/issue_4242_alias.go\")),\n\t\t\tgfile.GetContents(gtest.DataPath(\"issue\", \"4242\", \"service\", \"issue_4242_alias.go\")),\n\t\t)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_pack_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Pack_ToGoFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"packed\", \"data.go\")\n\t\t)\n\t\t// Create source directory with test files\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create test files\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"test.txt\"), \"hello world\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"test.json\"), `{\"key\":\"value\"}`)\n\t\tt.AssertNil(err)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack to go file\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:  srcPath,\n\t\t\tDst:  dstFile,\n\t\t\tName: \"packed\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\n\t\t// Verify it's a valid Go file\n\t\tcontent := gfile.GetContents(dstFile)\n\t\tt.Assert(gstr.Contains(content, \"package packed\"), true)\n\t\tt.Assert(gstr.Contains(content, \"func init()\"), true)\n\t})\n}\n\nfunc Test_Pack_ToBinaryFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"data.bin\")\n\t\t)\n\t\t// Create source directory with test files\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create test file\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"test.txt\"), \"binary content\")\n\t\tt.AssertNil(err)\n\n\t\t// Pack to binary file (no Name specified)\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc: srcPath,\n\t\t\tDst: dstFile,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\n\t\t// Verify it's a binary file (not a Go file)\n\t\tcontent := gfile.GetContents(dstFile)\n\t\tt.Assert(gstr.Contains(content, \"package\"), false)\n\t})\n}\n\nfunc Test_Pack_MultipleSources(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath1 = gfile.Temp(guid.S())\n\t\t\tsrcPath2 = gfile.Temp(guid.S())\n\t\t\tdstPath  = gfile.Temp(guid.S())\n\t\t\tdstFile  = filepath.Join(dstPath, \"packed\", \"multi.go\")\n\t\t)\n\t\t// Create source directories\n\t\terr := gfile.Mkdir(srcPath1)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath1)\n\n\t\terr = gfile.Mkdir(srcPath2)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath2)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create test files in each source\n\t\terr = gfile.PutContents(filepath.Join(srcPath1, \"file1.txt\"), \"content1\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(srcPath2, \"file2.txt\"), \"content2\")\n\t\tt.AssertNil(err)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack multiple sources (comma-separated)\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:  srcPath1 + \",\" + srcPath2,\n\t\t\tDst:  dstFile,\n\t\t\tName: \"packed\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\t})\n}\n\nfunc Test_Pack_WithPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"packed\", \"prefix.go\")\n\t\t)\n\t\t// Create source directory\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create test file\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"test.txt\"), \"with prefix\")\n\t\tt.AssertNil(err)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack with prefix\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:    srcPath,\n\t\t\tDst:    dstFile,\n\t\t\tName:   \"packed\",\n\t\t\tPrefix: \"/static\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\t})\n}\n\nfunc Test_Pack_WithKeepPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"packed\", \"keeppath.go\")\n\t\t)\n\t\t// Create source directory with subdirectory\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create subdirectory and file\n\t\tsubDir := filepath.Join(srcPath, \"subdir\")\n\t\terr = gfile.Mkdir(subDir)\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(subDir, \"test.txt\"), \"keeppath content\")\n\t\tt.AssertNil(err)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack with keepPath\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:      srcPath,\n\t\t\tDst:      dstFile,\n\t\t\tName:     \"packed\",\n\t\t\tKeepPath: true,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\t})\n}\n\nfunc Test_Pack_AutoPackageName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"mypackage\", \"data.go\")\n\t\t)\n\t\t// Create source directory\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create test file\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"test.txt\"), \"auto package name\")\n\t\tt.AssertNil(err)\n\n\t\t// Create mypackage directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"mypackage\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack without Name - should use directory name \"mypackage\"\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc: srcPath,\n\t\t\tDst: dstFile,\n\t\t\t// Name not specified, should be auto-detected as \"mypackage\"\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists and has correct package name\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\t\tcontent := gfile.GetContents(dstFile)\n\t\tt.Assert(gstr.Contains(content, \"package mypackage\"), true)\n\t})\n}\n\nfunc Test_Pack_EmptySource(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"packed\", \"empty.go\")\n\t\t)\n\t\t// Create empty source directory\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack empty directory\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:  srcPath,\n\t\t\tDst:  dstFile,\n\t\t\tName: \"packed\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists (even if source is empty)\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\t})\n}\n\nfunc Test_Pack_NestedDirectories(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gfile.Temp(guid.S())\n\t\t\tdstPath = gfile.Temp(guid.S())\n\t\t\tdstFile = filepath.Join(dstPath, \"packed\", \"nested.go\")\n\t\t)\n\t\t// Create source directory with nested structure\n\t\terr := gfile.Mkdir(srcPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(srcPath)\n\n\t\terr = gfile.Mkdir(dstPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// Create nested directories and files\n\t\tlevel1 := filepath.Join(srcPath, \"level1\")\n\t\tlevel2 := filepath.Join(level1, \"level2\")\n\t\tlevel3 := filepath.Join(level2, \"level3\")\n\t\terr = gfile.Mkdir(level3)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.PutContents(filepath.Join(srcPath, \"root.txt\"), \"root\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(level1, \"l1.txt\"), \"level1\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(level2, \"l2.txt\"), \"level2\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(level3, \"l3.txt\"), \"level3\")\n\t\tt.AssertNil(err)\n\n\t\t// Create packed directory\n\t\terr = gfile.Mkdir(filepath.Join(dstPath, \"packed\"))\n\t\tt.AssertNil(err)\n\n\t\t// Pack nested directories\n\t\t_, err = Pack.Index(context.Background(), cPackInput{\n\t\t\tSrc:  srcPath,\n\t\t\tDst:  dstFile,\n\t\t\tName: \"packed\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify output file exists\n\t\tt.Assert(gfile.Exists(dstFile), true)\n\n\t\t// Verify content includes all files\n\t\tcontent := gfile.GetContents(dstFile)\n\t\tt.Assert(gstr.Contains(content, \"package packed\"), true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/cmd_z_unit_run_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage cmd\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_cRunApp_getWatchPaths_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{\".\"},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\tt.AssertGT(len(watchPaths), 0)\n\t\tfor _, v := range watchPaths {\n\t\t\tt.Log(v)\n\t\t}\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_EmptyWatchPaths(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should default to current directory \".\"\n\t\tt.AssertGT(len(watchPaths), 0)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_CustomIgnorePattern(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths:     []string{\"testdata\"},\n\t\t\tIgnorePatterns: []string{\"2572\"},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Ensure the \"2572\" directory is not watched directly.\n\t\tfor _, wp := range watchPaths {\n\t\t\tt.Log(\"watch path:\", wp)\n\t\t\tt.Assert(strings.HasSuffix(wp.Path, \"2572\"), false)\n\t\t}\n\t\tt.AssertGT(len(watchPaths), 0)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_WithIgnoredDirectories(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory structure for testing\n\t\ttempDir := gfile.Temp(\"gf_run_test\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create directory structure:\n\t\t// tempDir/\n\t\t//   ├── src/\n\t\t//   │   ├── api/\n\t\t//   │   └── internal/\n\t\t//   ├── vendor/  <-- ignored\n\t\t//   └── node_modules/  <-- ignored\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"api\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"internal\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"vendor\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"node_modules\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should watch tempDir non-recursively (to catch top-level files) and src recursively\n\t\tt.Assert(len(watchPaths), 2)\n\t\t// First path is tempDir (non-recursive)\n\t\tt.Assert(watchPaths[0].Path, tempDir)\n\t\tt.Assert(watchPaths[0].Recursive, false)\n\t\t// Second path is src (recursive, since it has no ignored descendants)\n\t\tt.Assert(watchPaths[1].Path, filepath.Join(tempDir, \"src\"))\n\t\tt.Assert(watchPaths[1].Recursive, true)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_NoIgnoredDirectories(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory structure without ignored directories\n\t\ttempDir := gfile.Temp(\"gf_run_test_no_ignore\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create directory structure without ignored patterns:\n\t\t// tempDir/\n\t\t//   ├── src/\n\t\t//   │   ├── api/\n\t\t//   │   └── internal/\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"api\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"internal\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should watch the root directory recursively since no ignored directories exist\n\t\tt.Assert(len(watchPaths), 1)\n\t\tt.Assert(watchPaths[0].Path, tempDir)\n\t\tt.Assert(watchPaths[0].Recursive, true)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_CustomIgnorePatterns(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory structure\n\t\ttempDir := gfile.Temp(\"gf_run_test_custom_ignore\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create directory structure:\n\t\t// tempDir/\n\t\t//   ├── src/\n\t\t//   │   ├── api/\n\t\t//   │   └── internal/\n\t\t//   ├── build/  <-- ignored\n\t\t//   └── dist/  <-- ignored\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"api\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"src\", \"internal\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"build\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"dist\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths:     []string{tempDir},\n\t\t\tIgnorePatterns: []string{\"build\", \"dist\"},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should watch tempDir non-recursively and src recursively\n\t\tt.Assert(len(watchPaths), 2)\n\t\tt.Assert(watchPaths[0].Path, tempDir)\n\t\tt.Assert(watchPaths[0].Recursive, false)\n\t\tt.Assert(watchPaths[1].Path, filepath.Join(tempDir, \"src\"))\n\t\tt.Assert(watchPaths[1].Recursive, true)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_DeepNestedStructure(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a deep nested directory structure\n\t\ttempDir := gfile.Temp(\"gf_run_test_deep\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create deep directory structure:\n\t\t// tempDir/\n\t\t//   ├── a/\n\t\t//   │   ├── b/\n\t\t//   │   │   └── c/\n\t\t//   │   └── vendor/  <-- ignored\n\t\t//   └── d/\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"a\", \"b\", \"c\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"a\", \"vendor\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"d\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should watch individual valid directories due to ignored vendor directory\n\t\tt.AssertGT(len(watchPaths), 0)\n\n\t\t// Verify that vendor directory is not in watch list\n\t\tfor _, wp := range watchPaths {\n\t\t\tt.Assert(strings.Contains(wp.Path, \"vendor\"), false)\n\t\t}\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_MultipleRoots(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create multiple temporary directories\n\t\ttempDir1 := gfile.Temp(\"gf_run_test_multi1\")\n\t\ttempDir2 := gfile.Temp(\"gf_run_test_multi2\")\n\t\tdefer gfile.Remove(tempDir1)\n\t\tdefer gfile.Remove(tempDir2)\n\n\t\tgfile.Mkdir(filepath.Join(tempDir1, \"src\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir2, \"api\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir1, tempDir2},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should watch both root directories recursively\n\t\tt.Assert(len(watchPaths), 2)\n\n\t\t// Both directories should be in the watch list\n\t\tfoundDir1, foundDir2 := false, false\n\t\tfor _, wp := range watchPaths {\n\t\t\tif wp.Path == tempDir1 {\n\t\t\t\tfoundDir1 = true\n\t\t\t\tt.Assert(wp.Recursive, true)\n\t\t\t}\n\t\t\tif wp.Path == tempDir2 {\n\t\t\t\tfoundDir2 = true\n\t\t\t\tt.Assert(wp.Recursive, true)\n\t\t\t}\n\t\t}\n\t\tt.Assert(foundDir1, true)\n\t\tt.Assert(foundDir2, true)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_NonExistentDirectory(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{\"/non/existent/path\"},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Should fall back to current directory when no valid paths found\n\t\tt.AssertGT(len(watchPaths), 0)\n\n\t\t// Should contain current directory\n\t\tcurrentDir, _ := os.Getwd()\n\t\tfoundCurrentDir := false\n\t\tfor _, wp := range watchPaths {\n\t\t\tif wp.Path == currentDir {\n\t\t\t\tfoundCurrentDir = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tt.Assert(foundCurrentDir, true)\n\t})\n}\n\nfunc Test_isIgnoredDirName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test default ignore patterns\n\t\tt.Assert(isIgnoredDirName(\"node_modules\", defaultIgnorePatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"vendor\", defaultIgnorePatterns), true)\n\t\tt.Assert(isIgnoredDirName(\".git\", defaultIgnorePatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"_private\", defaultIgnorePatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"src\", defaultIgnorePatterns), false)\n\t\tt.Assert(isIgnoredDirName(\"api\", defaultIgnorePatterns), false)\n\n\t\t// Test custom ignore patterns\n\t\tcustomPatterns := []string{\"build\", \"dist\", \"*.tmp\"}\n\t\tt.Assert(isIgnoredDirName(\"build\", customPatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"dist\", customPatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"test.tmp\", customPatterns), true)\n\t\tt.Assert(isIgnoredDirName(\"src\", customPatterns), false)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_DeeplyNestedIgnore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory structure with deeply nested ignored directory\n\t\ttempDir := gfile.Temp(\"gf_run_test_deeply_nested\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create directory structure:\n\t\t// tempDir/\n\t\t//   ├── a/\n\t\t//   │   ├── b/\n\t\t//   │   │   ├── c/\n\t\t//   │   │   │   └── vendor/  <-- deeply nested ignored (4 levels)\n\t\t//   │   │   └── d/\n\t\t//   │   └── e/\n\t\t//   └── f/\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"a\", \"b\", \"c\", \"vendor\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"a\", \"b\", \"d\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"a\", \"e\"))\n\t\tgfile.Mkdir(filepath.Join(tempDir, \"f\"))\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Expected watch paths:\n\t\t// 1. tempDir (non-recursive) - has ignored descendant\n\t\t// 2. a (non-recursive) - has ignored descendant in b/c/vendor\n\t\t// 3. b (non-recursive) - has ignored descendant in c/vendor\n\t\t// 4. c (non-recursive) - has ignored child vendor\n\t\t// 5. d (recursive) - no ignored descendants\n\t\t// 6. e (recursive) - no ignored descendants\n\t\t// 7. f (recursive) - no ignored descendants\n\n\t\tt.AssertGT(len(watchPaths), 0)\n\n\t\t// Verify vendor is not in watch paths\n\t\tfor _, wp := range watchPaths {\n\t\t\tt.Assert(strings.Contains(wp.Path, \"vendor\"), false)\n\t\t}\n\n\t\t// Find specific paths and verify their recursive flags\n\t\tfoundF := false\n\t\tfor _, wp := range watchPaths {\n\t\t\tif wp.Path == filepath.Join(tempDir, \"f\") {\n\t\t\t\tfoundF = true\n\t\t\t\tt.Assert(wp.Recursive, true) // f should be recursive (no ignored descendants)\n\t\t\t}\n\t\t}\n\t\tt.Assert(foundF, true)\n\t})\n}\n\nfunc Test_cRunApp_getWatchPaths_EmptyDirectory(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create an empty temporary directory\n\t\ttempDir := gfile.Temp(\"gf_run_test_empty\")\n\t\tdefer gfile.Remove(tempDir)\n\n\t\tgfile.Mkdir(tempDir)\n\n\t\tapp := &cRunApp{\n\t\t\tWatchPaths: []string{tempDir},\n\t\t}\n\t\twatchPaths := app.getWatchPaths()\n\n\t\t// Empty directory should be watched recursively (no ignored descendants)\n\t\tt.Assert(len(watchPaths), 1)\n\t\tt.Assert(watchPaths[0].Path, tempDir)\n\t\tt.Assert(watchPaths[0].Recursive, true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nconst (\n\tCGenCtrlConfig = `gfcli.gen.ctrl`\n\tCGenCtrlUsage  = `gf gen ctrl [OPTION]`\n\tCGenCtrlBrief  = `parse api definitions to generate controller/sdk go files`\n\tCGenCtrlEg     = `\ngf gen ctrl\n`\n\tCGenCtrlBriefSrcFolder     = `source folder path to be parsed. default: api`\n\tCGenCtrlBriefDstFolder     = `destination folder path storing automatically generated go files. default: internal/controller`\n\tCGenCtrlBriefWatchFile     = `used in file watcher, it re-generates go files only if given file is under srcFolder`\n\tCGenCtrlBriefSdkPath       = `also generate SDK go files for api definitions to specified directory`\n\tCGenCtrlBriefSdkStdVersion = `use standard version prefix for generated sdk request path`\n\tCGenCtrlBriefSdkNoV1       = `do not add version suffix for interface module name if version is v1`\n\tCGenCtrlBriefClear         = `auto delete generated and unimplemented controller go files if api definitions are missing`\n\tCGenCtrlControllerMerge    = `generate all controller files into one go file by name of api definition source go file`\n)\n\nconst (\n\tPatternCtrlDefinition = `func\\s+\\(.+?\\)\\s+\\w+\\(.+?\\*(\\w+)\\.(\\w+)Req\\)\\s+\\(.+?\\*(\\w+)\\.(\\w+)Res,\\s+\\w+\\s+error\\)\\s+{`\n)\n\nconst (\n\tgenCtrlFileLockSeconds = 10\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenCtrlConfig`:             CGenCtrlConfig,\n\t\t`CGenCtrlUsage`:              CGenCtrlUsage,\n\t\t`CGenCtrlBrief`:              CGenCtrlBrief,\n\t\t`CGenCtrlEg`:                 CGenCtrlEg,\n\t\t`CGenCtrlBriefSrcFolder`:     CGenCtrlBriefSrcFolder,\n\t\t`CGenCtrlBriefDstFolder`:     CGenCtrlBriefDstFolder,\n\t\t`CGenCtrlBriefWatchFile`:     CGenCtrlBriefWatchFile,\n\t\t`CGenCtrlBriefSdkPath`:       CGenCtrlBriefSdkPath,\n\t\t`CGenCtrlBriefSdkStdVersion`: CGenCtrlBriefSdkStdVersion,\n\t\t`CGenCtrlBriefSdkNoV1`:       CGenCtrlBriefSdkNoV1,\n\t\t`CGenCtrlBriefClear`:         CGenCtrlBriefClear,\n\t\t`CGenCtrlControllerMerge`:    CGenCtrlControllerMerge,\n\t})\n}\n\ntype (\n\tCGenCtrl      struct{}\n\tCGenCtrlInput struct {\n\t\tg.Meta        `name:\"ctrl\" config:\"{CGenCtrlConfig}\" usage:\"{CGenCtrlUsage}\" brief:\"{CGenCtrlBrief}\" eg:\"{CGenCtrlEg}\"`\n\t\tSrcFolder     string `short:\"s\" name:\"srcFolder\"     brief:\"{CGenCtrlBriefSrcFolder}\" d:\"api\"`\n\t\tDstFolder     string `short:\"d\" name:\"dstFolder\"     brief:\"{CGenCtrlBriefDstFolder}\" d:\"internal/controller\"`\n\t\tWatchFile     string `short:\"w\" name:\"watchFile\"     brief:\"{CGenCtrlBriefWatchFile}\"`\n\t\tSdkPath       string `short:\"k\" name:\"sdkPath\"       brief:\"{CGenCtrlBriefSdkPath}\"`\n\t\tSdkStdVersion bool   `short:\"v\" name:\"sdkStdVersion\" brief:\"{CGenCtrlBriefSdkStdVersion}\" orphan:\"true\"`\n\t\tSdkNoV1       bool   `short:\"n\" name:\"sdkNoV1\"       brief:\"{CGenCtrlBriefSdkNoV1}\" orphan:\"true\"`\n\t\tClear         bool   `short:\"c\" name:\"clear\"         brief:\"{CGenCtrlBriefClear}\" orphan:\"true\"`\n\t\tMerge         bool   `short:\"m\" name:\"merge\"         brief:\"{CGenCtrlControllerMerge}\" orphan:\"true\"`\n\t}\n\tCGenCtrlOutput struct{}\n)\n\nfunc (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutput, err error) {\n\tif in.WatchFile != \"\" {\n\t\terr = c.generateByWatchFile(\n\t\t\tin.WatchFile, in.SdkPath, in.SdkStdVersion, in.SdkNoV1, in.Clear, in.Merge,\n\t\t)\n\t\tmlog.Print(`done!`)\n\t\treturn\n\t}\n\n\tif !gfile.Exists(in.SrcFolder) {\n\t\tmlog.Fatalf(`source folder path \"%s\" does not exist`, in.SrcFolder)\n\t}\n\n\terr = c.generateByModules(in)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmlog.Print(`done!`)\n\treturn\n}\n\nfunc (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, sdkNoV1, clear, merge bool) (err error) {\n\t// File lock to avoid multiple processes.\n\tvar (\n\t\tflockFilePath = gfile.Temp(\"gf.cli.gen.service.lock\")\n\t\tflockContent  = gfile.GetContents(flockFilePath)\n\t)\n\tif flockContent != \"\" {\n\t\tif gtime.Timestamp()-gconv.Int64(flockContent) < genCtrlFileLockSeconds {\n\t\t\t// If another generating process is running, it just exits.\n\t\t\tmlog.Debug(`another \"gen service\" process is running, exit`)\n\t\t\treturn\n\t\t}\n\t}\n\tdefer gfile.RemoveFile(flockFilePath)\n\t_ = gfile.PutContents(flockFilePath, gtime.TimestampStr())\n\n\t// check this updated file is an api file.\n\t// watch file should be in standard goframe project structure.\n\tvar (\n\t\tapiVersionPath      = gfile.Dir(watchFile)\n\t\tapiModuleFolderPath = gfile.Dir(apiVersionPath)\n\t\tshouldBeNameOfAPi   = gfile.Basename(gfile.Dir(apiModuleFolderPath))\n\t)\n\tif shouldBeNameOfAPi != \"api\" {\n\t\treturn nil\n\t}\n\t// watch file should have api definitions.\n\tif gfile.Exists(watchFile) {\n\t\tstructsInfo, err := c.getStructsNameInSrc(watchFile)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(structsInfo) == 0 {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tvar (\n\t\tprojectRootPath     = gfile.Dir(gfile.Dir(apiModuleFolderPath))\n\t\tmodule              = gfile.Basename(apiModuleFolderPath)\n\t\tdstModuleFolderPath = gfile.Join(projectRootPath, \"internal\", \"controller\", module)\n\t)\n\treturn c.generateByModule(\n\t\tapiModuleFolderPath, dstModuleFolderPath, sdkPath, sdkStdVersion, sdkNoV1, clear, merge,\n\t)\n}\n\n// generateByModules recursively calls generateByModule for multi-level modules generation.\nfunc (c CGenCtrl) generateByModules(in CGenCtrlInput) (err error) {\n\t// read root folder, example: api/user or api/app\n\tmoduleFolderPaths, err := gfile.ScanDir(in.SrcFolder, \"*\", false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, moduleFolder := range moduleFolderPaths {\n\t\tif !gfile.IsDir(moduleFolder) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// read children folder, example: api/user/v1 or api/app/user\n\t\tchildrenFolderPaths, err := gfile.ScanDir(moduleFolder, \"*\", false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, childrenFolderPath := range childrenFolderPaths {\n\t\t\tif !gfile.IsDir(childrenFolderPath) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tinCopy = in\n\t\t\t\tmodule = gfile.Basename(moduleFolder)\n\t\t\t)\n\t\t\tinCopy.SrcFolder = gfile.Join(in.SrcFolder, module)\n\t\t\tinCopy.DstFolder = gfile.Join(in.DstFolder, module)\n\t\t\terr = c.generateByModules(inCopy)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// generate go files by api module.\n\t\tvar (\n\t\t\tmodule              = gfile.Basename(moduleFolder)\n\t\t\tdstModuleFolderPath = gfile.Join(in.DstFolder, module)\n\t\t)\n\t\terr = c.generateByModule(\n\t\t\tmoduleFolder, dstModuleFolderPath, in.SdkPath,\n\t\t\tin.SdkStdVersion, in.SdkNoV1, in.Clear, in.Merge,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn\n}\n\n// parseApiModule parses certain api and generate associated go files by certain module, not all api modules.\nfunc (c CGenCtrl) generateByModule(\n\tapiModuleFolderPath, dstModuleFolderPath, sdkPath string,\n\tsdkStdVersion, sdkNoV1, clear, merge bool,\n) (err error) {\n\t// parse src and dst folder go files.\n\tapiItemsInSrc, err := c.getApiItemsInSrc(apiModuleFolderPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tapiItemsInDst, err := c.getApiItemsInDst(dstModuleFolderPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// generate api interface go files.\n\tif err = newApiInterfaceGenerator().Generate(apiModuleFolderPath, apiItemsInSrc); err != nil {\n\t\treturn\n\t}\n\n\t// generate controller go files.\n\t// api filtering for already implemented api controllers.\n\tvar (\n\t\talreadyImplementedCtrlSet = gset.NewStrSet()\n\t\ttoBeImplementedApiItems   = make([]apiItem, 0)\n\t)\n\tfor _, item := range apiItemsInDst {\n\t\talreadyImplementedCtrlSet.Add(item.String())\n\t}\n\tfor _, item := range apiItemsInSrc {\n\t\tif alreadyImplementedCtrlSet.Contains(item.String()) {\n\t\t\tcontinue\n\t\t}\n\t\ttoBeImplementedApiItems = append(toBeImplementedApiItems, item)\n\t}\n\tif len(toBeImplementedApiItems) > 0 {\n\t\terr = newControllerGenerator().Generate(dstModuleFolderPath, toBeImplementedApiItems, merge)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// delete unimplemented controllers if api definitions are missing.\n\tif clear {\n\t\tvar (\n\t\t\tapiDefinitionSet    = gset.NewStrSet()\n\t\t\textraApiItemsInCtrl = make([]apiItem, 0)\n\t\t)\n\t\tfor _, item := range apiItemsInSrc {\n\t\t\tapiDefinitionSet.Add(item.String())\n\t\t}\n\t\tfor _, item := range apiItemsInDst {\n\t\t\tif apiDefinitionSet.Contains(item.String()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\textraApiItemsInCtrl = append(extraApiItemsInCtrl, item)\n\t\t}\n\t\tif len(extraApiItemsInCtrl) > 0 {\n\t\t\terr = newControllerClearer().Clear(dstModuleFolderPath, extraApiItemsInCtrl)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// generate sdk go files.\n\tif sdkPath != \"\" {\n\t\tif err = newApiSdkGenerator().Generate(apiItemsInSrc, sdkPath, sdkStdVersion, sdkNoV1); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_api_item.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype apiItem struct {\n\tImport     string `eg:\"demo.com/api/user/v1\"`\n\tFileName   string `eg:\"user\"`\n\tModule     string `eg:\"user\"`\n\tVersion    string `eg:\"v1\"`\n\tMethodName string `eg:\"GetList\"`\n\tComment    string `eg:\"GetList get list\"`\n}\n\nfunc (a apiItem) String() string {\n\treturn gstr.Join([]string{\n\t\ta.Import, a.Module, a.Version, a.MethodName,\n\t}, \",\")\n}\n\n// GetComment returns the comment of apiItem.\nfunc (a apiItem) GetComment() string {\n\tif a.Comment == \"\" {\n\t\treturn \"\"\n\t}\n\t// format for handling comments\n\treturn fmt.Sprintf(\"\\n// %s %s\", a.MethodName, a.Comment)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_ast_parse.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"bytes\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/printer\"\n\t\"go/token\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype structInfo struct {\n\tstructName string\n\tcomment    string\n}\n\n// getStructsNameInSrc retrieves all struct names and comment\n// that end in \"Req\" and have \"g.Meta\" in their body.\nfunc (c CGenCtrl) getStructsNameInSrc(filePath string) (structInfos []*structInfo, err error) {\n\tvar (\n\t\tfileContent = gfile.GetContents(filePath)\n\t\tfileSet     = token.NewFileSet()\n\t)\n\n\tnode, err := parser.ParseFile(fileSet, \"\", fileContent, parser.ParseComments)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tast.Inspect(node, func(n ast.Node) bool {\n\t\tif typeSpec, ok := n.(*ast.TypeSpec); ok {\n\t\t\tstructName := typeSpec.Name.Name\n\t\t\tif !gstr.HasSuffix(structName, \"Req\") {\n\t\t\t\t// ignore struct name that do not end in \"Req\"\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif structType, ok := typeSpec.Type.(*ast.StructType); ok {\n\t\t\t\tvar buf bytes.Buffer\n\t\t\t\tif err := printer.Fprint(&buf, fileSet, structType); err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t// ignore struct name that match a request, but has no g.Meta in its body.\n\t\t\t\tif !gstr.Contains(buf.String(), `g.Meta`) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\tcomment := typeSpec.Doc.Text()\n\t\t\t\t// remove the struct name from the comment\n\t\t\t\tif gstr.HasPrefix(comment, structName) {\n\t\t\t\t\tcomment = gstr.TrimLeftStr(comment, structName, 1)\n\t\t\t\t}\n\t\t\t\t// remove the comment \\n or space\n\t\t\t\tcomment = gstr.Trim(comment)\n\n\t\t\t\tstructInfos = append(structInfos, &structInfo{\n\t\t\t\t\tstructName: structName,\n\t\t\t\t\tcomment:    comment,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\n\treturn\n}\n\n// getImportsInDst retrieves all import paths in the file.\nfunc (c CGenCtrl) getImportsInDst(filePath string) (imports []string, err error) {\n\tvar (\n\t\tfileContent = gfile.GetContents(filePath)\n\t\tfileSet     = token.NewFileSet()\n\t)\n\n\tnode, err := parser.ParseFile(fileSet, \"\", fileContent, parser.ParseComments)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tast.Inspect(node, func(n ast.Node) bool {\n\t\tif imp, ok := n.(*ast.ImportSpec); ok {\n\t\t\timports = append(imports, imp.Path.Value)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_ast_parse_clear.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"bytes\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/printer\"\n\t\"go/token\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// getFuncInDst retrieves all function declarations and bodies in the file.\nfunc (c *controllerClearer) getFuncInDst(filePath string) (funcs []string, err error) {\n\tvar (\n\t\tfileContent = gfile.GetContents(filePath)\n\t\tfileSet     = token.NewFileSet()\n\t)\n\n\tnode, err := parser.ParseFile(fileSet, \"\", fileContent, parser.ParseComments)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tast.Inspect(node, func(n ast.Node) bool {\n\t\tif fun, ok := n.(*ast.FuncDecl); ok {\n\t\t\tvar buf bytes.Buffer\n\t\t\tif err := printer.Fprint(&buf, fileSet, fun); err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfuncs = append(funcs, buf.String())\n\t\t}\n\t\treturn true\n\t})\n\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_calculate.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nfunc (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, err error) {\n\tvar importPath string\n\t// The second level folders: versions.\n\tapiVersionFolderPaths, err := gfile.ScanDir(apiModuleFolderPath, \"*\", false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, apiVersionFolderPath := range apiVersionFolderPaths {\n\t\tif !gfile.IsDir(apiVersionFolderPath) {\n\t\t\tcontinue\n\t\t}\n\t\t// The second level folders: versions.\n\t\tapiFileFolderPaths, err := gfile.ScanDir(apiVersionFolderPath, \"*.go\", false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\timportPath = utils.GetImportPath(apiVersionFolderPath)\n\t\tfor _, apiFileFolderPath := range apiFileFolderPaths {\n\t\t\tif gfile.IsDir(apiFileFolderPath) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstructsInfo, err := c.getStructsNameInSrc(apiFileFolderPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor _, s := range structsInfo {\n\t\t\t\t// remove end \"Req\"\n\t\t\t\tmethodName := gstr.TrimRightStr(s.structName, \"Req\", 1)\n\t\t\t\titem := apiItem{\n\t\t\t\t\tImport:     gstr.Trim(importPath, `\"`),\n\t\t\t\t\tFileName:   gfile.Name(apiFileFolderPath),\n\t\t\t\t\tModule:     gfile.Basename(apiModuleFolderPath),\n\t\t\t\t\tVersion:    gfile.Basename(apiVersionFolderPath),\n\t\t\t\t\tMethodName: methodName,\n\t\t\t\t\tComment:    s.comment,\n\t\t\t\t}\n\t\t\t\titems = append(items, item)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c CGenCtrl) getApiItemsInDst(dstFolder string) (items []apiItem, err error) {\n\tif !gfile.Exists(dstFolder) {\n\t\treturn nil, nil\n\t}\n\ttype importItem struct {\n\t\tPath  string\n\t\tAlias string\n\t}\n\tfilePaths, err := gfile.ScanDir(dstFolder, \"*.go\", true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, filePath := range filePaths {\n\t\tvar (\n\t\t\tarray       []string\n\t\t\timportItems []importItem\n\t\t\timportLines []string\n\t\t\tmodule      = gfile.Basename(gfile.Dir(filePath))\n\t\t)\n\t\timportLines, err = c.getImportsInDst(filePath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// retrieve all imports.\n\t\tfor _, importLine := range importLines {\n\t\t\tarray = gstr.SplitAndTrim(importLine, \" \")\n\t\t\tif len(array) == 2 {\n\t\t\t\timportItems = append(importItems, importItem{\n\t\t\t\t\tPath:  gstr.Trim(array[1], `\"`),\n\t\t\t\t\tAlias: array[0],\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\timportItems = append(importItems, importItem{\n\t\t\t\t\tPath: gstr.Trim(array[0], `\"`),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\t// retrieve all api usages.\n\t\t// retrieve it without using AST, but use regular expressions to retrieve.\n\t\t// It's because the api definition is simple and regular.\n\t\t// Use regular expressions to get better performance.\n\t\tfileContent := gfile.GetContents(filePath)\n\t\tmatches, err := gregex.MatchAllString(PatternCtrlDefinition, fileContent)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, match := range matches {\n\t\t\t// try to find the import path of the api.\n\t\t\tvar (\n\t\t\t\timportPath string\n\t\t\t\tversion    = match[1]\n\t\t\t\tmethodName = match[2] // not the function name, but the method name in api definition.\n\t\t\t)\n\t\t\tfor _, item := range importItems {\n\t\t\t\tif item.Alias != \"\" {\n\t\t\t\t\tif item.Alias == version {\n\t\t\t\t\t\timportPath = item.Path\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif gfile.Basename(item.Path) == version {\n\t\t\t\t\timportPath = item.Path\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\titem := apiItem{\n\t\t\t\tImport:     gstr.Trim(importPath, `\"`),\n\t\t\t\tModule:     module,\n\t\t\t\tVersion:    gfile.Basename(importPath),\n\t\t\t\tMethodName: methodName,\n\t\t\t}\n\t\t\titems = append(items, item)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\ntype controllerGenerator struct{}\n\nfunc newControllerGenerator() *controllerGenerator {\n\treturn &controllerGenerator{}\n}\n\nfunc (c *controllerGenerator) Generate(dstModuleFolderPath string, apiModuleApiItems []apiItem, merge bool) (err error) {\n\tvar (\n\t\tdoneApiItemSet = gset.NewStrSet()\n\t)\n\tfor _, item := range apiModuleApiItems {\n\t\tif doneApiItemSet.Contains(item.String()) {\n\t\t\tcontinue\n\t\t}\n\t\t// retrieve all api items of the same module.\n\t\tvar (\n\t\t\tsubItems   = c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version)\n\t\t\timportPath = gstr.Replace(gfile.Dir(item.Import), \"\\\\\", \"/\", -1)\n\t\t)\n\t\tif err = c.doGenerateCtrlNewByModuleAndVersion(\n\t\t\tdstModuleFolderPath, item.Module, item.Version, importPath,\n\t\t); err != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// use -merge\n\t\tif merge {\n\t\t\terr = c.doGenerateCtrlMergeItem(dstModuleFolderPath, subItems, doneApiItemSet)\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, subItem := range subItems {\n\t\t\terr = c.doGenerateCtrlItem(dstModuleFolderPath, subItem)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdoneApiItemSet.Add(subItem.String())\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *controllerGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {\n\tfor _, item := range items {\n\t\tif item.Module == module && item.Version == version {\n\t\t\tsubItems = append(subItems, item)\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *controllerGenerator) doGenerateCtrlNewByModuleAndVersion(\n\tdstModuleFolderPath, module, version, importPath string,\n) (err error) {\n\tvar (\n\t\tmoduleFilePath        = filepath.FromSlash(gfile.Join(dstModuleFolderPath, module+\".go\"))\n\t\tmoduleFilePathNew     = filepath.FromSlash(gfile.Join(dstModuleFolderPath, module+\"_new.go\"))\n\t\tctrlName              = fmt.Sprintf(`Controller%s`, gstr.UcFirst(version))\n\t\tinterfaceName         = fmt.Sprintf(`%s.I%s%s`, module, gstr.CaseCamel(module), gstr.UcFirst(version))\n\t\tnewFuncName           = fmt.Sprintf(`New%s`, gstr.UcFirst(version))\n\t\tnewFuncNameDefinition = fmt.Sprintf(`func %s()`, newFuncName)\n\t\talreadyCreated        bool\n\t)\n\tif !gfile.Exists(moduleFilePath) {\n\t\tcontent := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerEmpty, g.MapStrStr{\n\t\t\t\"{Module}\": module,\n\t\t})\n\t\tif err = gfile.PutContents(moduleFilePath, gstr.TrimLeft(content)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePath))\n\t}\n\tif !gfile.Exists(moduleFilePathNew) {\n\t\tcontent := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewEmpty, g.MapStrStr{\n\t\t\t\"{Module}\":     module,\n\t\t\t\"{ImportPath}\": fmt.Sprintf(`\"%s\"`, importPath),\n\t\t})\n\t\tif err = gfile.PutContents(moduleFilePathNew, gstr.TrimLeft(content)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePathNew))\n\t}\n\tfilePaths, err := gfile.ScanDir(dstModuleFolderPath, \"*.go\", false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, filePath := range filePaths {\n\t\tif gstr.Contains(gfile.GetContents(filePath), newFuncNameDefinition) {\n\t\t\talreadyCreated = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !alreadyCreated {\n\t\tcontent := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewFunc, g.MapStrStr{\n\t\t\t\"{CtrlName}\":      ctrlName,\n\t\t\t\"{NewFuncName}\":   newFuncName,\n\t\t\t\"{InterfaceName}\": interfaceName,\n\t\t})\n\t\terr = gfile.PutContentsAppend(moduleFilePathNew, content)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, item apiItem) (err error) {\n\tvar (\n\t\tmethodNameSnake = gstr.CaseSnake(item.MethodName)\n\t\tctrlName        = fmt.Sprintf(`Controller%s`, gstr.UcFirst(item.Version))\n\t\tmethodFilePath  = filepath.FromSlash(gfile.Join(dstModuleFolderPath, fmt.Sprintf(\n\t\t\t`%s_%s_%s.go`, item.Module, item.Version, methodNameSnake,\n\t\t)))\n\t)\n\tvar content string\n\n\tif gfile.Exists(methodFilePath) {\n\t\tcontent = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{\n\t\t\t\"{Module}\":        item.Module,\n\t\t\t\"{CtrlName}\":      ctrlName,\n\t\t\t\"{Version}\":       item.Version,\n\t\t\t\"{MethodName}\":    item.MethodName,\n\t\t\t\"{MethodComment}\": item.GetComment(),\n\t\t})\n\t\t// Use AST-based checking for more accurate method detection\n\t\tif methodExists(methodFilePath, ctrlName, item.MethodName) {\n\t\t\treturn\n\t\t}\n\t\tif err = gfile.PutContentsAppend(methodFilePath, gstr.TrimLeft(content)); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tcontent = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFunc, g.MapStrStr{\n\t\t\t\"{Module}\":        item.Module,\n\t\t\t\"{ImportPath}\":    item.Import,\n\t\t\t\"{CtrlName}\":      ctrlName,\n\t\t\t\"{Version}\":       item.Version,\n\t\t\t\"{MethodName}\":    item.MethodName,\n\t\t\t\"{MethodComment}\": item.GetComment(),\n\t\t})\n\t\tif err = gfile.PutContents(methodFilePath, gstr.TrimLeft(content)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tmlog.Printf(`generated: %s`, gfile.RealPath(methodFilePath))\n\treturn\n}\n\n// use -merge\nfunc (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string, apiItems []apiItem, doneApiSet *gset.StrSet) (err error) {\n\ttype controllerFileItem struct {\n\t\tmodule     string\n\t\tversion    string\n\t\timportPath string\n\t\t// Each ctrlFileItem has multiple CTRLs\n\t\tcontrollers strings.Builder\n\t}\n\t// It is possible that there are multiple files under one module\n\tctrlFileItemMap := make(map[string]*controllerFileItem)\n\n\tfor _, api := range apiItems {\n\t\tctrlFileItem, found := ctrlFileItemMap[api.FileName]\n\t\tif !found {\n\t\t\tctrlFileItem = &controllerFileItem{\n\t\t\t\tmodule:      api.Module,\n\t\t\t\tversion:     api.Version,\n\t\t\t\tcontrollers: strings.Builder{},\n\t\t\t\timportPath:  api.Import,\n\t\t\t}\n\t\t\tctrlFileItemMap[api.FileName] = ctrlFileItem\n\t\t}\n\n\t\tctrlName := fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version))\n\t\tctrl := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{\n\t\t\t\"{Module}\":        api.Module,\n\t\t\t\"{CtrlName}\":      ctrlName,\n\t\t\t\"{Version}\":       api.Version,\n\t\t\t\"{MethodName}\":    api.MethodName,\n\t\t\t\"{MethodComment}\": api.GetComment(),\n\t\t}))\n\n\t\tctrlFilePath := gfile.Join(dstModuleFolderPath, fmt.Sprintf(\n\t\t\t`%s_%s_%s.go`, ctrlFileItem.module, ctrlFileItem.version, api.FileName,\n\t\t))\n\t\t// Use AST-based checking for more accurate method detection\n\t\tif methodExists(ctrlFilePath, ctrlName, api.MethodName) {\n\t\t\treturn\n\t\t}\n\n\t\tctrlFileItem.controllers.WriteString(ctrl)\n\t\tdoneApiSet.Add(api.String())\n\t}\n\n\tfor ctrlFileName, ctrlFileItem := range ctrlFileItemMap {\n\t\tctrlFilePath := gfile.Join(dstModuleFolderPath, fmt.Sprintf(\n\t\t\t`%s_%s_%s.go`, ctrlFileItem.module, ctrlFileItem.version, ctrlFileName,\n\t\t))\n\n\t\t// This logic is only followed when a new ctrlFileItem is generated\n\t\t// Most of the rest of the time, the following logic is followed\n\t\tif !gfile.Exists(ctrlFilePath) {\n\t\t\tctrlFileHeader := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerHeader, g.MapStrStr{\n\t\t\t\t\"{Module}\":     ctrlFileItem.module,\n\t\t\t\t\"{ImportPath}\": ctrlFileItem.importPath,\n\t\t\t}))\n\t\t\terr = gfile.PutContents(ctrlFilePath, ctrlFileHeader)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = gfile.PutContentsAppend(ctrlFilePath, ctrlFileItem.controllers.String()); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmlog.Printf(`generated: %s`, gfile.RealPath(ctrlFilePath))\n\t}\n\treturn\n}\n\n// methodExists checks if a method with the given receiver type and name exists in the file.\n// It uses AST parsing to accurately detect method definitions regardless of formatting.\n// This handles various code formatting styles including multi-line method signatures.\nfunc methodExists(filePath, ctrlName, methodName string) bool {\n\tfset := token.NewFileSet()\n\tnode, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)\n\tif err != nil {\n\t\t// If parsing fails (e.g., file doesn't exist or invalid syntax), return false\n\t\treturn false\n\t}\n\tfor _, decl := range node.Decls {\n\t\tfuncDecl, ok := decl.(*ast.FuncDecl)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\t// Check if it's a method (has receiver)\n\t\tif funcDecl.Recv != nil && len(funcDecl.Recv.List) > 0 {\n\t\t\t// Extract receiver type name\n\t\t\t// Handle both *T and T patterns\n\t\t\trecvType := \"\"\n\t\t\tswitch t := funcDecl.Recv.List[0].Type.(type) {\n\t\t\tcase *ast.StarExpr:\n\t\t\t\tif ident, ok := t.X.(*ast.Ident); ok {\n\t\t\t\t\trecvType = ident.Name\n\t\t\t\t}\n\t\t\tcase *ast.Ident:\n\t\t\t\trecvType = t.Name\n\t\t\t}\n\n\t\t\t// Check if both receiver type and method name match\n\t\t\tif recvType == ctrlName && funcDecl.Name.Name == methodName {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\ntype controllerClearer struct{}\n\nfunc newControllerClearer() *controllerClearer {\n\treturn &controllerClearer{}\n}\n\nfunc (c *controllerClearer) Clear(dstModuleFolderPath string, extraApiItemsInCtrl []apiItem) (err error) {\n\tfor _, item := range extraApiItemsInCtrl {\n\t\tif err = c.doClear(dstModuleFolderPath, item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *controllerClearer) doClear(dstModuleFolderPath string, item apiItem) (err error) {\n\tvar (\n\t\tmethodNameSnake = gstr.CaseSnake(item.MethodName)\n\t\tmethodFilePath  = gfile.Join(dstModuleFolderPath, fmt.Sprintf(\n\t\t\t`%s_%s_%s.go`, item.Module, item.Version, methodNameSnake,\n\t\t))\n\t)\n\n\tfuncs, err := c.getFuncInDst(methodFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(funcs) > 1 {\n\t\t// One line.\n\t\tif !gstr.Contains(funcs[0], \"\\n\") && gstr.Contains(funcs[0], `CodeNotImplemented`) {\n\t\t\tmlog.Printf(\n\t\t\t\t`remove unimplemented and of no api definitions controller file: %s`,\n\t\t\t\tmethodFilePath,\n\t\t\t)\n\t\t\terr = gfile.RemoveFile(methodFilePath)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_generate_interface.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype apiInterfaceGenerator struct{}\n\nfunc newApiInterfaceGenerator() *apiInterfaceGenerator {\n\treturn &apiInterfaceGenerator{}\n}\n\nfunc (c *apiInterfaceGenerator) Generate(apiModuleFolderPath string, apiModuleApiItems []apiItem) (err error) {\n\tif len(apiModuleApiItems) == 0 {\n\t\treturn nil\n\t}\n\tvar firstApiItem = apiModuleApiItems[0]\n\tif err = c.doGenerate(apiModuleFolderPath, firstApiItem.Module, apiModuleApiItems); err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc (c *apiInterfaceGenerator) doGenerate(apiModuleFolderPath string, module string, items []apiItem) (err error) {\n\tvar (\n\t\tmoduleFilePath = filepath.FromSlash(gfile.Join(apiModuleFolderPath, fmt.Sprintf(`%s.go`, module)))\n\t\timportPathMap  = gmap.NewListMap()\n\t\timportPaths    []string\n\t)\n\t// if there's already exist file that with the same but not auto generated go file,\n\t// it uses another file name.\n\tif !utils.IsFileDoNotEdit(moduleFilePath) {\n\t\tmoduleFilePath = filepath.FromSlash(gfile.Join(apiModuleFolderPath, fmt.Sprintf(`%s.if.go`, module)))\n\t}\n\t// all import paths.\n\timportPathMap.Set(\"\\t\"+`\"context\"`+\"\\n\", 1)\n\tfor _, item := range items {\n\t\timportPathMap.Set(fmt.Sprintf(\"\\t\"+`\"%s\"`, item.Import), 1)\n\t}\n\timportPaths = gconv.Strings(importPathMap.Keys())\n\t// interface definitions.\n\tvar (\n\t\tdoneApiItemSet      = gset.NewStrSet()\n\t\tinterfaceDefinition string\n\t\tinterfaceContent    = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlApiInterface, g.MapStrStr{\n\t\t\t\"{Module}\":      module,\n\t\t\t\"{ImportPaths}\": gstr.Join(importPaths, \"\\n\"),\n\t\t}))\n\t)\n\tfor _, item := range items {\n\t\tif doneApiItemSet.Contains(item.String()) {\n\t\t\tcontinue\n\t\t}\n\t\t// retrieve all api items of the same module.\n\t\tsubItems := c.getSubItemsByModuleAndVersion(items, item.Module, item.Version)\n\t\tvar (\n\t\t\tmethod        string\n\t\t\tmethods       = make([]string, 0)\n\t\t\tinterfaceName = fmt.Sprintf(`I%s%s`, gstr.CaseCamel(item.Module), gstr.UcFirst(item.Version))\n\t\t)\n\t\tfor _, subItem := range subItems {\n\t\t\tmethod = fmt.Sprintf(\n\t\t\t\t\"\\t%s(ctx context.Context, req *%s.%sReq) (res *%s.%sRes, err error)\",\n\t\t\t\tsubItem.MethodName, subItem.Version, subItem.MethodName, subItem.Version, subItem.MethodName,\n\t\t\t)\n\t\t\tmethods = append(methods, method)\n\t\t\tdoneApiItemSet.Add(subItem.String())\n\t\t}\n\t\tinterfaceDefinition += fmt.Sprintf(\"type %s interface {\", interfaceName)\n\t\tinterfaceDefinition += \"\\n\"\n\t\tinterfaceDefinition += gstr.Join(methods, \"\\n\")\n\t\tinterfaceDefinition += \"\\n\"\n\t\tinterfaceDefinition += fmt.Sprintf(\"}\")\n\t\tinterfaceDefinition += \"\\n\\n\"\n\t}\n\tinterfaceContent = gstr.TrimLeft(gstr.ReplaceByMap(interfaceContent, g.MapStrStr{\n\t\t\"{Interfaces}\": gstr.TrimRightStr(interfaceDefinition, \"\\n\", 2),\n\t}))\n\terr = gfile.PutContents(moduleFilePath, interfaceContent)\n\tmlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePath))\n\treturn\n}\n\nfunc (c *apiInterfaceGenerator) getSubItemsByModule(items []apiItem, module string) (subItems []apiItem) {\n\tfor _, item := range items {\n\t\tif item.Module == module {\n\t\t\tsubItems = append(subItems, item)\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *apiInterfaceGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {\n\tfor _, item := range items {\n\t\tif item.Module == module && item.Version == version {\n\t\t\tsubItems = append(subItems, item)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genctrl/genctrl_generate_sdk.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genctrl\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\ntype apiSdkGenerator struct{}\n\nfunc newApiSdkGenerator() *apiSdkGenerator {\n\treturn &apiSdkGenerator{}\n}\n\nfunc (c *apiSdkGenerator) Generate(apiModuleApiItems []apiItem, sdkFolderPath string, sdkStdVersion, sdkNoV1 bool) (err error) {\n\tif err = c.doGenerateSdkPkgFile(sdkFolderPath); err != nil {\n\t\treturn\n\t}\n\n\tvar doneApiItemSet = gset.NewStrSet()\n\tfor _, item := range apiModuleApiItems {\n\t\tif doneApiItemSet.Contains(item.String()) {\n\t\t\tcontinue\n\t\t}\n\t\t// retrieve all api items of the same module.\n\t\tsubItems := c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version)\n\t\tif err = c.doGenerateSdkIClient(sdkFolderPath, item.Import, item.Module, item.Version, sdkNoV1); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err = c.doGenerateSdkImplementer(\n\t\t\tsubItems, sdkFolderPath, item.Import, item.Module, item.Version, sdkStdVersion, sdkNoV1,\n\t\t); err != nil {\n\t\t\treturn\n\t\t}\n\t\tfor _, subItem := range subItems {\n\t\t\tdoneApiItemSet.Add(subItem.String())\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *apiSdkGenerator) doGenerateSdkPkgFile(sdkFolderPath string) (err error) {\n\tvar (\n\t\tpkgName     = gfile.Basename(sdkFolderPath)\n\t\tpkgFilePath = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.go`, pkgName)))\n\t\tfileContent string\n\t)\n\tif gfile.Exists(pkgFilePath) {\n\t\treturn nil\n\t}\n\tfileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkPkgNew, g.MapStrStr{\n\t\t\"{PkgName}\": pkgName,\n\t}))\n\terr = gfile.PutContents(pkgFilePath, fileContent)\n\tmlog.Printf(`generated: %s`, gfile.RealPath(pkgFilePath))\n\treturn\n}\n\nfunc (c *apiSdkGenerator) doGenerateSdkIClient(\n\tsdkFolderPath, versionImportPath, module, version string, sdkNoV1 bool,\n) (err error) {\n\tvar (\n\t\tfileContent             string\n\t\tisDirty                 bool\n\t\tisExist                 bool\n\t\tpkgName                 = gfile.Basename(sdkFolderPath)\n\t\tfuncName                = gstr.CaseCamel(module) + gstr.UcFirst(version)\n\t\tinterfaceName           = fmt.Sprintf(`I%s`, funcName)\n\t\tmoduleImportPath        = gstr.Replace(fmt.Sprintf(`\"%s\"`, gfile.Dir(versionImportPath)), \"\\\\\", \"/\", -1)\n\t\tiClientFilePath         = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.iclient.go`, pkgName)))\n\t\tinterfaceFuncDefinition = fmt.Sprintf(\n\t\t\t`%s() %s.%s`,\n\t\t\tgstr.CaseCamel(module)+gstr.UcFirst(version), module, interfaceName,\n\t\t)\n\t)\n\tif sdkNoV1 && version == \"v1\" {\n\t\tinterfaceFuncDefinition = fmt.Sprintf(\n\t\t\t`%s() %s.%s`,\n\t\t\tgstr.CaseCamel(module), module, interfaceName,\n\t\t)\n\t}\n\tif isExist = gfile.Exists(iClientFilePath); isExist {\n\t\tfileContent = gfile.GetContents(iClientFilePath)\n\t} else {\n\t\tfileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkIClient, g.MapStrStr{\n\t\t\t\"{PkgName}\": pkgName,\n\t\t}))\n\t}\n\n\t// append the import path to current import paths.\n\tif !gstr.Contains(fileContent, moduleImportPath) {\n\t\tisDirty = true\n\t\t// It is without using AST, because it is from a template.\n\t\tfileContent, err = gregex.ReplaceString(\n\t\t\t`(import \\([\\s\\S]*?)\\)`,\n\t\t\tfmt.Sprintf(\"$1\\t%s\\n)\", moduleImportPath),\n\t\t\tfileContent,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// append the function definition to interface definition.\n\tif !gstr.Contains(fileContent, interfaceFuncDefinition) {\n\t\tisDirty = true\n\t\t// It is without using AST, because it is from a template.\n\t\tfileContent, err = gregex.ReplaceString(\n\t\t\t`(type IClient interface {[\\s\\S]*?)}`,\n\t\t\tfmt.Sprintf(\"$1\\t%s\\n}\", interfaceFuncDefinition),\n\t\t\tfileContent,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tif isDirty {\n\t\terr = gfile.PutContents(iClientFilePath, fileContent)\n\t\tif isExist {\n\t\t\tmlog.Printf(`updated: %s`, gfile.RealPath(iClientFilePath))\n\t\t} else {\n\t\t\tmlog.Printf(`generated: %s`, gfile.RealPath(iClientFilePath))\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c *apiSdkGenerator) doGenerateSdkImplementer(\n\titems []apiItem, sdkFolderPath, versionImportPath, module, version string, sdkStdVersion, sdkNoV1 bool,\n) (err error) {\n\tvar (\n\t\tpkgName             = gfile.Basename(sdkFolderPath)\n\t\tmoduleNameCamel     = gstr.CaseCamel(module)\n\t\tmoduleNameSnake     = gstr.CaseSnake(module)\n\t\tmoduleImportPath    = gstr.Replace(gfile.Dir(versionImportPath), \"\\\\\", \"/\", -1)\n\t\tversionPrefix       = \"\"\n\t\timplementerName     = moduleNameCamel + gstr.UcFirst(version)\n\t\timplementerFilePath = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(\n\t\t\t`%s_%s_%s.go`, pkgName, moduleNameSnake, version,\n\t\t)))\n\t)\n\tif sdkNoV1 && version == \"v1\" {\n\t\timplementerName = moduleNameCamel\n\t}\n\t// implementer file template.\n\tvar importPaths = make([]string, 0)\n\timportPaths = append(importPaths, fmt.Sprintf(\"\\t\\\"%s\\\"\", moduleImportPath))\n\timportPaths = append(importPaths, fmt.Sprintf(\"\\t\\\"%s\\\"\", versionImportPath))\n\timplementerFileContent := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementer, g.MapStrStr{\n\t\t\"{PkgName}\":         pkgName,\n\t\t\"{ImportPaths}\":     gstr.Join(importPaths, \"\\n\"),\n\t\t\"{ImplementerName}\": implementerName,\n\t}))\n\t// implementer new function definition.\n\tif sdkStdVersion {\n\t\tversionPrefix = fmt.Sprintf(`/api/%s`, version)\n\t}\n\timplementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerNew, g.MapStrStr{\n\t\t\"{Module}\":          module,\n\t\t\"{VersionPrefix}\":   versionPrefix,\n\t\t\"{ImplementerName}\": implementerName,\n\t}))\n\t// implementer functions definitions.\n\tfor _, item := range items {\n\t\timplementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerFunc, g.MapStrStr{\n\t\t\t\"{Version}\":         item.Version,\n\t\t\t\"{MethodName}\":      item.MethodName,\n\t\t\t\"{ImplementerName}\": implementerName,\n\t\t\t\"{MethodComment}\":   item.GetComment(),\n\t\t}))\n\t\timplementerFileContent += \"\\n\"\n\t}\n\terr = gfile.PutContents(implementerFilePath, implementerFileContent)\n\tmlog.Printf(`generated: %s`, gfile.RealPath(implementerFilePath))\n\treturn\n}\n\nfunc (c *apiSdkGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {\n\tfor _, item := range items {\n\t\tif item.Module == module && item.Version == version {\n\t\t\tsubItems = append(subItems, item)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\t\"github.com/olekukonko/tablewriter/renderer\"\n\t\"github.com/olekukonko/tablewriter/tw\"\n\t\"golang.org/x/mod/modfile\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype (\n\tCGenDao      struct{}\n\tCGenDaoInput struct {\n\t\tg.Meta             `name:\"dao\" config:\"{CGenDaoConfig}\" usage:\"{CGenDaoUsage}\" brief:\"{CGenDaoBrief}\" eg:\"{CGenDaoEg}\" ad:\"{CGenDaoAd}\"`\n\t\tPath               string   `name:\"path\"                short:\"p\"  brief:\"{CGenDaoBriefPath}\" d:\"internal\"`\n\t\tLink               string   `name:\"link\"                short:\"l\"  brief:\"{CGenDaoBriefLink}\"`\n\t\tTables             string   `name:\"tables\"              short:\"t\"  brief:\"{CGenDaoBriefTables}\"`\n\t\tTablesEx           string   `name:\"tablesEx\"            short:\"x\"  brief:\"{CGenDaoBriefTablesEx}\"`\n\t\tShardingPattern    []string `name:\"shardingPattern\"     short:\"sp\" brief:\"{CGenDaoBriefShardingPattern}\"`\n\t\tGroup              string   `name:\"group\"               short:\"g\"  brief:\"{CGenDaoBriefGroup}\" d:\"default\"`\n\t\tPrefix             string   `name:\"prefix\"              short:\"f\"  brief:\"{CGenDaoBriefPrefix}\"`\n\t\tRemovePrefix       string   `name:\"removePrefix\"        short:\"r\"  brief:\"{CGenDaoBriefRemovePrefix}\"`\n\t\tRemoveFieldPrefix  string   `name:\"removeFieldPrefix\"   short:\"rf\" brief:\"{CGenDaoBriefRemoveFieldPrefix}\"`\n\t\tJsonCase           string   `name:\"jsonCase\"            short:\"j\"  brief:\"{CGenDaoBriefJsonCase}\" d:\"CamelLower\"`\n\t\tImportPrefix       string   `name:\"importPrefix\"        short:\"i\"  brief:\"{CGenDaoBriefImportPrefix}\"`\n\t\tDaoPath            string   `name:\"daoPath\"             short:\"d\"  brief:\"{CGenDaoBriefDaoPath}\" d:\"dao\"`\n\t\tTablePath          string   `name:\"tablePath\"           short:\"tp\" brief:\"{CGenDaoBriefTablePath}\" d:\"table\"`\n\t\tDoPath             string   `name:\"doPath\"              short:\"o\"  brief:\"{CGenDaoBriefDoPath}\" d:\"model/do\"`\n\t\tEntityPath         string   `name:\"entityPath\"          short:\"e\"  brief:\"{CGenDaoBriefEntityPath}\" d:\"model/entity\"`\n\t\tTplDaoTablePath    string   `name:\"tplDaoTablePath\"     short:\"t0\" brief:\"{CGenDaoBriefTplDaoTablePath}\"`\n\t\tTplDaoIndexPath    string   `name:\"tplDaoIndexPath\"     short:\"t1\" brief:\"{CGenDaoBriefTplDaoIndexPath}\"`\n\t\tTplDaoInternalPath string   `name:\"tplDaoInternalPath\"  short:\"t2\" brief:\"{CGenDaoBriefTplDaoInternalPath}\"`\n\t\tTplDaoDoPath       string   `name:\"tplDaoDoPath\"        short:\"t3\" brief:\"{CGenDaoBriefTplDaoDoPathPath}\"`\n\t\tTplDaoEntityPath   string   `name:\"tplDaoEntityPath\"    short:\"t4\" brief:\"{CGenDaoBriefTplDaoEntityPath}\"`\n\t\tStdTime            bool     `name:\"stdTime\"             short:\"s\"  brief:\"{CGenDaoBriefStdTime}\" orphan:\"true\"`\n\t\tWithTime           bool     `name:\"withTime\"            short:\"w\"  brief:\"{CGenDaoBriefWithTime}\" orphan:\"true\"`\n\t\tGJsonSupport       bool     `name:\"gJsonSupport\"        short:\"n\"  brief:\"{CGenDaoBriefGJsonSupport}\" orphan:\"true\"`\n\t\tOverwriteDao       bool     `name:\"overwriteDao\"        short:\"v\"  brief:\"{CGenDaoBriefOverwriteDao}\" orphan:\"true\"`\n\t\tDescriptionTag     bool     `name:\"descriptionTag\"      short:\"c\"  brief:\"{CGenDaoBriefDescriptionTag}\" orphan:\"true\"`\n\t\tNoJsonTag          bool     `name:\"noJsonTag\"           short:\"k\"  brief:\"{CGenDaoBriefNoJsonTag}\" orphan:\"true\"`\n\t\tNoModelComment     bool     `name:\"noModelComment\"      short:\"m\"  brief:\"{CGenDaoBriefNoModelComment}\" orphan:\"true\"`\n\t\tClear              bool     `name:\"clear\"               short:\"a\"  brief:\"{CGenDaoBriefClear}\" orphan:\"true\"`\n\t\tGenTable           bool     `name:\"genTable\"            short:\"gt\" brief:\"{CGenDaoBriefGenTable}\" orphan:\"true\"`\n\n\t\tTypeMapping  map[DBFieldTypeName]CustomAttributeType  `name:\"typeMapping\"  short:\"y\"  brief:\"{CGenDaoBriefTypeMapping}\"  orphan:\"true\"`\n\t\tFieldMapping map[DBTableFieldName]CustomAttributeType `name:\"fieldMapping\" short:\"fm\" brief:\"{CGenDaoBriefFieldMapping}\" orphan:\"true\"`\n\n\t\t// internal usage purpose.\n\t\tgenItems *CGenDaoInternalGenItems\n\t}\n\tCGenDaoOutput struct{}\n\n\tCGenDaoInternalInput struct {\n\t\tCGenDaoInput\n\t\tDB               gdb.DB\n\t\tTableNames       []string\n\t\tNewTableNames    []string\n\t\tShardingTableSet *gset.StrSet\n\t}\n\tDBTableFieldName    = string\n\tDBFieldTypeName     = string\n\tCustomAttributeType struct {\n\t\tType   string `brief:\"custom attribute type name\"`\n\t\tImport string `brief:\"custom import for this type\"`\n\t}\n)\n\nvar (\n\tcreatedAt          = gtime.Now()\n\ttplView            = gview.New()\n\tdefaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{\n\t\t\"decimal\": {\n\t\t\tType: \"float64\",\n\t\t},\n\t\t\"money\": {\n\t\t\tType: \"float64\",\n\t\t},\n\t\t\"numeric\": {\n\t\t\tType: \"float64\",\n\t\t},\n\t\t\"smallmoney\": {\n\t\t\tType: \"float64\",\n\t\t},\n\t\t\"uuid\": {\n\t\t\tType:   \"uuid.UUID\",\n\t\t\tImport: \"github.com/google/uuid\",\n\t\t},\n\t}\n\n\t// tablewriter Options\n\ttwRenderer = tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{\n\t\tBorders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.Off, Right: tw.Off},\n\t\tSettings: tw.Settings{\n\t\t\tSeparators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},\n\t\t},\n\t\tSymbols: tw.NewSymbols(tw.StyleASCII),\n\t}))\n\ttwConfig = tablewriter.WithConfig(tablewriter.Config{\n\t\tRow: tw.CellConfig{\n\t\t\tFormatting: tw.CellFormatting{AutoWrap: tw.WrapNone},\n\t\t},\n\t})\n)\n\nfunc (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {\n\tin.genItems = newCGenDaoInternalGenItems()\n\tif in.Link != \"\" {\n\t\tdoGenDaoForArray(ctx, -1, in)\n\t} else if g.Cfg().Available(ctx) {\n\t\tv := g.Cfg().MustGet(ctx, CGenDaoConfig)\n\t\tif v.IsSlice() {\n\t\t\tfor i := 0; i < len(v.Interfaces()); i++ {\n\t\t\t\tdoGenDaoForArray(ctx, i, in)\n\t\t\t}\n\t\t} else {\n\t\t\tdoGenDaoForArray(ctx, -1, in)\n\t\t}\n\t} else {\n\t\tdoGenDaoForArray(ctx, -1, in)\n\t}\n\tdoClear(in.genItems)\n\tmlog.Print(\"done!\")\n\treturn\n}\n\n// doGenDaoForArray implements the \"gen dao\" command for configuration array.\nfunc doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {\n\tvar (\n\t\terr error\n\t\tdb  gdb.DB\n\t)\n\tif index >= 0 {\n\t\terr = g.Cfg().MustGet(\n\t\t\tctx,\n\t\t\tfmt.Sprintf(`%s.%d`, CGenDaoConfig, index),\n\t\t).Scan(&in)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(`invalid configuration of \"%s\": %+v`, CGenDaoConfig, err)\n\t\t}\n\t}\n\tif dirRealPath := gfile.RealPath(in.Path); dirRealPath == \"\" {\n\t\tmlog.Fatalf(`path \"%s\" does not exist`, in.Path)\n\t}\n\tremovePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, \",\")\n\n\t// It uses user passed database configuration.\n\tif in.Link != \"\" {\n\t\tvar tempGroup = gtime.TimestampNanoStr()\n\t\terr = gdb.AddConfigNode(tempGroup, gdb.ConfigNode{\n\t\t\tLink: in.Link,\n\t\t})\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(`database configuration failed: %+v`, err)\n\t\t}\n\t\tif db, err = gdb.Instance(tempGroup); err != nil {\n\t\t\tmlog.Fatalf(`database initialization failed: %+v`, err)\n\t\t}\n\t} else {\n\t\tdb = g.DB(in.Group)\n\t}\n\tif db == nil {\n\t\tmlog.Fatal(`database initialization failed, may be invalid database configuration`)\n\t}\n\n\tvar tableNames []string\n\tif in.Tables != \"\" {\n\t\tinputTables := gstr.SplitAndTrim(in.Tables, \",\")\n\t\t// Check if any table pattern contains wildcard characters.\n\t\t// https://github.com/gogf/gf/issues/4629\n\t\tvar hasPattern bool\n\t\tfor _, t := range inputTables {\n\t\t\tif containsWildcard(t) {\n\t\t\t\thasPattern = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif hasPattern {\n\t\t\t// Fetch all tables first, then filter by patterns.\n\t\t\tallTables, err := db.Tables(context.TODO())\n\t\t\tif err != nil {\n\t\t\t\tmlog.Fatalf(\"fetching tables failed: %+v\", err)\n\t\t\t}\n\t\t\ttableNames = filterTablesByPatterns(allTables, inputTables)\n\t\t} else {\n\t\t\t// Use exact table names as before.\n\t\t\ttableNames = inputTables\n\t\t}\n\t} else {\n\t\ttableNames, err = db.Tables(context.TODO())\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"fetching tables failed: %+v\", err)\n\t\t}\n\t}\n\t// Table excluding.\n\tif in.TablesEx != \"\" {\n\t\tarray := garray.NewStrArrayFrom(tableNames)\n\t\tfor _, p := range gstr.SplitAndTrim(in.TablesEx, \",\") {\n\t\t\tif containsWildcard(p) {\n\t\t\t\t// Use exact match with ^ and $ anchors for consistency with tables pattern.\n\t\t\t\tregPattern := \"^\" + patternToRegex(p) + \"$\"\n\t\t\t\tfor _, v := range array.Clone().Slice() {\n\t\t\t\t\tif gregex.IsMatchString(regPattern, v) {\n\t\t\t\t\t\tarray.RemoveValue(v)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tarray.RemoveValue(p)\n\t\t\t}\n\t\t}\n\t\ttableNames = array.Slice()\n\t}\n\n\t// merge default typeMapping to input typeMapping.\n\tif in.TypeMapping == nil {\n\t\tin.TypeMapping = defaultTypeMapping\n\t} else {\n\t\tfor key, typeMapping := range defaultTypeMapping {\n\t\t\tif _, ok := in.TypeMapping[key]; !ok {\n\t\t\t\tin.TypeMapping[key] = typeMapping\n\t\t\t}\n\t\t}\n\t}\n\n\t// Generating dao & model go files one by one according to given table name.\n\tvar (\n\t\tnewTableNames       = make([]string, len(tableNames))\n\t\tshardingNewTableSet = gset.NewStrSet()\n\t)\n\t// Sort sharding patterns by length descending, so that longer (more specific) patterns\n\t// are matched first. This prevents shorter patterns like \"a_?\" from incorrectly matching\n\t// tables that should match longer patterns like \"a_b_?\" or \"a_c_?\".\n\t// https://github.com/gogf/gf/issues/4603\n\tsortedShardingPatterns := make([]string, len(in.ShardingPattern))\n\tcopy(sortedShardingPatterns, in.ShardingPattern)\n\tsort.Slice(sortedShardingPatterns, func(i, j int) bool {\n\t\treturn len(sortedShardingPatterns[i]) > len(sortedShardingPatterns[j])\n\t})\n\tfor i, tableName := range tableNames {\n\t\tnewTableName := tableName\n\t\tfor _, v := range removePrefixArray {\n\t\t\tnewTableName = gstr.TrimLeftStr(newTableName, v, 1)\n\t\t}\n\t\tif len(sortedShardingPatterns) > 0 {\n\t\t\tfor _, pattern := range sortedShardingPatterns {\n\t\t\t\tvar (\n\t\t\t\t\tmatch      []string\n\t\t\t\t\tregPattern = gstr.Replace(pattern, \"?\", `(.+)`)\n\t\t\t\t)\n\t\t\t\tmatch, err = gregex.MatchString(regPattern, newTableName)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmlog.Fatalf(`invalid sharding pattern \"%s\": %+v`, pattern, err)\n\t\t\t\t}\n\t\t\t\tif len(match) < 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnewTableName = gstr.Replace(pattern, \"?\", \"\")\n\t\t\t\tnewTableName = gstr.Trim(newTableName, `_.-`)\n\t\t\t\tif shardingNewTableSet.Contains(newTableName) {\n\t\t\t\t\ttableNames[i] = \"\"\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t// Add prefix to sharding table name, if not, the isSharding check would not match.\n\t\t\t\tshardingNewTableSet.Add(in.Prefix + newTableName)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tnewTableName = in.Prefix + newTableName\n\t\tif tableNames[i] != \"\" {\n\t\t\t// If shardingNewTableSet contains newTableName (tableName is empty), it should not be added to tableNames, make it empty and filter later.\n\t\t\tnewTableNames[i] = newTableName\n\t\t}\n\t}\n\ttableNames = garray.NewStrArrayFrom(tableNames).FilterEmpty().Slice()\n\tnewTableNames = garray.NewStrArrayFrom(newTableNames).FilterEmpty().Slice() // Filter empty table names. make sure that newTableNames and tableNames have the same length.\n\tin.genItems.Scale()\n\n\t// Dao: index and internal.\n\tgenerateDao(ctx, CGenDaoInternalInput{\n\t\tCGenDaoInput:     in,\n\t\tDB:               db,\n\t\tTableNames:       tableNames,\n\t\tNewTableNames:    newTableNames,\n\t\tShardingTableSet: shardingNewTableSet,\n\t})\n\t// Table: table fields.\n\tgenerateTable(ctx, CGenDaoInternalInput{\n\t\tCGenDaoInput:     in,\n\t\tDB:               db,\n\t\tTableNames:       tableNames,\n\t\tNewTableNames:    newTableNames,\n\t\tShardingTableSet: shardingNewTableSet,\n\t})\n\t// Do.\n\tgenerateDo(ctx, CGenDaoInternalInput{\n\t\tCGenDaoInput:  in,\n\t\tDB:            db,\n\t\tTableNames:    tableNames,\n\t\tNewTableNames: newTableNames,\n\t})\n\t// Entity.\n\tgenerateEntity(ctx, CGenDaoInternalInput{\n\t\tCGenDaoInput:  in,\n\t\tDB:            db,\n\t\tTableNames:    tableNames,\n\t\tNewTableNames: newTableNames,\n\t})\n\n\tin.genItems.SetClear(in.Clear)\n}\n\nfunc getImportPartContent(ctx context.Context, source string, isDo bool, appendImports []string) string {\n\tvar packageImportsArray = garray.NewStrArray()\n\tif isDo {\n\t\tpackageImportsArray.Append(`\"github.com/gogf/gf/v2/frame/g\"`)\n\t}\n\n\t// Time package recognition.\n\tif strings.Contains(source, \"gtime.Time\") {\n\t\tpackageImportsArray.Append(`\"github.com/gogf/gf/v2/os/gtime\"`)\n\t} else if strings.Contains(source, \"time.Time\") {\n\t\tpackageImportsArray.Append(`\"time\"`)\n\t}\n\n\t// Json type.\n\tif strings.Contains(source, \"gjson.Json\") {\n\t\tpackageImportsArray.Append(`\"github.com/gogf/gf/v2/encoding/gjson\"`)\n\t}\n\n\t// Check and update imports in go.mod\n\tif len(appendImports) > 0 {\n\t\tgoModPath := utils.GetModPath()\n\t\tif goModPath == \"\" {\n\t\t\tmlog.Fatal(\"go.mod not found in current project\")\n\t\t}\n\t\tmod, err := modfile.Parse(goModPath, gfile.GetBytes(goModPath), nil)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"parse go.mod failed: %+v\", err)\n\t\t}\n\t\tfor _, appendImport := range appendImports {\n\t\t\tfound := false\n\t\t\tfor _, require := range mod.Require {\n\t\t\t\tif gstr.Contains(appendImport, require.Mod.Path) {\n\t\t\t\t\tfound = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !found {\n\t\t\t\tif err = gproc.ShellRun(ctx, `go get `+appendImport); err != nil {\n\t\t\t\t\tmlog.Fatalf(`%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpackageImportsArray.Append(fmt.Sprintf(`\"%s\"`, appendImport))\n\t\t}\n\t}\n\n\t// Generate and write content to golang file.\n\tpackageImportsStr := \"\"\n\tif packageImportsArray.Len() > 0 {\n\t\tpackageImportsStr = fmt.Sprintf(\"import(\\n%s\\n)\", packageImportsArray.Join(\"\\n\"))\n\t}\n\treturn packageImportsStr\n}\n\nfunc assignDefaultVar(view *gview.View, in CGenDaoInternalInput) {\n\tvar (\n\t\ttplCreatedAtDatetimeStr string\n\t\ttplDatetimeStr          = createdAt.String()\n\t)\n\tif in.WithTime {\n\t\ttplCreatedAtDatetimeStr = fmt.Sprintf(`Created at %s`, tplDatetimeStr)\n\t}\n\tview.Assigns(g.Map{\n\t\ttplVarDatetimeStr:          tplDatetimeStr,\n\t\ttplVarCreatedAtDatetimeStr: tplCreatedAtDatetimeStr,\n\t})\n}\n\nfunc sortFieldKeyForDao(fieldMap map[string]*gdb.TableField) []string {\n\tnames := make(map[int]string)\n\tfor _, field := range fieldMap {\n\t\tnames[field.Index] = field.Name\n\t}\n\tvar (\n\t\ti      = 0\n\t\tj      = 0\n\t\tresult = make([]string, len(names))\n\t)\n\tfor {\n\t\tif len(names) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tif val, ok := names[i]; ok {\n\t\t\tresult[j] = val\n\t\t\tj++\n\t\t\tdelete(names, i)\n\t\t}\n\t\ti++\n\t}\n\treturn result\n}\n\nfunc getTemplateFromPathOrDefault(filePath string, def string) string {\n\tif filePath != \"\" {\n\t\tif contents := gfile.GetContents(filePath); contents != \"\" {\n\t\t\treturn contents\n\t\t}\n\t}\n\treturn def\n}\n\n// containsWildcard checks if the pattern contains wildcard characters (* or ?).\nfunc containsWildcard(pattern string) bool {\n\treturn gstr.Contains(pattern, \"*\") || gstr.Contains(pattern, \"?\")\n}\n\n// patternToRegex converts a wildcard pattern to a regex pattern.\n// Wildcard characters: * matches any characters, ? matches single character.\nfunc patternToRegex(pattern string) string {\n\tpattern = gstr.ReplaceByMap(pattern, map[string]string{\n\t\t\"\\r\": \"\",\n\t\t\"\\n\": \"\",\n\t})\n\tpattern = gstr.ReplaceByMap(pattern, map[string]string{\n\t\t\"*\": \"\\r\",\n\t\t\"?\": \"\\n\",\n\t})\n\tpattern = gregex.Quote(pattern)\n\tpattern = gstr.ReplaceByMap(pattern, map[string]string{\n\t\t\"\\r\": \".*\",\n\t\t\"\\n\": \".\",\n\t})\n\treturn pattern\n}\n\n// filterTablesByPatterns filters tables by given patterns.\n// Patterns support wildcard characters: * matches any characters, ? matches single character.\n// https://github.com/gogf/gf/issues/4629\nfunc filterTablesByPatterns(allTables []string, patterns []string) []string {\n\tvar result []string\n\tmatched := make(map[string]bool)\n\tallTablesSet := make(map[string]bool)\n\tfor _, t := range allTables {\n\t\tallTablesSet[t] = true\n\t}\n\tfor _, p := range patterns {\n\t\tif containsWildcard(p) {\n\t\t\tregPattern := \"^\" + patternToRegex(p) + \"$\"\n\t\t\tfor _, table := range allTables {\n\t\t\t\tif !matched[table] && gregex.IsMatchString(regPattern, table) {\n\t\t\t\t\tresult = append(result, table)\n\t\t\t\t\tmatched[table] = true\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Exact table name, use direct string comparison.\n\t\t\tif !allTablesSet[p] {\n\t\t\t\tmlog.Printf(`table \"%s\" does not exist, skipped`, p)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !matched[p] {\n\t\t\t\tresult = append(result, p)\n\t\t\t\tmatched[p] = true\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_clear.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nfunc doClear(items *CGenDaoInternalGenItems) {\n\tvar allGeneratedFilePaths = make([]string, 0)\n\tfor _, item := range items.Items {\n\t\tallGeneratedFilePaths = append(allGeneratedFilePaths, item.GeneratedFilePaths...)\n\t}\n\tfor i, v := range allGeneratedFilePaths {\n\t\tallGeneratedFilePaths[i] = gfile.RealPath(v)\n\t}\n\tfor _, item := range items.Items {\n\t\tif !item.Clear {\n\t\t\tcontinue\n\t\t}\n\t\tdoClearItem(item, allGeneratedFilePaths)\n\t}\n}\n\nfunc doClearItem(item CGenDaoInternalGenItem, allGeneratedFilePaths []string) {\n\tvar generatedFilePaths = make([]string, 0)\n\tfor _, dirPath := range item.StorageDirPaths {\n\t\tfilePaths, err := gfile.ScanDirFile(dirPath, \"*.go\", true)\n\t\tif err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t\tgeneratedFilePaths = append(generatedFilePaths, filePaths...)\n\t}\n\tfor _, filePath := range generatedFilePaths {\n\t\tif !gstr.InArray(allGeneratedFilePaths, filePath) {\n\t\t\tif err := gfile.RemoveFile(filePath); err != nil {\n\t\t\t\tmlog.Print(err)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_dao.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nfunc generateDao(ctx context.Context, in CGenDaoInternalInput) {\n\tvar (\n\t\tdirPathDao         = gfile.Join(in.Path, in.DaoPath)\n\t\tdirPathDaoInternal = gfile.Join(dirPathDao, \"internal\")\n\t)\n\tin.genItems.AppendDirPath(dirPathDao)\n\tfor i := 0; i < len(in.TableNames); i++ {\n\t\tvar (\n\t\t\trealTableName = in.TableNames[i]\n\t\t\tnewTableName  = in.NewTableNames[i]\n\t\t)\n\t\tgenerateDaoSingle(ctx, generateDaoSingleInput{\n\t\t\tCGenDaoInternalInput: in,\n\t\t\tTableName:            realTableName,\n\t\t\tNewTableName:         newTableName,\n\t\t\tDirPathDao:           dirPathDao,\n\t\t\tDirPathDaoInternal:   dirPathDaoInternal,\n\t\t\tIsSharding:           in.ShardingTableSet.Contains(newTableName),\n\t\t})\n\t}\n}\n\ntype generateDaoSingleInput struct {\n\tCGenDaoInternalInput\n\t// TableName specifies the table name of the table.\n\tTableName string\n\t// NewTableName specifies the prefix-stripped or custom edited name of the table.\n\tNewTableName       string\n\tDirPathDao         string\n\tDirPathDaoInternal string\n\tIsSharding         bool\n}\n\n// generateDaoSingle generates the dao and model content of given table.\nfunc generateDaoSingle(ctx context.Context, in generateDaoSingleInput) {\n\t// Generating table data preparing.\n\tfieldMap, err := in.DB.TableFields(ctx, in.TableName)\n\tif err != nil {\n\t\tmlog.Fatalf(`fetching tables fields failed for table \"%s\": %+v`, in.TableName, err)\n\t}\n\tvar (\n\t\ttableNameCamelCase      = formatFieldName(in.NewTableName, FieldNameCaseCamel)\n\t\ttableNameCamelLowerCase = formatFieldName(in.NewTableName, FieldNameCaseCamelLower)\n\t\ttableNameSnakeCase      = gstr.CaseSnake(in.NewTableName)\n\t\timportPrefix            = in.ImportPrefix\n\t)\n\tif importPrefix == \"\" {\n\t\timportPrefix = utils.GetImportPath(gfile.Join(in.Path, in.DaoPath))\n\t} else {\n\t\timportPrefix = gstr.Join(g.SliceStr{importPrefix, in.DaoPath}, \"/\")\n\t}\n\n\tfileName := gstr.Trim(tableNameSnakeCase, \"-_.\")\n\tif len(fileName) > 5 && fileName[len(fileName)-5:] == \"_test\" {\n\t\t// Add suffix to avoid the table name which contains \"_test\",\n\t\t// which would make the go file a testing file.\n\t\tfileName += \"_table\"\n\t}\n\n\t// dao - index\n\tgenerateDaoIndex(generateDaoIndexInput{\n\t\tgenerateDaoSingleInput:  in,\n\t\tTableNameCamelCase:      tableNameCamelCase,\n\t\tTableNameCamelLowerCase: tableNameCamelLowerCase,\n\t\tImportPrefix:            importPrefix,\n\t\tFileName:                fileName,\n\t})\n\n\t// dao - internal\n\tgenerateDaoInternal(generateDaoInternalInput{\n\t\tgenerateDaoSingleInput:  in,\n\t\tTableNameCamelCase:      tableNameCamelCase,\n\t\tTableNameCamelLowerCase: tableNameCamelLowerCase,\n\t\tImportPrefix:            importPrefix,\n\t\tFileName:                fileName,\n\t\tFieldMap:                fieldMap,\n\t})\n}\n\ntype generateDaoIndexInput struct {\n\tgenerateDaoSingleInput\n\tTableNameCamelCase      string\n\tTableNameCamelLowerCase string\n\tImportPrefix            string\n\tFileName                string\n}\n\nfunc generateDaoIndex(in generateDaoIndexInput) {\n\tpath := filepath.FromSlash(gfile.Join(in.DirPathDao, in.FileName+\".go\"))\n\t// It should add path to result slice whenever it would generate the path file or not.\n\tin.genItems.AppendGeneratedFilePath(path)\n\tif in.OverwriteDao || !gfile.Exists(path) {\n\t\tvar (\n\t\t\tctx        = context.Background()\n\t\t\ttplContent = getTemplateFromPathOrDefault(\n\t\t\t\tin.TplDaoIndexPath, consts.TemplateGenDaoIndexContent,\n\t\t\t)\n\t\t)\n\t\ttplView.ClearAssigns()\n\t\ttplView.Assigns(gview.Params{\n\t\t\ttplVarTableSharding:           in.IsSharding,\n\t\t\ttplVarTableShardingPrefix:     in.NewTableName + \"_\",\n\t\t\ttplVarImportPrefix:            in.ImportPrefix,\n\t\t\ttplVarTableName:               in.TableName,\n\t\t\ttplVarTableNameCamelCase:      in.TableNameCamelCase,\n\t\t\ttplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,\n\t\t\ttplVarPackageName:             filepath.Base(in.DaoPath),\n\t\t})\n\t\tindexContent, err := tplView.ParseContent(ctx, tplContent)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"parsing template content failed: %v\", err)\n\t\t}\n\t\tif err = gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {\n\t\t\tmlog.Fatalf(\"writing content to '%s' failed: %v\", path, err)\n\t\t} else {\n\t\t\tutils.GoFmt(path)\n\t\t\tmlog.Print(\"generated:\", gfile.RealPath(path))\n\t\t}\n\t}\n}\n\ntype generateDaoInternalInput struct {\n\tgenerateDaoSingleInput\n\tTableNameCamelCase      string\n\tTableNameCamelLowerCase string\n\tImportPrefix            string\n\tFileName                string\n\tFieldMap                map[string]*gdb.TableField\n}\n\nfunc generateDaoInternal(in generateDaoInternalInput) {\n\tvar (\n\t\tctx                    = context.Background()\n\t\tremoveFieldPrefixArray = gstr.SplitAndTrim(in.RemoveFieldPrefix, \",\")\n\t\ttplContent             = getTemplateFromPathOrDefault(\n\t\t\tin.TplDaoInternalPath, consts.TemplateGenDaoInternalContent,\n\t\t)\n\t)\n\ttplView.ClearAssigns()\n\ttplView.Assigns(gview.Params{\n\t\ttplVarImportPrefix:            in.ImportPrefix,\n\t\ttplVarTableName:               in.TableName,\n\t\ttplVarGroupName:               in.Group,\n\t\ttplVarTableNameCamelCase:      in.TableNameCamelCase,\n\t\ttplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,\n\t\ttplVarColumnDefine:            gstr.Trim(generateColumnDefinitionForDao(in.FieldMap, removeFieldPrefixArray)),\n\t\ttplVarColumnNames:             gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),\n\t})\n\tassignDefaultVar(tplView, in.CGenDaoInternalInput)\n\tmodelContent, err := tplView.ParseContent(ctx, tplContent)\n\tif err != nil {\n\t\tmlog.Fatalf(\"parsing template content failed: %v\", err)\n\t}\n\tpath := filepath.FromSlash(gfile.Join(in.DirPathDaoInternal, in.FileName+\".go\"))\n\tin.genItems.AppendGeneratedFilePath(path)\n\tif err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {\n\t\tmlog.Fatalf(\"writing content to '%s' failed: %v\", path, err)\n\t} else {\n\t\tutils.GoFmt(path)\n\t\tmlog.Print(\"generated:\", gfile.RealPath(path))\n\t}\n}\n\n// generateColumnNamesForDao generates and returns the column names assignment content of column struct\n// for specified table.\nfunc generateColumnNamesForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {\n\tvar (\n\t\tbuffer = bytes.NewBuffer(nil)\n\t\tarray  = make([][]string, len(fieldMap))\n\t\tnames  = sortFieldKeyForDao(fieldMap)\n\t)\n\n\tfor index, name := range names {\n\t\tfield := fieldMap[name]\n\n\t\tnewFiledName := field.Name\n\t\tfor _, v := range removeFieldPrefixArray {\n\t\t\tnewFiledName = gstr.TrimLeftStr(newFiledName, v, 1)\n\t\t}\n\n\t\tarray[index] = []string{\n\t\t\t\"            #\" + formatFieldName(newFiledName, FieldNameCaseCamel) + \":\",\n\t\t\tfmt.Sprintf(` #\"%s\",`, field.Name),\n\t\t}\n\t}\n\ttable := tablewriter.NewTable(buffer, twRenderer, twConfig)\n\ttable.Bulk(array)\n\ttable.Render()\n\tnamesContent := buffer.String()\n\t// Let's do this hack of table writer for indent!\n\tnamesContent = gstr.Replace(namesContent, \"  #\", \"\")\n\tbuffer.Reset()\n\tbuffer.WriteString(namesContent)\n\treturn buffer.String()\n}\n\n// generateColumnDefinitionForDao generates and returns the column names definition for specified table.\nfunc generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {\n\tvar (\n\t\tbuffer = bytes.NewBuffer(nil)\n\t\tarray  = make([][]string, len(fieldMap))\n\t\tnames  = sortFieldKeyForDao(fieldMap)\n\t)\n\n\tfor index, name := range names {\n\t\tvar (\n\t\t\tfield   = fieldMap[name]\n\t\t\tcomment = gstr.Trim(gstr.ReplaceByArray(field.Comment, g.SliceStr{\n\t\t\t\t\"\\n\", \" \",\n\t\t\t\t\"\\r\", \" \",\n\t\t\t}))\n\t\t)\n\t\tnewFiledName := field.Name\n\t\tfor _, v := range removeFieldPrefixArray {\n\t\t\tnewFiledName = gstr.TrimLeftStr(newFiledName, v, 1)\n\t\t}\n\t\tarray[index] = []string{\n\t\t\t\"    #\" + formatFieldName(newFiledName, FieldNameCaseCamel),\n\t\t\t\" # \" + \"string\",\n\t\t\t\" #\" + fmt.Sprintf(`// %s`, comment),\n\t\t}\n\t}\n\ttable := tablewriter.NewTable(buffer, twRenderer, twConfig)\n\ttable.Bulk(array)\n\ttable.Render()\n\tdefineContent := buffer.String()\n\t// Let's do this hack of table writer for indent!\n\tdefineContent = gstr.Replace(defineContent, \"  #\", \"\")\n\tbuffer.Reset()\n\tbuffer.WriteString(defineContent)\n\treturn buffer.String()\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_do.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nfunc generateDo(ctx context.Context, in CGenDaoInternalInput) {\n\tvar dirPathDo = filepath.FromSlash(gfile.Join(in.Path, in.DoPath))\n\tin.genItems.AppendDirPath(dirPathDo)\n\tin.NoJsonTag = true\n\tin.DescriptionTag = false\n\tin.NoModelComment = false\n\t// Model content.\n\tfor i, tableName := range in.TableNames {\n\t\tfieldMap, err := in.DB.TableFields(ctx, tableName)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"fetching tables fields failed for table '%s':\\n%v\", tableName, err)\n\t\t}\n\t\tvar (\n\t\t\tnewTableName        = in.NewTableNames[i]\n\t\t\tdoFilePath          = gfile.Join(dirPathDo, gstr.CaseSnake(newTableName)+\".go\")\n\t\t\tstructDefinition, _ = generateStructDefinition(ctx, generateStructDefinitionInput{\n\t\t\t\tCGenDaoInternalInput: in,\n\t\t\t\tTableName:            tableName,\n\t\t\t\tStructName:           formatFieldName(newTableName, FieldNameCaseCamel),\n\t\t\t\tFieldMap:             fieldMap,\n\t\t\t\tIsDo:                 true,\n\t\t\t})\n\t\t)\n\t\t// replace all types to any.\n\t\tstructDefinition, _ = gregex.ReplaceStringFuncMatch(\n\t\t\t\"([A-Z]\\\\w*?)\\\\s+([\\\\w\\\\*\\\\.]+?)\\\\s+(//)\",\n\t\t\tstructDefinition,\n\t\t\tfunc(match []string) string {\n\t\t\t\t// If the type is already a pointer/slice/map, it does nothing.\n\t\t\t\tif !gstr.HasPrefix(match[2], \"*\") && !gstr.HasPrefix(match[2], \"[]\") && !gstr.HasPrefix(match[2], \"map\") {\n\t\t\t\t\treturn fmt.Sprintf(`%s any %s`, match[1], match[3])\n\t\t\t\t}\n\t\t\t\treturn match[0]\n\t\t\t},\n\t\t)\n\t\tmodelContent := generateDoContent(\n\t\t\tctx,\n\t\t\tin,\n\t\t\ttableName,\n\t\t\tformatFieldName(newTableName, FieldNameCaseCamel),\n\t\t\tstructDefinition,\n\t\t)\n\t\tin.genItems.AppendGeneratedFilePath(doFilePath)\n\t\terr = gfile.PutContents(doFilePath, strings.TrimSpace(modelContent))\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(`writing content to \"%s\" failed: %v`, doFilePath, err)\n\t\t} else {\n\t\t\tutils.GoFmt(doFilePath)\n\t\t\tmlog.Print(\"generated:\", gfile.RealPath(doFilePath))\n\t\t}\n\t}\n}\n\nfunc generateDoContent(\n\tctx context.Context, in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string,\n) string {\n\tvar (\n\t\ttplContent = getTemplateFromPathOrDefault(\n\t\t\tin.TplDaoDoPath, consts.TemplateGenDaoDoContent,\n\t\t)\n\t)\n\ttplView.ClearAssigns()\n\ttplView.Assigns(gview.Params{\n\t\ttplVarTableName:          tableName,\n\t\ttplVarPackageImports:     getImportPartContent(ctx, structDefine, true, nil),\n\t\ttplVarTableNameCamelCase: tableNameCamelCase,\n\t\ttplVarStructDefine:       structDefine,\n\t\ttplVarPackageName:        filepath.Base(in.DoPath),\n\t})\n\tassignDefaultVar(tplView, in)\n\tdoContent, err := tplView.ParseContent(ctx, tplContent)\n\tif err != nil {\n\t\tmlog.Fatalf(\"parsing template content failed: %v\", err)\n\t}\n\treturn doContent\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_entity.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nfunc generateEntity(ctx context.Context, in CGenDaoInternalInput) {\n\tvar dirPathEntity = gfile.Join(in.Path, in.EntityPath)\n\tin.genItems.AppendDirPath(dirPathEntity)\n\t// Model content.\n\tfor i, tableName := range in.TableNames {\n\t\tfieldMap, err := in.DB.TableFields(ctx, tableName)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"fetching tables fields failed for table '%s':\\n%v\", tableName, err)\n\t\t}\n\n\t\tvar (\n\t\t\tnewTableName                    = in.NewTableNames[i]\n\t\t\tentityFilePath                  = filepath.FromSlash(gfile.Join(dirPathEntity, gstr.CaseSnake(newTableName)+\".go\"))\n\t\t\tstructDefinition, appendImports = generateStructDefinition(ctx, generateStructDefinitionInput{\n\t\t\t\tCGenDaoInternalInput: in,\n\t\t\t\tTableName:            tableName,\n\t\t\t\tStructName:           formatFieldName(newTableName, FieldNameCaseCamel),\n\t\t\t\tFieldMap:             fieldMap,\n\t\t\t\tIsDo:                 false,\n\t\t\t})\n\t\t\tentityContent = generateEntityContent(\n\t\t\t\tctx,\n\t\t\t\tin,\n\t\t\t\tnewTableName,\n\t\t\t\tformatFieldName(newTableName, FieldNameCaseCamel),\n\t\t\t\tstructDefinition,\n\t\t\t\tappendImports,\n\t\t\t)\n\t\t)\n\t\tin.genItems.AppendGeneratedFilePath(entityFilePath)\n\t\terr = gfile.PutContents(entityFilePath, strings.TrimSpace(entityContent))\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"writing content to '%s' failed: %v\", entityFilePath, err)\n\t\t} else {\n\t\t\tutils.GoFmt(entityFilePath)\n\t\t\tmlog.Print(\"generated:\", gfile.RealPath(entityFilePath))\n\t\t}\n\t}\n}\n\nfunc generateEntityContent(\n\tctx context.Context, in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string, appendImports []string,\n) string {\n\tvar (\n\t\ttplContent = getTemplateFromPathOrDefault(\n\t\t\tin.TplDaoEntityPath, consts.TemplateGenDaoEntityContent,\n\t\t)\n\t)\n\ttplView.ClearAssigns()\n\ttplView.Assigns(gview.Params{\n\t\ttplVarTableName:          tableName,\n\t\ttplVarPackageImports:     getImportPartContent(ctx, structDefine, false, appendImports),\n\t\ttplVarTableNameCamelCase: tableNameCamelCase,\n\t\ttplVarStructDefine:       structDefine,\n\t\ttplVarPackageName:        filepath.Base(in.EntityPath),\n\t})\n\tassignDefaultVar(tplView, in)\n\tentityContent, err := tplView.ParseContent(ctx, tplContent)\n\tif err != nil {\n\t\tmlog.Fatalf(\"parsing template content failed: %v\", err)\n\t}\n\treturn entityContent\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_gen_item.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\ntype (\n\tCGenDaoInternalGenItems struct {\n\t\tindex int\n\t\tItems []CGenDaoInternalGenItem\n\t}\n\tCGenDaoInternalGenItem struct {\n\t\tClear              bool\n\t\tStorageDirPaths    []string\n\t\tGeneratedFilePaths []string\n\t}\n)\n\nfunc newCGenDaoInternalGenItems() *CGenDaoInternalGenItems {\n\treturn &CGenDaoInternalGenItems{\n\t\tindex: -1,\n\t\tItems: make([]CGenDaoInternalGenItem, 0),\n\t}\n}\n\nfunc (i *CGenDaoInternalGenItems) Scale() {\n\ti.Items = append(i.Items, CGenDaoInternalGenItem{\n\t\tStorageDirPaths:    make([]string, 0),\n\t\tGeneratedFilePaths: make([]string, 0),\n\t\tClear:              false,\n\t})\n\ti.index++\n}\n\nfunc (i *CGenDaoInternalGenItems) SetClear(clear bool) {\n\ti.Items[i.index].Clear = clear\n}\n\nfunc (i *CGenDaoInternalGenItems) AppendDirPath(storageDirPath string) {\n\ti.Items[i.index].StorageDirPaths = append(\n\t\ti.Items[i.index].StorageDirPaths,\n\t\tstorageDirPath,\n\t)\n}\n\nfunc (i *CGenDaoInternalGenItems) AppendGeneratedFilePath(generatedFilePath string) {\n\ti.Items[i.index].GeneratedFilePaths = append(\n\t\ti.Items[i.index].GeneratedFilePaths,\n\t\tgeneratedFilePath,\n\t)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_structure.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype generateStructDefinitionInput struct {\n\tCGenDaoInternalInput\n\tTableName  string                     // Table name.\n\tStructName string                     // Struct name.\n\tFieldMap   map[string]*gdb.TableField // Table field map.\n\tIsDo       bool                       // Is generating DTO struct.\n}\n\nfunc generateStructDefinition(ctx context.Context, in generateStructDefinitionInput) (string, []string) {\n\tvar appendImports []string\n\tbuffer := bytes.NewBuffer(nil)\n\tarray := make([][]string, len(in.FieldMap))\n\tnames := sortFieldKeyForDao(in.FieldMap)\n\tfor index, name := range names {\n\t\tvar imports string\n\t\tfield := in.FieldMap[name]\n\t\tarray[index], imports = generateStructFieldDefinition(ctx, field, in)\n\t\tif imports != \"\" {\n\t\t\tappendImports = append(appendImports, imports)\n\t\t}\n\t}\n\ttable := tablewriter.NewTable(buffer, twRenderer, twConfig)\n\ttable.Bulk(array)\n\ttable.Render()\n\tstContent := buffer.String()\n\t// Let's do this hack of table writer for indent!\n\tstContent = gstr.Replace(stContent, \"  #\", \"\")\n\tstContent = gstr.Replace(stContent, \"` \", \"`\")\n\tstContent = gstr.Replace(stContent, \"``\", \"\")\n\tbuffer.Reset()\n\tfmt.Fprintf(buffer, \"type %s struct {\\n\", in.StructName)\n\tif in.IsDo {\n\t\tfmt.Fprintf(buffer, \"g.Meta `orm:\\\"table:%s, do:true\\\"`\\n\", in.TableName)\n\t}\n\tbuffer.WriteString(stContent)\n\tbuffer.WriteString(\"}\")\n\treturn buffer.String(), appendImports\n}\n\nfunc getTypeMappingInfo(\n\tctx context.Context, fieldType string, inTypeMapping map[DBFieldTypeName]CustomAttributeType,\n) (typeNameStr, importStr string) {\n\tif typeMapping, ok := inTypeMapping[strings.ToLower(fieldType)]; ok {\n\t\ttypeNameStr = typeMapping.Type\n\t\timportStr = typeMapping.Import\n\t\treturn\n\t}\n\ttryTypeMatch, _ := gregex.MatchString(`(.+?)\\(([^\\(\\)]+)\\)([\\s\\)]*)`, fieldType)\n\tvar (\n\t\ttryTypeName string\n\t\tmoreTry     bool\n\t)\n\tif len(tryTypeMatch) == 4 {\n\t\ttryTypeMatch3, _ := gregex.ReplaceString(`\\s+`, \"\", tryTypeMatch[3])\n\t\ttryTypeName = gstr.Trim(tryTypeMatch[1]) + tryTypeMatch3\n\t\tmoreTry = tryTypeMatch3 != \"\"\n\t} else {\n\t\ttryTypeName = gstr.Split(fieldType, \" \")[0]\n\t}\n\tif tryTypeName != \"\" {\n\t\tif typeMapping, ok := inTypeMapping[strings.ToLower(tryTypeName)]; ok {\n\t\t\ttypeNameStr = typeMapping.Type\n\t\t\timportStr = typeMapping.Import\n\t\t} else if moreTry {\n\t\t\ttypeNameStr, importStr = getTypeMappingInfo(ctx, tryTypeName, inTypeMapping)\n\t\t}\n\t}\n\treturn\n}\n\n// generateStructFieldDefinition generates and returns the attribute definition for specified field.\nfunc generateStructFieldDefinition(\n\tctx context.Context, field *gdb.TableField, in generateStructDefinitionInput,\n) (attrLines []string, appendImport string) {\n\tvar (\n\t\terr              error\n\t\tlocalTypeName    gdb.LocalType\n\t\tlocalTypeNameStr string\n\t)\n\n\tif in.TypeMapping != nil && len(in.TypeMapping) > 0 {\n\t\tlocalTypeNameStr, appendImport = getTypeMappingInfo(ctx, field.Type, in.TypeMapping)\n\t}\n\n\tif localTypeNameStr == \"\" {\n\t\tlocalTypeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tlocalTypeNameStr = string(localTypeName)\n\t\tswitch localTypeName {\n\t\tcase gdb.LocalTypeDate, gdb.LocalTypeTime, gdb.LocalTypeDatetime:\n\t\t\tif in.StdTime {\n\t\t\t\tlocalTypeNameStr = \"time.Time\"\n\t\t\t} else {\n\t\t\t\tlocalTypeNameStr = \"*gtime.Time\"\n\t\t\t}\n\n\t\tcase gdb.LocalTypeInt64Bytes:\n\t\t\tlocalTypeNameStr = \"int64\"\n\n\t\tcase gdb.LocalTypeUint64Bytes:\n\t\t\tlocalTypeNameStr = \"uint64\"\n\n\t\t// Special type handle.\n\t\tcase gdb.LocalTypeJson, gdb.LocalTypeJsonb:\n\t\t\tif in.GJsonSupport {\n\t\t\t\tlocalTypeNameStr = \"*gjson.Json\"\n\t\t\t} else {\n\t\t\t\tlocalTypeNameStr = \"string\"\n\t\t\t}\n\t\t}\n\t}\n\n\tvar (\n\t\ttagKey         = \"`\"\n\t\tdescriptionTag = gstr.Replace(formatComment(field.Comment), `\"`, `\\\"`)\n\t)\n\tremoveFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, \",\")\n\tnewFiledName := field.Name\n\tfor _, v := range removeFieldPrefixArray {\n\t\tnewFiledName = gstr.TrimLeftStr(newFiledName, v, 1)\n\t}\n\n\tif in.FieldMapping != nil && len(in.FieldMapping) > 0 {\n\t\tif typeMapping, ok := in.FieldMapping[fmt.Sprintf(\"%s.%s\", in.TableName, newFiledName)]; ok {\n\t\t\tlocalTypeNameStr = typeMapping.Type\n\t\t\tappendImport = typeMapping.Import\n\t\t}\n\t}\n\n\tattrLines = []string{\n\t\t\"    #\" + formatFieldName(newFiledName, FieldNameCaseCamel),\n\t\t\" #\" + localTypeNameStr,\n\t}\n\n\tjsonTag := gstr.CaseConvert(newFiledName, gstr.CaseTypeMatch(in.JsonCase))\n\tattrLines = append(attrLines, fmt.Sprintf(` #%sjson:\"%s\"`, tagKey, jsonTag))\n\t// orm tag\n\tif !in.IsDo {\n\t\t// entity\n\t\tattrLines = append(attrLines, fmt.Sprintf(` #orm:\"%s\"`, field.Name))\n\t}\n\tattrLines = append(attrLines, fmt.Sprintf(` #description:\"%s\"%s`, descriptionTag, tagKey))\n\tattrLines = append(attrLines, fmt.Sprintf(` #// %s`, formatComment(field.Comment)))\n\n\tfor k, v := range attrLines {\n\t\tif in.NoJsonTag {\n\t\t\tv, _ = gregex.ReplaceString(`json:\".+\"`, ``, v)\n\t\t}\n\t\tif !in.DescriptionTag {\n\t\t\tv, _ = gregex.ReplaceString(`description:\".*\"`, ``, v)\n\t\t}\n\t\tif in.NoModelComment {\n\t\t\tv, _ = gregex.ReplaceString(`//.+`, ``, v)\n\t\t}\n\t\tattrLines[k] = v\n\t}\n\treturn attrLines, appendImport\n}\n\ntype FieldNameCase string\n\nconst (\n\tFieldNameCaseCamel      FieldNameCase = \"CaseCamel\"\n\tFieldNameCaseCamelLower FieldNameCase = \"CaseCamelLower\"\n)\n\n// formatFieldName formats and returns a new field name that is used for golang codes generating.\nfunc formatFieldName(fieldName string, nameCase FieldNameCase) string {\n\t// For normal databases like mysql, pgsql, sqlite,\n\t// field/table names of that are in normal case.\n\tvar newFieldName = fieldName\n\tif isAllUpper(fieldName) {\n\t\t// For special databases like dm, oracle,\n\t\t// field/table names of that are in upper case.\n\t\tnewFieldName = strings.ToLower(fieldName)\n\t}\n\tswitch nameCase {\n\tcase FieldNameCaseCamel:\n\t\treturn gstr.CaseCamel(newFieldName)\n\tcase FieldNameCaseCamelLower:\n\t\treturn gstr.CaseCamelLower(newFieldName)\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// isAllUpper checks and returns whether given `fieldName` all letters are upper case.\nfunc isAllUpper(fieldName string) bool {\n\tfor _, b := range fieldName {\n\t\tif b >= 'a' && b <= 'z' {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// formatComment formats the comment string to fit the golang code without any lines.\nfunc formatComment(comment string) string {\n\tcomment = gstr.ReplaceByArray(comment, g.SliceStr{\n\t\t\"\\n\", \" \",\n\t\t\"\\r\", \" \",\n\t})\n\tcomment = gstr.Replace(comment, `\\n`, \" \")\n\tcomment = gstr.Trim(comment)\n\treturn comment\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_table.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\n// generateTable generates dao files for given tables.\nfunc generateTable(ctx context.Context, in CGenDaoInternalInput) {\n\tdirPathTable := gfile.Join(in.Path, in.TablePath)\n\tif !in.GenTable {\n\t\tif gfile.Exists(dirPathTable) {\n\t\t\tin.genItems.AppendDirPath(dirPathTable)\n\t\t}\n\t\treturn\n\t}\n\tin.genItems.AppendDirPath(dirPathTable)\n\tfor i := 0; i < len(in.TableNames); i++ {\n\t\tvar (\n\t\t\trealTableName = in.TableNames[i]\n\t\t\tnewTableName  = in.NewTableNames[i]\n\t\t)\n\t\tgenerateTableSingle(ctx, generateTableSingleInput{\n\t\t\tCGenDaoInternalInput: in,\n\t\t\tTableName:            realTableName,\n\t\t\tNewTableName:         newTableName,\n\t\t\tDirPathTable:         dirPathTable,\n\t\t})\n\t}\n}\n\n// generateTableSingleInput is the input parameter for generateTableSingle.\ntype generateTableSingleInput struct {\n\tCGenDaoInternalInput\n\t// TableName specifies the table name of the table.\n\tTableName string\n\t// NewTableName specifies the prefix-stripped or custom edited name of the table.\n\tNewTableName string\n\tDirPathTable string\n}\n\n// generateTableSingle generates dao files for a single table.\nfunc generateTableSingle(ctx context.Context, in generateTableSingleInput) {\n\t// Generating table data preparing.\n\tfieldMap, err := in.DB.TableFields(ctx, in.TableName)\n\tif err != nil {\n\t\tmlog.Fatalf(`fetching tables fields failed for table \"%s\": %+v`, in.TableName, err)\n\t}\n\n\ttableNameSnakeCase := gstr.CaseSnake(in.NewTableName)\n\tfileName := gstr.Trim(tableNameSnakeCase, \"-_.\")\n\tif len(fileName) > 5 && fileName[len(fileName)-5:] == \"_test\" {\n\t\t// Add suffix to avoid the table name which contains \"_test\",\n\t\t// which would make the go file a testing file.\n\t\tfileName += \"_table\"\n\t}\n\tpath := filepath.FromSlash(gfile.Join(in.DirPathTable, fileName+\".go\"))\n\tin.genItems.AppendGeneratedFilePath(path)\n\tif in.OverwriteDao || !gfile.Exists(path) {\n\t\tvar (\n\t\t\tctx        = context.Background()\n\t\t\ttplContent = getTemplateFromPathOrDefault(\n\t\t\t\tin.TplDaoTablePath, consts.TemplateGenTableContent,\n\t\t\t)\n\t\t)\n\t\ttplView.ClearAssigns()\n\t\ttplView.Assigns(gview.Params{\n\t\t\ttplVarGroupName:          in.Group,\n\t\t\ttplVarTableName:          in.TableName,\n\t\t\ttplVarTableNameCamelCase: formatFieldName(in.NewTableName, FieldNameCaseCamel),\n\t\t\ttplVarPackageName:        filepath.Base(in.TablePath),\n\t\t\ttplVarTableFields:        generateTableFields(fieldMap),\n\t\t})\n\t\tindexContent, err := tplView.ParseContent(ctx, tplContent)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"parsing template content failed: %v\", err)\n\t\t}\n\t\tif err = gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {\n\t\t\tmlog.Fatalf(\"writing content to '%s' failed: %v\", path, err)\n\t\t} else {\n\t\t\tutils.GoFmt(path)\n\t\t\tmlog.Print(\"generated:\", gfile.RealPath(path))\n\t\t}\n\t}\n}\n\n// generateTableFields generates and returns the field definition content for specified table.\nfunc generateTableFields(fields map[string]*gdb.TableField) string {\n\tvar buf bytes.Buffer\n\tfieldNames := make([]string, 0, len(fields))\n\tfor fieldName := range fields {\n\t\tfieldNames = append(fieldNames, fieldName)\n\t}\n\tsort.Slice(fieldNames, func(i, j int) bool {\n\t\treturn fields[fieldNames[i]].Index < fields[fieldNames[j]].Index // asc\n\t})\n\tfor index, fieldName := range fieldNames {\n\t\tfield := fields[fieldName]\n\t\tbuf.WriteString(\"    \" + strconv.Quote(field.Name) + \": {\\n\")\n\t\tbuf.WriteString(\"        Index:   \" + gconv.String(field.Index) + \",\\n\")\n\t\tbuf.WriteString(\"        Name:    \" + strconv.Quote(field.Name) + \",\\n\")\n\t\tbuf.WriteString(\"        Type:    \" + strconv.Quote(field.Type) + \",\\n\")\n\t\tbuf.WriteString(\"        Null:    \" + gconv.String(field.Null) + \",\\n\")\n\t\tbuf.WriteString(\"        Key:     \" + strconv.Quote(field.Key) + \",\\n\")\n\t\tbuf.WriteString(\"        Default: \" + generateDefaultValue(field.Default) + \",\\n\")\n\t\tbuf.WriteString(\"        Extra:   \" + strconv.Quote(field.Extra) + \",\\n\")\n\t\tbuf.WriteString(\"        Comment: \" + strconv.Quote(field.Comment) + \",\\n\")\n\t\tbuf.WriteString(\"    },\")\n\t\tif index != len(fieldNames)-1 {\n\t\t\tbuf.WriteString(\"\\n\")\n\t\t}\n\t}\n\treturn buf.String()\n}\n\n// generateDefaultValue generates and returns the default value definition for specified field.\nfunc generateDefaultValue(value interface{}) string {\n\tif value == nil {\n\t\treturn \"nil\"\n\t}\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn strconv.Quote(v)\n\tdefault:\n\t\treturn gconv.String(v)\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_tag.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nconst (\n\tCGenDaoConfig = `gfcli.gen.dao`\n\tCGenDaoUsage  = `gf gen dao [OPTION]`\n\tCGenDaoBrief  = `automatically generate go files for dao/do/entity`\n\tCGenDaoEg     = `\ngf gen dao\ngf gen dao -l \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\ngf gen dao -p ./model -g user-center -t user,user_detail,user_login\ngf gen dao -r user_\n`\n\n\tCGenDaoAd = `\nCONFIGURATION SUPPORT\n    Options are also supported by configuration file.\n    It's suggested using configuration file instead of command line arguments making producing.\n    The configuration node name is \"gfcli.gen.dao\", which also supports multiple databases, for example(config.yaml):\n\tgfcli:\n\t  gen:\n\t\tdao:\n\t\t- link:     \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n\t\t  tables:   \"order,products\"\n\t\t  jsonCase: \"CamelLower\"\n\t\t- link:   \"mysql:root:12345678@tcp(127.0.0.1:3306)/primary\"\n\t\t  path:   \"./my-app\"\n\t\t  prefix: \"primary_\"\n\t\t  tables: \"user, userDetail\"\n\t\t  typeMapping:\n\t\t\tdecimal:\n\t\t\t  type:   decimal.Decimal\n\t\t\t  import: github.com/shopspring/decimal\n\t\t\tnumeric:\n\t\t\t  type: string\n\t\t  fieldMapping:\n\t\t\ttable_name.field_name:\n\t\t\t  type:   decimal.Decimal\n\t\t\t  import: github.com/shopspring/decimal\n`\n\tCGenDaoBriefPath              = `directory path for generated files`\n\tCGenDaoBriefLink              = `database configuration, the same as the ORM configuration of GoFrame`\n\tCGenDaoBriefTables            = `generate models only for given tables, multiple table names separated with ','`\n\tCGenDaoBriefTablesEx          = `generate models excluding given tables, multiple table names separated with ','`\n\tCGenDaoBriefPrefix            = `add prefix for all table of specified link/database tables`\n\tCGenDaoBriefRemovePrefix      = `remove specified prefix of the table, multiple prefix separated with ','`\n\tCGenDaoBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`\n\tCGenDaoBriefStdTime           = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`\n\tCGenDaoBriefWithTime          = `add created time for auto produced go files`\n\tCGenDaoBriefGJsonSupport      = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`\n\tCGenDaoBriefImportPrefix      = `custom import prefix for generated go files`\n\tCGenDaoBriefDaoPath           = `directory path for storing generated dao files under path`\n\tCGenDaoBriefTablePath         = `directory path for storing generated table files under path`\n\tCGenDaoBriefDoPath            = `directory path for storing generated do files under path`\n\tCGenDaoBriefEntityPath        = `directory path for storing generated entity files under path`\n\tCGenDaoBriefOverwriteDao      = `overwrite all dao files both inside/outside internal folder`\n\tCGenDaoBriefModelFile         = `custom file name for storing generated model content`\n\tCGenDaoBriefModelFileForDao   = `custom file name generating model for DAO operations like Where/Data. It's empty in default`\n\tCGenDaoBriefDescriptionTag    = `add comment to description tag for each field`\n\tCGenDaoBriefNoJsonTag         = `no json tag will be added for each field`\n\tCGenDaoBriefNoModelComment    = `no model comment will be added for each field`\n\tCGenDaoBriefClear             = `delete all generated go files that do not exist in database`\n\tCGenDaoBriefGenTable          = `generate table files`\n\tCGenDaoBriefTypeMapping       = `custom local type mapping for generated struct attributes relevant to fields of table`\n\tCGenDaoBriefFieldMapping      = `custom local type mapping for generated struct attributes relevant to specific fields of table`\n\tCGenDaoBriefShardingPattern   = `sharding pattern for table name, e.g. \"users_?\" will be replace tables \"users_001,users_002,...\" to \"users\" dao`\n\tCGenDaoBriefGroup             = `\nspecifying the configuration group name of database for generated ORM instance,\nit's not necessary and the default value is \"default\"\n`\n\tCGenDaoBriefJsonCase = `\ngenerated json tag case for model struct, cases are as follows:\n| Case            | Example            |\n|---------------- |--------------------|\n| Camel           | AnyKindOfString    |\n| CamelLower      | anyKindOfString    | default\n| Snake           | any_kind_of_string |\n| SnakeScreaming  | ANY_KIND_OF_STRING |\n| SnakeFirstUpper | rgb_code_md5       |\n| Kebab           | any-kind-of-string |\n| KebabScreaming  | ANY-KIND-OF-STRING |\n`\n\tCGenDaoBriefTplDaoIndexPath    = `template file path for dao index file`\n\tCGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`\n\tCGenDaoBriefTplDaoDoPathPath   = `template file path for dao do file`\n\tCGenDaoBriefTplDaoEntityPath   = `template file path for dao entity file`\n\n\ttplVarTableName               = `TplTableName`\n\ttplVarTableNameCamelCase      = `TplTableNameCamelCase`\n\ttplVarTableNameCamelLowerCase = `TplTableNameCamelLowerCase`\n\ttplVarTableSharding           = `TplTableSharding`\n\ttplVarTableShardingPrefix     = `TplTableShardingPrefix`\n\ttplVarTableFields             = `TplTableFields`\n\ttplVarPackageImports          = `TplPackageImports`\n\ttplVarImportPrefix            = `TplImportPrefix`\n\ttplVarStructDefine            = `TplStructDefine`\n\ttplVarColumnDefine            = `TplColumnDefine`\n\ttplVarColumnNames             = `TplColumnNames`\n\ttplVarGroupName               = `TplGroupName`\n\ttplVarDatetimeStr             = `TplDatetimeStr`\n\ttplVarCreatedAtDatetimeStr    = `TplCreatedAtDatetimeStr`\n\ttplVarPackageName             = `TplPackageName`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenDaoConfig`:                  CGenDaoConfig,\n\t\t`CGenDaoUsage`:                   CGenDaoUsage,\n\t\t`CGenDaoBrief`:                   CGenDaoBrief,\n\t\t`CGenDaoEg`:                      CGenDaoEg,\n\t\t`CGenDaoAd`:                      CGenDaoAd,\n\t\t`CGenDaoBriefPath`:               CGenDaoBriefPath,\n\t\t`CGenDaoBriefLink`:               CGenDaoBriefLink,\n\t\t`CGenDaoBriefTables`:             CGenDaoBriefTables,\n\t\t`CGenDaoBriefTablesEx`:           CGenDaoBriefTablesEx,\n\t\t`CGenDaoBriefPrefix`:             CGenDaoBriefPrefix,\n\t\t`CGenDaoBriefRemovePrefix`:       CGenDaoBriefRemovePrefix,\n\t\t`CGenDaoBriefRemoveFieldPrefix`:  CGenDaoBriefRemoveFieldPrefix,\n\t\t`CGenDaoBriefStdTime`:            CGenDaoBriefStdTime,\n\t\t`CGenDaoBriefWithTime`:           CGenDaoBriefWithTime,\n\t\t`CGenDaoBriefDaoPath`:            CGenDaoBriefDaoPath,\n\t\t`CGenDaoBriefTablePath`:          CGenDaoBriefTablePath,\n\t\t`CGenDaoBriefDoPath`:             CGenDaoBriefDoPath,\n\t\t`CGenDaoBriefEntityPath`:         CGenDaoBriefEntityPath,\n\t\t`CGenDaoBriefGJsonSupport`:       CGenDaoBriefGJsonSupport,\n\t\t`CGenDaoBriefImportPrefix`:       CGenDaoBriefImportPrefix,\n\t\t`CGenDaoBriefOverwriteDao`:       CGenDaoBriefOverwriteDao,\n\t\t`CGenDaoBriefModelFile`:          CGenDaoBriefModelFile,\n\t\t`CGenDaoBriefModelFileForDao`:    CGenDaoBriefModelFileForDao,\n\t\t`CGenDaoBriefDescriptionTag`:     CGenDaoBriefDescriptionTag,\n\t\t`CGenDaoBriefNoJsonTag`:          CGenDaoBriefNoJsonTag,\n\t\t`CGenDaoBriefNoModelComment`:     CGenDaoBriefNoModelComment,\n\t\t`CGenDaoBriefClear`:              CGenDaoBriefClear,\n\t\t`CGenDaoBriefGenTable`:           CGenDaoBriefGenTable,\n\t\t`CGenDaoBriefTypeMapping`:        CGenDaoBriefTypeMapping,\n\t\t`CGenDaoBriefFieldMapping`:       CGenDaoBriefFieldMapping,\n\t\t`CGenDaoBriefShardingPattern`:    CGenDaoBriefShardingPattern,\n\t\t`CGenDaoBriefGroup`:              CGenDaoBriefGroup,\n\t\t`CGenDaoBriefJsonCase`:           CGenDaoBriefJsonCase,\n\t\t`CGenDaoBriefTplDaoIndexPath`:    CGenDaoBriefTplDaoIndexPath,\n\t\t`CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,\n\t\t`CGenDaoBriefTplDaoDoPathPath`:   CGenDaoBriefTplDaoDoPathPath,\n\t\t`CGenDaoBriefTplDaoEntityPath`:   CGenDaoBriefTplDaoEntityPath,\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/gendao/gendao_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gendao\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test containsWildcard function.\nfunc Test_containsWildcard(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(containsWildcard(\"trade_*\"), true)\n\t\tt.Assert(containsWildcard(\"user_?\"), true)\n\t\tt.Assert(containsWildcard(\"*\"), true)\n\t\tt.Assert(containsWildcard(\"?\"), true)\n\t\tt.Assert(containsWildcard(\"trade_order\"), false)\n\t\tt.Assert(containsWildcard(\"\"), false)\n\t})\n}\n\n// Test patternToRegex function.\nfunc Test_patternToRegex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// * should become .*\n\t\tt.Assert(patternToRegex(\"trade_*\"), \"trade_.*\")\n\t\t// ? should become .\n\t\tt.Assert(patternToRegex(\"user_???\"), \"user_...\")\n\t\t// Mixed\n\t\tt.Assert(patternToRegex(\"*_order_?\"), \".*_order_.\")\n\t\t// No wildcards - should escape special regex chars\n\t\tt.Assert(patternToRegex(\"trade_order\"), \"trade_order\")\n\t\t// Just *\n\t\tt.Assert(patternToRegex(\"*\"), \".*\")\n\t})\n}\n\n// Test filterTablesByPatterns with * wildcard.\nfunc Test_filterTablesByPatterns_Star(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\", \"user_log\", \"config\"}\n\n\t\t// Single pattern with *\n\t\tresult := filterTablesByPatterns(allTables, []string{\"trade_*\"})\n\t\tt.Assert(len(result), 2)\n\t\tt.AssertIN(\"trade_order\", result)\n\t\tt.AssertIN(\"trade_item\", result)\n\n\t\t// Multiple patterns with *\n\t\tresult = filterTablesByPatterns(allTables, []string{\"trade_*\", \"user_*\"})\n\t\tt.Assert(len(result), 4)\n\t\tt.AssertIN(\"trade_order\", result)\n\t\tt.AssertIN(\"trade_item\", result)\n\t\tt.AssertIN(\"user_info\", result)\n\t\tt.AssertIN(\"user_log\", result)\n\t})\n}\n\n// Test filterTablesByPatterns with ? wildcard.\nfunc Test_filterTablesByPatterns_Question(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\", \"user_log\", \"config\"}\n\n\t\t// ? matches single character: user_log (3 chars) but not user_info (4 chars)\n\t\tresult := filterTablesByPatterns(allTables, []string{\"user_???\"})\n\t\tt.Assert(len(result), 1)\n\t\tt.AssertIN(\"user_log\", result)\n\t\tt.AssertNI(\"user_info\", result)\n\n\t\t// user_???? should match user_info (4 chars)\n\t\tresult = filterTablesByPatterns(allTables, []string{\"user_????\"})\n\t\tt.Assert(len(result), 1)\n\t\tt.AssertIN(\"user_info\", result)\n\t\tt.AssertNI(\"user_log\", result)\n\t})\n}\n\n// Test filterTablesByPatterns with mixed patterns and exact names.\nfunc Test_filterTablesByPatterns_Mixed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\", \"user_log\", \"config\"}\n\n\t\t// Pattern + exact name\n\t\tresult := filterTablesByPatterns(allTables, []string{\"trade_*\", \"config\"})\n\t\tt.Assert(len(result), 3)\n\t\tt.AssertIN(\"trade_order\", result)\n\t\tt.AssertIN(\"trade_item\", result)\n\t\tt.AssertIN(\"config\", result)\n\t\tt.AssertNI(\"user_info\", result)\n\t\tt.AssertNI(\"user_log\", result)\n\t})\n}\n\n// Test filterTablesByPatterns with exact names only (backward compatibility).\nfunc Test_filterTablesByPatterns_ExactNames(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\", \"user_log\", \"config\"}\n\n\t\t// Exact names only\n\t\tresult := filterTablesByPatterns(allTables, []string{\"trade_order\", \"config\"})\n\t\tt.Assert(len(result), 2)\n\t\tt.AssertIN(\"trade_order\", result)\n\t\tt.AssertIN(\"config\", result)\n\t\tt.AssertNI(\"trade_item\", result)\n\t})\n}\n\n// Test filterTablesByPatterns - no duplicates when table matches multiple patterns.\nfunc Test_filterTablesByPatterns_NoDuplicates(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\"}\n\n\t\t// trade_order matches both patterns, should only appear once\n\t\tresult := filterTablesByPatterns(allTables, []string{\"trade_*\", \"trade_order\"})\n\t\tt.Assert(len(result), 2) // trade_order, trade_item\n\n\t\t// Count occurrences of trade_order\n\t\tcount := 0\n\t\tfor _, v := range result {\n\t\t\tif v == \"trade_order\" {\n\t\t\t\tcount++\n\t\t\t}\n\t\t}\n\t\tt.Assert(count, 1) // No duplicates\n\t})\n}\n\n// Test filterTablesByPatterns - pattern matches nothing.\nfunc Test_filterTablesByPatterns_NoMatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\"}\n\n\t\t// Pattern that matches nothing\n\t\tresult := filterTablesByPatterns(allTables, []string{\"nonexistent_*\"})\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test filterTablesByPatterns - empty input.\nfunc Test_filterTablesByPatterns_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\"}\n\n\t\t// Empty patterns\n\t\tresult := filterTablesByPatterns(allTables, []string{})\n\t\tt.Assert(len(result), 0)\n\n\t\t// Empty tables\n\t\tresult = filterTablesByPatterns([]string{}, []string{\"trade_*\"})\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test filterTablesByPatterns - \"*\" matches all tables.\nfunc Test_filterTablesByPatterns_MatchAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\", \"user_log\", \"config\"}\n\n\t\t// \"*\" should match all tables\n\t\tresult := filterTablesByPatterns(allTables, []string{\"*\"})\n\t\tt.Assert(len(result), 5)\n\t})\n}\n\n// Test filterTablesByPatterns - non-existent exact table name should be skipped.\nfunc Test_filterTablesByPatterns_NonExistent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tallTables := []string{\"trade_order\", \"trade_item\", \"user_info\"}\n\n\t\t// Mix of existing and non-existing tables\n\t\tresult := filterTablesByPatterns(allTables, []string{\"trade_order\", \"nonexistent\", \"user_info\"})\n\t\tt.Assert(len(result), 2)\n\t\tt.AssertIN(\"trade_order\", result)\n\t\tt.AssertIN(\"user_info\", result)\n\t\tt.AssertNI(\"nonexistent\", result)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genenums/genenums.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genenums\n\nimport (\n\t\"context\"\n\n\t\"golang.org/x/tools/go/packages\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\ntype (\n\tCGenEnums      struct{}\n\tCGenEnumsInput struct {\n\t\tg.Meta   `name:\"enums\" config:\"{CGenEnumsConfig}\" brief:\"{CGenEnumsBrief}\" eg:\"{CGenEnumsEg}\"`\n\t\tSrc      string   `name:\"src\"      short:\"s\"  dc:\"source folder path to be parsed\" d:\"api\"`\n\t\tPath     string   `name:\"path\"     short:\"p\"  dc:\"output go file path storing enums content\" d:\"internal/packed/packed_enums.go\"`\n\t\tPrefixes []string `name:\"prefixes\" short:\"x\"  dc:\"only exports packages that starts with specified prefixes\"`\n\t}\n\tCGenEnumsOutput struct{}\n)\n\nconst (\n\tCGenEnumsConfig = `gfcli.gen.enums`\n\tCGenEnumsBrief  = `parse go files in current project and generate enums go file`\n\tCGenEnumsEg     = `\ngf gen enums\ngf gen enums -p internal/packed/packed_enums.go\ngf gen enums -p internal/packed/packed_enums.go -s .\ngf gen enums -x github.com/gogf\n`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenEnumsEg`:     CGenEnumsEg,\n\t\t`CGenEnumsBrief`:  CGenEnumsBrief,\n\t\t`CGenEnumsConfig`: CGenEnumsConfig,\n\t})\n}\n\nfunc (c CGenEnums) Enums(ctx context.Context, in CGenEnumsInput) (out *CGenEnumsOutput, err error) {\n\trealPath := gfile.RealPath(in.Src)\n\tif realPath == \"\" {\n\t\tmlog.Fatalf(`source folder path \"%s\" does not exist`, in.Src)\n\t}\n\t// Convert output path to absolute before Chdir, so it remains correct after directory change.\n\t// See: https://github.com/gogf/gf/issues/4387\n\toutputPath := gfile.Abs(in.Path)\n\n\toriginPwd := gfile.Pwd()\n\tdefer gfile.Chdir(originPwd)\n\n\terr = gfile.Chdir(realPath)\n\tif err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\tmlog.Printf(`scanning for enums: %s`, realPath)\n\tcfg := &packages.Config{\n\t\tDir:   realPath,\n\t\tMode:  pkgLoadMode,\n\t\tTests: false,\n\t}\n\tpkgs, err := packages.Load(cfg)\n\tif err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\tp := NewEnumsParser(in.Prefixes)\n\tp.ParsePackages(pkgs)\n\tvar enumsContent = gstr.ReplaceByMap(consts.TemplateGenEnums, g.MapStrStr{\n\t\t\"{PackageName}\": gfile.Basename(gfile.Dir(outputPath)),\n\t\t\"{EnumsJson}\":   \"`\" + p.Export() + \"`\",\n\t})\n\tenumsContent = gstr.Trim(enumsContent)\n\tif err = gfile.PutContents(outputPath, enumsContent); err != nil {\n\t\treturn\n\t}\n\tmlog.Printf(`generated enums go file: %s`, outputPath)\n\tmlog.Print(\"done!\")\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genenums/genenums_parser.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genenums\n\nimport (\n\t\"go/constant\"\n\t\"go/types\"\n\n\t\"golang.org/x/tools/go/packages\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst pkgLoadMode = 0xffffff\n\ntype EnumsParser struct {\n\tenums            []EnumItem\n\tparsedPkg        map[string]struct{}\n\tprefixes         []string\n\tstandardPackages map[string]struct{}\n}\n\ntype EnumItem struct {\n\tName  string\n\tValue string\n\tKind  constant.Kind // String/Int/Bool/Float/Complex/Unknown\n\tType  string        // Pkg.ID + TypeName\n}\n\nfunc NewEnumsParser(prefixes []string) *EnumsParser {\n\treturn &EnumsParser{\n\t\tenums:            make([]EnumItem, 0),\n\t\tparsedPkg:        make(map[string]struct{}),\n\t\tprefixes:         prefixes,\n\t\tstandardPackages: getStandardPackages(),\n\t}\n}\n\nfunc (p *EnumsParser) ParsePackages(pkgs []*packages.Package) {\n\tfor _, pkg := range pkgs {\n\t\tp.ParsePackage(pkg)\n\t}\n}\n\nfunc (p *EnumsParser) ParsePackage(pkg *packages.Package) {\n\t// Ignore std packages.\n\tif _, ok := p.standardPackages[pkg.ID]; ok {\n\t\treturn\n\t}\n\t// Ignore pared packages.\n\tif _, ok := p.parsedPkg[pkg.ID]; ok {\n\t\treturn\n\t}\n\tp.parsedPkg[pkg.ID] = struct{}{}\n\n\t// Only parse specified prefixes.\n\tif len(p.prefixes) > 0 {\n\t\tvar hasPrefix bool\n\t\tfor _, prefix := range p.prefixes {\n\t\t\tif hasPrefix = gstr.HasPrefix(pkg.ID, prefix); hasPrefix {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !hasPrefix {\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar (\n\t\tscope = pkg.Types.Scope()\n\t\tnames = scope.Names()\n\t)\n\tfor _, name := range names {\n\t\tcon, ok := scope.Lookup(name).(*types.Const)\n\t\tif !ok {\n\t\t\t// Only constants can be enums.\n\t\t\tcontinue\n\t\t}\n\t\tif !con.Exported() {\n\t\t\t// Ignore unexported values.\n\t\t\tcontinue\n\t\t}\n\n\t\tvar enumType = con.Type().String()\n\t\tif !gstr.Contains(enumType, \"/\") {\n\t\t\t// Ignore std types.\n\t\t\tcontinue\n\t\t}\n\t\tvar (\n\t\t\tenumName  = con.Name()\n\t\t\tenumValue = con.Val().ExactString()\n\t\t\tenumKind  = con.Val().Kind()\n\t\t)\n\t\tif con.Val().Kind() == constant.String {\n\t\t\tenumValue = constant.StringVal(con.Val())\n\t\t}\n\t\tp.enums = append(p.enums, EnumItem{\n\t\t\tName:  enumName,\n\t\t\tValue: enumValue,\n\t\t\tType:  enumType,\n\t\t\tKind:  enumKind,\n\t\t})\n\t}\n\tfor _, im := range pkg.Imports {\n\t\tp.ParsePackage(im)\n\t}\n}\n\nfunc (p *EnumsParser) Export() string {\n\tvar typeEnumMap = make(map[string][]any)\n\tfor _, enum := range p.enums {\n\t\tif typeEnumMap[enum.Type] == nil {\n\t\t\ttypeEnumMap[enum.Type] = make([]any, 0)\n\t\t}\n\t\tvar value any\n\t\tswitch enum.Kind {\n\t\tcase constant.Int:\n\t\t\tvalue = gconv.Int64(enum.Value)\n\t\tcase constant.String:\n\t\t\tvalue = enum.Value\n\t\tcase constant.Float:\n\t\t\tvalue = gconv.Float64(enum.Value)\n\t\tcase constant.Bool:\n\t\t\tvalue = gconv.Bool(enum.Value)\n\t\tdefault:\n\t\t\tvalue = enum.Value\n\t\t}\n\t\ttypeEnumMap[enum.Type] = append(typeEnumMap[enum.Type], value)\n\t}\n\treturn gjson.MustEncodeString(typeEnumMap)\n}\n\nfunc getStandardPackages() map[string]struct{} {\n\tstandardPackages := make(map[string]struct{})\n\tstdPackages, err := packages.Load(nil, \"std\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfor _, p := range stdPackages {\n\t\tstandardPackages[p.ID] = struct{}{}\n\t}\n\treturn standardPackages\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genenums/genenums_z_unit_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genenums\n\nimport (\n\t\"go/constant\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"golang.org/x/tools/go/packages\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_NewEnumsParser(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test creating parser without prefixes\n\t\tp := NewEnumsParser(nil)\n\t\tt.AssertNE(p, nil)\n\t\tt.Assert(len(p.enums), 0)\n\t\tt.Assert(len(p.prefixes), 0)\n\t\tt.AssertNE(p.parsedPkg, nil)\n\t\tt.AssertNE(p.standardPackages, nil)\n\t})\n}\n\nfunc Test_NewEnumsParser_WithPrefixes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test creating parser with prefixes\n\t\tprefixes := []string{\"github.com/gogf\", \"github.com/test\"}\n\t\tp := NewEnumsParser(prefixes)\n\t\tt.AssertNE(p, nil)\n\t\tt.Assert(len(p.prefixes), 2)\n\t\tt.Assert(p.prefixes[0], \"github.com/gogf\")\n\t\tt.Assert(p.prefixes[1], \"github.com/test\")\n\t})\n}\n\nfunc Test_EnumsParser_Export_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test exporting empty enums\n\t\tp := NewEnumsParser(nil)\n\t\tresult := p.Export()\n\t\tt.Assert(result, \"{}\")\n\t})\n}\n\nfunc Test_EnumsParser_Export_WithEnums(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test exporting with manually added enums\n\t\tp := NewEnumsParser(nil)\n\n\t\t// Add some test enums\n\t\tp.enums = []EnumItem{\n\t\t\t{\n\t\t\t\tName:  \"StatusActive\",\n\t\t\t\tValue: \"1\",\n\t\t\t\tType:  \"pkg.Status\",\n\t\t\t\tKind:  constant.Int,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"StatusInactive\",\n\t\t\t\tValue: \"0\",\n\t\t\t\tType:  \"pkg.Status\",\n\t\t\t\tKind:  constant.Int,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"TypeA\",\n\t\t\t\tValue: \"type_a\",\n\t\t\t\tType:  \"pkg.Type\",\n\t\t\t\tKind:  constant.String,\n\t\t\t},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tt.AssertNE(result, \"\")\n\n\t\t// Parse the result to verify - use raw map to avoid gjson path issues with \".\"\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\t// Verify Status type has 2 values\n\t\tstatusValues := resultMap[\"pkg.Status\"]\n\t\tt.Assert(len(statusValues), 2)\n\n\t\t// Verify Type type has 1 value\n\t\ttypeValues := resultMap[\"pkg.Type\"]\n\t\tt.Assert(len(typeValues), 1)\n\t\tt.Assert(typeValues[0], \"type_a\")\n\t})\n}\n\nfunc Test_EnumsParser_Export_IntValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := NewEnumsParser(nil)\n\t\tp.enums = []EnumItem{\n\t\t\t{Name: \"One\", Value: \"1\", Type: \"pkg.Int\", Kind: constant.Int},\n\t\t\t{Name: \"Two\", Value: \"2\", Type: \"pkg.Int\", Kind: constant.Int},\n\t\t\t{Name: \"Negative\", Value: \"-5\", Type: \"pkg.Int\", Kind: constant.Int},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\tvalues := resultMap[\"pkg.Int\"]\n\t\tt.Assert(len(values), 3)\n\t\t// Int values should be exported as integers (stored as float64 in JSON)\n\t\tt.Assert(values[0], float64(1))\n\t\tt.Assert(values[1], float64(2))\n\t\tt.Assert(values[2], float64(-5))\n\t})\n}\n\nfunc Test_EnumsParser_Export_FloatValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := NewEnumsParser(nil)\n\t\tp.enums = []EnumItem{\n\t\t\t{Name: \"Pi\", Value: \"3.14159\", Type: \"pkg.Float\", Kind: constant.Float},\n\t\t\t{Name: \"E\", Value: \"2.71828\", Type: \"pkg.Float\", Kind: constant.Float},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\tvalues := resultMap[\"pkg.Float\"]\n\t\tt.Assert(len(values), 2)\n\t})\n}\n\nfunc Test_EnumsParser_Export_BoolValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := NewEnumsParser(nil)\n\t\tp.enums = []EnumItem{\n\t\t\t{Name: \"True\", Value: \"true\", Type: \"pkg.Bool\", Kind: constant.Bool},\n\t\t\t{Name: \"False\", Value: \"false\", Type: \"pkg.Bool\", Kind: constant.Bool},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\tvalues := resultMap[\"pkg.Bool\"]\n\t\tt.Assert(len(values), 2)\n\t\tt.Assert(values[0], true)\n\t\tt.Assert(values[1], false)\n\t})\n}\n\nfunc Test_EnumsParser_Export_StringValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := NewEnumsParser(nil)\n\t\tp.enums = []EnumItem{\n\t\t\t{Name: \"Hello\", Value: \"hello\", Type: \"pkg.Str\", Kind: constant.String},\n\t\t\t{Name: \"World\", Value: \"world\", Type: \"pkg.Str\", Kind: constant.String},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\tvalues := resultMap[\"pkg.Str\"]\n\t\tt.Assert(len(values), 2)\n\t\tt.Assert(values[0], \"hello\")\n\t\tt.Assert(values[1], \"world\")\n\t})\n}\n\nfunc Test_EnumsParser_Export_MixedTypes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := NewEnumsParser(nil)\n\t\tp.enums = []EnumItem{\n\t\t\t{Name: \"IntVal\", Value: \"42\", Type: \"pkg.IntType\", Kind: constant.Int},\n\t\t\t{Name: \"StrVal\", Value: \"test\", Type: \"pkg.StrType\", Kind: constant.String},\n\t\t\t{Name: \"BoolVal\", Value: \"true\", Type: \"pkg.BoolType\", Kind: constant.Bool},\n\t\t}\n\n\t\tresult := p.Export()\n\t\tvar resultMap map[string][]interface{}\n\t\terr := gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\t// Each type should have its own array\n\t\tt.Assert(len(resultMap[\"pkg.IntType\"]), 1)\n\t\tt.Assert(len(resultMap[\"pkg.StrType\"]), 1)\n\t\tt.Assert(len(resultMap[\"pkg.BoolType\"]), 1)\n\t})\n}\n\nfunc Test_EnumItem_Structure(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test EnumItem structure\n\t\titem := EnumItem{\n\t\t\tName:  \"TestEnum\",\n\t\t\tValue: \"test_value\",\n\t\t\tType:  \"github.com/test/pkg.EnumType\",\n\t\t\tKind:  constant.String,\n\t\t}\n\n\t\tt.Assert(item.Name, \"TestEnum\")\n\t\tt.Assert(item.Value, \"test_value\")\n\t\tt.Assert(item.Type, \"github.com/test/pkg.EnumType\")\n\t\tt.Assert(item.Kind, constant.String)\n\t})\n}\n\nfunc Test_EnumsParser_ParsePackages_Integration(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory with a Go package containing enums\n\t\t// Note: The module path must contain \"/\" for enums to be parsed\n\t\t// (the parser skips std types without \"/\" in the type name)\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create go.mod with a path containing \"/\"\n\t\tgoModContent := `module github.com/test/enumtest\n\ngo 1.21\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"go.mod\"), goModContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create a Go file with enum definitions\n\t\tenumsContent := `package enumtest\n\ntype Status int\n\nconst (\n\tStatusActive   Status = 1\n\tStatusInactive Status = 0\n)\n\ntype Color string\n\nconst (\n\tColorRed   Color = \"red\"\n\tColorGreen Color = \"green\"\n\tColorBlue  Color = \"blue\"\n)\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"enums.go\"), enumsContent)\n\t\tt.AssertNil(err)\n\n\t\t// Load the package\n\t\tcfg := &packages.Config{\n\t\t\tDir:   tempDir,\n\t\t\tMode:  pkgLoadMode,\n\t\t\tTests: false,\n\t\t}\n\t\tpkgs, err := packages.Load(cfg)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(pkgs) > 0, true)\n\n\t\t// Parse the packages\n\t\tp := NewEnumsParser(nil)\n\t\tp.ParsePackages(pkgs)\n\n\t\t// Export and verify - result should contain parsed enums\n\t\tresult := p.Export()\n\t\t// Verify the export contains some data\n\t\tt.Assert(len(result) > 2, true) // More than just \"{}\"\n\n\t\t// Parse result as raw map to handle keys with \"/\"\n\t\tvar resultMap map[string][]interface{}\n\t\terr = gjson.DecodeTo(result, &resultMap)\n\t\tt.AssertNil(err)\n\n\t\t// Verify Status enum was parsed (type will be \"github.com/test/enumtest.Status\")\n\t\tstatusKey := \"github.com/test/enumtest.Status\"\n\t\tstatusValues, hasStatus := resultMap[statusKey]\n\t\tt.Assert(hasStatus, true)\n\t\tt.Assert(len(statusValues), 2)\n\n\t\t// Verify Color enum was parsed\n\t\tcolorKey := \"github.com/test/enumtest.Color\"\n\t\tcolorValues, hasColor := resultMap[colorKey]\n\t\tt.Assert(hasColor, true)\n\t\tt.Assert(len(colorValues), 3)\n\t})\n}\n\nfunc Test_EnumsParser_ParsePackages_WithPrefixes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a temporary directory with a Go package\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create go.mod with a specific module name\n\t\tgoModContent := `module github.com/allowed/pkg\n\ngo 1.21\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"go.mod\"), goModContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create a Go file with enum definitions\n\t\tenumsContent := `package pkg\n\ntype Status int\n\nconst (\n\tStatusOK Status = 1\n)\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"enums.go\"), enumsContent)\n\t\tt.AssertNil(err)\n\n\t\t// Load the package\n\t\tcfg := &packages.Config{\n\t\t\tDir:   tempDir,\n\t\t\tMode:  pkgLoadMode,\n\t\t\tTests: false,\n\t\t}\n\t\tpkgs, err := packages.Load(cfg)\n\t\tt.AssertNil(err)\n\n\t\t// Parse with prefix filter that matches\n\t\tp := NewEnumsParser([]string{\"github.com/allowed\"})\n\t\tp.ParsePackages(pkgs)\n\n\t\tresult := p.Export()\n\t\t// Should have enums because prefix matches\n\t\tt.AssertNE(result, \"{}\")\n\n\t\t// Parse with prefix filter that doesn't match\n\t\tp2 := NewEnumsParser([]string{\"github.com/other\"})\n\t\tp2.ParsePackages(pkgs)\n\n\t\tresult2 := p2.Export()\n\t\t// Should be empty because prefix doesn't match\n\t\tt.Assert(result2, \"{}\")\n\t})\n}\n\nfunc Test_getStandardPackages(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstdPkgs := getStandardPackages()\n\t\tt.AssertNE(stdPkgs, nil)\n\t\tt.Assert(len(stdPkgs) > 0, true)\n\n\t\t// Verify some common standard packages are included\n\t\t_, hasFmt := stdPkgs[\"fmt\"]\n\t\tt.Assert(hasFmt, true)\n\n\t\t_, hasOs := stdPkgs[\"os\"]\n\t\tt.Assert(hasOs, true)\n\n\t\t_, hasContext := stdPkgs[\"context\"]\n\t\tt.Assert(hasContext, true)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// ProcessOptions contains options for the Process function\ntype ProcessOptions struct {\n\tSelectVersion bool   // Enable interactive version selection\n\tModulePath    string // Custom go.mod module path (e.g., github.com/xxx/xxx)\n\tUpgradeDeps   bool   // Upgrade dependencies to latest (go get -u ./...)\n}\n\n// Process handles the template generation flow from remote repository\nfunc Process(ctx context.Context, repo, name string, opts *ProcessOptions) error {\n\tif opts == nil {\n\t\topts = &ProcessOptions{}\n\t}\n\n\t// 0. Check Go environment first\n\tmlog.Print(\"Checking Go environment...\")\n\tgoEnv, err := CheckGoEnv(ctx)\n\tif err != nil {\n\t\tmlog.Printf(\"Go environment check failed: %v\", err)\n\t\treturn err\n\t}\n\tmlog.Printf(\"Go environment OK (version: %s)\", goEnv.GOVERSION)\n\n\t// Check if this is a git subdirectory URL\n\tif IsSubdirRepo(repo) {\n\t\treturn processGitSubdir(ctx, repo, name, opts)\n\t}\n\n\t// Try Go module download first, fallback to git subdirectory if it fails\n\t// This handles edge cases where the heuristic may be incorrect\n\terr = processGoModule(ctx, repo, name, opts)\n\tif err != nil {\n\t\tmlog.Printf(\"Go module download failed, trying git subdirectory mode: %v\", err)\n\t\tmlog.Print(\"Note: If this is a git subdirectory, you can force git mode by using a full git URL\")\n\n\t\t// If Go module download fails, try git subdirectory as fallback\n\t\t// This handles cases where the heuristic incorrectly classified a git subdir as Go module\n\t\tif IsSubdirRepo(repo) {\n\t\t\tmlog.Print(\"Falling back to git subdirectory download...\")\n\t\t\treturn processGitSubdir(ctx, repo, name, opts)\n\t\t}\n\t}\n\n\treturn err\n}\n\n// processGoModule handles standard Go module download via go get\nfunc processGoModule(ctx context.Context, repo, name string, opts *ProcessOptions) error {\n\t// Extract module path (without version)\n\tmodulePath := repo\n\tspecifiedVersion := \"\"\n\tif gstr.Contains(repo, \"@\") {\n\t\tparts := gstr.Split(repo, \"@\")\n\t\tmodulePath = parts[0]\n\t\tspecifiedVersion = parts[1]\n\t}\n\n\t// Default name to repo basename if empty\n\tif name == \"\" {\n\t\tname = filepath.Base(modulePath)\n\t}\n\n\t// Determine the target module path for go.mod\n\ttargetModulePath := name\n\tif opts.ModulePath != \"\" {\n\t\ttargetModulePath = opts.ModulePath\n\t}\n\n\t// 1. Determine version to use\n\tvar targetVersion string\n\tif specifiedVersion != \"\" {\n\t\t// User specified version, try to use it first\n\t\ttargetVersion = specifiedVersion\n\t\tmlog.Printf(\"Using specified version: %s\", targetVersion)\n\t} else if opts.SelectVersion {\n\t\t// Interactive version selection\n\t\tmlog.Print(\"Fetching available versions...\")\n\t\tversionInfo, err := GetModuleVersions(ctx, modulePath)\n\t\tif err != nil {\n\t\t\tmlog.Printf(\"Failed to get versions: %v\", err)\n\t\t\treturn err\n\t\t}\n\n\t\ttargetVersion, err = SelectVersion(ctx, versionInfo.Versions, modulePath)\n\t\tif err != nil {\n\t\t\tmlog.Printf(\"Version selection failed: %v\", err)\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// Default: use latest version\n\t\tmlog.Print(\"Fetching latest version...\")\n\t\tlatest, err := GetLatestVersion(ctx, modulePath)\n\t\tif err != nil {\n\t\t\tmlog.Printf(\"Failed to get latest version, will try @latest tag: %v\", err)\n\t\t\ttargetVersion = \"latest\"\n\t\t} else {\n\t\t\ttargetVersion = latest\n\t\t\tmlog.Printf(\"Latest version: %s\", targetVersion)\n\t\t}\n\t}\n\n\t// 2. Download Template with determined version\n\trepoWithVersion := modulePath + \"@\" + targetVersion\n\tsrcDir, err := downloadTemplate(ctx, repoWithVersion)\n\tif err != nil {\n\t\t// If specified version download failed, offer to select from available versions\n\t\tif specifiedVersion != \"\" {\n\t\t\tmlog.Printf(\"Failed to download specified version '%s': %v\", specifiedVersion, err)\n\t\t\tmlog.Print(\"Fetching available versions...\")\n\n\t\t\tversionInfo, verErr := GetModuleVersions(ctx, modulePath)\n\t\t\tif verErr != nil {\n\t\t\t\tmlog.Printf(\"Failed to get available versions: %v\", verErr)\n\t\t\t\treturn err // Return original download error\n\t\t\t}\n\n\t\t\tif len(versionInfo.Versions) == 0 {\n\t\t\t\tmlog.Print(\"No versions available for this module\")\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Let user select from available versions\n\t\t\tselectedVersion, selErr := SelectVersion(ctx, versionInfo.Versions, modulePath)\n\t\t\tif selErr != nil {\n\t\t\t\tmlog.Printf(\"Version selection failed: %v\", selErr)\n\t\t\t\treturn selErr\n\t\t\t}\n\n\t\t\t// Retry download with selected version\n\t\t\ttargetVersion = selectedVersion\n\t\t\trepoWithVersion = modulePath + \"@\" + targetVersion\n\t\t\tsrcDir, err = downloadTemplate(ctx, repoWithVersion)\n\t\t\tif err != nil {\n\t\t\t\tmlog.Printf(\"Download failed: %v\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tmlog.Printf(\"Download failed: %v\", err)\n\t\t\treturn err\n\t\t}\n\t}\n\n\tmlog.Debugf(\"Template located at: %s\", srcDir)\n\n\t// 3. Generate Project\n\tif err := generateProject(ctx, srcDir, name, modulePath, targetModulePath); err != nil {\n\t\tmlog.Printf(\"Generation failed: %v\", err)\n\t\treturn err\n\t}\n\n\t// 4. Handle dependencies\n\tvar projectDir string\n\tif name == \".\" {\n\t\tprojectDir = gfile.Pwd()\n\t} else {\n\t\tprojectDir = filepath.Join(gfile.Pwd(), name)\n\t}\n\tif opts.UpgradeDeps {\n\t\t// Upgrade all dependencies to latest\n\t\tif err := upgradeDependencies(ctx, projectDir); err != nil {\n\t\t\tmlog.Printf(\"Failed to upgrade dependencies: %v\", err)\n\t\t}\n\t} else {\n\t\t// Default: just tidy dependencies\n\t\tif err := tidyDependencies(ctx, projectDir); err != nil {\n\t\t\tmlog.Printf(\"Failed to tidy dependencies: %v\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// processGitSubdir handles git subdirectory download via sparse checkout\nfunc processGitSubdir(ctx context.Context, repo, name string, opts *ProcessOptions) error {\n\tmlog.Print(\"Detected subdirectory URL, using git sparse checkout...\")\n\n\t// Check if git is available\n\tgitVersion, err := CheckGitEnv(ctx)\n\tif err != nil {\n\t\tmlog.Printf(\"Git is required for subdirectory templates: %v\", err)\n\t\treturn err\n\t}\n\tmlog.Printf(\"Git available (%s)\", gitVersion)\n\n\t// Download via git sparse checkout\n\tsrcDir, gitInfo, err := downloadGitSubdir(ctx, repo)\n\tif err != nil {\n\t\tmlog.Printf(\"Git download failed: %v\", err)\n\t\treturn err\n\t}\n\n\t// Clean up temp directory after generation\n\t// The temp dir is parent of parent of srcDir (tempDir/repo/subpath)\n\ttempDir := filepath.Dir(filepath.Dir(srcDir))\n\tif tempDir != \"\" && gfile.Exists(tempDir) && gstr.Contains(tempDir, \"gf-init-git\") {\n\t\tdefer func() {\n\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to remove temp directory %s: %v\", tempDir, err)\n\t\t\t} else {\n\t\t\t\tmlog.Debugf(\"Cleaned up temp directory: %s\", tempDir)\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Default name to subpath basename if empty\n\tif name == \"\" {\n\t\tname = filepath.Base(gitInfo.SubPath)\n\t}\n\n\t// Get original module name from go.mod (might be \"main\" or something else)\n\toldModule := GetModuleNameFromGoMod(srcDir)\n\tif oldModule == \"\" {\n\t\t// Fallback: construct from git info\n\t\toldModule = gitInfo.Host + \"/\" + gitInfo.Owner + \"/\" + gitInfo.Repo + \"/\" + gitInfo.SubPath\n\t}\n\n\t// Determine the target module path for go.mod\n\ttargetModulePath := name\n\tif opts.ModulePath != \"\" {\n\t\ttargetModulePath = opts.ModulePath\n\t}\n\n\tmlog.Debugf(\"Template located at: %s\", srcDir)\n\tmlog.Debugf(\"Original module: %s\", oldModule)\n\n\t// Generate Project\n\tif err := generateProject(ctx, srcDir, name, oldModule, targetModulePath); err != nil {\n\t\tmlog.Printf(\"Generation failed: %v\", err)\n\t\treturn err\n\t}\n\n\t// Handle dependencies\n\tvar projectDir string\n\tif name == \".\" {\n\t\tprojectDir = gfile.Pwd()\n\t} else {\n\t\tprojectDir = filepath.Join(gfile.Pwd(), name)\n\t}\n\tif opts.UpgradeDeps {\n\t\t// Upgrade all dependencies to latest\n\t\tif err := upgradeDependencies(ctx, projectDir); err != nil {\n\t\t\tmlog.Printf(\"Failed to upgrade dependencies: %v\", err)\n\t\t}\n\t} else {\n\t\t// Default: just tidy dependencies\n\t\tif err := tidyDependencies(ctx, projectDir); err != nil {\n\t\t\tmlog.Printf(\"Failed to tidy dependencies: %v\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_ast.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/printer\"\n\t\"go/token\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// ASTReplacer handles import path replacement using Go AST\ntype ASTReplacer struct {\n\toldModule string\n\tnewModule string\n\tfset      *token.FileSet\n}\n\n// NewASTReplacer creates a new AST-based import replacer\nfunc NewASTReplacer(oldModule, newModule string) *ASTReplacer {\n\treturn &ASTReplacer{\n\t\toldModule: oldModule,\n\t\tnewModule: newModule,\n\t\tfset:      token.NewFileSet(),\n\t}\n}\n\n// ReplaceInFile replaces import paths in a single Go file\nfunc (r *ASTReplacer) ReplaceInFile(ctx context.Context, filePath string) error {\n\t// Read file content\n\tcontent := gfile.GetContents(filePath)\n\tif content == \"\" {\n\t\treturn nil\n\t}\n\n\t// Parse the file\n\tfile, err := parser.ParseFile(r.fset, filePath, content, parser.ParseComments)\n\tif err != nil {\n\t\tmlog.Debugf(\"Failed to parse %s: %v\", filePath, err)\n\t\treturn nil // Skip files that can't be parsed\n\t}\n\n\t// Track if any changes were made\n\tchanged := false\n\n\t// Traverse and modify imports\n\tast.Inspect(file, func(n ast.Node) bool {\n\t\tswitch x := n.(type) {\n\t\tcase *ast.ImportSpec:\n\t\t\tif x.Path != nil {\n\t\t\t\timportPath := strings.Trim(x.Path.Value, `\"`)\n\t\t\t\tif strings.HasPrefix(importPath, r.oldModule) {\n\t\t\t\t\t// Replace only the leading module prefix for clarity and correctness.\n\t\t\t\t\tnewPath := r.newModule + strings.TrimPrefix(importPath, r.oldModule)\n\t\t\t\t\tx.Path.Value = `\"` + newPath + `\"`\n\t\t\t\t\tchanged = true\n\t\t\t\t\tmlog.Debugf(\"Replaced import: %s -> %s in %s\", importPath, newPath, filePath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\n\tif !changed {\n\t\treturn nil\n\t}\n\n\t// Write back to file without formatting.\n\t// Formatting will be handled by formatGoFiles after all replacements are done.\n\tvar buf bytes.Buffer\n\tif err := printer.Fprint(&buf, r.fset, file); err != nil {\n\t\treturn err\n\t}\n\n\treturn gfile.PutContents(filePath, buf.String())\n}\n\n// ReplaceInDir replaces import paths in all Go files in a directory (recursively)\nfunc (r *ASTReplacer) ReplaceInDir(ctx context.Context, dir string) error {\n\tmlog.Printf(\"Replacing imports: %s -> %s\", r.oldModule, r.newModule)\n\n\t// Find all .go files\n\tfiles, err := findGoFiles(dir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, file := range files {\n\t\tif err := r.ReplaceInFile(ctx, file); err != nil {\n\t\t\tmlog.Printf(\"Failed to process %s: %v\", file, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// findGoFiles recursively finds all .go files in a directory\nfunc findGoFiles(dir string) ([]string, error) {\n\tvar files []string\n\n\terr := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !info.IsDir() && strings.HasSuffix(path, \".go\") {\n\t\t\tfiles = append(files, path)\n\t\t}\n\t\treturn nil\n\t})\n\n\treturn files, err\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_downloader.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// downloadTemplate fetches the remote repository using go get\nfunc downloadTemplate(ctx context.Context, repo string) (string, error) {\n\t// 1. Create a temporary directory workspace\n\ttempDir := gfile.Temp(\"gf-init-cli\")\n\tif tempDir == \"\" {\n\t\treturn \"\", fmt.Errorf(\"failed to create temporary directory\")\n\t}\n\tif err := gfile.Mkdir(tempDir); err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer func() {\n\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\tmlog.Debugf(\"Failed to remove temp directory %s: %v\", tempDir, err)\n\t\t}\n\t}() // Clean up the temp workspace\n\n\tmlog.Debugf(\"Using temp workspace: %s\", tempDir)\n\n\t// 2. Initialize a temp go module to perform go get\n\t// We run commands inside the temp directory\n\tif err := runCmd(ctx, tempDir, \"go\", \"mod\", \"init\", \"temp\"); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// 3. Run go get <repo>\n\t// Try different version strategies: original -> @latest -> @master\n\tmoduleName := repo\n\tif gstr.Contains(repo, \"@\") {\n\t\tmoduleName = gstr.Split(repo, \"@\")[0]\n\t}\n\n\tvar downloadErrs []string\n\tversionsToTry := []string{repo}\n\tif !gstr.Contains(repo, \"@\") {\n\t\tversionsToTry = append(versionsToTry, repo+\"@latest\", repo+\"@master\")\n\t}\n\n\tvar successRepo string\n\tfor _, tryRepo := range versionsToTry {\n\t\tmlog.Printf(\"Downloading template %s...\", tryRepo)\n\t\tif err := runCmd(ctx, tempDir, \"go\", \"get\", tryRepo); err == nil {\n\t\t\tsuccessRepo = tryRepo\n\t\t\tbreak\n\t\t} else {\n\t\t\tdownloadErrs = append(downloadErrs, fmt.Sprintf(\"%s: %v\", tryRepo, err))\n\t\t\tmlog.Debugf(\"Failed to download %s, trying next...\", tryRepo)\n\t\t}\n\t}\n\n\tif successRepo == \"\" {\n\t\terrMsg := \"all download attempts failed\"\n\t\tif len(downloadErrs) > 0 {\n\t\t\terrMsg = strings.Join(downloadErrs, \"; \")\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"failed to download repo %s: %s\", repo, errMsg)\n\t}\n\n\t// 4. Find the local path using go list -m -json <repo>\n\tlistCmd := exec.CommandContext(ctx, \"go\", \"list\", \"-m\", \"-json\", moduleName)\n\tlistCmd.Dir = tempDir\n\toutput, err := listCmd.Output()\n\tif err != nil {\n\t\tif exitErr, ok := err.(*exec.ExitError); ok {\n\t\t\treturn \"\", fmt.Errorf(\"go list failed: %s\", string(exitErr.Stderr))\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"failed to locate module path: %w\", err)\n\t}\n\n\tvar modInfo struct {\n\t\tDir string `json:\"Dir\"`\n\t}\n\tif err := json.Unmarshal(output, &modInfo); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse go list output: %w\", err)\n\t}\n\n\tif modInfo.Dir == \"\" {\n\t\treturn \"\", fmt.Errorf(\"module directory not found for %s\", repo)\n\t}\n\n\treturn modInfo.Dir, nil\n}\n\nfunc runCmd(ctx context.Context, dir string, name string, args ...string) error {\n\tcmd := exec.CommandContext(ctx, name, args...)\n\tcmd.Dir = dir\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\treturn cmd.Run()\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_env.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// GoEnv represents Go environment variables\ntype GoEnv struct {\n\tGOVERSION   string `json:\"GOVERSION\"`\n\tGOROOT      string `json:\"GOROOT\"`\n\tGOPATH      string `json:\"GOPATH\"`\n\tGOMODCACHE  string `json:\"GOMODCACHE\"`\n\tGOPROXY     string `json:\"GOPROXY\"`\n\tGO111MODULE string `json:\"GO111MODULE\"`\n}\n\n// CheckGoEnv verifies Go is installed and properly configured\nfunc CheckGoEnv(ctx context.Context) (*GoEnv, error) {\n\t// 1. Check if go binary exists\n\tgoPath, err := exec.LookPath(\"go\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"go is not installed or not in PATH: %w\", err)\n\t}\n\tmlog.Debugf(\"Found go binary at: %s\", goPath)\n\n\t// 2. Get go env as JSON\n\tcmd := exec.CommandContext(ctx, \"go\", \"env\", \"-json\")\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\tif exitErr, ok := err.(*exec.ExitError); ok {\n\t\t\treturn nil, fmt.Errorf(\"go env failed: %s\", string(exitErr.Stderr))\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to run go env: %w\", err)\n\t}\n\n\t// 3. Parse JSON output\n\tvar env GoEnv\n\tif err := json.Unmarshal(output, &env); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse go env output: %w\", err)\n\t}\n\n\t// 4. Validate critical environment variables\n\tif env.GOROOT == \"\" {\n\t\treturn nil, fmt.Errorf(\"GOROOT is not set\")\n\t}\n\tif env.GOMODCACHE == \"\" && env.GOPATH == \"\" {\n\t\treturn nil, fmt.Errorf(\"neither GOMODCACHE nor GOPATH is set\")\n\t}\n\n\tmlog.Debugf(\"Go Version: %s\", env.GOVERSION)\n\tmlog.Debugf(\"GOROOT: %s\", env.GOROOT)\n\tmlog.Debugf(\"GOMODCACHE: %s\", env.GOMODCACHE)\n\tmlog.Debugf(\"GOPROXY: %s\", env.GOPROXY)\n\n\treturn &env, nil\n}\n\n// CheckGitEnv verifies Git is installed and returns its version\nfunc CheckGitEnv(ctx context.Context) (string, error) {\n\t// 1. Check if git binary exists\n\tgitPath, err := exec.LookPath(\"git\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"git is not installed or not in PATH: %w\", err)\n\t}\n\tmlog.Debugf(\"Found git binary at: %s\", gitPath)\n\n\t// 2. Get git version\n\tcmd := exec.CommandContext(ctx, \"git\", \"--version\")\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to get git version: %w\", err)\n\t}\n\n\tversion := strings.TrimSpace(string(output))\n\tmlog.Debugf(\"Git version: %s\", version)\n\n\treturn version, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_generator.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"path/filepath\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// generateProject copies the template to the destination and performs cleanup\n// oldModule: original module path from template\n// newModule: target module path for go.mod (can be different from project name)\nfunc generateProject(ctx context.Context, srcPath, name, oldModule, newModule string) error {\n\tpwd := gfile.Pwd()\n\n\tdstPath := filepath.Join(pwd, name)\n\tif name == \".\" {\n\t\tdstPath = pwd\n\t}\n\n\tif gfile.Exists(dstPath) && !gfile.IsEmpty(dstPath) {\n\t\treturn fmt.Errorf(\"target directory %s is not empty\", dstPath)\n\t}\n\n\tmlog.Printf(\"Generating project in %s...\", dstPath)\n\n\t// 1. Copy files\n\tif err := gfile.Copy(srcPath, dstPath); err != nil {\n\t\treturn err\n\t}\n\n\t// 2. Clean up .git directory\n\tgitDir := filepath.Join(dstPath, \".git\")\n\tif gfile.Exists(gitDir) {\n\t\tif err := gfile.Remove(gitDir); err != nil {\n\t\t\tmlog.Debugf(\"Failed to remove .git directory: %v\", err)\n\t\t}\n\t}\n\n\t// 3. Clean up go.work and go.work.sum (workspace files should not be in generated project)\n\tfor _, workFile := range []string{\"go.work\", \"go.work.sum\"} {\n\t\tworkPath := filepath.Join(dstPath, workFile)\n\t\tif gfile.Exists(workPath) {\n\t\t\tif err := gfile.Remove(workPath); err != nil {\n\t\t\t\tmlog.Printf(\"Failed to remove %s: %v\", workFile, err)\n\t\t\t} else {\n\t\t\t\tmlog.Debugf(\"Removed %s\", workFile)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Update go.mod module name\n\tgoModPath := filepath.Join(dstPath, \"go.mod\")\n\tif gfile.Exists(goModPath) {\n\t\tcontent := gfile.GetContents(goModPath)\n\t\tlines := gstr.Split(content, \"\\n\")\n\t\tif len(lines) > 0 && gstr.HasPrefix(lines[0], \"module \") {\n\t\t\tlines[0] = \"module \" + newModule\n\t\t\tnewContent := gstr.Join(lines, \"\\n\")\n\t\t\tif err := gfile.PutContents(goModPath, newContent); err != nil {\n\t\t\t\tmlog.Printf(\"Failed to update go.mod: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 5. Use AST to replace import paths in all Go files\n\tif oldModule != \"\" && oldModule != newModule {\n\t\treplacer := NewASTReplacer(oldModule, newModule)\n\t\tif err := replacer.ReplaceInDir(ctx, dstPath); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to replace imports: %w\", err)\n\t\t}\n\t}\n\n\t// 6. Format the generated Go files using go/format (not imports.Process)\n\t// Note: We use formatGoFiles instead of utils.GoFmt because imports.Process\n\t// may incorrectly \"fix\" local import paths by replacing them with cached module paths.\n\tformatGoFiles(dstPath)\n\n\tmlog.Print(\"Project generated successfully!\")\n\treturn nil\n}\n\n// tidyDependencies runs go mod tidy in the project directory\nfunc tidyDependencies(ctx context.Context, projectDir string) error {\n\tmlog.Print(\"Tidying dependencies (go mod tidy)...\")\n\tif err := runCmd(ctx, projectDir, \"go\", \"mod\", \"tidy\"); err != nil {\n\t\treturn fmt.Errorf(\"go mod tidy failed: %w\", err)\n\t}\n\tmlog.Print(\"Dependencies tidied successfully!\")\n\treturn nil\n}\n\n// upgradeDependencies runs go get -u ./... to upgrade all dependencies to latest\nfunc upgradeDependencies(ctx context.Context, projectDir string) error {\n\tmlog.Print(\"Upgrading dependencies to latest (go get -u ./...)...\")\n\tif err := runCmd(ctx, projectDir, \"go\", \"get\", \"-u\", \"./...\"); err != nil {\n\t\treturn fmt.Errorf(\"go get -u failed: %w\", err)\n\t}\n\t// Run tidy again after upgrade\n\tif err := runCmd(ctx, projectDir, \"go\", \"mod\", \"tidy\"); err != nil {\n\t\treturn fmt.Errorf(\"go mod tidy after upgrade failed: %w\", err)\n\t}\n\tmlog.Print(\"Dependencies upgraded successfully!\")\n\treturn nil\n}\n\n// formatGoFiles formats all Go files in the directory using go/format.\n// Unlike imports.Process, this only formats code without modifying imports,\n// which prevents incorrect \"fixing\" of local import paths.\nfunc formatGoFiles(dir string) {\n\tfiles, err := findGoFiles(dir)\n\tif err != nil {\n\t\tmlog.Printf(\"Failed to find Go files for formatting: %v\", err)\n\t\treturn\n\t}\n\n\tfor _, file := range files {\n\t\tcontent := gfile.GetContents(file)\n\t\tif content == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tformatted, err := format.Source([]byte(content))\n\t\tif err != nil {\n\t\t\tmlog.Debugf(\"Failed to format %s: %v\", file, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif string(formatted) != content {\n\t\t\tif err := gfile.PutContents(file, string(formatted)); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to write formatted file %s: %v\", file, err)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_git_downloader.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// GitRepoInfo holds parsed git repository information\ntype GitRepoInfo struct {\n\tHost     string // e.g., github.com\n\tOwner    string // e.g., gogf\n\tRepo     string // e.g., examples\n\tBranch   string // e.g., main (default: main)\n\tSubPath  string // e.g., httpserver/jwt\n\tCloneURL string // e.g., https://github.com/gogf/examples.git\n}\n\n// ParseGitURL parses a git URL and extracts repository info\n// Supports formats:\n//   - github.com/owner/repo\n//   - github.com/owner/repo/subdir/path\n//   - github.com/owner/repo/tree/branch/subdir/path (from GitHub web URL)\nfunc ParseGitURL(url string) (*GitRepoInfo, error) {\n\t// Remove protocol prefix if present\n\turl = strings.TrimPrefix(url, \"https://\")\n\turl = strings.TrimPrefix(url, \"http://\")\n\turl = strings.TrimSuffix(url, \".git\")\n\n\t// Remove version suffix like @v1.0.0\n\tif idx := strings.Index(url, \"@\"); idx != -1 {\n\t\turl = url[:idx]\n\t}\n\n\tparts := strings.Split(url, \"/\")\n\tif len(parts) < 3 {\n\t\treturn nil, fmt.Errorf(\"invalid git URL: %s\", url)\n\t}\n\n\tinfo := &GitRepoInfo{\n\t\tHost:   parts[0],\n\t\tOwner:  parts[1],\n\t\tRepo:   parts[2],\n\t\tBranch: \"main\", // default branch\n\t}\n\n\t// Check for /tree/branch/ pattern (GitHub web URL)\n\tif len(parts) > 4 && parts[3] == \"tree\" {\n\t\tinfo.Branch = parts[4]\n\t\tif len(parts) > 5 {\n\t\t\tinfo.SubPath = strings.Join(parts[5:], \"/\")\n\t\t}\n\t} else if len(parts) > 3 {\n\t\t// Direct subpath: github.com/owner/repo/subdir/path\n\t\tinfo.SubPath = strings.Join(parts[3:], \"/\")\n\t}\n\n\tinfo.CloneURL = fmt.Sprintf(\"https://%s/%s/%s.git\", info.Host, info.Owner, info.Repo)\n\n\treturn info, nil\n}\n\n// IsSubdirRepo checks if the URL points to a subdirectory of a repository\n// Returns false for Go module paths (which may have /vN suffix or nested module paths)\n// Note: This uses heuristics that may have false positives/negatives in edge cases\nfunc IsSubdirRepo(url string) bool {\n\tinfo, err := ParseGitURL(url)\n\tif err != nil {\n\t\treturn false\n\t}\n\tif info.SubPath == \"\" {\n\t\treturn false\n\t}\n\n\t// Check if this looks like a Go module path rather than a git subdirectory\n\t// Go modules can have nested paths like github.com/owner/repo/cmd/tool/v2\n\t// We should try to resolve it as a Go module first\n\n\t// If the URL can be resolved as a Go module, it's not a subdir repo\n\t// We use a heuristic: check if the full path looks like a valid Go module\n\t// by checking if it ends with /vN (major version) or contains common module patterns\n\n\t// Remove version suffix for checking\n\tcleanURL := url\n\tif before, _, ok := strings.Cut(url, \"@\"); ok {\n\t\tcleanURL = before\n\t}\n\n\t// Check if the path ends with /vN (Go module major version)\n\tparts := strings.Split(cleanURL, \"/\")\n\tif len(parts) > 0 {\n\t\tlastPart := parts[len(parts)-1]\n\t\tif len(lastPart) >= 2 && lastPart[0] == 'v' {\n\t\t\t// Check if it's v2, v3, etc.\n\t\t\tif _, err := fmt.Sscanf(lastPart, \"v%d\", new(int)); err == nil {\n\t\t\t\t// This looks like a Go module with major version suffix\n\t\t\t\t// It could be either a versioned module or a subdir ending in vN\n\t\t\t\t// We'll treat it as a Go module and let go get handle it\n\t\t\t\tmlog.Debugf(\"URL %s detected as Go module (ends with /vN)\", url)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\t// For GitHub URLs, check if the subpath could be a nested Go module\n\t// Common patterns: cmd/*, internal/*, pkg/*, contrib/*\n\tsubPathParts := strings.Split(info.SubPath, \"/\")\n\tif len(subPathParts) > 0 {\n\t\tfirstPart := subPathParts[0]\n\t\t// These are common Go module nesting patterns\n\t\tif firstPart == \"cmd\" || firstPart == \"contrib\" || firstPart == \"tools\" {\n\t\t\t// This might be a nested Go module, not a simple subdirectory\n\t\t\t// Let go get try first\n\t\t\tmlog.Debugf(\"URL %s detected as Go module (starts with common pattern)\", url)\n\t\t\treturn false\n\t\t}\n\t}\n\n\tmlog.Debugf(\"URL %s detected as git subdirectory\", url)\n\treturn true\n}\n\n// downloadGitSubdir downloads a subdirectory from a git repository using sparse checkout\nfunc downloadGitSubdir(ctx context.Context, repoURL string) (string, *GitRepoInfo, error) {\n\tinfo, err := ParseGitURL(repoURL)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tif info.SubPath == \"\" {\n\t\treturn \"\", nil, fmt.Errorf(\"not a subdirectory URL: %s\", repoURL)\n\t}\n\n\t// Create temp directory for clone\n\ttempDir := gfile.Temp(\"gf-init-git\")\n\tif tempDir == \"\" {\n\t\treturn \"\", nil, fmt.Errorf(\"failed to create temporary directory\")\n\t}\n\tif err := gfile.Mkdir(tempDir); err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tcloneDir := filepath.Join(tempDir, info.Repo)\n\tmlog.Debugf(\"Using git temp workspace: %s\", tempDir)\n\tmlog.Printf(\"Cloning %s (sparse checkout: %s)...\", info.CloneURL, info.SubPath)\n\n\t// 1. Clone with no checkout, filter, and sparse\n\tif err := runCmd(ctx, tempDir, \"git\", \"clone\", \"--filter=blob:none\", \"--no-checkout\", \"--sparse\", info.CloneURL); err != nil {\n\t\t// Fallback: try without filter for older git versions\n\t\tmlog.Debugf(\"Sparse clone failed, trying full clone...\")\n\t\tif err := gfile.Remove(cloneDir); err != nil {\n\t\t\tmlog.Debugf(\"Failed to remove clone directory: %v\", err)\n\t\t}\n\t\tif err := runCmd(ctx, tempDir, \"git\", \"clone\", \"--no-checkout\", info.CloneURL); err != nil {\n\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t\t}\n\t\t\treturn \"\", nil, fmt.Errorf(\"git clone failed: %w\", err)\n\t\t}\n\t}\n\n\t// 2. Set sparse-checkout to the subpath\n\tif err := runCmd(ctx, cloneDir, \"git\", \"sparse-checkout\", \"set\", info.SubPath); err != nil {\n\t\t// Fallback for older git: use sparse-checkout init + set\n\t\tmlog.Debugf(\"sparse-checkout set failed, trying legacy method...\")\n\t\tif err := runCmd(ctx, cloneDir, \"git\", \"sparse-checkout\", \"init\", \"--cone\"); err != nil {\n\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t\t}\n\t\t\treturn \"\", nil, fmt.Errorf(\"git sparse-checkout init (legacy) failed: %w\", err)\n\t\t}\n\t\tif err := runCmd(ctx, cloneDir, \"git\", \"sparse-checkout\", \"set\", info.SubPath); err != nil {\n\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t\t}\n\t\t\treturn \"\", nil, fmt.Errorf(\"git sparse-checkout set (legacy) failed: %w\", err)\n\t\t}\n\t}\n\n\t// 3. Checkout the branch\n\tif err := runCmd(ctx, cloneDir, \"git\", \"checkout\", info.Branch); err != nil {\n\t\t// Try master if main fails\n\t\tif info.Branch == \"main\" {\n\t\t\tmlog.Debugf(\"Branch 'main' not found, trying 'master'...\")\n\t\t\tinfo.Branch = \"master\"\n\t\t\tif err := runCmd(ctx, cloneDir, \"git\", \"checkout\", \"master\"); err != nil {\n\t\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t\t\t}\n\t\t\t\treturn \"\", nil, fmt.Errorf(\"git checkout failed: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t\t}\n\t\t\treturn \"\", nil, fmt.Errorf(\"git checkout failed: %w\", err)\n\t\t}\n\t}\n\n\t// Return the path to the subdirectory\n\tsubDirPath := filepath.Join(cloneDir, info.SubPath)\n\tif !gfile.Exists(subDirPath) {\n\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t}\n\t\treturn \"\", nil, fmt.Errorf(\"subdirectory not found: %s\", info.SubPath)\n\t}\n\n\tmlog.Debugf(\"Subdirectory located at: %s\", subDirPath)\n\treturn subDirPath, info, nil\n}\n\n// GetModuleNameFromGoMod reads module name from go.mod file\nfunc GetModuleNameFromGoMod(dir string) string {\n\tgoModPath := filepath.Join(dir, \"go.mod\")\n\tif !gfile.Exists(goModPath) {\n\t\treturn \"\"\n\t}\n\n\tcontent := gfile.GetContents(goModPath)\n\tlines := gstr.Split(content, \"\\n\")\n\tfor _, line := range lines {\n\t\tline = strings.TrimSpace(line)\n\t\tif after, ok := strings.CutPrefix(line, \"module \"); ok {\n\t\t\treturn strings.TrimSpace(after)\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_selector.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// SelectVersion prompts user to select a version interactively\nfunc SelectVersion(ctx context.Context, versions []string, modulePath string) (string, error) {\n\tif len(versions) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no versions available for selection\")\n\t}\n\n\tif len(versions) == 1 {\n\t\tmlog.Printf(\"Only one version available: %s\", versions[0])\n\t\treturn versions[0], nil\n\t}\n\n\t// Display available versions\n\tfmt.Printf(\"\\nAvailable versions for %s:\\n\", modulePath)\n\tfmt.Println(strings.Repeat(\"-\", 40))\n\n\t// Show versions with index (newest first)\n\tmaxDisplay := 20 // Limit display to avoid overwhelming output\n\tdisplayCount := len(versions)\n\tif displayCount > maxDisplay {\n\t\tdisplayCount = maxDisplay\n\t}\n\n\tfor i := 0; i < displayCount; i++ {\n\t\tmarker := \"\"\n\t\tif i == 0 {\n\t\t\tmarker = \" (latest)\"\n\t\t}\n\t\tfmt.Printf(\"  [%2d] %s%s\\n\", i+1, versions[i], marker)\n\t}\n\n\tif len(versions) > maxDisplay {\n\t\tfmt.Printf(\"  ... and %d more versions\\n\", len(versions)-maxDisplay)\n\t}\n\n\tfmt.Println(strings.Repeat(\"-\", 40))\n\n\t// Prompt for selection\n\treader := bufio.NewReader(os.Stdin)\n\tfor {\n\t\tfmt.Printf(\"Select version [1-%d] or enter version string (default: 1 for latest): \", displayCount)\n\n\t\tinput, err := reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to read input: %w\", err)\n\t\t}\n\n\t\tinput = strings.TrimSpace(input)\n\n\t\t// Default to latest\n\t\tif input == \"\" {\n\t\t\tfmt.Printf(\"Selected: %s (latest)\\n\", versions[0])\n\t\t\treturn versions[0], nil\n\t\t}\n\n\t\t// Try parsing as number first\n\t\tidx, err := strconv.Atoi(input)\n\t\tif err == nil {\n\t\t\t// Valid number - check if in range\n\t\t\tif idx >= 1 && idx <= len(versions) {\n\t\t\t\t// Allow selection from all versions, not just displayed ones\n\t\t\t\tselected := versions[idx-1]\n\t\t\t\tfmt.Printf(\"Selected: %s\\n\", selected)\n\t\t\t\treturn selected, nil\n\t\t\t} else if idx < 1 || idx > displayCount {\n\t\t\t\tfmt.Printf(\"Invalid selection. Please enter a number between 1 and %d, or type a version string.\\n\", displayCount)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\t// Try matching the input as a version string (e.g., \"v1.2.3\")\n\t\t\tfor _, v := range versions {\n\t\t\t\tif v == input || strings.Contains(v, input) {\n\t\t\t\t\tfmt.Printf(\"Selected: %s\\n\", v)\n\t\t\t\t\treturn v, nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tfmt.Printf(\"Version '%s' not found. Please select by number or type a valid version string.\\n\", input)\n\t\t\tcontinue\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_version.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"golang.org/x/mod/semver\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// VersionInfo contains module version information\ntype VersionInfo struct {\n\tModule   string   `json:\"module\"`\n\tVersions []string `json:\"versions\"`\n\tLatest   string   `json:\"latest\"`\n}\n\n// GetModuleVersions fetches available versions for a Go module\nfunc GetModuleVersions(ctx context.Context, modulePath string) (*VersionInfo, error) {\n\t// Create a temporary directory for go list\n\ttempDir := gfile.Temp(\"gf-init-version\")\n\tif tempDir == \"\" {\n\t\treturn nil, fmt.Errorf(\"failed to create temporary directory for go list\")\n\t}\n\tif err := gfile.Mkdir(tempDir); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tif err := gfile.Remove(tempDir); err != nil {\n\t\t\tmlog.Debugf(\"Failed to remove temp directory: %v\", err)\n\t\t}\n\t}()\n\n\t// Initialize a temp go module\n\tif err := runCmd(ctx, tempDir, \"go\", \"mod\", \"init\", \"temp\"); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to init temp module: %w\", err)\n\t}\n\n\t// Get versions using go list -m -versions\n\tcmd := exec.CommandContext(ctx, \"go\", \"list\", \"-m\", \"-versions\", modulePath)\n\tcmd.Dir = tempDir\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\t// Try with @latest to see if module exists\n\t\tmlog.Debugf(\"go list -versions failed, trying @latest: %v\", err)\n\t\treturn getLatestOnly(ctx, tempDir, modulePath)\n\t}\n\n\t// Parse output: \"module/path v1.0.0 v1.1.0 v2.0.0\"\n\tparts := strings.Fields(strings.TrimSpace(string(output)))\n\tif len(parts) < 1 {\n\t\treturn nil, fmt.Errorf(\"no version information found for %s\", modulePath)\n\t}\n\n\tinfo := &VersionInfo{\n\t\tModule:   parts[0],\n\t\tVersions: []string{},\n\t}\n\n\tif len(parts) > 1 {\n\t\tinfo.Versions = parts[1:]\n\t\t// Sort versions in descending order (newest first)\n\t\tsort.Slice(info.Versions, func(i, j int) bool {\n\t\t\treturn semver.Compare(info.Versions[i], info.Versions[j]) > 0\n\t\t})\n\t\tinfo.Latest = info.Versions[0]\n\t}\n\n\t// If no tagged versions, try to get latest\n\tif len(info.Versions) == 0 {\n\t\tlatestInfo, err := getLatestOnly(ctx, tempDir, modulePath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinfo.Latest = latestInfo.Latest\n\t\tif latestInfo.Latest != \"\" {\n\t\t\tinfo.Versions = []string{latestInfo.Latest}\n\t\t}\n\t}\n\n\treturn info, nil\n}\n\n// getLatestOnly gets only the latest version when go list -versions fails\nfunc getLatestOnly(ctx context.Context, tempDir, modulePath string) (*VersionInfo, error) {\n\t// Try go list -m modulePath@latest\n\tcmd := exec.CommandContext(ctx, \"go\", \"list\", \"-m\", \"-json\", modulePath+\"@latest\")\n\tcmd.Dir = tempDir\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\t// Try without @latest\n\t\tcmd = exec.CommandContext(ctx, \"go\", \"list\", \"-m\", \"-json\", modulePath)\n\t\tcmd.Dir = tempDir\n\t\toutput, err = cmd.Output()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get module info for %s: %w\", modulePath, err)\n\t\t}\n\t}\n\n\tvar modInfo struct {\n\t\tPath    string `json:\"Path\"`\n\t\tVersion string `json:\"Version\"`\n\t}\n\tif err := json.Unmarshal(output, &modInfo); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse module info: %w\", err)\n\t}\n\n\treturn &VersionInfo{\n\t\tModule:   modInfo.Path,\n\t\tVersions: []string{modInfo.Version},\n\t\tLatest:   modInfo.Version,\n\t}, nil\n}\n\n// GetLatestVersion returns the latest version of a module\nfunc GetLatestVersion(ctx context.Context, modulePath string) (string, error) {\n\tinfo, err := GetModuleVersions(ctx, modulePath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif info.Latest == \"\" {\n\t\treturn \"\", fmt.Errorf(\"no version found for %s\", modulePath)\n\t}\n\treturn info.Latest, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/geninit/geninit_z_unit_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage geninit\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_ParseGitURL_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test basic github URL\n\t\tinfo, err := ParseGitURL(\"github.com/gogf/gf\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"gf\")\n\t\tt.Assert(info.SubPath, \"\")\n\t\tt.Assert(info.Branch, \"main\")\n\t\tt.Assert(info.CloneURL, \"https://github.com/gogf/gf.git\")\n\t})\n}\n\nfunc Test_ParseGitURL_WithHTTPS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test URL with https prefix\n\t\tinfo, err := ParseGitURL(\"https://github.com/gogf/gf\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"gf\")\n\t})\n}\n\nfunc Test_ParseGitURL_WithGitSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test URL with .git suffix\n\t\tinfo, err := ParseGitURL(\"github.com/gogf/gf.git\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"gf\")\n\t})\n}\n\nfunc Test_ParseGitURL_WithSubPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test URL with subdirectory\n\t\tinfo, err := ParseGitURL(\"github.com/gogf/examples/httpserver/jwt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"examples\")\n\t\tt.Assert(info.SubPath, \"httpserver/jwt\")\n\t\tt.Assert(info.CloneURL, \"https://github.com/gogf/examples.git\")\n\t})\n}\n\nfunc Test_ParseGitURL_WithTreeBranch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test GitHub web URL with /tree/branch/\n\t\tinfo, err := ParseGitURL(\"github.com/gogf/examples/tree/develop/httpserver/jwt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"examples\")\n\t\tt.Assert(info.Branch, \"develop\")\n\t\tt.Assert(info.SubPath, \"httpserver/jwt\")\n\t})\n}\n\nfunc Test_ParseGitURL_WithVersion(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test URL with version suffix\n\t\tinfo, err := ParseGitURL(\"github.com/gogf/gf/cmd/gf/v2@v2.9.7\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(info.Host, \"github.com\")\n\t\tt.Assert(info.Owner, \"gogf\")\n\t\tt.Assert(info.Repo, \"gf\")\n\t\tt.Assert(info.SubPath, \"cmd/gf/v2\")\n\t})\n}\n\nfunc Test_ParseGitURL_Invalid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test invalid URL (too short)\n\t\t_, err := ParseGitURL(\"github.com/gogf\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_IsSubdirRepo_NotSubdir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Standard Go module paths should not be detected as subdirectory\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/gf\"), false)\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/gf/v2\"), false)\n\t})\n}\n\nfunc Test_IsSubdirRepo_GoModuleWithCmd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Go module paths with common patterns should not be detected as subdirectory\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/gf/cmd/gf/v2\"), false)\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/gf/contrib/drivers/mysql/v2\"), false)\n\t})\n}\n\nfunc Test_IsSubdirRepo_ActualSubdir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Actual subdirectories should be detected\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/examples/httpserver/jwt\"), true)\n\t\tt.Assert(IsSubdirRepo(\"github.com/gogf/examples/grpc/basic\"), true)\n\t})\n}\n\nfunc Test_GetModuleNameFromGoMod_Valid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory with go.mod\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Write go.mod file\n\t\tgoModContent := `module github.com/test/myproject\n\ngo 1.21\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.9.0\n)\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"go.mod\"), goModContent)\n\t\tt.AssertNil(err)\n\n\t\t// Test extraction\n\t\tmoduleName := GetModuleNameFromGoMod(tempDir)\n\t\tt.Assert(moduleName, \"github.com/test/myproject\")\n\t})\n}\n\nfunc Test_GetModuleNameFromGoMod_NoFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory without go.mod\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Test extraction - should return empty\n\t\tmoduleName := GetModuleNameFromGoMod(tempDir)\n\t\tt.Assert(moduleName, \"\")\n\t})\n}\n\nfunc Test_GetModuleNameFromGoMod_SimpleModule(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory with simple go.mod\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Write simple go.mod file\n\t\tgoModContent := `module main\n\ngo 1.21\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"go.mod\"), goModContent)\n\t\tt.AssertNil(err)\n\n\t\t// Test extraction\n\t\tmoduleName := GetModuleNameFromGoMod(tempDir)\n\t\tt.Assert(moduleName, \"main\")\n\t})\n}\n\nfunc Test_ASTReplacer_ReplaceInFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create a Go file with imports\n\t\tgoFileContent := `package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/old/module/internal/service\"\n\t\"github.com/old/module/pkg/utils\"\n\t\"github.com/other/package\"\n)\n\nfunc main() {\n\tfmt.Println(\"Hello\")\n}\n`\n\t\tgoFilePath := filepath.Join(tempDir, \"main.go\")\n\t\terr = gfile.PutContents(goFilePath, goFileContent)\n\t\tt.AssertNil(err)\n\n\t\t// Replace imports\n\t\treplacer := NewASTReplacer(\"github.com/old/module\", \"github.com/new/project\")\n\t\terr = replacer.ReplaceInFile(context.Background(), goFilePath)\n\t\tt.AssertNil(err)\n\n\t\t// Verify replacement\n\t\tcontent := gfile.GetContents(goFilePath)\n\t\tt.Assert(gfile.Exists(goFilePath), true)\n\n\t\t// Check that old imports are replaced\n\t\tt.AssertNE(content, \"\")\n\t\tt.Assert(contains(content, `\"github.com/new/project/internal/service\"`), true)\n\t\tt.Assert(contains(content, `\"github.com/new/project/pkg/utils\"`), true)\n\n\t\t// Check that other imports are not affected\n\t\tt.Assert(contains(content, `\"github.com/other/package\"`), true)\n\t\tt.Assert(contains(content, `\"fmt\"`), true)\n\t})\n}\n\nfunc Test_ASTReplacer_ReplaceInDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory structure\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create subdirectory\n\t\tsubDir := filepath.Join(tempDir, \"sub\")\n\t\terr = gfile.Mkdir(subDir)\n\t\tt.AssertNil(err)\n\n\t\t// Create main.go\n\t\tmainContent := `package main\n\nimport \"github.com/old/module/sub\"\n\nfunc main() {\n\tsub.Hello()\n}\n`\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"main.go\"), mainContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create sub/sub.go\n\t\tsubContent := `package sub\n\nimport \"github.com/old/module/pkg\"\n\nfunc Hello() {\n\tpkg.Do()\n}\n`\n\t\terr = gfile.PutContents(filepath.Join(subDir, \"sub.go\"), subContent)\n\t\tt.AssertNil(err)\n\n\t\t// Replace imports in directory\n\t\treplacer := NewASTReplacer(\"github.com/old/module\", \"github.com/new/project\")\n\t\terr = replacer.ReplaceInDir(context.Background(), tempDir)\n\t\tt.AssertNil(err)\n\n\t\t// Verify main.go replacement\n\t\tmainResult := gfile.GetContents(filepath.Join(tempDir, \"main.go\"))\n\t\tt.Assert(contains(mainResult, `\"github.com/new/project/sub\"`), true)\n\n\t\t// Verify sub/sub.go replacement\n\t\tsubResult := gfile.GetContents(filepath.Join(subDir, \"sub.go\"))\n\t\tt.Assert(contains(subResult, `\"github.com/new/project/pkg\"`), true)\n\t})\n}\n\nfunc Test_findGoFiles(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create temp directory structure\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Create subdirectories\n\t\tsubDir := filepath.Join(tempDir, \"sub\")\n\t\terr = gfile.Mkdir(subDir)\n\t\tt.AssertNil(err)\n\n\t\t// Create various files\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"main.go\"), \"package main\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(tempDir, \"readme.md\"), \"# README\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(subDir, \"sub.go\"), \"package sub\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.PutContents(filepath.Join(subDir, \"data.json\"), \"{}\")\n\t\tt.AssertNil(err)\n\n\t\t// Find Go files\n\t\tfiles, err := findGoFiles(tempDir)\n\t\tt.AssertNil(err)\n\n\t\t// Should find exactly 2 Go files\n\t\tt.Assert(len(files), 2)\n\n\t\t// Verify file names\n\t\thasMain := false\n\t\thasSub := false\n\t\tfor _, f := range files {\n\t\t\tif filepath.Base(f) == \"main.go\" {\n\t\t\t\thasMain = true\n\t\t\t}\n\t\t\tif filepath.Base(f) == \"sub.go\" {\n\t\t\t\thasSub = true\n\t\t\t}\n\t\t}\n\t\tt.Assert(hasMain, true)\n\t\tt.Assert(hasSub, true)\n\t})\n}\n\nfunc Test_findGoFiles_EmptyDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create empty temp directory\n\t\ttempDir := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDir)\n\n\t\t// Find Go files\n\t\tfiles, err := findGoFiles(tempDir)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\t})\n}\n\n// Helper function to check if string contains substring\nfunc contains(s, substr string) bool {\n\treturn len(s) >= len(substr) && (s == substr || len(s) > 0 && containsAt(s, substr))\n}\n\nfunc containsAt(s, substr string) bool {\n\tfor i := 0; i <= len(s)-len(substr); i++ {\n\t\tif s[i:i+len(substr)] == substr {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genpb/genpb.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genpb\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\ntype (\n\tCGenPb      struct{}\n\tCGenPbInput struct {\n\t\tg.Meta     `name:\"pb\" config:\"{CGenPbConfig}\" brief:\"{CGenPbBrief}\" eg:\"{CGenPbEg}\"`\n\t\tPath       string `name:\"path\" short:\"p\"  dc:\"protobuf file folder path\" d:\"manifest/protobuf\"`\n\t\tOutputApi  string `name:\"api\"  short:\"a\"  dc:\"output folder path storing generated go files of api\" d:\"api\"`\n\t\tOutputCtrl string `name:\"ctrl\" short:\"c\"  dc:\"output folder path storing generated go files of controller\" d:\"internal/controller\"`\n\t}\n\tCGenPbOutput struct{}\n)\n\nconst (\n\tCGenPbConfig = `gfcli.gen.pb`\n\tCGenPbBrief  = `parse proto files and generate protobuf go files`\n\tCGenPbEg     = `\ngf gen pb\ngf gen pb -p . -a . -p .\n`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenPbEg`:     CGenPbEg,\n\t\t`CGenPbBrief`:  CGenPbBrief,\n\t\t`CGenPbConfig`: CGenPbConfig,\n\t})\n}\n\nfunc (c CGenPb) Pb(ctx context.Context, in CGenPbInput) (out *CGenPbOutput, err error) {\n\t// Necessary check.\n\tprotoc := gproc.SearchBinary(\"protoc\")\n\tif protoc == \"\" {\n\t\tmlog.Fatalf(`command \"protoc\" not found in your environment, please install protoc first: https://grpc.io/docs/languages/go/quickstart/`)\n\t}\n\n\t// protocol fold checks.\n\tvar (\n\t\tprotoPath    = gfile.RealPath(in.Path)\n\t\tisParsingPWD bool\n\t)\n\tif protoPath == \"\" {\n\t\t// Use current working directory as protoPath if there are proto files under.\n\t\tcurrentPath := gfile.Pwd()\n\t\tcurrentFiles, _ := gfile.ScanDirFile(currentPath, \"*.proto\")\n\t\tif len(currentFiles) > 0 {\n\t\t\tprotoPath = currentPath\n\t\t\tisParsingPWD = true\n\t\t} else {\n\t\t\tmlog.Fatalf(`proto files folder \"%s\" does not exist`, in.Path)\n\t\t}\n\t}\n\t// output path checks.\n\toutputApiPath := gfile.RealPath(in.OutputApi)\n\tif outputApiPath == \"\" {\n\t\tif isParsingPWD {\n\t\t\toutputApiPath = protoPath\n\t\t} else {\n\t\t\tmlog.Fatalf(`output api folder \"%s\" does not exist`, in.OutputApi)\n\t\t}\n\t}\n\toutputCtrlPath := gfile.RealPath(in.OutputCtrl)\n\tif outputCtrlPath == \"\" {\n\t\tif isParsingPWD {\n\t\t\toutputCtrlPath = \"\"\n\t\t} else {\n\t\t\tmlog.Fatalf(`output controller folder \"%s\" does not exist`, in.OutputCtrl)\n\t\t}\n\t}\n\n\t// folder scanning.\n\tfiles, err := gfile.ScanDirFile(protoPath, \"*.proto\", true)\n\tif err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\tif len(files) == 0 {\n\t\tmlog.Fatalf(`no proto files found in folder \"%s\"`, in.Path)\n\t}\n\n\tvar originPwd = gfile.Pwd()\n\tdefer gfile.Chdir(originPwd)\n\n\tif err = gfile.Chdir(protoPath); err != nil {\n\t\tmlog.Fatal(err)\n\t}\n\tfor _, file := range files {\n\t\tvar command = gproc.NewProcess(protoc, nil)\n\t\tcommand.Args = append(command.Args, \"--proto_path=\"+gfile.Pwd())\n\t\tcommand.Args = append(command.Args, \"--go_out=paths=source_relative:\"+outputApiPath)\n\t\tcommand.Args = append(command.Args, \"--go-grpc_out=paths=source_relative:\"+outputApiPath)\n\t\tcommand.Args = append(command.Args, file)\n\t\tmlog.Print(command.String())\n\t\tif err = command.Run(ctx); err != nil {\n\t\t\tmlog.Fatal(err)\n\t\t}\n\t}\n\t// Generate struct tag according comment rules.\n\terr = c.generateStructTag(ctx, generateStructTagInput{OutputApiPath: outputApiPath})\n\tif err != nil {\n\t\treturn\n\t}\n\t// Generate controllers according comment rules.\n\tif outputCtrlPath != \"\" {\n\t\terr = c.generateController(ctx, generateControllerInput{\n\t\t\tOutputApiPath:  outputApiPath,\n\t\t\tOutputCtrlPath: outputCtrlPath,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tmlog.Print(\"done!\")\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genpb/genpb_controller.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genpb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype generateControllerInput struct {\n\tOutputApiPath  string\n\tOutputCtrlPath string\n}\n\ntype generateCtrl struct {\n\tName    string\n\tPackage string\n\tVersion string\n\tMethods []generateCtrlMethod\n}\n\ntype generateCtrlMethod struct {\n\tName       string\n\tDefinition string\n}\n\nconst (\n\tcontrollerTemplate = `\npackage {Package}\n\ntype Controller struct {\n\t{Version}.Unimplemented{Name}Server\n}\n\nfunc Register(s *grpcx.GrpcServer) {\n\t{Version}.Register{Name}Server(s.Server, &Controller{})\n}\n`\n\tcontrollerMethodTemplate = `\nfunc (*Controller) {Definition} {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n`\n)\n\nfunc (c CGenPb) generateController(ctx context.Context, in generateControllerInput) (err error) {\n\tfiles, err := gfile.ScanDirFile(in.OutputApiPath, \"*_grpc.pb.go\", true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar controllers []generateCtrl\n\tfor _, file := range files {\n\t\tfileControllers, err := c.parseControllers(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcontrollers = append(controllers, fileControllers...)\n\t}\n\tif len(controllers) == 0 {\n\t\treturn nil\n\t}\n\t// Generate controller files.\n\terr = c.doGenerateControllers(in, controllers)\n\treturn\n}\n\nfunc (c CGenPb) parseControllers(filePath string) ([]generateCtrl, error) {\n\tvar (\n\t\tcontrollers []generateCtrl\n\t\tcontent     = gfile.GetContents(filePath)\n\t)\n\t_, err := gregex.ReplaceStringFuncMatch(\n\t\t`type (\\w+)Server interface {([\\s\\S]+?)}`,\n\t\tcontent,\n\t\tfunc(match []string) string {\n\t\t\tctrl := generateCtrl{\n\t\t\t\tName:    match[1],\n\t\t\t\tPackage: strings.ReplaceAll(gfile.Basename(gfile.Dir(gfile.Dir(filePath))), \"-\", \"_\"),\n\t\t\t\tVersion: gfile.Basename(gfile.Dir(filePath)),\n\t\t\t\tMethods: make([]generateCtrlMethod, 0),\n\t\t\t}\n\t\t\tlines := gstr.Split(match[2], \"\\n\")\n\t\t\tfor _, line := range lines {\n\t\t\t\tline = gstr.Trim(line)\n\t\t\t\tif line == \"\" || !gstr.IsLetterUpper(line[0]) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// Comment.\n\t\t\t\tif gregex.IsMatchString(`^//.+`, line) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tline, _ = gregex.ReplaceStringFuncMatch(\n\t\t\t\t\t`^(\\w+)\\(context\\.Context, \\*(\\w+)\\) \\(\\*(\\w+), error\\)$`,\n\t\t\t\t\tline,\n\t\t\t\t\tfunc(match []string) string {\n\t\t\t\t\t\treturn fmt.Sprintf(\n\t\t\t\t\t\t\t`%s(ctx context.Context, req *%s.%s) (res *%s.%s, err error)`,\n\t\t\t\t\t\t\tmatch[1], ctrl.Version, match[2], ctrl.Version, match[3],\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tctrl.Methods = append(ctrl.Methods, generateCtrlMethod{\n\t\t\t\t\tName:       gstr.Split(line, \"(\")[0],\n\t\t\t\t\tDefinition: line,\n\t\t\t\t})\n\t\t\t}\n\t\t\tif len(ctrl.Methods) > 0 {\n\t\t\t\tcontrollers = append(controllers, ctrl)\n\t\t\t}\n\t\t\treturn match[0]\n\t\t},\n\t)\n\treturn controllers, err\n}\n\nfunc (c CGenPb) doGenerateControllers(in generateControllerInput, controllers []generateCtrl) (err error) {\n\tfor _, controller := range controllers {\n\t\terr = c.doGenerateController(in, controller)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\terr = utils.ReplaceGeneratedContentGFV2(in.OutputCtrlPath)\n\treturn nil\n}\n\nfunc (c CGenPb) doGenerateController(in generateControllerInput, controller generateCtrl) (err error) {\n\tvar (\n\t\tfolderPath = gfile.Join(in.OutputCtrlPath, controller.Package)\n\t\tfilePath   = gfile.Join(folderPath, controller.Package+\".go\")\n\t\tisDirty    bool\n\t)\n\tif !gfile.Exists(folderPath) {\n\t\tif err = gfile.Mkdir(folderPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif !gfile.Exists(filePath) {\n\t\ttemplateContent := gstr.ReplaceByMap(controllerTemplate, g.MapStrStr{\n\t\t\t\"{Name}\":    controller.Name,\n\t\t\t\"{Version}\": controller.Version,\n\t\t\t\"{Package}\": controller.Package,\n\t\t})\n\t\tif err = gfile.PutContents(filePath, templateContent); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tisDirty = true\n\t}\n\t// Exist controller content.\n\tvar ctrlContent string\n\tfiles, err := gfile.ScanDirFile(folderPath, \"*.go\", false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, file := range files {\n\t\tif ctrlContent != \"\" {\n\t\t\tctrlContent += \"\\n\"\n\t\t}\n\t\tctrlContent += gfile.GetContents(file)\n\t}\n\t// Generate method content.\n\tvar generatedContent string\n\tfor _, method := range controller.Methods {\n\t\tif gstr.Contains(ctrlContent, fmt.Sprintf(`%s(`, method.Name)) {\n\t\t\tcontinue\n\t\t}\n\t\tif generatedContent != \"\" {\n\t\t\tgeneratedContent += \"\\n\"\n\t\t}\n\t\tgeneratedContent += gstr.ReplaceByMap(controllerMethodTemplate, g.MapStrStr{\n\t\t\t\"{Definition}\": method.Definition,\n\t\t})\n\t}\n\tif generatedContent != \"\" {\n\t\terr = gfile.PutContentsAppend(filePath, generatedContent)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tisDirty = true\n\t}\n\tif isDirty {\n\t\tutils.GoFmt(filePath)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genpb/genpb_tag.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genpb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype generateStructTagInput struct {\n\tOutputApiPath string\n}\n\nfunc (c CGenPb) generateStructTag(ctx context.Context, in generateStructTagInput) (err error) {\n\tfiles, err := gfile.ScanDirFile(in.OutputApiPath, \"*.pb.go\", true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar content string\n\tfor _, file := range files {\n\t\tcontent = gfile.GetContents(file)\n\t\tcontent, err = c.doTagReplacement(ctx, content)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = gfile.PutContents(file, content); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tutils.GoFmt(file)\n\t}\n\treturn\n}\n\nfunc (c CGenPb) doTagReplacement(ctx context.Context, content string) (string, error) {\n\tcontent, err := gregex.ReplaceStringFuncMatch(`type (\\w+) struct {([\\s\\S]+?)}`, content, func(match []string) string {\n\t\tvar (\n\t\t\ttopCommentMatch  []string\n\t\t\ttailCommentMatch []string\n\t\t\tlines            = gstr.Split(match[2], \"\\n\")\n\t\t\tlineTagMap       = gmap.NewListMap()\n\t\t)\n\t\tfor index, line := range lines {\n\t\t\tline = gstr.Trim(line)\n\t\t\tif line == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Top comment.\n\t\t\ttopCommentMatch, _ = gregex.MatchString(`^/[/|\\*](.+)`, line)\n\t\t\tif len(topCommentMatch) > 1 {\n\t\t\t\tc.tagCommentIntoListMap(gstr.Trim(topCommentMatch[1]), lineTagMap)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Tail comment.\n\t\t\ttailCommentMatch, _ = gregex.MatchString(\".+?`.+?`.+?//(.+)\", line)\n\t\t\tif len(tailCommentMatch) > 1 {\n\t\t\t\tc.tagCommentIntoListMap(gstr.Trim(tailCommentMatch[1]), lineTagMap)\n\t\t\t}\n\t\t\t// Tag injection.\n\t\t\tif !lineTagMap.IsEmpty() {\n\t\t\t\ttagContent := c.listMapToStructTag(lineTagMap)\n\t\t\t\tlineTagMap.Clear()\n\t\t\t\t// If already have it, don't add it anymore\n\t\t\t\tif gstr.Contains(gstr.StrTill(line, \"` //\"), tagContent) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tline, _ = gregex.ReplaceString(\"`(.+)`\", fmt.Sprintf(\"`$1 %s`\", tagContent), line)\n\t\t\t}\n\t\t\tlines[index] = line\n\t\t}\n\t\tmatch[2] = gstr.Join(lines, \"\\n\")\n\t\treturn fmt.Sprintf(\"type %s struct {%s}\", match[1], match[2])\n\t})\n\treturn content, err\n}\n\nfunc (c CGenPb) tagCommentIntoListMap(comment string, lineTagMap *gmap.ListMap) {\n\ttagCommentMatch, _ := gregex.MatchString(`^(\\w+):(.+)`, comment)\n\tif len(tagCommentMatch) > 1 {\n\t\tvar (\n\t\t\ttagName    = gstr.Trim(tagCommentMatch[1])\n\t\t\ttagContent = gstr.Trim(tagCommentMatch[2])\n\t\t)\n\t\tlineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)\n\t} else {\n\t\tvar (\n\t\t\ttagName = \"dc\"\n\t\t\t// Convert backticks and double quotes to single quotes.\n\t\t\ttagContent = gstr.ReplaceByMap(comment, g.MapStrStr{\n\t\t\t\t\"`\": `'`,\n\t\t\t\t`\"`: `'`,\n\t\t\t})\n\t\t)\n\t\tlineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)\n\t}\n}\n\nfunc (c CGenPb) listMapToStructTag(lineTagMap *gmap.ListMap) string {\n\tvar tag string\n\tlineTagMap.Iterator(func(key, value any) bool {\n\t\tif tag != \"\" {\n\t\t\ttag += \" \"\n\t\t}\n\t\ttag += fmt.Sprintf(\n\t\t\t`%s:\"%s\"`,\n\t\t\tkey, gstr.Replace(gconv.String(value), `\"`, `\\\"`),\n\t\t)\n\t\treturn true\n\t})\n\treturn tag\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genpbentity/genpbentity.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genpbentity\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\t\"github.com/olekukonko/tablewriter/renderer\"\n\t\"github.com/olekukonko/tablewriter/tw\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype (\n\tCGenPbEntity      struct{}\n\tCGenPbEntityInput struct {\n\t\tg.Meta            `name:\"pbentity\" config:\"{CGenPbEntityConfig}\" brief:\"{CGenPbEntityBrief}\" eg:\"{CGenPbEntityEg}\" ad:\"{CGenPbEntityAd}\"`\n\t\tPath              string   `name:\"path\"              short:\"p\"  brief:\"{CGenPbEntityBriefPath}\" d:\"manifest/protobuf/pbentity\"`\n\t\tPackage           string   `name:\"package\"           short:\"k\"  brief:\"{CGenPbEntityBriefPackage}\"`\n\t\tGoPackage         string   `name:\"goPackage\"           short:\"g\"  brief:\"{CGenPbEntityBriefGoPackage}\"`\n\t\tLink              string   `name:\"link\"              short:\"l\"  brief:\"{CGenPbEntityBriefLink}\"`\n\t\tTables            string   `name:\"tables\"            short:\"t\"  brief:\"{CGenPbEntityBriefTables}\"`\n\t\tPrefix            string   `name:\"prefix\"            short:\"f\"  brief:\"{CGenPbEntityBriefPrefix}\"`\n\t\tRemovePrefix      string   `name:\"removePrefix\"      short:\"r\"  brief:\"{CGenPbEntityBriefRemovePrefix}\"`\n\t\tRemoveFieldPrefix string   `name:\"removeFieldPrefix\" short:\"rf\" brief:\"{CGenPbEntityBriefRemoveFieldPrefix}\"`\n\t\tTablesEx          string   `name:\"tablesEx\"          short:\"x\"  brief:\"{CGenDaoBriefTablesEx}\"`\n\t\tNameCase          string   `name:\"nameCase\"          short:\"n\"  brief:\"{CGenPbEntityBriefNameCase}\" d:\"Camel\"`\n\t\tJsonCase          string   `name:\"jsonCase\"          short:\"j\"  brief:\"{CGenPbEntityBriefJsonCase}\" d:\"none\"`\n\t\tOption            string   `name:\"option\"            short:\"o\"  brief:\"{CGenPbEntityBriefOption}\"`\n\t\tShardingPattern   []string `name:\"shardingPattern\"     short:\"sp\" brief:\"{CGenDaoBriefShardingPattern}\"`\n\n\t\tTypeMapping  map[DBFieldTypeName]CustomAttributeType  `name:\"typeMapping\"  short:\"y\"  brief:\"{CGenPbEntityBriefTypeMapping}\"  orphan:\"true\"`\n\t\tFieldMapping map[DBTableFieldName]CustomAttributeType `name:\"fieldMapping\" short:\"fm\" brief:\"{CGenPbEntityBriefFieldMapping}\" orphan:\"true\"`\n\t}\n\tCGenPbEntityOutput struct{}\n\n\tCGenPbEntityInternalInput struct {\n\t\tCGenPbEntityInput\n\t\tDB           gdb.DB\n\t\tTableName    string // TableName specifies the table name of the table.\n\t\tNewTableName string // NewTableName specifies the prefix-stripped name of the table.\n\t}\n\n\tDBTableFieldName    = string\n\tDBFieldTypeName     = string\n\tCustomAttributeType struct {\n\t\tType   string `brief:\"custom attribute type name\"`\n\t\tImport string `brief:\"custom import for this type\"`\n\t}\n)\n\nconst (\n\tdefaultPackageSuffix = `api/pbentity`\n\tCGenPbEntityConfig   = `gfcli.gen.pbentity`\n\tCGenPbEntityBrief    = `generate entity message files in protobuf3 format`\n\tCGenPbEntityEg       = `\ngf gen pbentity\ngf gen pbentity -l \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\ngf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login\ngf gen pbentity -r user_ -k github.com/gogf/gf/example/protobuf\ngf gen pbentity -r user_\n`\n\n\tCGenPbEntityAd = `\nCONFIGURATION SUPPORT\n    Options are also supported by configuration file.\n    It's suggested using configuration file instead of command line arguments making producing.\n    The configuration node name is \"gf.gen.pbentity\", which also supports multiple databases, for example(config.yaml):\n    gfcli:\n      gen:\n      - pbentity:\n            link:    \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n            path:    \"protocol/demos/entity\"\n            tables:  \"order,products\"\n            package: \"demos\"\n      - pbentity:\n            link:    \"mysql:root:12345678@tcp(127.0.0.1:3306)/primary\"\n            path:    \"protocol/demos/entity\"\n            prefix:  \"primary_\"\n            tables:  \"user, userDetail\"\n            package: \"demos\"\n            option:  |\n\t\t\t  option go_package    = \"protobuf/demos\";\n\t\t\t  option java_package  = \"protobuf/demos\";\n\t\t\t  option php_namespace = \"protobuf/demos\";\n            typeMapping:\n              json:\n                type: google.protobuf.Value\n                import: google/protobuf/struct.proto\n              jsonb:\n                type: google.protobuf.Value\n                import: google/protobuf/struct.proto\n`\n\tCGenPbEntityBriefPath              = `directory path for generated files storing`\n\tCGenPbEntityBriefPackage           = `package path for all entity proto files`\n\tCGenPbEntityBriefGoPackage         = `go package path for all entity proto files`\n\tCGenPbEntityBriefLink              = `database configuration, the same as the ORM configuration of GoFrame`\n\tCGenPbEntityBriefTables            = `generate models only for given tables, multiple table names separated with ','`\n\tCGenPbEntityBriefPrefix            = `add specified prefix for all entity names and entity proto files`\n\tCGenPbEntityBriefRemovePrefix      = `remove specified prefix of the table, multiple prefix separated with ','`\n\tCGenPbEntityBriefTablesEx          = `generate all models exclude the specified tables, multiple prefix separated with ','`\n\tCGenPbEntityBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`\n\tCGenPbEntityBriefOption            = `extra protobuf options`\n\tCGenPbEntityBriefShardingPattern   = `sharding pattern for table name, e.g. \"users_?\" will replace tables \"users_001,users_002,...\" to \"users\" pbentity`\n\tCGenPbEntityBriefGroup             = `\nspecifying the configuration group name of database for generated ORM instance,\nit's not necessary and the default value is \"default\"\n`\n\n\tCGenPbEntityBriefNameCase = `\ncase for message attribute names, default is \"Camel\":\n| Case            | Example            |\n|---------------- |--------------------|\n| Camel           | AnyKindOfString    |\n| CamelLower      | anyKindOfString    | default\n| Snake           | any_kind_of_string |\n| SnakeScreaming  | ANY_KIND_OF_STRING |\n| SnakeFirstUpper | rgb_code_md5       |\n| Kebab           | any-kind-of-string |\n| KebabScreaming  | ANY-KIND-OF-STRING |\n`\n\n\tCGenPbEntityBriefJsonCase = `\ncase for message json tag, cases are the same as \"nameCase\", default \"CamelLower\".\nset it to \"none\" to ignore json tag generating.\n`\n\n\tCGenPbEntityBriefTypeMapping  = `custom local type mapping for generated struct attributes relevant to fields of table`\n\tCGenPbEntityBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`\n)\n\nvar defaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{\n\t// gdb.LocalTypeString\n\t\"string\": {\n\t\tType: \"string\",\n\t},\n\t// gdb.LocalTypeTime\n\t// \"time\": {\n\t// \tType:   \"google.protobuf.Duration\",\n\t// \tImport: \"google/protobuf/duration.proto\",\n\t// },\n\t// gdb.LocalTypeDate\n\t\"date\": {\n\t\tType:   \"google.protobuf.Timestamp\",\n\t\tImport: \"google/protobuf/timestamp.proto\",\n\t},\n\t// gdb.LocalTypeDatetime\n\t\"datetime\": {\n\t\tType:   \"google.protobuf.Timestamp\",\n\t\tImport: \"google/protobuf/timestamp.proto\",\n\t},\n\t// gdb.LocalTypeInt\n\t\"int\": {\n\t\tType: \"int32\",\n\t},\n\t// gdb.LocalTypeUint\n\t\"uint\": {\n\t\tType: \"uint32\",\n\t},\n\t// gdb.LocalTypeInt64\n\t\"int64\": {\n\t\tType: \"int64\",\n\t},\n\t// gdb.LocalTypeUint64\n\t\"uint64\": {\n\t\tType: \"uint64\",\n\t},\n\t// gdb.LocalTypeIntSlice\n\t\"[]int\": {\n\t\tType: \"repeated int32\",\n\t},\n\t// gdb.LocalTypeInt64Slice\n\t\"[]int64\": {\n\t\tType: \"repeated int64\",\n\t},\n\t// gdb.LocalTypeUint64Slice\n\t\"[]uint64\": {\n\t\tType: \"repeated uint64\",\n\t},\n\t// gdb.LocalTypeInt64Bytes\n\t\"int64-bytes\": {\n\t\tType: \"repeated int64\",\n\t},\n\t// gdb.LocalTypeUint64Bytes\n\t\"uint64-bytes\": {\n\t\tType: \"repeated uint64\",\n\t},\n\t// gdb.LocalTypeFloat32\n\t\"float32\": {\n\t\tType: \"float\",\n\t},\n\t// gdb.LocalTypeFloat64\n\t\"float64\": {\n\t\tType: \"double\",\n\t},\n\t// gdb.LocalTypeBytes\n\t\"[]byte\": {\n\t\tType: \"bytes\",\n\t},\n\t// gdb.LocalTypeBool\n\t\"bool\": {\n\t\tType: \"bool\",\n\t},\n\t// gdb.LocalTypeJson\n\t// \"json\": {\n\t// \tType:   \"google.protobuf.Value\",\n\t// \tImport: \"google/protobuf/struct.proto\",\n\t// },\n\t// gdb.LocalTypeJsonb\n\t// \"jsonb\": {\n\t// \tType:   \"google.protobuf.Value\",\n\t// \tImport: \"google/protobuf/struct.proto\",\n\t// },\n}\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenPbEntityConfig`:                 CGenPbEntityConfig,\n\t\t`CGenPbEntityBrief`:                  CGenPbEntityBrief,\n\t\t`CGenPbEntityEg`:                     CGenPbEntityEg,\n\t\t`CGenPbEntityAd`:                     CGenPbEntityAd,\n\t\t`CGenPbEntityBriefPath`:              CGenPbEntityBriefPath,\n\t\t`CGenPbEntityBriefPackage`:           CGenPbEntityBriefPackage,\n\t\t`CGenPbEntityBriefGoPackage`:         CGenPbEntityBriefGoPackage,\n\t\t`CGenPbEntityBriefLink`:              CGenPbEntityBriefLink,\n\t\t`CGenPbEntityBriefTables`:            CGenPbEntityBriefTables,\n\t\t`CGenPbEntityBriefPrefix`:            CGenPbEntityBriefPrefix,\n\t\t`CGenPbEntityBriefRemovePrefix`:      CGenPbEntityBriefRemovePrefix,\n\t\t`CGenPbEntityBriefTablesEx`:          CGenPbEntityBriefTablesEx,\n\t\t`CGenPbEntityBriefRemoveFieldPrefix`: CGenPbEntityBriefRemoveFieldPrefix,\n\t\t`CGenPbEntityBriefGroup`:             CGenPbEntityBriefGroup,\n\t\t`CGenPbEntityBriefNameCase`:          CGenPbEntityBriefNameCase,\n\t\t`CGenPbEntityBriefJsonCase`:          CGenPbEntityBriefJsonCase,\n\t\t`CGenPbEntityBriefOption`:            CGenPbEntityBriefOption,\n\t\t`CGenPbEntityBriefShardingPattern`:   CGenPbEntityBriefShardingPattern,\n\t\t`CGenPbEntityBriefTypeMapping`:       CGenPbEntityBriefTypeMapping,\n\t\t`CGenPbEntityBriefFieldMapping`:      CGenPbEntityBriefFieldMapping,\n\t})\n}\n\nfunc (c CGenPbEntity) PbEntity(ctx context.Context, in CGenPbEntityInput) (out *CGenPbEntityOutput, err error) {\n\tvar (\n\t\tconfig = g.Cfg()\n\t)\n\tif config.Available(ctx) {\n\t\tv := config.MustGet(ctx, CGenPbEntityConfig)\n\t\tif v.IsSlice() {\n\t\t\tfor i := 0; i < len(v.Interfaces()); i++ {\n\t\t\t\tdoGenPbEntityForArray(ctx, i, in)\n\t\t\t}\n\t\t} else {\n\t\t\tdoGenPbEntityForArray(ctx, -1, in)\n\t\t}\n\t} else {\n\t\tdoGenPbEntityForArray(ctx, -1, in)\n\t}\n\tmlog.Print(\"done!\")\n\treturn\n}\n\nfunc doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput) {\n\tvar (\n\t\terr error\n\t\tdb  gdb.DB\n\t)\n\tif index >= 0 {\n\t\terr = g.Cfg().MustGet(\n\t\t\tctx,\n\t\t\tfmt.Sprintf(`%s.%d`, CGenPbEntityConfig, index),\n\t\t).Scan(&in)\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(`invalid configuration of \"%s\": %+v`, CGenPbEntityConfig, err)\n\t\t}\n\t}\n\tif in.Package == \"\" {\n\t\tmlog.Debug(`package parameter is empty, trying calculating the package path using go.mod`)\n\t\tmodName := utils.GetImportPath(gfile.Pwd())\n\t\tin.Package = modName + \"/\" + defaultPackageSuffix\n\t}\n\tremovePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, \",\")\n\n\texcludeTables := gset.NewStrSetFrom(gstr.SplitAndTrim(in.TablesEx, \",\"))\n\n\t// It uses user passed database configuration.\n\tif in.Link != \"\" {\n\t\tvar (\n\t\t\ttempGroup = gtime.TimestampNanoStr()\n\t\t\tmatch, _  = gregex.MatchString(`([a-z]+):(.+)`, in.Link)\n\t\t)\n\t\tif len(match) == 3 {\n\t\t\tgdb.AddConfigNode(tempGroup, gdb.ConfigNode{\n\t\t\t\tType: gstr.Trim(match[1]),\n\t\t\t\tLink: in.Link,\n\t\t\t})\n\t\t\tdb, _ = gdb.Instance(tempGroup)\n\t\t}\n\t} else {\n\t\tdb = g.DB()\n\t}\n\tif db == nil {\n\t\tmlog.Fatal(\"database initialization failed\")\n\t}\n\n\ttableNames := ([]string)(nil)\n\tshardingNewTableSet := gset.NewStrSet()\n\tif in.Tables != \"\" {\n\t\ttableNames = gstr.SplitAndTrim(in.Tables, \",\")\n\t} else {\n\t\ttableNames, err = db.Tables(context.TODO())\n\t\tif err != nil {\n\t\t\tmlog.Fatalf(\"fetching tables failed: \\n %v\", err)\n\t\t}\n\t}\n\t// merge default typeMapping to input typeMapping.\n\tif in.TypeMapping == nil {\n\t\tin.TypeMapping = defaultTypeMapping\n\t} else {\n\t\tfor key, typeMapping := range defaultTypeMapping {\n\t\t\tif _, ok := in.TypeMapping[key]; !ok {\n\t\t\t\tin.TypeMapping[key] = typeMapping\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, tableName := range tableNames {\n\t\tif excludeTables.Contains(tableName) {\n\t\t\tcontinue\n\t\t}\n\t\tnewTableName := tableName\n\t\tfor _, v := range removePrefixArray {\n\t\t\tnewTableName = gstr.TrimLeftStr(newTableName, v, 1)\n\t\t}\n\t\tvar shardingTableName string\n\t\tif len(in.ShardingPattern) > 0 {\n\t\t\tfor _, pattern := range in.ShardingPattern {\n\t\t\t\tvar (\n\t\t\t\t\tmatch      []string\n\t\t\t\t\tregPattern = gstr.Replace(pattern, \"?\", `(.+)`)\n\t\t\t\t)\n\t\t\t\tmatch, err = gregex.MatchString(regPattern, newTableName)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmlog.Fatalf(`invalid sharding pattern \"%s\": %+v`, pattern, err)\n\t\t\t\t}\n\t\t\t\tif len(match) < 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tshardingTableName = gstr.Replace(pattern, \"?\", \"\")\n\t\t\t\tshardingTableName = gstr.Trim(shardingTableName, `_.-`)\n\t\t\t}\n\t\t}\n\t\tif shardingTableName != \"\" {\n\t\t\tif shardingNewTableSet.Contains(shardingTableName) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tshardingNewTableSet.Add(shardingTableName)\n\t\t\tnewTableName = shardingTableName\n\t\t}\n\t\tgeneratePbEntityContentFile(ctx, CGenPbEntityInternalInput{\n\t\t\tCGenPbEntityInput: in,\n\t\t\tDB:                db,\n\t\t\tTableName:         tableName,\n\t\t\tNewTableName:      newTableName,\n\t\t})\n\t}\n}\n\n// generatePbEntityContentFile generates the protobuf files for given table.\nfunc generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInput) {\n\tfieldMap, err := in.DB.TableFields(ctx, in.TableName)\n\tif err != nil {\n\t\tmlog.Fatalf(\"fetching tables fields failed for table '%s':\\n%v\", in.TableName, err)\n\t}\n\t// Change the `newTableName` if `Prefix` is given.\n\tnewTableName := in.Prefix + in.NewTableName\n\tvar (\n\t\ttableNameCamelCase                 = gstr.CaseCamel(newTableName)\n\t\ttableNameSnakeCase                 = gstr.CaseSnake(newTableName)\n\t\tentityMessageDefine, appendImports = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)\n\t\tfileName                           = gstr.Trim(tableNameSnakeCase, \"-_.\")\n\t\tpath                               = filepath.FromSlash(gfile.Join(in.Path, fileName+\".proto\"))\n\t)\n\tpackageImportStr := \"\"\n\tvar packageImportsArray = garray.NewStrArray()\n\tif len(appendImports) > 0 {\n\t\tfor _, appendImport := range appendImports {\n\t\t\tpackageImportStr = fmt.Sprintf(`import \"%s\";`, appendImport)\n\t\t\tif packageImportsArray.Search(packageImportStr) == -1 {\n\t\t\t\tpackageImportsArray.Append(packageImportStr)\n\t\t\t}\n\t\t}\n\t}\n\tif in.GoPackage == \"\" {\n\t\tin.GoPackage = in.Package\n\t}\n\tentityContent := gstr.ReplaceByMap(getTplPbEntityContent(\"\"), g.MapStrStr{\n\t\t\"{Imports}\":       packageImportsArray.Join(\"\\n\"),\n\t\t\"{PackageName}\":   gfile.Basename(in.Package),\n\t\t\"{GoPackage}\":     in.GoPackage,\n\t\t\"{OptionContent}\": in.Option,\n\t\t\"{EntityMessage}\": entityMessageDefine,\n\t})\n\tif err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {\n\t\tmlog.Fatalf(\"writing content to '%s' failed: %v\", path, err)\n\t} else {\n\t\tmlog.Print(\"generated:\", gfile.RealPath(path))\n\t}\n}\n\n// generateEntityMessageDefinition generates and returns the message definition for specified table.\nfunc generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) (string, []string) {\n\tvar (\n\t\tappendImports []string\n\t\tbuffer        = bytes.NewBuffer(nil)\n\t\tarray         = make([][]string, len(fieldMap))\n\t\tnames         = sortFieldKeyForPbEntity(fieldMap)\n\t)\n\tfor index, name := range names {\n\t\tvar imports string\n\t\tarray[index], imports = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)\n\t\tif imports != \"\" {\n\t\t\tappendImports = append(appendImports, imports)\n\t\t}\n\t}\n\ttable := tablewriter.NewTable(buffer,\n\t\ttablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{\n\t\t\tBorders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.On, Right: tw.Off},\n\t\t\tSettings: tw.Settings{\n\t\t\t\tSeparators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},\n\t\t\t},\n\t\t\tSymbols: tw.NewSymbolCustom(\"Proto\").WithColumn(\" \"),\n\t\t})),\n\t\ttablewriter.WithConfig(tablewriter.Config{\n\t\t\tRow: tw.CellConfig{\n\t\t\t\tFormatting: tw.CellFormatting{AutoWrap: tw.WrapNone},\n\t\t\t},\n\t\t}),\n\t)\n\ttable.Bulk(array)\n\ttable.Render()\n\tstContent := buffer.String()\n\t// Let's do this hack of table writer for indent!\n\tstContent = regexp.MustCompile(`\\s+\\n`).ReplaceAllString(gstr.Replace(stContent, \"  #\", \"\"), \"\\n\")\n\tbuffer.Reset()\n\tbuffer.WriteString(fmt.Sprintf(\"message %s {\\n\", entityName))\n\tbuffer.WriteString(stContent)\n\tbuffer.WriteString(\"}\")\n\treturn buffer.String(), appendImports\n}\n\n// generateMessageFieldForPbEntity generates and returns the message definition for specified field.\nfunc generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) (attrLines []string, appendImport string) {\n\tvar (\n\t\tlocalTypeNameStr string\n\t\tlocalTypeName    gdb.LocalType\n\t\tcomment          string\n\t\tjsonTagStr       string\n\t\terr              error\n\t\tctx              = gctx.GetInitCtx()\n\t)\n\tif in.TypeMapping != nil && len(in.TypeMapping) > 0 {\n\t\t// match typeMapping after local type transform.\n\t\t// eg: double => string, varchar => string etc.\n\t\tlocalTypeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif localTypeName != \"\" {\n\t\t\tif typeMappingLocal, localOk := in.TypeMapping[strings.ToLower(string(localTypeName))]; localOk {\n\t\t\t\tlocalTypeNameStr = typeMappingLocal.Type\n\t\t\t\tappendImport = typeMappingLocal.Import\n\t\t\t}\n\t\t}\n\t\t// Try match unknown / string localTypeName with db type.\n\t\tif localTypeName == \"\" || localTypeName == gdb.LocalTypeString {\n\t\t\tformattedFieldType, _ := in.DB.GetFormattedDBTypeNameForField(field.Type)\n\t\t\tif typeMapping, ok := in.TypeMapping[strings.ToLower(formattedFieldType)]; ok {\n\t\t\t\tlocalTypeNameStr = typeMapping.Type\n\t\t\t\tappendImport = typeMapping.Import\n\t\t\t}\n\t\t}\n\t}\n\n\tif localTypeNameStr == \"\" {\n\t\tlocalTypeNameStr = \"string\"\n\t}\n\n\tcomment = gstr.ReplaceByArray(field.Comment, g.SliceStr{\n\t\t\"\\n\", \" \",\n\t\t\"\\r\", \" \",\n\t})\n\tcomment = gstr.Trim(comment)\n\tcomment = gstr.Replace(comment, `\\n`, \" \")\n\tcomment, _ = gregex.ReplaceString(`\\s{2,}`, ` `, comment)\n\tif jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != \"\" {\n\t\tjsonTagStr = fmt.Sprintf(`[json_name = \"%s\"]`, jsonTagName)\n\t\t// beautiful indent.\n\t\tif index < 10 {\n\t\t\t// 3 spaces\n\t\t\tjsonTagStr = \"   \" + jsonTagStr\n\t\t} else if index < 100 {\n\t\t\t// 2 spaces\n\t\t\tjsonTagStr = \"  \" + jsonTagStr\n\t\t} else {\n\t\t\t// 1 spaces\n\t\t\tjsonTagStr = \" \" + jsonTagStr\n\t\t}\n\t}\n\n\tremoveFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, \",\")\n\tnewFiledName := field.Name\n\tfor _, v := range removeFieldPrefixArray {\n\t\tnewFiledName = gstr.TrimLeftStr(newFiledName, v, 1)\n\t}\n\n\tif in.FieldMapping != nil && len(in.FieldMapping) > 0 {\n\t\tif typeMapping, ok := in.FieldMapping[fmt.Sprintf(\"%s.%s\", in.TableName, newFiledName)]; ok {\n\t\t\tlocalTypeNameStr = typeMapping.Type\n\t\t\tappendImport = typeMapping.Import\n\t\t}\n\t}\n\n\treturn []string{\n\t\t\"    #\" + localTypeNameStr,\n\t\t\" #\" + formatCase(newFiledName, in.NameCase),\n\t\t\" #= \" + gconv.String(index) + jsonTagStr + \";\",\n\t\t\" #\" + fmt.Sprintf(`// %s`, comment),\n\t}, appendImport\n}\n\nfunc getTplPbEntityContent(tplEntityPath string) string {\n\tif tplEntityPath != \"\" {\n\t\treturn gfile.GetContents(tplEntityPath)\n\t}\n\treturn consts.TemplatePbEntityMessageContent\n}\n\n// formatCase call gstr.Case* function to convert the s to specified case.\nfunc formatCase(str, caseStr string) string {\n\tif caseStr == \"none\" {\n\t\treturn \"\"\n\t}\n\treturn gstr.CaseConvert(str, gstr.CaseTypeMatch(caseStr))\n}\n\nfunc sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {\n\tnames := make(map[int]string)\n\tfor _, field := range fieldMap {\n\t\tnames[field.Index] = field.Name\n\t}\n\tvar (\n\t\tresult = make([]string, len(names))\n\t\ti      = 0\n\t\tj      = 0\n\t)\n\tfor {\n\t\tif len(names) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tif val, ok := names[i]; ok {\n\t\t\tresult[j] = val\n\t\t\tj++\n\t\t\tdelete(names, i)\n\t\t}\n\t\ti++\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nconst (\n\tCGenServiceConfig = `gfcli.gen.service`\n\tCGenServiceUsage  = `gf gen service [OPTION]`\n\tCGenServiceBrief  = `parse struct and associated functions from packages to generate service go file`\n\tCGenServiceEg     = `\ngf gen service\ngf gen service -f Snake\n`\n\tCGenServiceBriefSrcFolder    = `source folder path to be parsed. default: internal/logic`\n\tCGenServiceBriefDstFolder    = `destination folder path storing automatically generated go files. default: internal/service`\n\tCGenServiceBriefFileNameCase = `\ndestination file name storing automatically generated go files, cases are as follows:\n| Case            | Example            |\n|---------------- |--------------------|\n| Lower           | anykindofstring    |\n| Camel           | AnyKindOfString    |\n| CamelLower      | anyKindOfString    |\n| Snake           | any_kind_of_string | default\n| SnakeScreaming  | ANY_KIND_OF_STRING |\n| SnakeFirstUpper | rgb_code_md5       |\n| Kebab           | any-kind-of-string |\n| KebabScreaming  | ANY-KIND-OF-STRING |\n`\n\tCGenServiceBriefWatchFile    = `used in file watcher, it re-generates all service go files only if given file is under srcFolder`\n\tCGenServiceBriefStPattern    = `regular expression matching struct name for generating service. default: ^s([A-Z]\\\\\\\\w+)$`\n\tCGenServiceBriefPackages     = `produce go files only for given source packages(source folders)`\n\tCGenServiceBriefImportPrefix = `custom import prefix to calculate import path for generated importing go file of logic`\n\tCGenServiceBriefClear        = `delete all generated go files that are not used any further`\n)\n\nfunc init() {\n\tgtag.Sets(g.MapStrStr{\n\t\t`CGenServiceConfig`:            CGenServiceConfig,\n\t\t`CGenServiceUsage`:             CGenServiceUsage,\n\t\t`CGenServiceBrief`:             CGenServiceBrief,\n\t\t`CGenServiceEg`:                CGenServiceEg,\n\t\t`CGenServiceBriefSrcFolder`:    CGenServiceBriefSrcFolder,\n\t\t`CGenServiceBriefDstFolder`:    CGenServiceBriefDstFolder,\n\t\t`CGenServiceBriefFileNameCase`: CGenServiceBriefFileNameCase,\n\t\t`CGenServiceBriefWatchFile`:    CGenServiceBriefWatchFile,\n\t\t`CGenServiceBriefStPattern`:    CGenServiceBriefStPattern,\n\t\t`CGenServiceBriefPackages`:     CGenServiceBriefPackages,\n\t\t`CGenServiceBriefImportPrefix`: CGenServiceBriefImportPrefix,\n\t\t`CGenServiceBriefClear`:        CGenServiceBriefClear,\n\t})\n}\n\ntype (\n\tCGenService      struct{}\n\tCGenServiceInput struct {\n\t\tg.Meta          `name:\"service\" config:\"{CGenServiceConfig}\" usage:\"{CGenServiceUsage}\" brief:\"{CGenServiceBrief}\" eg:\"{CGenServiceEg}\"`\n\t\tSrcFolder       string   `short:\"s\" name:\"srcFolder\" brief:\"{CGenServiceBriefSrcFolder}\" d:\"internal/logic\"`\n\t\tDstFolder       string   `short:\"d\" name:\"dstFolder\" brief:\"{CGenServiceBriefDstFolder}\" d:\"internal/service\"`\n\t\tDstFileNameCase string   `short:\"f\" name:\"dstFileNameCase\" brief:\"{CGenServiceBriefFileNameCase}\" d:\"Snake\"`\n\t\tWatchFile       string   `short:\"w\" name:\"watchFile\" brief:\"{CGenServiceBriefWatchFile}\"`\n\t\tStPattern       string   `short:\"a\" name:\"stPattern\" brief:\"{CGenServiceBriefStPattern}\" d:\"^s([A-Z]\\\\w+)$\"`\n\t\tPackages        []string `short:\"p\" name:\"packages\" brief:\"{CGenServiceBriefPackages}\"`\n\t\tImportPrefix    string   `short:\"i\" name:\"importPrefix\" brief:\"{CGenServiceBriefImportPrefix}\"`\n\t\tClear           bool     `short:\"l\" name:\"clear\" brief:\"{CGenServiceBriefClear}\" orphan:\"true\"`\n\t}\n\tCGenServiceOutput struct{}\n)\n\nconst (\n\tgenServiceFileLockSeconds = 10\n)\n\ntype fileInfo struct {\n\tPkgItems  []pkgItem\n\tFuncItems []funcItem\n}\n\ntype folderInfo struct {\n\tSrcPackageName      string\n\tSrcImportedPackages *garray.SortedStrArray\n\tSrcStructFunctions  *gmap.ListMap\n\tDstFilePath         string\n\n\tFileInfos []*fileInfo\n}\n\nfunc (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGenServiceOutput, err error) {\n\tin.SrcFolder = filepath.ToSlash(in.SrcFolder)\n\tin.SrcFolder = gstr.TrimRight(in.SrcFolder, `/`)\n\tin.WatchFile = filepath.ToSlash(in.WatchFile)\n\tin.WatchFile = gstr.TrimRight(in.WatchFile, `/`)\n\n\t// Watch file handling.\n\tif in.WatchFile != \"\" {\n\t\t// File lock to avoid multiple processes.\n\t\tvar (\n\t\t\tflockFilePath = gfile.Temp(\"gf.cli.gen.service.lock\")\n\t\t\tflockContent  = gfile.GetContents(flockFilePath)\n\t\t)\n\t\tif flockContent != \"\" {\n\t\t\tif gtime.Timestamp()-gconv.Int64(flockContent) < genServiceFileLockSeconds {\n\t\t\t\t// If another \"gen service\" process is running, it just exits.\n\t\t\t\tmlog.Debug(`another \"gen service\" process is running, exit`)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tdefer gfile.RemoveFile(flockFilePath)\n\t\t_ = gfile.PutContents(flockFilePath, gtime.TimestampStr())\n\n\t\t// It works only if given WatchFile is in SrcFolder.\n\t\tvar (\n\t\t\twatchFileDir = gfile.Dir(in.WatchFile)\n\t\t\tsrcFolderDir = gfile.Dir(watchFileDir)\n\t\t)\n\t\tmlog.Debug(\"watchFileDir:\", watchFileDir)\n\t\tmlog.Debug(\"logicFolderDir:\", srcFolderDir)\n\t\tif !gstr.HasSuffix(gstr.Replace(srcFolderDir, `\\`, `/`), in.SrcFolder) {\n\t\t\tmlog.Printf(`ignore watch file \"%s\", not in source path \"%s\"`, in.WatchFile, in.SrcFolder)\n\t\t\treturn\n\t\t}\n\t\tvar newWorkingDir = gfile.Dir(gfile.Dir(srcFolderDir))\n\t\tif err = gfile.Chdir(newWorkingDir); err != nil {\n\t\t\tmlog.Fatalf(`%+v`, err)\n\t\t}\n\t\tmlog.Debug(\"Chdir:\", newWorkingDir)\n\n\t\tin.WatchFile = \"\"\n\t\tin.Packages = []string{gfile.Basename(watchFileDir)}\n\t\treturn c.Service(ctx, in)\n\t}\n\n\tif !gfile.Exists(in.SrcFolder) {\n\t\tmlog.Fatalf(`source folder path \"%s\" does not exist`, in.SrcFolder)\n\t}\n\n\tif in.ImportPrefix == \"\" {\n\t\tin.ImportPrefix = utils.GetImportPath(in.SrcFolder)\n\t}\n\n\tvar (\n\t\tisDirty                 atomic.Value                                 // Temp boolean.\n\t\tfiles                   []string                                     // Temp file array.\n\t\tinitImportSrcPackages   []string                                     // Used for generating logic.go.\n\t\tinputPackages           = in.Packages                                // Custom packages.\n\t\tdstPackageName          = gstr.ToLower(gfile.Basename(in.DstFolder)) // Package name for generated go files.\n\t\tgeneratedDstFilePathSet = gset.NewStrSet()                           // All generated file path set.\n\t)\n\tisDirty.Store(false)\n\n\t// The first level folders.\n\tsrcFolderPaths, err := gfile.ScanDir(in.SrcFolder, \"*\", false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// it will use goroutine to generate service files for each package.\n\tvar (\n\t\tfolderInfos    []folderInfo\n\t\twg             = sync.WaitGroup{}\n\t\tallStructItems = make(map[string][]string)\n\t)\n\n\tfor _, srcFolderPath := range srcFolderPaths {\n\t\tif !gfile.IsDir(srcFolderPath) {\n\t\t\tcontinue\n\t\t}\n\t\t// Only retrieve sub files, no recursively.\n\t\tif files, err = gfile.ScanDir(srcFolderPath, \"*.go\", false); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(files) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar (\n\t\t\tsrcPackageName      = gfile.Basename(srcFolderPath)\n\t\t\tsrcImportedPackages = garray.NewSortedStrArray().SetUnique(true)\n\t\t\tsrcStructFunctions  = gmap.NewListMap()\n\t\t\tdstFilePath         = gfile.Join(in.DstFolder,\n\t\t\t\tc.getDstFileNameCase(srcPackageName, in.DstFileNameCase)+\".go\",\n\t\t\t)\n\t\t)\n\n\t\tfolder := folderInfo{\n\t\t\tSrcPackageName:      srcPackageName,\n\t\t\tSrcImportedPackages: srcImportedPackages,\n\t\t\tSrcStructFunctions:  srcStructFunctions,\n\t\t\tDstFilePath:         dstFilePath,\n\t\t}\n\n\t\tfor _, file := range files {\n\t\t\tpkgItems, structItems, funcItems, err := c.parseItemsInSrc(file)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor k, v := range structItems {\n\t\t\t\tallStructItems[k] = v\n\t\t\t}\n\t\t\tfolder.FileInfos = append(folder.FileInfos, &fileInfo{\n\t\t\t\tPkgItems:  pkgItems,\n\t\t\t\tFuncItems: funcItems,\n\t\t\t})\n\t\t}\n\n\t\tfolderInfos = append(folderInfos, folder)\n\t}\n\n\tfolderInfos = c.calculateStructEmbeddedFuncInfos(folderInfos, allStructItems)\n\n\tfor _, folder := range folderInfos {\n\t\t// Parse single logic package folder.\n\t\tvar (\n\t\t\tsrcPackageName      = folder.SrcPackageName\n\t\t\tsrcImportedPackages = folder.SrcImportedPackages\n\t\t\tsrcStructFunctions  = folder.SrcStructFunctions\n\t\t\tdstFilePath         = folder.DstFilePath\n\t\t)\n\t\tgeneratedDstFilePathSet.Add(dstFilePath)\n\t\t// if it were to use goroutine,\n\t\t// it would cause the order of the generated functions in the file to be disordered.\n\t\tfor _, file := range folder.FileInfos {\n\t\t\tpkgItems, funcItems := file.PkgItems, file.FuncItems\n\n\t\t\t// Calculate imported packages for service generating.\n\t\t\terr = c.calculateImportedItems(in, pkgItems, funcItems, srcImportedPackages)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\t// Calculate functions and interfaces for service generating.\n\t\t\terr = c.calculateFuncItems(in, funcItems, srcStructFunctions)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tinitImportSrcPackages = append(\n\t\t\tinitImportSrcPackages,\n\t\t\tfmt.Sprintf(`%s/%s`, in.ImportPrefix, srcPackageName),\n\t\t)\n\t\t// Ignore source packages if input packages given.\n\t\tif len(inputPackages) > 0 && !gstr.InArray(inputPackages, srcPackageName) {\n\t\t\tmlog.Debugf(\n\t\t\t\t`ignore source package \"%s\" as it is not in desired packages: %+v`,\n\t\t\t\tsrcPackageName, inputPackages,\n\t\t\t)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Generating service go file for single logic package.\n\t\twg.Add(1)\n\t\tgo func(generateServiceFilesInput generateServiceFilesInput) {\n\t\t\tdefer wg.Done()\n\t\t\tok, err := c.generateServiceFile(generateServiceFilesInput)\n\t\t\tif err != nil {\n\t\t\t\tmlog.Printf(`error generating service file \"%s\": %v`, generateServiceFilesInput.DstFilePath, err)\n\t\t\t}\n\t\t\tif !isDirty.Load().(bool) && ok {\n\t\t\t\tisDirty.Store(true)\n\t\t\t}\n\t\t}(generateServiceFilesInput{\n\t\t\tCGenServiceInput:    in,\n\t\t\tSrcPackageName:      srcPackageName,\n\t\t\tSrcImportedPackages: srcImportedPackages.Slice(),\n\t\t\tSrcStructFunctions:  srcStructFunctions,\n\t\t\tDstPackageName:      dstPackageName,\n\t\t\tDstFilePath:         dstFilePath,\n\t\t})\n\t}\n\twg.Wait()\n\n\tif in.Clear {\n\t\tfiles, err = gfile.ScanDirFile(in.DstFolder, \"*.go\", false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvar relativeFilePath string\n\t\tfor _, file := range files {\n\t\t\trelativeFilePath = gstr.SubStrFromR(file, in.DstFolder)\n\t\t\tif !generatedDstFilePathSet.Contains(relativeFilePath) &&\n\t\t\t\tutils.IsFileDoNotEdit(relativeFilePath) {\n\n\t\t\t\tmlog.Printf(`remove no longer used service file: %s`, relativeFilePath)\n\t\t\t\tif err = gfile.RemoveFile(file); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif isDirty.Load().(bool) {\n\t\t// Generate initialization go file.\n\t\tif len(initImportSrcPackages) > 0 {\n\t\t\tif err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// Replace v1 to v2 for GoFrame.\n\t\tif err = utils.ReplaceGeneratedContentGFV2(in.DstFolder); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmlog.Printf(`gofmt go files in \"%s\"`, in.DstFolder)\n\t\tutils.GoFmt(in.DstFolder)\n\t}\n\n\t// auto update main.go.\n\tif err = c.checkAndUpdateMain(in.SrcFolder); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmlog.Print(`done!`)\n\treturn\n}\n\nfunc (c CGenService) checkAndUpdateMain(srcFolder string) (err error) {\n\tvar (\n\t\tlogicPackageName = gstr.ToLower(gfile.Basename(srcFolder))\n\t\tlogicFilePath    = gfile.Join(srcFolder, logicPackageName+\".go\")\n\t\timportPath       = utils.GetImportPath(srcFolder)\n\t\timportStr        = fmt.Sprintf(`_ \"%s\"`, importPath)\n\t\tmainFilePath     = gfile.Join(gfile.Dir(gfile.Dir(gfile.Dir(logicFilePath))), \"main.go\")\n\t\tmainFileContent  = gfile.GetContents(mainFilePath)\n\t)\n\t// No main content found.\n\tif mainFileContent == \"\" {\n\t\treturn nil\n\t}\n\tif gstr.Contains(mainFileContent, importStr) {\n\t\treturn nil\n\t}\n\tmatch, err := gregex.MatchString(`import \\(([\\s\\S]+?)\\)`, mainFileContent)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// No match.\n\tif len(match) < 2 {\n\t\treturn nil\n\t}\n\tlines := garray.NewStrArrayFrom(gstr.Split(match[1], \"\\n\"))\n\tfor i, line := range lines.Slice() {\n\t\tline = gstr.Trim(line)\n\t\tif len(line) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif line[0] == '_' {\n\t\t\tcontinue\n\t\t}\n\t\t// Insert the logic import into imports.\n\t\tif err = lines.InsertBefore(i, fmt.Sprintf(\"\\t%s\\n\\n\", importStr)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbreak\n\t}\n\tmainFileContent, err = gregex.ReplaceString(\n\t\t`import \\(([\\s\\S]+?)\\)`,\n\t\tfmt.Sprintf(`import (%s)`, lines.Join(\"\\n\")),\n\t\tmainFileContent,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmlog.Print(`update main.go`)\n\terr = gfile.PutContents(mainFilePath, mainFileContent)\n\tutils.GoFmt(mainFilePath)\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice_ast_parse.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype pkgItem struct {\n\tAlias     string `eg:\"gdbas\"`\n\tPath      string `eg:\"github.com/gogf/gf/v2/database/gdb\"`\n\tRawImport string `eg:\"gdbas github.com/gogf/gf/v2/database/gdb\"`\n}\n\ntype funcItem struct {\n\tReceiver   string              `eg:\"sUser\"`\n\tMethodName string              `eg:\"GetList\"`\n\tParams     []map[string]string `eg:\"ctx: context.Context, cond: *SearchInput\"`\n\tResults    []map[string]string `eg:\"list: []*User, err: error\"`\n\tComment    string              `eg:\"Get user list\"`\n}\n\n// parseItemsInSrc parses the pkgItem and funcItem from the specified file.\n// It can't skip the private methods.\n// It can't skip the imported packages of import alias equal to `_`.\nfunc (c CGenService) parseItemsInSrc(filePath string) (pkgItems []pkgItem, structItems map[string][]string, funcItems []funcItem, err error) {\n\tvar (\n\t\tfileContent = gfile.GetContents(filePath)\n\t\tfileSet     = token.NewFileSet()\n\t)\n\n\tnode, err := parser.ParseFile(fileSet, \"\", fileContent, parser.ParseComments)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tstructItems = make(map[string][]string)\n\tpkg := node.Name.Name\n\tpkgAliasMap := make(map[string]string)\n\tast.Inspect(node, func(n ast.Node) bool {\n\t\tswitch x := n.(type) {\n\t\tcase *ast.ImportSpec:\n\t\t\t// parse the imported packages.\n\t\t\tpkgItem := c.parseImportPackages(x)\n\t\t\tpkgItems = append(pkgItems, pkgItem)\n\t\t\tpkgPath := strings.Trim(pkgItem.Path, \"\\\"\")\n\t\t\tpkgPath = strings.ReplaceAll(pkgPath, \"\\\\\", \"/\")\n\t\t\ttmp := strings.Split(pkgPath, \"/\")\n\t\t\tsrcPkg := tmp[len(tmp)-1]\n\t\t\tif srcPkg != pkgItem.Alias {\n\t\t\t\tpkgAliasMap[pkgItem.Alias] = srcPkg\n\t\t\t}\n\t\tcase *ast.TypeSpec: // type define\n\t\t\tswitch xType := x.Type.(type) {\n\t\t\tcase *ast.StructType: // define struct\n\t\t\t\t// parse the struct declaration.\n\t\t\t\tvar structName = pkg + \".\" + x.Name.Name\n\t\t\t\tvar structEmbeddedStruct []string\n\t\t\t\tfor _, field := range xType.Fields.List {\n\t\t\t\t\tif len(field.Names) > 0 || field.Tag == nil { // not anonymous field\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\ttagValue := strings.Trim(field.Tag.Value, \"`\")\n\t\t\t\t\ttagValue = strings.TrimSpace(tagValue)\n\t\t\t\t\tif len(tagValue) == 0 { // not set tag\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttags := gstructs.ParseTag(tagValue)\n\n\t\t\t\t\tif v, ok := tags[\"gen\"]; !ok || v != \"extend\" {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tvar embeddedStruct string\n\t\t\t\t\tswitch v := field.Type.(type) {\n\t\t\t\t\tcase *ast.Ident:\n\t\t\t\t\t\tif embeddedStruct, err = c.astExprToString(v); err != nil {\n\t\t\t\t\t\t\tembeddedStruct = \"\"\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tembeddedStruct = pkg + \".\" + embeddedStruct\n\t\t\t\t\tcase *ast.StarExpr:\n\t\t\t\t\t\tif embeddedStruct, err = c.astExprToString(v.X); err != nil {\n\t\t\t\t\t\t\tembeddedStruct = \"\"\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tembeddedStruct = pkg + \".\" + embeddedStruct\n\t\t\t\t\tcase *ast.SelectorExpr:\n\t\t\t\t\t\tvar pkg string\n\t\t\t\t\t\tif pkg, err = c.astExprToString(v.X); err != nil {\n\t\t\t\t\t\t\tembeddedStruct = \"\"\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif v, ok := pkgAliasMap[pkg]; ok {\n\t\t\t\t\t\t\tpkg = v\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif embeddedStruct, err = c.astExprToString(v.Sel); err != nil {\n\t\t\t\t\t\t\tembeddedStruct = \"\"\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tembeddedStruct = pkg + \".\" + embeddedStruct\n\t\t\t\t\t}\n\n\t\t\t\t\tif embeddedStruct == \"\" {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tstructEmbeddedStruct = append(structEmbeddedStruct, embeddedStruct)\n\n\t\t\t\t}\n\t\t\t\tif len(structEmbeddedStruct) > 0 {\n\t\t\t\t\tstructItems[structName] = structEmbeddedStruct\n\t\t\t\t}\n\t\t\tcase *ast.Ident: // define ident\n\t\t\t\tvar (\n\t\t\t\t\tstructName = pkg + \".\" + x.Name.Name\n\t\t\t\t\ttypeName   = pkg + \".\" + xType.Name\n\t\t\t\t)\n\t\t\t\tstructItems[structName] = []string{typeName}\n\t\t\tcase *ast.SelectorExpr: // define selector\n\t\t\t\tvar (\n\t\t\t\t\tstructName  = pkg + \".\" + x.Name.Name\n\t\t\t\t\tselecotrPkg string\n\t\t\t\t\ttypeName    string\n\t\t\t\t)\n\t\t\t\tif selecotrPkg, err = c.astExprToString(xType.X); err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif v, ok := pkgAliasMap[selecotrPkg]; ok {\n\t\t\t\t\tselecotrPkg = v\n\t\t\t\t}\n\t\t\t\tif typeName, err = c.astExprToString(xType.Sel); err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttypeName = selecotrPkg + \".\" + typeName\n\t\t\t\tstructItems[structName] = []string{typeName}\n\t\t\t}\n\n\t\tcase *ast.FuncDecl:\n\t\t\t// parse the function items.\n\t\t\tif x.Recv == nil {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tvar funcName = x.Name.Name\n\t\t\tfuncItems = append(funcItems, funcItem{\n\t\t\t\tReceiver:   c.parseFuncReceiverTypeName(x),\n\t\t\t\tMethodName: funcName,\n\t\t\t\tParams:     c.parseFuncParams(x),\n\t\t\t\tResults:    c.parseFuncResults(x),\n\t\t\t\tComment:    c.parseFuncComment(x),\n\t\t\t})\n\t\t}\n\t\treturn true\n\t})\n\treturn\n}\n\n// parseImportPackages retrieves the imported packages from the specified ast.ImportSpec.\nfunc (c CGenService) parseImportPackages(node *ast.ImportSpec) (packages pkgItem) {\n\tif node.Path == nil {\n\t\treturn\n\t}\n\tvar (\n\t\talias     string\n\t\tpath      = node.Path.Value\n\t\trawImport string\n\t)\n\n\tif node.Name != nil {\n\t\talias = node.Name.Name\n\t\trawImport = node.Name.Name + \" \" + path\n\t} else {\n\t\trawImport = path\n\t}\n\n\t// if the alias is empty, it will further retrieve the real alias.\n\tif alias == \"\" {\n\t\talias = c.getRealAlias(path)\n\t}\n\n\treturn pkgItem{\n\t\tAlias:     alias,\n\t\tPath:      path,\n\t\tRawImport: rawImport,\n\t}\n}\n\n// getRealAlias retrieves the real alias of the package.\n// If package is \"github.com/gogf/gf\", the alias is \"gf\".\n// If package is \"github.com/gogf/gf/v2\", the alias is \"gf\" instead of \"v2\".\nfunc (c CGenService) getRealAlias(importPath string) (pkgName string) {\n\timportPath = gstr.Trim(importPath, `\"`)\n\tparts := gstr.Split(importPath, \"/\")\n\tif len(parts) == 0 {\n\t\treturn\n\t}\n\n\tpkgName = parts[len(parts)-1]\n\n\tif !gstr.HasPrefix(pkgName, \"v\") {\n\t\treturn pkgName\n\t}\n\n\tif len(parts) < 2 {\n\t\treturn pkgName\n\t}\n\n\tif gstr.IsNumeric(gstr.SubStr(pkgName, 1)) {\n\t\tpkgName = parts[len(parts)-2]\n\t}\n\n\treturn pkgName\n}\n\n// parseFuncReceiverTypeName retrieves the receiver type of the function.\n// For example:\n//\n// func(s *sArticle) -> *sArticle\n// func(s sArticle) -> sArticle\nfunc (c CGenService) parseFuncReceiverTypeName(node *ast.FuncDecl) (receiverType string) {\n\tif node.Recv == nil {\n\t\treturn \"\"\n\t}\n\treceiverType, err := c.astExprToString(node.Recv.List[0].Type)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn\n}\n\n// parseFuncParams retrieves the input parameters of the function.\n// It returns the name and type of the input parameters.\n// For example:\n//\n// []map[string]string{paramName:ctx paramType:context.Context, paramName:info paramType:struct{}}\nfunc (c CGenService) parseFuncParams(node *ast.FuncDecl) (params []map[string]string) {\n\tif node.Type.Params == nil {\n\t\treturn\n\t}\n\tfor _, param := range node.Type.Params.List {\n\t\tif param.Names == nil {\n\t\t\t// No name for the return value.\n\t\t\tresultType, err := c.astExprToString(param.Type)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tparams = append(params, map[string]string{\n\t\t\t\t\"paramName\": \"\",\n\t\t\t\t\"paramType\": resultType,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tfor _, name := range param.Names {\n\t\t\tparamType, err := c.astExprToString(param.Type)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tparams = append(params, map[string]string{\n\t\t\t\t\"paramName\": name.Name,\n\t\t\t\t\"paramType\": paramType,\n\t\t\t})\n\t\t}\n\t}\n\treturn\n}\n\n// parseFuncResults retrieves the output parameters of the function.\n// It returns the name and type of the output parameters.\n// For example:\n//\n// []map[string]string{resultName:list resultType:[]*User, resultName:err resultType:error}\n// []map[string]string{resultName: \"\", resultType: error}\nfunc (c CGenService) parseFuncResults(node *ast.FuncDecl) (results []map[string]string) {\n\tif node.Type.Results == nil {\n\t\treturn\n\t}\n\tfor _, result := range node.Type.Results.List {\n\t\tif result.Names == nil {\n\t\t\t// No name for the return value.\n\t\t\tresultType, err := c.astExprToString(result.Type)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresults = append(results, map[string]string{\n\t\t\t\t\"resultName\": \"\",\n\t\t\t\t\"resultType\": resultType,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tfor _, name := range result.Names {\n\t\t\tresultType, err := c.astExprToString(result.Type)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresults = append(results, map[string]string{\n\t\t\t\t\"resultName\": name.Name,\n\t\t\t\t\"resultType\": resultType,\n\t\t\t})\n\t\t}\n\t}\n\treturn\n}\n\n// parseFuncComment retrieves the comment of the function.\nfunc (c CGenService) parseFuncComment(node *ast.FuncDecl) string {\n\treturn c.astCommentToString(node.Doc)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice_ast_utils.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"bytes\"\n\t\"go/ast\"\n\t\"go/format\"\n\t\"go/token\"\n\t\"strings\"\n)\n\n// exprToString converts ast.Expr to string.\n// For example:\n//\n// ast.Expr -> \"context.Context\"\n// ast.Expr -> \"*v1.XxxReq\"\n// ast.Expr -> \"error\"\n// ast.Expr -> \"int\"\nfunc (c CGenService) astExprToString(expr ast.Expr) (string, error) {\n\tvar (\n\t\tbuf bytes.Buffer\n\t\terr error\n\t)\n\terr = format.Node(&buf, token.NewFileSet(), expr)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn buf.String(), nil\n}\n\n// astCommentToString returns the raw (original) text of the comment.\n// It includes the comment markers (//, /*, and */).\n// It adds a newline at the end of the comment.\nfunc (c CGenService) astCommentToString(node *ast.CommentGroup) string {\n\tif node == nil {\n\t\treturn \"\"\n\t}\n\tvar b strings.Builder\n\tfor _, c := range node.List {\n\t\tb.WriteString(c.Text + \"\\n\")\n\t}\n\treturn b.String()\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice_calculate.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nfunc (c CGenService) calculateImportedItems(\n\tin CGenServiceInput,\n\tpkgItems []pkgItem, funcItems []funcItem,\n\tsrcImportedPackages *garray.SortedStrArray,\n) (err error) {\n\t// allFuncParamType saves all the param and result types of the functions.\n\tvar allFuncParamType strings.Builder\n\n\tfor _, item := range funcItems {\n\t\tfor _, param := range item.Params {\n\t\t\tallFuncParamType.WriteString(param[\"paramType\"] + \",\")\n\t\t}\n\t\tfor _, result := range item.Results {\n\t\t\tallFuncParamType.WriteString(result[\"resultType\"] + \",\")\n\t\t}\n\t}\n\n\tfor _, item := range pkgItems {\n\t\t// Skip anonymous imports\n\t\tif item.Alias == \"_\" {\n\t\t\tmlog.Debugf(`ignore anonymous package: %s`, item.RawImport)\n\t\t\tcontinue\n\t\t}\n\t\t// Keep all imports, let gofmt clean up unused ones.\n\t\t// We cannot accurately infer package name from import path\n\t\t// (e.g., path \"minio-go\" but package name is \"minio\").\n\t\tsrcImportedPackages.Add(item.RawImport)\n\t}\n\treturn nil\n}\n\nfunc (c CGenService) calculateFuncItems(\n\tin CGenServiceInput,\n\tfuncItems []funcItem,\n\tsrcPkgInterfaceMap *gmap.ListMap,\n) (err error) {\n\tvar srcPkgInterfaceFunc []map[string]string\n\n\tfor _, item := range funcItems {\n\t\tvar (\n\t\t\t// eg: \"sArticle\"\n\t\t\treceiverName  string\n\t\t\treceiverMatch []string\n\n\t\t\t// eg: \"GetList(ctx context.Context, req *v1.ArticleListReq) (list []*v1.Article, err error)\"\n\t\t\tfuncHead string\n\t\t)\n\n\t\t// handle the receiver name.\n\t\tif item.Receiver == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\treceiverName = item.Receiver\n\t\treceiverName = gstr.Trim(receiverName, \"*\")\n\t\t// Match and pick the struct name from receiver.\n\t\tif receiverMatch, err = gregex.MatchString(in.StPattern, receiverName); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(receiverMatch) < 1 {\n\t\t\tcontinue\n\t\t}\n\t\treceiverName = gstr.CaseCamel(receiverMatch[1])\n\n\t\t// check if the func name is public.\n\t\tif !gstr.IsLetterUpper(item.MethodName[0]) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !srcPkgInterfaceMap.Contains(receiverName) {\n\t\t\tsrcPkgInterfaceFunc = make([]map[string]string, 0)\n\t\t\tsrcPkgInterfaceMap.Set(receiverName, srcPkgInterfaceFunc)\n\t\t} else {\n\t\t\tsrcPkgInterfaceFunc = srcPkgInterfaceMap.Get(receiverName).([]map[string]string)\n\t\t}\n\n\t\t// make the func head.\n\t\tparamsStr := c.tidyParam(item.Params)\n\t\tresultsStr := c.tidyResult(item.Results)\n\t\tfuncHead = fmt.Sprintf(\"%s(%s) (%s)\", item.MethodName, paramsStr, resultsStr)\n\n\t\tsrcPkgInterfaceFunc = append(srcPkgInterfaceFunc, map[string]string{\n\t\t\t\"funcHead\":    funcHead,\n\t\t\t\"funcComment\": item.Comment,\n\t\t})\n\t\tsrcPkgInterfaceMap.Set(receiverName, srcPkgInterfaceFunc)\n\t}\n\treturn nil\n}\n\n// tidyParam tidies the input parameters.\n// For example:\n//\n// []map[string]string{paramName:ctx paramType:context.Context, paramName:info paramType:struct{}}\n// -> ctx context.Context, info struct{}\nfunc (c CGenService) tidyParam(paramSlice []map[string]string) (paramStr string) {\n\tfor i, param := range paramSlice {\n\t\tif i > 0 {\n\t\t\tparamStr += \", \"\n\t\t}\n\t\tparamStr += fmt.Sprintf(\"%s %s\", param[\"paramName\"], param[\"paramType\"])\n\t}\n\treturn\n}\n\n// tidyResult tidies the output parameters.\n// For example:\n//\n// []map[string]string{resultName:list resultType:[]*User, resultName:err resultType:error}\n// -> list []*User, err error\n//\n// []map[string]string{resultName: \"\", resultType: error}\n// -> error\nfunc (c CGenService) tidyResult(resultSlice []map[string]string) (resultStr string) {\n\tfor i, result := range resultSlice {\n\t\tif i > 0 {\n\t\t\tresultStr += \", \"\n\t\t}\n\t\tif result[\"resultName\"] != \"\" {\n\t\t\tresultStr += fmt.Sprintf(\"%s %s\", result[\"resultName\"], result[\"resultType\"])\n\t\t} else {\n\t\t\tresultStr += result[\"resultType\"]\n\t\t}\n\t}\n\treturn\n}\n\nfunc (c CGenService) getStructFuncItems(structName string, allStructItems map[string][]string, funcItemsWithoutEmbed map[string][]*funcItem) (funcItems []*funcItem) {\n\tfuncItemNameSet := map[string]struct{}{}\n\n\tif items, ok := funcItemsWithoutEmbed[structName]; ok {\n\t\tfuncItems = append(funcItems, items...)\n\t\tfor _, item := range items {\n\t\t\tfuncItemNameSet[item.MethodName] = struct{}{}\n\t\t}\n\t}\n\n\tembeddedStructNames, ok := allStructItems[structName]\n\tif !ok {\n\t\treturn\n\t}\n\n\tfor _, embeddedStructName := range embeddedStructNames {\n\t\titems := c.getStructFuncItems(embeddedStructName, allStructItems, funcItemsWithoutEmbed)\n\n\t\tfor _, item := range items {\n\t\t\tif _, ok := funcItemNameSet[item.MethodName]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfuncItemNameSet[item.MethodName] = struct{}{}\n\t\t\tfuncItems = append(funcItems, item)\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (c CGenService) calculateStructEmbeddedFuncInfos(folderInfos []folderInfo, allStructItems map[string][]string) (newFolerInfos []folderInfo) {\n\tfuncItemsWithoutEmbed := make(map[string][]*funcItem)\n\tfuncItemMap := make(map[string]*([]funcItem))\n\tfuncItemsWithoutEmbedMap := make(map[string]*funcItem)\n\n\tnewFolerInfos = append(newFolerInfos, folderInfos...)\n\n\tfor _, folder := range newFolerInfos {\n\t\tfor k := range folder.FileInfos {\n\t\t\tfi := folder.FileInfos[k]\n\t\t\tfor k := range fi.FuncItems {\n\t\t\t\titem := &fi.FuncItems[k]\n\t\t\t\treceiver := folder.SrcPackageName + \".\" + strings.ReplaceAll(item.Receiver, \"*\", \"\")\n\t\t\t\tfuncItemMap[receiver] = &fi.FuncItems\n\t\t\t\tfuncItemsWithoutEmbed[receiver] = append(funcItemsWithoutEmbed[receiver], item)\n\t\t\t\tfuncItemsWithoutEmbedMap[fmt.Sprintf(\"%s:%s\", receiver, item.MethodName)] = item\n\t\t\t}\n\t\t}\n\t}\n\n\tfor receiver, structItems := range allStructItems {\n\t\treceiverName := strings.ReplaceAll(receiver, \"*\", \"\")\n\t\tfor _, structName := range structItems {\n\t\t\t// Get the list of methods for the corresponding structName.\n\t\t\tfor _, funcItem := range c.getStructFuncItems(structName, allStructItems, funcItemsWithoutEmbed) {\n\t\t\t\tif _, ok := funcItemsWithoutEmbedMap[fmt.Sprintf(\"%s:%s\", receiverName, funcItem.MethodName)]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif funcItemsPtr, ok := funcItemMap[receiverName]; ok {\n\t\t\t\t\tnewFuncItem := *funcItem\n\t\t\t\t\tnewFuncItem.Receiver = getReceiverName(receiver)\n\t\t\t\t\t(*funcItemsPtr) = append((*funcItemsPtr), newFuncItem)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc getReceiverName(receiver string) string {\n\tss := strings.Split(receiver, \".\")\n\treturn ss[len(ss)-1]\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice_generate.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\ntype generateServiceFilesInput struct {\n\tCGenServiceInput\n\tSrcPackageName      string\n\tSrcImportedPackages []string\n\tSrcStructFunctions  *gmap.ListMap\n\tDstPackageName      string\n\tDstFilePath         string // Absolute file path for generated service go file.\n}\n\nfunc (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool, err error) {\n\tvar generatedContent bytes.Buffer\n\n\tc.generatePackageImports(&generatedContent, in.DstPackageName, in.SrcImportedPackages)\n\tc.generateType(&generatedContent, in.SrcStructFunctions, in.DstPackageName)\n\tc.generateVar(&generatedContent, in.SrcStructFunctions)\n\tc.generateFunc(&generatedContent, in.SrcStructFunctions)\n\n\t// Write file content to disk.\n\tif gfile.Exists(in.DstFilePath) {\n\t\tif !utils.IsFileDoNotEdit(in.DstFilePath) {\n\t\t\tmlog.Printf(`ignore file as it is manually maintained: %s`, in.DstFilePath)\n\t\t\treturn false, nil\n\t\t}\n\t}\n\tmlog.Printf(`generating service go file: %s`, in.DstFilePath)\n\tif err = gfile.PutBytes(in.DstFilePath, generatedContent.Bytes()); err != nil {\n\t\treturn true, err\n\t}\n\treturn true, nil\n}\n\n// generateInitializationFile generates `logic.go`.\nfunc (c CGenService) generateInitializationFile(in CGenServiceInput, importSrcPackages []string) (err error) {\n\tvar (\n\t\tlogicPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder))\n\t\tlogicFilePath    = gfile.Join(in.SrcFolder, logicPackageName+\".go\")\n\t\tlogicImports     string\n\t\tgeneratedContent string\n\t)\n\tif !utils.IsFileDoNotEdit(logicFilePath) {\n\t\tmlog.Debugf(`ignore file as it is manually maintained: %s`, logicFilePath)\n\t\treturn nil\n\t}\n\tfor _, importSrcPackage := range importSrcPackages {\n\t\tlogicImports += fmt.Sprintf(`%s_ \"%s\"%s`, \"\\t\", importSrcPackage, \"\\n\")\n\t}\n\tgeneratedContent = gstr.ReplaceByMap(consts.TemplateGenServiceLogicContent, g.MapStrStr{\n\t\t\"{PackageName}\": logicPackageName,\n\t\t\"{Imports}\":     logicImports,\n\t})\n\tmlog.Printf(`generating init go file: %s`, logicFilePath)\n\tif err = gfile.PutContents(logicFilePath, generatedContent); err != nil {\n\t\treturn err\n\t}\n\tutils.GoFmt(logicFilePath)\n\treturn nil\n}\n\n// getDstFileNameCase call gstr.Case* function to convert the s to specified case.\nfunc (c CGenService) getDstFileNameCase(str, caseStr string) (newStr string) {\n\tif newStr := gstr.CaseConvert(str, gstr.CaseTypeMatch(caseStr)); newStr != str {\n\t\treturn newStr\n\t}\n\treturn gstr.CaseSnake(str)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/genservice/genservice_generate_template.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genservice\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n)\n\nfunc (c CGenService) generatePackageImports(generatedContent *bytes.Buffer, packageName string, imports []string) {\n\tgeneratedContent.WriteString(gstr.ReplaceByMap(consts.TemplateGenServiceContentHead, g.MapStrStr{\n\t\t\"{PackageName}\": packageName,\n\t\t\"{Imports}\": fmt.Sprintf(\n\t\t\t\"import (\\n%s\\n)\", gstr.Join(imports, \"\\n\"),\n\t\t),\n\t}))\n}\n\n// generateType type definitions.\n// See: const.TemplateGenServiceContentInterface\nfunc (c CGenService) generateType(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap, dstPackageName string) {\n\tgeneratedContent.WriteString(\"type(\")\n\tgeneratedContent.WriteString(\"\\n\")\n\n\tsrcStructFunctions.Iterator(func(key, value any) bool {\n\t\tvar (\n\t\t\tfuncContents = make([]string, 0)\n\t\t\tfuncContent  string\n\t\t)\n\t\tstructName, funcSlice := key.(string), value.([]map[string]string)\n\t\t// Generating interface content.\n\t\tfor _, funcInfo := range funcSlice {\n\t\t\t// Remove package name calls of `dstPackageName` in produced codes.\n\t\t\tfuncHead, _ := gregex.ReplaceString(\n\t\t\t\tfmt.Sprintf(`\\*{0,1}%s\\.`, dstPackageName),\n\t\t\t\t``, funcInfo[\"funcHead\"],\n\t\t\t)\n\t\t\tfuncContent = funcInfo[\"funcComment\"] + funcHead\n\t\t\tfuncContents = append(funcContents, funcContent)\n\t\t}\n\n\t\t// funcContents to string.\n\t\tgeneratedContent.WriteString(\n\t\t\tgstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentInterface, g.MapStrStr{\n\t\t\t\t\"{InterfaceName}\":  \"I\" + structName,\n\t\t\t\t\"{FuncDefinition}\": gstr.Join(funcContents, \"\\n\\t\"),\n\t\t\t})),\n\t\t)\n\t\tgeneratedContent.WriteString(\"\\n\")\n\t\treturn true\n\t})\n\n\tgeneratedContent.WriteString(\")\")\n\tgeneratedContent.WriteString(\"\\n\")\n}\n\n// generateVar variable definitions.\n// See: const.TemplateGenServiceContentVariable\nfunc (c CGenService) generateVar(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap) {\n\t// Generating variable and register definitions.\n\tvar variableContent string\n\n\tsrcStructFunctions.Iterator(func(key, value any) bool {\n\t\tstructName := key.(string)\n\t\tvariableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{\n\t\t\t\"{StructName}\":    structName,\n\t\t\t\"{InterfaceName}\": \"I\" + structName,\n\t\t}))\n\t\tvariableContent += \"\\n\"\n\t\treturn true\n\t})\n\tif variableContent != \"\" {\n\t\tgeneratedContent.WriteString(\"var(\")\n\t\tgeneratedContent.WriteString(\"\\n\")\n\t\tgeneratedContent.WriteString(variableContent)\n\t\tgeneratedContent.WriteString(\")\")\n\t\tgeneratedContent.WriteString(\"\\n\")\n\t}\n}\n\n// generateFunc function definitions.\n// See: const.TemplateGenServiceContentRegister\nfunc (c CGenService) generateFunc(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap) {\n\t// Variable register function definitions.\n\tsrcStructFunctions.Iterator(func(key, value any) bool {\n\t\tstructName := key.(string)\n\t\tgeneratedContent.WriteString(gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{\n\t\t\t\"{StructName}\":    structName,\n\t\t\t\"{InterfaceName}\": \"I\" + structName,\n\t\t})))\n\t\tgeneratedContent.WriteString(\"\\n\\n\")\n\t\treturn true\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/build/multiple/multiple.go",
    "content": "package main\n\nfunc main() {\n\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/build/single/main.go",
    "content": "package main\n\nfunc main() {\n\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/build/varmap/go.mod",
    "content": "module github.com/gogf/gf/cmd/gf/cmd/gf/testdata/vardump/v2\n\ngo 1.23.0\n\ntoolchain go1.24.6\n\nrequire github.com/gogf/gf/v2 v2.10.0\n\nrequire (\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../../../../../\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/build/varmap/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/build/varmap/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gbuild\"\n)\n\nfunc main() {\n\tfor k, v := range gbuild.Data() {\n\t\tfmt.Printf(\"%s: %v\\n\", k, v)\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/fix/fix25_content.go",
    "content": "package testdata\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Hook_Multi(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/multi-hook\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"show\")\n\t})\n\n\ts.BindHookHandlerByMap(\"/multi-hook\", map[string]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/multi-hook/{id}\", map[string]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/api/article/article_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v1\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v2\"\n)\n\ntype IArticleV1 interface {\n\tCreate(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)\n\tUpdate(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)\n\tGetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error)\n\tGetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error)\n}\n\ntype IArticleV2 interface {\n\tCreate(ctx context.Context, req *v2.CreateReq) (res *v2.CreateRes, err error)\n\tUpdate(ctx context.Context, req *v2.UpdateReq) (res *v2.UpdateRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/api/article/v1/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype (\n\t// CreateReq add title.\n\tCreateReq struct {\n\t\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tCreateRes struct{}\n)\n\ntype (\n\tUpdateReq struct {\n\t\tg.Meta `path:\"/article/update\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tUpdateRes struct{}\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/api/article/v1/get.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype GetListReq struct {\n\tg.Meta `path:\"/article/list\" method:\"get\" tags:\"ArticleService\"`\n}\n\ntype GetListRes struct {\n\tlist []struct{}\n}\n\ntype GetOneReq struct {\n\tg.Meta `path:\"/article/one\" method:\"get\" tags:\"ArticleService\"`\n}\n\ntype GetOneRes struct {\n\tone struct{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/api/article/v2/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v2\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype CreateReq struct {\n\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\tTitle  string `v:\"required\"`\n}\n\ntype CreateRes struct{}\n\ntype UpdateReq struct {\n\tg.Meta `path:\"/article/update\" method:\"post\" tags:\"ArticleService\"`\n\tTitle  string `v:\"required\"`\n}\n\ntype UpdateRes struct{}\n\n//type GetListReq struct {\n//\tg.Meta `path:\"/article/list\" method:\"get\" tags:\"ArticleService\"`\n//}\n//\n//type GetListRes struct {\n//\tlist []struct{}\n//}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage article\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage article\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() article.IArticleV1 {\n\treturn &ControllerV1{}\n}\n\ntype ControllerV2 struct{}\n\nfunc NewV2() article.IArticleV2 {\n\treturn &ControllerV2{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v1_create.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v1\"\n)\n\n// Create add title.\nfunc (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v1_get_list.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v1\"\n)\n\nfunc (c *ControllerV1) GetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v1_get_one.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v1\"\n)\n\nfunc (c *ControllerV1) GetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v1_update.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v1\"\n)\n\nfunc (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v2_create.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v2\"\n)\n\nfunc (c *ControllerV2) Create(ctx context.Context, req *v2.CreateReq) (res *v2.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/default/controller/article/article_v2_update.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/default/api/article/v2\"\n)\n\nfunc (c *ControllerV2) Update(ctx context.Context, req *v2.UpdateReq) (res *v2.UpdateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/dict_add_new_ctrl_expect.gotest",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1\"\n)\n\ntype IDictV1 interface {\n\tDictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error)\n\tDictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error)\n}\n\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/dict_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1\"\n)\n\ntype IDictV1 interface {\n\tDictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1/dict_type.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype DictTypeAddPageReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeAddPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/controller/dict/dict.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage dict\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/controller/dict/dict_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() dict.IDictV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/controller/dict/dict_v1_dict_type.go",
    "content": "package dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1\"\n)\n\nfunc (c *ControllerV1) DictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_ctrl/controller/dict/dict_v1_test_new.gotest",
    "content": "package dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1\"\n)\n\nfunc (c *ControllerV1) DictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV1) DictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/dict_add_new_ctrl_expect.gotest",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_ctrl/api/dict/v1\"\n)\n\ntype IDictV1 interface {\n\tDictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error)\n\tDictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error)\n}\n\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/dict_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/v1\"\n)\n\ntype IDictV1 interface {\n\tDictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/v1/dict_type.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype DictTypeAddPageReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeAddPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/controller/dict/dict.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage dict\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/controller/dict/dict_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage dict\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() dict.IDictV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/controller/dict/dict_v1_dict_type.go",
    "content": "package dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/v1\"\n)\n\nfunc (c *ControllerV1) DictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/merge/add_new_file/controller/dict/dict_v1_test_new.gotest",
    "content": "package dict\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/merge/add_new_file/api/dict/v1\"\n)\n\nfunc (c *ControllerV1) DictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/admin/article/article_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/article/v1\"\n)\n\ntype IArticleV1 interface {\n\tCreate(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/admin/article/v1/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype (\n\t// CreateReq add title.\n\tCreateReq struct {\n\t\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tCreateRes struct{}\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/admin/user/user_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/user/v1\"\n)\n\ntype IUserV1 interface {\n\tCreate(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/admin/user/v1/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype (\n\t// CreateReq add title.\n\tCreateReq struct {\n\t\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tCreateRes struct{}\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/app/user/user_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/v1\"\n)\n\ntype IUserV1 interface {\n\tCreate(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)\n\tUpdate(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext/user_ext_expect.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage user_ext\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext/v1\"\n)\n\ntype IUserExtV1 interface {\n\tCreate(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)\n\tUpdate(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext/v1/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype (\n\t// CreateReq add title.\n\tCreateReq struct {\n\t\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tCreateRes struct{}\n)\n\ntype (\n\tUpdateReq struct {\n\t\tg.Meta `path:\"/article/update\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tUpdateRes struct{}\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/api/app/user/v1/edit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype (\n\t// CreateReq add title.\n\tCreateReq struct {\n\t\tg.Meta `path:\"/article/create\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tCreateRes struct{}\n)\n\ntype (\n\tUpdateReq struct {\n\t\tg.Meta `path:\"/article/update\" method:\"post\" tags:\"ArticleService\"`\n\t\tTitle  string `v:\"required\"`\n\t}\n\n\tUpdateRes struct{}\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/article/article.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage article\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/article/article_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage article\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/article\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() article.IArticleV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/article/article_v1_create.go",
    "content": "package article\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/article/v1\"\n)\n\n// Create add title.\nfunc (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/user/user.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/user/user_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/user\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() user.IUserV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/admin/user/user_v1_create.go",
    "content": "package user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/admin/user/v1\"\n)\n\n// Create add title.\nfunc (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_ext/user_ext.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user_ext\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_ext/user_ext_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user_ext\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() user_ext.IUserExtV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_ext/user_ext_v1_create.go",
    "content": "package user_ext\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext/v1\"\n)\n\n// Create add title.\nfunc (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_ext/user_ext_v1_update.go",
    "content": "package user_ext\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/user_ext/v1\"\n)\n\nfunc (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage user\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() user.IUserV1 {\n\treturn &ControllerV1{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_v1_create.go",
    "content": "package user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/v1\"\n)\n\n// Create add title.\nfunc (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genctrl/multi/controller/app/user/user_v1_update.go",
    "content": "package user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genctrl/multi/api/app/user/v1\"\n)\n\nfunc (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/internal/table_user.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// TableUserDao is the data access object for the table table_user.\ntype TableUserDao struct {\n\ttable    string             // table is the underlying table name of the DAO.\n\tgroup    string             // group is the database configuration group name of the current DAO.\n\tcolumns  TableUserColumns   // columns contains all the column names of Table for convenient usage.\n\thandlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// TableUserColumns defines and stores column names for the table table_user.\ntype TableUserColumns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// tableUserColumns holds the columns for the table table_user.\nvar tableUserColumns = TableUserColumns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewTableUserDao creates and returns a new DAO object for table data access.\nfunc NewTableUserDao(handlers ...gdb.ModelHandler) *TableUserDao {\n\treturn &TableUserDao{\n\t\tgroup:    \"test\",\n\t\ttable:    \"table_user\",\n\t\tcolumns:  tableUserColumns,\n\t\thandlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *TableUserDao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *TableUserDao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *TableUserDao) Columns() TableUserColumns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *TableUserDao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/table_user.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"for-gendao-test/pkg/dao/internal\"\n)\n\n// tableUserDao is the data access object for the table table_user.\n// You can define custom methods on it to extend its functionality as needed.\ntype tableUserDao struct {\n\t*internal.TableUserDao\n}\n\nvar (\n\t// TableUser is a globally accessible object for table table_user operations.\n\tTableUser = tableUserDao{internal.NewTableUserDao()}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user/model/do/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure of table table_user for DAO operations like Where/Data.\ntype TableUser struct {\n\tg.Meta   `orm:\"table:table_user, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user/model/entity/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure for table table_user.\ntype TableUser struct {\n\tId       uint        `json:\"ID\"        orm:\"id\"        ` // User ID\n\tPassport string      `json:\"PASSPORT\"  orm:\"passport\"  ` // User Passport\n\tPassword string      `json:\"PASSWORD\"  orm:\"password\"  ` // User Password\n\tNickname string      `json:\"NICKNAME\"  orm:\"nickname\"  ` // User Nickname\n\tScore    float64     `json:\"SCORE\"     orm:\"score\"     ` // Total score amount.\n\tCreateAt *gtime.Time `json:\"CREATE_AT\" orm:\"create_at\" ` // Created Time\n\tUpdateAt *gtime.Time `json:\"UPDATE_AT\" orm:\"update_at\" ` // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/internal/table_user.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// TableUserDao is the data access object for the table table_user.\ntype TableUserDao struct {\n\ttable    string             // table is the underlying table name of the DAO.\n\tgroup    string             // group is the database configuration group name of the current DAO.\n\tcolumns  TableUserColumns   // columns contains all the column names of Table for convenient usage.\n\thandlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// TableUserColumns defines and stores column names for the table table_user.\ntype TableUserColumns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// tableUserColumns holds the columns for the table table_user.\nvar tableUserColumns = TableUserColumns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewTableUserDao creates and returns a new DAO object for table data access.\nfunc NewTableUserDao(handlers ...gdb.ModelHandler) *TableUserDao {\n\treturn &TableUserDao{\n\t\tgroup:    \"test\",\n\t\ttable:    \"table_user\",\n\t\tcolumns:  tableUserColumns,\n\t\thandlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *TableUserDao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *TableUserDao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *TableUserDao) Columns() TableUserColumns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *TableUserDao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/table_user.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"for-gendao-test/pkg/dao/internal\"\n)\n\n// tableUserDao is the data access object for the table table_user.\n// You can define custom methods on it to extend its functionality as needed.\ntype tableUserDao struct {\n\t*internal.TableUserDao\n}\n\nvar (\n\t// TableUser is a globally accessible object for table table_user operations.\n\tTableUser = tableUserDao{internal.NewTableUserDao()}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/do/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure of table table_user for DAO operations like Where/Data.\ntype TableUser struct {\n\tg.Meta   `orm:\"table:table_user, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/entity/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/shopspring/decimal\"\n)\n\n// TableUser is the golang structure for table table_user.\ntype TableUser struct {\n\tId       int64           `json:\"id\"       orm:\"id\"        ` // User ID\n\tPassport string          `json:\"passport\" orm:\"passport\"  ` // User Passport\n\tPassword string          `json:\"password\" orm:\"password\"  ` // User Password\n\tNickname string          `json:\"nickname\" orm:\"nickname\"  ` // User Nickname\n\tScore    decimal.Decimal `json:\"score\"    orm:\"score\"     ` // Total score amount.\n\tCreateAt *gtime.Time     `json:\"createAt\" orm:\"create_at\" ` // Created Time\n\tUpdateAt *gtime.Time     `json:\"updateAt\" orm:\"update_at\" ` // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_sqlite3/dao/internal/table_user.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// TableUserDao is the data access object for the table table_user.\ntype TableUserDao struct {\n\ttable    string             // table is the underlying table name of the DAO.\n\tgroup    string             // group is the database configuration group name of the current DAO.\n\tcolumns  TableUserColumns   // columns contains all the column names of Table for convenient usage.\n\thandlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// TableUserColumns defines and stores column names for the table table_user.\ntype TableUserColumns struct {\n\tId        string //\n\tPassport  string //\n\tPassword  string //\n\tNickname  string //\n\tCreatedAt string //\n\tUpdatedAt string //\n}\n\n// tableUserColumns holds the columns for the table table_user.\nvar tableUserColumns = TableUserColumns{\n\tId:        \"id\",\n\tPassport:  \"passport\",\n\tPassword:  \"password\",\n\tNickname:  \"nickname\",\n\tCreatedAt: \"created_at\",\n\tUpdatedAt: \"updated_at\",\n}\n\n// NewTableUserDao creates and returns a new DAO object for table data access.\nfunc NewTableUserDao(handlers ...gdb.ModelHandler) *TableUserDao {\n\treturn &TableUserDao{\n\t\tgroup:    \"test\",\n\t\ttable:    \"table_user\",\n\t\tcolumns:  tableUserColumns,\n\t\thandlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *TableUserDao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *TableUserDao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *TableUserDao) Columns() TableUserColumns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *TableUserDao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_sqlite3/dao/table_user.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"for-gendao-test/pkg/dao/internal\"\n)\n\n// tableUserDao is the data access object for the table table_user.\n// You can define custom methods on it to extend its functionality as needed.\ntype tableUserDao struct {\n\t*internal.TableUserDao\n}\n\nvar (\n\t// TableUser is a globally accessible object for table table_user operations.\n\tTableUser = tableUserDao{internal.NewTableUserDao()}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_sqlite3/model/do/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure of table table_user for DAO operations like Where/Data.\ntype TableUser struct {\n\tg.Meta    `orm:\"table:table_user, do:true\"`\n\tId        any         //\n\tPassport  any         //\n\tPassword  any         //\n\tNickname  any         //\n\tCreatedAt *gtime.Time //\n\tUpdatedAt *gtime.Time //\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_sqlite3/model/entity/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure for table table_user.\ntype TableUser struct {\n\tId        int         `json:\"id\"        orm:\"id\"         ` //\n\tPassport  string      `json:\"passport\"  orm:\"passport\"   ` //\n\tPassword  string      `json:\"password\"  orm:\"password\"   ` //\n\tNickname  string      `json:\"nickname\"  orm:\"nickname\"   ` //\n\tCreatedAt *gtime.Time `json:\"createdAt\" orm:\"created_at\" ` //\n\tUpdatedAt *gtime.Time `json:\"updatedAt\" orm:\"updated_at\" ` //\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/internal/table_user.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// TableUserDao is the data access object for the table table_user.\ntype TableUserDao struct {\n\ttable    string             // table is the underlying table name of the DAO.\n\tgroup    string             // group is the database configuration group name of the current DAO.\n\tcolumns  TableUserColumns   // columns contains all the column names of Table for convenient usage.\n\thandlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// TableUserColumns defines and stores column names for the table table_user.\ntype TableUserColumns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// tableUserColumns holds the columns for the table table_user.\nvar tableUserColumns = TableUserColumns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewTableUserDao creates and returns a new DAO object for table data access.\nfunc NewTableUserDao(handlers ...gdb.ModelHandler) *TableUserDao {\n\treturn &TableUserDao{\n\t\tgroup:    \"test\",\n\t\ttable:    \"table_user\",\n\t\tcolumns:  tableUserColumns,\n\t\thandlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *TableUserDao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *TableUserDao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *TableUserDao) Columns() TableUserColumns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *TableUserDao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/table_user.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"for-gendao-test/pkg/dao/internal\"\n)\n\n// tableUserDao is the data access object for the table table_user.\n// You can define custom methods on it to extend its functionality as needed.\ntype tableUserDao struct {\n\t*internal.TableUserDao\n}\n\nvar (\n\t// TableUser is a globally accessible object for table table_user operations.\n\tTableUser = tableUserDao{internal.NewTableUserDao()}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/do/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure of table table_user for DAO operations like Where/Data.\ntype TableUser struct {\n\tg.Meta   `orm:\"table:table_user, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/entity/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/shopspring/decimal\"\n)\n\n// TableUser is the golang structure for table table_user.\ntype TableUser struct {\n\tId       int64           `json:\"id\"       orm:\"id\"        ` // User ID\n\tPassport string          `json:\"passport\" orm:\"passport\"  ` // User Passport\n\tPassword string          `json:\"password\" orm:\"password\"  ` // User Password\n\tNickname string          `json:\"nickname\" orm:\"nickname\"  ` // User Nickname\n\tScore    decimal.Decimal `json:\"score\"    orm:\"score\"     ` // Total score amount.\n\tCreateAt *gtime.Time     `json:\"createAt\" orm:\"create_at\" ` // Created Time\n\tUpdateAt *gtime.Time     `json:\"updateAt\" orm:\"update_at\" ` // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/go.mod.txt",
    "content": "module for-gendao-test/pkg\n\ngo 1.20\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.8.1\n\tgithub.com/shopspring/decimal v1.3.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.2.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/fatih/color v1.15.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.6.0 // indirect\n\tgithub.com/go-logr/logr v1.2.4 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/gorilla/websocket v1.5.0 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.0.1 // indirect\n\tgithub.com/magiconair/properties v1.8.6 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.19 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.15 // indirect\n\tgithub.com/olekukonko/tablewriter v0.0.5 // indirect\n\tgithub.com/rivo/uniseg v0.4.4 // indirect\n\tgo.opentelemetry.io/otel v1.24.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.24.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.24.0 // indirect\n\tgolang.org/x/net v0.17.0 // indirect\n\tgolang.org/x/sys v0.13.0 // indirect\n\tgolang.org/x/text v0.13.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/sharding/sharding.sql",
    "content": "CREATE TABLE `single_table`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport`  varchar(45) NOT NULL COMMENT 'User Passport',\n    `password`  varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname`  varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score`     decimal(10, 2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n\nCREATE TABLE `users_0001`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport`  varchar(45) NOT NULL COMMENT 'User Passport',\n    `password`  varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname`  varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score`     decimal(10, 2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `users_0002`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport`  varchar(45) NOT NULL COMMENT 'User Passport',\n    `password`  varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname`  varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score`     decimal(10, 2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n\nCREATE TABLE `orders_0001`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ORDER ID',\n    `amount`    decimal(10, 2) unsigned DEFAULT NULL COMMENT 'Total amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `orders_0002`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ORDER ID',\n    `amount`    decimal(10, 2) unsigned DEFAULT NULL COMMENT 'Total amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/sharding/sharding_overlapping.sql",
    "content": "-- Test case for issue #4603: overlapping sharding patterns\n-- https://github.com/gogf/gf/issues/4603\n--\n-- Patterns: \"a_?\", \"a_b_?\", \"a_c_?\"\n-- Expected: a_1/a_2 -> \"a\", a_b_1/a_b_2 -> \"a_b\", a_c_1/a_c_2 -> \"a_c\"\n\nCREATE TABLE `a_1`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `a_2`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `a_b_1`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `a_b_2`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `a_c_1`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `a_c_2`\n(\n    `id`        int unsigned NOT NULL AUTO_INCREMENT,\n    `name`      varchar(45) NOT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/sqlite3/user.sqlite3.sql",
    "content": "create table `%s`(\n    id         INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,\n    passport   VARCHAR(45)  NOT NULL DEFAULT passport,\n    password   VARCHAR(128) NOT NULL DEFAULT password,\n    nickname   VARCHAR(45),\n    created_at TIMESTAMP,\n    updated_at TIMESTAMP\n)"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/tables_pattern.sql",
    "content": "-- Test case for issue #4629: tables pattern matching\n-- https://github.com/gogf/gf/issues/4629\n-- Standard SQL syntax compatible with MySQL and PostgreSQL\n--\n-- Tables: trade_order, trade_item, user_info, user_log, config\n\nCREATE TABLE trade_order (\n    id   INTEGER PRIMARY KEY,\n    name VARCHAR(45) NOT NULL\n);\n\nCREATE TABLE trade_item (\n    id   INTEGER PRIMARY KEY,\n    name VARCHAR(45) NOT NULL\n);\n\nCREATE TABLE user_info (\n    id   INTEGER PRIMARY KEY,\n    name VARCHAR(45) NOT NULL\n);\n\nCREATE TABLE user_log (\n    id   INTEGER PRIMARY KEY,\n    name VARCHAR(45) NOT NULL\n);\n\nCREATE TABLE config (\n    id   INTEGER PRIMARY KEY,\n    name VARCHAR(45) NOT NULL\n);\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/gendao/user.tpl.sql",
    "content": "CREATE TABLE `%s` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genpb/multiple_tags.proto",
    "content": "syntax = \"proto3\";\n\npackage genpb;\n\noption go_package = \"genpb/v1\";\n\nmessage UserReq {\n  // v:required\n  // v:#Id > 0\n  int64 Id = 1;\n  // User name for login\n  string Name = 2;\n  // v:required\n  // v:email\n  string Email = 3; // User email address\n}\n\nmessage UserResp {\n  int64 Id = 1;\n  string Name = 2;\n  string Email = 3;\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genpb/nested_message.proto",
    "content": "syntax = \"proto3\";\n\npackage genpb;\n\noption go_package = \"genpb/v1\";\n\nmessage Order {\n  // v:required\n  int64 OrderId = 1;\n  // Order details\n  OrderDetail Detail = 2;\n}\n\nmessage OrderDetail {\n  // v:required\n  string ProductName = 1;\n  // v:min:1\n  int32 Quantity = 2;\n  // v:min:0.01\n  double Price = 3;\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genpbentity/generated/table_user.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage unittest;\n\noption go_package = \"unittest\";\n\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    Id       = 1; // User ID\n    string                    Passport = 2; // User Passport\n    string                    Password = 3; // User Password\n    string                    Nickname = 4; // User Nickname\n    string                    Score    = 5; // Total score amount.\n    google.protobuf.Timestamp CreateAt = 6; // Created Time\n    google.protobuf.Timestamp UpdateAt = 7; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genpbentity/generated/table_user_snake_screaming.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage unittest;\n\noption go_package = \"unittest\";\n\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    ID        = 1; // User ID\n    string                    PASSPORT  = 2; // User Passport\n    string                    PASSWORD  = 3; // User Password\n    string                    NICKNAME  = 4; // User Nickname\n    string                    SCORE     = 5; // Total score amount.\n    google.protobuf.Timestamp CREATE_AT = 6; // Created Time\n    google.protobuf.Timestamp UPDATE_AT = 7; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genpbentity/user.tpl.sql",
    "content": "CREATE TABLE `%s` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/article/article.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage article\n\nimport (\n\t\"context\"\n\t\"go/ast\"\n\tt \"time\"\n\n\tgdbalias \"github.com/gogf/gf/v2/database/gdb\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n)\n\ntype sArticle struct {\n}\n\nfunc init() {\n\tservice.RegisterArticle(&sArticle{})\n}\n\n// Get article details\nfunc (s *sArticle) Get(ctx context.Context, id uint) (info struct{}, err error) {\n\treturn struct{}{}, err\n}\n\n// Create\n/**\n * create an article.\n * @author oldme\n */\nfunc (s *sArticle) Create(ctx context.Context, info struct{}) (id uint, err error) {\n\t// Use time package to test alias import.\n\tt.Now()\n\treturn id, err\n}\n\nfunc (s *sArticle) A1o2(ctx context.Context, str string, a, b *ast.GoStmt) error {\n\treturn nil\n}\n\nfunc (s *sArticle) B_2(ctx context.Context, db gdbalias.Raw) (err error) {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/article/article_extra.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage article\n\n// import (\n//\t\"context\"\n//\n//\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n// )\nimport (\n\t\"context\"\n\n\t/**\n\t *\n\t */\n\t_ \"github.com/gogf/gf/v2/os/gfile\"\n\n\t// This is a random comment\n\tgdbas \"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// T1 random comment\nfunc (s sArticle) T1(ctx context.Context, id, id2 uint) (gdb gdbas.Model, err error) {\n\tg := gdbas.Model{}\n\treturn g, err\n}\n\n// I'm a random comment\n\n// t2 random comment\nfunc (s *sArticle) t2(ctx context.Context) (err error) {\n\t/**\n\t\t\t * random comment\n\t* i (1). func (s *sArticle) t2(ctx context.Context) (err error) { /** 1883\n\t\t*\n\t*/\n\t_ = func(ctx2 context.Context) {}\n\treturn nil\n}\n\n// T3\n/**\n * random comment @*4213hHY1&%##%><<Y\n * @param b\n * @return c, d\n * @return err\n * @author oldme\n */\nfunc (s *sArticle) T3(ctx context.Context, b *gdbas.Model) (c, d *gdbas.Model, err error) {\n\t/* import (\n\t*\t\"context\"\n\t*\n\t*\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n\t */\n\treturn nil, nil, nil\n}\n\n/**\n * random comment\n */\n\n// func (s *sArticle) T4(i any) any\n// # $ % ^ & * ( ) _ + - = { } | [ ] \\ : \" ; ' < > ? , . /\nfunc (s *sArticle) T4(i any) any {\n\treturn nil\n}\n\n/**\n * func (s *sArticle) T4(i any) any {\n * \t\treturn nil\n * }\n */\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/base/base.go",
    "content": "package base\n\ntype Base = sBase\n\ntype sBase struct {\n\tbaseDestory `gen:\"extend\"`\n}\n\n// sBase Init\nfunc (*sBase) Init() {\n\n}\n\n// sBase Destory\nfunc (*sBase) Destory() {\n\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/base/base_destory.go",
    "content": "package base\n\ntype baseDestory struct{}\n\n// baseDestory Destory\nfunc (baseDestory) Destory() {\n\n}\n\n// baseDestory BeforeDestory\nfunc (baseDestory) BeforeDestory() {\n\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/base/sub/sub.go",
    "content": "package sub\n\ntype SubBase struct {\n}\n\n// subbase init\nfunc (*SubBase) Init() {\n\n}\n\n// subbase  GetSubBase\nfunc (*SubBase) GetSubBase() {\n\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_app.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage delivery\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n)\n\ntype sDeliveryApp struct{}\n\nfunc NewDeliveryApp() *sDeliveryApp {\n\treturn &sDeliveryApp{}\n}\n\nfunc (s *sDeliveryApp) Create(ctx context.Context) (i service.IDeliveryCluster, err error) {\n\treturn\n}\n\nfunc (s *sDeliveryApp) GetList(ctx context.Context, i service.IDeliveryCluster) (err error) {\n\tservice.Article().Get(ctx, 1)\n\treturn\n}\n\nfunc (s *sDeliveryApp) GetOne(ctx context.Context) (err error) {\n\treturn\n}\n\nfunc (s *sDeliveryApp) Delete(ctx context.Context) (err error) {\n\treturn\n}\n\nfunc (s *sDeliveryApp) AA(ctx context.Context) (err error) { return }\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_cluster.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage delivery\n\nimport (\n\t\"context\"\n\n\tgdbas \"github.com/gogf/gf/v2/database/gdb\"\n)\n\ntype sDeliveryCluster struct{}\n\nfunc NewDeliveryCluster() *sDeliveryCluster {\n\treturn &sDeliveryCluster{}\n}\n\n// Create 自动创建Cluster及Project.\nfunc (s *sDeliveryCluster) Create(ctx context.Context) (err error, gdb gdbas.Model) {\n\treturn\n}\n\nfunc (s *sDeliveryCluster) Delete(ctx context.Context) (err error) {\n\treturn\n}\n\nfunc (s *sDeliveryCluster) GetList(ctx context.Context) (err error) {\n\treturn\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/logic_expect.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage logic\n\nimport (\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/article\"\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/base\"\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/delivery\"\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/user\"\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/user/supper_vip_user.go",
    "content": "package user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n)\n\nfunc init() {\n\tservice.RegisterSuperVipUser(&sSuperVipUser{\n\t\tsVipUser: &sVipUser{},\n\t})\n}\n\ntype sSuperVipUser struct {\n\t*sVipUser `gen:\"extend\"`\n}\n\n// Get supper vip user level\nfunc (s sSuperVipUser) GetVipLevel(ctx context.Context) (vipLevel int, err error) {\n\treturn 1, nil\n}\n\n// Set supper vip user level\nfunc (s *sSuperVipUser) SetVipLevel(ctx context.Context, id int, vipLevel int) (err error) {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/user/user.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage user\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/base\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n)\n\nfunc init() {\n\tservice.RegisterUser(New())\n}\n\ntype sUser struct {\n\tbase.Base\n}\n\nfunc New() *sUser {\n\treturn &sUser{}\n}\n\n// Create creates a new user.\nfunc (s *sUser) Create(ctx context.Context, name string) (id int, err error) {\n\treturn 0, nil\n}\n\n// GetOne retrieves user by id.\nfunc (s *sUser) GetOne(ctx context.Context, id int) (name string, err error) {\n\treturn \"\", nil\n}\n\n// GetList retrieves user list.\nfunc (s *sUser) GetList(ctx context.Context) (names []string, err error) {\n\treturn nil, nil\n}\n\n// Update updates user by id.\nfunc (s *sUser) Update(ctx context.Context, id int) (name string, err error) {\n\treturn \"\", nil\n}\n\n// Delete deletes user by id.\nfunc (s *sUser) Delete(ctx context.Context, id int) (err error) {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/logic/user/vip_user.go",
    "content": "package user\n\nimport (\n\t\"context\"\n\n\tbbb \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/base\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service\"\n)\n\nfunc init() {\n\tservice.RegisterVipUser(&sVipUser{})\n}\n\ntype mybase = bbb.Base\n\ntype sVipUser struct {\n\tsUser  `gen:\"extend\"`\n\tmybase `gen:\"extend\"`\n}\n\n// Create creates a new vip user.\nfunc (s *sVipUser) Create(ctx context.Context, name string, vipLevel int) (id int, err error) {\n\treturn 0, nil\n}\n\n// Get vip user level\nfunc (s *sVipUser) GetVipLevel() (vipLevel int, err error) {\n\treturn 1, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/service/article.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n\t\"go/ast\"\n\n\tgdbalias \"github.com/gogf/gf/v2/database/gdb\"\n\tgdbas \"github.com/gogf/gf/v2/database/gdb\"\n)\n\ntype (\n\tIArticle interface {\n\t\t// Get article details\n\t\tGet(ctx context.Context, id uint) (info struct{}, err error)\n\t\t// Create\n\t\t/**\n\t\t * create an article.\n\t\t * @author oldme\n\t\t */\n\t\tCreate(ctx context.Context, info struct{}) (id uint, err error)\n\t\tA1o2(ctx context.Context, str string, a *ast.GoStmt, b *ast.GoStmt) error\n\t\tB_2(ctx context.Context, db gdbalias.Raw) (err error)\n\t\t// T1 random comment\n\t\tT1(ctx context.Context, id uint, id2 uint) (gdb gdbas.Model, err error)\n\t\t// T3\n\t\t/**\n\t\t * random comment @*4213hHY1&%##%><<Y\n\t\t * @param b\n\t\t * @return c, d\n\t\t * @return err\n\t\t * @author oldme\n\t\t */\n\t\tT3(ctx context.Context, b *gdbas.Model) (c *gdbas.Model, d *gdbas.Model, err error)\n\t\t// func (s *sArticle) T4(i any) any\n\t\t// # $ % ^ & * ( ) _ + - = { } | [ ] \\ : \" ; ' < > ? , . /\n\t\tT4(i any) any\n\t}\n)\n\nvar (\n\tlocalArticle IArticle\n)\n\nfunc Article() IArticle {\n\tif localArticle == nil {\n\t\tpanic(\"implement not found for interface IArticle, forgot register?\")\n\t}\n\treturn localArticle\n}\n\nfunc RegisterArticle(i IArticle) {\n\tlocalArticle = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/service/base.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\ntype (\n\tIBase interface {\n\t\t// sBase Init\n\t\tInit()\n\t\t// sBase Destory\n\t\tDestory()\n\t\t// baseDestory BeforeDestory\n\t\tBeforeDestory()\n\t}\n)\n\nvar (\n\tlocalBase IBase\n)\n\nfunc Base() IBase {\n\tif localBase == nil {\n\t\tpanic(\"implement not found for interface IBase, forgot register?\")\n\t}\n\treturn localBase\n}\n\nfunc RegisterBase(i IBase) {\n\tlocalBase = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/service/delivery.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n\n\tgdbas \"github.com/gogf/gf/v2/database/gdb\"\n)\n\ntype (\n\tIDeliveryApp interface {\n\t\tCreate(ctx context.Context) (i IDeliveryCluster, err error)\n\t\tGetList(ctx context.Context, i IDeliveryCluster) (err error)\n\t\tGetOne(ctx context.Context) (err error)\n\t\tDelete(ctx context.Context) (err error)\n\t\tAA(ctx context.Context) (err error)\n\t}\n\tIDeliveryCluster interface {\n\t\t// Create 自动创建Cluster及Project.\n\t\tCreate(ctx context.Context) (err error, gdb gdbas.Model)\n\t\tDelete(ctx context.Context) (err error)\n\t\tGetList(ctx context.Context) (err error)\n\t}\n)\n\nvar (\n\tlocalDeliveryApp     IDeliveryApp\n\tlocalDeliveryCluster IDeliveryCluster\n)\n\nfunc DeliveryApp() IDeliveryApp {\n\tif localDeliveryApp == nil {\n\t\tpanic(\"implement not found for interface IDeliveryApp, forgot register?\")\n\t}\n\treturn localDeliveryApp\n}\n\nfunc RegisterDeliveryApp(i IDeliveryApp) {\n\tlocalDeliveryApp = i\n}\n\nfunc DeliveryCluster() IDeliveryCluster {\n\tif localDeliveryCluster == nil {\n\t\tpanic(\"implement not found for interface IDeliveryCluster, forgot register?\")\n\t}\n\treturn localDeliveryCluster\n}\n\nfunc RegisterDeliveryCluster(i IDeliveryCluster) {\n\tlocalDeliveryCluster = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/genservice/service/user.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n)\n\ntype (\n\tISuperVipUser interface {\n\t\t// Get supper vip user level\n\t\tGetVipLevel(ctx context.Context) (vipLevel int, err error)\n\t\t// Set supper vip user level\n\t\tSetVipLevel(ctx context.Context, id int, vipLevel int) (err error)\n\t\t// Create creates a new vip user.\n\t\tCreate(ctx context.Context, name string, vipLevel int) (id int, err error)\n\t\t// GetOne retrieves user by id.\n\t\tGetOne(ctx context.Context, id int) (name string, err error)\n\t\t// GetList retrieves user list.\n\t\tGetList(ctx context.Context) (names []string, err error)\n\t\t// Update updates user by id.\n\t\tUpdate(ctx context.Context, id int) (name string, err error)\n\t\t// Delete deletes user by id.\n\t\tDelete(ctx context.Context, id int) (err error)\n\t\t// sBase Init\n\t\tInit()\n\t\t// sBase Destory\n\t\tDestory()\n\t\t// baseDestory BeforeDestory\n\t\tBeforeDestory()\n\t}\n\tIUser interface {\n\t\t// Create creates a new user.\n\t\tCreate(ctx context.Context, name string) (id int, err error)\n\t\t// GetOne retrieves user by id.\n\t\tGetOne(ctx context.Context, id int) (name string, err error)\n\t\t// GetList retrieves user list.\n\t\tGetList(ctx context.Context) (names []string, err error)\n\t\t// Update updates user by id.\n\t\tUpdate(ctx context.Context, id int) (name string, err error)\n\t\t// Delete deletes user by id.\n\t\tDelete(ctx context.Context, id int) (err error)\n\t}\n\tIVipUser interface {\n\t\t// Create creates a new vip user.\n\t\tCreate(ctx context.Context, name string, vipLevel int) (id int, err error)\n\t\t// Get vip user level\n\t\tGetVipLevel() (vipLevel int, err error)\n\t\t// GetOne retrieves user by id.\n\t\tGetOne(ctx context.Context, id int) (name string, err error)\n\t\t// GetList retrieves user list.\n\t\tGetList(ctx context.Context) (names []string, err error)\n\t\t// Update updates user by id.\n\t\tUpdate(ctx context.Context, id int) (name string, err error)\n\t\t// Delete deletes user by id.\n\t\tDelete(ctx context.Context, id int) (err error)\n\t\t// sBase Init\n\t\tInit()\n\t\t// sBase Destory\n\t\tDestory()\n\t\t// baseDestory BeforeDestory\n\t\tBeforeDestory()\n\t}\n)\n\nvar (\n\tlocalSuperVipUser ISuperVipUser\n\tlocalUser         IUser\n\tlocalVipUser      IVipUser\n)\n\nfunc SuperVipUser() ISuperVipUser {\n\tif localSuperVipUser == nil {\n\t\tpanic(\"implement not found for interface ISuperVipUser, forgot register?\")\n\t}\n\treturn localSuperVipUser\n}\n\nfunc RegisterSuperVipUser(i ISuperVipUser) {\n\tlocalSuperVipUser = i\n}\n\nfunc User() IUser {\n\tif localUser == nil {\n\t\tpanic(\"implement not found for interface IUser, forgot register?\")\n\t}\n\treturn localUser\n}\n\nfunc RegisterUser(i IUser) {\n\tlocalUser = i\n}\n\nfunc VipUser() IVipUser {\n\tif localVipUser == nil {\n\t\tpanic(\"implement not found for interface IVipUser, forgot register?\")\n\t}\n\treturn localVipUser\n}\n\nfunc RegisterVipUser(i IVipUser) {\n\tlocalVipUser = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/config.yaml",
    "content": "gfcli:\n  gen:\n    dao:\n      - link: \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n        tables: \"user1\"\n        descriptionTag: true\n        noModelComment: true\n        group: \"sys\"\n        clear: true\n        overwriteDao: true\n      - link: \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n        tables: \"user2\"\n        descriptionTag: true\n        noModelComment: true\n        group: \"book\"\n        clear: true\n        overwriteDao: true\n\n\n\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/dao/internal/user_3.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User3Dao is the data access object for the table user3.\ntype User3Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User3Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User3Columns defines and stores column names for the table user3.\ntype User3Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user3Columns holds the columns for the table user3.\nvar user3Columns = User3Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser3Dao creates and returns a new DAO object for table data access.\nfunc NewUser3Dao() *User3Dao {\n\treturn &User3Dao{\n\t\tgroup:   \"sys\",\n\t\ttable:   \"user3\",\n\t\tcolumns: user3Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User3Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User3Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User3Dao) Columns() User3Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User3Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User3Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User3Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/dao/internal/user_4.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User4Dao is the data access object for the table user4.\ntype User4Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User4Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User4Columns defines and stores column names for the table user4.\ntype User4Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user4Columns holds the columns for the table user4.\nvar user4Columns = User4Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser4Dao creates and returns a new DAO object for table data access.\nfunc NewUser4Dao() *User4Dao {\n\treturn &User4Dao{\n\t\tgroup:   \"book\",\n\t\ttable:   \"user4\",\n\t\tcolumns: user4Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User4Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User4Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User4Dao) Columns() User4Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User4Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User4Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User4Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/dao/user_3.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser3Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser3Dao = *internal.User3Dao\n\n// user3Dao is the data access object for the table user3.\n// You can define custom methods on it to extend its functionality as needed.\ntype user3Dao struct {\n\tinternalUser3Dao\n}\n\nvar (\n\t// User3 is a globally accessible object for table user3 operations.\n\tUser3 = user3Dao{\n\t\tinternal.NewUser3Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/dao/user_4.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser4Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser4Dao = *internal.User4Dao\n\n// user4Dao is the data access object for the table user4.\n// You can define custom methods on it to extend its functionality as needed.\ntype user4Dao struct {\n\tinternalUser4Dao\n}\n\nvar (\n\t// User4 is a globally accessible object for table user4 operations.\n\tUser4 = user4Dao{\n\t\tinternal.NewUser4Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/model/do/user_3.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User1 is the golang structure of table user1 for DAO operations like Where/Data.\ntype User1 struct {\n\tg.Meta   `orm:\"table:user1, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/model/do/user_4.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User2 is the golang structure of table user2 for DAO operations like Where/Data.\ntype User2 struct {\n\tg.Meta   `orm:\"table:user2, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/model/entity/user_3.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User1 is the golang structure for table user1.\ntype User1 struct {\n\tId       uint        `json:\"ID\"        description:\"User ID\"`\n\tPassport string      `json:\"PASSPORT\"  description:\"User Passport\"`\n\tPassword string      `json:\"PASSWORD\"  description:\"User Password\"`\n\tNickname string      `json:\"NICKNAME\"  description:\"User Nickname\"`\n\tScore    float64     `json:\"SCORE\"     description:\"Total score amount.\"`\n\tCreateAt *gtime.Time `json:\"CREATE_AT\" description:\"Created Time\"`\n\tUpdateAt *gtime.Time `json:\"UPDATE_AT\" description:\"Updated Time\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/model/entity/user_4.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User2 is the golang structure for table user2.\ntype User2 struct {\n\tId       uint        `json:\"ID\"        description:\"User ID\"`\n\tPassport string      `json:\"PASSPORT\"  description:\"User Passport\"`\n\tPassword string      `json:\"PASSWORD\"  description:\"User Password\"`\n\tNickname string      `json:\"NICKNAME\"  description:\"User Nickname\"`\n\tScore    float64     `json:\"SCORE\"     description:\"Total score amount.\"`\n\tCreateAt *gtime.Time `json:\"CREATE_AT\" description:\"Created Time\"`\n\tUpdateAt *gtime.Time `json:\"UPDATE_AT\" description:\"Updated Time\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/sql1.sql",
    "content": "CREATE TABLE `user1` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2572/sql2.sql",
    "content": "CREATE TABLE `user2` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/config.yaml",
    "content": "gfcli:\n  gen:\n    dao:\n      - link: \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n        tables: \"user1\"\n        descriptionTag: true\n        noModelComment: true\n        group: \"sys\"\n        clear: true\n        overwriteDao: false\n      - link: \"mysql:root:12345678@tcp(127.0.0.1:3306)/test\"\n        tables: \"user2\"\n        descriptionTag: true\n        noModelComment: true\n        group: \"book\"\n        clear: true\n        overwriteDao: true\n\n\n\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/internal/user_1.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User1Dao is the data access object for the table user1.\ntype User1Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User1Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User1Columns defines and stores column names for the table user1.\ntype User1Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user1Columns holds the columns for the table user1.\nvar user1Columns = User1Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser1Dao creates and returns a new DAO object for table data access.\nfunc NewUser1Dao() *User1Dao {\n\treturn &User1Dao{\n\t\tgroup:   \"sys\",\n\t\ttable:   \"user1\",\n\t\tcolumns: user1Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User1Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User1Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User1Dao) Columns() User1Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User1Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User1Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User1Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/internal/user_2.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User2Dao is the data access object for the table user2.\ntype User2Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User2Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User2Columns defines and stores column names for the table user2.\ntype User2Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user2Columns holds the columns for the table user2.\nvar user2Columns = User2Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser2Dao creates and returns a new DAO object for table data access.\nfunc NewUser2Dao() *User2Dao {\n\treturn &User2Dao{\n\t\tgroup:   \"sys\",\n\t\ttable:   \"user2\",\n\t\tcolumns: user2Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User2Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User2Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User2Dao) Columns() User2Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User2Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User2Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User2Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/internal/user_3.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User3Dao is the data access object for the table user3.\ntype User3Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User3Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User3Columns defines and stores column names for the table user3.\ntype User3Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user3Columns holds the columns for the table user3.\nvar user3Columns = User3Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser3Dao creates and returns a new DAO object for table data access.\nfunc NewUser3Dao() *User3Dao {\n\treturn &User3Dao{\n\t\tgroup:   \"sys\",\n\t\ttable:   \"user3\",\n\t\tcolumns: user3Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User3Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User3Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User3Dao) Columns() User3Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User3Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User3Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User3Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/internal/user_4.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// User4Dao is the data access object for the table user4.\ntype User4Dao struct {\n\ttable   string       // table is the underlying table name of the DAO.\n\tgroup   string       // group is the database configuration group name of the current DAO.\n\tcolumns User4Columns // columns contains all the column names of Table for convenient usage.\n}\n\n// User4Columns defines and stores column names for the table user4.\ntype User4Columns struct {\n\tId       string // User ID\n\tPassport string // User Passport\n\tPassword string // User Password\n\tNickname string // User Nickname\n\tScore    string // Total score amount.\n\tCreateAt string // Created Time\n\tUpdateAt string // Updated Time\n}\n\n// user4Columns holds the columns for the table user4.\nvar user4Columns = User4Columns{\n\tId:       \"id\",\n\tPassport: \"passport\",\n\tPassword: \"password\",\n\tNickname: \"nickname\",\n\tScore:    \"score\",\n\tCreateAt: \"create_at\",\n\tUpdateAt: \"update_at\",\n}\n\n// NewUser4Dao creates and returns a new DAO object for table data access.\nfunc NewUser4Dao() *User4Dao {\n\treturn &User4Dao{\n\t\tgroup:   \"book\",\n\t\ttable:   \"user4\",\n\t\tcolumns: user4Columns,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *User4Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *User4Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *User4Dao) Columns() User4Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *User4Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *User4Dao) Ctx(ctx context.Context) *gdb.Model {\n\treturn dao.DB().Model(dao.table).Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *User4Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/user_1.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\n// I am not overwritten.\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser1Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser1Dao = *internal.User1Dao\n\n// user1Dao is the data access object for the table user1.\n// You can define custom methods on it to extend its functionality as needed.\ntype user1Dao struct {\n\tinternalUser1Dao\n}\n\nvar (\n\t// User1 is a globally accessible object for table user1 operations.\n\tUser1 = user1Dao{\n\t\tinternal.NewUser1Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/user_2.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\n// I am not overwritten.\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser2Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser2Dao = *internal.User2Dao\n\n// user2Dao is the data access object for the table user2.\n// You can define custom methods on it to extend its functionality as needed.\ntype user2Dao struct {\n\tinternalUser2Dao\n}\n\nvar (\n\t// User2 is a globally accessible object for table user2 operations.\n\tUser2 = user2Dao{\n\t\tinternal.NewUser2Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/user_3.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser3Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser3Dao = *internal.User3Dao\n\n// user3Dao is the data access object for the table user3.\n// You can define custom methods on it to extend its functionality as needed.\ntype user3Dao struct {\n\tinternalUser3Dao\n}\n\nvar (\n\t// User3 is a globally accessible object for table user3 operations.\n\tUser3 = user3Dao{\n\t\tinternal.NewUser3Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/dao/user_4.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"/internal\"\n)\n\n// internalUser4Dao is an internal type for wrapping the internal DAO implementation.\ntype internalUser4Dao = *internal.User4Dao\n\n// user4Dao is the data access object for the table user4.\n// You can define custom methods on it to extend its functionality as needed.\ntype user4Dao struct {\n\tinternalUser4Dao\n}\n\nvar (\n\t// User4 is a globally accessible object for table user4 operations.\n\tUser4 = user4Dao{\n\t\tinternal.NewUser4Dao(),\n\t}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/model/do/user_3.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User1 is the golang structure of table user1 for DAO operations like Where/Data.\ntype User1 struct {\n\tg.Meta   `orm:\"table:user1, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/model/do/user_4.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User2 is the golang structure of table user2 for DAO operations like Where/Data.\ntype User2 struct {\n\tg.Meta   `orm:\"table:user2, do:true\"`\n\tId       any         // User ID\n\tPassport any         // User Passport\n\tPassword any         // User Password\n\tNickname any         // User Nickname\n\tScore    any         // Total score amount.\n\tCreateAt *gtime.Time // Created Time\n\tUpdateAt *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/model/entity/user_3.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User1 is the golang structure for table user1.\ntype User1 struct {\n\tId       uint        `json:\"ID\"        description:\"User ID\"`\n\tPassport string      `json:\"PASSPORT\"  description:\"User Passport\"`\n\tPassword string      `json:\"PASSWORD\"  description:\"User Password\"`\n\tNickname string      `json:\"NICKNAME\"  description:\"User Nickname\"`\n\tScore    float64     `json:\"SCORE\"     description:\"Total score amount.\"`\n\tCreateAt *gtime.Time `json:\"CREATE_AT\" description:\"Created Time\"`\n\tUpdateAt *gtime.Time `json:\"UPDATE_AT\" description:\"Updated Time\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/model/entity/user_4.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// User2 is the golang structure for table user2.\ntype User2 struct {\n\tId       uint        `json:\"ID\"        description:\"User ID\"`\n\tPassport string      `json:\"PASSPORT\"  description:\"User Passport\"`\n\tPassword string      `json:\"PASSWORD\"  description:\"User Password\"`\n\tNickname string      `json:\"NICKNAME\"  description:\"User Nickname\"`\n\tScore    float64     `json:\"SCORE\"     description:\"Total score amount.\"`\n\tCreateAt *gtime.Time `json:\"CREATE_AT\" description:\"Created Time\"`\n\tUpdateAt *gtime.Time `json:\"UPDATE_AT\" description:\"Updated Time\"`\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/sql1.sql",
    "content": "CREATE TABLE `user1` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2616/sql2.sql",
    "content": "CREATE TABLE `user2` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n    `password` varchar(45) NOT NULL COMMENT 'User Password',\n    `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n    `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2746/issue_2746.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\n// Issue2746 is the golang structure for table issue2746.\ntype Issue2746 struct {\n\tId       uint        `json:\"ID\"       orm:\"id\"       ` // User ID\n\tNickname string      `json:\"NICKNAME\" orm:\"nickname\" ` // User Nickname\n\tTag      *gjson.Json `json:\"TAG\"      orm:\"tag\"      ` //\n\tInfo     string      `json:\"INFO\"     orm:\"info\"     ` //\n\tTag2     *gjson.Json `json:\"TAG_2\"    orm:\"tag2\"     ` // Tag2\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/2746/sql.sql",
    "content": "CREATE TABLE %s (\n     `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n     `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n     `tag`  json NOT NULL,\n     `info` longtext DEFAULT NULL,\n     `tag2` json COMMENT 'Tag2',\n     PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3328/logic/.gitkeep",
    "content": ""
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3459/config.yaml",
    "content": "gfcli:\n  gen:\n    dao:\n      - link: \"pgsql:postgres:postgres@tcp(127.0.0.1:5432)/postgres\"\n        tablesEx: \"ex_table1,ex_table2\""
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/api/hello/hello.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage hello\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3460/api/hello/v1\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3460/api/hello/v2\"\n)\n\ntype IHelloV1 interface {\n\tDictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error)\n\tDictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error)\n\tDictTypeEditPage(ctx context.Context, req *v1.DictTypeEditPageReq) (res *v1.DictTypeEditPageRes, err error)\n\tDictTypeEdit(ctx context.Context, req *v1.DictTypeEditReq) (res *v1.DictTypeEditRes, err error)\n}\n\ntype IHelloV2 interface {\n\tDictTypeAddPage(ctx context.Context, req *v2.DictTypeAddPageReq) (res *v2.DictTypeAddPageRes, err error)\n\tDictTypeAdd(ctx context.Context, req *v2.DictTypeAddReq) (res *v2.DictTypeAddRes, err error)\n\tDictTypeEditPage(ctx context.Context, req *v2.DictTypeEditPageReq) (res *v2.DictTypeEditPageRes, err error)\n\tDictTypeEdit(ctx context.Context, req *v2.DictTypeEditReq) (res *v2.DictTypeEditRes, err error)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/api/hello/v1/req.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v1\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype DictTypeAddPageReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeAddPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n\ntype DictTypeAddReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"post\" summary:\"添加字典类型\"`\n}\ntype DictTypeAddRes struct {\n}\n\ntype DictTypeEditPageReq struct {\n\tg.Meta `path:\"/dict/type/edit\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeEditPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n\ntype DictTypeEditReq struct {\n\tg.Meta `path:\"/dict/type/edit\" tags:\"字典管理\" method:\"put\" summary:\"修改字典类型\"`\n}\ntype DictTypeEditRes struct {\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/api/hello/v2/req.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage v2\n\nimport \"github.com/gogf/gf/v2/frame/g\"\n\ntype DictTypeAddPageReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeAddPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n\ntype DictTypeAddReq struct {\n\tg.Meta `path:\"/dict/type/add\" tags:\"字典管理\" method:\"post\" summary:\"添加字典类型\"`\n}\ntype DictTypeAddRes struct {\n}\n\ntype DictTypeEditPageReq struct {\n\tg.Meta `path:\"/dict/type/edit\" tags:\"字典管理\" method:\"get\" summary:\"字典类型添加页面\"`\n}\n\ntype DictTypeEditPageRes struct {\n\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n}\n\ntype DictTypeEditReq struct {\n\tg.Meta `path:\"/dict/type/edit\" tags:\"字典管理\" method:\"put\" summary:\"修改字典类型\"`\n}\ntype DictTypeEditRes struct {\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/controller/hello/hello.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage hello\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/controller/hello/hello_new.go",
    "content": "// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage hello\n\nimport (\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3460/api/hello\"\n)\n\ntype ControllerV1 struct{}\n\nfunc NewV1() hello.IHelloV1 {\n\treturn &ControllerV1{}\n}\n\ntype ControllerV2 struct{}\n\nfunc NewV2() hello.IHelloV2 {\n\treturn &ControllerV2{}\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/controller/hello/hello_v1_req.go",
    "content": "package hello\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3460/api/hello/v1\"\n)\n\nfunc (c *ControllerV1) DictTypeAddPage(ctx context.Context, req *v1.DictTypeAddPageReq) (res *v1.DictTypeAddPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV1) DictTypeAdd(ctx context.Context, req *v1.DictTypeAddReq) (res *v1.DictTypeAddRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV1) DictTypeEditPage(ctx context.Context, req *v1.DictTypeEditPageReq) (res *v1.DictTypeEditPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV1) DictTypeEdit(ctx context.Context, req *v1.DictTypeEditReq) (res *v1.DictTypeEditRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3460/controller/hello/hello_v2_req.go",
    "content": "package hello\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3460/api/hello/v2\"\n)\n\nfunc (c *ControllerV2) DictTypeAddPage(ctx context.Context, req *v2.DictTypeAddPageReq) (res *v2.DictTypeAddPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV2) DictTypeAdd(ctx context.Context, req *v2.DictTypeAddReq) (res *v2.DictTypeAddRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV2) DictTypeEditPage(ctx context.Context, req *v2.DictTypeEditPageReq) (res *v2.DictTypeEditPageRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\nfunc (c *ControllerV2) DictTypeEdit(ctx context.Context, req *v2.DictTypeEditReq) (res *v2.DictTypeEditRes, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3545/table_user.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage pbentity;\n\noption go_package = \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/api/pbentity\";\n\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    Id       = 1; // User ID\n    string                    Passport = 2; // User Passport\n    string                    Password = 3; // User Password\n    string                    Nickname = 4; // User Nickname\n    string                    Score    = 5; // Total score amount.\n    google.protobuf.Timestamp CreateAt = 6; // Created Time\n    google.protobuf.Timestamp UpdateAt = 7; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3685/table_user.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage pbentity;\n\noption go_package = \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/api/pbentity\";\n\nimport \"google/protobuf/struct.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    Id       = 1; // User ID\n    string                    Passport = 2; // User Passport\n    string                    Password = 3; // User Password\n    string                    Nickname = 4; // User Nickname\n    string                    Score    = 5; // Total score amount.\n    google.protobuf.Value     Data     = 6; // User Data\n    google.protobuf.Timestamp CreateAt = 7; // Created Time\n    google.protobuf.Timestamp UpdateAt = 8; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3685/user.tpl.sql",
    "content": "CREATE TABLE `%s` (\n  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n  `passport` varchar(45) NOT NULL COMMENT 'User Passport',\n  `password` varchar(45) NOT NULL COMMENT 'User Password',\n  `nickname` varchar(45) NOT NULL COMMENT 'User Nickname',\n  `score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',\n  `data` json DEFAULT NULL COMMENT 'User Data',\n  `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n  `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3749/dao/internal/table_user.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// TableUserDao is the data access object for the table table_user.\ntype TableUserDao struct {\n\ttable    string             // table is the underlying table name of the DAO.\n\tgroup    string             // group is the database configuration group name of the current DAO.\n\tcolumns  TableUserColumns   // columns contains all the column names of Table for convenient usage.\n\thandlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// TableUserColumns defines and stores column names for the table table_user.\ntype TableUserColumns struct {\n\tId        string // User ID\n\tParentId  string //\n\tPassport  string // User Passport\n\tPassWord  string // User Password\n\tNickname2 string // User Nickname\n\tCreateAt  string // Created Time\n\tUpdateAt  string // Updated Time\n}\n\n// tableUserColumns holds the columns for the table table_user.\nvar tableUserColumns = TableUserColumns{\n\tId:        \"Id\",\n\tParentId:  \"parentId\",\n\tPassport:  \"PASSPORT\",\n\tPassWord:  \"PASS_WORD\",\n\tNickname2: \"NICKNAME2\",\n\tCreateAt:  \"create_at\",\n\tUpdateAt:  \"update_at\",\n}\n\n// NewTableUserDao creates and returns a new DAO object for table data access.\nfunc NewTableUserDao(handlers ...gdb.ModelHandler) *TableUserDao {\n\treturn &TableUserDao{\n\t\tgroup:    \"test\",\n\t\ttable:    \"table_user\",\n\t\tcolumns:  tableUserColumns,\n\t\thandlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *TableUserDao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *TableUserDao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *TableUserDao) Columns() TableUserColumns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *TableUserDao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3749/dao/table_user.go",
    "content": "// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage dao\n\nimport (\n\t\"for-gendao-test/pkg/dao/internal\"\n)\n\n// tableUserDao is the data access object for the table table_user.\n// You can define custom methods on it to extend its functionality as needed.\ntype tableUserDao struct {\n\t*internal.TableUserDao\n}\n\nvar (\n\t// TableUser is a globally accessible object for table table_user operations.\n\tTableUser = tableUserDao{internal.NewTableUserDao()}\n)\n\n// Add your custom methods and functionality below.\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3749/model/do/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage do\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure of table table_user for DAO operations like Where/Data.\ntype TableUser struct {\n\tg.Meta    `orm:\"table:table_user, do:true\"`\n\tId        any         // User ID\n\tParentId  any         //\n\tPassport  any         // User Passport\n\tPassWord  any         // User Password\n\tNickname2 any         // User Nickname\n\tCreateAt  *gtime.Time // Created Time\n\tUpdateAt  *gtime.Time // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3749/model/entity/table_user.go",
    "content": "// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage entity\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// TableUser is the golang structure for table table_user.\ntype TableUser struct {\n\tId        uint        `json:\"id\"        orm:\"Id\"        ` // User ID\n\tParentId  string      `json:\"parentId\"  orm:\"parentId\"  ` //\n\tPassport  string      `json:\"pASSPORT\"  orm:\"PASSPORT\"  ` // User Passport\n\tPassWord  string      `json:\"pASSWORD\"  orm:\"PASS_WORD\" ` // User Password\n\tNickname2 string      `json:\"nICKNAME2\" orm:\"NICKNAME2\" ` // User Nickname\n\tCreateAt  *gtime.Time `json:\"createAt\"  orm:\"create_at\" ` // Created Time\n\tUpdateAt  *gtime.Time `json:\"updateAt\"  orm:\"update_at\" ` // Updated Time\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3749/user.tpl.sql",
    "content": "CREATE TABLE `%s` (\n    `Id`        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    `parentId`  varchar(45) NOT NULL COMMENT '',\n    `PASSPORT`  varchar(45) NOT NULL COMMENT 'User Passport',\n    `PASS_WORD`  varchar(45) NOT NULL COMMENT 'User Password',\n    `NICKNAME2`  varchar(45) NOT NULL COMMENT 'User Nickname',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3835/logic/issue3835/issue3835.go",
    "content": "package issue3835\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3835/service\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\nfunc init() {\n\tservice.RegisterItest(New())\n}\n\ntype sItest struct {\n}\n\nfunc New() *sItest {\n\treturn &sItest{}\n}\n\nfunc (s *sItest) F(ctx context.Context) (d mysql.Driver, err error) {\n\treturn mysql.Driver{}, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3835/logic/logic.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage logic\n\nimport (\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/3835/logic/issue3835\"\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3835/service/issue_3835.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\ntype (\n\tIItest interface {\n\t\tF(ctx context.Context) (d mysql.Driver, err error)\n\t}\n)\n\nvar (\n\tlocalItest IItest\n)\n\nfunc Itest() IItest {\n\tif localItest == nil {\n\t\tpanic(\"implement not found for interface IItest, forgot register?\")\n\t}\n\treturn localItest\n}\n\nfunc RegisterItest(i IItest) {\n\tlocalItest = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3882/issue3882.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\noption go_package = \"github.com/gogf/gf/cmd/gf/test\";\n\nmessage SomeMessage {\n  // Some comment on field with \"one\" `two` 'three' in the comment.\n  string field = 1;\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/3953/issue3953.proto",
    "content": "syntax = \"proto3\";\npackage account;\n\noption go_package = \"account/v1\";\n\nservice Account {\n  rpc getUserByIds (Req) returns (Resp) {\n  }\n}\n\nmessage Req {\n  repeated int64 ids = 1; // v: required\n}\nmessage Resp {\n  repeated string data = 1;\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4242/logic/issue4242/issue4242.go",
    "content": "package issue4242\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/4242/service\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\nfunc init() {\n\tservice.RegisterIssue4242(New())\n}\n\ntype sIssue4242 struct {\n}\n\nfunc New() *sIssue4242 {\n\treturn &sIssue4242{}\n}\n\n// GetDriver tests versioned import path is preserved.\nfunc (s *sIssue4242) GetDriver(ctx context.Context) (d mysql.Driver, err error) {\n\treturn mysql.Driver{}, nil\n}\n\n// GetRequest tests another versioned import.\nfunc (s *sIssue4242) GetRequest(ctx context.Context) (*ghttp.Request, error) {\n\tg.Log().Info(ctx, \"getting request\")\n\treturn nil, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4242/logic/issue4242alias/issue4242alias.go",
    "content": "package issue4242alias\n\nimport (\n\t\"context\"\n\n\t// Anonymous import (should be skipped)\n\t_ \"github.com/gogf/gf/v2/os/gres\"\n\n\t// Versioned import without alias\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/4242/service\"\n\n\t// Explicit alias import\n\tmysqlDriver \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\nfunc init() {\n\tservice.RegisterIssue4242Alias(New())\n}\n\ntype sIssue4242Alias struct {\n}\n\nfunc New() *sIssue4242Alias {\n\treturn &sIssue4242Alias{}\n}\n\n// GetDriver tests explicit alias import.\nfunc (s *sIssue4242Alias) GetDriver(ctx context.Context) (d mysqlDriver.Driver, err error) {\n\treturn mysqlDriver.Driver{}, nil\n}\n\n// GetRequest tests versioned import.\nfunc (s *sIssue4242Alias) GetRequest(ctx context.Context) (*ghttp.Request, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4242/logic/logic.go",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage logic\n\nimport (\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/4242/logic/issue4242\"\n\t_ \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/4242/logic/issue4242alias\"\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4242/service/issue_4242.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n)\n\ntype (\n\tIIssue4242 interface {\n\t\t// GetDriver tests versioned import path is preserved.\n\t\tGetDriver(ctx context.Context) (d mysql.Driver, err error)\n\t\t// GetRequest tests another versioned import.\n\t\tGetRequest(ctx context.Context) (*ghttp.Request, error)\n\t}\n)\n\nvar (\n\tlocalIssue4242 IIssue4242\n)\n\nfunc Issue4242() IIssue4242 {\n\tif localIssue4242 == nil {\n\t\tpanic(\"implement not found for interface IIssue4242, forgot register?\")\n\t}\n\treturn localIssue4242\n}\n\nfunc RegisterIssue4242(i IIssue4242) {\n\tlocalIssue4242 = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4242/service/issue_4242_alias.go",
    "content": "// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage service\n\nimport (\n\t\"context\"\n\n\tmysqlDriver \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n)\n\ntype (\n\tIIssue4242Alias interface {\n\t\t// GetDriver tests explicit alias import.\n\t\tGetDriver(ctx context.Context) (d mysqlDriver.Driver, err error)\n\t\t// GetRequest tests versioned import.\n\t\tGetRequest(ctx context.Context) (*ghttp.Request, error)\n\t}\n)\n\nvar (\n\tlocalIssue4242Alias IIssue4242Alias\n)\n\nfunc Issue4242Alias() IIssue4242Alias {\n\tif localIssue4242Alias == nil {\n\t\tpanic(\"implement not found for interface IIssue4242Alias, forgot register?\")\n\t}\n\treturn localIssue4242Alias\n}\n\nfunc RegisterIssue4242Alias(i IIssue4242Alias) {\n\tlocalIssue4242Alias = i\n}\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4330/issue4330_double.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage pbentity;\n\noption go_package = \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/api/pbentity\";\n\nimport \"google/protobuf/struct.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    Id       = 1; // User ID\n    string                    Passport = 2; // User Passport\n    string                    Password = 3; // User Password\n    string                    Nickname = 4; // User Nickname\n    double                    Score    = 5; // Total score amount.\n    google.protobuf.Value     Data     = 6; // User Data\n    google.protobuf.Timestamp CreateAt = 7; // Created Time\n    google.protobuf.Timestamp UpdateAt = 8; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4330/issue4330_string.proto",
    "content": "// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage pbentity;\n\noption go_package = \"github.com/gogf/gf/cmd/gf/v2/internal/cmd/api/pbentity\";\n\nimport \"google/protobuf/struct.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\nmessage TableUser {\n    uint32                    Id       = 1; // User ID\n    string                    Passport = 2; // User Passport\n    string                    Password = 3; // User Password\n    string                    Nickname = 4; // User Nickname\n    string                    Score    = 5; // Total score amount.\n    google.protobuf.Value     Data     = 6; // User Data\n    google.protobuf.Timestamp CreateAt = 7; // Created Time\n    google.protobuf.Timestamp UpdateAt = 8; // Updated Time\n}"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4387/api/types.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage api\n\n// Status is a sample enum type for testing.\ntype Status int\n\nconst (\n\tStatusPending Status = iota\n\tStatusActive\n\tStatusDone\n)\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4387/go.mod",
    "content": "module github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/issue/4387\n\ngo 1.23.0\n\ntoolchain go1.24.12\n"
  },
  {
    "path": "cmd/gf/internal/cmd/testdata/issue/4387/go.sum",
    "content": ""
  },
  {
    "path": "cmd/gf/internal/consts/consts.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst (\n\t// DoNotEditKey is used in generated files,\n\t// which marks the files will be overwritten by CLI tool.\n\tDoNotEditKey = `DO NOT EDIT`\n)\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_ctrl_template.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenCtrlControllerEmpty = `\n// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage {Module}\n`\n\nconst TemplateGenCtrlControllerNewEmpty = `\n// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage {Module}\n\nimport (\n\t{ImportPath}\n)\n`\n\nconst TemplateGenCtrlControllerNewFunc = `\ntype {CtrlName} struct{}\n\nfunc {NewFuncName}() {InterfaceName} {\n\treturn &{CtrlName}{}\n}\n`\n\nconst TemplateGenCtrlControllerMethodFunc = `\npackage {Module}\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"{ImportPath}\"\n)\n{MethodComment}\nfunc (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n`\n\nconst TemplateGenCtrlControllerHeader = `\npackage {Module}\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"{ImportPath}\"\n)\n\n`\n\nconst TemplateGenCtrlControllerMethodFuncMerge = `\n{MethodComment}\nfunc (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {\n\treturn nil, gerror.NewCode(gcode.CodeNotImplemented)\n}\n`\n\nconst TemplateGenCtrlApiInterface = `\n// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// =================================================================================\n\npackage {Module}\n\nimport (\n{ImportPaths}\n)\n\n{Interfaces}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_ctrl_template_sdk.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenCtrlSdkPkgNew = `\n// =================================================================================\n// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.\n// =================================================================================\n\npackage {PkgName}\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/contrib/sdk/httpclient/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype implementer struct {\n\tconfig httpclient.Config\n}\n\nfunc New(config httpclient.Config) IClient {\n\treturn &implementer{\n\t\tconfig: config,\n\t}\n}\n\n`\n\nconst TemplateGenCtrlSdkIClient = `\n// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. \n// =================================================================================\n\npackage {PkgName}\n\nimport (\n)\n\ntype IClient interface {\n}\n`\n\nconst TemplateGenCtrlSdkImplementer = `\n// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. \n// =================================================================================\n\npackage {PkgName}\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/contrib/sdk/httpclient/v2\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n{ImportPaths}\n)\n\ntype implementer{ImplementerName} struct {\n\t*httpclient.Client\n}\n\n`\n\nconst TemplateGenCtrlSdkImplementerNew = `\nfunc (i *implementer) {ImplementerName}() {Module}.I{ImplementerName} {\n\tvar (\n\t\tclient = httpclient.New(i.config)\n\t\tprefix = gstr.TrimRight(i.config.URL, \"/\") + \"{VersionPrefix}\"\n\t)\n\tclient.Client = client.Prefix(prefix)\n\treturn &implementer{ImplementerName}{client}\n}\n\n`\n\nconst TemplateGenCtrlSdkImplementerFunc = `{MethodComment}\nfunc (i *implementer{ImplementerName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {\n\terr = i.Request(ctx, req, &res)\n\treturn\n}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_dao_template_dao.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenDaoIndexContent = `\n// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage {{.TplPackageName}}\n\nimport (\n\t\"{{.TplImportPrefix}}/internal\"\n)\n\n// {{.TplTableNameCamelLowerCase}}Dao is the data access object for the table {{.TplTableName}}.\n// You can define custom methods on it to extend its functionality as needed.\ntype {{.TplTableNameCamelLowerCase}}Dao struct {\n\t*internal.{{.TplTableNameCamelCase}}Dao\n}\n\nvar (\n    // {{.TplTableNameCamelCase}} is a globally accessible object for table {{.TplTableName}} operations.\n\t{{.TplTableNameCamelCase}} = {{.TplTableNameCamelLowerCase}}Dao{\n{{- if .TplTableSharding -}}\n    internal.New{{.TplTableNameCamelCase}}Dao({{.TplTableNameCamelLowerCase}}ShardingHandler),\n{{- else -}}\n    internal.New{{.TplTableNameCamelCase}}Dao(),\n{{- end -}}\n\t}\n)\n\n{{if .TplTableSharding -}}\n// {{.TplTableNameCamelLowerCase}}ShardingHandler is the handler for sharding operations.\n// You can fill this sharding handler with your custom implementation.\nfunc {{.TplTableNameCamelLowerCase}}ShardingHandler(m *gdb.Model) *gdb.Model {\n\tm = m.Sharding(gdb.ShardingConfig{\n\t\tTable:  gdb.ShardingTableConfig{\n\t\t\tEnable: true,\n\t\t\tPrefix: \"{{.TplTableShardingPrefix}}\",\n\t\t\t// Replace Rule field with your custom sharding rule.\n\t\t\t// Or you can use \"&gdb.DefaultShardingRule{}\" for default sharding rule.\n\t\t\tRule: nil,\n        },\n\t\tSchema: gdb.ShardingSchemaConfig{},\n\t})\n\treturn m\n}\n{{- end}}\n\n// Add your custom methods and functionality below.\n\n`\n\nconst TemplateGenDaoInternalContent = `\n// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}\n// ==========================================================================\n\npackage internal\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// {{.TplTableNameCamelCase}}Dao is the data access object for the table {{.TplTableName}}.\ntype {{.TplTableNameCamelCase}}Dao struct {\n\ttable   string          // table is the underlying table name of the DAO.\n\tgroup   string          // group is the database configuration group name of the current DAO.\n\tcolumns {{.TplTableNameCamelCase}}Columns // columns contains all the column names of Table for convenient usage.\n    handlers []gdb.ModelHandler // handlers for customized model modification.\n}\n\n// {{.TplTableNameCamelCase}}Columns defines and stores column names for the table {{.TplTableName}}.\ntype {{.TplTableNameCamelCase}}Columns struct {\n\t{{.TplColumnDefine}}\n}\n\n// {{.TplTableNameCamelLowerCase}}Columns holds the columns for the table {{.TplTableName}}.\nvar {{.TplTableNameCamelLowerCase}}Columns = {{.TplTableNameCamelCase}}Columns{\n\t{{.TplColumnNames}}\n}\n\n// New{{.TplTableNameCamelCase}}Dao creates and returns a new DAO object for table data access.\nfunc New{{.TplTableNameCamelCase}}Dao(handlers ...gdb.ModelHandler) *{{.TplTableNameCamelCase}}Dao {\n\treturn &{{.TplTableNameCamelCase}}Dao{\n\t\tgroup:   \"{{.TplGroupName}}\",\n\t\ttable:   \"{{.TplTableName}}\",\n\t\tcolumns: {{.TplTableNameCamelLowerCase}}Columns,\n        handlers: handlers,\n\t}\n}\n\n// DB retrieves and returns the underlying raw database management object of the current DAO.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) DB() gdb.DB {\n\treturn g.DB(dao.group)\n}\n\n// Table returns the table name of the current DAO.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) Table() string {\n\treturn dao.table\n}\n\n// Columns returns all column names of the current DAO.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) Columns() {{.TplTableNameCamelCase}}Columns {\n\treturn dao.columns\n}\n\n// Group returns the database configuration group name of the current DAO.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) Group() string {\n\treturn dao.group\n}\n\n// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) Ctx(ctx context.Context) *gdb.Model {\n\tmodel := dao.DB().Model(dao.table)\n\tfor _, handler := range dao.handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model.Safe().Ctx(ctx)\n}\n\n// Transaction wraps the transaction logic using function f.\n// It rolls back the transaction and returns the error if function f returns a non-nil error.\n// It commits the transaction and returns nil if function f returns nil.\n//\n// Note: Do not commit or roll back the transaction in function f,\n// as it is automatically handled by this function.\nfunc (dao *{{.TplTableNameCamelCase}}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {\n\treturn dao.Ctx(ctx).Transaction(ctx, f)\n}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_dao_template_do.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenDaoDoContent = `\n// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}\n// =================================================================================\n\npackage {{.TplPackageName}}\n\n{{.TplPackageImports}}\n\n// {{.TplTableNameCamelCase}} is the golang structure of table {{.TplTableName}} for DAO operations like Where/Data.\n{{.TplStructDefine}}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_dao_template_entity.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenDaoEntityContent = `\n// =================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}\n// =================================================================================\n\npackage {{.TplPackageName}}\n\n{{.TplPackageImports}}\n\n// {{.TplTableNameCamelCase}} is the golang structure for table {{.TplTableName}}.\n{{.TplStructDefine}}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_dao_template_table.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenTableContent = `\n// =================================================================================\n// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.\n// =================================================================================\n\npackage {{.TplPackageName}}\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// {{.TplTableNameCamelCase}} defines the fields of table \"{{.TplTableName}}\" with their properties.\n// This map is used internally by GoFrame ORM to understand table structure.\nvar {{.TplTableNameCamelCase}} = map[string]*gdb.TableField{\n{{.TplTableFields}}\n}\n\n// Set{{.TplTableNameCamelCase}}TableFields registers the table fields definition to the database instance.\n// db: database instance that implements gdb.DB interface.\n// schema: optional schema/namespace name, especially for databases that support schemas.\nfunc Set{{.TplTableNameCamelCase}}TableFields(ctx context.Context, db gdb.DB, schema ...string) error {\n\treturn db.GetCore().SetTableFields(ctx, \"{{.TplTableName}}\", {{.TplTableNameCamelCase}}, schema...)\n}\n\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_enums_template.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenEnums = `\n// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ================================================================================\n\npackage {PackageName}\n\nimport (\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nfunc init() {\n\tgtag.SetGlobalEnums({EnumsJson})\n}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_pbentity_template.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplatePbEntityMessageContent = `\n// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\nsyntax = \"proto3\";\n\npackage {PackageName};\n\noption go_package = \"{GoPackage}\";\n{OptionContent}\n{Imports}\n\n{EntityMessage}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_service_template.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenServiceContentHead = `\n// ================================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// You can delete these comments if you wish manually maintain this interface file.\n// ================================================================================\n\npackage {PackageName}\n\n{Imports}\n`\n\nconst TemplateGenServiceContentInterface = `\n{InterfaceName} interface {\n\t{FuncDefinition}\n}\n`\n\nconst TemplateGenServiceContentVariable = `\nlocal{StructName} {InterfaceName}\n`\n\nconst TemplateGenServiceContentRegister = `\nfunc {StructName}() {InterfaceName} {\n\tif local{StructName} == nil {\n\t\tpanic(\"implement not found for interface {InterfaceName}, forgot register?\")\n\t}\n\treturn local{StructName}\n}\n\nfunc Register{StructName}(i {InterfaceName}) {\n\tlocal{StructName} = i\n}\n`\n"
  },
  {
    "path": "cmd/gf/internal/consts/consts_gen_service_template_logic.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consts\n\nconst TemplateGenServiceLogicContent = `\n// ==========================================================================\n// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.\n// ==========================================================================\n\npackage {PackageName}\n\nimport(\n\t{Imports}\n)\n`\n"
  },
  {
    "path": "cmd/gf/internal/packed/packed.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage packed\n"
  },
  {
    "path": "cmd/gf/internal/packed/template-mono-app.go",
    "content": "package packed\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/7RaCTjU2xs+FNmXkMouY2co11IoUo19F0JNjDGMmcEQIS0kyVIppCylBQlpQ0pFkSVLpQXZKYQWa/g//e/NnZ8YM6PreZp51NP7vt/3nd/5fed8r5nhsuW8gAkwgRgE0Q6Q/KwFzICI8iRgkUSUgiceh1dAEghwY6QHyhWDRVlbMQA64StaaJYvo5wR+4bZLMzMzHKtzeqkaxDVFebS0qZ1nV98vvmycxCIfgyGMpfTr8DOdsdJexXcYxwb2/H0SLpOOyyjgEEjApZRWDAeMF4YwcBg4KA4XdNyQ2fMioDqhvXEXUmX7f2IlpBEH2Fu7jxvVNyExVrsL3h7EAAwM2NmuIKpUUtrLAAAkAEAWDgSgXkjsdimo2e8TdFYbzYUCxvCi31yBlXG1kz61Qrl+vL61oRKuAVTTZXhC312A4XynnYW+WqjGhsmRX152TyL1nrrcmkZGek79Y2mL0yXYV5Wwg0a4csz6Jb/0qdzSjTMBABgRKIP/KaPb159SAJmVtlPLNL/sTCWwEJYcDcUFotfFPH37EmQR/z7UxH9L/St6Gr3J1vYQl/UWbJpl8GG21f0VnyMSVMx0x08nq1uWJxVvZ2d+fKgU/tI7Qo3hr2tzglregiTjTtq0uqclBBxVZJa6iNM/ZfyYuqdAx8daUFzHO7OCMuI5rPx0MxRu7frdtLxaRQ/7HOLP1c/SvBMeXj6W6WrdnUYFY1dOipyjPjJUc9XGMIRjk3olfXlkpWp5vHnT3V0Nse1mfjqwE46nkoNvn+xca32uU6hfYc5zxkTWt6u2Sxk/TWb1UWjtdtq5+mubRywbrvoh3VedBXjE+cMJ9JzZtebxfiBlkYAQA4duRoIL5IxP2UayiC1KOjvlcBW55kcUWZb3lpwgKWSRz5qTxUPEYl0zhr3On8sIbQ0w16sRchcMj1aqrm5MSAQzaepBXj7PNVbHkXf8nfKmcy2q70i48Zy9VksY9Jy2L0VQ4b8mojsATttrwnbpA7+fuKMRI1/f7+GRflDdl30hZMcIY9KfQIj09tDfRKH7+ntx7BarmkYLtT5HBY9NMV5Tk1UTvKkQ43wzV2wuA27clZiJqRF9muNM/9K7kp7QWwmAKCH7AJfNW8e3JDOHjQkVXxBMLgzHueKQSsGID2xs8B60cUmcsq8oZPBx83rm+Ty/KYRsXISshIsLE4leaYn+N4/e4PeOjJgziuROX4uEX8U5tTiJFb1kc6h/oRt60fdCI8r4qneEVGVUa9yS68iBrb3lVx13SCD0wn0cyziDSd4y5yjY7LC0flX7gPb021rGCM1R3Nc1uYnfHctCmwSSU4uexXSV62T/dIgu9qv6N1Mo67jqoeoEst9CjYRDtpYpVjVOiWQ3Jz4ztH7/N4vjJF1j10ffkD2q30kltmKxcltn3hgepx9MMpk2GBqcE+ydZVqbGaDeU/ArdvTsxuW/bZPfC0AAFE6GtP280PBGYtR9Py3HtjY3Vk8ylxlKWop7bmjFvKFERNvdK1Z7jB4bRvWeSfutaHiqOvpm4l3WKaGbk6tuzjq2V116OumdcK5xxN9mT71tbhJEujvhqYmrneeRjKYyCDENiv0xXyQdDvMbzzEY36/uvSa2/EoaRNcgof6JqzCV23TOO/k908436abFHRe97b5zotAP/+0NtVoY1nsLfOaAyFBZ3ex0CkeaueOLJxeP707aDTggaCzytrD5+4YMr4I4SjYuU0W3ZZzxmyqMCM4vE001L/k/mXXFULVIu9Pw7oGZKfPzcgMyGeuczU7Gi0rrFvS97aXrwbtH/l9bVdH0kpriTi4IfZuQ1setwAdL8NfnroFiEHfHfwghZvnQ2L5/S2uzRtGgt2PnYjhmCj5iKvtt4yzOMt/6mLDprXX4EnfGz7Q/arF6ZsujzbQAfCGbC2EydeCtA6h1h9i2lW5DjjN8FlGG+gVc2XEXB8hEtveWN5lfSdyxuSyrsl6Ov5nfgPMfNt+DJ5xvklX2D+852nyiw9qwjFSU3VjlUNd0wHKiRyDSMIyDMyl5s0Kf2UNqdCI6b0BESXWHIcFm1pCGOpFNdLWEUotI3J1+kJtgl+nNBuLPGBPXX99/bLy9F7WrmOGFTe04azX2Eqb8mfaUaJ8x98rWJlcg7nY8+21szPRlZO+rogsy/dd+Xpyl9NzG9FQuxh8+cs+ro7NTu5Ps7e2bn+Jtr2o28d5FrPNxjBC1Wu8EFVTbtAdruYff+1wSvBB/a0qdWZMERwsnkiV85KXMOttJNzen+p2yD/fxxrXMrnWzcYu8niJ7RS/6/LKo9MS+62sP67dnWUJz99/P5WPi78jRLeI+y33JVbW/qGQQ7d1bu9M6sNGrdKriN+B/R73qmON5d1wAUXksOZ50LTlbo+NNEye4VCZMfZTU2neLowhQU04+uKxCN22D7WT/of9SjO8uZ5tf88G42c5MB3XeU/fCobiLRbryr6Wwmr4/lja823DjAje2mYtTqnJmCF3wTvCp2uckj/b308JcHD2T3/xVmxTs2PUh61GLIXFdd9GGoc72pFj79XXEvclB4YEi1311Rg6TqzQd3F4rpDwPPvHe80S+bXBZ8cfhOe+1nxYfSpneMtgR2GEcaxI2sn9gRL9Ipfi3Y/7Ol5OOLncSgB5W9a8zny4schuLLDnHRyl8YzdwPPisbysFxzMe+8f1SiSbSzI5RLoHRG+2tBT1tvnHMd1VtJuZzRRZrqsT6Po+ReeLRVnpGvNV7Zj8iJaUs8E9Z36jFM+MBY8qPZwP6dWV8Omvb6RLEm6quCesjer13Cz47TmxYObg/hOoEcb8GksreECvcTWFx6pfLKc+2Fq52/ylT7AaX7DqN4X2hHuMPlDCm2Ud6gG1+LFmB+Azk3aF7T6QVS4XUSpj4lmlYSpeeGeHroNgyo516cVf3y7FNl9oXjG91MvK7d72T7lDzVRr9IbMsdCRr+0XMm6bb3XwrWedaAsXUqo78S7UQWR/c+FdKd0NqaVFfLnP70nzd00w/DrqZspCskSWwYA9wpyb6H5m2MMjojyxiGxNPRtwmQB4c6eLjS83mCLgv78Q9oxEGN1PJqUuMJe1OesJt484lwnzF4gUTtyyuzOrdEMrdfHDdYpn1I7dHOm2LaoVvCmlDI+uSXo/omvIsTlPg63RpSlMmoxqO7SMy2ZdfZrevq8JrVqZOzjm9yb3U1TBmRXV2z0aSixyt70+hx+l0UeLroyfKdsmWBufbDR+c/K6L6CU0qMRU/0WQ6VCsuEuhBzvjOjpEK2vxgCgf1jcXv1nKbdLzsp1S/fI75f9YjNJ7TOjoZNbeaa2TwJFuay/U1mCBMJz0lUR8Bh346CpD4Bh741KYqDYM3l2BLHoslidi2iBL3EqfRwIV2+BOGSqM32uEY1zA9ZTOWFPNd7nUXBR4tsmv0Ru2CYsx5H3SeH38INU3fyflKsmXms1gmLFbzWWRo2se+hsBbcMcnaAxeU1rg7pfCAm71Pco5teBQ8VNeXh3FER85X+NbGPqcZ1l/L6a/owAFjOgDU6clVX2yRQuFxPkQfGhaAHCW4/3yRLgNZhFGNiZGpNaLmhZyiTDf9bH9Qws9WxQcA4CS7mGGL0hK98VgsypuGB0WOUmyaDzwq1DHMcwCqecRMr8wV1haY6c9+L6PkdK64/61DXkJqR5yTsZKIQv7A2pnpJ/EbRh4qdp0wzGP0iBVuyrb3PV0rcGPZjpokTb7wr8w6G22DD/rWMecXrHvQ1+wgxn5ECO+BMgg5eSVentOOb1tzovZso5BhhjiKBQBwkG0U1GkJazcOtQ8aWrH7ky1cy1vfTfIeidzD/zptBQLWs4Or/+m13YYe4+XNA1523Cdqi8IljIVFk10zY9b0DI19EOup7RVdDdNHnqY7z6g3UvFGag3hQdu2FNYdOl9fP7baGjbFHd7BbDo5YnXos/eJ9aODmiw3Vh5eOZ5we7XqLfuYlhsNBZ/+KjR/FrkhQiO3QtG9XqinXz1wtOP1LdjNXatUzl13Y7IoXCtic6WlO6x3/WXhFeP9n6pH9mW6736YlaXckHnMGNbWlpPMb3/sAf2vpA2dQ6x/CgCIJps0LZqS5qe8+/ezWHQxrk+JLQz9Vcb/LzsdcbFRPnreCxtU8jPrj5vrW7m9UzL71sxaJLSRKMokGNRzNWxMeGXbBW/Xg3kqq8qEN/IUyGa7p27AvJz88UmcP0WdXZv9wPjgCuawoPVDK9Ks7DkMrj4+Y5r2l8i73tGVD8+z2x5E3uCePBbOupOvJrGzCzsc4DxxTW6ajRA/GKKXtkL4bP77k3Ja8iO6DXjMRvEI7LO9w8sKO298S8DUS7V51/my3vlsYNmx8WRRxbU4D7zf5hbbL+83O6fx1NvJBj3eOXsgFn/M/ax+znmB6pebCxL/xw7EpKBwRTSG6IFCEWbRZx+ZnwAMi+41ouQpsHg0xpkG5TIUwP7X2j3xLijsn9f+f9gla19HCYkLLYtGnjLkJUcgRQkPCkfEEANoiEKJcvQlR7JIa0JAOnugXP58a/I37j9f87UmoC5DxuHfm+CvjO6veBZtTMTJk/qgvP0wzqg/H80/wFQW43eaNfPSeCIxONIUBdXoZD5W4no67NvDm5blUsd2X+5+2D1CB4OLUcPqfiPdCwid+0Uvs9unJw/8kAuTu+yWcBO43ECZO6dtStRGFd/K5wxTPqOStv3GBozgPcSaazZVF724z3lZtr9ZRhTJUWmb4qxkt6z93tceLuDf/4jOyPjxprqNXw8qDvVyxpWJJL2p/l50LbBiIifLlyN5iOVXhOu4kj+eAgA0AuoPVp5IHMYV5UOkoV8UIwv4zzUfDRVXoAR33lvEEzGPTJ4osR0dPPmFw/xeCdL4ziPVrtJ1Qyy4DleGuxwRRRF3dwwcLWU+adlvOj01/uj8Nm/2Gthn1hNvCPqK3jub+XbtzHPIxW5MnhDznDhEWKfuSq+TjVNyQ7GV2ua+3nMW/aQiEB+vjT4vyokX7dlz/YimyuCZq2deyaWHdoU3G2adsQmx9XWohbUT4+uP+yfu+osJjpBczap3V2hlwNk96VVjOa1vprVtspjoFawcOtaNKJ2+HuLslqB9OK9j51S6WQIMu2+yJ/7J8DdZxwNNn6Oj8EH57JPFmzU1HsmObPpV7WuHlSbaAAB4uiUUxwVFwOID/tghYQ4u3MPXh4j3xOxH0cCgRB0DfC/Sh5Z9ZQsNNP/8rScKR4QuvKDYYpPlymyhk5pl90tYHJM4Ik61y+4/nV/y2O96FN3A+0tDPu9O3/PRmOhukOD9UtoX+5mPV/mzNkeX8Q+r4ZK04A0j8k/1pQwyGQjrbyDumBk4XQ/cLX0RGLy47rw+IXMmlbtJMtf7mspavnB6Nhvc28aUTPM7jc8u9GWy9/TfLUjSMIVLqKmUfMgNyA48pZ5T9OnLFM5qdUSK5ZYTTjeCnjF4B+3U8jtzx7qpT8rzUty/Qxe2OjnVfABAINlOfSstmfr1K5KIweOgyZJ/nsf+WImLoXb6yhC9skH4fXqtYi/t3sphx04f8bCPMojx9Hg17boLV2ReNof/dYA78mNSiu2gMOau8wFkp52sr36bV7amm6wQLhA+JGFpm5vtp9p7DI3LMnpUx7nqh4z4w9n4ypgqnrr+fFQA9SeRReL7570DjQxbrcOyTJkprK346hD9oY837g0wMNoXxp+Iq5U4flIjRL/X22/zxCNnOfyw+S2eZLWxswe4tMtenGI4t1xE0OjgmwJmJCL/uVgGprHUVcnoy4+k/SfWYGBtwcv09HzYq+2Zd8cEOx6eWpc3U6f6NlZW4yWGTrXI/vDu2XDzL+6pCgQAXCf7fKlQGS7eD+WNRQb40PAoa9JIBXdB+aGweAINj7XhEin/ea94IgnQ0mpGFZuUKbFtH9Usu9pfHMcegNq+d++MnhFz5zMD78hYf389zOfuDh/5hvbIO8Ie3P2jnzecFfW/3qWAM1WJ91UimAmaJVgrqexqr4U1WvCfU8jZcQGDOzuTVKnms/KHOuh95+fpXQW2ur0rEmztQjruDMl0t3cbTuxwbB10G/5S55FYGOL1/pZx8MV94SbfObtPpxdJMmlaFl6IMcvZqvTOuhk/uwoipixeXQEA/CCbJ6Ol5mmhrRAbpZX5ZAtb6KRWmUOJplPWRjQCjuXWs9nsHyZ2l1PgjVWi+5h2QtvLovNbnzCf15i+MTNitZlJrUIYzpPjahFEUP6r5G2o2d63BS75Q2/U86PigidQritWXXj7JPJVl2AkeI/mXO78Hc7wcmy47yhHQfqOB8t+RY5ets55HwDgLtnITZcaObmtrcrYPXQL147h4AsX4Xsiimp3Mtkx3IS/f3ildjo1S5BgspmtY3o0WWVqq1o27OiUSo5dSqtVZabA4O6n9s+eqTxBXXSsXPlkNLv09qqLHFlo01zE1j3Cic/s2FRCX0gYdhh+0XlZ2rC5v7FIXdV4c69Ay6vDfi/lLo0pRLrYng5dveq6t7CJ3rfZvvDH5fIfxwEAWUtp41zwzh4UXCdSeiCcgwvX+/8XxPfizfpl1Lq8wtRI5rVplUx5leHt9a/zW9strii2WtiIAs2pw1sFg4MEt2pOTV3DbYrP2p2gey8k9m4kmuto9UQEA4NDtKIiy7aMsvHL2yoyelmsUjd+f5T57ZuhhQ/rN5/1Xw3k2nl8LKuMvvnwbPjKlblF80aq2eawzhNNP3gZBlhUZDIno/e8kZWWXh6uzhhm1uxqG/tYs7yrn5VFNFeNbvZUcREX050GALCjp/7wMjcHf38p+riR+GVemj6vajA1kK9pbbewYaool7f52/5TLm+DyEYYKyroG5sjDIwr4QbWiArTGhMFC4RsdZV+XQf9si2zW8HJfIvhrf/vdcgtABHyIjHK6jgayi+9OOp/dJsxy0HwxhPxe31daVCvShkyXPGnfAWMqwIO5Yzy8UF6B9Aay/zHM2+UD97X2xn1x45nvwDhBN+9WAru2H7HlaQEF+5G9KTlEgxOMfiSF480RVQErC8aQ8v6V6YCfsmxyFJEtoTFpEgVAdzZh5aZmhrVJEtOnBJ1lBhPJJqWw6YGDTRLjk2BOlJ3nz+2T5Lh+I/2/FmGX//0xxqW35CXHMH8V42+RAyWtjtrcXJ4S1bLPR86GZV09LzL/tVJaiP++Yb79ZN+6OcnBSbouYCkvl8BCODzeQF/9yL/izi/X/jvHy4woONOBxZ1Dy+MJQDBurMQ1m/DdGi8pL5YCUi8TPSAOvcwObHCELEblwHKbbZQvaRWUymI3phFQamTvAoiOX45WNy8CpVK6sgUh0jtXBBs3mvnucCk9kIosAAjoMbeOReY1EElDAG+ugJQ6lUkl9O1kJwKsQLKrFiUriscWcA5Vixo6KRuHxgk9CeLgs61YpETLAYRjGUHVLmHoJpJLT1yEM2llODO4x4ipxwGUb6JA1BtFFoYWw76rFGKvcjeRuquUYHkZ5w6BnIbx99UpJ4UdQhVLSdYunlnLh2peUMLQsfADf6Q7YXyx85wJaDcJAINhLRHgG7nqYuC/t56kJMsCpG8jAdQ4w9ZWLQMRLQ9BbBLkf2QPP5cawilslfxAhqsIeRkr4PIDqQE34WyVSIPUf6KMmTqxEtBxGvxARoMIQsHoAQJIIlydOqCgL5oVqwCVHlBoPJJLRrQF81uSnDn8YKQUy4OUf6SPMPvxo+FMw+VrsAPaDJ+zGUgdUesgTDEzcsw1/NBeb/ktxpQ5rCgdFU8Iwv4u8MCGjipUUABErjIGkCjw4Jy7S5rAVUGBEqbj/uU4M5rQFiYQQnCICwAlmJAgBaBdMS+BVKEMBpoFpy6zaUlnXxvhdDmCII/Os2fy0w6hIa2PjFC4A/N2cnVUgVSywPCYKnD7oWpNCFUH2mkmmfYDc0o6UDXEJJRBxHwnwy75yogHawaQRSEioL/Zow8VwLpLNMUIuGAGPjP5rmUb3fR4oCqKSo0OtJpIrSB6qYEd74p6lwK0lkg6Yt24NCndYCmISW55IhAkhMjAaiYMC7cIEhDUtO1OOpSmmJ9GKByuLiwcFWI8EuUIZMbLlLelPBJAsrmipSudFeygL/PFRfGlYTgPqAEd+5cceGUw6EXb1KA5rkiuRCkISEcpYjlt5HiwkEoQxc8FfDUhSELCcNCGtA2TVyYQBFCkE8VwZxp4sLZUoNka7UMWPI0kfKmMZI6trmDxIWD0oAE9YUGGurCUoCEhZYFNM8QKd0OK6nlWMquriUHqBwfUnrVEU8ZMnXi10DEz8xL8fvkcGHJ0HGEqTygZnJITig3idAZnez5gElwGBj/9moaApggAN/lf/72vwAAAP//E9IPLjBJAAA=\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/packed/template-mono.go",
    "content": "package packed\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/+y9BVRW2ds+fEgp6VApQUC6JKVTOgVBQEVKulsFCRGkQ1IaFCRERZEQkW4QBAEJQUK6O74185txeFQen3K+//u+v1lrYOly3de+7r3POfvc93X2paaIgkoMYAAYQKicky5w6D8KABNwMrG2szJ0MmGztrWx5WA3M3cydHJyML/u7GTiqHURDUCiyBYxe6/R0NiiyNHKyt7ZKt+iyKGspFrsvHEMFQAODtQUj2F0qXGdpwAAgBQAgKPhTvwUztzMxtbB5BsUT7Airi8njvSGIzHpOr0HCq4aGmcVSWBGzdfJdZIOmyE528wLmr23mKr4O0h5TZ9IzmmJZ/VLmR7T/XCv+SvtHQnlT7z1dalmidYEdZnxXDhKr5ZES7Uk9CN8JojobO84cwyeZDI2yBI88FdkJvtK9P72i9BuK/cPm4krW+h/s5lRnHnnBQBAPlg2pD+wUTa0NDE1t/qHS1OLYhuTsrxWg5xSW88xgtJGwXiP133ewN9AnZHjlyn+TAw4ILIfgDRkJKSVZdiVpb8hOTWLECLT4FxYStY0rjvVtYDU0/QuDJvTSvriZj3+woKdd/7wDuWU3wcNolLFLlWHNBJZMyd9GYJ345dWEm2SW8iwIpLnz5NO+NQbX9D5vHDTpf+usFuUuqIZbzmdp9XUPYYgr2+DvqguyWIGAMDtQ4MGfhg0wQ+DNrSz+zbcP+Ic/tdHx6H6WRwOQztztr//9pdBf8zo2V8G/XEusZY38AJdl3A01NTUnmqpdTK2ybU2qjMyqnZ+WXZcdT6Oa+fkgqbIlJWZTf9gIprR/nUJ+ubmhTrfTInRQLT4Uvqc12iCgfQ5Cvrs+21DBRICdK+5VyIdFTQ1SFZXV9dWV88RRj2v8rNxUMm+YsPHbl7xyUr8W8pn7dN73QAAeASWFeOvWf24cDS07dpdWRRalLUwGJvaFZTZ1THkW9ka5FnlteyaOTTscBYvYqiwMTcrqYyPjo4if7vi87RItngAAGAHO3u0vx6SoZ05DMuCEaLAHDdMrKxsYVggXFCE/89PdrN/cF60GVhUc+IcW5ycIvZajg7mYzj2UbM07K2OYXRFWWBCQu2DGYssk9n5M33oQm+Z8SXF/OiM7HaGJepSI5K57EaMYzw/dlTrkXWXvhV5SSbccOtZcqdwsVpE0TuLkMk1dNcnLpp3CpZPyAxU9N0pmrQnpp3MoJOR0B2SVxO1VDlpsjXidPAm//ySabihWfQtivzl94r4RkY8fKXjhSoh8fwJmg815TNjG25Qn/XI/+zj0N8XuiTRFyzzyGxXPy9hoVR8FMVGxZk3rHwxTTpiczM2FNtOQVOB+WvUvTfIf0++0Fb30CAAAG+RwM0RCzRJdOGCYZp4oEP4caasWotUfLlwUEde38ZqJmINudZC5GRoaPRkyz7pXpxfTc5lmiFKdYbM0LODg73unmYkwiIA8Yy1wFBV6Au3K4U7+bod2Uw3sB7Vh6MnotKXHFtUJBOWy5/TFbXf1kkcI5t1OqBrc5udFdRoqDwuafYwAterqsbR837mqJ9j/FKJtIc5tubJrqVSiXn/0MW9qwn8dCwMEfptVM/06KPP6RUSmm8zUnvc2sL8O+3bHa/ncwEAmAJ7aZz5dVJuGBpZwpBuDsgicxjZ2piam7G7G1pbfUORDq1QYeEi9tu5FaT+/hNLkcu+XDgLHTMdFtaVt0WqwSQD9R/NpNbn1InpcrcS4m3v0l8ZukLT8hVJ/32wzshXyUDLbNpUh8CQ5pAPT2seyc3Jzrx9ZHqOyUbC08WgjDjAzoEpAQnjog2SW7MrIJup04Z+X3ij0PjU87g10zLPT9TJybUfvGZaJfK7FfJbXcr6D3olDUgrTd5qurJpB+qLWnGG83VyAsmD8f0GDknXl9Hvd74zrRw2nOX/6lSrQxPNIrv9RjXo+EKIypLC3sK1ZK0WvvDcLvVJ9xfF+9/uiJdlpkmGAAA4DfaigODRY27jZOJgY2gFw22RBfLoHEbWxjCsAW7oEP74//AF56RWZfGJE19E8SrXlPGx+nSRUw7yqXP0aVbmC5qeeSQxstfpbJFNDip0yrIEnVSvDwlXbEyYJHmlnYkbSy8OE5T3V2E5d7ZgVTukp0ngathAu71KZ+kX7Rltz+0bl6rkeuITUbMtBot6biZGBjk76u/PaDBNeMfMG40ac5nd7xs+kMmfVHh3Yjb5ogYG3bocDV2GZ74q487J9qmTVNc2TqRoBDc02+Z3Y8smAErS7aYdCrc4pm54HBMOeuSMrMms4L+HwUh3NvLl3osl4arSpU+ta8cLDEJUY129gzXkRgq2bltL4VEGAoF0Xw3x0rCU8EbqbJVfzZDz3H7wYrxN55z+6qBotcGMvXBmfiRPk5ZU8d7mbCx9BwuWM9mE2Aj2MqEc7kWHUcm9sqthybEFrbm8/G86ZsLwDMR48rjae3UCQjgw/acZcGZ9taeFbzj3VOwT/b30sEUDEzSQAEAGGdziYIdm6mxtHJ0cYVgfAlCD/PXr8CphllNqU1FS1ZJra2dhZ5r4Z9fxlgynhQQAADywVwE3dGNwcrC1sjJxgOFyE4AJCOZdiQQccD/bpVRhInPh+3/2zHU7XpLzNuoprduLO/aU/L5GyVYMcqVknh0H+9Wx59Yr2ceDFYvQLcOpPuVfdo7qIC9AudCWKEwSsIIpcV7nlrdzJ+bz12fezAzq0xz3pbS1NFHwisiOZcXTJZEZjBdF+nvuctTk7loBAICLBI6jDNwcr9qYuILwVFG0mBHH1y9TVXdbekrWk4pSHpMUdvojecYtPYtmKdPsAPn71/zmqZLwG5Ai+4m11KgnFw9eSbSldUpwKkS+Y0AROH5vNqpIlXvkZnWUKGmoz0SWf85drJ0zuPVEVOtzOch7jVxNnyqXGUsUMBS+GPVc/9hhIeJRpjKZ2zslS8nRRjfxlqHssTzl5KzAzuArT7L558bKerRlJhIZjUF3T2c9WTI1mba+co9dc9o+fKNgyKrS5cn6lopBSLy2jBUz5sHt7El/0vSwb+8CaGLneJoBAEgEm0YF+NPownX1x/1SaJFKDSfO3clmzTil1q/s6u7+Cvdeo/AHjEwwRwo4D+YSjg6qY8vh4DwYv5oiVra9OH/mHaUmbVadfiDaKef3d4JGGC7nRIVmfIq9RM5YJmdvZ283k0H+0cxJ/QAFYyKhfIRXk2bS0vlNaO+wE/Un+878fG3ZHEMmpARgMjSIM8tv9/0pt6F4hgZ0seGP82VXve19Vvr7Ub7ac3dwtnllbCE3lJMV3cFDA/Ctw7p8ngtzjau8HLS2CnPM4s6oWGKMU8jAQ/t0r2vAl6+eOYNVv/vRNtbfaXXn9xzpAQDgHBKinq/Ghra/Z0t7GOHPCoqlick/r9bfrrc/oqH98hbGBgWela2ZuREMnPigxfhXWVnbGptY/WZWf2LAzYoTakRjWJagIAwwcHPjgRrUxMbJ3MkdBn4iMELBzRGaDZidoZGlifFv3oD9B+SvXz/bgAGdOUz6/9QrV9AtPhD9cvvFAcUIHE0cXMyNTH4zz79QoJzAHzEZfo1pbWhucziTwaFFWO848e9ODmn6qTR2UGxi4Y6OjGI3xGdzfSzz84jx2ZzXqJI/1puSsrDD7M+SdSPuGWBcYKJhlCYYz2dS0WJGjWXEbC4eon/h/Uf7CJ+LLBqtg2a1rKfOphFcMp7V857AjkAvt336iRPN4LbofgzqvJ4dUM36mdL2obs4UcnGsabRsOcftUZd1TcinZ/cd8ZNXvz2yMM4V0IeCwDAEgDnC6u1oY25qYmjEww7aHbIo/9VVoBhqZyHGuSnJYzgsCqVak4c8YUtLBb9kacMA9cSHUaJNtFe2T/30QuoGawZzngbLkDjELT25dGkkMCTiVNJitykSTlRkfrRaaUsawUar9X6cJ4Fa/YHE3XJmrcFK0wkoqF4c5Hm8op78iWVb/QActloK6s+HrjXKCdyPPOf8VwsjCOMoXYiz+fyWsXRaKB/4NTMxWqdg8ZpcI/GW2aCo0JWl9f7Qcz+5+C9BWxl6VoqFl7HTIJLPetoI+bu2Ncmw7bb0u7d+Di/HqYaMPZVN+Bm5SCl0PCWDfm6p5ebnYJWPlfKt0uAfw5veQAAACMkRE2YsYmdla3773mv+g6Ew9LZ0cnW2tzDBAY4ETjgOK4bOsJy+1KGF/Ovv7U2sXECXaZOYRUq9Zw4NRvCtRXi/qWmUteNp2psNLBZk/Bq0btfXUAKutx9oKzettFFyes+aqOhiFps6krt6Bb1TFbYrqvUhJ2KWyj/CzGKGqMj6oZFlKONQhuSmodp8Weja/vUOmM8LW3K9BEyLUic2ipXdlRZox711qNMRqLOtg93p/WHJwP8+G+v3GD8MErnv0PDd2tBWpqByavS29jjdZzXs1jXD1m5mWyjV8TMn+P/U0+2U0l8UggAgBnYdxo1uFP29x8NncxtbUCzxtpUdPwdJz5ax372IjKXQkA5skiFvehU85LBF0da/69McluZsfyinQ+zmboHA3hvE9z/mpiis0Bl/srotuEXXWZn+c/2+cI3mCltPDkW6TR1nua78E3dM7N5olTViUe6y0Rb+e0hWovRWGcKAIAtAOcL3C/I/vXQA6WpH8KFhSyBI7OTREum06Hy3uMOWq1oy21jOzNCbsN2DqGQaxubC9WahRw1j3v8w1huWQz7Ud/LIFWTms7OkWwxIPcj4HsgvWJAxEMx7mQTMeZnkr44J9nSQvVA24rs9lDv68w68tf7KihCCpcbuqf3h1Ntv9F+eCMp3AUAgHSwl6IEPLRtXUwcrAzdHWG4BcgjApfD2MTFxMrWDobbgQ4i8f96elkb2oFOvlWYsmK1OP7dhS0SKf/0gLrsTm30IB+qGeVy1edRT53Wqwfl00bCYusuHndL2vB1pQpaf6j5suoMxZPRaxUSbrhvigdZat8VRdLQswLCgrIjxMuSfTI04zLn6ChrRyO3tZuIBCU2WQGgYMQ/ej3a3WlH2sKX41hvMBUumbdfwZjTa8AvjBWD80xEX1jCB78rBDxrwkF39aZlDnjyxZLuz0eLoWpiBH3IfVN21ZZqQrW/ZsaimCl2/Fne04LYmcSBglvRHVauaTTxFxTih/PG5tzHXPsW3yzUfSaw5S/fpf5EbCqOlJSqJP7PXYVjT9R95o+5BntXuYbQzP9zU2b74/ozcfju8mvlyq0Wx0HtuK3KRcaZMpzbdvI9ticG7QNtN3+aV3i4VkGPCW2vyXbNC99dw78xsSl0MNB1nehTnKeXYEbCc6cuDXPxx5pvM8Kypl5bFoV88TAhKqCO8xjsz+j2qY9DZk1hx9Bne4MVNzPmKsmX/MnzDcrfufCoTGB2BgCgEOwq1EdoLsDdbVuULfzE8S8s3XqYznEtsKzjEoYu2jOOgcrsjv3UJxR2KmI4Y/sbyTx7Uvz59Hf3eAp1U0YuNueSL1ytu1xfz1Ntkm7QTFi9kV9TTJqO+8RM9amc1DWq+HpdHB6/djrFMcVlie6aLrHZ3jIBPmWxKfKhDz4u3SwZm2z3jXWi/E6Q5jlQqUivftsI72Y17AYBAPAEYVtVY1sjSwgqyjC9e38HwiH95y8QrYID9vKGVkOjqhJTj2oLU0OLYjF3z/ORUY1s9hEN7dOA8J6PFMWtmxRSwnt7j22EYp9cjZMs8Qp/dd8M/27rdiAamn4oOzuWTE7tVpZMY84U1sXU82tVuaurihqO2KuO3CsKLKNEjpotSquOROdW8HPFhQtS1cT8vwR/2iVGm8PiYcrdCb32kZmRETVAAN1fbdBUJ/ydcMP4LDbW6af8SN/2m+k2YRNpAADoIsP5mvd9Qv7zi93xxiGRQ7dqU0uXqgJr28iohjZGYwOr9n/0Gw2s2nL5csrsbPLK6nIKys0cClpyjaptKmwacsytLfKdY8go/8gwIp5rLEkBACAOdp2wQjFicy4BGxhWCS+UEHBXLiB4CXQwcbR1djAy+T0vgX9H57Bzvm4FQRHyR5BzUINw3HCyhqUwKAwbEtyTxAs9rp2Vs5k5LCtQFFYsuFnyQ48Mx9IUgh2Nw8gRlgaqNHyIcOdXBA58c2tDM1hehmXhxYSb9Xk4RmAByzRLwQX4b7QSvsHBIbQUhAEGbm4/l4xa2F5HvGT0cFCESkZ1t+Thk4zK5ITrwSoZBWEFvWRUvrW1XXOxSXUUGemf8SxqXNTk+rMzB712DWQ8CNWu/RD5v9o1qHeBIDlEuHbtp9ERql07EuF77ZpfROf9bk78upSoyustmp7RqDf1S44tSBNfrKk140jM7nNrbeGWb0fpOzCIfLAioJ8V/v4r/8rOm8bGUk9y4RIehZNdgSXiZ/0d/GrFSOn90/MyiZlrHPRx+9W577wzfmdMdSUx0HqZ4fF95CaGEp79C2/9DrST4pIiK6LxHjypUuWj1ZeizLdlor8/xsFUY5a4iytOT65+XOOebR96pad2yeepR5SP9VnJHo9cx1v0xZ1bKEMbxM1GM5hsOmOl1/FqxtM7anz2ZMGpDcWdqbSVlpH4QM/HDNId1ExOFfveRB8EUT5pqWWJjw2taa3femzAhkY0zT9WEvSBRFjEomTK1Fekc2i7mvDKqJtE8AntkdcP7S0+Xur1th8yfcqBbZTPbyASfKdQtEZfWEqU3SQzBePC/bFZ3VfRayq5M7dwFnq3b3c5tzqGIjHO3MK5MRlrc1CamL/3Ws9oxJTBFc+xWOO5uOC2WKhDYsGrYn7l3lO9chr3Vk7X6q4vu367gRCLhUh7IAHADAwatyOmGLEaN3AgiNe4QXO1IFKJciTCb9Js/BwPsUoUMBj/KivEKlHAYPym7SM4RAQqUcDD/CYlCjhQBCtRfg31m5QoPwdGsBIFHMi/o0T5+QgQrUQBi/KblCggmD8qUbhC33Hiy8y0MOVddCEIe3Hp4/VitONk4qFjJ6RM67CIiDHtXYnpmBlvVL4Z8uStcWxoVGPEUXvclFcn6chpze6h70Htz6lIpU70genGtJwOZ3fQ2a9lvUH+vK0UDJ/CzW8gJfBLUy1t+zpUUTjvbW5qE5rfqEIKxq43K3eeQFfOrFqQNKy8+tGG8CB2NeX+/rTFQ18h4W/Nmgs1g/QJMIpRvqONYDHKT6MjWowCDuSn7yR+LSIqdZw4QIfIo6fvkKWi9sXvC9vH8NhL+uvF1siMrj8m3HlV8VWk6tF0X8cO7eu7D5O6R6NqJjIuLvtnOamHlpNUa2Bp8QBKYjXe11Ce8wLKUfpBqWu0RlTJ5nscZeVc8cQ8eWmdImebPl+vwHw7sOR/bWN4vVVHhjjA3uNWYuwGXsjkCid7gWsFuV3C9lYtC2+x17cl/AUDyzsOAIBOhGUbwUoScCC/QUkCGRxilSRQYP5XSQJ9yv7HK0mgIfu/SEkCIW2EK0mgxEW4kgRG/P8qSeBWksCa+f+NShJYc/F/QklyRHIQqyQBB/J/UkkCNiH/PytJft7IcnQxQnwj63BQhDayak0a4WtkfV0sl4K1kQXCCvpGloJSm0qrovq380/+qdFW1d9Y4fuzDgb96Scgg4Lt9JOzEAXmMDG6YYuwVtlPo//5A+Rj29AqC24JfL/2AVX1WXkvp2PUI2I5mJL38Ok3XF4aBAh0jVmZ2WO6b5yWb8CmQ5Opcn3MPLl48EqmzTAnPzWKzl/5sp0FgSDdWHhmrWFNxRBJqM94NXq2h83T/lH7snqP4j7+VDFB2fg9bFfkpbP0WFyWXEqPcysYop58uKiu5VqlUhhQZ+n00OWCGeFKvPKEetT5tr413xQvzXrBEr00clJe5UCrFp/W/pRV9zvhSk0RFSMhuZRhRLaXbubzNrcnpTWgHdyVeT62JM+uqRS0KpaaIqHwWrc5eihw6szfU68i4n0wBADAK7CtMmYocgjT0SfcUAH8ME/6f37Ii482s8mirXfHr83n/XG09NTU1xeddJNa65DrRT0pGyV3hbB4zk4/iueP3z2GWX3bVumeIIk/+blUVIOBncZHN+gbr5sU7fgaYMm89JnoOTEXb5h5ewL7Ilsry814CZXCPFROk/cf0kwqGfRyzjDKO2/O9qKeiRVxk72XZ5lAicUiac2l8RV3WMNXYQ/3yshbe+5qzf5ofpHQdwycc7jYVy8zCp9pGfosR2lx/qZh1IWklg1nwwrm3cLzU+cm23H3bbf8vb7tz+jlWt41AQBAhgR9cxkkZQhtLv8Q+b/NZfjuaQhvLv80OkKby0ciQHMwinseSfFPD0ZxquwgKhGwpLyuopHW1VRSEzOU23n5JPW0/Y5gKXG+6u2i20WPwlwIgo0rXstfy+2htmx9xZSjszC6ezVWgatQ56sogwqp48vxL/MH6Xx29Ib6c8kX35dG6jjUGzsVrmGaVI6eRKlGmSUd0wwicN/Pj/GokiPyDjzxEedyzgKaiPKC9wXMF0rXFGRyng4D/l+k379M4XMhYiUva/vAX6LNK2owhMStQHOnbGKn+LiIEx0yXWRmgIgfM6eIN3Ul72CBbcem7vsHQkatdp0bOziu+XVL4S8V3jNeOv5hfcwxbjLmivrjMs4DpKvhkzFfxOnPsndX7qydcJvvz1sfrSPz2FtKmwlA5x3dSph+ukSfqjbod6c6N+Y83uWHzoUH35beZz8MVA0kAJCCoWl8xNQhtmkMDuTXTeNR5C6sU/pJoWhoyUxYL7Ewa01kvm22MPUTDvVLxoS8ZHn/XKXQH5xy5BhhPziFHyYgWDc0YrCj/bjB+empKVyhiVVcqnzPvz81pRh3JpytRO/FV+Y0fv1joUmX3JlxJ4l8nJ5uAXr/nJpC6Us+1DMTvU+rzMGEp0t8mbnr7N/zpru5oGMJAMBxJOjFhJAT/OHIlNAii2pxfGnLhUs47D4GOgGip2NmUSWekmfcvnVZkbZ0YKxcgVPygIoQ4wvKKNMx0yFH3PYDSgfcmJc+KunGfOZVRTIjNKfw1C/rz7t9iG2RUKv4wPmh6O2+39jX4Oo3omSpAffUrx+0PRS/WSgtJZdwnPxyflnV9lcNt+MFXfPTSpKn+ozJeHLHoj/NVS/c1qs3txumtuwn7BPBZA554ExBz09v8+Cs7Yqk08P0enXRRIfne2mka1Ub/dFx5jG12RRLq65CHC/wb6H9ncRYFdLhZgAAYpGgF6FCkUQXrquOhu6H8ygdUmVRzYlzt71T8x6FrMb7OH3XOfK8p2VnL/a2vNSXwWTLWhB95jwgce9gbHLnySNV6hPxbcj4jiS8s6nm8kFLHy57Zx/vbGuul4s0CLdzqHvNYFverlGzdXmw/P1+7PmrGQM3bR5enkJSUaSZxXA9xpQdSTiz0z3WOXz+GYtobF11O7Xalk+Z86mw/fW6WCqh8S3qFpRn0y7pIkNp6i9lsN/skswPZ18vTDS/ebfem57B7e2lb/cL2truzpcAACwj7KmKSBHKkQi/Sa7xczzEilDAYPyrrBArQgGD8ZtEKOAQEShCAQ/zm0Qo4EARLEL5NdRvEqH8HBjBIhRwIP+OCOXnI0C0CAUsym8SoYBg/kSEElTNiS9j2c7kx5LzFH0dS49VL7MRzYf7AQlBu9xHIyOM1552p7U0MvduDnnydvBm3hAwRmrQb86sk3Tktm7y0G1L/utAlPrUojFaNKl8gcLuCu2WdPtIztHQ4FvYHeU0771n8B6cJPq6vrSU71diW4WEc7/j3NB5R9+7JRsB4bXUZEVlNQcye7F5laW6kyO4/5yt9u5VpT2sIpTvaCNYhPLT6IgWoYADOeJElFaVak4c7wX3P09EMTUwFBNcwij3GSjRrcqXGrUZnVO/JpeEL1i7/UU1ZWEkLyHIlb0pzj5b1sFJ4u5oQXeZ5Jak+7kGbhX7cypK5FmCXMzxthPHgbvhOcR4a7peVqpnLQG6Th9zDwkRz6e4Xd3lpLrMzJeCI5bxSkN64sQ80Bu/0CqWj594UHoRJY69ZqSKdiX2im/etMSKwoHd3f0Nf4bU62H+uYId91gs95AXX5S7P1254G6WItP9qmx+ydxLQHQmfH5gMK2PbyB7zeDVoJhAVvr6ub9Xw6rKMmc/AACGSIiaLwTLWMCB/AYZC2RwiJWxQIH5XxkL9Cn7Hy9jgYbs/yIZC4S0ES5jgRIX4TIWGPH/K2OBW8YCa+b/N8pYYM3F/wkZyxHJQayMBRzI/0kZC9iE/D95IMrPR4zQA1GOhvg3ak/fAO0cbJ1srzubIuyUAPAwHOx/EGMzN2WzMTEycXQ0dHCHlSULFPCO9la/p757GIHD2fGPhXwIKrijSKFanKJ+qUJ1aTjB29fH5zRlwdecqi+0S9xO05SNORIemLH329jft8rkddTKD87is02t0HW+Cj/19D1Tl+32zYCUcSNpLrVuV86nwkRBdzqRrtnXnH7Q/7GfhyZW9yaDDGpNhjhyPRKxmq0xUXM9OwMxa/veoM2tDQ1l0vXUsiKrTOHm99Lm6LH6/pP6JweEJpifZb8JerTsUhR5KTCov3F5Lft2uU1mcDV2Y336wzyqoelJ9zNS9CWkZwpOSutjU4ah4SyKYiU566mYjk9e4L11kEwa0tr1OCvfVMZZ7MAs7NaAzD5+6CJ+8PicaT2qEq6Vj+fL6MbUg0vPcCO8fMw5eh+VeT5M+XZFnudapsFGAoAyeHvtEJ+ZggHLtfHt0Ad4S1DEP2CZ2bJb2/5TKYyOkniWyIlzt3ecmHUAjY+hcWbm5aUpTAq14CBrdd1wu53QKKWd8zjGpYY6N1NWByJRnKMC3qetdukWE78449qJbLiqnYpFnMNIESMbv5F+bZOXptDdtdNRsy3kfM4Ex9rrzVWkXVH7aGrNaXVstKttsry57MXsXC4NHU1ibjPtfLLBKgED7WZrhUK7tVjrpfSqSYqJXVSJtJhXHoiJ9bkNEFBoJVPM7Lqjir0xjnJSfdlneLLi1TbWpPQcEOlf8SXUvKHKE/ONwjsB7esGuRQxjvkWJnyt1yhfErM9o4qXvSYh93qwzGMgQvq6aOfelbk+KRujaMFybU7diPGTMwOWyY8wLs1mejE/UvYXxukStz/NJtgVo+5N3f+yViAqmZbB7qRIgaxckOw9ZCpkDA4s+ai3t9Rb7Xmjjl9+ZLOpKvXx5dNxN/KHtC7b2UZXwi7Hrz3ZksuiH8zxiCUsEQmK5+XDVTHsvn/8SmuAg2je+rTiktDfkxfXqM/ugAQAAqhQT56js/W3ycuLu+A41hDpvbBwqeUhTVVZiNsxNykfVAzv03a+G4xu1VcrJXLMYqfjknvmE+9LPip809KkZMzFkn0Td/hMh/gn4RdRvGHuSMqpOQc64a6rlPtnLuzPnO88GTQ8YPByI69Nmpy7oO01VZKxKd2oU2pmesF8TkrIYuXBmh5t9J0N9BpVzspBkTXhRadC0ussx2ND8BitzwrI5yzkj6Ua6EiPlgckbqFRfDDseCmTKNGqLYm9Xe/zRjOlgB37IXJTxFZqDOHoJyZCq+vv3C22ltBfdgi0Cblqf5opuD8s8aZhYvLdnAFqO56WU4dR4Gf5BpTeF8S8drVvlVTYjH2qI1PHyBwoWOWjx9XQh+rYdVN0xYciztozxRMmRDy1JbuiVNw8/UXzlmHh3j3KuwpLwqgsIr0uJ5i3JZV8cxrSMLqvbaYSpKRdihU9K+KfGOr0tDAxCac0OEgkO9wUfRv19IlLadvIxZ82hT4pfrRT2dwT0RJWTy25KXGL7YbL2igdvWNSXnmH9Eypg49RyMyl6Y8+OXIbB1uTjQxiygMon9ef4zyKwP4U+gmHX2vULs9pCCdTmyEkmtzhS8lY0AbbxP15HSMi7qUChtcj29cKXjxZStP9Uj/W751mLHW/MMNF6NnypUGc8g+nyVMnU9olZa4+NrFyKCNoy0hjZ1y9MV1zvUSjjF5U117CFOg8ubO47o2/zn9xN7D5mvTLzWJ8bafnuy+61RpMV31lXDQoHp5tJC/zDTAKOhtXWb3nGzlGfHBy+0KF3ny291Cbfrekp6CPKt8TQjqXVcyFKQNH8q6sjMIAk/A93A3avingMsO8ZM2VuC+XCOiE3F1DhaJ1HDWXdyMxBp3lFgfUdwMTstQe7E8pjWpymbgrZ6Iq02DraX8RZmmj4m5/M62KkrtumkXw2E3ntUv6AdU6rdwcU6cr58aNrs4BRsvaeHTLFn/yGBsTxfx3SnW2YW8JMlLiTj+JMltV79orertQI7TyxUBNaC5QtHoHwyxxTZsDG0elNiRGkNlcUFGK/+KUcs7b2y4UQaW4qbyYF/C1GldbxsNU+IO1CjqWJQIDO5HGcSg3z6+a9XO/TC80QzW4hfJO9pW5l8uu5YTi5lBMAeYpmw0mLjLt4nM8G/E7bPVSPgL3cIlrrOJpcwq+iA22A7lmZhOampUhXWpOtprhIbYn3SaQ9ync7Cwm33tgGTR55yoaOp4Jls8wHYx7Ejodjvk19gH/qwzckQPyXXqgO6ERiUcYiebVTm03yobfPE1gx2xMxn3y0zSfmzhZT2peXRlE1SW4w8eI/phcPBZHMyK4fbdj4UuUInHaTJT/sZSMr6xl3tkqEmzd6apX7Gvmq9UwEoRjaFaQ3rTe6hwqSny5uJPNuWLdaXUpWneJzlDi80PXsRNEZtQoPR7UdIT7mGLKcxc+iEy64vc0nqNvEPK5xXOvZrSgsjbdT9W1upJyrYu54625+wA6J2U7brGNPPF97B3lactHOjjRrHZaZkl2teNfbYYXnLzZcvOcz+swh15pacD0LYvc4y0/4Wve76X/2ZKbWbUN+dwcYbq1Rvsl3J7OExwECSM9qdmxp5RTDUr1mtcyvXx3O+8mWLSnxb/bHifuXXZ+sx7gcMr/fM71dkbkuljZ0DaaHs7bEYGFDWS6G3YZIR7PrPeeUZDxdRIrPJxsuG6HPd7ILSKJTDJQfpxzobCx+hODJYHq1tndmPy3J56ZKzOKs3M8NttSZ2cwYtHCxatTj8A9niDYwxmQX3D7fgi+aq6jaTOvU1zCW2tSIdEH+3S2T/SYQ5Lt29gmscqULMSaOScTu8lM2FRKCfOrrnzpDRiqJZX9xDJF4PmiyaMp7gxqj5C4ivrszLET3fK8l1LzAR4RbBvKIKaTonibT/nUBFO5kKp7kZGCZUsF3+tPitaRY/annh9jnVYqSgs/27lRVbjzsDOiftsi+rNLg4FHYQuBLlcA9l4pXYzuB9oLfMtBWbmFGx95G8+cGDW7MkqrPEN704V/VzDH/o4eGoFocxmmAL1wfHLR5VAkt8EKwqRNNRZGGQsx49bCGGFibO+JlyeiZs23na17GoprbK/ffirnZWHrbOlY+sRHoFVh2/iKEuZjvo8W1v3plb6jKc0Y1o8SperZzWsqvDV0c7q254TJ1F/mjPfwbkb0Lz7LqL++e3xORv28UQ/31DExdoJnn1TNHXNWHXWG1zCkX4T3N3Gu3CWyXu1lElaR4pbZApQbNyd9LnjdnsUTvDvYNOV0DtWktOZhdfv7O015unUuusqPOsXLZZiX5T1pq4SmIl0UpjPlsw29OADU7C9jx31GUlxR1IO5F1ZPZft15Mom83C7ut2rs7ZuNz6f6Ckg3rNGFf5633NEcRbAmxzHtwwLoRKnEmwstqcUW5hUuUxlw0XLM9ej25NMNNmrfyP4ySVdqZEylVIskVba8UDdhoyCyKLYYAkv/Ey5xVgH1OVnjXgLnh1kn+203N+xBzxXSkAuTBqsrY2J4hZkKKCyyeZ8afJmVrQ9eZ+BoIMHVX05t9zl8RArfajSu5Ln/RV2aK8U28ey1DZOZHQ9ZCjdOyEvsmo9e5+HkjXf/TyVW3z6+kojJqEwppoyZ+M7UeORiFe3X0tVNzVQj6sds17HvYvTn7r+euPtQkNYr3U0umUphZaQs2ygKo9W592O/lLju9KncpYfD5WxsA5bIe/zTsnM0gwJ5/C65955kH2Ofin6AjJtaczVYfnsOokU3kbxia8Re4H882OTOj7DaidkDE9J4GNJ2C+zHT/DfBclOM13sfh9MPMCvgG5Q65zZOhkepAAz+yZCs5+/GeDW0loLqzYuQ/3JhjRswkIL6jtHs9iRPU9yWyMsZwiPD1zbk6sjkYMPe/DjEa9QETOVlWaZXm8yAOu52tyWLE1dkGoxT6JhAt9S2R9t332CYqY+kSbkbZ4hIrmnC4GPJbPy3AbvK+IO7xGXpc0T5ofFOwo6ep7PlNafdRLykP9OVlGwW7OqcH7oqKPeYzbFT98LlCxDW9GweDheZTyrp7GrWAi9cmzjXT/dOHA3A20reEZWbkvuno8Pmk15Fj1jBGpPMHV1Ff7RCZt+9rGAHmbm94qt5XpSYUpWJHCcUgt1tgKLN0JozL2D4S+rE1Si5N+VjaiZiN/rDXcuWVVWGy6LBocTi+Xxig8xh+7SLXYrOvZ0b2AvV7vs7eVJ/dKD6URb52mdE8+PvaGxskvN7jcb9uc2kD+dPLNQLKpuvCOYtv9HoKUjSAPNQqOU3tKQceSayqcJGijcqm6U7cVP/NM+sYFblcerA1/25mfy/2QHIkJABJE4N4xCH/Y3MEorqb6aaA/f7AZWZmzW/8T1Cr86hMiLvzaFP6U0acbGqylgdsfJbWwXqLZyyxJ9NPan2u8axr1LP4l1t7is70z6RvWEy13VoTOUD0NinfGmJ4ZusFgh/zKLzWe22jfEE2FSY5GjG0mbJjhhg+Z8iKRenlrzeMbQSGMKjZxlgJCVjLN5e1EWUmT64tSfDma7IJPkrRE0N7HPytlYIxS4aKzjn4+TJ0y/kDSWzHVrSa9oDL4gGz4VjJH/YmQu5nZc5FVKylSi1oRTbqblmcvVtpYDBsKYNBQcdrm9ElcWKlfN1Z0LwuqnPC6LHR/+t7J6LSMoAD8RQ8+D/+Vk0PXK2S3NrOlSTDHmwkH5pw2rWpkARkJ5UQ19veeg51ob81qalwZuDnCdTeCb6Wcoh3L8BW1KyXn2SHOih73z5xaDUWfbjbdW/3nbKU6z/B6HiQA6ANbGD519EQcngQ/reGwUT7821cOSLooYu550GhQ6859nXpX9MiG7IUY80MF/yRjZPbQuX5cEpndhRjrZ0ilfWNVwSIplbbCVKroY42xnc17Kw7nyQerF9GfJSz5hOMtpmNZEGQv388mQSZB47QcWd9n0cFMusxDGpx18sLHdD6lIKSTLQumeMN31Vg0ntB8SToex/nAQaVAtFDhMQldd9HBqPFpI59pyu67gSRfNKKttCwt4onVLHSrEiYSefLwXF6M5otjdIXZNmw6yy1Sn+V91H9arXb3pDajWpnvuIYOm+CFhwnXu7gntR1H7/K7XWL0SbnpbS7FE6PGHYqukGMonJA1pnue4EGfgeJlNXksZiHGhxu8HeU9p/zRssavxunp8K6adWY8ZunavExZqbT7MY0E/+GSWNrQs12/Tj80h92Fa9Zqcx9IuYdT0bU7P2AmphCKXeFc2y7JonjQnsH09vjqtmlIUnWQbkeJcnS7cmRccTfpPEOGPQWRNtYu+TZ1e0edhh65HCG9c2gSN5KYlwL2p+z0CeHQ4XAHbWHGuJdlcamMOlvo92I6BsTCsgPCFi0oXiVHtl1Nnr9cniiobySQ2dzHJVRRUU99ugjZY29pdr23cWzZcHWAjmp9PXTHbjBC8yrui5fP0h+MR69QPu7PGxwQfsfD7B6xdcc3vKe8vDXIZlFuYbRU/mI4dcaogyvtLFVGlEWQs6ZZnB4u40slRfW0p2drF1yjFjfail1NXr9lc8gZjQt/0o7ORud2HNtByxorm0a9Y0aszbS9eam3XqBYJ8dJk5yFZZ3jCkeD1pUkJGZmncC6bJpk0sQmNgsVV4a5udiogGE8m5UnGx81RSvOTOhd/Ej8DEk8ZlRIrmlh3mHSkH73c+417sqUW9hagNgnceKqlN5rvYwUUzH66omFewqjFvVVKRMZA/I3W16V+a76tGaQSO/IGBNP3L9RclWanaK3rTpPUhHbwjzOPoGGv4od2ZSAt7DVi/r2dmfN/amR2xFiMo2SrSU2E/2l79835bEfDNcmvfpqY138OPhxXkbr49k8RwO1sv1xyfbHEovU2ecur4rE88g+krY7IPv7miuO7HE+gwIAJ4+Bu4uS/HDNOTuZW8Em9KI6Khbc1dDj30cGMzokZGKUf8bXpcZ1nuJPM30AoAAwv/27zDt//AQd7R+jNHRycjC/7uxkcrinCRrysHv/CZCQtj8NaW5mY+tgcmS4wx79pCDhRJC+D/fDh5PfBzvsnU8GEiz7h2A/fq/4T7Sf++3/5z98YE5CDxkA675/dBwqkDgZP4tzlPs+KNXDnvVnQahu/jLorxN52H6eESR6GwoAvQs+uIzQgmTEEBWAztH+6MCMIIFLIQr8g3csaFoOG7NzgaTlJBoAh6M9OBosIDSuoAMwmr6DMjnsdc4DwuQtdAjQkTkDQubDMQBKK3VQEoe/fOMAIcGBAcBspQ5u/GdBxu+ICcBgNg7pVHdCHv27b+pAs3TYvZobJEvnsAB4zMbBUWEHoTKPDcBujQ3K5vDxnQIgbDRxAPitscFx4gbh1Asd3I8fcx0NJAACJH4cQIQLNmgaD7tFS4CksRAOOHA3g//gHrZXlgHBjcIFEOxM/T32YQ9iBRDsfjzgd9g5Q36tcxEAMBofg1I8vJ8Eva1HQYfw454VHBk2EDIohADMnsdH0+EDoWMGLQY8hPqgAPv++x5ICYkQAfDaHYMjxAlCqBBqMGPI1pwgCCdSYgABTsfgaPGA0LoPNd4PX/UcTU0EhNo6jFDQ0QN9itqSALD7G4MSO/xpDehTtBtqkJ980AOOEwcIJ21SAA4z46NnC5RUOfQo4CbqP3CH/X0ZQOA4yQBofYwh33TSnQBgMAyGdI35QB79x89jQPNz2PD2PEh+JqEGgXqjDsrq3CkAdlddSPdpcVCD/PQjkqPhREDgjpEDCHPVBZ24w19HKINMnCe8mEd+RPL9GEA+WgAZQwEF8Ptsar8fxuGPCEC3jImUwO8wkAU3/xIg8x9JBSDUyvVoXHkQXCxq4LdYuYIm/rCWXgck8UGIxD/qy4Xvh3NYzn4NZDioNMC/52/6/bAOC8n1QYaFTwv8O1ajkN+E2c4AsBt8gvI+LOUG3XJGQg3yMz3793iHhdiHdxZzdzLoAPj9M8HlkBUkh1r0AKzml0fvlXhBMlgCJQR0O1rQvQwTAwCD7yWkCy4A8ug/+l4eDXIOBGQWapDvfS+PnhhhkInRPgsgxvcSHDleEHJt0EP+YHl5ND1REHrnGQFEWV6CI8gPQvAF9KBQLUghEDRaJgBBbpdHJ1UaJKnR8CFCl1rQ/SkxM4Awo8uj6cqC0L0HLyZ0hM+DboxYAMR4XB7NVgp0Nw4XIDz1o20okH/ZyTy6fmTICiDA3hLydmzPT/GOcLYEJXHYDxK0HcvCBkDtbPl99MPujqDtWCR2AHqHScg7dBG/Dg9jh24Gsshwdug4OAEYLBUhrdqHQB4dbIfusPceaIduAToE2Dt077kB2I39IO3Q8Z8D4Df2g3x6yqCAg62pQskDwOfhB3kPIgQKKFibKkvQYsBDyIgXgNm5D1JC9dBiwPNQFOQD4DHtg/ShmAoDDDxNFRJ+AF6/PkibKt4wQsHTVNmCAhPmpsoVAQB+qz7ImyojUMDB3lSRFQTg9+X7Hu6wTx1oU6X013CwN1WKzgMwGN9BusbwhADYje9A83PY+w20qeIENQicTZVbwgDsBnOQNlVGoQaBq6miLgIgzGAO0qZKLbyYCGiqbIoCv8+xDfKmyrgY8Du81CBvqnwSBxDqagZpU+WiBPBbXM0gbap0IxIf/qaKihTw71l9Qd5UuSwN/DuuW5DfhF1lANi9riBtqnyCGgS+psqcLAC/lRTkZZ+UCwDkPlCgHA67J4GWfVZ/GfTXZZ/DNkigZZ8mOQB6PybIVfhX5QHonJUg3WeVQBT4eyMC0KwcdggCrSmRKgAwOyuB48AMwuGyIgCb9xAojcOmOqBFnzKoAKBiAlrdm1cCoHTsgbS6J6cMwOzYA/lqClYBYPC0gbR8NA15dLDVvcMmKaATraQKwONpA/lT4pg6ALsDCyibw04noO+DVlCDwKW/x9cA4DNTgbRH6A4TEPh72GHfETFQbRzsaGDuBP9BPWzUAdpKatAEEOpw8j3yYb8L0JbdcS0A0bYgkF/i4toAjAYbkFaI06FDgKegSngJgNlbA9KCqgu0GPAQmoICDNYKsZIOAK+tBuQV4jdQg8FUIabXBRDgqAF5hTgBajyYK8RolwEEmWlA/vC8DQUmzBXiMahB4KoQm+gBcJhmQFohboYe5dcV4sMmEqAVYjF9AFq/DMj3mnwGAAyuFJCusWjIo/+qQnzYVgG0QrwFNQicFWLpqwDs3g2QVohzoAaBq0J84hqAMO8GSCvEwfBiIqBCXGkI/D4zBMgrxHnXgd9hUwB5hTjDCECoYQCkFWJyY+C3GAZAWiFORCQ+/BViElPg3ztFH/IKMY0Z8O8caA/5TVj0BgD7MfKQVogzoAaBr0L8whyA/5R2yGX3phYArEesQyq7b4QSAp73kPOWADynq0OqT02DAQbc6eqQv9eftgJgPFgdlNvh475B3+t9oEP48WB1yHeem9YADKeJHz1JnKBfFdgAsJ8m/j3M4XOpiUFg3v0A891B4t+HOnwKImgoLzsA/LHW4FJLCJJafQ8A/CGKoGM6fI4fFciYsn4a6KeHKH4f9PBBZadAgrLfBCA5EBAcXRIQuulewC9POzt63YAynj8qFnQ3puOHBnggIecNHHnQGRr6H/+qBCgB+pQAINj7jz/9fwEAAP//W5J0EHvNAAA=\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/packed/template-single.go",
    "content": "package packed\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/7SbBziV//vHH0Kyt8jMyDHOQTIiq2TvlYwyjnnsY4eUkS00RJRQNpGtkr2JbAplbzKy/lf/37d+jjhG35/ryrmUXvf7vu/P8zz387nvj5LsCTQSABPABIKl4FrAji8a4BQAh1rawPThUA57MysTGBQCNjGD68PhdmYGDnCovboaOoBCmXTJ5KNKTW2DLKSRHdzaKN0gC5GXU3zjsHISDQC2t5VkT2K2KXFdpAIAgAwAgP0NUu5j0MzEytoO+tsYT5As3l1OnCsr9iRky0yuJ/CU0DnLSP1fVIyPLpO2WA1IWSdIqna6g8r4WsguGKeKT6uLJvZcNj6p9ele/fhZLzH5vgvVVc9Moi0JqxKiuHDk8ueFi9TFdO7fGSFmtPZygPRTgIx0EwW2fWRZyceJP3rkhrTDXD6tRi+uYfzyZ1J28oMnAADpSP05vYc/8voWUGMz2H+9wVpYwfd3msdRUVJSylJXamVpkmqsVWZhUWz9umC/5ICLZwN3RJcFJSYkMT0ciWSxLSzAWF2VrLqbIDbElFyILuDPlFxUGeUyLpAsowPeahrIECv4Vsi9GG4vo6pCurR0nigip8zbyk4hSc+KlxdU2gcTBX55oT/TnOkEAEAiUi8o9vBCRULsirwEWP7KbzdUNGyandhkGuTVMaUbOWqk2aXVbeohKphNDbLN0rgyHDWjQ1jsjXJNGphgaXbWbJUvH9VrWEAglryPnYrNiifM2ushMp0QtGSU32tGLJzORwEAALkd6oA/1BHvoU7fxuy3rp+knb+/P4libxLEFAqDWR/I+zNuZ5Hx/vMdbPJfcG6IvPmkKIF354QqyXVpfBHci6Iadh5o9L43X1vLTs8TmF2ncQiSr+m/+4Dd7nbCc9AqS0qdQN/G8n1701xyZ//wroST1TQMfqZU8UtdujaZTv6SYotdH9T8sCZxY3m1+zJ6LSU8Xwcyz+h1Y+Nx48iQVElHPH/GPsvzJIbjXJ0d7dRcXupF6qea75yYh3myarcFrojcGwYVMJU9nYiROVssd2d5MEDP3Ns0fLnv1ABI+2ZrN8VnXPXFRDZGgaHPyRlk9TlUsiTSI3GmemIqRW+TwoXHzv9KpMOliciOnxcLCrLwUyENlyPXMTLAdADyzyTAGrMV7nLhoH0p9MCqJ2YPvtlADNfXN0xds42599i7Ivk6/QC1MnNCyLn+/k4XNxNSoUsAyaQl/0BZSK6zXuZ6ulZLEsgU62V1GEY0GlPByTlZciGp9GktYdsf16KHyafg24xNzlNTAio173DFTZ7ex/Msq7B3C0wY8raPmi+44mqGrUrRNl8kNuMTMreJ/4SPjo35vk4TzWttpsjz2plEZj9YaF0vrZ36FVii61SwFAAARpFGgWyPKJhYgy2tjX67HRku9jCaE8e38xsJey86d5iCiXEv2xIaHsvVyrxX7FIF7nERLmaCoCWHcsN593APLa/1bsNxKb81TOqTw11Pgwwel6inEUmMZrNQPcLlgUjQrxoyu/D01bJbFubO4TRCJgznB/nmJtmV3zWa0b2gulXIY3M7jycpoSvi5kvPL09Fek6DLhKDP89+mpTfMnqA0ZZtUpsYDXGDBaTBr8+KdHexzRQsTFV8VTTW5t+IkO95l91LT43tYt1IEepfTHgBW7EFhv3BkOZWy5fUBHHVxI7EOtvC9papK5gdytWt4Y+lncWVP0T2lr5fDEmgtI+f1JtuHU6Xz6HezlB6nWIxYmG6MuI6DA1xTtLzi14oMsuqtqURCIHxhMLJVCKjvy81GXw59SK++jYrG8EZjRKaG4tr+tpncqU3V+N8A6Zt6ud5L960HTEw8Fig7HFnTR8vWunUlZm341jOf9g2djtey3Iui6ruG/C9mG1dbQPnV+aSziqOW6IAAB7aMTJn72D5O3NpXdIRKVKdJ+fcPQOKz8mMlPHFk8vduc3CfUpwJOoKs5fitq96/+Y1Uvf1jvMwHE2RLZeFr/QX2KpuYTkRmt60muhtjfEtuS3Z0i5iDPebzaIV+OF5W3jk+t0YX/RRVDxzW94XF67Cza0e9MyEEAkNFlaimVAurlu/IxnEmaIkENH3KHSRLB2NWs8m6L3sqbd6W0MjXLDme/obyzTsQKmYDhsu4TJlagxL7VyKPnYmIUMRY5jkbNi58ddZZC15FSen6em/KwjTYYDHDOvx8a59CLyYHgMu7vzO6OF361T0pI+bk/JZvxTMi5V+lxTLaAqSEl/dZsNjNofpnxC1v4Mb95X/cQRL/SBOCa7ugrMGSv9zRVvwCpPQ88HSpy5c6k34grST591K8fnbNV+PPnceL3xY+vKFogFlkASe5DOMzeKr7uzuFqwOmSb6WuKsr/Xs6wUmr4Y4Zum8STHpKEJvFH6X/uziZoCblmOKvjHn84H7QWHgh1f88NUZ2q2oHlQY+P/QGiR0Vc6b2Sh8Nt5yJ1uq891boWkRXn/lig07TClye8seWWLP4rGVafjz3Gopi9PB4SoYYWQ459c5FpnAXjbo7I8Iqy4mf/6sycLyXF1I3MZZd2M5Ie3hAr/TRx2juMAwr3xKo0sbG84pXS+vchje1YYM8uiEnMewln/62C1DLabiJSu4Biya6+c2BuOs2xKvjKNizn2xGMZ2Ep5TI6iZ01ETeGrZH00CxjSnqmam+uryJvUa6YoIjkDQfJys56xTm66RTT43+fnsYhL6J5U00lia7h9VSy2sBl/enYj7wF3jUVnqDVMAYiVn5Kr0Hn/VJGRkc8j5RKrQkAxy8VDwnuk55/0i4EY7u0/OUmbEmsftqZQXo9P3VUN6yHJYwHMqMWexgi+oOW4INtdfwBkmctKN96zSQx26+aBOPUKyDU0OGparF9/BlPcdU5qz+8o1Oa/2CQydsdVKNK2nQpq0F/pDKbrvF2+2CRpquJ6bpbANxcxz4f8uxCDKRqUxNJbwTQ5dm3PQigorZm3ou4TuyTmGUycJ1GtX05jWsmfSuqvIlK93U6wEeMZltCVdmgtyvi3txKt+uVZ8cjDdB3dWe6R+gbzkon6dGe5EsnhW7psHTY9pUMkWmZOxiUbqKbn9a06j3xijUWuOiAqV3+QNcm8tDRbjLYF+0cJeGu5jKOg/c702jy3nCjrcZ4aJlmmu1kJwsyq0WyP0DWFsIR391qUNKIpHCTSZ3QpWNG3dzkFPrGD/oecSOL/9PC4ql77kdHdOu/uMP3NNAGauWGu5Ln5RAm2gkXOHX3er4srj03xxHEGv2pblybJPpSiqwXsteu4SkStryFLbBjm/xRzI73/UJU4zS7HgSDH2OjbgjUtBbKiUt+Jz6L3mbH/DdQ5Idt+JGnIPqt6VDLemWbq0iNDwZ7N3mS9leU9Csp3pqnorndojlglO38wvgaJ4+5+L9mCXJgm8gTHd/OlRTW6hXwRF8kQQcYY3z0Bab/CpuTUWUP+pBtLqhqtGfmXyTVs0EN+bVJ0vg6aUJiQyhEDYQbmyNXnSl274yn3njmFgp2/Yehxrwe7VWd4Yk9kz3sm9POAqy0rnw+lvzqZ24c5n/yJTftOH9GatFcp368OuUVXCdecnlzc51og6fKhGVEIfOlxsnmhgDpCjfQniXvH2n1eLSskSrSazRtk4ZyfypvbFveqNE55xlNdzPkeABl7K9lVGQnkjyusVMM+stcvn90xGeYl8uMouLmLmlzkme5OirFXCTBzF0WXwlay2wBk32Qy7hHevFlDMsxp410EwxbhzVK8izFNEtVGcb+VVvIBUJWzP1Z67VZZwuww9xpmEpYstMvpFo0NR9RX72+QFTfwRHWa8JAuMP4Q3XE8UwyOv34BAC0QL69MecD3D7xsRfwcGuVxkvc+huxCQmNr8YOaJEfaPVa2HBVJtRZhxo/hrj6W9319CI2xN/ATEUJn7Ork8XkafO7ciYzfkmPaFJH0z7ILwSg/ncu3pb5eEmMvjNAlHhhtPfeOfibw/ooPmIlT9tFHx5L2mBukPmuOPQ8rRv49cvh9aZ//1LvVYuKPcRIJ0lUc/KYBhuOChfdU/NIiz9NHLBy7eIFButWwsD9FJy6FKl9yLDxSqKJezXErR1Tx+XFhVURL1bsOprMvjvFTDIFjImzE9upIs2BCtjcNSXuDw8I2rwXafj1+BK64b4WqGoI6PYHl8Yl4c6Ds8wQBCcUeQkepsWVw9itTiWcuBlZZH7weHayI0uieJoJglacU5sjVPhHowbL2pLp/u4Y7TjDN548mCJrQsFlly1QPelRwli0rtow99oD2IZfVooryQP4OrKYHtsmMqJfXMXH73oxY5znzfJPGSK22pGd1i4owoSZgY6teUMPJKvteTztC6jZdSTzxrdHzW/AXdKs7a1Mhvk5C49EqZCvXpcH45frXmPlt6+cx+kYwL+ZbKbOvGhFR4sHtCHnilaOU4rkpCr7snGjk+teZURmvZg2kzxVA6eh2/ZU2ank9h8MDlTSuvnr8ywIlWToAhoUxZiTnBgctw8SrqrWa0QYuXuikllxVl4trSn8KFyNUZ27O0XQfY3Gsci2LRNdhPSbKtr0u6bykv3LAf23qR4MQtkcmtQRZ1JxaYdHxs7uDcEXaGjRrGNoYbl2vrewdzzn6M6fRUl8tHUi877qmQ26JAm0co1ukBtEhDM8lMobj0u57ZDMuBfMz16zSb3RHGcAZaUwP0Atv800pKLRo6Y112SsR3rzVe/cDgDeP7xBHkGaYX/zzIkzfEfJSraKiv1FzpW2sANtWDWgMhHdkQ79mURLfoNY+uYtZeUg6qb9Jq08ZLN3qDVcbsyylIqmv4cPy5uMtOe4sO3ECxaBLsriMG5KmE3199l0RMPE6vCrTT4D/o8Z+8Tll55dKmCb7L5gqgJDHGMtXxuiy7yElOWCv0OpczrVgyUYINyYT3cPiAb4mQBe4TV75hEeMNl0nnd4wcCidkzxT7z+hGvBSgDHVTu7DiksEX7IYx493HrshlFruZvEgky5T0Jp7vyXBlvXv8lXsvMSFPW2uepQbPhG7pdAXj+Uc5/9jM38b/VU2B3LwXUU4BwG1CZC8YJHtUU6b6hhbHeLGg2wcFMbS2MjYzAbvoW8J+Y6+ElCqwcZF4r7sHKH/sY8t23JIKY2NkZcTC0nufrRhE2lvdZXJ5eVqZhDFl7UmUtS+T3oAefcM4is7HoGtfxsX9LZLOPrPzD64P/pRV8VJq+urk+5fG50FWYm6OusUkfjZ2oCcomGpWKM71TsDVhGtNGIFCK5lGlDmPvxsXu/XRxsZWfvKcbBRLb5dJb3Qs7tnuFNclewd9r+rEoeGvIwzjDONt5QRi+6N6dO1iDBYwAls/GL/7rD/FNw6vvEYfyXb1x1vFANzZYIV5mc3Zm7HqDbxhKW3Koy65b7Z+v6lfl5ggHfgZFpRjBe3nNw5DmBnY8r+5gIXdSCXmIqiM44sbylpRYS/y/9Elro6Vh24rMS/Wc9b2fK2vccTrqDyszbnXmwzxK5YjDV6Lggw0WQFRDpgTkwOmzDao+d7PorgNt/TRFUBS9CIck6GfmU3vkMvPESuXNFa8Mg0IZlGwemzBLwjjWBRWjLSL7S3H705QKPyaZqfxnUTKpG6C8pncxcqwXOUmD89bD7WxUMBeQ4SBRVvcWzdurbi8pTLkobzzJE8Wo9kTr1BTgtVkMPOB0mZRsrvfIJ238/uSROOT1I20vRFM36ZZt55sg6bZUxiMlXxDWGnE3092j5E2mTgHfqf8NhxNpM4YCZGF5bcNZhOeQSFBv2ApXig16yBJDsQREn+OqikRNe4/v+xufi8oFO/H+3GrlinVSJWH5OHxbYKUryDR39s+o/zKRMRro7LzKADQhTQTVMgysTML3uqfQ4d4CTz0tklVQ2SulBIkh6Ytw+GDXar52D20DxQSxRW4UcirHadPkUpszD4wfI1SNDV/syq2+TMfTei5zdbV+rlvWy5cUXiz+jYnzJiMmrpOOnMJnPP23zJw8X+vjneHqm/AE/0jncBzBpsKVf8ssUlvDfeOuH552re4z7jTuE/UJIxhf7snW5shDMF+hVPRl7M9BKUjDejlUFN4xWR0ndRAS0tBnI0lDaxfmeNA1LGurVenQeetFWpd0z5JMCyiZ16VfvnL1XaTa/Hik/gPzSQ0ZP15bdeKoE01MiN+fM6PXt2Jc78tfZmnVQnTHw/LUp8nhvmFGbcGo2lv+IhOTswkduTAOqWphlZgwPtrm+TGaPW+W4yuaurjlDdSVSE5riXPSAnIhz3Fiwm7CV9gY0/NeXq9EXujGT0JCya7UvtIEvY98tMwhWq+3xmw/rxQDNAnmj+qwcLEju5VKQ+b6KvI1jaTteGjCYm/5y8++Lll3fmOY0WyHUH11V4cJnIsj63IrwXSakxQklL6b+mv4rBle+89r5OYx5Aiaem/hH9uPXTOnCqPJqJJL3bmekmci46hc0JzN71gv27w58tyWEWlrUvLnfPDQ/qrvfyUcKdYN093+pcOAnMB8FppI506jsd16Ru9Qu/ZKd0frr31y+oQetcYnjkvOjtc5C8fRvv8vqsb4xTti0fmAQ66iY/vo6md0X/DqtyqPN9ZrLXqNtoDgQpU48pYxt/LTm3GO2VQ4itQzNpZmEVwZmyZ5mXbaOXYpGEkwUNmLc0QOGirclKguG6BWLT2AUuLMtGQWbb/wLMHtybDZ6y4PFbdZ/neueJf+tYmaOAQiBUtzgsUcNlh2873624Jxd8WuUUaZLLSZv0c64vfmTH4l2aLZ6Ss+K5MfDGvSSveWgktmfGWUEv66axvnDORy/ZqshqwxchxMcmKdrp1+m2wn5Z/hb2CUAOjonLRzVGU87M8mWlb4I2lF4EjT0u3HSbGsAnNK524PjcFf0poS1n1XFkYSEp9o26gYvwRe7oy4Rz1ZFDPCgetax21+KbYxeeVReQ5VQUshH3b6L+uue1iz1T6EwBAeBLZ02evvWAzKzjUzkofdozNSiokOIihpdExHmoMByB//tm5VwYPE7Po4yTwaf6YeRoefpetlQa3kLFlOVwpL9dJncZCIvE+RW20aPe2HjuEx2+EcaSxLTo0/+J2LzpanAnIUA+br0WF5carQQtVFSxSA0Hrd0GQbl8isjNkbmtG5I4UlkqzlJjRuKMdHSsciT1fFjc+s+EuPtEpx7+gImXKcMHIrnbGVEdFPM9ELplFQMrFtsRepFDKBt/tlQu7gOCTbSn6WN2qU6JQculglXu0n9BjBjDxqWyjRD+NFJQp4JKu3enLj+NbIGY/4zLdy9ZXxxVaLfhhouBsue679XT8E6ZGGEZgofd49KxyKwQNK7GpfuAoiE6eOltqFYPI1Pm+70MNyTDcQm0rivjZRtWYUW9IiDJtk+cHTUl7cWF9XWx1qoEN13s8k8KBAzEuVY/iaL9zOqYLZvKltV09SW/Y+/i2Qbi4jiQowy7M88SvZdR4z4lfFgUAeFGR5Z0WaZKsrezh9sdIPehg6j8fOxcAq5Rck4KcorpUUzMbGDSC+rseeE+O00AKAAA+0iXMcIBRuJ01DAa1O8bFAToc+dg7+9xH4e+x099UdgqVi8Bn0C3FGbcg+X1E1lnnXC9bar67hrEwZqkicreW7a3yR+eX34G/BclmY1iE0fSlX3eIaDmTcUKyKVqI1G/xlNjFa+63HVpP5RQyvJ3s16HHvUttbQGV8byf9IgdX4tUoj9K+HdRkKwk5QsDAAAPaVHAe3SnblhBnRAdKzUvFyVA+9KzTnI38CZ56/OTUkyjkgRTVa9uyE4u3m+bttUjDGop9mOUp6GLNU4JpRidW/pMP9oyRjcXnpBVCyicuIpXy89IYVM0qH4DK/TOSKlPchVW8YllP4ZYp+ls1P5vp6EzIl3YYKIXRD5cFlww0zfLZeC25AkHuN5md1SQwOva4QuMtJW2eDOS6WayRvnspjxaracT4RcyNJIGRnzGhBJp3NamJhqXnV6Zf36bmsrVlnJPnmlwMDOW/Pq9t6i/IvZB+DVRJQAAQUgjJniMiDly3fiz6RBcpuDDSSDR2aAZpNv6yOTMBjrR8BMf62CHMYaHeHInxQ02nE4U2QwacNc2Fq40uK+OMQw+VTG4bftEi8TildyXtNxUr7oK5dnJaGyhtRrbOdu53gjahLgayRPbBDJtMa6J1dwjj2tWFscUfT5TniC7ec3+/cUvid/SPoDul/CS3cBLwisazhx4I7IdII6tl1f1VEoysPL6q43gOlLpr/xkgXFKEp2tr1VaTQaTP22ezst4wW0P/mrFzZqoE50Tyvdwaesmu5p4kYwvZBXvV/wK505aNAEAQINy7GeYkb71v9Tx2Yn8/3ayBRRq85v9+yr5+d/RD7y10CAzALM2MTM8hupzB0L/t7otrY2gsH9b9/9D/1o3/cEmjI6zUFgPw/1r9UwHW4Fawc3gLsfwAHxY9l97gbTmsNE3tIAa/ds1x3+o/3zsVXMArckgndu/JxkWMcw/ER9YcdAhM2kPtXM0M4T+2578gz1iEv40Qr6HEUt9MyuEiryJK+MDJ07VfKGwRDuIQo+9lI2TDoMMfFt8gjKwKvk6ubp4H/UD0q53sy+3Hy9wcBWGX0FJCHLgHn0uUPywMqOeaeR6GNuKqVoVPcVmY7wQQQCl/BOMPpyJ67dHhssvDWxnN9V0d2QGxpmDdbFRnt3gebd4ywbf1G58iMu/qi3eQ3U4duqZgaC2O+act+bv1NyXg1y9DwBAG3DU1yNLfSszY6g9/BgVIC0S3D+bdMdINNvB1D13AINCyxTKOXF8Z+8v4CkXvNeXzyvj/VbBMIdlNWyMno/nX+yfLzntW3HqvuqU4tbmWlmMhB1uE9MMdlCXjTTYTrOfVFszWycLdjH2B73lDy8bBn5jVLF0K05TKE7FtayOmw9NymvdrB8Jm8TQ4VvTjd5MuyvEM/vg5YNPbAne3/z6ZVMfaHhec9BpYRqCP/oY4BylfQETIsV8GvtKPjWRy8ObCQ2rmV+6toQ1UjFROdR0hhmWOSPSPA1NHwvfyR7W3ExQeswEc1offVQ+v8Sq69E3ExJsfSsHd71UREigjHVZ8FeeX93h/DEIAIA1yrETYwS1gVm7/EsF/y4qxMLBHm5taeYKPQYffBQ+xEDf/ji3EeEjG/nnby2hVnDEBQcPK1VA48LxXheqLHl/Sjcazz98iNU1IgcPu9rf4ERPvuSgyRu2LtC583HMSWBFIZ0nUKVZjxUPhUyDzqCTMz0P68iS7Voe3LFDDWI1QevMILlllx1thxoZq+XOzCnmyTBQ2DBappsYZhJD/CVNJz541iCRBRJ65iMKdupiWy9OzEfqIQLUjZAnrI13KpxhAS8zt8++CO+aQFUZX56lcPSqj55ITI5kGtYTMZ2PFP79AlwQzMyfDQCALdKiW+zoUfr1oz7czNoKMVDsddm4HzgJ0Fu2kuZQuWT8SlAvldoKj9XP6361P+szDpJaS3jEJ9z6NAnU3u93wYMwcDw67tosjVm+oYf+Vy1WB+lB23QhU1ZqKzfIHKPqtax0R96xeyZWqXJlrfhkG6Cz737fBisxa6uMf14ewFFfKQ7w7p8HDKJfRo1cWOWcOD6Dui9b0FHHNXKXUb0eznxwQVOtJnpdsyYrnm8l8vGkYulbwhfXyYWtlpLdST3OhlwXFVTRlCc1mCm6zJ/t1lbBY/6Z0pS/bs0hkMpEThPrs4mB8XJWroH86vdrGbLmsJpvfiMRuDyRuWHYr9a38dx/ZzLXqyXTFQCAV0gvKu4j+WrtCLWD6bvYH+PqvXgsQxAjqCMUZm1zjCtZ+q8M/vMIsdS3QcypUPD/X9QY60KVL5ec2KntZIOvSFgTEqM2hRLNnmWkoSHk7XQRMozSdr0vrMLhPTzgnkSEGfqmJHG1ohHKhQeTw2OJ8bkZHv26FppApA7OzGns65vY4uu0bpJZtQU4E2g/mjUBfi1QnCdfxvV7eT1TehJsZJths2ie1Ry6Ilc5ZEMhIco/Pp5z5XvTIXJNUQ1PmUAodaCJo70fs8PJ9t3veubc6wXCBAAAfiCNkczfxWi/O59RY/bPhY/W0n/DVoRARrN503fmrMCdV0yB19B+rDChOyUzz+PNMC7VGpquYPmfzl/U05vQrrzb+qN3TCsIFJ3Qjlpwmi2cTD68XunzmXrMDM2Lmz+8kjvT+1XbXYJA7xcsL/v4/1BEudC9LTlRFZFefe6X16KvxwUcAADIQeq1/N95jexO1iBv7i1KIDnv/jQectO/uEUTUwv9NaT3XVLL1rNUKhsFEZzhrZVYns3LfOlMvps8mVpxX9TqU87M3qi6Xl3NUw6N160nKl9Jr3hDFo+XaqKYJXX5Jk1UtRYOj3czo+yw7IJYe0WbyFRnMT+vvMjYmYFPdxzb2V6scgQaXYvwPk2WZkejcGUJ61c0NhJrNgIAAEg9fpVmZG1ocYjdv8O92u2iQq78/wfCHLYd9sKKek2tohyoQ7EBVNMg+4a7I+fLkEoS+IuKBh0gtHnnMpX7LarLQpubr6wEH6XeeCxe4BmWH2hC4Nv4wx8dXScEDMaSSK5cS5SoTR7DUnt28XtZytKSrIo99pI996IM2xCxvWqD3JI98flFghRRoYxnSiI+X4P6NkjQp7F4QCnrITe7WFlY0Pz4MXyU+o2vhX0Qqvk2hY1Fl8WH8vvaircKHXkOAIAW6lFfSHZH4D8fYHvTHRPc7Yp1DW2KMuxNX4ZUNDBra9g1/jOMXsOuIZUuJQ/mkJZXlpKRr4fIqEvVKjYpcKhIsTY2SLcOo57471D5/RyV+csAAIgiTT01MolmXPxWx0g880HM/8luxG8LNnbWcGsDB+NjKOc5DBcC/imdw8yYwwpqCLW317dzOa4fe71t2UHtrR3sDKH/0tvWLxzExsEAdohdsT+pjAdTIaZwy+NsXHEcEv3XC4b5EIZsYA4mZsdZ75BDw//aD5ZDmPqLBcR+BDzE0P44La4LRzTx1yEDH8WgmaW+yXHeGfmObOSv/WI7iklz+3/pbojEwv/krv6b/+sf/qVC5A/uX6vfa2PQAW4GO96uMt3+tL9Wiv8nG4lCFFSSE//VuPMAIQ1w6vfvJXj9/H7IU4q7oTtP8VEiQG33ge46ibgbuPNA3WkEoBgKcPBRwN24nSfgKBBwJ1GBQ5zJ+y9v73Nz//kiAKbFEvfgIZ6i259EgUCa3Zv0R68d0dOdR8TOIngqcgI4yik6ZEKpEIRaoQGHPW+GqHXnqSsmBK1lByCRyf0Pe+e5IDIEdjU6cNAprt2wnWOxiDCvk8BBB4uQBZIEIZDNBMBBc7WIunaOi9Ih6KIkBA4/V7sbu3P2ERGrSAQcfvJ0N3bneBcVArabGDjcGCWyWJ5GiKU8OXCYKbHDrvEYJLhdU2KITu8cRmJAcHr2AOTuKTFkYmkRxEZSAEcYbULUu3PiCISgd+Jg6h6jTchUMyCovkEJHHGKaX8yCIFceDjyAXfWncM/3AiRoTgD/M0U025DO2dmeBEMzRzd0O7Jot3Gdg6YCCIYo6MG/pWhnMNfZDdpgMOOsSA6sbNqQnyQ5ByA/LMUQyaXBkEuCS1w+AmW/QWfQxBsdiD0byQ3IKPvHl45rGR6OuDIwyvIJNMjSPY+mG50uJXBiqC67zDcowlnQhAuTg8ceWRlf/FgBPGxh2UfzQHExwjmWeAI0yqI0neOkSA+RvQOpu4xrYJMNR2C6lZk/D9HU/aPOKJsFgbgGKMpu/k7RzjIEfjBe/B3T6UcvvqBMQKHGQI57EooRoL7cwgE0eWd0wxsCC4TMgHHGgI5vG41ZuAIMxKHLSdSDqbuOSOxPx+MwMc6Bxx/RgIx+DsnAYQRgm99ZCP7dgp3G93ZoBdDMPqABfgXRw52293ZLEcsZexBwL8yDIAsh9yIxSwr8Hct+f0NXUQwVHMsQ3u05BFjubP1LI0QSwE24H/Qkt9tf2cTWAbBvi478L9od+8WsLPvKo8gQJUD+B91ng9/Y9MHA0fo9yJ6trPziVgS5R9M3avf+8dDbkffcudDdNqrEAIco52KLCzUCGHR4QQO3Qvd/8HPjBCUrIOYf1PcEnEBR2qD7i+aB0G0+WG4yNqghy81evYwtUcD67ArG8QNHKEDuj+VEYHqeTB1dwd0/1BzIIS655Dooy0TZgT5l88DR29+7u8ABMGBZ4eGH80FFgQXsHmA4/Q998ezI+DNj4Df1ffcP04XEOLUeEQTR4sWYgkofAE4fstzf4f4EBx6cWQjR3OJDcElMl7gmN3Ow970nI9m4W/u22PITO3R6DzspoQoH3CcRicy4eQIwpP2MPBnj3N/uYjtgKX9aUcTib9D5LaYEj+ApL2JjvHz9xQBRaCZCgAe8v/86f8CAAD//w4CtDV7VQAA\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "cmd/gf/internal/service/install.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage service\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nvar (\n\tInstall = serviceInstall{}\n)\n\ntype serviceInstall struct{}\n\ntype serviceInstallAvailablePath struct {\n\tdirPath   string\n\tfilePath  string\n\twritable  bool\n\tinstalled bool\n\tIsSelf    bool\n}\n\nfunc (s serviceInstall) Run(ctx context.Context) (err error) {\n\t// Ask where to install.\n\tpaths := s.getAvailablePaths()\n\tif len(paths) <= 0 {\n\t\tmlog.Printf(\"no path detected, you can manually install gf by copying the binary to path folder.\")\n\t\treturn\n\t}\n\tmlog.Printf(\"I found some installable paths for you(from $PATH): \")\n\tmlog.Printf(\"  %2s | %8s | %9s | %s\", \"Id\", \"Writable\", \"Installed\", \"Path\")\n\n\t// Print all paths status and determine the default selectedID value.\n\tvar (\n\t\tselectedID = -1\n\t\tnewPaths   []serviceInstallAvailablePath\n\t\tpathSet    = gset.NewStrSet() // Used for repeated items filtering.\n\t)\n\tfor _, path := range paths {\n\t\tif !pathSet.AddIfNotExist(path.dirPath) {\n\t\t\tcontinue\n\t\t}\n\t\tnewPaths = append(newPaths, path)\n\t}\n\tpaths = newPaths\n\tfor id, path := range paths {\n\t\tmlog.Printf(\"  %2d | %8t | %9t | %s\", id, path.writable, path.installed, path.dirPath)\n\t\tif selectedID == -1 {\n\t\t\t// Use the previously installed path as the most priority choice.\n\t\t\tif path.installed {\n\t\t\t\tselectedID = id\n\t\t\t}\n\t\t}\n\t}\n\t// If there's no previously installed path, use the first writable path.\n\tif selectedID == -1 {\n\t\t// Order by choosing priority.\n\t\tcommonPaths := garray.NewStrArrayFrom(g.SliceStr{\n\t\t\ts.getGoPathBin(),\n\t\t\t`/usr/local/bin`,\n\t\t\t`/usr/bin`,\n\t\t\t`/usr/sbin`,\n\t\t\t`C:\\Windows`,\n\t\t\t`C:\\Windows\\system32`,\n\t\t\t`C:\\Go\\bin`,\n\t\t\t`C:\\Program Files`,\n\t\t\t`C:\\Program Files (x86)`,\n\t\t})\n\t\t// Check the common installation directories.\n\t\tcommonPaths.Iterator(func(k int, v string) bool {\n\t\t\tfor id, aPath := range paths {\n\t\t\t\tif strings.EqualFold(aPath.dirPath, v) {\n\t\t\t\t\tselectedID = id\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tif selectedID == -1 {\n\t\t\tselectedID = 0\n\t\t}\n\t}\n\n\tif allyes.Check() {\n\t\t// Use the default selectedID.\n\t\tmlog.Printf(\"please choose one installation destination [default %d]: %d\", selectedID, selectedID)\n\t} else {\n\t\tfor {\n\t\t\t// Get input and update selectedID.\n\t\t\tvar (\n\t\t\t\tinputID int\n\t\t\t\tinput   = gcmd.Scanf(\"please choose one installation destination [default %d]: \", selectedID)\n\t\t\t)\n\t\t\tif input != \"\" {\n\t\t\t\tinputID = gconv.Int(input)\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Check if out of range.\n\t\t\tif inputID >= len(paths) || inputID < 0 {\n\t\t\t\tmlog.Printf(\"invalid install destination Id: %d\", inputID)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tselectedID = inputID\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Get selected destination path.\n\tdstPath := paths[selectedID]\n\n\t// Install the new binary.\n\tmlog.Debugf(`copy file from \"%s\" to \"%s\"`, gfile.SelfPath(), dstPath.filePath)\n\terr = gfile.CopyFile(gfile.SelfPath(), dstPath.filePath)\n\tif err != nil {\n\t\tmlog.Printf(\"install gf binary to '%s' failed: %v\", dstPath.dirPath, err)\n\t\tmlog.Printf(\"you can manually install gf by copying the binary to folder: %s\", dstPath.dirPath)\n\t} else {\n\t\tmlog.Printf(\"gf binary is successfully installed to: %s\", dstPath.filePath)\n\t}\n\treturn\n}\n\n// IsInstalled checks and returns whether the binary is installed.\nfunc (s serviceInstall) IsInstalled() (*serviceInstallAvailablePath, bool) {\n\tpaths := s.getAvailablePaths()\n\tfor _, aPath := range paths {\n\t\tif aPath.installed {\n\t\t\treturn &aPath, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// getGoPathBin retrieves ad returns the GOPATH/bin path for binary.\nfunc (s serviceInstall) getGoPathBin() string {\n\tif goPath := genv.Get(`GOPATH`).String(); goPath != \"\" {\n\t\treturn gfile.Join(goPath, \"bin\")\n\t}\n\treturn \"\"\n}\n\n// getAvailablePaths returns the installation paths data for the binary.\nfunc (s serviceInstall) getAvailablePaths() []serviceInstallAvailablePath {\n\tvar (\n\t\tfolderPaths    []serviceInstallAvailablePath\n\t\tbinaryFileName = \"gf\"\n\t)\n\n\t// Windows binary file name suffix.\n\tif runtime.GOOS == \"windows\" {\n\t\tbinaryFileName += \".exe\"\n\t}\n\n\t// $GOPATH/bin\n\tif goPathBin := s.getGoPathBin(); goPathBin != \"\" {\n\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\tfolderPaths, goPathBin, binaryFileName,\n\t\t)\n\t}\n\tswitch runtime.GOOS {\n\tcase \"darwin\":\n\t\tdarwinInstallationCheckPaths := []string{\"/usr/local/bin\"}\n\t\tfor _, v := range darwinInstallationCheckPaths {\n\t\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\t\tfolderPaths, v, binaryFileName,\n\t\t\t)\n\t\t}\n\t\tfallthrough\n\n\tdefault:\n\t\t// Search and find the writable directory path.\n\t\tenvPath := genv.Get(\"PATH\", genv.Get(\"Path\").String()).String()\n\t\tif gstr.Contains(envPath, \";\") {\n\t\t\t// windows.\n\t\t\tfor _, v := range gstr.SplitAndTrim(envPath, \";\") {\n\t\t\t\tif v == \".\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\t\t\tfolderPaths, v, binaryFileName,\n\t\t\t\t)\n\t\t\t}\n\t\t} else if gstr.Contains(envPath, \":\") {\n\t\t\t// *nix.\n\t\t\tfor _, v := range gstr.SplitAndTrim(envPath, \":\") {\n\t\t\t\tif v == \".\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\t\t\tfolderPaths, v, binaryFileName,\n\t\t\t\t)\n\t\t\t}\n\t\t} else if envPath != \"\" {\n\t\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\t\tfolderPaths, envPath, binaryFileName,\n\t\t\t)\n\t\t} else {\n\t\t\tfolderPaths = s.checkAndAppendToAvailablePath(\n\t\t\t\tfolderPaths, \"/usr/local/bin\", binaryFileName,\n\t\t\t)\n\t\t}\n\t}\n\treturn folderPaths\n}\n\n// checkAndAppendToAvailablePath checks if `path` is writable and already installed.\n// It adds the `path` to `folderPaths` if it is writable or already installed, or else it ignores the `path`.\nfunc (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInstallAvailablePath, dirPath string, binaryFileName string) []serviceInstallAvailablePath {\n\tvar (\n\t\tfilePath  = gfile.Join(dirPath, binaryFileName)\n\t\twritable  = gfile.IsWritable(dirPath)\n\t\tinstalled = gfile.Exists(filePath)\n\t\tself      = gfile.SelfPath() == filePath\n\t)\n\tif !writable && !installed {\n\t\treturn folderPaths\n\t}\n\treturn append(\n\t\tfolderPaths,\n\t\tserviceInstallAvailablePath{\n\t\t\tdirPath:   dirPath,\n\t\t\twritable:  writable,\n\t\t\tfilePath:  filePath,\n\t\t\tinstalled: installed,\n\t\t\tIsSelf:    self,\n\t\t})\n}\n"
  },
  {
    "path": "cmd/gf/internal/utility/allyes/allyes.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage allyes\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n)\n\nconst (\n\tEnvName = \"GF_CLI_ALL_YES\"\n)\n\n// Init initializes the package manually.\nfunc Init() {\n\tif gcmd.GetOpt(\"y\") != nil {\n\t\tgenv.MustSet(EnvName, \"1\")\n\t}\n}\n\n// Check checks whether option allow all yes for command.\nfunc Check() bool {\n\treturn genv.Get(EnvName).String() == \"1\"\n}\n"
  },
  {
    "path": "cmd/gf/internal/utility/mlog/mlog.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mlog\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\nconst (\n\theaderPrintEnvName = \"GF_CLI_MLOG_HEADER\"\n)\n\nvar (\n\tctx    = context.TODO()\n\tlogger = glog.New()\n)\n\nfunc init() {\n\tif genv.Get(headerPrintEnvName).String() == \"1\" {\n\t\tlogger.SetHeaderPrint(true)\n\t} else {\n\t\tlogger.SetHeaderPrint(false)\n\t}\n\n\tif gcmd.GetOpt(\"debug\") != nil || gcmd.GetOpt(\"gf.debug\") != nil {\n\t\tlogger.SetHeaderPrint(true)\n\t\tlogger.SetStackSkip(4)\n\t\tlogger.SetFlags(logger.GetFlags() | glog.F_FILE_LONG)\n\t\tlogger.SetDebug(true)\n\t} else {\n\t\tlogger.SetStack(false)\n\t\tlogger.SetDebug(false)\n\t}\n}\n\n// SetHeaderPrint enables/disables header printing to stdout.\nfunc SetHeaderPrint(enabled bool) {\n\tlogger.SetHeaderPrint(enabled)\n\tif enabled {\n\t\t_ = genv.Set(headerPrintEnvName, \"1\")\n\t} else {\n\t\t_ = genv.Set(headerPrintEnvName, \"0\")\n\t}\n}\n\nfunc Print(v ...any) {\n\tlogger.Print(ctx, v...)\n}\n\nfunc Printf(format string, v ...any) {\n\tlogger.Printf(ctx, format, v...)\n}\n\nfunc Fatal(v ...any) {\n\tlogger.Fatal(ctx, v...)\n}\n\nfunc Fatalf(format string, v ...any) {\n\tlogger.Fatalf(ctx, format, v...)\n}\n\nfunc Debug(v ...any) {\n\tlogger.Debug(ctx, v...)\n}\n\nfunc Debugf(format string, v ...any) {\n\tlogger.Debugf(ctx, format, v...)\n}\n"
  },
  {
    "path": "cmd/gf/internal/utility/utils/utils.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"golang.org/x/tools/imports\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// GoFmt formats the source file and adds or removes import statements as necessary.\nfunc GoFmt(path string) {\n\treplaceFunc := func(path, content string) string {\n\t\tres, err := imports.Process(path, []byte(content), nil)\n\t\tif err != nil {\n\t\t\tmlog.Printf(`error format \"%s\" go files: %v`, path, err)\n\t\t\treturn content\n\t\t}\n\t\treturn string(res)\n\t}\n\n\tvar err error\n\tif gfile.IsFile(path) {\n\t\t// File format.\n\t\tif gfile.ExtName(path) != \"go\" {\n\t\t\treturn\n\t\t}\n\t\terr = gfile.ReplaceFileFunc(replaceFunc, path)\n\t} else {\n\t\t// Folder format.\n\t\terr = gfile.ReplaceDirFunc(replaceFunc, path, \"*.go\", true)\n\t}\n\tif err != nil {\n\t\tmlog.Printf(`error format \"%s\" go files: %v`, path, err)\n\t}\n}\n\n// GoModTidy executes `go mod tidy` at specified directory `dirPath`.\nfunc GoModTidy(ctx context.Context, dirPath string) error {\n\tcommand := fmt.Sprintf(`cd %s && go mod tidy`, dirPath)\n\terr := gproc.ShellRun(ctx, command)\n\treturn err\n}\n\n// IsFileDoNotEdit checks and returns whether file contains `do not edit` key.\nfunc IsFileDoNotEdit(filePath string) bool {\n\tif !gfile.Exists(filePath) {\n\t\treturn true\n\t}\n\treturn gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)\n}\n\n// ReplaceGeneratedContentGFV2 replaces generated go content from goframe v1 to v2.\nfunc ReplaceGeneratedContentGFV2(folderPath string) (err error) {\n\treturn gfile.ReplaceDirFunc(func(path, content string) string {\n\t\tif gstr.Contains(content, `\"github.com/gogf/gf`) && !gstr.Contains(content, `\"github.com/gogf/gf/v2`) {\n\t\t\tcontent = gstr.Replace(content, `\"github.com/gogf/gf\"`, `\"github.com/gogf/gf/v2\"`)\n\t\t\tcontent = gstr.Replace(content, `\"github.com/gogf/gf/`, `\"github.com/gogf/gf/v2/`)\n\t\t\tcontent = gstr.Replace(content, `\"github.com/gogf/gf/v2/contrib/`, `\"github.com/gogf/gf/contrib/`)\n\t\t\treturn content\n\t\t}\n\t\treturn content\n\t}, folderPath, \"*.go\", true)\n}\n\n// GetImportPath calculates and returns the golang import path for given `dirPath`.\n// Note that it needs a `go.mod` in current working directory or parent directories to detect the path.\nfunc GetImportPath(dirPath string) string {\n\t// If `filePath` does not exist, create it firstly to find the import path.\n\tvar realPath = gfile.RealPath(dirPath)\n\tif realPath == \"\" {\n\t\t_ = gfile.Mkdir(dirPath)\n\t\trealPath = gfile.RealPath(dirPath)\n\t}\n\n\tvar (\n\t\tnewDir     = gfile.Dir(realPath)\n\t\toldDir     string\n\t\tsuffix     = gfile.Basename(dirPath)\n\t\tgoModName  = \"go.mod\"\n\t\tgoModPath  string\n\t\timportPath string\n\t)\n\tfor {\n\t\tgoModPath = gfile.Join(newDir, goModName)\n\t\tif gfile.Exists(goModPath) {\n\t\t\tmatch, _ := gregex.MatchString(`^module\\s+(.+)\\s*`, gfile.GetContents(goModPath))\n\t\t\timportPath = gstr.Trim(match[1]) + \"/\" + suffix\n\t\t\timportPath = gstr.Replace(importPath, `\\`, `/`)\n\t\t\timportPath = gstr.TrimRight(importPath, `/`)\n\t\t\treturn importPath\n\t\t}\n\t\toldDir = newDir\n\t\tnewDir = gfile.Dir(oldDir)\n\t\tif newDir == oldDir {\n\t\t\treturn \"\"\n\t\t}\n\t\tsuffix = gfile.Basename(oldDir) + \"/\" + suffix\n\t}\n}\n\n// GetModPath retrieves and returns the file path of go.mod for current project.\nfunc GetModPath() string {\n\tvar (\n\t\toldDir    = gfile.Pwd()\n\t\tnewDir    = oldDir\n\t\tgoModName = \"go.mod\"\n\t\tgoModPath string\n\t)\n\tfor {\n\t\tgoModPath = gfile.Join(newDir, goModName)\n\t\tif gfile.Exists(goModPath) {\n\t\t\treturn goModPath\n\t\t}\n\t\tnewDir = gfile.Dir(oldDir)\n\t\tif newDir == oldDir {\n\t\t\tbreak\n\t\t}\n\t\toldDir = newDir\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "cmd/gf/internal/utility/utils/utils_http_download.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/schollz/progressbar/v3\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\n// HTTPDownloadFileWithPercent downloads target url file to local path with percent process printing.\nfunc HTTPDownloadFileWithPercent(url string, localSaveFilePath string) error {\n\tstart := time.Now()\n\tout, err := os.Create(localSaveFilePath)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `download \"%s\" to \"%s\" failed`, url, localSaveFilePath)\n\t}\n\tdefer out.Close()\n\n\theadResp, err := http.Head(url)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `download \"%s\" to \"%s\" failed`, url, localSaveFilePath)\n\t}\n\tdefer headResp.Body.Close()\n\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `download \"%s\" to \"%s\" failed`, url, localSaveFilePath)\n\t}\n\tdefer resp.Body.Close()\n\n\tbar := progressbar.NewOptions(int(resp.ContentLength), progressbar.OptionShowBytes(true), progressbar.OptionShowCount())\n\twriter := io.MultiWriter(out, bar)\n\t_, err = io.Copy(writer, resp.Body)\n\n\telapsed := time.Since(start)\n\tif elapsed > time.Minute {\n\t\tmlog.Printf(`download completed in %.0fm`, float64(elapsed)/float64(time.Minute))\n\t} else {\n\t\tmlog.Printf(`download completed in %.0fs`, elapsed.Seconds())\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/gf/internal/utility/utils/utils_test.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils\"\n)\n\nfunc Test_GetModPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgoModPath := utils.GetModPath()\n\t\tfmt.Println(goModPath)\n\t})\n}\n"
  },
  {
    "path": "cmd/gf/main.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage main\n\nimport (\n\t_ \"time/tzdata\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\n\t\"github.com/gogf/gf/cmd/gf/v2/gfcmd\"\n\t\"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog\"\n)\n\nfunc main() {\n\tvar (\n\t\tctx          = gctx.GetInitCtx()\n\t\tcommand, err = gfcmd.GetCommand(ctx)\n\t)\n\n\tif err != nil {\n\t\tmlog.Fatalf(`%+v`, err)\n\t}\n\tif command == nil {\n\t\tpanic(gerror.New(`retrieve root command failed for \"gf\"`))\n\t}\n\tcommand.Run(ctx)\n}\n"
  },
  {
    "path": "cmd/gf/test/testdata/tpls/tpl1.yaml",
    "content": "server:\n  address: {{.server.address}}"
  },
  {
    "path": "cmd/gf/test/testdata/tpls/tpl2.sql",
    "content": "insert into {{.sql.table}}"
  },
  {
    "path": "cmd/gf/test/testdata/values.json",
    "content": "{\n    \"server\": {\n        \"address\": \"https://goframe.org\"\n    },\n    \"sql\":{\n        \"table\": \"table_name\"\n    }\n}"
  },
  {
    "path": "container/garray/garray.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package garray provides most commonly used array containers which also support concurrent-safe/unsafe switch feature.\npackage garray\n"
  },
  {
    "path": "container/garray/garray_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"sort\"\n\t\"strings\"\n)\n\n// defaultComparatorInt for int comparison.\nfunc defaultComparatorInt(a, b int) int {\n\tif a < b {\n\t\treturn -1\n\t}\n\tif a > b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\n// defaultComparatorStr for string comparison.\nfunc defaultComparatorStr(a, b string) int {\n\treturn strings.Compare(a, b)\n}\n\n// defaultSorter is a generic sorting function that sorts a slice of comparable types\n// using the provided comparator function.\nfunc defaultSorter[T comparable](values []T, comparator func(a T, b T) int) {\n\tsort.Slice(values, func(i, j int) bool {\n\t\treturn comparator(values[i], values[j]) < 0\n\t})\n}\n\n// quickSortInt is the quick-sorting algorithm implements for int.\nfunc quickSortInt(values []int, comparator func(a, b int) int) {\n\tif len(values) <= 1 {\n\t\treturn\n\t}\n\tmid, i := values[0], 1\n\thead, tail := 0, len(values)-1\n\tfor head < tail {\n\t\tif comparator(values[i], mid) > 0 {\n\t\t\tvalues[i], values[tail] = values[tail], values[i]\n\t\t\ttail--\n\t\t} else {\n\t\t\tvalues[i], values[head] = values[head], values[i]\n\t\t\thead++\n\t\t\ti++\n\t\t}\n\t}\n\tvalues[head] = mid\n\tquickSortInt(values[:head], comparator)\n\tquickSortInt(values[head+1:], comparator)\n}\n\n// quickSortStr is the quick-sorting algorithm implements for string.\nfunc quickSortStr(values []string, comparator func(a, b string) int) {\n\tif len(values) <= 1 {\n\t\treturn\n\t}\n\tmid, i := values[0], 1\n\thead, tail := 0, len(values)-1\n\tfor head < tail {\n\t\tif comparator(values[i], mid) > 0 {\n\t\t\tvalues[i], values[tail] = values[tail], values[i]\n\t\t\ttail--\n\t\t} else {\n\t\t\tvalues[i], values[head] = values[head], values[i]\n\t\t\thead++\n\t\t\ti++\n\t\t}\n\t}\n\tvalues[head] = mid\n\tquickSortStr(values[:head], comparator)\n\tquickSortStr(values[head+1:], comparator)\n}\n\n// tToAnySlice converts []T to []any\nfunc tToAnySlice[T any](values []T) []any {\n\tif values == nil {\n\t\treturn nil\n\t}\n\tanyValues := make([]any, len(values), cap(values))\n\tfor k, v := range values {\n\t\tanyValues[k] = v\n\t}\n\treturn anyValues\n}\n\n// anyToTSlice is convert []any to []T\nfunc anyToTSlice[T any](values []any) []T {\n\tif values == nil {\n\t\treturn nil\n\t}\n\ttValues := make([]T, len(values), cap(values))\n\tfor k, v := range values {\n\t\ttValues[k], _ = v.(T)\n\t}\n\treturn tValues\n}\n\n// tToAnySlices converts [][]T to [][]any\nfunc tToAnySlices[T any](values [][]T) [][]any {\n\tif values == nil {\n\t\treturn nil\n\t}\n\tanyValues := make([][]any, len(values), cap(values))\n\tfor k, v := range values {\n\t\tanyValues[k] = tToAnySlice(v)\n\t}\n\treturn anyValues\n}\n\n// anyToTSlices converts [][]any to [][]T\nfunc anyToTSlices[T any](values [][]any) [][]T {\n\tif values == nil {\n\t\treturn nil\n\t}\n\ttValues := make([][]T, len(values), cap(values))\n\tfor k, v := range values {\n\t\ttValues[k] = anyToTSlice[T](v)\n\t}\n\treturn tValues\n}\n"
  },
  {
    "path": "container/garray/garray_normal_any.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Array is a golang array with rich features.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype Array struct {\n\t*TArray[any]\n\tonce sync.Once\n}\n\n// New creates and returns an empty array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc New(safe ...bool) *Array {\n\treturn NewArraySize(0, 0, safe...)\n}\n\n// NewArray is alias of New, please see New.\nfunc NewArray(safe ...bool) *Array {\n\treturn NewArraySize(0, 0, safe...)\n}\n\n// NewArraySize create and returns an array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewArraySize(size int, cap int, safe ...bool) *Array {\n\treturn &Array{\n\t\tTArray: NewTArraySize[any](size, cap, safe...),\n\t}\n}\n\n// NewArrayRange creates and returns an array by a range from `start` to `end`\n// with step value `step`.\nfunc NewArrayRange(start, end, step int, safe ...bool) *Array {\n\tif step == 0 {\n\t\tpanic(fmt.Sprintf(`invalid step value: %d`, step))\n\t}\n\tslice := make([]any, 0)\n\tindex := 0\n\tfor i := start; i <= end; i += step {\n\t\tslice = append(slice, i)\n\t\tindex++\n\t}\n\treturn NewArrayFrom(slice, safe...)\n}\n\n// NewFrom is alias of NewArrayFrom.\n// See NewArrayFrom.\nfunc NewFrom(array []any, safe ...bool) *Array {\n\treturn NewArrayFrom(array, safe...)\n}\n\n// NewFromCopy is alias of NewArrayFromCopy.\n// See NewArrayFromCopy.\nfunc NewFromCopy(array []any, safe ...bool) *Array {\n\treturn NewArrayFromCopy(array, safe...)\n}\n\n// NewArrayFrom creates and returns an array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewArrayFrom(array []any, safe ...bool) *Array {\n\treturn &Array{\n\t\tTArray: NewTArrayFrom(array, safe...),\n\t}\n}\n\n// NewArrayFromCopy creates and returns an array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewArrayFromCopy(array []any, safe ...bool) *Array {\n\tnewArray := make([]any, len(array))\n\tcopy(newArray, array)\n\treturn NewArrayFrom(newArray, safe...)\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *Array) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TArray == nil {\n\t\t\ta.TArray = NewTArray[any](false)\n\t\t}\n\t})\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns `nil`.\nfunc (a *Array) At(index int) (value any) {\n\ta.lazyInit()\n\treturn a.TArray.At(index)\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *Array) Get(index int) (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Get(index)\n}\n\n// Set sets value to specified index.\nfunc (a *Array) Set(index int, value any) error {\n\ta.lazyInit()\n\treturn a.TArray.Set(index, value)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *Array) SetArray(array []any) *Array {\n\ta.lazyInit()\n\ta.TArray.SetArray(array)\n\treturn a\n}\n\n// Replace replaces the array items by given `array` from the beginning of array.\nfunc (a *Array) Replace(array []any) *Array {\n\ta.lazyInit()\n\ta.TArray.Replace(array)\n\treturn a\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *Array) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.TArray.Sum()\n}\n\n// SortFunc sorts the array by custom function `less`.\nfunc (a *Array) SortFunc(less func(v1, v2 any) bool) *Array {\n\ta.lazyInit()\n\ta.TArray.SortFunc(less)\n\treturn a\n}\n\n// InsertBefore inserts the `values` to the front of `index`.\nfunc (a *Array) InsertBefore(index int, values ...any) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertBefore(index, values...)\n}\n\n// InsertAfter inserts the `values` to the back of `index`.\nfunc (a *Array) InsertAfter(index int, values ...any) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertAfter(index, values...)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *Array) Remove(index int) (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *Array) RemoveValue(value any) bool {\n\ta.lazyInit()\n\treturn a.TArray.RemoveValue(value)\n}\n\n// RemoveValues removes multiple items by `values`.\nfunc (a *Array) RemoveValues(values ...any) {\n\ta.lazyInit()\n\ta.TArray.RemoveValues(values...)\n}\n\n// PushLeft pushes one or multiple items to the beginning of array.\nfunc (a *Array) PushLeft(value ...any) *Array {\n\ta.lazyInit()\n\ta.TArray.PushLeft(value...)\n\treturn a\n}\n\n// PushRight pushes one or multiple items to the end of array.\n// It equals to Append.\nfunc (a *Array) PushRight(value ...any) *Array {\n\ta.lazyInit()\n\ta.TArray.PushRight(value...)\n\treturn a\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *Array) PopRand() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\nfunc (a *Array) PopRands(size int) []any {\n\ta.lazyInit()\n\treturn a.TArray.PopRands(size)\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *Array) PopLeft() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *Array) PopRight() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRight()\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\nfunc (a *Array) PopLefts(size int) []any {\n\ta.lazyInit()\n\treturn a.TArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\nfunc (a *Array) PopRights(size int) []any {\n\ta.lazyInit()\n\treturn a.TArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *Array) Range(start int, end ...int) []any {\n\ta.lazyInit()\n\treturn a.TArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *Array) SubSlice(offset int, length ...int) []any {\n\ta.lazyInit()\n\treturn a.TArray.SubSlice(offset, length...)\n}\n\n// Append is alias of PushRight, please See PushRight.\nfunc (a *Array) Append(value ...any) *Array {\n\ta.lazyInit()\n\ta.TArray.Append(value...)\n\treturn a\n}\n\n// Len returns the length of array.\nfunc (a *Array) Len() int {\n\ta.lazyInit()\n\treturn a.TArray.Len()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *Array) Slice() []any {\n\ta.lazyInit()\n\treturn a.TArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *Array) Interfaces() []any {\n\treturn a.Slice()\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *Array) Clone() (newArray *Array) {\n\ta.lazyInit()\n\treturn &Array{TArray: a.TArray.Clone()}\n}\n\n// Clear deletes all items of current array.\nfunc (a *Array) Clear() *Array {\n\ta.lazyInit()\n\ta.TArray.Clear()\n\treturn a\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *Array) Contains(value any) bool {\n\ta.lazyInit()\n\treturn a.TArray.Contains(value)\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *Array) Search(value any) int {\n\ta.lazyInit()\n\treturn a.TArray.Search(value)\n}\n\n// Unique uniques the array, clear repeated items.\n// Example: [1,1,2,3,2] -> [1,2,3]\nfunc (a *Array) Unique() *Array {\n\ta.lazyInit()\n\ta.TArray.Unique()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *Array) LockFunc(f func(array []any)) *Array {\n\ta.lazyInit()\n\ta.TArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *Array) RLockFunc(f func(array []any)) *Array {\n\ta.lazyInit()\n\ta.TArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *Array) Merge(array any) *Array {\n\ta.lazyInit()\n\treturn a.Append(gconv.Interfaces(array)...)\n}\n\n// Fill fills an array with num entries of the value `value`,\n// keys starting at the `startIndex` parameter.\nfunc (a *Array) Fill(startIndex int, num int, value any) error {\n\ta.lazyInit()\n\treturn a.TArray.Fill(startIndex, num, value)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *Array) Chunk(size int) [][]any {\n\ta.lazyInit()\n\treturn a.TArray.Chunk(size)\n}\n\n// Pad pads array to the specified length with `value`.\n// If size is positive then the array is padded on the right, or negative on the left.\n// If the absolute value of `size` is less than or equal to the length of the array\n// then no padding takes place.\nfunc (a *Array) Pad(size int, val any) *Array {\n\ta.lazyInit()\n\ta.TArray.Pad(size, val)\n\treturn a\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *Array) Rand() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *Array) Rands(size int) []any {\n\ta.lazyInit()\n\treturn a.TArray.Rands(size)\n}\n\n// Shuffle randomly shuffles the array.\nfunc (a *Array) Shuffle() *Array {\n\ta.lazyInit()\n\ta.TArray.Shuffle()\n\treturn a\n}\n\n// Reverse makes array with elements in reverse order.\nfunc (a *Array) Reverse() *Array {\n\ta.lazyInit()\n\ta.TArray.Reverse()\n\treturn a\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *Array) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.TArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *Array) CountValues() map[any]int {\n\ta.lazyInit()\n\treturn a.TArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *Array) Iterator(f func(k int, v any) bool) {\n\ta.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *Array) IteratorAsc(f func(k int, v any) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *Array) IteratorDesc(f func(k int, v any) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *Array) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.lazyInit()\n\treturn a.TArray.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a Array) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.TArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *Array) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *Array) UnmarshalValue(value any) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalValue(value)\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *Array) Filter(filter func(index int, value any) bool) *Array {\n\ta.lazyInit()\n\ta.TArray.Filter(filter)\n\treturn a\n}\n\n// FilterNil removes all nil value of the array.\nfunc (a *Array) FilterNil() *Array {\n\ta.lazyInit()\n\ta.TArray.FilterNil()\n\treturn a\n}\n\n// FilterEmpty removes all empty value of the array.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (a *Array) FilterEmpty() *Array {\n\ta.lazyInit()\n\ta.TArray.FilterEmpty()\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *Array) Walk(f func(value any) any) *Array {\n\ta.lazyInit()\n\ta.TArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *Array) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.TArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *Array) DeepCopy() any {\n\tif a == nil {\n\t\treturn nil\n\t}\n\ta.lazyInit()\n\treturn &Array{\n\t\tTArray: a.TArray.DeepCopy().(*TArray[any]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_normal_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// IntArray is a golang int array with rich features.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype IntArray struct {\n\t*TArray[int]\n\tonce sync.Once\n}\n\n// NewIntArray creates and returns an empty array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewIntArray(safe ...bool) *IntArray {\n\treturn NewIntArraySize(0, 0, safe...)\n}\n\n// NewIntArraySize create and returns an array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewIntArraySize(size int, cap int, safe ...bool) *IntArray {\n\treturn &IntArray{\n\t\tTArray: NewTArraySize[int](size, cap, safe...),\n\t}\n}\n\n// NewIntArrayRange creates and returns an array by a range from `start` to `end`\n// with step value `step`.\nfunc NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {\n\tif step == 0 {\n\t\tpanic(fmt.Sprintf(`invalid step value: %d`, step))\n\t}\n\tslice := make([]int, 0)\n\tindex := 0\n\tfor i := start; i <= end; i += step {\n\t\tslice = append(slice, i)\n\t\tindex++\n\t}\n\treturn NewIntArrayFrom(slice, safe...)\n}\n\n// NewIntArrayFrom creates and returns an array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewIntArrayFrom(array []int, safe ...bool) *IntArray {\n\treturn &IntArray{\n\t\tTArray: NewTArrayFrom(array, safe...),\n\t}\n}\n\n// NewIntArrayFromCopy creates and returns an array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {\n\tnewArray := make([]int, len(array))\n\tcopy(newArray, array)\n\treturn NewIntArrayFrom(newArray, safe...)\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *IntArray) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TArray == nil {\n\t\t\ta.TArray = NewTArray[int](false)\n\t\t}\n\t})\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns `0`.\nfunc (a *IntArray) At(index int) (value int) {\n\ta.lazyInit()\n\treturn a.TArray.At(index)\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *IntArray) Get(index int) (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Get(index)\n}\n\n// Set sets value to specified index.\nfunc (a *IntArray) Set(index int, value int) error {\n\ta.lazyInit()\n\treturn a.TArray.Set(index, value)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *IntArray) SetArray(array []int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.SetArray(array)\n\treturn a\n}\n\n// Replace replaces the array items by given `array` from the beginning of array.\nfunc (a *IntArray) Replace(array []int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.Replace(array)\n\treturn a\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *IntArray) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.TArray.Sum()\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort in increasing order(default) or decreasing order.\nfunc (a *IntArray) Sort(reverse ...bool) *IntArray {\n\ta.lazyInit()\n\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\tif len(reverse) > 0 && reverse[0] {\n\t\tsort.Slice(a.array, func(i, j int) bool {\n\t\t\treturn a.array[i] >= a.array[j]\n\t\t})\n\t} else {\n\t\tsort.Ints(a.array)\n\t}\n\treturn a\n}\n\n// SortFunc sorts the array by custom function `less`.\nfunc (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {\n\ta.lazyInit()\n\ta.TArray.SortFunc(less)\n\treturn a\n}\n\n// InsertBefore inserts the `values` to the front of `index`.\nfunc (a *IntArray) InsertBefore(index int, values ...int) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertBefore(index, values...)\n}\n\n// InsertAfter inserts the `value` to the back of `index`.\nfunc (a *IntArray) InsertAfter(index int, values ...int) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertAfter(index, values...)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *IntArray) Remove(index int) (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *IntArray) RemoveValue(value int) bool {\n\ta.lazyInit()\n\treturn a.TArray.RemoveValue(value)\n}\n\n// RemoveValues removes multiple items by `values`.\nfunc (a *IntArray) RemoveValues(values ...int) {\n\ta.lazyInit()\n\ta.TArray.RemoveValues(values...)\n}\n\n// PushLeft pushes one or multiple items to the beginning of array.\nfunc (a *IntArray) PushLeft(value ...int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.PushLeft(value...)\n\treturn a\n}\n\n// PushRight pushes one or multiple items to the end of array.\n// It equals to Append.\nfunc (a *IntArray) PushRight(value ...int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.PushRight(value...)\n\treturn a\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *IntArray) PopLeft() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *IntArray) PopRight() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRight()\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *IntArray) PopRand() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *IntArray) PopRands(size int) []int {\n\ta.lazyInit()\n\treturn a.TArray.PopRands(size)\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *IntArray) PopLefts(size int) []int {\n\ta.lazyInit()\n\treturn a.TArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *IntArray) PopRights(size int) []int {\n\ta.lazyInit()\n\treturn a.TArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *IntArray) Range(start int, end ...int) []int {\n\ta.lazyInit()\n\treturn a.TArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *IntArray) SubSlice(offset int, length ...int) []int {\n\ta.lazyInit()\n\treturn a.TArray.SubSlice(offset, length...)\n}\n\n// Append is alias of PushRight,please See PushRight.\nfunc (a *IntArray) Append(value ...int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.Append(value...)\n\treturn a\n}\n\n// Len returns the length of array.\nfunc (a *IntArray) Len() int {\n\ta.lazyInit()\n\treturn a.TArray.Len()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *IntArray) Slice() []int {\n\ta.lazyInit()\n\treturn a.TArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *IntArray) Interfaces() []any {\n\ta.lazyInit()\n\treturn a.TArray.Interfaces()\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *IntArray) Clone() (newArray *IntArray) {\n\ta.lazyInit()\n\treturn &IntArray{\n\t\tTArray: a.TArray.Clone(),\n\t}\n}\n\n// Clear deletes all items of current array.\nfunc (a *IntArray) Clear() *IntArray {\n\ta.lazyInit()\n\ta.TArray.Clear()\n\treturn a\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *IntArray) Contains(value int) bool {\n\ta.lazyInit()\n\treturn a.TArray.Contains(value)\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *IntArray) Search(value int) int {\n\ta.lazyInit()\n\treturn a.TArray.Search(value)\n}\n\n// Unique uniques the array, clear repeated items.\n// Example: [1,1,2,3,2] -> [1,2,3]\nfunc (a *IntArray) Unique() *IntArray {\n\ta.lazyInit()\n\ta.TArray.Unique()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *IntArray) LockFunc(f func(array []int)) *IntArray {\n\ta.lazyInit()\n\ta.TArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *IntArray) RLockFunc(f func(array []int)) *IntArray {\n\ta.lazyInit()\n\ta.TArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *IntArray) Merge(array any) *IntArray {\n\treturn a.Append(gconv.Ints(array)...)\n}\n\n// Fill fills an array with num entries of the value `value`,\n// keys starting at the `startIndex` parameter.\nfunc (a *IntArray) Fill(startIndex int, num int, value int) error {\n\ta.lazyInit()\n\treturn a.TArray.Fill(startIndex, num, value)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *IntArray) Chunk(size int) [][]int {\n\ta.lazyInit()\n\treturn a.TArray.Chunk(size)\n}\n\n// Pad pads array to the specified length with `value`.\n// If size is positive then the array is padded on the right, or negative on the left.\n// If the absolute value of `size` is less than or equal to the length of the array\n// then no padding takes place.\nfunc (a *IntArray) Pad(size int, value int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.Pad(size, value)\n\treturn a\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *IntArray) Rand() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *IntArray) Rands(size int) []int {\n\ta.lazyInit()\n\treturn a.TArray.Rands(size)\n}\n\n// Shuffle randomly shuffles the array.\nfunc (a *IntArray) Shuffle() *IntArray {\n\ta.lazyInit()\n\ta.TArray.Shuffle()\n\treturn a\n}\n\n// Reverse makes array with elements in reverse order.\nfunc (a *IntArray) Reverse() *IntArray {\n\ta.lazyInit()\n\ta.TArray.Reverse()\n\treturn a\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *IntArray) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.TArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *IntArray) CountValues() map[int]int {\n\ta.lazyInit()\n\treturn a.TArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *IntArray) Iterator(f func(k int, v int) bool) {\n\ta.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *IntArray) IteratorAsc(f func(k int, v int) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *IntArray) IteratorDesc(f func(k int, v int) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *IntArray) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\treturn \"[\" + a.Join(\",\") + \"]\"\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a IntArray) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.TArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *IntArray) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *IntArray) UnmarshalValue(value any) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalValue(value)\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *IntArray) Filter(filter func(index int, value int) bool) *IntArray {\n\ta.lazyInit()\n\ta.TArray.Filter(filter)\n\treturn a\n}\n\n// FilterEmpty removes all zero value of the array.\nfunc (a *IntArray) FilterEmpty() *IntArray {\n\ta.lazyInit()\n\ta.TArray.FilterEmpty()\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *IntArray) Walk(f func(value int) int) *IntArray {\n\ta.lazyInit()\n\ta.TArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *IntArray) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.TArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *IntArray) DeepCopy() any {\n\tif a == nil {\n\t\treturn nil\n\t}\n\ta.lazyInit()\n\treturn &IntArray{\n\t\tTArray: a.TArray.DeepCopy().(*TArray[int]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_normal_str.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"bytes\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// StrArray is a golang string array with rich features.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype StrArray struct {\n\t*TArray[string]\n\tonce sync.Once\n}\n\n// NewStrArray creates and returns an empty array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewStrArray(safe ...bool) *StrArray {\n\treturn NewStrArraySize(0, 0, safe...)\n}\n\n// NewStrArraySize create and returns an array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewStrArraySize(size int, cap int, safe ...bool) *StrArray {\n\treturn &StrArray{\n\t\tTArray: NewTArraySize[string](size, cap, safe...),\n\t}\n}\n\n// NewStrArrayFrom creates and returns an array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewStrArrayFrom(array []string, safe ...bool) *StrArray {\n\treturn &StrArray{\n\t\tTArray: NewTArrayFrom(array, safe...),\n\t}\n}\n\n// NewStrArrayFromCopy creates and returns an array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {\n\tnewArray := make([]string, len(array))\n\tcopy(newArray, array)\n\treturn NewStrArrayFrom(newArray, safe...)\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *StrArray) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TArray == nil {\n\t\t\ta.TArray = NewTArray[string](false)\n\t\t}\n\t})\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns an empty string.\nfunc (a *StrArray) At(index int) (value string) {\n\ta.lazyInit()\n\treturn a.TArray.At(index)\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *StrArray) Get(index int) (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Get(index)\n}\n\n// Set sets value to specified index.\nfunc (a *StrArray) Set(index int, value string) error {\n\ta.lazyInit()\n\treturn a.TArray.Set(index, value)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *StrArray) SetArray(array []string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.SetArray(array)\n\treturn a\n}\n\n// Replace replaces the array items by given `array` from the beginning of array.\nfunc (a *StrArray) Replace(array []string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.Replace(array)\n\treturn a\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *StrArray) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.TArray.Sum()\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort\n// in increasing order(default) or decreasing order\nfunc (a *StrArray) Sort(reverse ...bool) *StrArray {\n\ta.lazyInit()\n\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif len(reverse) > 0 && reverse[0] {\n\t\tsort.Slice(a.array, func(i, j int) bool {\n\t\t\treturn strings.Compare(a.array[i], a.array[j]) >= 0\n\t\t})\n\t} else {\n\t\tsort.Strings(a.array)\n\t}\n\treturn a\n}\n\n// SortFunc sorts the array by custom function `less`.\nfunc (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {\n\ta.lazyInit()\n\ta.TArray.SortFunc(less)\n\treturn a\n}\n\n// InsertBefore inserts the `values` to the front of `index`.\nfunc (a *StrArray) InsertBefore(index int, values ...string) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertBefore(index, values...)\n}\n\n// InsertAfter inserts the `values` to the back of `index`.\nfunc (a *StrArray) InsertAfter(index int, values ...string) error {\n\ta.lazyInit()\n\treturn a.TArray.InsertAfter(index, values...)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *StrArray) Remove(index int) (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *StrArray) RemoveValue(value string) bool {\n\ta.lazyInit()\n\treturn a.TArray.RemoveValue(value)\n}\n\n// RemoveValues removes multiple items by `values`.\nfunc (a *StrArray) RemoveValues(values ...string) {\n\ta.lazyInit()\n\ta.TArray.RemoveValues(values...)\n}\n\n// PushLeft pushes one or multiple items to the beginning of array.\nfunc (a *StrArray) PushLeft(value ...string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.PushLeft(value...)\n\treturn a\n}\n\n// PushRight pushes one or multiple items to the end of array.\n// It equals to Append.\nfunc (a *StrArray) PushRight(value ...string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.PushRight(value...)\n\treturn a\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *StrArray) PopLeft() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *StrArray) PopRight() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRight()\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *StrArray) PopRand() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *StrArray) PopRands(size int) []string {\n\ta.lazyInit()\n\treturn a.TArray.PopRands(size)\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *StrArray) PopLefts(size int) []string {\n\ta.lazyInit()\n\treturn a.TArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *StrArray) PopRights(size int) []string {\n\ta.lazyInit()\n\treturn a.TArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *StrArray) Range(start int, end ...int) []string {\n\ta.lazyInit()\n\treturn a.TArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *StrArray) SubSlice(offset int, length ...int) []string {\n\ta.lazyInit()\n\treturn a.TArray.SubSlice(offset, length...)\n}\n\n// Append is alias of PushRight,please See PushRight.\nfunc (a *StrArray) Append(value ...string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.Append(value...)\n\treturn a\n}\n\n// Len returns the length of array.\nfunc (a *StrArray) Len() int {\n\ta.lazyInit()\n\treturn a.TArray.Len()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *StrArray) Slice() []string {\n\ta.lazyInit()\n\treturn a.TArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *StrArray) Interfaces() []any {\n\ta.lazyInit()\n\treturn a.TArray.Interfaces()\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *StrArray) Clone() (newArray *StrArray) {\n\ta.lazyInit()\n\treturn &StrArray{\n\t\tTArray: a.TArray.Clone(),\n\t}\n}\n\n// Clear deletes all items of current array.\nfunc (a *StrArray) Clear() *StrArray {\n\ta.lazyInit()\n\ta.TArray.Clear()\n\treturn a\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *StrArray) Contains(value string) bool {\n\ta.lazyInit()\n\treturn a.TArray.Contains(value)\n}\n\n// ContainsI checks whether a value exists in the array with case-insensitively.\n// Note that it internally iterates the whole array to do the comparison with case-insensitively.\nfunc (a *StrArray) ContainsI(value string) bool {\n\ta.lazyInit()\n\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\treturn false\n\t}\n\tfor _, v := range a.array {\n\t\tif strings.EqualFold(v, value) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *StrArray) Search(value string) int {\n\ta.lazyInit()\n\treturn a.TArray.Search(value)\n}\n\n// Unique uniques the array, clear repeated items.\n// Example: [1,1,2,3,2] -> [1,2,3]\nfunc (a *StrArray) Unique() *StrArray {\n\ta.lazyInit()\n\ta.TArray.Unique()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *StrArray) LockFunc(f func(array []string)) *StrArray {\n\ta.lazyInit()\n\ta.TArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *StrArray) RLockFunc(f func(array []string)) *StrArray {\n\ta.lazyInit()\n\ta.TArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *StrArray) Merge(array any) *StrArray {\n\treturn a.Append(gconv.Strings(array)...)\n}\n\n// Fill fills an array with num entries of the value `value`,\n// keys starting at the `startIndex` parameter.\nfunc (a *StrArray) Fill(startIndex int, num int, value string) error {\n\ta.lazyInit()\n\treturn a.TArray.Fill(startIndex, num, value)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *StrArray) Chunk(size int) [][]string {\n\ta.lazyInit()\n\treturn a.TArray.Chunk(size)\n}\n\n// Pad pads array to the specified length with `value`.\n// If size is positive then the array is padded on the right, or negative on the left.\n// If the absolute value of `size` is less than or equal to the length of the array\n// then no padding takes place.\nfunc (a *StrArray) Pad(size int, value string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.Pad(size, value)\n\treturn a\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *StrArray) Rand() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.TArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *StrArray) Rands(size int) []string {\n\ta.lazyInit()\n\treturn a.TArray.Rands(size)\n}\n\n// Shuffle randomly shuffles the array.\nfunc (a *StrArray) Shuffle() *StrArray {\n\ta.lazyInit()\n\ta.TArray.Shuffle()\n\treturn a\n}\n\n// Reverse makes array with elements in reverse order.\nfunc (a *StrArray) Reverse() *StrArray {\n\ta.lazyInit()\n\ta.TArray.Reverse()\n\treturn a\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *StrArray) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.TArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *StrArray) CountValues() map[string]int {\n\ta.lazyInit()\n\treturn a.TArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *StrArray) Iterator(f func(k int, v string) bool) {\n\ta.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *StrArray) IteratorAsc(f func(k int, v string) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *StrArray) IteratorDesc(f func(k int, v string) bool) {\n\ta.lazyInit()\n\ta.TArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *StrArray) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\n\ta.lazyInit()\n\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteByte('[')\n\tfor k, v := range a.array {\n\t\tbuffer.WriteString(`\"` + gstr.QuoteMeta(v, `\"\\`) + `\"`)\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a StrArray) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.TArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *StrArray) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *StrArray) UnmarshalValue(value any) error {\n\ta.lazyInit()\n\treturn a.TArray.UnmarshalValue(value)\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *StrArray) Filter(filter func(index int, value string) bool) *StrArray {\n\ta.lazyInit()\n\ta.TArray.Filter(filter)\n\treturn a\n}\n\n// FilterEmpty removes all empty string value of the array.\nfunc (a *StrArray) FilterEmpty() *StrArray {\n\ta.lazyInit()\n\ta.TArray.FilterEmpty()\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *StrArray) Walk(f func(value string) string) *StrArray {\n\ta.lazyInit()\n\ta.TArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *StrArray) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.TArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *StrArray) DeepCopy() any {\n\tif a == nil {\n\t\treturn nil\n\t}\n\ta.lazyInit()\n\treturn &StrArray{\n\t\tTArray: a.TArray.DeepCopy().(*TArray[string]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_normal_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"sort\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\n// TArray is a golang array with rich features.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype TArray[T comparable] struct {\n\tmu    rwmutex.RWMutex\n\tarray []T\n}\n\n// NewTArray creates and returns an empty array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewTArray[T comparable](safe ...bool) *TArray[T] {\n\treturn NewTArraySize[T](0, 0, safe...)\n}\n\n// NewTArraySize create and returns an array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewTArraySize[T comparable](size int, cap int, safe ...bool) *TArray[T] {\n\treturn &TArray[T]{\n\t\tmu:    rwmutex.Create(safe...),\n\t\tarray: make([]T, size, cap),\n\t}\n}\n\n// NewTArrayFrom creates and returns an array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewTArrayFrom[T comparable](array []T, safe ...bool) *TArray[T] {\n\treturn &TArray[T]{\n\t\tmu:    rwmutex.Create(safe...),\n\t\tarray: array,\n\t}\n}\n\n// NewTArrayFromCopy creates and returns an array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewTArrayFromCopy[T comparable](array []T, safe ...bool) *TArray[T] {\n\tnewArray := make([]T, len(array))\n\tcopy(newArray, array)\n\treturn &TArray[T]{\n\t\tmu:    rwmutex.Create(safe...),\n\t\tarray: newArray,\n\t}\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns `nil`.\nfunc (a *TArray[T]) At(index int) (value T) {\n\tvalue, _ = a.Get(index)\n\treturn\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *TArray[T]) Get(index int) (value T, found bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif index < 0 || index >= len(a.array) {\n\t\tfound = false\n\t\treturn\n\t}\n\treturn a.array[index], true\n}\n\n// Set sets value to specified index.\nfunc (a *TArray[T]) Set(index int, value T) error {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif index < 0 || index >= len(a.array) {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"index %d out of array range %d\", index, len(a.array))\n\t}\n\ta.array[index] = value\n\treturn nil\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *TArray[T]) SetArray(array []T) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\ta.array = array\n\treturn a\n}\n\n// Replace replaces the array items by given `array` from the beginning of array.\nfunc (a *TArray[T]) Replace(array []T) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tmax := len(array)\n\tif max > len(a.array) {\n\t\tmax = len(a.array)\n\t}\n\tfor i := 0; i < max; i++ {\n\t\ta.array[i] = array[i]\n\t}\n\treturn a\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *TArray[T]) Sum() (sum int) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor _, v := range a.array {\n\t\tsum += gconv.Int(v)\n\t}\n\treturn\n}\n\n// SortFunc sorts the array by custom function `less`.\nfunc (a *TArray[T]) SortFunc(less func(v1, v2 T) bool) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tsort.Slice(a.array, func(i, j int) bool {\n\t\treturn less(a.array[i], a.array[j])\n\t})\n\treturn a\n}\n\n// InsertBefore inserts the `values` to the front of `index`.\nfunc (a *TArray[T]) InsertBefore(index int, values ...T) error {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif index < 0 || index >= len(a.array) {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"index %d out of array range %d\", index, len(a.array))\n\t}\n\trear := append([]T{}, a.array[index:]...)\n\ta.array = append(a.array[0:index], values...)\n\ta.array = append(a.array, rear...)\n\treturn nil\n}\n\n// InsertAfter inserts the `values` to the back of `index`.\nfunc (a *TArray[T]) InsertAfter(index int, values ...T) error {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif index < 0 || index >= len(a.array) {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"index %d out of array range %d\", index, len(a.array))\n\t}\n\trear := append([]T{}, a.array[index+1:]...)\n\ta.array = append(a.array[0:index+1], values...)\n\ta.array = append(a.array, rear...)\n\treturn nil\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *TArray[T]) Remove(index int) (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\treturn a.doRemoveWithoutLock(index)\n}\n\n// doRemoveWithoutLock removes an item by index without lock.\nfunc (a *TArray[T]) doRemoveWithoutLock(index int) (value T, found bool) {\n\tif index < 0 || index >= len(a.array) {\n\t\tfound = false\n\t\treturn\n\t}\n\t// Determine array boundaries when deleting to improve deletion efficiency.\n\tif index == 0 {\n\t\tvalue := a.array[0]\n\t\ta.array = a.array[1:]\n\t\treturn value, true\n\t} else if index == len(a.array)-1 {\n\t\tvalue := a.array[index]\n\t\ta.array = a.array[:index]\n\t\treturn value, true\n\t}\n\t// If it is a non-boundary delete,\n\t// it will involve the creation of an array,\n\t// then the deletion is less efficient.\n\tvalue = a.array[index]\n\ta.array = append(a.array[:index], a.array[index+1:]...)\n\treturn value, true\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *TArray[T]) RemoveValue(value T) bool {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif i := a.doSearchWithoutLock(value); i != -1 {\n\t\ta.doRemoveWithoutLock(i)\n\t\treturn true\n\t}\n\treturn false\n}\n\n// RemoveValues removes multiple items by `values`.\nfunc (a *TArray[T]) RemoveValues(values ...T) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor _, value := range values {\n\t\tif i := a.doSearchWithoutLock(value); i != -1 {\n\t\t\ta.doRemoveWithoutLock(i)\n\t\t}\n\t}\n}\n\n// PushLeft pushes one or multiple items to the beginning of array.\nfunc (a *TArray[T]) PushLeft(value ...T) *TArray[T] {\n\ta.mu.Lock()\n\ta.array = append(value, a.array...)\n\ta.mu.Unlock()\n\treturn a\n}\n\n// PushRight pushes one or multiple items to the end of array.\n// It equals to Append.\nfunc (a *TArray[T]) PushRight(value ...T) *TArray[T] {\n\ta.mu.Lock()\n\ta.array = append(a.array, value...)\n\ta.mu.Unlock()\n\treturn a\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *TArray[T]) PopRand() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\treturn a.doRemoveWithoutLock(grand.Intn(len(a.array)))\n}\n\n// PopRands randomly pops and returns `size` items out of array.\nfunc (a *TArray[T]) PopRands(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tif size >= len(a.array) {\n\t\tsize = len(a.array)\n\t}\n\tarray := make([]T, size)\n\tfor i := 0; i < size; i++ {\n\t\tarray[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))\n\t}\n\treturn array\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *TArray[T]) PopLeft() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif len(a.array) == 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\tvalue = a.array[0]\n\ta.array = a.array[1:]\n\treturn value, true\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *TArray[T]) PopRight() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tindex := len(a.array) - 1\n\tif index < 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\tvalue = a.array[index]\n\ta.array = a.array[:index]\n\treturn value, true\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\nfunc (a *TArray[T]) PopLefts(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tif size >= len(a.array) {\n\t\tarray := a.array\n\t\ta.array = a.array[:0]\n\t\treturn array\n\t}\n\tvalue := a.array[0:size]\n\ta.array = a.array[size:]\n\treturn value\n}\n\n// PopRights pops and returns `size` items from the end of array.\nfunc (a *TArray[T]) PopRights(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tindex := len(a.array) - size\n\tif index <= 0 {\n\t\tarray := a.array\n\t\ta.array = a.array[:0]\n\t\treturn array\n\t}\n\tvalue := a.array[index:]\n\ta.array = a.array[:index]\n\treturn value\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *TArray[T]) Range(start int, end ...int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\toffsetEnd := len(a.array)\n\tif len(end) > 0 && end[0] < offsetEnd {\n\t\toffsetEnd = end[0]\n\t}\n\tif start > offsetEnd {\n\t\treturn nil\n\t}\n\tif start < 0 {\n\t\tstart = 0\n\t}\n\tarray := ([]T)(nil)\n\tif a.mu.IsSafe() {\n\t\tarray = make([]T, offsetEnd-start)\n\t\tcopy(array, a.array[start:offsetEnd])\n\t} else {\n\t\tarray = a.array[start:offsetEnd]\n\t}\n\treturn array\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *TArray[T]) SubSlice(offset int, length ...int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tsize := len(a.array)\n\tif len(length) > 0 {\n\t\tsize = length[0]\n\t}\n\tif offset > len(a.array) {\n\t\treturn nil\n\t}\n\tif offset < 0 {\n\t\toffset = len(a.array) + offset\n\t\tif offset < 0 {\n\t\t\treturn nil\n\t\t}\n\t}\n\tif size < 0 {\n\t\toffset += size\n\t\tsize = -size\n\t\tif offset < 0 {\n\t\t\treturn nil\n\t\t}\n\t}\n\tend := offset + size\n\tif end > len(a.array) {\n\t\tend = len(a.array)\n\t\tsize = len(a.array) - offset\n\t}\n\tif a.mu.IsSafe() {\n\t\ts := make([]T, size)\n\t\tcopy(s, a.array[offset:])\n\t\treturn s\n\t} else {\n\t\treturn a.array[offset:end]\n\t}\n}\n\n// Append is alias of PushRight, please See PushRight.\nfunc (a *TArray[T]) Append(value ...T) *TArray[T] {\n\ta.PushRight(value...)\n\treturn a\n}\n\n// Len returns the length of array.\nfunc (a *TArray[T]) Len() int {\n\ta.mu.RLock()\n\tlength := len(a.array)\n\ta.mu.RUnlock()\n\treturn length\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *TArray[T]) Slice() []T {\n\tif a.mu.IsSafe() {\n\t\ta.mu.RLock()\n\t\tdefer a.mu.RUnlock()\n\t\tarray := make([]T, len(a.array))\n\t\tcopy(array, a.array)\n\t\treturn array\n\t} else {\n\t\treturn a.array\n\t}\n}\n\n// Interfaces returns current array as []any.\nfunc (a *TArray[T]) Interfaces() []any {\n\treturn tToAnySlice(a.Slice())\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *TArray[T]) Clone() (newArray *TArray[T]) {\n\ta.mu.RLock()\n\tarray := make([]T, len(a.array))\n\tcopy(array, a.array)\n\ta.mu.RUnlock()\n\treturn NewTArrayFrom(array, a.mu.IsSafe())\n}\n\n// Clear deletes all items of current array.\nfunc (a *TArray[T]) Clear() *TArray[T] {\n\ta.mu.Lock()\n\tif len(a.array) > 0 {\n\t\ta.array = make([]T, 0)\n\t}\n\ta.mu.Unlock()\n\treturn a\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *TArray[T]) Contains(value T) bool {\n\treturn a.Search(value) != -1\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *TArray[T]) Search(value T) int {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\treturn a.doSearchWithoutLock(value)\n}\n\nfunc (a *TArray[T]) doSearchWithoutLock(value T) int {\n\tif len(a.array) == 0 {\n\t\treturn -1\n\t}\n\tresult := -1\n\tfor index, v := range a.array {\n\t\tif v == value {\n\t\t\tresult = index\n\t\t\tbreak\n\t\t}\n\t}\n\treturn result\n}\n\n// Unique uniques the array, clear repeated items.\n// Example: [1,1,2,3,2] -> [1,2,3]\nfunc (a *TArray[T]) Unique() *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif len(a.array) == 0 {\n\t\treturn a\n\t}\n\tvar (\n\t\tok          bool\n\t\ttemp        T\n\t\tuniqueSet   = make(map[T]struct{})\n\t\tuniqueArray = make([]T, 0, len(a.array))\n\t)\n\tfor i := 0; i < len(a.array); i++ {\n\t\ttemp = a.array[i]\n\t\tif _, ok = uniqueSet[temp]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tuniqueSet[temp] = struct{}{}\n\t\tuniqueArray = append(uniqueArray, temp)\n\t}\n\ta.array = uniqueArray\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *TArray[T]) LockFunc(f func(array []T)) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tf(a.array)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *TArray[T]) RLockFunc(f func(array []T)) *TArray[T] {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tf(a.array)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *TArray[T]) Merge(array any) *TArray[T] {\n\tvar vals []T\n\tswitch v := array.(type) {\n\tcase *SortedTArray[T]:\n\t\tvals = v.Slice()\n\tcase *TArray[T]:\n\t\tvals = v.Slice()\n\tcase []T:\n\t\tvals = v\n\tdefault:\n\t\tinterfaces := gconv.Interfaces(v)\n\t\tif err := gconv.Scan(interfaces, &vals); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\n\treturn a.Append(vals...)\n}\n\n// Fill fills an array with num entries of the value `value`,\n// keys starting at the `startIndex` parameter.\nfunc (a *TArray[T]) Fill(startIndex int, num int, value T) error {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif startIndex < 0 || startIndex > len(a.array) {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"index %d out of array range %d\", startIndex, len(a.array))\n\t}\n\tfor i := startIndex; i < startIndex+num; i++ {\n\t\tif i > len(a.array)-1 {\n\t\t\ta.array = append(a.array, value)\n\t\t} else {\n\t\t\ta.array[i] = value\n\t\t}\n\t}\n\treturn nil\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *TArray[T]) Chunk(size int) [][]T {\n\tif size < 1 {\n\t\treturn nil\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tlength := len(a.array)\n\tchunks := int(math.Ceil(float64(length) / float64(size)))\n\tvar n [][]T\n\tfor i, end := 0, 0; chunks > 0; chunks-- {\n\t\tend = (i + 1) * size\n\t\tif end > length {\n\t\t\tend = length\n\t\t}\n\t\tn = append(n, a.array[i*size:end])\n\t\ti++\n\t}\n\treturn n\n}\n\n// Pad pads array to the specified length with `value`.\n// If size is positive then the array is padded on the right, or negative on the left.\n// If the absolute value of `size` is less than or equal to the length of the array\n// then no padding takes place.\nfunc (a *TArray[T]) Pad(size int, val T) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {\n\t\treturn a\n\t}\n\tn := size\n\tif size < 0 {\n\t\tn = -size\n\t}\n\tn -= len(a.array)\n\ttmp := make([]T, n)\n\tfor i := 0; i < n; i++ {\n\t\ttmp[i] = val\n\t}\n\tif size > 0 {\n\t\ta.array = append(a.array, tmp...)\n\t} else {\n\t\ta.array = append(tmp, a.array...)\n\t}\n\treturn a\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *TArray[T]) Rand() (value T, found bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\treturn a.array[grand.Intn(len(a.array))], true\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *TArray[T]) Rands(size int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tarray := make([]T, size)\n\tfor i := 0; i < size; i++ {\n\t\tarray[i] = a.array[grand.Intn(len(a.array))]\n\t}\n\treturn array\n}\n\n// Shuffle randomly shuffles the array.\nfunc (a *TArray[T]) Shuffle() *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i, v := range grand.Perm(len(a.array)) {\n\t\ta.array[i], a.array[v] = a.array[v], a.array[i]\n\t}\n\treturn a\n}\n\n// Reverse makes array with elements in reverse order.\nfunc (a *TArray[T]) Reverse() *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {\n\t\ta.array[i], a.array[j] = a.array[j], a.array[i]\n\t}\n\treturn a\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *TArray[T]) Join(glue string) string {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\treturn \"\"\n\t}\n\tbuffer := bytes.NewBuffer(nil)\n\tfor k, v := range a.array {\n\t\tbuffer.WriteString(gconv.String(v))\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteString(glue)\n\t\t}\n\t}\n\treturn buffer.String()\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *TArray[T]) CountValues() map[T]int {\n\tm := make(map[T]int)\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor _, v := range a.array {\n\t\tm[v]++\n\t}\n\treturn m\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *TArray[T]) Iterator(f func(k int, v T) bool) {\n\ta.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *TArray[T]) IteratorAsc(f func(k int, v T) bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor k, v := range a.array {\n\t\tif !f(k, v) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *TArray[T]) IteratorDesc(f func(k int, v T) bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor i := len(a.array) - 1; i >= 0; i-- {\n\t\tif !f(i, a.array[i]) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *TArray[T]) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteByte('[')\n\ts := \"\"\n\tfor k, v := range a.array {\n\t\ts = gconv.String(v)\n\t\tif gstr.IsNumeric(s) {\n\t\t\tbuffer.WriteString(s)\n\t\t} else {\n\t\t\tbuffer.WriteString(`\"` + gstr.QuoteMeta(s, `\"\\`) + `\"`)\n\t\t}\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// DO NOT change this receiver to pointer type, as the TArray can be used as a var defined variable, like:\n// var a TArray[int]\n// Please refer to corresponding tests for more details.\nfunc (a TArray[T]) MarshalJSON() ([]byte, error) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\treturn json.Marshal(a.array)\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *TArray[T]) UnmarshalJSON(b []byte) error {\n\tif a.array == nil {\n\t\ta.array = make([]T, 0)\n\t}\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif err := json.UnmarshalUseNumber(b, &a.array); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *TArray[T]) UnmarshalValue(value any) error {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tswitch value.(type) {\n\tcase string, []byte:\n\t\treturn json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)\n\tdefault:\n\t\tif err := gconv.Scan(gconv.SliceAny(value), &a.array); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *TArray[T]) Filter(filter func(index int, value T) bool) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif filter(i, a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// FilterNil removes all nil value of the array.\nfunc (a *TArray[T]) FilterNil() *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif empty.IsNil(a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// FilterEmpty removes all empty value of the array.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (a *TArray[T]) FilterEmpty() *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif empty.IsEmpty(a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *TArray[T]) Walk(f func(value T) T) *TArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i, v := range a.array {\n\t\ta.array[i] = f(v)\n\t}\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *TArray[T]) IsEmpty() bool {\n\treturn a.Len() == 0\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *TArray[T]) DeepCopy() any {\n\tif a == nil {\n\t\treturn nil\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tnewSlice := make([]T, len(a.array))\n\tfor i, v := range a.array {\n\t\tnewSlice[i] = deepcopy.Copy(v).(T)\n\t}\n\treturn NewTArrayFrom(newSlice, a.mu.IsSafe())\n}\n"
  },
  {
    "path": "container/garray/garray_sorted_any.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SortedArray is a golang sorted array with rich features.\n// It is using increasing order in default, which can be changed by\n// setting it a custom comparator.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype SortedArray struct {\n\t*SortedTArray[any]\n\tonce sync.Once\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *SortedArray) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.SortedTArray == nil {\n\t\t\ta.SortedTArray = NewSortedTArraySize[any](0, nil, false)\n\t\t}\n\t})\n}\n\n// NewSortedArray creates and returns an empty sorted array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety, which is false in default.\n// The parameter `comparator` used to compare values to sort in array,\n// if it returns value < 0, means `a` < `b`; the `a` will be inserted before `b`;\n// if it returns value = 0, means `a` = `b`; the `a` will be replaced by     `b`;\n// if it returns value > 0, means `a` > `b`; the `a` will be inserted after  `b`;\nfunc NewSortedArray(comparator func(a, b any) int, safe ...bool) *SortedArray {\n\treturn NewSortedArraySize(0, comparator, safe...)\n}\n\n// NewSortedArraySize create and returns an sorted array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedArraySize(cap int, comparator func(a, b any) int, safe ...bool) *SortedArray {\n\treturn &SortedArray{\n\t\tSortedTArray: NewSortedTArraySize(cap, comparator, safe...),\n\t}\n}\n\n// NewSortedArrayRange creates and returns an array by a range from `start` to `end`\n// with step value `step`.\nfunc NewSortedArrayRange(start, end, step int, comparator func(a, b any) int, safe ...bool) *SortedArray {\n\tif step == 0 {\n\t\tpanic(fmt.Sprintf(`invalid step value: %d`, step))\n\t}\n\tslice := make([]any, 0)\n\tindex := 0\n\tfor i := start; i <= end; i += step {\n\t\tslice = append(slice, i)\n\t\tindex++\n\t}\n\treturn NewSortedArrayFrom(slice, comparator, safe...)\n}\n\n// NewSortedArrayFrom creates and returns an sorted array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedArrayFrom(array []any, comparator func(a, b any) int, safe ...bool) *SortedArray {\n\ta := NewSortedArraySize(0, comparator, safe...)\n\ta.array = array\n\tsort.Slice(a.array, func(i, j int) bool {\n\t\treturn a.getComparator()(a.array[i], a.array[j]) < 0\n\t})\n\treturn a\n}\n\n// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedArrayFromCopy(array []any, comparator func(a, b any) int, safe ...bool) *SortedArray {\n\tnewArray := make([]any, len(array))\n\tcopy(newArray, array)\n\treturn NewSortedArrayFrom(newArray, comparator, safe...)\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns `nil`.\nfunc (a *SortedArray) At(index int) (value any) {\n\ta.lazyInit()\n\treturn a.SortedTArray.At(index)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *SortedArray) SetArray(array []any) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetArray(array)\n\treturn a\n}\n\n// SetComparator sets/changes the comparator for sorting.\n// It resorts the array as the comparator is changed.\nfunc (a *SortedArray) SetComparator(comparator func(a, b any) int) {\n\ta.lazyInit()\n\ta.SortedTArray.SetComparator(comparator)\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort\n// in increasing order(default) or decreasing order\nfunc (a *SortedArray) Sort() *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Sort()\n\treturn a\n}\n\n// Add adds one or multiple values to sorted array, the array always keeps sorted.\n// It's alias of function Append, see Append.\nfunc (a *SortedArray) Add(values ...any) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Add(values...)\n\treturn a\n}\n\n// Append adds one or multiple values to sorted array, the array always keeps sorted.\nfunc (a *SortedArray) Append(values ...any) *SortedArray {\n\ta.SortedTArray.Append(values...)\n\treturn a\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedArray) Get(index int) (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Get(index)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedArray) Remove(index int) (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *SortedArray) RemoveValue(value any) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.RemoveValue(value)\n}\n\n// RemoveValues removes an item by `values`.\nfunc (a *SortedArray) RemoveValues(values ...any) {\n\ta.lazyInit()\n\ta.SortedTArray.RemoveValues(values...)\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedArray) PopLeft() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedArray) PopRight() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRight()\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedArray) PopRand() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\nfunc (a *SortedArray) PopRands(size int) []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRands(size)\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\nfunc (a *SortedArray) PopLefts(size int) []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\nfunc (a *SortedArray) PopRights(size int) []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *SortedArray) Range(start int, end ...int) []any {\n\treturn a.SortedTArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *SortedArray) SubSlice(offset int, length ...int) []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.SubSlice(offset, length...)\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *SortedArray) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Sum()\n}\n\n// Len returns the length of array.\nfunc (a *SortedArray) Len() int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Len()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *SortedArray) Slice() []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *SortedArray) Interfaces() []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Interfaces()\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *SortedArray) Contains(value any) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.Contains(value)\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *SortedArray) Search(value any) (index int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Search(value)\n}\n\n// SetUnique sets unique mark to the array,\n// which means it does not contain any repeated items.\n// It also does unique check, remove all repeated items.\nfunc (a *SortedArray) SetUnique(unique bool) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetUnique(unique)\n\treturn a\n}\n\n// Unique uniques the array, clear repeated items.\nfunc (a *SortedArray) Unique() *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Unique()\n\treturn a\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *SortedArray) Clone() (newArray *SortedArray) {\n\ta.lazyInit()\n\treturn &SortedArray{\n\t\tSortedTArray: a.SortedTArray.Clone(),\n\t}\n}\n\n// Clear deletes all items of current array.\nfunc (a *SortedArray) Clear() *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Clear()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *SortedArray) LockFunc(f func(array []any)) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *SortedArray) RLockFunc(f func(array []any)) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *SortedArray) Merge(array any) *SortedArray {\n\treturn a.Add(gconv.Interfaces(array)...)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *SortedArray) Chunk(size int) [][]any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Chunk(size)\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *SortedArray) Rand() (value any, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *SortedArray) Rands(size int) []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rands(size)\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *SortedArray) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *SortedArray) CountValues() map[any]int {\n\ta.lazyInit()\n\treturn a.SortedTArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *SortedArray) Iterator(f func(k int, v any) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.Iterator(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedArray) IteratorAsc(f func(k int, v any) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedArray) IteratorDesc(f func(k int, v any) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *SortedArray) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.lazyInit()\n\treturn a.SortedTArray.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a SortedArray) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.SortedTArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\n// Note that the comparator is set as string comparator in default.\nfunc (a *SortedArray) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\treturn a.SortedTArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\n// Note that the comparator is set as string comparator in default.\nfunc (a *SortedArray) UnmarshalValue(value any) (err error) {\n\ta.lazyInit()\n\treturn a.SortedTArray.UnmarshalValue(value)\n}\n\n// FilterNil removes all nil value of the array.\nfunc (a *SortedArray) FilterNil() *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.FilterNil()\n\treturn a\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *SortedArray) Filter(filter func(index int, value any) bool) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Filter(filter)\n\treturn a\n}\n\n// FilterEmpty removes all empty value of the array.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (a *SortedArray) FilterEmpty() *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.FilterEmpty()\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *SortedArray) Walk(f func(value any) any) *SortedArray {\n\ta.lazyInit()\n\ta.SortedTArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *SortedArray) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *SortedArray) DeepCopy() any {\n\ta.lazyInit()\n\treturn &SortedArray{\n\t\tSortedTArray: a.SortedTArray.DeepCopy().(*SortedTArray[any]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_sorted_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SortedIntArray is a golang sorted int array with rich features.\n// It is using increasing order in default, which can be changed by\n// setting it a custom comparator.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype SortedIntArray struct {\n\t*SortedTArray[int]\n\tonce sync.Once\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *SortedIntArray) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.SortedTArray == nil {\n\t\t\ta.SortedTArray = NewSortedTArraySize(0, defaultComparatorInt, false)\n\t\t\ta.SetSorter(quickSortInt)\n\t\t}\n\t})\n}\n\n// NewSortedIntArray creates and returns an empty sorted array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedIntArray(safe ...bool) *SortedIntArray {\n\treturn NewSortedIntArraySize(0, safe...)\n}\n\n// NewSortedIntArrayComparator creates and returns an empty sorted array with specified comparator.\n// The parameter `safe` is used to specify whether using array in concurrent-safety which is false in default.\nfunc NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *SortedIntArray {\n\tarray := NewSortedIntArray(safe...)\n\tarray.comparator = comparator\n\treturn array\n}\n\n// NewSortedIntArraySize create and returns an sorted array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {\n\ta := NewSortedTArraySize(cap, defaultComparatorInt, safe...)\n\ta.SetSorter(quickSortInt)\n\treturn &SortedIntArray{\n\t\tSortedTArray: a,\n\t}\n}\n\n// NewSortedIntArrayRange creates and returns an array by a range from `start` to `end`\n// with step value `step`.\nfunc NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {\n\tif step == 0 {\n\t\tpanic(fmt.Sprintf(`invalid step value: %d`, step))\n\t}\n\tslice := make([]int, 0)\n\tindex := 0\n\tfor i := start; i <= end; i += step {\n\t\tslice = append(slice, i)\n\t\tindex++\n\t}\n\treturn NewSortedIntArrayFrom(slice, safe...)\n}\n\n// NewSortedIntArrayFrom creates and returns an sorted array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray {\n\ta := NewSortedIntArraySize(0, safe...)\n\ta.array = array\n\ta.sorter(a.array, defaultComparatorInt)\n\treturn a\n}\n\n// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedIntArrayFromCopy(array []int, safe ...bool) *SortedIntArray {\n\tnewArray := make([]int, len(array))\n\tcopy(newArray, array)\n\treturn NewSortedIntArrayFrom(newArray, safe...)\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns `0`.\nfunc (a *SortedIntArray) At(index int) (value int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.At(index)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *SortedIntArray) SetArray(array []int) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetArray(array)\n\treturn a\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort\n// in increasing order(default) or decreasing order.\nfunc (a *SortedIntArray) Sort() *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Sort()\n\treturn a\n}\n\n// Add adds one or multiple values to sorted array, the array always keeps sorted.\n// It's alias of function Append, see Append.\nfunc (a *SortedIntArray) Add(values ...int) *SortedIntArray {\n\ta.lazyInit()\n\treturn a.Append(values...)\n}\n\n// Append adds one or multiple values to sorted array, the array always keeps sorted.\nfunc (a *SortedIntArray) Append(values ...int) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Append(values...)\n\treturn a\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedIntArray) Get(index int) (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Get(index)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedIntArray) Remove(index int) (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *SortedIntArray) RemoveValue(value int) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.RemoveValue(value)\n}\n\n// RemoveValues removes an item by `values`.\nfunc (a *SortedIntArray) RemoveValues(values ...int) {\n\ta.lazyInit()\n\ta.SortedTArray.RemoveValues(values...)\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedIntArray) PopLeft() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedIntArray) PopRight() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRight()\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedIntArray) PopRand() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedIntArray) PopRands(size int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRands(size)\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedIntArray) PopLefts(size int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedIntArray) PopRights(size int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *SortedIntArray) Range(start int, end ...int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *SortedIntArray) SubSlice(offset int, length ...int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.SubSlice(offset, length...)\n}\n\n// Len returns the length of array.\nfunc (a *SortedIntArray) Len() int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Len()\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *SortedIntArray) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Sum()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *SortedIntArray) Slice() []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *SortedIntArray) Interfaces() []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Interfaces()\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *SortedIntArray) Contains(value int) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.Contains(value)\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *SortedIntArray) Search(value int) (index int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Search(value)\n}\n\n// SetUnique sets unique mark to the array,\n// which means it does not contain any repeated items.\n// It also do unique check, remove all repeated items.\nfunc (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetUnique(unique)\n\treturn a\n}\n\n// Unique uniques the array, clear repeated items.\nfunc (a *SortedIntArray) Unique() *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Unique()\n\treturn a\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *SortedIntArray) Clone() (newArray *SortedIntArray) {\n\ta.lazyInit()\n\treturn &SortedIntArray{\n\t\tSortedTArray: a.SortedTArray.Clone(),\n\t}\n}\n\n// Clear deletes all items of current array.\nfunc (a *SortedIntArray) Clear() *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Clear()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *SortedIntArray) Merge(array any) *SortedIntArray {\n\ta.lazyInit()\n\treturn a.Add(gconv.Ints(array)...)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *SortedIntArray) Chunk(size int) [][]int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Chunk(size)\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *SortedIntArray) Rand() (value int, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *SortedIntArray) Rands(size int) []int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rands(size)\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *SortedIntArray) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *SortedIntArray) CountValues() map[int]int {\n\ta.lazyInit()\n\treturn a.SortedTArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *SortedIntArray) Iterator(f func(k int, v int) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.Iterator(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *SortedIntArray) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.lazyInit()\n\treturn \"[\" + a.Join(\",\") + \"]\"\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a SortedIntArray) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.SortedTArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *SortedIntArray) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\tif a.comparator == nil || a.sorter == nil {\n\t\ta.comparator = defaultComparatorInt\n\t\ta.sorter = quickSortInt\n\t\ta.array = make([]int, 0)\n\t}\n\n\treturn a.SortedTArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *SortedIntArray) UnmarshalValue(value any) (err error) {\n\ta.lazyInit()\n\tif a.comparator == nil || a.sorter == nil {\n\t\ta.comparator = defaultComparatorInt\n\t\ta.sorter = quickSortInt\n\t}\n\n\treturn a.SortedTArray.UnmarshalValue(value)\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *SortedIntArray) Filter(filter func(index int, value int) bool) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Filter(filter)\n\treturn a\n}\n\n// FilterEmpty removes all zero value of the array.\nfunc (a *SortedIntArray) FilterEmpty() *SortedIntArray {\n\ta.lazyInit()\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\tif len(a.array) == 0 {\n\t\treturn a\n\t}\n\n\tif a.array[0] != 0 && a.array[len(a.array)-1] != 0 {\n\t\ta.SortedTArray.FilterEmpty()\n\t\treturn a\n\t}\n\n\tfor i := 0; i < len(a.array); {\n\t\tif a.array[i] == 0 {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tfor i := len(a.array) - 1; i >= 0; {\n\t\tif a.array[i] == 0 {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t\ti--\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *SortedIntArray) Walk(f func(value int) int) *SortedIntArray {\n\ta.lazyInit()\n\ta.SortedTArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *SortedIntArray) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *SortedIntArray) DeepCopy() any {\n\ta.lazyInit()\n\treturn &SortedIntArray{\n\t\tSortedTArray: a.SortedTArray.DeepCopy().(*SortedTArray[int]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_sorted_str.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SortedStrArray is a golang sorted string array with rich features.\n// It is using increasing order in default, which can be changed by\n// setting it a custom comparator.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype SortedStrArray struct {\n\t*SortedTArray[string]\n\tonce sync.Once\n}\n\n// lazyInit lazily initializes the array.\nfunc (a *SortedStrArray) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.SortedTArray == nil {\n\t\t\ta.SortedTArray = NewSortedTArraySize(0, defaultComparatorStr, false)\n\t\t\ta.SetSorter(quickSortStr)\n\t\t}\n\t})\n}\n\n// NewSortedStrArray creates and returns an empty sorted array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedStrArray(safe ...bool) *SortedStrArray {\n\treturn NewSortedStrArraySize(0, safe...)\n}\n\n// NewSortedStrArrayComparator creates and returns an empty sorted array with specified comparator.\n// The parameter `safe` is used to specify whether using array in concurrent-safety which is false in default.\nfunc NewSortedStrArrayComparator(comparator func(a, b string) int, safe ...bool) *SortedStrArray {\n\tarray := NewSortedStrArray(safe...)\n\tarray.comparator = comparator\n\treturn array\n}\n\n// NewSortedStrArraySize create and returns an sorted array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {\n\ta := NewSortedTArraySize(cap, defaultComparatorStr, safe...)\n\ta.SetSorter(quickSortStr)\n\treturn &SortedStrArray{\n\t\tSortedTArray: a,\n\t}\n}\n\n// NewSortedStrArrayFrom creates and returns an sorted array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {\n\ta := NewSortedStrArraySize(0, safe...)\n\ta.array = array\n\tquickSortStr(a.array, a.getComparator())\n\treturn a\n}\n\n// NewSortedStrArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedStrArrayFromCopy(array []string, safe ...bool) *SortedStrArray {\n\tnewArray := make([]string, len(array))\n\tcopy(newArray, array)\n\treturn NewSortedStrArrayFrom(newArray, safe...)\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *SortedStrArray) SetArray(array []string) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetArray(array)\n\treturn a\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns an empty string.\nfunc (a *SortedStrArray) At(index int) (value string) {\n\ta.lazyInit()\n\treturn a.SortedTArray.At(index)\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort\n// in increasing order(default) or decreasing order.\nfunc (a *SortedStrArray) Sort() *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Sort()\n\treturn a\n}\n\n// Add adds one or multiple values to sorted array, the array always keeps sorted.\n// It's alias of function Append, see Append.\nfunc (a *SortedStrArray) Add(values ...string) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Add(values...)\n\treturn a\n}\n\n// Append adds one or multiple values to sorted array, the array always keeps sorted.\nfunc (a *SortedStrArray) Append(values ...string) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Append(values...)\n\treturn a\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedStrArray) Get(index int) (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Get(index)\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedStrArray) Remove(index int) (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Remove(index)\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *SortedStrArray) RemoveValue(value string) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.RemoveValue(value)\n}\n\n// RemoveValues removes an item by `values`.\nfunc (a *SortedStrArray) RemoveValues(values ...string) {\n\ta.lazyInit()\n\ta.SortedTArray.RemoveValues(values...)\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedStrArray) PopLeft() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLeft()\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedStrArray) PopRight() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRight()\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedStrArray) PopRand() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRand()\n}\n\n// PopRands randomly pops and returns `size` items out of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedStrArray) PopRands(size int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRands(size)\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedStrArray) PopLefts(size int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopLefts(size)\n}\n\n// PopRights pops and returns `size` items from the end of array.\n// If the given `size` is greater than size of the array, it returns all elements of the array.\n// Note that if given `size` <= 0 or the array is empty, it returns nil.\nfunc (a *SortedStrArray) PopRights(size int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.PopRights(size)\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *SortedStrArray) Range(start int, end ...int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Range(start, end...)\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *SortedStrArray) SubSlice(offset int, length ...int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.SubSlice(offset, length...)\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *SortedStrArray) Sum() (sum int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Sum()\n}\n\n// Len returns the length of array.\nfunc (a *SortedStrArray) Len() int {\n\ta.lazyInit()\n\treturn a.SortedTArray.Len()\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *SortedStrArray) Slice() []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Slice()\n}\n\n// Interfaces returns current array as []any.\nfunc (a *SortedStrArray) Interfaces() []any {\n\ta.lazyInit()\n\treturn a.SortedTArray.Interfaces()\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *SortedStrArray) Contains(value string) bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.Contains(value)\n}\n\n// ContainsI checks whether a value exists in the array with case-insensitively.\n// Note that it internally iterates the whole array to do the comparison with case-insensitively.\nfunc (a *SortedStrArray) ContainsI(value string) bool {\n\ta.lazyInit()\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\treturn false\n\t}\n\tfor _, v := range a.array {\n\t\tif strings.EqualFold(v, value) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *SortedStrArray) Search(value string) (index int) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Search(value)\n}\n\n// SetUnique sets unique mark to the array,\n// which means it does not contain any repeated items.\n// It also do unique check, remove all repeated items.\nfunc (a *SortedStrArray) SetUnique(unique bool) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.SetUnique(unique)\n\treturn a\n}\n\n// Unique uniques the array, clear repeated items.\nfunc (a *SortedStrArray) Unique() *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Unique()\n\treturn a\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *SortedStrArray) Clone() (newArray *SortedStrArray) {\n\ta.lazyInit()\n\treturn &SortedStrArray{\n\t\tSortedTArray: a.SortedTArray.Clone(),\n\t}\n}\n\n// Clear deletes all items of current array.\nfunc (a *SortedStrArray) Clear() *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Clear()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *SortedStrArray) LockFunc(f func(array []string)) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.LockFunc(f)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *SortedStrArray) RLockFunc(f func(array []string)) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.RLockFunc(f)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *SortedStrArray) Merge(array any) *SortedStrArray {\n\ta.lazyInit()\n\treturn a.Add(gconv.Strings(array)...)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *SortedStrArray) Chunk(size int) [][]string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Chunk(size)\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *SortedStrArray) Rand() (value string, found bool) {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rand()\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *SortedStrArray) Rands(size int) []string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Rands(size)\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *SortedStrArray) Join(glue string) string {\n\ta.lazyInit()\n\treturn a.SortedTArray.Join(glue)\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *SortedStrArray) CountValues() map[string]int {\n\ta.lazyInit()\n\treturn a.SortedTArray.CountValues()\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *SortedStrArray) Iterator(f func(k int, v string) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.Iterator(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {\n\ta.lazyInit()\n\ta.SortedTArray.IteratorDesc(f)\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *SortedStrArray) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.lazyInit()\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteByte('[')\n\tfor k, v := range a.array {\n\t\tbuffer.WriteString(`\"` + gstr.QuoteMeta(v, `\"\\`) + `\"`)\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that do not use pointer as its receiver here.\nfunc (a SortedStrArray) MarshalJSON() ([]byte, error) {\n\ta.lazyInit()\n\treturn a.SortedTArray.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (a *SortedStrArray) UnmarshalJSON(b []byte) error {\n\ta.lazyInit()\n\tif a.comparator == nil || a.sorter == nil {\n\t\ta.comparator = defaultComparatorStr\n\t\ta.sorter = quickSortStr\n\t\ta.array = make([]string, 0)\n\t}\n\treturn a.SortedTArray.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\nfunc (a *SortedStrArray) UnmarshalValue(value any) (err error) {\n\ta.lazyInit()\n\tif a.comparator == nil || a.sorter == nil {\n\t\ta.comparator = defaultComparatorStr\n\t\ta.sorter = quickSortStr\n\t}\n\n\treturn a.SortedTArray.UnmarshalValue(value)\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *SortedStrArray) Filter(filter func(index int, value string) bool) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Filter(filter)\n\treturn a\n}\n\n// FilterEmpty removes all empty string value of the array.\nfunc (a *SortedStrArray) FilterEmpty() *SortedStrArray {\n\ta.lazyInit()\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\tif len(a.array) == 0 {\n\t\treturn a\n\t}\n\n\tif a.array[0] != \"\" && a.array[len(a.array)-1] != \"\" {\n\t\ta.SortedTArray.FilterEmpty()\n\t\treturn a\n\t}\n\n\tfor i := 0; i < len(a.array); {\n\t\tif a.array[i] == \"\" {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tfor i := len(a.array) - 1; i >= 0; {\n\t\tif a.array[i] == \"\" {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t\ti--\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *SortedStrArray) Walk(f func(value string) string) *SortedStrArray {\n\ta.lazyInit()\n\ta.SortedTArray.Walk(f)\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *SortedStrArray) IsEmpty() bool {\n\ta.lazyInit()\n\treturn a.SortedTArray.IsEmpty()\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *SortedStrArray) DeepCopy() any {\n\ta.lazyInit()\n\treturn &SortedStrArray{\n\t\tSortedTArray: a.SortedTArray.DeepCopy().(*SortedTArray[string]),\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_sorted_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// SortedTArray is a golang sorted array with rich features.\n// It is using increasing order in default, which can be changed by\n// setting it a custom comparator.\n// It contains a concurrent-safe/unsafe switch, which should be set\n// when its initialization and cannot be changed then.\ntype SortedTArray[T comparable] struct {\n\tmu         rwmutex.RWMutex\n\tarray      []T\n\tunique     bool             // Whether enable unique feature(false)\n\tcomparator func(a, b T) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)\n\tsorter     func(values []T, comparator func(a, b T) int)\n}\n\n// NewSortedTArray creates and returns an empty sorted array.\n// The parameter `safe` is used to specify whether using array in concurrent-safety, which is false in default.\n// The parameter `comparator` used to compare values to sort in array,\n// if it returns value < 0, means `a` < `b`; the `a` will be inserted before `b`;\n// if it returns value = 0, means `a` = `b`; the `a` will be replaced by     `b`;\n// if it returns value > 0, means `a` > `b`; the `a` will be inserted after  `b`;\nfunc NewSortedTArray[T comparable](comparator func(a, b T) int, safe ...bool) *SortedTArray[T] {\n\tif comparator == nil {\n\t\tcomparator = gutil.ComparatorTStr\n\t}\n\treturn NewSortedTArraySize(0, comparator, safe...)\n}\n\n// NewSortedTArraySize create and returns a sorted array with given size and cap.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedTArraySize[T comparable](cap int, comparator func(a, b T) int, safe ...bool) *SortedTArray[T] {\n\tif comparator == nil {\n\t\tcomparator = gutil.ComparatorTStr\n\t}\n\treturn &SortedTArray[T]{\n\t\tmu:         rwmutex.Create(safe...),\n\t\tarray:      make([]T, 0, cap),\n\t\tcomparator: comparator,\n\t\tsorter:     nil,\n\t}\n}\n\n// NewSortedTArrayFrom creates and returns an sorted array with given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedTArrayFrom[T comparable](array []T, comparator func(a, b T) int, safe ...bool) *SortedTArray[T] {\n\tif comparator == nil {\n\t\tcomparator = gutil.ComparatorTStr\n\t}\n\ta := NewSortedTArraySize(0, comparator, safe...)\n\ta.array = array\n\ta.getSorter()(a.array, a.getComparator())\n\treturn a\n}\n\n// NewSortedTArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using array in concurrent-safety,\n// which is false in default.\nfunc NewSortedTArrayFromCopy[T comparable](array []T, comparator func(a, b T) int, safe ...bool) *SortedTArray[T] {\n\tif comparator == nil {\n\t\tcomparator = gutil.ComparatorTStr\n\t}\n\tnewArray := make([]T, len(array))\n\tcopy(newArray, array)\n\treturn NewSortedTArrayFrom(newArray, comparator, safe...)\n}\n\nfunc (a *SortedTArray[T]) getSorter() func(values []T, comparator func(a, b T) int) {\n\tif a.sorter == nil {\n\t\treturn defaultSorter\n\t} else {\n\t\treturn a.sorter\n\t}\n}\n\n// At returns the value by the specified index.\n// If the given `index` is out of range of the array, it returns the zero value of type `T`\nfunc (a *SortedTArray[T]) At(index int) (value T) {\n\tvalue, _ = a.Get(index)\n\treturn\n}\n\n// SetArray sets the underlying slice array with the given `array`.\nfunc (a *SortedTArray[T]) SetArray(array []T) *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\ta.array = array\n\ta.getSorter()(a.array, a.getComparator())\n\n\treturn a\n}\n\n// SetSorter sets/changes the sorter for sorting.\nfunc (a *SortedTArray[T]) SetSorter(sorter func(values []T, comparator func(a, b T) int)) {\n\tif sorter == nil {\n\t\ta.sorter = defaultSorter\n\t} else {\n\t\ta.sorter = sorter\n\t}\n\ta.sorter(a.array, a.getComparator())\n}\n\n// SetComparator sets/changes the comparator for sorting.\n// It resorts the array as the comparator is changed.\nfunc (a *SortedTArray[T]) SetComparator(comparator func(a, b T) int) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif comparator == nil {\n\t\tcomparator = gutil.ComparatorTStr\n\t}\n\ta.comparator = comparator\n\ta.getSorter()(a.array, comparator)\n}\n\n// Sort sorts the array in increasing order.\n// The parameter `reverse` controls whether sort\n// in increasing order(default) or decreasing order\nfunc (a *SortedTArray[T]) Sort() *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\ta.getSorter()(a.array, a.getComparator())\n\n\treturn a\n}\n\n// Add adds one or multiple values to sorted array, the array always keeps sorted.\n// It's alias of function Append, see Append.\nfunc (a *SortedTArray[T]) Add(values ...T) *SortedTArray[T] {\n\treturn a.Append(values...)\n}\n\n// Append adds one or multiple values to sorted array, the array always keeps sorted.\nfunc (a *SortedTArray[T]) Append(values ...T) *SortedTArray[T] {\n\tif len(values) == 0 {\n\t\treturn a\n\t}\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor _, value := range values {\n\t\tindex, cmp := a.binSearch(value, false)\n\t\tif a.unique && cmp == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif index < 0 {\n\t\t\ta.array = append(a.array, value)\n\t\t\tcontinue\n\t\t}\n\t\tif cmp > 0 {\n\t\t\tindex++\n\t\t}\n\t\ta.array = append(a.array[:index], append([]T{value}, a.array[index:]...)...)\n\t}\n\treturn a\n}\n\n// Get returns the value by the specified index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedTArray[T]) Get(index int) (value T, found bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif index < 0 || index >= len(a.array) {\n\t\tfound = false\n\t\treturn\n\t}\n\treturn a.array[index], true\n}\n\n// Remove removes an item by index.\n// If the given `index` is out of range of the array, the `found` is false.\nfunc (a *SortedTArray[T]) Remove(index int) (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\treturn a.doRemoveWithoutLock(index)\n}\n\n// doRemoveWithoutLock removes an item by index without lock.\nfunc (a *SortedTArray[T]) doRemoveWithoutLock(index int) (value T, found bool) {\n\tif index < 0 || index >= len(a.array) {\n\t\tfound = false\n\t\treturn\n\t}\n\t// Determine array boundaries when deleting to improve deletion efficiency.\n\tif index == 0 {\n\t\tvalue := a.array[0]\n\t\ta.array = a.array[1:]\n\t\treturn value, true\n\t} else if index == len(a.array)-1 {\n\t\tvalue := a.array[index]\n\t\ta.array = a.array[:index]\n\t\treturn value, true\n\t}\n\t// If it is a non-boundary delete,\n\t// it will involve the creation of an array,\n\t// then the deletion is less efficient.\n\tvalue = a.array[index]\n\ta.array = append(a.array[:index], a.array[index+1:]...)\n\treturn value, true\n}\n\n// RemoveValue removes an item by value.\n// It returns true if value is found in the array, or else false if not found.\nfunc (a *SortedTArray[T]) RemoveValue(value T) bool {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif i, r := a.binSearch(value, false); r == 0 {\n\t\t_, res := a.doRemoveWithoutLock(i)\n\t\treturn res\n\t}\n\treturn false\n}\n\n// RemoveValues removes an item by `values`.\nfunc (a *SortedTArray[T]) RemoveValues(values ...T) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor _, value := range values {\n\t\tif i, r := a.binSearch(value, false); r == 0 {\n\t\t\ta.doRemoveWithoutLock(i)\n\t\t}\n\t}\n}\n\n// PopLeft pops and returns an item from the beginning of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedTArray[T]) PopLeft() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif len(a.array) == 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\tvalue = a.array[0]\n\ta.array = a.array[1:]\n\treturn value, true\n}\n\n// PopRight pops and returns an item from the end of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedTArray[T]) PopRight() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tindex := len(a.array) - 1\n\tif index < 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\tvalue = a.array[index]\n\ta.array = a.array[:index]\n\treturn value, true\n}\n\n// PopRand randomly pops and return an item out of array.\n// Note that if the array is empty, the `found` is false.\nfunc (a *SortedTArray[T]) PopRand() (value T, found bool) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\treturn a.doRemoveWithoutLock(grand.Intn(len(a.array)))\n}\n\n// PopRands randomly pops and returns `size` items out of array.\nfunc (a *SortedTArray[T]) PopRands(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tif size >= len(a.array) {\n\t\tsize = len(a.array)\n\t}\n\tarray := make([]T, size)\n\tfor i := 0; i < size; i++ {\n\t\tarray[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))\n\t}\n\treturn array\n}\n\n// PopLefts pops and returns `size` items from the beginning of array.\nfunc (a *SortedTArray[T]) PopLefts(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tif size >= len(a.array) {\n\t\tarray := a.array\n\t\ta.array = a.array[:0]\n\t\treturn array\n\t}\n\tvalue := a.array[0:size]\n\ta.array = a.array[size:]\n\treturn value\n}\n\n// PopRights pops and returns `size` items from the end of array.\nfunc (a *SortedTArray[T]) PopRights(size int) []T {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tindex := len(a.array) - size\n\tif index <= 0 {\n\t\tarray := a.array\n\t\ta.array = a.array[:0]\n\t\treturn array\n\t}\n\tvalue := a.array[index:]\n\ta.array = a.array[:index]\n\treturn value\n}\n\n// Range picks and returns items by range, like array[start:end].\n// Notice, if in concurrent-safe usage, it returns a copy of slice;\n// else a pointer to the underlying data.\n//\n// If `end` is negative, then the offset will start from the end of array.\n// If `end` is omitted, then the sequence will have everything from start up\n// until the end of the array.\nfunc (a *SortedTArray[T]) Range(start int, end ...int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\toffsetEnd := len(a.array)\n\tif len(end) > 0 && end[0] < offsetEnd {\n\t\toffsetEnd = end[0]\n\t}\n\tif start > offsetEnd {\n\t\treturn nil\n\t}\n\tif start < 0 {\n\t\tstart = 0\n\t}\n\tarray := ([]T)(nil)\n\tif a.mu.IsSafe() {\n\t\tarray = make([]T, offsetEnd-start)\n\t\tcopy(array, a.array[start:offsetEnd])\n\t} else {\n\t\tarray = a.array[start:offsetEnd]\n\t}\n\treturn array\n}\n\n// SubSlice returns a slice of elements from the array as specified\n// by the `offset` and `size` parameters.\n// If in concurrent safe usage, it returns a copy of the slice; else a pointer.\n//\n// If offset is non-negative, the sequence will start at that offset in the array.\n// If offset is negative, the sequence will start that far from the end of the array.\n//\n// If length is given and is positive, then the sequence will have up to that many elements in it.\n// If the array is shorter than the length, then only the available array elements will be present.\n// If length is given and is negative then the sequence will stop that many elements from the end of the array.\n// If it is omitted, then the sequence will have everything from offset up until the end of the array.\n//\n// Any possibility crossing the left border of array, it will fail.\nfunc (a *SortedTArray[T]) SubSlice(offset int, length ...int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tsize := len(a.array)\n\tif len(length) > 0 {\n\t\tsize = length[0]\n\t}\n\tif offset > len(a.array) {\n\t\treturn nil\n\t}\n\tif offset < 0 {\n\t\toffset = len(a.array) + offset\n\t\tif offset < 0 {\n\t\t\treturn nil\n\t\t}\n\t}\n\tif size < 0 {\n\t\toffset += size\n\t\tsize = -size\n\t\tif offset < 0 {\n\t\t\treturn nil\n\t\t}\n\t}\n\tend := offset + size\n\tif end > len(a.array) {\n\t\tend = len(a.array)\n\t\tsize = len(a.array) - offset\n\t}\n\tif a.mu.IsSafe() {\n\t\ts := make([]T, size)\n\t\tcopy(s, a.array[offset:])\n\t\treturn s\n\t} else {\n\t\treturn a.array[offset:end]\n\t}\n}\n\n// Sum returns the sum of values in an array.\nfunc (a *SortedTArray[T]) Sum() (sum int) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor _, v := range a.array {\n\t\tsum += gconv.Int(v)\n\t}\n\treturn\n}\n\n// Len returns the length of array.\nfunc (a *SortedTArray[T]) Len() int {\n\ta.mu.RLock()\n\tlength := len(a.array)\n\ta.mu.RUnlock()\n\treturn length\n}\n\n// Slice returns the underlying data of array.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (a *SortedTArray[T]) Slice() []T {\n\tvar array []T\n\tif a.mu.IsSafe() {\n\t\ta.mu.RLock()\n\t\tdefer a.mu.RUnlock()\n\t\tarray = make([]T, len(a.array))\n\t\tcopy(array, a.array)\n\t} else {\n\t\tarray = a.array\n\t}\n\treturn array\n}\n\n// Interfaces returns current array as []any.\nfunc (a *SortedTArray[T]) Interfaces() []any {\n\treturn tToAnySlice(a.Slice())\n}\n\n// Contains checks whether a value exists in the array.\nfunc (a *SortedTArray[T]) Contains(value T) bool {\n\treturn a.Search(value) != -1\n}\n\n// Search searches array by `value`, returns the index of `value`,\n// or returns -1 if not exists.\nfunc (a *SortedTArray[T]) Search(value T) (index int) {\n\tif i, r := a.binSearch(value, true); r == 0 {\n\t\treturn i\n\t}\n\treturn -1\n}\n\n// Binary search.\n// It returns the last compared index and the result.\n// If `result` equals to 0, it means the value at `index` is equals to `value`.\n// If `result` lesser than 0, it means the value at `index` is lesser than `value`.\n// If `result` greater than 0, it means the value at `index` is greater than `value`.\nfunc (a *SortedTArray[T]) binSearch(value T, lock bool) (index int, result int) {\n\tif lock {\n\t\ta.mu.RLock()\n\t\tdefer a.mu.RUnlock()\n\t}\n\tif len(a.array) == 0 {\n\t\treturn -1, -2\n\t}\n\tmin := 0\n\tmax := len(a.array) - 1\n\tmid := 0\n\tcmp := -2\n\tfor min <= max {\n\t\tmid = min + (max-min)/2\n\t\tcmp = a.getComparator()(value, a.array[mid])\n\t\tswitch {\n\t\tcase cmp < 0:\n\t\t\tmax = mid - 1\n\t\tcase cmp > 0:\n\t\t\tmin = mid + 1\n\t\tdefault:\n\t\t\treturn mid, cmp\n\t\t}\n\t}\n\treturn mid, cmp\n}\n\n// SetUnique sets unique mark to the array,\n// which means it does not contain any repeated items.\n// It also does unique check, remove all repeated items.\nfunc (a *SortedTArray[T]) SetUnique(unique bool) *SortedTArray[T] {\n\toldUnique := a.unique\n\ta.unique = unique\n\tif unique && oldUnique != unique {\n\t\ta.Unique()\n\t}\n\treturn a\n}\n\n// Unique uniques the array, clear repeated items.\nfunc (a *SortedTArray[T]) Unique() *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif len(a.array) == 0 {\n\t\treturn a\n\t}\n\tfor i := 0; i < len(a.array)-1; {\n\t\tif a.getComparator()(a.array[i], a.array[i+1]) == 0 {\n\t\t\ta.array = append(a.array[:i+1], a.array[i+2:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// Clone returns a new array, which is a copy of current array.\nfunc (a *SortedTArray[T]) Clone() (newArray *SortedTArray[T]) {\n\ta.mu.RLock()\n\tarray := make([]T, len(a.array))\n\tcopy(array, a.array)\n\ta.mu.RUnlock()\n\treturn NewSortedTArrayFrom[T](array, a.comparator, a.mu.IsSafe())\n}\n\n// Clear deletes all items of current array.\nfunc (a *SortedTArray[T]) Clear() *SortedTArray[T] {\n\ta.mu.Lock()\n\tif len(a.array) > 0 {\n\t\ta.array = make([]T, 0)\n\t}\n\ta.mu.Unlock()\n\treturn a\n}\n\n// LockFunc locks writing by callback function `f`.\nfunc (a *SortedTArray[T]) LockFunc(f func(array []T)) *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\t// Keep the array always sorted.\n\tdefer a.getSorter()(a.array, a.getComparator())\n\n\tf(a.array)\n\treturn a\n}\n\n// RLockFunc locks reading by callback function `f`.\nfunc (a *SortedTArray[T]) RLockFunc(f func(array []T)) *SortedTArray[T] {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tf(a.array)\n\treturn a\n}\n\n// Merge merges `array` into current array.\n// The parameter `array` can be any garray or slice type.\n// The difference between Merge and Append is Append supports only specified slice type,\n// but Merge supports more parameter types.\nfunc (a *SortedTArray[T]) Merge(array any) *SortedTArray[T] {\n\tvar vals []T\n\tswitch v := array.(type) {\n\tcase *SortedTArray[T]:\n\t\tvals = v.Slice()\n\tcase *TArray[T]:\n\t\tvals = v.Slice()\n\tcase []T:\n\t\tvals = v\n\tdefault:\n\t\tinterfaces := gconv.Interfaces(v)\n\t\tif err := gconv.Scan(interfaces, &vals); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\n\treturn a.Add(vals...)\n}\n\n// Chunk splits an array into multiple arrays,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (a *SortedTArray[T]) Chunk(size int) [][]T {\n\tif size < 1 {\n\t\treturn nil\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tlength := len(a.array)\n\tchunks := int(math.Ceil(float64(length) / float64(size)))\n\tvar n [][]T\n\tfor i, end := 0, 0; chunks > 0; chunks-- {\n\t\tend = (i + 1) * size\n\t\tif end > length {\n\t\t\tend = length\n\t\t}\n\t\tn = append(n, a.array[i*size:end])\n\t\ti++\n\t}\n\treturn n\n}\n\n// Rand randomly returns one item from array(no deleting).\nfunc (a *SortedTArray[T]) Rand() (value T, found bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\tfound = false\n\t\treturn\n\t}\n\treturn a.array[grand.Intn(len(a.array))], true\n}\n\n// Rands randomly returns `size` items from array(no deleting).\nfunc (a *SortedTArray[T]) Rands(size int) []T {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif size <= 0 || len(a.array) == 0 {\n\t\treturn nil\n\t}\n\tarray := make([]T, size)\n\tfor i := 0; i < size; i++ {\n\t\tarray[i] = a.array[grand.Intn(len(a.array))]\n\t}\n\treturn array\n}\n\n// Join joins array elements with a string `glue`.\nfunc (a *SortedTArray[T]) Join(glue string) string {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tif len(a.array) == 0 {\n\t\treturn \"\"\n\t}\n\tbuffer := bytes.NewBuffer(nil)\n\tfor k, v := range a.array {\n\t\tbuffer.WriteString(gconv.String(v))\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteString(glue)\n\t\t}\n\t}\n\treturn buffer.String()\n}\n\n// CountValues counts the number of occurrences of all values in the array.\nfunc (a *SortedTArray[T]) CountValues() map[T]int {\n\tm := make(map[T]int)\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor _, v := range a.array {\n\t\tm[v]++\n\t}\n\treturn m\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (a *SortedTArray[T]) Iterator(f func(k int, v T) bool) {\n\ta.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedTArray[T]) IteratorAsc(f func(k int, v T) bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor k, v := range a.array {\n\t\tif !f(k, v) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (a *SortedTArray[T]) IteratorDesc(f func(k int, v T) bool) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tfor i := len(a.array) - 1; i >= 0; i-- {\n\t\tif !f(i, a.array[i]) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// String returns current array as a string, which implements like json.Marshal does.\nfunc (a *SortedTArray[T]) String() string {\n\tif a == nil {\n\t\treturn \"\"\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteByte('[')\n\ts := \"\"\n\tfor k, v := range a.array {\n\t\ts = gconv.String(v)\n\t\tif gstr.IsNumeric(s) {\n\t\t\tbuffer.WriteString(s)\n\t\t} else {\n\t\t\tbuffer.WriteString(`\"` + gstr.QuoteMeta(s, `\"\\`) + `\"`)\n\t\t}\n\t\tif k != len(a.array)-1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// DO NOT change this receiver to pointer type, as the TArray can be used as a var defined variable, like:\n// var a SortedTArray[int]\n// Please refer to corresponding tests for more details.\nfunc (a SortedTArray[T]) MarshalJSON() ([]byte, error) {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\treturn json.Marshal(a.array)\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\n// Note that the comparator is set as string comparator in default.\nfunc (a *SortedTArray[T]) UnmarshalJSON(b []byte) error {\n\tif a.comparator == nil {\n\t\ta.array = make([]T, 0)\n\t\ta.comparator = gutil.ComparatorTStr\n\t}\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif err := json.UnmarshalUseNumber(b, &a.array); err != nil {\n\t\treturn err\n\t}\n\tif a.comparator != nil && a.array != nil {\n\t\ta.getSorter()(a.array, a.comparator)\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for array.\n// Note that the comparator is set as string comparator in default.\nfunc (a *SortedTArray[T]) UnmarshalValue(value any) (err error) {\n\tif a.comparator == nil {\n\t\ta.comparator = gutil.ComparatorTStr\n\t}\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tswitch value.(type) {\n\tcase string, []byte:\n\t\terr = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)\n\tdefault:\n\t\tif err = gconv.Scan(value, &a.array); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tif a.comparator != nil && a.array != nil {\n\t\ta.getSorter()(a.array, a.comparator)\n\t}\n\treturn err\n}\n\n// FilterNil removes all nil value of the array.\nfunc (a *SortedTArray[T]) FilterNil() *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif empty.IsNil(a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// Filter iterates array and filters elements using custom callback function.\n// It removes the element from array if callback function `filter` returns true,\n// it or else does nothing and continues iterating.\nfunc (a *SortedTArray[T]) Filter(filter func(index int, value T) bool) *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif filter(i, a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// FilterEmpty removes all empty value of the array.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (a *SortedTArray[T]) FilterEmpty() *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tfor i := 0; i < len(a.array); {\n\t\tif empty.IsEmpty(a.array[i]) {\n\t\t\ta.array = append(a.array[:i], a.array[i+1:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\treturn a\n}\n\n// Walk applies a user supplied function `f` to every item of array.\nfunc (a *SortedTArray[T]) Walk(f func(value T) T) *SortedTArray[T] {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\t// Keep the array always sorted.\n\tdefer a.getSorter()(a.array, a.getComparator())\n\n\tfor i, v := range a.array {\n\t\ta.array[i] = f(v)\n\t}\n\treturn a\n}\n\n// IsEmpty checks whether the array is empty.\nfunc (a *SortedTArray[T]) IsEmpty() bool {\n\treturn a.Len() == 0\n}\n\n// getComparator returns the comparator if it's previously set,\n// or else it panics.\nfunc (a *SortedTArray[T]) getComparator() func(a, b T) int {\n\tif a.comparator == nil {\n\t\ta.comparator = gutil.ComparatorTStr\n\t}\n\treturn a.comparator\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (a *SortedTArray[T]) DeepCopy() any {\n\tif a == nil {\n\t\treturn nil\n\t}\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\tnewSlice := make([]T, len(a.array))\n\tfor i, v := range a.array {\n\t\tnewSlice[i], _ = deepcopy.Copy(v).(T)\n\t}\n\treturn NewSortedTArrayFrom[T](newSlice, a.comparator, a.mu.IsSafe())\n}\n"
  },
  {
    "path": "container/garray/garray_z_bench_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n)\n\ntype anySortedArrayItem struct {\n\tpriority int64\n\tvalue    any\n}\n\nvar (\n\tanyArray       = garray.NewArray()\n\tanySortedArray = garray.NewSortedArray(func(a, b any) int {\n\t\treturn int(a.(anySortedArrayItem).priority - b.(anySortedArrayItem).priority)\n\t})\n)\n\nfunc Benchmark_AnyArray_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanyArray.Append(i)\n\t}\n}\n\nfunc Benchmark_AnySortedArray_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanySortedArray.Add(anySortedArrayItem{\n\t\t\tpriority: int64(i),\n\t\t\tvalue:    i,\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_normal_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n)\n\nfunc ExampleNew() {\n\t// A normal array.\n\ta := garray.New()\n\n\t// Adding items.\n\tfor i := 0; i < 10; i++ {\n\t\ta.Append(i)\n\t}\n\n\t// Print the array length.\n\tfmt.Println(a.Len())\n\n\t// Print the array items.\n\tfmt.Println(a.Slice())\n\n\t// Retrieve item by index.\n\tfmt.Println(a.Get(6))\n\n\t// Check item existence.\n\tfmt.Println(a.Contains(6))\n\tfmt.Println(a.Contains(100))\n\n\t// Insert item before specified index.\n\ta.InsertAfter(9, 11)\n\t// Insert item after specified index.\n\ta.InsertBefore(10, 10)\n\n\tfmt.Println(a.Slice())\n\n\t// Modify item by index.\n\ta.Set(0, 100)\n\tfmt.Println(a.Slice())\n\n\tfmt.Println(a.At(0))\n\n\t// Search item and return its index.\n\tfmt.Println(a.Search(5))\n\n\t// Remove item by index.\n\ta.Remove(0)\n\tfmt.Println(a.Slice())\n\n\t// Empty the array, removes all items of it.\n\tfmt.Println(a.Slice())\n\ta.Clear()\n\tfmt.Println(a.Slice())\n\n\t// Output:\n\t// 10\n\t// [0 1 2 3 4 5 6 7 8 9]\n\t// 6 true\n\t// true\n\t// false\n\t// [0 1 2 3 4 5 6 7 8 9 10 11]\n\t// [100 1 2 3 4 5 6 7 8 9 10 11]\n\t// 100\n\t// 5\n\t// [1 2 3 4 5 6 7 8 9 10 11]\n\t// [1 2 3 4 5 6 7 8 9 10 11]\n\t// []\n}\n\nfunc ExampleArray_Iterator() {\n\tarray := garray.NewArrayFrom(g.Slice{\"a\", \"b\", \"c\"})\n\t// Iterator is alias of IteratorAsc, which iterates the array readonly in ascending order\n\t//  with given callback function `f`.\n\t// If `f` returns true, then it continues iterating; or false to stop.\n\tarray.Iterator(func(k int, v any) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\t// IteratorDesc iterates the array readonly in descending order with given callback function `f`.\n\t// If `f` returns true, then it continues iterating; or false to stop.\n\tarray.IteratorDesc(func(k int, v any) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n\t// 2 c\n\t// 1 b\n\t// 0 a\n}\n\nfunc ExampleArray_Reverse() {\n\tarray := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Reverse makes array with elements in reverse order.\n\tfmt.Println(array.Reverse().Slice())\n\n\t// Output:\n\t// [9 8 7 6 5 4 3 2 1]\n}\n\nfunc ExampleArray_Shuffle() {\n\tarray := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Shuffle randomly shuffles the array.\n\tfmt.Println(array.Shuffle().Slice())\n}\n\nfunc ExampleArray_Rands() {\n\tarray := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Randomly retrieve and return 2 items from the array.\n\t// It does not delete the items from array.\n\tfmt.Println(array.Rands(2))\n\n\t// Randomly pick and return one item from the array.\n\t// It deletes the picked up item from array.\n\tfmt.Println(array.PopRand())\n}\n\nfunc ExampleArray_PopRand() {\n\tarray := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Randomly retrieve and return 2 items from the array.\n\t// It does not delete the items from array.\n\tfmt.Println(array.Rands(2))\n\n\t// Randomly pick and return one item from the array.\n\t// It deletes the picked up item from array.\n\tfmt.Println(array.PopRand())\n}\n\nfunc ExampleArray_Join() {\n\tarray := garray.NewFrom(g.Slice{\"a\", \"b\", \"c\", \"d\"})\n\tfmt.Println(array.Join(\",\"))\n\n\t// Output:\n\t// a,b,c,d\n}\n\nfunc ExampleArray_Chunk() {\n\tarray := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Chunk splits an array into multiple arrays,\n\t// the size of each array is determined by `size`.\n\t// The last chunk may contain less than size elements.\n\tfmt.Println(array.Chunk(2))\n\n\t// Output:\n\t// [[1 2] [3 4] [5 6] [7 8] [9]]\n}\n\nfunc ExampleArray_PopLeft() {\n\tarray := garray.NewFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Any Pop* functions pick, delete and return the item from array.\n\n\tfmt.Println(array.PopLeft())\n\tfmt.Println(array.PopLefts(2))\n\tfmt.Println(array.PopRight())\n\tfmt.Println(array.PopRights(2))\n\n\t// Output:\n\t// 1 true\n\t// [2 3]\n\t// 9 true\n\t// [7 8]\n}\n\nfunc ExampleArray_PopLefts() {\n\tarray := garray.NewFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Any Pop* functions pick, delete and return the item from array.\n\n\tfmt.Println(array.PopLeft())\n\tfmt.Println(array.PopLefts(2))\n\tfmt.Println(array.PopRight())\n\tfmt.Println(array.PopRights(2))\n\n\t// Output:\n\t// 1 true\n\t// [2 3]\n\t// 9 true\n\t// [7 8]\n}\n\nfunc ExampleArray_PopRight() {\n\tarray := garray.NewFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Any Pop* functions pick, delete and return the item from array.\n\n\tfmt.Println(array.PopLeft())\n\tfmt.Println(array.PopLefts(2))\n\tfmt.Println(array.PopRight())\n\tfmt.Println(array.PopRights(2))\n\n\t// Output:\n\t// 1 true\n\t// [2 3]\n\t// 9 true\n\t// [7 8]\n}\n\nfunc ExampleArray_PopRights() {\n\tarray := garray.NewFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t// Any Pop* functions pick, delete and return the item from array.\n\n\tfmt.Println(array.PopLeft())\n\tfmt.Println(array.PopLefts(2))\n\tfmt.Println(array.PopRight())\n\tfmt.Println(array.PopRights(2))\n\n\t// Output:\n\t// 1 true\n\t// [2 3]\n\t// 9 true\n\t// [7 8]\n}\n\nfunc ExampleArray_Contains() {\n\tvar array garray.StrArray\n\tarray.Append(\"a\")\n\tfmt.Println(array.Contains(\"a\"))\n\tfmt.Println(array.Contains(\"A\"))\n\tfmt.Println(array.ContainsI(\"A\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// true\n}\n\nfunc ExampleArray_Merge() {\n\tarray1 := garray.NewFrom(g.Slice{1, 2})\n\tarray2 := garray.NewFrom(g.Slice{3, 4})\n\tslice1 := g.Slice{5, 6}\n\tslice2 := []int{7, 8}\n\tslice3 := []string{\"9\", \"0\"}\n\tfmt.Println(array1.Slice())\n\tarray1.Merge(array1)\n\tarray1.Merge(array2)\n\tarray1.Merge(slice1)\n\tarray1.Merge(slice2)\n\tarray1.Merge(slice3)\n\tfmt.Println(array1.Slice())\n\n\t// Output:\n\t// [1 2]\n\t// [1 2 1 2 3 4 5 6 7 8 9 0]\n}\n\nfunc ExampleArray_Filter() {\n\tarray1 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tarray2 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tfmt.Printf(\"%#v\\n\", array1.Filter(func(index int, value any) bool {\n\t\treturn empty.IsNil(value)\n\t}).Slice())\n\tfmt.Printf(\"%#v\\n\", array2.Filter(func(index int, value any) bool {\n\t\treturn empty.IsEmpty(value)\n\t}).Slice())\n\n\t// Output:\n\t// []interface {}{0, 1, 2, \"\", []interface {}{}, \"john\"}\n\t// []interface {}{1, 2, \"john\"}\n}\n\nfunc ExampleArray_FilterEmpty() {\n\tarray1 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tarray2 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tfmt.Printf(\"%#v\\n\", array1.FilterNil().Slice())\n\tfmt.Printf(\"%#v\\n\", array2.FilterEmpty().Slice())\n\n\t// Output:\n\t// []interface {}{0, 1, 2, \"\", []interface {}{}, \"john\"}\n\t// []interface {}{1, 2, \"john\"}\n}\n\nfunc ExampleArray_FilterNil() {\n\tarray1 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tarray2 := garray.NewFrom(g.Slice{0, 1, 2, nil, \"\", g.Slice{}, \"john\"})\n\tfmt.Printf(\"%#v\\n\", array1.FilterNil().Slice())\n\tfmt.Printf(\"%#v\\n\", array2.FilterEmpty().Slice())\n\n\t// Output:\n\t// []interface {}{0, 1, 2, \"\", []interface {}{}, \"john\"}\n\t// []interface {}{1, 2, \"john\"}\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_normal_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleIntArray_Walk() {\n\tvar array garray.IntArray\n\ttables := g.SliceInt{10, 20}\n\tprefix := 99\n\tarray.Append(tables...)\n\t// Add prefix for given table names.\n\tarray.Walk(func(value int) int {\n\t\treturn prefix + value\n\t})\n\tfmt.Println(array.Slice())\n\n\t// Output:\n\t// [109 119]\n}\n\nfunc ExampleNewIntArray() {\n\ts := garray.NewIntArray()\n\ts.Append(10)\n\ts.Append(20)\n\ts.Append(15)\n\ts.Append(30)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 15 30]\n}\n\nfunc ExampleNewIntArraySize() {\n\ts := garray.NewIntArraySize(3, 5)\n\ts.Set(0, 10)\n\ts.Set(1, 20)\n\ts.Set(2, 15)\n\ts.Set(3, 30)\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [10 20 15] 3 5\n}\n\nfunc ExampleNewIntArrayRange() {\n\ts := garray.NewIntArrayRange(1, 5, 1)\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [1 2 3 4 5] 5 8\n}\n\nfunc ExampleNewIntArrayFrom() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [10 20 15 30] 4 4\n}\n\nfunc ExampleNewIntArrayFromCopy() {\n\ts := garray.NewIntArrayFromCopy(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [10 20 15 30] 4 4\n}\n\nfunc ExampleIntArray_At() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})\n\tsAt := s.At(2)\n\tfmt.Println(sAt)\n\n\t// Output:\n\t// 15\n}\n\nfunc ExampleIntArray_Get() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})\n\tsGet, sBool := s.Get(3)\n\tfmt.Println(sGet, sBool)\n\tsGet, sBool = s.Get(99)\n\tfmt.Println(sGet, sBool)\n\n\t// Output:\n\t// 30 true\n\t// 0 false\n}\n\nfunc ExampleIntArray_Set() {\n\ts := garray.NewIntArraySize(3, 5)\n\ts.Set(0, 10)\n\ts.Set(1, 20)\n\ts.Set(2, 15)\n\ts.Set(3, 30)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 15]\n}\n\nfunc ExampleIntArray_SetArray() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 15 30]\n}\n\nfunc ExampleIntArray_Replace() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s.Slice())\n\ts.Replace(g.SliceInt{12, 13})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 15 30]\n\t// [12 13 15 30]\n}\n\nfunc ExampleIntArray_Sum() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\ta := s.Sum()\n\tfmt.Println(a)\n\n\t// Output:\n\t// 75\n}\n\nfunc ExampleIntArray_Sort() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\ta := s.Sort()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [10,15,20,30]\n}\n\nfunc ExampleIntArray_SortFunc() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.SortFunc(func(v1, v2 int) bool {\n\t\t// fmt.Println(v1,v2)\n\t\treturn v1 > v2\n\t})\n\tfmt.Println(s)\n\ts.SortFunc(func(v1, v2 int) bool {\n\t\treturn v1 < v2\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [30,20,15,10]\n\t// [10,15,20,30]\n}\n\nfunc ExampleIntArray_InsertBefore() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\ts.InsertBefore(1, 99)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 99 20 15 30]\n}\n\nfunc ExampleIntArray_InsertAfter() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\ts.InsertAfter(1, 99)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 99 15 30]\n}\n\nfunc ExampleIntArray_Remove() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.Remove(1)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 15 30]\n}\n\nfunc ExampleIntArray_RemoveValue() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.RemoveValue(20)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 15 30]\n}\n\nfunc ExampleIntArray_PushLeft() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.PushLeft(96, 97, 98, 99)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [96 97 98 99 10 20 15 30]\n}\n\nfunc ExampleIntArray_PushRight() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.PushRight(96, 97, 98, 99)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 20 15 30 96 97 98 99]\n}\n\nfunc ExampleIntArray_PopLeft() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.PopLeft()\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [20 15 30]\n}\n\nfunc ExampleIntArray_PopRight() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\tfmt.Println(s)\n\ts.PopRight()\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 20 15]\n}\n\nfunc ExampleIntArray_PopRand() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60, 70})\n\tfmt.Println(s)\n\tr, _ := s.PopRand()\n\tfmt.Println(s)\n\tfmt.Println(r)\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60,70]\n\t// [10,20,15,30,40,60,70]\n\t// 50\n}\n\nfunc ExampleIntArray_PopRands() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.PopRands(2)\n\tfmt.Println(s)\n\tfmt.Println(r)\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40]\n\t// [50 60]\n}\n\nfunc ExampleIntArray_PopLefts() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.PopLefts(2)\n\tfmt.Println(s)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [15,30,40,50,60]\n\t// [10 20]\n}\n\nfunc ExampleIntArray_PopRights() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.PopRights(2)\n\tfmt.Println(s)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40]\n\t// [50 60]\n}\n\nfunc ExampleIntArray_Range() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.Range(2, 5)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [15 30 40]\n}\n\nfunc ExampleIntArray_SubSlice() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.SubSlice(3, 4)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [30 40 50 60]\n}\n\nfunc ExampleIntArray_Append() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\ts.Append(96, 97, 98)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60,96,97,98]\n}\n\nfunc ExampleIntArray_Len() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Len())\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// 7\n}\n\nfunc ExampleIntArray_Slice() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [10 20 15 30 40 50 60]\n}\n\nfunc ExampleIntArray_Interfaces() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tr := s.Interfaces()\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10 20 15 30 40 50 60]\n}\n\nfunc ExampleIntArray_Clone() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.Clone()\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60]\n}\n\nfunc ExampleIntArray_Clear() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Clear())\n\tfmt.Println(s)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// []\n\t// []\n}\n\nfunc ExampleIntArray_Contains() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s.Contains(20))\n\tfmt.Println(s.Contains(21))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIntArray_Search() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s.Search(20))\n\tfmt.Println(s.Search(21))\n\n\t// Output:\n\t// 1\n\t// -1\n}\n\nfunc ExampleIntArray_Unique() {\n\ts := garray.NewIntArray()\n\ts.SetArray(g.SliceInt{10, 20, 15, 15, 20, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Unique())\n\n\t// Output:\n\t// [10,20,15,15,20,50,60]\n\t// [10,20,15,50,60]\n}\n\nfunc ExampleIntArray_LockFunc() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.LockFunc(func(array []int) {\n\t\tfor i := 0; i < len(array)-1; i++ {\n\t\t\tfmt.Println(array[i])\n\t\t}\n\t})\n\n\t// Output:\n\t// 10\n\t// 20\n\t// 15\n\t// 30\n\t// 40\n\t// 50\n}\n\nfunc ExampleIntArray_RLockFunc() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.RLockFunc(func(array []int) {\n\t\tfor i := 0; i < len(array); i++ {\n\t\t\tfmt.Println(array[i])\n\t\t}\n\t})\n\n\t// Output:\n\t// 10\n\t// 20\n\t// 15\n\t// 30\n\t// 40\n\t// 50\n\t// 60\n}\n\nfunc ExampleIntArray_Merge() {\n\ts1 := garray.NewIntArray()\n\ts2 := garray.NewIntArray()\n\ts1.SetArray(g.SliceInt{10, 20, 15})\n\ts2.SetArray(g.SliceInt{40, 50, 60})\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\ts1.Merge(s2)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// [10,20,15]\n\t// [40,50,60]\n\t// [10,20,15,40,50,60]\n}\n\nfunc ExampleIntArray_Fill() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\ts.Fill(2, 3, 99)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,99,99,99,50,60]\n}\n\nfunc ExampleIntArray_Chunk() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tr := s.Chunk(3)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [[10 20 15] [30 40 50] [60]]\n}\n\nfunc ExampleIntArray_Pad() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.Pad(8, 99)\n\tfmt.Println(s)\n\ts.Pad(-10, 89)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [10,20,15,30,40,50,60,99]\n\t// [89,89,10,20,15,30,40,50,60,99]\n}\n\nfunc ExampleIntArray_Rand() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Rand())\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// 10 true\n}\n\nfunc ExampleIntArray_Rands() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Rands(3))\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [20 50 20]\n}\n\nfunc ExampleIntArray_Shuffle() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Shuffle())\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,40,15,50,20,60,30]\n}\n\nfunc ExampleIntArray_Reverse() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Reverse())\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [60,50,40,30,15,20,10]\n}\n\nfunc ExampleIntArray_Join() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.Join(\",\"))\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// 10,20,15,30,40,50,60\n}\n\nfunc ExampleIntArray_CountValues() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 15, 40, 40, 40})\n\tfmt.Println(s.CountValues())\n\n\t// Output:\n\t// map[10:1 15:2 20:1 40:3]\n}\n\nfunc ExampleIntArray_Iterator() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.Iterator(func(k int, v int) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 10\n\t// 1 20\n\t// 2 15\n\t// 3 30\n\t// 4 40\n\t// 5 50\n\t// 6 60\n}\n\nfunc ExampleIntArray_IteratorAsc() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.IteratorAsc(func(k int, v int) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 10\n\t// 1 20\n\t// 2 15\n\t// 3 30\n\t// 4 40\n\t// 5 50\n\t// 6 60\n}\n\nfunc ExampleIntArray_IteratorDesc() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\ts.IteratorDesc(func(k int, v int) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 6 60\n\t// 5 50\n\t// 4 40\n\t// 3 30\n\t// 2 15\n\t// 1 20\n\t// 0 10\n}\n\nfunc ExampleIntArray_String() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.String())\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60]\n}\n\nfunc ExampleIntArray_MarshalJSON() {\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores garray.IntArray\n\t}\n\tvar array garray.IntArray\n\tarray.SetArray(g.SliceInt{98, 97, 96})\n\ts := Student{\n\t\tId:     1,\n\t\tName:   \"john\",\n\t\tScores: array,\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// Output:\n\t// {\"Id\":1,\"Name\":\"john\",\"Scores\":[98,97,96]}\n}\n\nfunc ExampleIntArray_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":[98,96,97]}`)\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *garray.IntArray\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// Output:\n\t// {1 john [98,96,97]}\n}\n\nfunc ExampleIntArray_UnmarshalValue() {\n\ttype Student struct {\n\t\tName   string\n\t\tScores *garray.IntArray\n\t}\n\n\tvar s *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":   \"john\",\n\t\t\"scores\": g.SliceInt{96, 98, 97},\n\t}, &s)\n\tfmt.Println(s)\n\n\t// Output:\n\t// &{john [96,98,97]}\n}\n\nfunc ExampleIntArray_Filter() {\n\tarray1 := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})\n\tarray2 := garray.NewIntArrayFrom(g.SliceInt{10, 4, 51, 5, 45, 50, 56})\n\tfmt.Println(array1.Filter(func(index int, value int) bool {\n\t\treturn empty.IsEmpty(value)\n\t}))\n\tfmt.Println(array2.Filter(func(index int, value int) bool {\n\t\treturn value%2 == 0\n\t}))\n\tfmt.Println(array2.Filter(func(index int, value int) bool {\n\t\treturn value%2 == 1\n\t}))\n\n\t// Output:\n\t// [10,40,50,60]\n\t// [51,5,45]\n\t// []\n}\n\nfunc ExampleIntArray_FilterEmpty() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})\n\tfmt.Println(s)\n\tfmt.Println(s.FilterEmpty())\n\n\t// Output:\n\t// [10,40,50,0,0,0,60]\n\t// [10,40,50,60]\n}\n\nfunc ExampleIntArray_IsEmpty() {\n\ts := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\tfmt.Println(s.IsEmpty())\n\ts1 := garray.NewIntArray()\n\tfmt.Println(s1.IsEmpty())\n\n\t// Output:\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_normal_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleStrArray_Walk() {\n\tvar array garray.StrArray\n\ttables := g.SliceStr{\"user\", \"user_detail\"}\n\tprefix := \"gf_\"\n\tarray.Append(tables...)\n\t// Add prefix for given table names.\n\tarray.Walk(func(value string) string {\n\t\treturn prefix + value\n\t})\n\tfmt.Println(array.Slice())\n\n\t// Output:\n\t// [gf_user gf_user_detail]\n}\n\nfunc ExampleNewStrArray() {\n\ts := garray.NewStrArray()\n\ts.Append(\"We\")\n\ts.Append(\"are\")\n\ts.Append(\"GF\")\n\ts.Append(\"fans\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [We are GF fans]\n}\n\nfunc ExampleNewStrArraySize() {\n\ts := garray.NewStrArraySize(3, 5)\n\ts.Set(0, \"We\")\n\ts.Set(1, \"are\")\n\ts.Set(2, \"GF\")\n\ts.Set(3, \"fans\")\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [We are GF] 3 5\n}\n\nfunc ExampleNewStrArrayFrom() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [We are GF fans !] 5 5\n}\n\nfunc ExampleStrArray_At() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\tsAt := s.At(2)\n\tfmt.Println(sAt)\n\n\t// Output:\n\t// GF\n}\n\nfunc ExampleStrArray_Get() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\tsGet, sBool := s.Get(3)\n\tfmt.Println(sGet, sBool)\n\n\t// Output:\n\t// fans true\n}\n\nfunc ExampleStrArray_Set() {\n\ts := garray.NewStrArraySize(3, 5)\n\ts.Set(0, \"We\")\n\ts.Set(1, \"are\")\n\ts.Set(2, \"GF\")\n\ts.Set(3, \"fans\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [We are GF]\n}\n\nfunc ExampleStrArray_SetArray() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [We are GF fans !]\n}\n\nfunc ExampleStrArray_Replace() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\tfmt.Println(s.Slice())\n\ts.Replace(g.SliceStr{\"Happy\", \"coding\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [We are GF fans !]\n\t// [Happy coding GF fans !]\n}\n\nfunc ExampleStrArray_Sum() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"3\", \"5\", \"10\"})\n\ta := s.Sum()\n\tfmt.Println(a)\n\n\t// Output:\n\t// 18\n}\n\nfunc ExampleStrArray_Sort() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"a\", \"c\"})\n\ta := s.Sort()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleStrArray_SortFunc() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\tfmt.Println(s)\n\ts.SortFunc(func(v1, v2 string) bool {\n\t\treturn gstr.Compare(v1, v2) > 0\n\t})\n\tfmt.Println(s)\n\ts.SortFunc(func(v1, v2 string) bool {\n\t\treturn gstr.Compare(v1, v2) < 0\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"b\",\"c\",\"a\"]\n\t// [\"c\",\"b\",\"a\"]\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleStrArray_InsertBefore() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.InsertBefore(1, \"here\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a here b c d]\n}\n\nfunc ExampleStrArray_InsertAfter() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.InsertAfter(1, \"here\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b here c d]\n}\n\nfunc ExampleStrArray_Remove() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.Remove(1)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a c d]\n}\n\nfunc ExampleStrArray_RemoveValue() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.RemoveValue(\"b\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a c d]\n}\n\nfunc ExampleStrArray_PushLeft() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.PushLeft(\"We\", \"are\", \"GF\", \"fans\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [We are GF fans a b c d]\n}\n\nfunc ExampleStrArray_PushRight() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.PushRight(\"We\", \"are\", \"GF\", \"fans\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d We are GF fans]\n}\n\nfunc ExampleStrArray_PopLeft() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.PopLeft()\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [b c d]\n}\n\nfunc ExampleStrArray_PopRight() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\ts.PopRight()\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c]\n}\n\nfunc ExampleStrArray_PopRand() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr, _ := s.PopRand()\n\tfmt.Println(r)\n\n\t// May Output:\n\t// e\n}\n\nfunc ExampleStrArray_PopRands() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.PopRands(2)\n\tfmt.Println(r)\n\n\t// May Output:\n\t// [e c]\n}\n\nfunc ExampleStrArray_PopLefts() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.PopLefts(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [a b]\n\t// [\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleStrArray_PopRights() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.PopRights(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [g h]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleStrArray_Range() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.Range(2, 5)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [c d e]\n}\n\nfunc ExampleStrArray_SubSlice() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.SubSlice(3, 4)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [d e f g]\n}\n\nfunc ExampleStrArray_Append() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\"})\n\ts.Append(\"a\", \"b\", \"c\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"We\",\"are\",\"GF\",\"fans\",\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleStrArray_Len() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Len())\n\n\t// Output:\n\t// 8\n}\n\nfunc ExampleStrArray_Slice() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleStrArray_Interfaces() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.Interfaces()\n\tfmt.Println(r)\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleStrArray_Clone() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.Clone()\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleStrArray_Clear() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Clear())\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// []\n\t// []\n}\n\nfunc ExampleStrArray_Contains() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Contains(\"e\"))\n\tfmt.Println(s.Contains(\"z\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrArray_ContainsI() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.ContainsI(\"E\"))\n\tfmt.Println(s.ContainsI(\"z\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrArray_Search() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Search(\"e\"))\n\tfmt.Println(s.Search(\"z\"))\n\n\t// Output:\n\t// 4\n\t// -1\n}\n\nfunc ExampleStrArray_Unique() {\n\ts := garray.NewStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\tfmt.Println(s.Unique())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleStrArray_LockFunc() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts.LockFunc(func(array []string) {\n\t\tarray[len(array)-1] = \"GF fans\"\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"GF fans\"]\n}\n\nfunc ExampleStrArray_RLockFunc() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\"})\n\ts.RLockFunc(func(array []string) {\n\t\tfor i := 0; i < len(array); i++ {\n\t\t\tfmt.Println(array[i])\n\t\t}\n\t})\n\n\t// Output:\n\t// a\n\t// b\n\t// c\n\t// d\n\t// e\n}\n\nfunc ExampleStrArray_Merge() {\n\ts1 := garray.NewStrArray()\n\ts2 := garray.NewStrArray()\n\ts1.SetArray(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts2.SetArray(g.SliceStr{\"d\", \"e\", \"f\"})\n\ts1.Merge(s2)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleStrArray_Fill() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\ts.Fill(2, 3, \"here\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"here\",\"here\",\"here\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleStrArray_Chunk() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tr := s.Chunk(3)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [[a b c] [d e f] [g h]]\n}\n\nfunc ExampleStrArray_Pad() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts.Pad(7, \"here\")\n\tfmt.Println(s)\n\ts.Pad(-10, \"there\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"here\",\"here\",\"here\",\"here\"]\n\t// [\"there\",\"there\",\"there\",\"a\",\"b\",\"c\",\"here\",\"here\",\"here\",\"here\"]\n}\n\nfunc ExampleStrArray_Rand() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Rand())\n\n\t// May Output:\n\t// c true\n}\n\nfunc ExampleStrArray_Rands() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Rands(3))\n\n\t// May Output:\n\t// [e h e]\n}\n\nfunc ExampleStrArray_Shuffle() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Shuffle())\n\n\t// May Output:\n\t// [\"a\",\"c\",\"e\",\"d\",\"b\",\"g\",\"f\",\"h\"]\n}\n\nfunc ExampleStrArray_Reverse() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\tfmt.Println(s.Reverse())\n\n\t// Output:\n\t// [\"h\",\"g\",\"f\",\"e\",\"d\",\"c\",\"b\",\"a\"]\n}\n\nfunc ExampleStrArray_Join() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\tfmt.Println(s.Join(\",\"))\n\n\t// Output:\n\t// a,b,c\n}\n\nfunc ExampleStrArray_CountValues() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\tfmt.Println(s.CountValues())\n\n\t// Output:\n\t// map[a:1 b:1 c:3 d:2]\n}\n\nfunc ExampleStrArray_Iterator() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts.Iterator(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleStrArray_IteratorAsc() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts.IteratorAsc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleStrArray_IteratorDesc() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\ts.IteratorDesc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 2 c\n\t// 1 b\n\t// 0 a\n}\n\nfunc ExampleStrArray_String() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\"})\n\tfmt.Println(s.String())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleStrArray_MarshalJSON() {\n\ttype Student struct {\n\t\tId      int\n\t\tName    string\n\t\tLessons []string\n\t}\n\ts := Student{\n\t\tId:      1,\n\t\tName:    \"john\",\n\t\tLessons: []string{\"Math\", \"English\", \"Music\"},\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// Output:\n\t// {\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Music\"]}\n}\n\nfunc ExampleStrArray_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Sport\"]}`)\n\ttype Student struct {\n\t\tId      int\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// Output:\n\t// {1 john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleStrArray_UnmarshalValue() {\n\ttype Student struct {\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\tvar s *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": []byte(`[\"Math\",\"English\",\"Sport\"]`),\n\t}, &s)\n\tfmt.Println(s)\n\n\tvar s1 *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": g.SliceStr{\"Math\", \"English\", \"Sport\"},\n\t}, &s1)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleStrArray_Filter() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"Math\", \"English\", \"Sport\"})\n\ts1 := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s1.Filter(func(index int, value string) bool {\n\t\treturn empty.IsEmpty(value)\n\t}))\n\n\tfmt.Println(s.Filter(func(index int, value string) bool {\n\t\treturn strings.Contains(value, \"h\")\n\t}))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"Sport\"]\n}\n\nfunc ExampleStrArray_FilterEmpty() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s.FilterEmpty())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleStrArray_IsEmpty() {\n\ts := garray.NewStrArrayFrom(g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s.IsEmpty())\n\ts1 := garray.NewStrArray()\n\tfmt.Println(s1.IsEmpty())\n\n\t// Output:\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_normal_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleTArray_Walk() {\n\t{\n\t\tvar intArray garray.TArray[int]\n\t\tintTables := g.SliceInt{10, 20}\n\t\tintPrefix := 99\n\t\tintArray.Append(intTables...)\n\t\t// Add prefix for given table names.\n\t\tintArray.Walk(func(value int) int {\n\t\t\treturn intPrefix + value\n\t\t})\n\t\tfmt.Println(intArray.Slice())\n\t}\n\n\t{\n\t\tvar strArray garray.TArray[string]\n\t\tstrTables := g.SliceStr{\"user\", \"user_detail\"}\n\t\tstrPrefix := \"gf_\"\n\t\tstrArray.Append(strTables...)\n\t\t// Add prefix for given table names.\n\t\tstrArray.Walk(func(value string) string {\n\t\t\treturn strPrefix + value\n\t\t})\n\t\tfmt.Println(strArray.Slice())\n\t}\n\n\t// Output:\n\t// [109 119]\n\t// [gf_user gf_user_detail]\n}\n\nfunc ExampleNewTArray() {\n\t{\n\t\tintArr := garray.NewTArray[int]()\n\t\tintArr.Append(10)\n\t\tintArr.Append(20)\n\t\tintArr.Append(15)\n\t\tintArr.Append(30)\n\t\tfmt.Println(intArr.Slice())\n\t}\n\n\t{\n\t\tstrArr := garray.NewTArray[string]()\n\t\tstrArr.Append(\"We\")\n\t\tstrArr.Append(\"are\")\n\t\tstrArr.Append(\"GF\")\n\t\tstrArr.Append(\"fans\")\n\t\tfmt.Println(strArr.Slice())\n\t}\n\n\t// Output:\n\t// [10 20 15 30]\n\t// [We are GF fans]\n}\n\nfunc ExampleNewTArraySize() {\n\t{\n\t\tintArr := garray.NewTArraySize[int](3, 5)\n\t\tintArr.Set(0, 10)\n\t\tintArr.Set(1, 20)\n\t\tintArr.Set(2, 15)\n\t\tintArr.Set(3, 30)\n\t\tfmt.Println(intArr.Slice(), intArr.Len(), cap(intArr.Slice()))\n\t}\n\n\t{\n\t\tstrArr := garray.NewTArraySize[string](3, 5)\n\t\tstrArr.Set(0, \"We\")\n\t\tstrArr.Set(1, \"are\")\n\t\tstrArr.Set(2, \"GF\")\n\t\tstrArr.Set(3, \"fans\")\n\t\tfmt.Println(strArr.Slice(), strArr.Len(), cap(strArr.Slice()))\n\t}\n\n\t// Output:\n\t// [10 20 15] 3 5\n\t// [We are GF] 3 5\n}\n\nfunc ExampleNewTArrayFrom() {\n\t{\n\t\tintArr := garray.NewTArrayFrom[int](g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(intArr.Slice(), intArr.Len(), cap(intArr.Slice()))\n\t}\n\n\t{\n\t\tstrArr := garray.NewTArrayFrom[string](g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\t\tfmt.Println(strArr.Slice(), strArr.Len(), cap(strArr.Slice()))\n\t}\n\n\t// Output:\n\t// [10 20 15 30] 4 4\n\t// [We are GF fans !] 5 5\n}\n\nfunc ExampleNewTArrayFromCopy() {\n\t{\n\t\tintArr := garray.NewTArrayFromCopy(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(intArr.Slice(), intArr.Len(), cap(intArr.Slice()))\n\t}\n\n\t{\n\t\tstrArr := garray.NewTArrayFromCopy(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\"})\n\t\tfmt.Println(strArr.Slice(), strArr.Len(), cap(strArr.Slice()))\n\t}\n\n\t// Output:\n\t// [10 20 15 30] 4 4\n\t// [a b c d e] 5 5\n}\n\nfunc ExampleTArray_At() {\n\t{\n\t\tintArr := garray.NewTArrayFrom[int](g.SliceInt{10, 20, 15, 30})\n\t\tisAt := intArr.At(2)\n\t\tfmt.Println(isAt)\n\t}\n\n\t{\n\t\tstrArr := garray.NewTArrayFrom[string](g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\t\tssAt := strArr.At(2)\n\t\tfmt.Println(ssAt)\n\t}\n\n\t// Output:\n\t// 15\n\t// GF\n}\n\nfunc ExampleTArray_Get() {\n\t{\n\t\ts := garray.NewTArrayFrom[int](g.SliceInt{10, 20, 15, 30})\n\t\tsGet, sBool := s.Get(3)\n\t\tfmt.Println(sGet, sBool)\n\t\tsGet, sBool = s.Get(99)\n\t\tfmt.Println(sGet, sBool)\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\t\tsGet, sBool := s.Get(3)\n\t\tfmt.Println(sGet, sBool)\n\t}\n\n\t// Output:\n\t// 30 true\n\t// 0 false\n\t// fans true\n}\n\nfunc ExampleTArray_Set() {\n\t{\n\t\ts := garray.NewTArraySize[int](3, 5)\n\t\ts.Set(0, 10)\n\t\ts.Set(1, 20)\n\t\ts.Set(2, 15)\n\t\ts.Set(3, 30)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArraySize[string](3, 5)\n\t\ts.Set(0, \"We\")\n\t\ts.Set(1, \"are\")\n\t\ts.Set(2, \"GF\")\n\t\ts.Set(3, \"fans\")\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10 20 15]\n\t// [We are GF]\n}\n\nfunc ExampleTArray_SetArray() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10 20 15 30]\n\t// [We are GF fans !]\n}\n\nfunc ExampleTArray_Replace() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s.Slice())\n\t\ts.Replace(g.SliceInt{12, 13})\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\", \"!\"})\n\t\tfmt.Println(s.Slice())\n\t\ts.Replace(g.SliceStr{\"Happy\", \"coding\"})\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10 20 15 30]\n\t// [12 13 15 30]\n\t// [We are GF fans !]\n\t// [Happy coding GF fans !]\n}\n\nfunc ExampleTArray_Sum() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\ta := s.Sum()\n\t\tfmt.Println(a)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"3\", \"5\", \"10\"})\n\t\ta := s.Sum()\n\t\tfmt.Println(a)\n\t}\n\t// Output:\n\t// 75\n\t// 18\n}\n\nfunc ExampleTArray_SortFunc() {\n\t{\n\t\ts := garray.NewTArrayFrom[int](g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.SortFunc(func(v1, v2 int) bool {\n\t\t\t// fmt.Println(v1,v2)\n\t\t\treturn v1 > v2\n\t\t})\n\t\tfmt.Println(s)\n\t\ts.SortFunc(func(v1, v2 int) bool {\n\t\t\treturn v1 < v2\n\t\t})\n\t\tfmt.Println(s)\n\t}\n\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"b\", \"c\", \"a\"})\n\t\tfmt.Println(s)\n\t\ts.SortFunc(func(v1, v2 string) bool {\n\t\t\treturn gstr.Compare(v1, v2) > 0\n\t\t})\n\t\tfmt.Println(s)\n\t\ts.SortFunc(func(v1, v2 string) bool {\n\t\t\treturn gstr.Compare(v1, v2) < 0\n\t\t})\n\t\tfmt.Println(s)\n\t}\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [30,20,15,10]\n\t// [10,15,20,30]\n\t// [\"b\",\"c\",\"a\"]\n\t// [\"c\",\"b\",\"a\"]\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleTArray_InsertBefore() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\ts.InsertBefore(1, 99)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.InsertBefore(1, \"here\")\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10 99 20 15 30]\n\t// [a here b c d]\n}\n\nfunc ExampleTArray_InsertAfter() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\ts.InsertAfter(1, 99)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.InsertAfter(1, \"here\")\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10 20 99 15 30]\n\t// [a b here c d]\n}\n\nfunc ExampleTArray_Remove() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.Remove(1)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.Remove(1)\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 15 30]\n\t// [a c d]\n}\n\nfunc ExampleTArray_RemoveValue() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.RemoveValue(20)\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.RemoveValue(\"b\")\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 15 30]\n\t// [a c d]\n}\n\nfunc ExampleTArray_PushLeft() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.PushLeft(96, 97, 98, 99)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.PushLeft(\"We\", \"are\", \"GF\", \"fans\")\n\t\tfmt.Println(s.Slice())\n\t}\n\n\t// Output:\n\t// [10,20,15,30]\n\t// [96 97 98 99 10 20 15 30]\n\t// [We are GF fans a b c d]\n}\n\nfunc ExampleTArray_PushRight() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.PushRight(96, 97, 98, 99)\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.PushRight(\"We\", \"are\", \"GF\", \"fans\")\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 20 15 30 96 97 98 99]\n\t// [a b c d We are GF fans]\n}\n\nfunc ExampleTArray_PopLeft() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.PopLeft()\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.PopLeft()\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10,20,15,30]\n\t// [20 15 30]\n\t// [b c d]\n}\n\nfunc ExampleTArray_PopRight() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30})\n\t\tfmt.Println(s)\n\t\ts.PopRight()\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\"})\n\t\ts.PopRight()\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10,20,15,30]\n\t// [10 20 15]\n\t// [a b c]\n}\n\nfunc ExampleTArray_PopRand() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60, 70})\n\t\tfmt.Println(s)\n\t\tr, _ := s.PopRand()\n\t\tfmt.Println(s)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr, _ := s.PopRand()\n\t\tfmt.Println(r)\n\t}\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60,70]\n\t// [10,20,15,30,40,60,70]\n\t// 50\n\t// e\n}\n\nfunc ExampleTArray_PopRands() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.PopRands(2)\n\t\tfmt.Println(s)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.PopRands(2)\n\t\tfmt.Println(r)\n\t}\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40]\n\t// [50 60]\n\t// [e c]\n}\n\nfunc ExampleTArray_PopLefts() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.PopLefts(2)\n\t\tfmt.Println(s)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.PopLefts(2)\n\t\tfmt.Println(r)\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [15,30,40,50,60]\n\t// [10 20]\n\t// [a b]\n\t// [\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleTArray_PopRights() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.PopRights(2)\n\t\tfmt.Println(s)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.PopRights(2)\n\t\tfmt.Println(r)\n\t\tfmt.Println(s)\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40]\n\t// [50 60]\n\t// [g h]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleTArray_Range() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.Range(2, 5)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.Range(2, 5)\n\t\tfmt.Println(r)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [15 30 40]\n\t// [c d e]\n}\n\nfunc ExampleTArray_SubSlice() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.SubSlice(3, 4)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.SubSlice(3, 4)\n\t\tfmt.Println(r)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [30 40 50 60]\n\t// [d e f g]\n}\n\nfunc ExampleTArray_Append() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\ts.Append(96, 97, 98)\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"We\", \"are\", \"GF\", \"fans\"})\n\t\ts.Append(\"a\", \"b\", \"c\")\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60,96,97,98]\n\t// [\"We\",\"are\",\"GF\",\"fans\",\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleTArray_Len() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Len())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Len())\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// 7\n\t// 8\n}\n\nfunc ExampleTArray_Slice() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s.Slice())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Slice())\n\t}\n\t// Output:\n\t// [10 20 15 30 40 50 60]\n\t// [a b c d e f g h]\n}\n\nfunc ExampleTArray_Interfaces() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tr := s.Interfaces()\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.Interfaces()\n\t\tfmt.Println(r)\n\t}\n\t// Output:\n\t// [10 20 15 30 40 50 60]\n\t// [a b c d e f g h]\n}\n\nfunc ExampleTArray_Clone() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.Clone()\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.Clone()\n\t\tfmt.Println(r)\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleTArray_Clear() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Clear())\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Clear())\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// []\n\t// []\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// []\n\t// []\n}\n\nfunc ExampleTArray_Contains() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s.Contains(20))\n\t\tfmt.Println(s.Contains(21))\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Contains(\"e\"))\n\t\tfmt.Println(s.Contains(\"z\"))\n\t}\n\t// Output:\n\t// true\n\t// false\n\t// true\n\t// false\n}\n\nfunc ExampleTArray_Search() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s.Search(20))\n\t\tfmt.Println(s.Search(21))\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Search(\"e\"))\n\t\tfmt.Println(s.Search(\"z\"))\n\t}\n\t// Output:\n\t// 1\n\t// -1\n\t// 4\n\t// -1\n}\n\nfunc ExampleTArray_Unique() {\n\t{\n\t\ts := garray.NewTArray[int]()\n\t\ts.SetArray(g.SliceInt{10, 20, 15, 15, 20, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Unique())\n\t}\n\t{\n\t\ts := garray.NewTArray[string]()\n\t\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\t\tfmt.Println(s.Unique())\n\t}\n\t// Output:\n\t// [10,20,15,15,20,50,60]\n\t// [10,20,15,50,60]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleTArray_LockFunc() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.LockFunc(func(array []int) {\n\t\t\tfor i := 0; i < len(array)-1; i++ {\n\t\t\t\tfmt.Println(array[i])\n\t\t\t}\n\t\t})\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts.LockFunc(func(array []string) {\n\t\t\tarray[len(array)-1] = \"GF fans\"\n\t\t})\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// 10\n\t// 20\n\t// 15\n\t// 30\n\t// 40\n\t// 50\n\t// [\"a\",\"b\",\"GF fans\"]\n}\n\nfunc ExampleTArray_RLockFunc() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.RLockFunc(func(array []int) {\n\t\t\tfor i := 0; i < len(array); i++ {\n\t\t\t\tfmt.Println(array[i])\n\t\t\t}\n\t\t})\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\"})\n\t\ts.RLockFunc(func(array []string) {\n\t\t\tfor i := 0; i < len(array); i++ {\n\t\t\t\tfmt.Println(array[i])\n\t\t\t}\n\t\t})\n\t}\n\t// Output:\n\t// 10\n\t// 20\n\t// 15\n\t// 30\n\t// 40\n\t// 50\n\t// 60\n\t// a\n\t// b\n\t// c\n\t// d\n\t// e\n}\n\nfunc ExampleTArray_Merge() {\n\t{\n\t\ts1 := garray.NewTArray[int]()\n\t\ts2 := garray.NewTArray[int]()\n\t\ts1.SetArray(g.SliceInt{10, 20, 15})\n\t\ts2.SetArray(g.SliceInt{40, 50, 60})\n\t\tfmt.Println(s1)\n\t\tfmt.Println(s2)\n\t\ts1.Merge(s2)\n\t\tfmt.Println(s1)\n\t}\n\t{\n\t\ts1 := garray.NewTArray[string]()\n\t\ts2 := garray.NewTArray[string]()\n\t\ts1.SetArray(g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts2.SetArray(g.SliceStr{\"d\", \"e\", \"f\"})\n\t\ts1.Merge(s2)\n\t\tfmt.Println(s1)\n\t}\n\t// Output:\n\t// [10,20,15]\n\t// [40,50,60]\n\t// [10,20,15,40,50,60]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleTArray_Fill() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\ts.Fill(2, 3, 99)\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\ts.Fill(2, 3, \"here\")\n\t\tfmt.Println(s)\n\t}\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,99,99,99,50,60]\n\t// [\"a\",\"b\",\"here\",\"here\",\"here\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleTArray_Chunk() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tr := s.Chunk(3)\n\t\tfmt.Println(r)\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tr := s.Chunk(3)\n\t\tfmt.Println(r)\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [[10 20 15] [30 40 50] [60]]\n\t// [[a b c] [d e f] [g h]]\n}\n\nfunc ExampleTArray_Pad() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.Pad(8, 99)\n\t\tfmt.Println(s)\n\t\ts.Pad(-10, 89)\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts.Pad(7, \"here\")\n\t\tfmt.Println(s)\n\t\ts.Pad(-10, \"there\")\n\t\tfmt.Println(s)\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60,99]\n\t// [89,89,10,20,15,30,40,50,60,99]\n\t// [\"a\",\"b\",\"c\",\"here\",\"here\",\"here\",\"here\"]\n\t// [\"there\",\"there\",\"there\",\"a\",\"b\",\"c\",\"here\",\"here\",\"here\",\"here\"]\n}\n\nfunc ExampleTArray_Rand() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Rand())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Rand())\n\t}\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// 10 true\n\t// c true\n}\n\nfunc ExampleTArray_Rands() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Rands(3))\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Rands(3))\n\t}\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [20 50 20]\n\t// [e h e]\n}\n\nfunc ExampleTArray_Shuffle() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Shuffle())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Shuffle())\n\t}\n\n\t// May Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,40,15,50,20,60,30]\n\t// [\"a\",\"c\",\"e\",\"d\",\"b\",\"g\",\"f\",\"h\"]\n}\n\nfunc ExampleTArray_Reverse() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Reverse())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"})\n\t\tfmt.Println(s.Reverse())\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [60,50,40,30,15,20,10]\n\t// [\"h\",\"g\",\"f\",\"e\",\"d\",\"c\",\"b\",\"a\"]\n}\n\nfunc ExampleTArray_Join() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.Join(\",\"))\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\tfmt.Println(s.Join(\",\"))\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// 10,20,15,30,40,50,60\n\t// a,b,c\n}\n\nfunc ExampleTArray_CountValues() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 15, 40, 40, 40})\n\t\tfmt.Println(s.CountValues())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\t\tfmt.Println(s.CountValues())\n\t}\n\n\t// Output:\n\t// map[10:1 15:2 20:1 40:3]\n\t// map[a:1 b:1 c:3 d:2]\n}\n\nfunc ExampleTArray_Iterator() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.Iterator(func(k int, v int) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts.Iterator(func(k int, v string) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\n\t// Output:\n\t// 0 10\n\t// 1 20\n\t// 2 15\n\t// 3 30\n\t// 4 40\n\t// 5 50\n\t// 6 60\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleTArray_IteratorAsc() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.IteratorAsc(func(k int, v int) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts.IteratorAsc(func(k int, v string) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\n\t// Output:\n\t// 0 10\n\t// 1 20\n\t// 2 15\n\t// 3 30\n\t// 4 40\n\t// 5 50\n\t// 6 60\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleTArray_IteratorDesc() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\ts.IteratorDesc(func(k int, v int) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\ts.IteratorDesc(func(k int, v string) bool {\n\t\t\tfmt.Println(k, v)\n\t\t\treturn true\n\t\t})\n\t}\n\n\t// Output:\n\t// 6 60\n\t// 5 50\n\t// 4 40\n\t// 3 30\n\t// 2 15\n\t// 1 20\n\t// 0 10\n\t// 2 c\n\t// 1 b\n\t// 0 a\n}\n\nfunc ExampleTArray_String() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.String())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"c\"})\n\t\tfmt.Println(s.String())\n\t}\n\n\t// Output:\n\t// [10,20,15,30,40,50,60]\n\t// [10,20,15,30,40,50,60]\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleTArray_MarshalJSON() {\n\t{\n\t\ttype Student struct {\n\t\t\tId     int\n\t\t\tName   string\n\t\t\tScores garray.TArray[int]\n\t\t}\n\t\tvar array garray.TArray[int]\n\t\tarray.SetArray(g.SliceInt{98, 97, 96})\n\t\ts := Student{\n\t\t\tId:     1,\n\t\t\tName:   \"john\",\n\t\t\tScores: array,\n\t\t}\n\t\tb, _ := json.Marshal(s)\n\t\tfmt.Println(string(b))\n\t}\n\t{\n\t\ttype Student struct {\n\t\t\tId      int\n\t\t\tName    string\n\t\t\tLessons []string\n\t\t}\n\t\ts := Student{\n\t\t\tId:      1,\n\t\t\tName:    \"john\",\n\t\t\tLessons: []string{\"Math\", \"English\", \"Music\"},\n\t\t}\n\t\tb, _ := json.Marshal(s)\n\t\tfmt.Println(string(b))\n\t}\n\n\t// Output:\n\t// {\"Id\":1,\"Name\":\"john\",\"Scores\":[98,97,96]}\n\t// {\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Music\"]}\n}\n\nfunc ExampleTArray_UnmarshalJSON() {\n\t{\n\t\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":[98,96,97]}`)\n\t\ttype Student struct {\n\t\t\tId     int\n\t\t\tName   string\n\t\t\tScores *garray.TArray[int]\n\t\t}\n\t\ts := Student{}\n\t\tjson.Unmarshal(b, &s)\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Sport\"]}`)\n\t\ttype Student struct {\n\t\t\tId      int\n\t\t\tName    string\n\t\t\tLessons *garray.TArray[string]\n\t\t}\n\t\ts := Student{}\n\t\tjson.Unmarshal(b, &s)\n\t\tfmt.Println(s)\n\t}\n\n\t// Output:\n\t// {1 john [98,96,97]}\n\t// {1 john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleTArray_UnmarshalValue() {\n\t{\n\t\ttype Student struct {\n\t\t\tName   string\n\t\t\tScores *garray.TArray[int]\n\t\t}\n\n\t\tvar s *Student\n\t\tgconv.Struct(g.Map{\n\t\t\t\"name\":   \"john\",\n\t\t\t\"scores\": g.SliceInt{96, 98, 97},\n\t\t}, &s)\n\t\tfmt.Println(s)\n\t}\n\t{\n\t\ttype Student struct {\n\t\t\tName    string\n\t\t\tLessons *garray.TArray[string]\n\t\t}\n\t\tvar s *Student\n\t\tgconv.Struct(g.Map{\n\t\t\t\"name\":    \"john\",\n\t\t\t\"lessons\": []byte(`[\"Math\",\"English\",\"Sport\"]`),\n\t\t}, &s)\n\t\tfmt.Println(s)\n\n\t\tvar s1 *Student\n\t\tgconv.Struct(g.Map{\n\t\t\t\"name\":    \"john\",\n\t\t\t\"lessons\": g.SliceStr{\"Math\", \"English\", \"Sport\"},\n\t\t}, &s1)\n\t\tfmt.Println(s1)\n\t}\n\n\t// Output:\n\t// &{john [96,98,97]}\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleTArray_Filter() {\n\t{\n\t\tarray1 := garray.NewTArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})\n\t\tarray2 := garray.NewTArrayFrom(g.SliceInt{10, 4, 51, 5, 45, 50, 56})\n\t\tfmt.Println(array1.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}))\n\t\tfmt.Println(array2.Filter(func(index int, value int) bool {\n\t\t\treturn value%2 == 0\n\t\t}))\n\t\tfmt.Println(array2.Filter(func(index int, value int) bool {\n\t\t\treturn value%2 == 1\n\t\t}))\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"Math\", \"English\", \"Sport\"})\n\t\ts1 := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\t\tfmt.Println(s1.Filter(func(index int, value string) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}))\n\n\t\tfmt.Println(s.Filter(func(index int, value string) bool {\n\t\t\treturn strings.Contains(value, \"h\")\n\t\t}))\n\t}\n\n\t// Output:\n\t// [10,40,50,60]\n\t// [51,5,45]\n\t// []\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"Sport\"]\n}\n\nfunc ExampleTArray_FilterEmpty() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})\n\t\tfmt.Println(s)\n\t\tfmt.Println(s.FilterEmpty())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\t\tfmt.Println(s.FilterEmpty())\n\t}\n\n\t// Output:\n\t// [10,40,50,0,0,0,60]\n\t// [10,40,50,60]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleTArray_IsEmpty() {\n\t{\n\t\ts := garray.NewTArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})\n\t\tfmt.Println(s.IsEmpty())\n\t\ts1 := garray.NewTArray[int]()\n\t\tfmt.Println(s1.IsEmpty())\n\t}\n\t{\n\t\ts := garray.NewTArrayFrom[string](g.SliceStr{\"a\", \"b\", \"\", \"c\", \"\", \"\", \"d\"})\n\t\tfmt.Println(s.IsEmpty())\n\t\ts1 := garray.NewTArray[string]()\n\t\tfmt.Println(s1.IsEmpty())\n\t}\n\n\t// Output:\n\t// false\n\t// true\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_sorted_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleSortedStrArray_Walk() {\n\tvar array garray.SortedStrArray\n\ttables := g.SliceStr{\"user\", \"user_detail\"}\n\tprefix := \"gf_\"\n\tarray.Append(tables...)\n\t// Add prefix for given table names.\n\tarray.Walk(func(value string) string {\n\t\treturn prefix + value\n\t})\n\tfmt.Println(array.Slice())\n\n\t// Output:\n\t// [gf_user gf_user_detail]\n}\n\nfunc ExampleNewSortedStrArray() {\n\ts := garray.NewSortedStrArray()\n\ts.Append(\"b\")\n\ts.Append(\"d\")\n\ts.Append(\"c\")\n\ts.Append(\"a\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleNewSortedStrArraySize() {\n\ts := garray.NewSortedStrArraySize(3)\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [a b c d] 4 4\n}\n\nfunc ExampleNewStrArrayFromCopy() {\n\ts := garray.NewSortedStrArrayFromCopy(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleSortedStrArray_At() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tsAt := s.At(2)\n\tfmt.Println(s)\n\tfmt.Println(sAt)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// c\n\n}\n\nfunc ExampleSortedStrArray_Get() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"d\", \"c\", \"a\", \"e\"})\n\tsGet, sBool := s.Get(3)\n\tfmt.Println(s)\n\tfmt.Println(sGet, sBool)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\"]\n\t// d true\n}\n\nfunc ExampleSortedStrArray_SetArray() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleSortedStrArray_SetUnique() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\", \"c\", \"a\"})\n\tfmt.Println(s.SetUnique(true))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_Sum() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray([]string{\"5\", \"3\", \"2\"})\n\tfmt.Println(s)\n\ta := s.Sum()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [\"2\",\"3\",\"5\"]\n\t// 10\n}\n\nfunc ExampleSortedStrArray_Sort() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s)\n\ta := s.Sort()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_Remove() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\ts.Remove(1)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// [a c d]\n}\n\nfunc ExampleSortedStrArray_RemoveValue() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\ts.RemoveValue(\"b\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// [a c d]\n}\n\nfunc ExampleSortedStrArray_PopLeft() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tr, _ := s.PopLeft()\n\tfmt.Println(r)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// a\n\t// [b c d]\n}\n\nfunc ExampleSortedStrArray_PopRight() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\tr, _ := s.PopRight()\n\tfmt.Println(r)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// d\n\t// [a b c]\n}\n\nfunc ExampleSortedStrArray_PopRights() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopRights(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [g h]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleSortedStrArray_Rand() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr, _ := s.PopRand()\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// b\n\t// [\"a\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedStrArray_PopRands() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopRands(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// [d a]\n\t// [\"b\",\"c\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedStrArray_PopLefts() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopLefts(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [a b]\n\t// [\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedStrArray_Range() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Range(2, 5)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [c d e]\n}\n\nfunc ExampleSortedStrArray_SubSlice() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.SubSlice(3, 4)\n\tfmt.Println(s.Slice())\n\tfmt.Println(r)\n\n\t// Output:\n\t// [a b c d e f g h]\n\t// [d e f g]\n}\n\nfunc ExampleSortedStrArray_Add() {\n\ts := garray.NewSortedStrArray()\n\ts.Add(\"b\", \"d\", \"c\", \"a\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_Append() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s)\n\ts.Append(\"f\", \"e\", \"g\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\"]\n}\n\nfunc ExampleSortedStrArray_Len() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Len())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// 8\n}\n\nfunc ExampleSortedStrArray_Slice() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleSortedStrArray_Interfaces() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Interfaces()\n\tfmt.Println(r)\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleSortedStrArray_Clone() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Clone()\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedStrArray_Clear() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Clear())\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// []\n\t// []\n}\n\nfunc ExampleSortedStrArray_Contains() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s.Contains(\"e\"))\n\tfmt.Println(s.Contains(\"E\"))\n\tfmt.Println(s.Contains(\"z\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// false\n}\n\nfunc ExampleSortedStrArray_ContainsI() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.ContainsI(\"E\"))\n\tfmt.Println(s.ContainsI(\"z\"))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// true\n\t// false\n}\n\nfunc ExampleSortedStrArray_Search() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Search(\"e\"))\n\tfmt.Println(s.Search(\"E\"))\n\tfmt.Println(s.Search(\"z\"))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// 4\n\t// -1\n\t// -1\n}\n\nfunc ExampleSortedStrArray_Unique() {\n\ts := garray.NewSortedStrArray()\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Unique())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"c\",\"c\",\"d\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_LockFunc() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts.LockFunc(func(array []string) {\n\t\tarray[len(array)-1] = \"GF fans\"\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"GF fans\",\"a\",\"b\"]\n}\n\nfunc ExampleSortedStrArray_RLockFunc() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts.RLockFunc(func(array []string) {\n\t\tarray[len(array)-1] = \"GF fans\"\n\t\tfmt.Println(array[len(array)-1])\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// GF fans\n\t// [\"a\",\"b\",\"GF fans\"]\n}\n\nfunc ExampleSortedStrArray_Merge() {\n\ts1 := garray.NewSortedStrArray()\n\ts2 := garray.NewSortedStrArray()\n\ts1.SetArray(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts2.SetArray(g.SliceStr{\"e\", \"d\", \"f\"})\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\ts1.Merge(s2)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\"]\n\t// [\"d\",\"e\",\"f\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleSortedStrArray_Chunk() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Chunk(3)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [[a b c] [d e f] [g h]]\n}\n\nfunc ExampleSortedStrArray_Rands() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Rands(3))\n\n\t// May Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [h g c]\n}\n\nfunc ExampleSortedStrArray_Join() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s.Join(\",\"))\n\n\t// Output:\n\t// a,b,c,d,e,f,g,h\n}\n\nfunc ExampleSortedStrArray_CountValues() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\tfmt.Println(s.CountValues())\n\n\t// Output:\n\t// map[a:1 b:1 c:3 d:2]\n}\n\nfunc ExampleSortedStrArray_Iterator() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts.Iterator(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleSortedStrArray_IteratorAsc() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts.IteratorAsc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleSortedStrArray_IteratorDesc() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts.IteratorDesc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 2 c\n\t// 1 b\n\t// 0 a\n}\n\nfunc ExampleSortedStrArray_String() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\tfmt.Println(s.String())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleSortedStrArray_MarshalJSON() {\n\ttype Student struct {\n\t\tID     int\n\t\tName   string\n\t\tLevels garray.SortedStrArray\n\t}\n\tr := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts := Student{\n\t\tID:     1,\n\t\tName:   \"john\",\n\t\tLevels: *r,\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// Output:\n\t// {\"ID\":1,\"Name\":\"john\",\"Levels\":[\"a\",\"b\",\"c\"]}\n}\n\nfunc ExampleSortedStrArray_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Sport\"]}`)\n\ttype Student struct {\n\t\tId      int\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// Output:\n\t// {1 john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleSortedStrArray_UnmarshalValue() {\n\ttype Student struct {\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\tvar s *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": []byte(`[\"Math\",\"English\",\"Sport\"]`),\n\t}, &s)\n\tfmt.Println(s)\n\n\tvar s1 *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": g.SliceStr{\"Math\", \"English\", \"Sport\"},\n\t}, &s1)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleSortedStrArray_Filter() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Filter(func(index int, value string) bool {\n\t\treturn empty.IsEmpty(value)\n\t}))\n\n\t// Output:\n\t// [\"\",\"\",\"\",\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_FilterEmpty() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s)\n\tfmt.Println(s.FilterEmpty())\n\n\t// Output:\n\t// [\"\",\"\",\"\",\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedStrArray_IsEmpty() {\n\ts := garray.NewSortedStrArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"})\n\tfmt.Println(s.IsEmpty())\n\ts1 := garray.NewSortedStrArray()\n\tfmt.Println(s1.IsEmpty())\n\n\t// Output:\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/garray/garray_z_example_sorted_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage garray_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleSortedTArray_Walk() {\n\tvar array garray.SortedTArray[string]\n\tarray.SetComparator(gutil.ComparatorT)\n\ttables := g.SliceStr{\"user\", \"user_detail\"}\n\tprefix := \"gf_\"\n\tarray.Append(tables...)\n\t// Add prefix for given table names.\n\tarray.Walk(func(value string) string {\n\t\treturn prefix + value\n\t})\n\tfmt.Println(array.Slice())\n\n\t// Output:\n\t// [gf_user gf_user_detail]\n}\n\nfunc ExampleNewSortedTArray() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.Append(\"b\")\n\ts.Append(\"d\")\n\ts.Append(\"c\")\n\ts.Append(\"a\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleNewSortedTArraySize() {\n\ts := garray.NewSortedTArraySize[string](3, gutil.ComparatorT)\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s.Slice(), s.Len(), cap(s.Slice()))\n\n\t// Output:\n\t// [a b c d] 4 4\n}\n\nfunc ExampleNewSortedTArrayFromCopy() {\n\ts := garray.NewSortedTArrayFromCopy(g.SliceStr{\"b\", \"d\", \"c\", \"a\"}, gutil.ComparatorT)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleSortedTArray_At() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"d\", \"c\", \"a\"}, gutil.ComparatorT)\n\tsAt := s.At(2)\n\tfmt.Println(s)\n\tfmt.Println(sAt)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// c\n\n}\n\nfunc ExampleSortedTArray_Get() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"d\", \"c\", \"a\", \"e\"}, gutil.ComparatorT)\n\tsGet, sBool := s.Get(3)\n\tfmt.Println(s)\n\tfmt.Println(sGet, sBool)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\"]\n\t// d true\n}\n\nfunc ExampleSortedTArray_SetArray() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n}\n\nfunc ExampleSortedTArray_SetUnique() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray([]string{\"b\", \"d\", \"a\", \"c\", \"c\", \"a\"})\n\tfmt.Println(s.SetUnique(true))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_Sum() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray([]string{\"5\", \"3\", \"2\"})\n\tfmt.Println(s)\n\ta := s.Sum()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [2,3,5]\n\t// 10\n}\n\nfunc ExampleSortedTArray_Sort() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"a\", \"c\"})\n\tfmt.Println(s)\n\ta := s.Sort()\n\tfmt.Println(a)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_Remove() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\ts.Remove(1)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// [a c d]\n}\n\nfunc ExampleSortedTArray_RemoveValue() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\ts.RemoveValue(\"b\")\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// [a c d]\n}\n\nfunc ExampleSortedTArray_PopLeft() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tr, _ := s.PopLeft()\n\tfmt.Println(r)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// a\n\t// [b c d]\n}\n\nfunc ExampleSortedTArray_PopRight() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s.Slice())\n\tr, _ := s.PopRight()\n\tfmt.Println(r)\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d]\n\t// d\n\t// [a b c]\n}\n\nfunc ExampleSortedTArray_PopRights() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopRights(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [g h]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleSortedTArray_Rand() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr, _ := s.PopRand()\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// b\n\t// [\"a\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedTArray_PopRands() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopRands(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// [d a]\n\t// [\"b\",\"c\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedTArray_PopLefts() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.PopLefts(2)\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [a b]\n\t// [\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedTArray_Range() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Range(2, 5)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [c d e]\n}\n\nfunc ExampleSortedTArray_SubSlice() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.SubSlice(3, 4)\n\tfmt.Println(s.Slice())\n\tfmt.Println(r)\n\n\t// Output:\n\t// [a b c d e f g h]\n\t// [d e f g]\n}\n\nfunc ExampleSortedTArray_Add() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.Add(\"b\", \"d\", \"c\", \"a\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_Append() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"b\", \"d\", \"c\", \"a\"})\n\tfmt.Println(s)\n\ts.Append(\"f\", \"e\", \"g\")\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\"]\n}\n\nfunc ExampleSortedTArray_Len() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Len())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// 8\n}\n\nfunc ExampleSortedTArray_Slice() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s.Slice())\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleSortedTArray_Interfaces() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Interfaces()\n\tfmt.Println(r)\n\n\t// Output:\n\t// [a b c d e f g h]\n}\n\nfunc ExampleSortedTArray_Clone() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tr := s.Clone()\n\tfmt.Println(r)\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n}\n\nfunc ExampleSortedTArray_Clear() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Clear())\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// []\n\t// []\n}\n\nfunc ExampleSortedTArray_Contains() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s.Contains(\"e\"))\n\tfmt.Println(s.Contains(\"E\"))\n\tfmt.Println(s.Contains(\"z\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// false\n}\n\nfunc ExampleSortedTArray_Search() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Search(\"e\"))\n\tfmt.Println(s.Search(\"E\"))\n\tfmt.Println(s.Search(\"z\"))\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// 4\n\t// -1\n\t// -1\n}\n\nfunc ExampleSortedTArray_Unique() {\n\ts := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts.SetArray(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"})\n\tfmt.Println(s)\n\tfmt.Println(s.Unique())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\",\"c\",\"c\",\"d\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_LockFunc() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts.LockFunc(func(array []string) {\n\t\tarray[len(array)-1] = \"GF fans\"\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// [\"GF fans\",\"a\",\"b\"]\n}\n\nfunc ExampleSortedTArray_RLockFunc() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts.RLockFunc(func(array []string) {\n\t\tarray[len(array)-1] = \"GF fans\"\n\t\tfmt.Println(array[len(array)-1])\n\t})\n\tfmt.Println(s)\n\n\t// Output:\n\t// GF fans\n\t// [\"a\",\"b\",\"GF fans\"]\n}\n\nfunc ExampleSortedTArray_Merge() {\n\ts1 := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts2 := garray.NewSortedTArray[string](gutil.ComparatorT)\n\ts1.SetArray(g.SliceStr{\"b\", \"c\", \"a\"})\n\ts2.SetArray(g.SliceStr{\"e\", \"d\", \"f\"})\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\ts1.Merge(s2)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\"]\n\t// [\"d\",\"e\",\"f\"]\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n}\n\nfunc ExampleSortedTArray_Chunk() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"}, gutil.ComparatorT)\n\tr := s.Chunk(3)\n\tfmt.Println(r)\n\n\t// Output:\n\t// [[a b c] [d e f] [g h]]\n}\n\nfunc ExampleSortedTArray_Rands() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"}, gutil.ComparatorT)\n\tfmt.Println(s)\n\tfmt.Println(s.Rands(3))\n\n\t// May Output:\n\t// [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\"]\n\t// [h g c]\n}\n\nfunc ExampleSortedTArray_Join() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"c\", \"b\", \"a\", \"d\", \"f\", \"e\", \"h\", \"g\"}, gutil.ComparatorT)\n\tfmt.Println(s.Join(\",\"))\n\n\t// Output:\n\t// a,b,c,d,e,f,g,h\n}\n\nfunc ExampleSortedTArray_CountValues() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"a\", \"b\", \"c\", \"c\", \"c\", \"d\", \"d\"}, gutil.ComparatorT)\n\tfmt.Println(s.CountValues())\n\n\t// Output:\n\t// map[a:1 b:1 c:3 d:2]\n}\n\nfunc ExampleSortedTArray_Iterator() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts.Iterator(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleSortedTArray_IteratorAsc() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts.IteratorAsc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 0 a\n\t// 1 b\n\t// 2 c\n}\n\nfunc ExampleSortedTArray_IteratorDesc() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts.IteratorDesc(func(k int, v string) bool {\n\t\tfmt.Println(k, v)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 2 c\n\t// 1 b\n\t// 0 a\n}\n\nfunc ExampleSortedTArray_String() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\tfmt.Println(s.String())\n\n\t// Output:\n\t// [\"a\",\"b\",\"c\"]\n}\n\nfunc ExampleSortedTArray_MarshalJSON() {\n\ttype Student struct {\n\t\tID     int\n\t\tName   string\n\t\tLevels garray.SortedTArray[string]\n\t}\n\tr := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"c\", \"a\"}, gutil.ComparatorT)\n\ts := Student{\n\t\tID:     1,\n\t\tName:   \"john\",\n\t\tLevels: *r,\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// Output:\n\t// {\"ID\":1,\"Name\":\"john\",\"Levels\":[\"a\",\"b\",\"c\"]}\n}\n\nfunc ExampleSortedTArray_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Lessons\":[\"Math\",\"English\",\"Sport\"]}`)\n\ttype Student struct {\n\t\tId      int\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// Output:\n\t// {1 john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleSortedTArray_UnmarshalValue() {\n\ttype Student struct {\n\t\tName    string\n\t\tLessons *garray.StrArray\n\t}\n\tvar s *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": []byte(`[\"Math\",\"English\",\"Sport\"]`),\n\t}, &s)\n\tfmt.Println(s)\n\n\tvar s1 *Student\n\tgconv.Struct(g.Map{\n\t\t\"name\":    \"john\",\n\t\t\"lessons\": g.SliceStr{\"Math\", \"English\", \"Sport\"},\n\t}, &s1)\n\tfmt.Println(s1)\n\n\t// Output:\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n\t// &{john [\"Math\",\"English\",\"Sport\"]}\n}\n\nfunc ExampleSortedTArray_Filter() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"}, gutil.ComparatorT)\n\tfmt.Println(s)\n\tfmt.Println(s.Filter(func(index int, value string) bool {\n\t\treturn empty.IsEmpty(value)\n\t}))\n\n\t// Output:\n\t// [\"\",\"\",\"\",\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_FilterEmpty() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"}, gutil.ComparatorT)\n\tfmt.Println(s)\n\tfmt.Println(s.FilterEmpty())\n\n\t// Output:\n\t// [\"\",\"\",\"\",\"a\",\"b\",\"c\",\"d\"]\n\t// [\"a\",\"b\",\"c\",\"d\"]\n}\n\nfunc ExampleSortedTArray_IsEmpty() {\n\ts := garray.NewSortedTArrayFrom(g.SliceStr{\"b\", \"a\", \"\", \"c\", \"\", \"\", \"d\"}, gutil.ComparatorT)\n\tfmt.Println(s.IsEmpty())\n\ts1 := garray.NewSortedTArray[string](gutil.ComparatorT)\n\tfmt.Println(s1.IsEmpty())\n\n\t// Output:\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_all_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Array_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.Array\n\t\texpect := []int{2, 3, 1}\n\t\tarray.Append(2, 3, 1)\n\t\tt.Assert(array.Slice(), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.IntArray\n\t\texpect := []int{2, 3, 1}\n\t\tarray.Append(2, 3, 1)\n\t\tt.Assert(array.Slice(), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.StrArray\n\t\texpect := []string{\"b\", \"a\"}\n\t\tarray.Append(\"b\", \"a\")\n\t\tt.Assert(array.Slice(), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.SortedArray\n\t\tarray.SetComparator(gutil.ComparatorInt)\n\t\texpect := []int{1, 2, 3}\n\t\tarray.Add(2, 3, 1)\n\t\tt.Assert(array.Slice(), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.SortedIntArray\n\t\texpect := []int{1, 2, 3}\n\t\tarray.Add(2, 3, 1)\n\t\tt.Assert(array.Slice(), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.SortedStrArray\n\t\texpect := []string{\"a\", \"b\", \"c\"}\n\t\tarray.Add(\"c\", \"a\", \"b\")\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_SortedIntArray_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar array garray.SortedIntArray\n\t\texpect := []int{1, 2, 3}\n\t\tarray.Add(2, 3, 1)\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_IntArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{1, 2, 3, 4, 5, 6}\n\t\tarray := garray.NewIntArray()\n\t\tarray.Append(1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6)\n\t\tarray.Unique()\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_SortedIntArray1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}\n\t\tarray := garray.NewSortedIntArray()\n\t\tfor i := 10; i > -1; i-- {\n\t\t\tarray.Add(i)\n\t\t}\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Add().Slice(), expect)\n\t})\n}\n\nfunc Test_SortedIntArray2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}\n\t\tarray := garray.NewSortedIntArray()\n\t\tfor i := 0; i <= 10; i++ {\n\t\t\tarray.Add(i)\n\t\t}\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_SortedStrArray1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"10\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"}\n\t\tarray1 := garray.NewSortedStrArray()\n\t\tarray2 := garray.NewSortedStrArray(true)\n\t\tfor i := 10; i > -1; i-- {\n\t\t\tarray1.Add(gconv.String(i))\n\t\t\tarray2.Add(gconv.String(i))\n\t\t}\n\t\tt.Assert(array1.Slice(), expect)\n\t\tt.Assert(array2.Slice(), expect)\n\t})\n\n}\n\nfunc Test_SortedStrArray2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"10\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"}\n\t\tarray := garray.NewSortedStrArray()\n\t\tfor i := 0; i <= 10; i++ {\n\t\t\tarray.Add(gconv.String(i))\n\t\t}\n\t\tt.Assert(array.Slice(), expect)\n\t\tarray.Add()\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_SortedArray1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"10\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"}\n\t\tarray := garray.NewSortedArray(func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t})\n\t\tfor i := 10; i > -1; i-- {\n\t\t\tarray.Add(gconv.String(i))\n\t\t}\n\t\tt.Assert(array.Slice(), expect)\n\t})\n}\n\nfunc Test_SortedArray2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"10\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray := garray.NewSortedArray(func1)\n\t\tarray2 := garray.NewSortedArray(func1, true)\n\t\tfor i := 0; i <= 10; i++ {\n\t\t\tarray.Add(gconv.String(i))\n\t\t\tarray2.Add(gconv.String(i))\n\t\t}\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Add().Slice(), expect)\n\t\tt.Assert(array2.Slice(), expect)\n\t})\n}\n\nfunc TestNewFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"100\", \"200\", \"300\", \"400\", \"500\", \"600\"}\n\t\tarray1 := garray.NewFromCopy(a1)\n\t\tt.AssertIN(array1.PopRands(2), a1)\n\t\tt.Assert(len(array1.PopRands(1)), 1)\n\t\tt.Assert(len(array1.PopRands(9)), 3)\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_normal_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Array_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []any{0, 1, 2, 3}\n\t\tarray := garray.NewArrayFrom(expect)\n\t\tarray2 := garray.NewArrayFrom(expect)\n\t\tarray3 := garray.NewArrayFrom([]any{})\n\t\tarray4 := garray.NewArrayRange(1, 5, 1)\n\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Interfaces(), expect)\n\t\terr := array.Set(0, 100)\n\t\tt.AssertNil(err)\n\n\t\terr = array.Set(100, 100)\n\t\tt.AssertNE(err, nil)\n\n\t\tt.Assert(array.IsEmpty(), false)\n\n\t\tcopyArray := array.DeepCopy()\n\t\tca := copyArray.(*garray.Array)\n\t\tca.Set(0, 1)\n\t\tcval, _ := ca.Get(0)\n\t\tval, _ := array.Get(0)\n\t\tt.AssertNE(cval, val)\n\n\t\tv, ok := array.Get(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Get(1)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Get(4)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Search(100), 0)\n\t\tt.Assert(array3.Search(100), -1)\n\t\tt.Assert(array.Contains(100), true)\n\n\t\tv, ok = array.Remove(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Remove(-1)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array.Remove(100000)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array2.Remove(3)\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array2.Remove(1)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array.Contains(100), false)\n\t\tarray.Append(4)\n\t\tt.Assert(array.Len(), 4)\n\t\tarray.InsertBefore(0, 100)\n\t\tarray.InsertAfter(0, 200)\n\t\tt.Assert(array.Slice(), []any{100, 200, 2, 2, 3, 4})\n\t\tarray.InsertBefore(5, 300)\n\t\tarray.InsertAfter(6, 400)\n\t\tt.Assert(array.Slice(), []any{100, 200, 2, 2, 3, 300, 4, 400})\n\t\tt.Assert(array.Clear().Len(), 0)\n\t\terr = array.InsertBefore(99, 9900)\n\t\tt.AssertNE(err, nil)\n\t\terr = array.InsertAfter(99, 9900)\n\t\tt.AssertNE(err, nil)\n\n\t\tt.Assert(array4.String(), \"[1,2,3,4,5]\")\n\t})\n}\n\nfunc TestArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect1 := []any{0, 1, 2, 3}\n\t\texpect2 := []any{3, 2, 1, 0}\n\t\tarray := garray.NewArray()\n\t\tfor i := 3; i >= 0; i-- {\n\t\t\tarray.Append(i)\n\t\t}\n\t\tarray.SortFunc(func(v1, v2 any) bool {\n\t\t\treturn v1.(int) < v2.(int)\n\t\t})\n\t\tt.Assert(array.Slice(), expect1)\n\t\tarray.SortFunc(func(v1, v2 any) bool {\n\t\t\treturn v1.(int) > v2.(int)\n\t\t})\n\t\tt.Assert(array.Slice(), expect2)\n\t})\n}\n\nfunc TestArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []any{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray := garray.NewArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []any{1, 2, 3, 4, 5})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []any{}\n\t\tarray := garray.NewArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []any{})\n\t})\n}\n\nfunc TestArray_PushAndPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []any{0, 1, 2, 3}\n\t\tarray := garray.NewArrayFrom(expect)\n\t\tt.Assert(array.Slice(), expect)\n\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []any{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []any{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tarray.PushLeft(1).PushRight(2)\n\t\tt.Assert(array.Slice(), []any{1, 2})\n\t})\n}\n\nfunc TestArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{100, 200, 300, 400, 500, 600}\n\t\tarray := garray.NewFromCopy(a1)\n\t\tt.AssertIN(array.PopRands(2), []any{100, 200, 300, 400, 500, 600})\n\t})\n}\n\nfunc TestArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tt.Assert(array.PopLefts(2), g.Slice{1, 2})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{3})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tt.Assert(array.PopRights(2), g.Slice{2, 3})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{1})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestArray_PopLeftsAndPopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New()\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tvalue2 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(value1)\n\t\tarray2 := garray.NewArrayFrom(value2)\n\t\tt.Assert(array1.PopLefts(2), []any{0, 1})\n\t\tt.Assert(array1.Slice(), []any{2, 3, 4, 5, 6})\n\t\tt.Assert(array1.PopRights(2), []any{5, 6})\n\t\tt.Assert(array1.Slice(), []any{2, 3, 4})\n\t\tt.Assert(array1.PopRights(20), []any{2, 3, 4})\n\t\tt.Assert(array1.Slice(), []any{})\n\t\tt.Assert(array2.PopLefts(20), []any{0, 1, 2, 3, 4, 5, 6})\n\t\tt.Assert(array2.Slice(), []any{})\n\t})\n}\n\nfunc TestArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(value1)\n\t\tarray2 := garray.NewArrayFrom(value1, true)\n\t\tt.Assert(array1.Range(0, 1), []any{0})\n\t\tt.Assert(array1.Range(1, 2), []any{1})\n\t\tt.Assert(array1.Range(0, 2), []any{0, 1})\n\t\tt.Assert(array1.Range(-1, 10), value1)\n\t\tt.Assert(array1.Range(10, 2), nil)\n\t\tt.Assert(array2.Range(1, 3), []any{1, 2})\n\t})\n}\n\nfunc TestArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\ti1 := []any{0, 1, 2, 3}\n\t\ti2 := []any{4, 5, 6, 7}\n\t\tarray1 := garray.NewArrayFrom(i1)\n\t\tarray2 := garray.NewArrayFrom(i2)\n\t\tt.Assert(array1.Merge(array2).Slice(), []any{0, 1, 2, 3, 4, 5, 6, 7})\n\n\t\t// s1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti3 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti4 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\t\ta1 := garray.NewArrayFrom(i1)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i3).Len(), 9)\n\t\tt.Assert(a1.Merge(i4).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestArray_Fill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0}\n\t\ta2 := []any{0}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := garray.NewArrayFrom(a2, true)\n\n\t\tt.Assert(array1.Fill(1, 2, 100), nil)\n\t\tt.Assert(array1.Slice(), []any{0, 100, 100})\n\n\t\tt.Assert(array2.Fill(0, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []any{100, 100})\n\n\t\tt.AssertNE(array2.Fill(-1, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []any{100, 100})\n\t})\n}\n\nfunc TestArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []any{1, 2})\n\t\tt.Assert(chunks[1], []any{3, 4})\n\t\tt.Assert(chunks[2], []any{5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []any{1, 2})\n\t\tt.Assert(chunks[1], []any{3, 4})\n\t\tt.Assert(chunks[2], []any{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestArray_Pad(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []any{0, 1, 1})\n\t\tt.Assert(array1.Pad(-4, 1).Slice(), []any{1, 0, 1, 1})\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []any{1, 0, 1, 1})\n\t})\n}\n\nfunc TestArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := garray.NewArrayFrom(a1, true)\n\t\tt.Assert(array1.SubSlice(0, 2), []any{0, 1})\n\t\tt.Assert(array1.SubSlice(2, 2), []any{2, 3})\n\t\tt.Assert(array1.SubSlice(5, 8), []any{5, 6})\n\t\tt.Assert(array1.SubSlice(9, 1), nil)\n\t\tt.Assert(array1.SubSlice(-2, 2), []any{5, 6})\n\t\tt.Assert(array1.SubSlice(-9, 2), nil)\n\t\tt.Assert(array1.SubSlice(1, -2), nil)\n\t\tt.Assert(array2.SubSlice(0, 2), []any{0, 1})\n\t})\n}\n\nfunc TestArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(len(array1.Rands(2)), 2)\n\t\tt.Assert(len(array1.Rands(10)), 10)\n\t\tt.AssertIN(array1.Rands(1)[0], a1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewArrayFrom(s1)\n\t\ti1, ok := a1.Rand()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(a1.Contains(i1), true)\n\t\tt.Assert(a1.Len(), 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\trand, found := array1.Rand()\n\t\tt.AssertNil(rand)\n\t\tt.Assert(found, false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\trand := array1.Rands(1)\n\t\tt.AssertNil(rand)\n\t})\n}\n\nfunc TestArray_Shuffle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.Shuffle().Len(), 7)\n\t})\n}\n\nfunc TestArray_Reverse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.Reverse().Slice(), []any{6, 5, 4, 3, 2, 1, 0})\n\t})\n}\n\nfunc TestArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.2.3.4.5.6`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, `\"a\"`, `\\a`}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.\"a\".\\a`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(len(array1.Join(\".\")), 0)\n\t})\n}\n\nfunc TestArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tt.Assert(array1.String(), `[0,1,2,3,4,5,6]`)\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestArray_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\t\ta3 := []any{\"m\", \"n\", \"p\", \"z\", \"x\", \"y\", \"d\", \"u\"}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := array1.Replace(a2)\n\t\tt.Assert(array2.Len(), 7)\n\t\tt.Assert(array2.Contains(\"b\"), true)\n\t\tt.Assert(array2.Contains(4), true)\n\t\tt.Assert(array2.Contains(\"v\"), false)\n\t\tarray3 := array1.Replace(a3)\n\t\tt.Assert(array3.Len(), 7)\n\t\tt.Assert(array3.Contains(4), false)\n\t\tt.Assert(array3.Contains(\"p\"), true)\n\t\tt.Assert(array3.Contains(\"u\"), false)\n\t})\n}\n\nfunc TestArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray1 = array1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"b\"), true)\n\t\tt.Assert(array1.Contains(\"5\"), false)\n\t})\n}\n\nfunc TestArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\t\ta3 := []any{\"a\", \"1\", \"2\"}\n\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := garray.NewArrayFrom(a2)\n\t\tarray3 := garray.NewArrayFrom(a3)\n\n\t\tt.Assert(array1.Sum(), 6)\n\t\tt.Assert(array2.Sum(), 0)\n\t\tt.Assert(array3.Sum(), 3)\n\n\t})\n}\n\nfunc TestArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array2.Sum(), 6)\n\t\tt.AssertEQ(array1, array2)\n\n\t})\n}\n\nfunc TestArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"b\", \"c\", \"d\", \"e\", \"d\"}\n\t\tarray1 := garray.NewArrayFrom(a1)\n\t\tarray2 := array1.CountValues()\n\t\tt.Assert(len(array2), 5)\n\t\tt.Assert(array2[\"b\"], 1)\n\t\tt.Assert(array2[\"d\"], 2)\n\t})\n}\n\nfunc TestArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []any) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []any) { // 读锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停1秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候，并没有阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestArray_Json(t *testing.T) {\n\t// pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := garray.NewArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.New()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.Array\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// value.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := *garray.NewArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.New()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.Array\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.Array\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n\t// value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.Array\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n}\n\nfunc TestArray_Iterator(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestArray_RemoveValue(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestArray_RemoveValues(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.Slice{\"d\"})\n\t})\n}\n\nfunc TestArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.Array\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[1,2,3]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.Slice{1, 2, 3},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n}\n\nfunc TestArray_FilterNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}\n\t\tarray := garray.NewArrayFromCopy(values)\n\t\tt.Assert(array.FilterNil().Slice(), values)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})\n\t\tt.Assert(array.FilterNil(), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}\n\t\tarray := garray.NewArrayFromCopy(values)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}).Slice(), values)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}})\n\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFrom(g.Slice{1, 2, 3, 4})\n\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}})\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFrom(g.Slice{1, 2, 3, 4})\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewArrayFrom(g.Slice{\"1\", \"2\"})\n\t\tt.Assert(array.Walk(func(value any) any {\n\t\t\treturn \"key-\" + gconv.String(value)\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_normal_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_IntArray_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{0, 1, 2, 3}\n\t\texpect2 := []int{}\n\t\tarray := garray.NewIntArrayFrom(expect)\n\t\tarray2 := garray.NewIntArrayFrom(expect2)\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Interfaces(), expect)\n\t\tarray.Set(0, 100)\n\n\t\tv, ok := array.Get(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Get(1)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array.Search(100), 0)\n\t\tt.Assert(array2.Search(100), -1)\n\t\tt.Assert(array.Contains(100), true)\n\n\t\tv, ok = array.Remove(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Remove(-1)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array.Remove(100000)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Contains(100), false)\n\t\tarray.Append(4)\n\t\tt.Assert(array.Len(), 4)\n\t\tarray.InsertBefore(0, 100)\n\t\tarray.InsertAfter(0, 200)\n\t\tt.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 4})\n\t\tarray.InsertBefore(5, 300)\n\t\tarray.InsertAfter(6, 400)\n\t\tt.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 300, 4, 400})\n\t\tt.Assert(array.Clear().Len(), 0)\n\t\terr := array.InsertBefore(99, 300)\n\t\tt.AssertNE(err, nil)\n\t\terr = array.InsertAfter(99, 400)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom([]int{0, 1, 2, 3})\n\t\tcopyArray := array.DeepCopy().(*garray.IntArray)\n\t\tcopyArray.Set(0, 1)\n\t\tcval, _ := copyArray.Get(0)\n\t\tval, _ := array.Get(0)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n\nfunc TestIntArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect1 := []int{0, 1, 2, 3}\n\t\texpect2 := []int{3, 2, 1, 0}\n\t\tarray := garray.NewIntArray()\n\t\tarray2 := garray.NewIntArray(true)\n\t\tfor i := 3; i >= 0; i-- {\n\t\t\tarray.Append(i)\n\t\t\tarray2.Append(i)\n\t\t}\n\t\tarray.Sort()\n\t\tt.Assert(array.Slice(), expect1)\n\t\tarray.Sort(true)\n\t\tt.Assert(array.Slice(), expect2)\n\t\tt.Assert(array2.Slice(), expect2)\n\t})\n}\n\nfunc TestIntArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray := garray.NewIntArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []int{1, 2, 3, 4, 5})\n\t\tarray2 := garray.NewIntArrayFrom([]int{})\n\t\tt.Assert(array2.Unique().Slice(), []int{})\n\t})\n}\n\nfunc TestIntArray_PushAndPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{0, 1, 2, 3}\n\t\tarray := garray.NewIntArrayFrom(expect)\n\t\tt.Assert(array.Slice(), expect)\n\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []int{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []int{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tarray.PushLeft(1).PushRight(2)\n\t\tt.Assert(array.Slice(), []int{1, 2})\n\t})\n}\n\nfunc TestIntArray_PopLeftsAndPopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArray()\n\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tvalue2 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(value1)\n\t\tarray2 := garray.NewIntArrayFrom(value2)\n\t\tt.Assert(array1.PopLefts(2), []int{0, 1})\n\t\tt.Assert(array1.Slice(), []int{2, 3, 4, 5, 6})\n\t\tt.Assert(array1.PopRights(2), []int{5, 6})\n\t\tt.Assert(array1.Slice(), []int{2, 3, 4})\n\t\tt.Assert(array1.PopRights(20), []int{2, 3, 4})\n\t\tt.Assert(array1.Slice(), []int{})\n\t\tt.Assert(array2.PopLefts(20), []int{0, 1, 2, 3, 4, 5, 6})\n\t\tt.Assert(array2.Slice(), []int{})\n\t})\n}\n\nfunc TestIntArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(value1)\n\t\tarray2 := garray.NewIntArrayFrom(value1, true)\n\t\tt.Assert(array1.Range(0, 1), []int{0})\n\t\tt.Assert(array1.Range(1, 2), []int{1})\n\t\tt.Assert(array1.Range(0, 2), []int{0, 1})\n\t\tt.Assert(array1.Range(10, 2), nil)\n\t\tt.Assert(array1.Range(-1, 10), value1)\n\t\tt.Assert(array2.Range(1, 2), []int{1})\n\t})\n}\n\nfunc TestIntArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\tn1 := []int{0, 1, 2, 3}\n\t\tn2 := []int{4, 5, 6, 7}\n\t\ti1 := []any{\"1\", \"2\"}\n\t\ts1 := []string{\"a\", \"b\", \"c\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ta1 := garray.NewIntArrayFrom(n1)\n\t\ta2 := garray.NewIntArrayFrom(n2)\n\t\ta3 := garray.NewArrayFrom(i1)\n\t\ta4 := garray.NewStrArrayFrom(s1)\n\n\t\ta5 := garray.NewSortedStrArrayFrom(s2)\n\t\ta6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\n\t\ta7 := garray.NewSortedStrArrayFrom(s1)\n\t\ta8 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\n\t\tt.Assert(a1.Merge(a2).Slice(), []int{0, 1, 2, 3, 4, 5, 6, 7})\n\t\tt.Assert(a1.Merge(a3).Len(), 10)\n\t\tt.Assert(a1.Merge(a4).Len(), 13)\n\t\tt.Assert(a1.Merge(a5).Len(), 15)\n\t\tt.Assert(a1.Merge(a6).Len(), 18)\n\t\tt.Assert(a1.Merge(a7).Len(), 21)\n\t\tt.Assert(a1.Merge(a8).Len(), 23)\n\t})\n}\n\nfunc TestIntArray_Fill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0}\n\t\ta2 := []int{0}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray2 := garray.NewIntArrayFrom(a2)\n\t\tt.Assert(array1.Fill(1, 2, 100), nil)\n\t\tt.Assert(array1.Slice(), []int{0, 100, 100})\n\n\t\tt.Assert(array2.Fill(0, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []int{100, 100})\n\n\t\tt.AssertNE(array2.Fill(-1, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []int{100, 100})\n\t})\n}\n\nfunc TestIntArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestIntArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3})\n\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestIntArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3})\n\t\tt.Assert(array.PopLefts(2), g.Slice{1, 2})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{3})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestIntArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3})\n\t\tt.Assert(array.PopRights(2), g.Slice{2, 3})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{1})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestIntArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []int{1, 2})\n\t\tt.Assert(chunks[1], []int{3, 4})\n\t\tt.Assert(chunks[2], []int{5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int{1, 2, 3})\n\t\tt.Assert(chunks[1], []int{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []int{1, 2})\n\t\tt.Assert(chunks[1], []int{3, 4})\n\t\tt.Assert(chunks[2], []int{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int{1, 2, 3})\n\t\tt.Assert(chunks[1], []int{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestIntArray_Pad(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []int{0, 1, 1})\n\t\tt.Assert(array1.Pad(-4, 1).Slice(), []int{1, 0, 1, 1})\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []int{1, 0, 1, 1})\n\t})\n}\n\nfunc TestIntArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray2 := garray.NewIntArrayFrom(a1, true)\n\t\tt.Assert(array1.SubSlice(6), []int{6})\n\t\tt.Assert(array1.SubSlice(5), []int{5, 6})\n\t\tt.Assert(array1.SubSlice(8), nil)\n\t\tt.Assert(array1.SubSlice(0, 2), []int{0, 1})\n\t\tt.Assert(array1.SubSlice(2, 2), []int{2, 3})\n\t\tt.Assert(array1.SubSlice(5, 8), []int{5, 6})\n\t\tt.Assert(array1.SubSlice(-1, 1), []int{6})\n\t\tt.Assert(array1.SubSlice(-1, 9), []int{6})\n\t\tt.Assert(array1.SubSlice(-2, 3), []int{5, 6})\n\t\tt.Assert(array1.SubSlice(-7, 3), []int{0, 1, 2})\n\t\tt.Assert(array1.SubSlice(-8, 3), nil)\n\t\tt.Assert(array1.SubSlice(-1, -3), []int{3, 4, 5})\n\t\tt.Assert(array1.SubSlice(-9, 3), nil)\n\t\tt.Assert(array1.SubSlice(1, -1), []int{0})\n\t\tt.Assert(array1.SubSlice(1, -3), nil)\n\t\tt.Assert(array2.SubSlice(0, 2), []int{0, 1})\n\t})\n}\n\nfunc TestIntArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(len(array1.Rands(2)), 2)\n\t\tt.Assert(len(array1.Rands(10)), 10)\n\t\tt.AssertIN(array1.Rands(1)[0], a1)\n\n\t\tv, ok := array1.Rand()\n\t\tt.AssertIN(v, a1)\n\t\tt.Assert(ok, true)\n\n\t\tarray2 := garray.NewIntArrayFrom([]int{})\n\t\tv, ok = array2.Rand()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tintSlices := array2.Rands(1)\n\t\tt.Assert(intSlices, nil)\n\t})\n}\n\nfunc TestIntArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{100, 200, 300, 400, 500, 600}\n\t\tarray := garray.NewIntArrayFrom(a1)\n\t\tns1 := array.PopRands(2)\n\t\tt.AssertIN(ns1, []int{100, 200, 300, 400, 500, 600})\n\t\tt.Assert(len(ns1), 2)\n\n\t\tns2 := array.PopRands(7)\n\t\tt.Assert(len(ns2), 4)\n\t\tt.AssertIN(ns2, []int{100, 200, 300, 400, 500, 600})\n\t})\n}\n\nfunc TestIntArray_Shuffle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.Shuffle().Len(), 7)\n\t})\n}\n\nfunc TestIntArray_Reverse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.Reverse().Slice(), []int{6, 5, 4, 3, 2, 1, 0})\n\t})\n}\n\nfunc TestIntArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), \"0.1.2.3.4.5.6\")\n\t})\n}\n\nfunc TestIntArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.String(), \"[0,1,2,3,4,5,6]\")\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestIntArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\ta2 := []int{6, 7}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(array1, []int{6, 7})\n\t})\n}\n\nfunc TestIntArray_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\ta2 := []int{6, 7}\n\t\ta3 := []int{9, 10, 11, 12, 13}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray1.Replace(a2)\n\t\tt.Assert(array1, []int{6, 7, 3, 5})\n\n\t\tarray1.Replace(a3)\n\t\tt.Assert(array1, []int{9, 10, 11, 12})\n\t})\n}\n\nfunc TestIntArray_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray1.Clear()\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestIntArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array1, array2)\n\t})\n}\n\nfunc TestArray_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tv, ok := array1.Get(2)\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 4)\n\t})\n}\n\nfunc TestIntArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tt.Assert(array1.Sum(), 11)\n\t})\n}\n\nfunc TestIntArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5, 3}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tm1 := array1.CountValues()\n\t\tt.Assert(len(m1), 4)\n\t\tt.Assert(m1[1], 1)\n\t\tt.Assert(m1[3], 2)\n\t})\n}\n\nfunc TestNewIntArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5, 3}\n\t\tarray1 := garray.NewIntArrayFromCopy(a1)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, a1)\n\t})\n}\n\nfunc TestIntArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 5, 4}\n\t\tarray1 := garray.NewIntArrayFrom(a1)\n\t\tv, ok := array1.Remove(1)\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 4)\n\n\t\tv, ok = array1.Remove(0)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 3)\n\n\t\tv, ok = array1.Remove(2)\n\t\tt.Assert(v, 4)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 2)\n\t})\n}\n\nfunc TestIntArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 2, 3, 4}\n\t\ta1 := garray.NewIntArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []int) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = 6\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(6), true)\n\t})\n}\n\nfunc TestIntArray_SortFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 4, 3, 2}\n\t\ta1 := garray.NewIntArrayFrom(s1)\n\t\tfunc1 := func(v1, v2 int) bool {\n\t\t\treturn v1 < v2\n\t\t}\n\t\ta11 := a1.SortFunc(func1)\n\t\tt.Assert(a11, []int{1, 2, 3, 4})\n\n\t})\n}\n\nfunc TestIntArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 2, 3, 4}\n\t\ta1 := garray.NewIntArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []int) { // 读锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停1秒\n\t\t\tn1[2] = 6\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候，并没有阻塞。\n\t\tt.Assert(a1.Contains(6), true)\n\t})\n}\n\nfunc TestIntArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 4, 3, 2}\n\t\ta1 := garray.NewIntArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewIntArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.IntArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 4, 3, 2}\n\t\ta1 := *garray.NewIntArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewIntArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.IntArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.IntArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.IntArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n}\n\nfunc TestIntArray_Iterator(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestIntArray_RemoveValue(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(99), false)\n\t\tt.Assert(array.RemoveValue(20), true)\n\t\tt.Assert(array.RemoveValue(10), true)\n\t\tt.Assert(array.RemoveValue(20), false)\n\t\tt.Assert(array.RemoveValue(88), false)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestIntArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(10, 20, 40)\n\t\tt.Assert(array.Slice(), g.SliceInt{30})\n\t})\n}\n\nfunc TestIntArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.IntArray\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[1,2,3]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\tvar v *V\n\t//\terr := gconv.Struct(g.Map{\n\t//\t\t\"name\":  \"john\",\n\t//\t\t\"array\": g.Slice{1, 2, 3},\n\t//\t}, &v)\n\t//\tt.AssertNil(err)\n\t//\tt.Assert(v.Name, \"john\")\n\t//\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t// })\n}\n\nfunc TestIntArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceInt{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\n\t\t}), g.SliceInt{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn value%2 == 0\n\t\t}), g.SliceInt{1, 3})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn value%2 == 1\n\t\t}), g.SliceInt{2, 4})\n\t})\n}\n\nfunc TestIntArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})\n\t\tt.Assert(array.FilterEmpty(), g.SliceInt{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.FilterEmpty(), g.SliceInt{1, 2, 3, 4})\n\t})\n}\n\nfunc TestIntArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayFrom(g.SliceInt{1, 2})\n\t\tt.Assert(array.Walk(func(value int) int {\n\t\t\treturn 10 + value\n\t\t}), g.Slice{11, 12})\n\t})\n}\n\nfunc TestIntArray_NewIntArrayRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayRange(0, 128, 4)\n\t\tt.Assert(array.String(), `[0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128]`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewIntArrayRange(1, 128, 4)\n\t\tt.Assert(array.String(), `[1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125]`)\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_normal_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_StrArray_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"2\", \"3\"}\n\t\tarray := garray.NewStrArrayFrom(expect)\n\t\tarray2 := garray.NewStrArrayFrom(expect, true)\n\t\tarray3 := garray.NewStrArrayFrom([]string{})\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Interfaces(), expect)\n\t\tarray.Set(0, \"100\")\n\n\t\tv, ok := array.Get(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array3.Get(0)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Search(\"100\"), 0)\n\t\tt.Assert(array.Contains(\"100\"), true)\n\n\t\tv, ok = array.Remove(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Remove(-1)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array.Remove(100000)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Contains(\"100\"), false)\n\t\tarray.Append(\"4\")\n\t\tt.Assert(array.Len(), 4)\n\t\tarray.InsertBefore(0, \"100\")\n\t\tarray.InsertAfter(0, \"200\")\n\t\tt.Assert(array.Slice(), []string{\"100\", \"200\", \"1\", \"2\", \"3\", \"4\"})\n\t\tarray.InsertBefore(5, \"300\")\n\t\tarray.InsertAfter(6, \"400\")\n\t\tt.Assert(array.Slice(), []string{\"100\", \"200\", \"1\", \"2\", \"3\", \"300\", \"4\", \"400\"})\n\t\tt.Assert(array.Clear().Len(), 0)\n\t\tt.Assert(array2.Slice(), expect)\n\t\tt.Assert(array3.Search(\"100\"), -1)\n\t\terr := array.InsertBefore(99, \"300\")\n\t\tt.AssertNE(err, nil)\n\t\tarray.InsertAfter(99, \"400\")\n\t\tt.AssertNE(err, nil)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom([]string{\"0\", \"1\", \"2\", \"3\"})\n\n\t\tcopyArray := array.DeepCopy().(*garray.StrArray)\n\t\tcopyArray.Set(0, \"1\")\n\t\tcval, _ := copyArray.Get(0)\n\t\tval, _ := array.Get(0)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n\nfunc TestStrArray_ContainsI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := garray.NewStrArray()\n\t\tt.Assert(s.Contains(\"A\"), false)\n\t\ts.Append(\"a\", \"b\", \"C\")\n\t\tt.Assert(s.Contains(\"A\"), false)\n\t\tt.Assert(s.Contains(\"a\"), true)\n\t\tt.Assert(s.ContainsI(\"A\"), true)\n\t})\n}\n\nfunc TestStrArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect1 := []string{\"0\", \"1\", \"2\", \"3\"}\n\t\texpect2 := []string{\"3\", \"2\", \"1\", \"0\"}\n\t\tarray := garray.NewStrArray()\n\t\tfor i := 3; i >= 0; i-- {\n\t\t\tarray.Append(gconv.String(i))\n\t\t}\n\t\tarray.Sort()\n\t\tt.Assert(array.Slice(), expect1)\n\t\tarray.Sort(true)\n\t\tt.Assert(array.Slice(), expect2)\n\t})\n}\n\nfunc TestStrArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"1\", \"1\", \"2\", \"2\", \"3\", \"3\", \"2\", \"2\"}\n\t\tarray := garray.NewStrArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []string{\"1\", \"2\", \"3\"})\n\t\tarray1 := garray.NewStrArrayFrom([]string{})\n\t\tt.Assert(array1.Unique().Slice(), []string{})\n\t})\n}\n\nfunc TestStrArray_PushAndPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []string{\"0\", \"1\", \"2\", \"3\"}\n\t\tarray := garray.NewStrArrayFrom(expect)\n\t\tt.Assert(array.Slice(), expect)\n\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, \"0\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, \"3\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []string{\"1\", \"2\"})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []string{\"1\", \"2\"})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tarray.PushLeft(\"1\").PushRight(\"2\")\n\t\tt.Assert(array.Slice(), []string{\"1\", \"2\"})\n\t})\n}\n\nfunc TestStrArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestStrArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestStrArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tt.Assert(array.PopLefts(2), g.Slice{\"1\", \"2\"})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{\"3\"})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestStrArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tt.Assert(array.PopRights(2), g.Slice{\"2\", \"3\"})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{\"1\"})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestStrArray_PopLeftsAndPopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArray()\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tvalue2 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(value1)\n\t\tarray2 := garray.NewStrArrayFrom(value2)\n\t\tt.Assert(array1.PopLefts(2), []any{\"0\", \"1\"})\n\t\tt.Assert(array1.Slice(), []any{\"2\", \"3\", \"4\", \"5\", \"6\"})\n\t\tt.Assert(array1.PopRights(2), []any{\"5\", \"6\"})\n\t\tt.Assert(array1.Slice(), []any{\"2\", \"3\", \"4\"})\n\t\tt.Assert(array1.PopRights(20), []any{\"2\", \"3\", \"4\"})\n\t\tt.Assert(array1.Slice(), []any{})\n\t\tt.Assert(array2.PopLefts(20), []any{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"})\n\t\tt.Assert(array2.Slice(), []any{})\n\t})\n}\n\nfunc TestString_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(value1)\n\t\tarray2 := garray.NewStrArrayFrom(value1, true)\n\t\tt.Assert(array1.Range(0, 1), []any{\"0\"})\n\t\tt.Assert(array1.Range(1, 2), []any{\"1\"})\n\t\tt.Assert(array1.Range(0, 2), []any{\"0\", \"1\"})\n\t\tt.Assert(array1.Range(-1, 10), value1)\n\t\tt.Assert(array1.Range(10, 1), nil)\n\t\tt.Assert(array2.Range(0, 1), []any{\"0\"})\n\t})\n}\n\nfunc TestStrArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta11 := []string{\"0\", \"1\", \"2\", \"3\"}\n\t\ta21 := []string{\"4\", \"5\", \"6\", \"7\"}\n\t\tarray1 := garray.NewStrArrayFrom(a11)\n\t\tarray2 := garray.NewStrArrayFrom(a21)\n\t\tt.Assert(array1.Merge(array2).Slice(), []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\"})\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti1 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti2 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\t\ta1 := garray.NewStrArrayFrom(s1)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i1).Len(), 9)\n\t\tt.Assert(a1.Merge(i2).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestStrArray_Fill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\"}\n\t\ta2 := []string{\"0\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tarray2 := garray.NewStrArrayFrom(a2)\n\t\tt.Assert(array1.Fill(1, 2, \"100\"), nil)\n\t\tt.Assert(array1.Slice(), []string{\"0\", \"100\", \"100\"})\n\t\tt.Assert(array2.Fill(0, 2, \"100\"), nil)\n\t\tt.Assert(array2.Slice(), []string{\"100\", \"100\"})\n\t\tt.AssertNE(array2.Fill(-1, 2, \"100\"), nil)\n\t\tt.Assert(array2.Len(), 2)\n\t})\n}\n\nfunc TestStrArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\"})\n\t\tt.Assert(chunks[1], []string{\"3\", \"4\"})\n\t\tt.Assert(chunks[2], []string{\"5\"})\n\t\tt.Assert(len(array1.Chunk(0)), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\", \"3\"})\n\t\tt.Assert(chunks[1], []string{\"4\", \"5\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\"})\n\t\tt.Assert(chunks[1], []string{\"3\", \"4\"})\n\t\tt.Assert(chunks[2], []string{\"5\", \"6\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\", \"3\"})\n\t\tt.Assert(chunks[1], []string{\"4\", \"5\", \"6\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestStrArray_Pad(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Pad(3, \"1\").Slice(), []string{\"0\", \"1\", \"1\"})\n\t\tt.Assert(array1.Pad(-4, \"1\").Slice(), []string{\"1\", \"0\", \"1\", \"1\"})\n\t\tt.Assert(array1.Pad(3, \"1\").Slice(), []string{\"1\", \"0\", \"1\", \"1\"})\n\t})\n}\n\nfunc TestStrArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tarray2 := garray.NewStrArrayFrom(a1, true)\n\t\tt.Assert(array1.SubSlice(0, 2), []string{\"0\", \"1\"})\n\t\tt.Assert(array1.SubSlice(2, 2), []string{\"2\", \"3\"})\n\t\tt.Assert(array1.SubSlice(5, 8), []string{\"5\", \"6\"})\n\t\tt.Assert(array1.SubSlice(8, 2), nil)\n\t\tt.Assert(array1.SubSlice(1, -2), nil)\n\t\tt.Assert(array1.SubSlice(-5, 2), []string{\"2\", \"3\"})\n\t\tt.Assert(array1.SubSlice(-10, 1), nil)\n\t\tt.Assert(array2.SubSlice(0, 2), []string{\"0\", \"1\"})\n\t})\n}\n\nfunc TestStrArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(len(array1.Rands(2)), \"2\")\n\t\tt.Assert(len(array1.Rands(10)), 10)\n\t\tt.AssertIN(array1.Rands(1)[0], a1)\n\t\tv, ok := array1.Rand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(v, a1)\n\n\t\tarray2 := garray.NewStrArrayFrom([]string{})\n\t\tv, ok = array2.Rand()\n\t\tt.Assert(ok, false)\n\t\tt.Assert(v, \"\")\n\t\tstrArray := array2.Rands(1)\n\t\tt.AssertNil(strArray)\n\t})\n}\n\nfunc TestStrArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.AssertIN(array1.PopRands(1), []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"})\n\t\tt.AssertIN(array1.PopRands(1), []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"})\n\t\tt.AssertNI(array1.PopRands(1), array1.Slice())\n\t\tt.AssertNI(array1.PopRands(1), array1.Slice())\n\t\tt.Assert(len(array1.PopRands(10)), 3)\n\t})\n}\n\nfunc TestStrArray_Shuffle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Shuffle().Len(), 7)\n\t})\n}\n\nfunc TestStrArray_Reverse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Reverse().Slice(), []string{\"6\", \"5\", \"4\", \"3\", \"2\", \"1\", \"0\"})\n\t})\n}\n\nfunc TestStrArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.2.3.4.5.6`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", `\"a\"`, `\\a`}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.\"a\".\\a`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), \"\")\n\t})\n}\n\nfunc TestStrArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.String(), `[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\"]`)\n\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestNewStrArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\ta2 := garray.NewStrArrayFromCopy(a1)\n\t\ta3 := garray.NewStrArrayFromCopy(a1, true)\n\t\tt.Assert(a2.Contains(\"1\"), true)\n\t\tt.Assert(a2.Len(), 7)\n\t\tt.Assert(a2, a3)\n\t})\n}\n\nfunc TestStrArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\ta2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Contains(\"2\"), true)\n\t\tt.Assert(array1.Len(), 7)\n\n\t\tarray1 = array1.SetArray(a2)\n\t\tt.Assert(array1.Contains(\"2\"), false)\n\t\tt.Assert(array1.Contains(\"c\"), true)\n\t\tt.Assert(array1.Len(), 4)\n\t})\n}\n\nfunc TestStrArray_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\ta2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta3 := []string{\"o\", \"p\", \"q\", \"x\", \"y\", \"z\", \"w\", \"r\", \"v\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tt.Assert(array1.Contains(\"2\"), true)\n\t\tt.Assert(array1.Len(), 7)\n\n\t\tarray1 = array1.Replace(a2)\n\t\tt.Assert(array1.Contains(\"2\"), false)\n\t\tt.Assert(array1.Contains(\"c\"), true)\n\t\tt.Assert(array1.Contains(\"5\"), true)\n\t\tt.Assert(array1.Len(), 7)\n\n\t\tarray1 = array1.Replace(a3)\n\t\tt.Assert(array1.Contains(\"2\"), false)\n\t\tt.Assert(array1.Contains(\"c\"), false)\n\t\tt.Assert(array1.Contains(\"5\"), false)\n\t\tt.Assert(array1.Contains(\"p\"), true)\n\t\tt.Assert(array1.Contains(\"r\"), false)\n\t\tt.Assert(array1.Len(), 7)\n\n\t})\n}\n\nfunc TestStrArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\ta2 := []string{\"0\", \"a\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tarray2 := garray.NewStrArrayFrom(a2)\n\t\tt.Assert(array1.Sum(), 21)\n\t\tt.Assert(array2.Sum(), 18)\n\t})\n}\n\nfunc TestStrArray_PopRand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tstr1, ok := array1.PopRand()\n\t\tt.Assert(strings.Contains(\"0,1,2,3,4,5,6\", str1), true)\n\t\tt.Assert(array1.Len(), 6)\n\t\tt.Assert(ok, true)\n\t})\n}\n\nfunc TestStrArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array2, array1)\n\t\tt.Assert(array2.Len(), 7)\n\t})\n}\n\nfunc TestStrArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"4\", \"6\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\n\t\tm1 := array1.CountValues()\n\t\tt.Assert(len(m1), 6)\n\t\tt.Assert(m1[\"2\"], 1)\n\t\tt.Assert(m1[\"4\"], 2)\n\t})\n}\n\nfunc TestStrArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"a\", \"c\"}\n\t\tarray1 := garray.NewStrArrayFrom(a1)\n\t\ts1, ok := array1.Remove(1)\n\t\tt.Assert(s1, \"a\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 4)\n\t\ts1, ok = array1.Remove(3)\n\t\tt.Assert(s1, \"c\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 3)\n\t})\n}\n\nfunc TestStrArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewStrArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []string) { // 读锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停1秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候，并没有阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestStrArray_SortFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\ta1 := garray.NewStrArrayFrom(s1)\n\t\tfunc1 := func(v1, v2 string) bool {\n\t\t\treturn v1 < v2\n\t\t}\n\t\ta11 := a1.SortFunc(func1)\n\t\tt.Assert(a11, []string{\"a\", \"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestStrArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewStrArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []string) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestStrArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := garray.NewStrArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewStrArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.StrArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := *garray.NewStrArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewStrArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.StrArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.StrArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []string{\"A+\", \"A\", \"A\"},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.StrArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []string{\"A+\", \"A\", \"A\"},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n}\n\nfunc TestStrArray_Iterator(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestStrArray_RemoveValue(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestStrArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.SliceStr{\"d\"})\n\t})\n}\n\nfunc TestStrArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.StrArray\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[\"1\",\"2\",\"3\"]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.SliceStr{\"1\", \"2\", \"3\"})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.SliceStr{\"1\", \"2\", \"3\"},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.SliceStr{\"1\", \"2\", \"3\"})\n\t})\n}\nfunc TestStrArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"\", \"1\", \"2\", \"0\"})\n\t\tt.Assert(array.Filter(func(index int, value string) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceStr{\"1\", \"2\", \"0\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.Filter(func(index int, value string) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceStr{\"1\", \"2\"})\n\t})\n}\n\nfunc TestStrArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"\", \"1\", \"2\", \"0\"})\n\t\tt.Assert(array.FilterEmpty(), g.SliceStr{\"1\", \"2\", \"0\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.FilterEmpty(), g.SliceStr{\"1\", \"2\"})\n\t})\n}\n\nfunc TestStrArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.Walk(func(value string) string {\n\t\t\treturn \"key-\" + value\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_normal_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_TArray_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{0, 1, 2, 3}\n\t\tarray := garray.NewTArrayFrom(expect)\n\t\tarray2 := garray.NewTArrayFrom(expect)\n\t\tarray3 := garray.NewTArrayFrom([]int{})\n\n\t\tt.Assert(array.Slice(), expect)\n\t\tt.Assert(array.Interfaces(), expect)\n\t\terr := array.Set(0, 100) // 100, 1, 2, 3\n\t\tt.AssertNil(err)\n\n\t\terr = array.Set(100, 100)\n\t\tt.AssertNE(err, nil)\n\n\t\tt.Assert(array.IsEmpty(), false)\n\n\t\tcopyArray := array.DeepCopy()\n\t\tca := copyArray.(*garray.TArray[int])\n\t\tca.Set(0, 1)\n\t\tcval, _ := ca.Get(0)\n\t\tval, _ := array.Get(0)\n\t\tt.AssertNE(cval, val)\n\n\t\tv, ok := array.Get(0)\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Get(1)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.Get(4)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tt.Assert(array.Search(100), 0)\n\t\tt.Assert(array3.Search(100), -1)\n\t\tt.Assert(array.Contains(100), true)\n\n\t\tv, ok = array.Remove(0) // 1, 2, 3\n\t\tt.Assert(v, 100)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Slice(), []int{1, 2, 3})\n\n\t\tv, ok = array.Remove(-1)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.Slice(), []int{1, 2, 3})\n\n\t\tv, ok = array.Remove(100000)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.Slice(), []int{1, 2, 3})\n\n\t\tv, ok = array2.Remove(3) // 0 1 2\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array2.Remove(1) // 0 2\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array.Contains(100), false)\n\t\tarray.Append(4) // 2, 2, 3, 4\n\t\tt.Assert(array.Slice(), []int{2, 2, 3, 4})\n\t\tt.Assert(array.Len(), 4)\n\t\tarray.InsertBefore(0, 100) // 100, 2, 2, 3, 4\n\t\tt.Assert(array.Slice(), []int{100, 2, 2, 3, 4})\n\t\tarray.InsertAfter(0, 200) // 100, 200, 2, 2, 3, 4\n\t\tt.Assert(array.Slice(), []int{100, 200, 2, 2, 3, 4})\n\t\tarray.InsertBefore(5, 300)\n\t\tarray.InsertAfter(6, 400)\n\t\tt.Assert(array.Slice(), []int{100, 200, 2, 2, 3, 300, 4, 400})\n\t\tt.Assert(array.Clear().Len(), 0)\n\t\terr = array.InsertBefore(99, 9900)\n\t\tt.AssertNE(err, nil)\n\t\terr = array.InsertAfter(99, 9900)\n\t\tt.AssertNE(err, nil)\n\n\t\tt.Assert(array.String(), \"[]\")\n\t})\n}\n\nfunc TestTArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect1 := []any{0, 1, 2, 3}\n\t\texpect2 := []any{3, 2, 1, 0}\n\t\tarray := garray.NewTArray[int]()\n\t\tfor i := 3; i >= 0; i-- {\n\t\t\tarray.Append(i)\n\t\t}\n\t\tarray.SortFunc(func(v1, v2 int) bool {\n\t\t\treturn v1 < v2\n\t\t})\n\t\tt.Assert(array.Slice(), expect1)\n\t\tarray.SortFunc(func(v1, v2 int) bool {\n\t\t\treturn v1 > v2\n\t\t})\n\t\tt.Assert(array.Slice(), expect2)\n\t})\n}\n\nfunc TestTArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray := garray.NewTArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []int{1, 2, 3, 4, 5})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []int{}\n\t\tarray := garray.NewTArrayFrom(expect)\n\t\tt.Assert(array.Unique().Slice(), []int{})\n\t})\n}\n\nfunc TestTArray_PushAndPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := []any{0, 1, 2, 3}\n\t\tarray := garray.NewTArrayFrom(expect)\n\t\tt.Assert(array.Slice(), expect)\n\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []any{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array.PopRand()\n\t\tt.AssertIN(v, []any{1, 2})\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tarray.PushLeft(1).PushRight(2)\n\t\tt.Assert(array.Slice(), []any{1, 2})\n\t})\n}\n\nfunc TestTArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{100, 200, 300, 400, 500, 600}\n\t\tarray := garray.NewFromCopy(a1)\n\t\tt.AssertIN(array.PopRands(2), []any{100, 200, 300, 400, 500, 600})\n\t})\n}\n\nfunc TestTArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestTArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestTArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tt.Assert(array.PopLefts(2), g.Slice{1, 2})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{3})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestTArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewFrom(g.Slice{1, 2, 3})\n\t\tt.Assert(array.PopRights(2), g.Slice{2, 3})\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.PopLefts(2), g.Slice{1})\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestTArray_PopLeftsAndPopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New()\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tvalue2 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(value1)\n\t\tarray2 := garray.NewTArrayFrom(value2)\n\t\tt.Assert(array1.PopLefts(2), []any{0, 1})\n\t\tt.Assert(array1.Slice(), []any{2, 3, 4, 5, 6})\n\t\tt.Assert(array1.PopRights(2), []any{5, 6})\n\t\tt.Assert(array1.Slice(), []any{2, 3, 4})\n\t\tt.Assert(array1.PopRights(20), []any{2, 3, 4})\n\t\tt.Assert(array1.Slice(), []any{})\n\t\tt.Assert(array2.PopLefts(20), []any{0, 1, 2, 3, 4, 5, 6})\n\t\tt.Assert(array2.Slice(), []any{})\n\t})\n}\n\nfunc TestTArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(value1)\n\t\tarray2 := garray.NewTArrayFrom(value1, true)\n\t\tt.Assert(array1.Range(0, 1), []any{0})\n\t\tt.Assert(array1.Range(1, 2), []any{1})\n\t\tt.Assert(array1.Range(0, 2), []any{0, 1})\n\t\tt.Assert(array1.Range(-1, 10), value1)\n\t\tt.Assert(array1.Range(10, 2), nil)\n\t\tt.Assert(array2.Range(1, 3), []any{1, 2})\n\t})\n}\n\nfunc TestTArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\ti1 := []any{0, 1, 2, 3}\n\t\ti2 := []any{4, 5, 6, 7}\n\t\tarray1 := garray.NewTArrayFrom(i1)\n\t\tarray2 := garray.NewTArrayFrom(i2)\n\t\tt.Assert(array1.Merge(array2).Slice(), []any{0, 1, 2, 3, 4, 5, 6, 7})\n\n\t\t// s1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti3 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti4 := garray.NewTArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\t\ta1 := garray.NewTArrayFrom(i1)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i3).Len(), 9)\n\t\tt.Assert(a1.Merge(i4).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestTArray_Fill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0}\n\t\ta2 := []any{0}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := garray.NewTArrayFrom(a2, true)\n\n\t\tt.Assert(array1.Fill(1, 2, 100), nil)\n\t\tt.Assert(array1.Slice(), []any{0, 100, 100})\n\n\t\tt.Assert(array2.Fill(0, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []any{100, 100})\n\n\t\tt.AssertNE(array2.Fill(-1, 2, 100), nil)\n\t\tt.Assert(array2.Slice(), []any{100, 100})\n\t})\n}\n\nfunc TestTArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []any{1, 2})\n\t\tt.Assert(chunks[1], []any{3, 4})\n\t\tt.Assert(chunks[2], []any{5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []any{1, 2})\n\t\tt.Assert(chunks[1], []any{3, 4})\n\t\tt.Assert(chunks[2], []any{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestTArray_Pad(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []any{0, 1, 1})\n\t\tt.Assert(array1.Pad(-4, 1).Slice(), []any{1, 0, 1, 1})\n\t\tt.Assert(array1.Pad(3, 1).Slice(), []any{1, 0, 1, 1})\n\t})\n}\n\nfunc TestTArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := garray.NewTArrayFrom(a1, true)\n\t\tt.Assert(array1.SubSlice(0, 2), []any{0, 1})\n\t\tt.Assert(array1.SubSlice(2, 2), []any{2, 3})\n\t\tt.Assert(array1.SubSlice(5, 8), []any{5, 6})\n\t\tt.Assert(array1.SubSlice(9, 1), nil)\n\t\tt.Assert(array1.SubSlice(-2, 2), []any{5, 6})\n\t\tt.Assert(array1.SubSlice(-9, 2), nil)\n\t\tt.Assert(array1.SubSlice(1, -2), nil)\n\t\tt.Assert(array2.SubSlice(0, 2), []any{0, 1})\n\t})\n}\n\nfunc TestTArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(len(array1.Rands(2)), 2)\n\t\tt.Assert(len(array1.Rands(10)), 10)\n\t\tt.AssertIN(array1.Rands(1)[0], a1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewTArrayFrom(s1)\n\t\ti1, ok := a1.Rand()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(a1.Contains(i1), true)\n\t\tt.Assert(a1.Len(), 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\trand, found := array1.Rand()\n\t\tt.AssertNil(rand)\n\t\tt.Assert(found, false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\trand := array1.Rands(1)\n\t\tt.AssertNil(rand)\n\t})\n}\n\nfunc TestTArray_Shuffle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.Shuffle().Len(), 7)\n\t})\n}\n\nfunc TestTArray_Reverse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.Reverse().Slice(), []any{6, 5, 4, 3, 2, 1, 0})\n\t})\n}\n\nfunc TestTArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.2.3.4.5.6`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, `\"a\"`, `\\a`}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `0.1.\"a\".\\a`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(len(array1.Join(\".\")), 0)\n\t})\n}\n\nfunc TestTArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tt.Assert(array1.String(), `[0,1,2,3,4,5,6]`)\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestTArray_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\t\ta3 := []any{\"m\", \"n\", \"p\", \"z\", \"x\", \"y\", \"d\", \"u\"}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := array1.Replace(a2)\n\t\tt.Assert(array2.Len(), 7)\n\t\tt.Assert(array2.Contains(\"b\"), true)\n\t\tt.Assert(array2.Contains(4), true)\n\t\tt.Assert(array2.Contains(\"v\"), false)\n\t\tarray3 := array1.Replace(a3)\n\t\tt.Assert(array3.Len(), 7)\n\t\tt.Assert(array3.Contains(4), false)\n\t\tt.Assert(array3.Contains(\"p\"), true)\n\t\tt.Assert(array3.Contains(\"u\"), false)\n\t})\n}\n\nfunc TestTArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3, 4, 5, 6}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray1 = array1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"b\"), true)\n\t\tt.Assert(array1.Contains(\"5\"), false)\n\t})\n}\n\nfunc TestTArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3}\n\t\ta2 := []any{\"a\", \"b\", \"c\"}\n\t\ta3 := []any{\"a\", \"1\", \"2\"}\n\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := garray.NewTArrayFrom(a2)\n\t\tarray3 := garray.NewTArrayFrom(a3)\n\n\t\tt.Assert(array1.Sum(), 6)\n\t\tt.Assert(array2.Sum(), 0)\n\t\tt.Assert(array3.Sum(), 3)\n\n\t})\n}\n\nfunc TestTArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, 2, 3}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array2.Sum(), 6)\n\t\tt.AssertEQ(array1, array2)\n\n\t})\n}\n\nfunc TestTArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"b\", \"c\", \"d\", \"e\", \"d\"}\n\t\tarray1 := garray.NewTArrayFrom(a1)\n\t\tarray2 := array1.CountValues()\n\t\tt.Assert(len(array2), 5)\n\t\tt.Assert(array2[\"b\"], 1)\n\t\tt.Assert(array2[\"d\"], 2)\n\t})\n}\n\nfunc TestTArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewTArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []any) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestTArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewTArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []any) { // read lock\n\t\t\ttime.Sleep(2 * time.Second) // sleep 2 s\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // wait go1 do line lock for 0.01s. Then do.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // wait for go1 done.\n\n\t\t//  Prevent CI jitter, in milliseconds.\n\t\tt.AssertLT(t2-t1, 20) // Go1 acquired a read lock, so when Go2 reads, it is not blocked.\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestTArray_Json(t *testing.T) {\n\t// pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := garray.NewTArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.New()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.Array\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// value.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := *garray.NewTArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.New()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Slice(), s1)\n\n\t\tvar a3 garray.Array\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.Array\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n\t// value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.Array\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, data[\"Scores\"])\n\t})\n}\n\nfunc TestTArray_Iterator(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewTArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestTArray_RemoveValue(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewTArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestTArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewTArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.Slice{\"d\"})\n\t})\n}\n\nfunc TestTArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.Array\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[1,2,3]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.Slice{1, 2, 3},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n}\n\nfunc TestTArray_FilterNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}\n\t\tarray := garray.NewTArrayFromCopy(values)\n\t\tt.Assert(array.FilterNil().Slice(), values)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})\n\t\tt.Assert(array.FilterNil(), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestTArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}\n\t\tarray := garray.NewTArrayFromCopy(values)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}).Slice(), values)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFrom(g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}})\n\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFrom(g.Slice{1, 2, 3, 4})\n\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestTArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFrom(g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}})\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFrom(g.Slice{1, 2, 3, 4})\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestTArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewTArrayFrom(g.Slice{\"1\", \"2\"})\n\t\tt.Assert(array.Walk(func(value any) any {\n\t\t\treturn \"key-\" + gconv.String(value)\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_sorted_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc TestSortedArray_NewSortedArrayFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\t\ta2 := []any{\"h\", \"j\", \"i\", \"k\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tfunc2 := func(v1, v2 any) int {\n\t\t\treturn -1\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray2 := garray.NewSortedArrayFrom(a2, func2)\n\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"a\", \"c\", \"f\"})\n\n\t\tt.Assert(array2.Len(), 4)\n\t\tt.Assert(array2, []any{\"k\", \"i\", \"j\", \"h\"})\n\t})\n}\n\nfunc TestNewSortedArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tfunc2 := func(v1, v2 any) int {\n\t\t\treturn -1\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFromCopy(a1, func1)\n\t\tarray2 := garray.NewSortedArrayFromCopy(a1, func2)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"a\", \"c\", \"f\"})\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array2, []any{\"c\", \"f\", \"a\"})\n\t})\n}\n\nfunc TestNewSortedArrayRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn gconv.Int(v1) - gconv.Int(v2)\n\t\t}\n\n\t\tarray1 := garray.NewSortedArrayRange(1, 5, 1, func1)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []any{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestSortedArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\t\ta2 := []any{\"e\", \"h\", \"g\", \"k\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1, []any{\"e\", \"g\", \"h\", \"k\"})\n\t})\n\n}\n\nfunc TestSortedArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray1.Sort()\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"a\", \"c\", \"f\"})\n\t})\n\n}\n\nfunc TestSortedArray_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tv, ok := array1.Get(2)\n\t\tt.Assert(v, \"f\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(1)\n\t\tt.Assert(v, \"c\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(99)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t})\n\n}\n\nfunc TestSortedArray_At(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"f\", \"c\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tv := array1.At(2)\n\t\tt.Assert(v, \"f\")\n\t})\n}\n\nfunc TestSortedArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1, ok := array1.Remove(1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"b\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"b\"), false)\n\n\t\tv, ok := array1.Remove(-1)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(100000)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\ti2, ok := array1.Remove(0)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i2), \"a\")\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(array1.Contains(\"a\"), false)\n\n\t\ti3, ok := array1.Remove(1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i3), \"d\")\n\t\tt.Assert(array1.Len(), 1)\n\t\tt.Assert(array1.Contains(\"d\"), false)\n\t})\n\n}\n\nfunc TestSortedArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedArrayFrom(\n\t\t\t[]any{\"a\", \"d\", \"c\", \"b\"},\n\t\t\tgutil.ComparatorString,\n\t\t)\n\t\ti1, ok := array1.PopLeft()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"a\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"b\", \"c\", \"d\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{1, 2, 3}, gutil.ComparatorInt)\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedArrayFrom(\n\t\t\t[]any{\"a\", \"d\", \"c\", \"b\"},\n\t\t\tgutil.ComparatorString,\n\t\t)\n\t\ti1, ok := array1.PopRight()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"d\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"a\", \"b\", \"c\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{1, 2, 3}, gutil.ComparatorInt)\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedArray_PopRand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1, ok := array1.PopRand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 3)\n\n\t})\n}\n\nfunc TestSortedArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1 := array1.PopRands(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 2)\n\n\t\ti2 := array1.PopRands(3)\n\t\tt.Assert(len(i1), 2)\n\t\tt.AssertIN(i2, []any{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 0)\n\n\t})\n}\n\nfunc TestSortedArray_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArray(gutil.ComparatorInt)\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n}\n\nfunc TestSortedArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1 := array1.PopLefts(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 4)\n\n\t\ti2 := array1.PopLefts(5)\n\t\tt.Assert(len(i2), 4)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1 := array1.PopRights(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.Assert(i1, []any{\"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 4)\n\n\t\ti2 := array1.PopRights(10)\n\t\tt.Assert(len(i2), 4)\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray2 := garray.NewSortedArrayFrom(a1, func1, true)\n\t\ti1 := array1.Range(2, 5)\n\t\tt.Assert(i1, []any{\"c\", \"d\", \"e\"})\n\t\tt.Assert(array1.Len(), 6)\n\n\t\ti2 := array1.Range(7, 5)\n\t\tt.Assert(len(i2), 0)\n\t\ti2 = array1.Range(-1, 2)\n\t\tt.Assert(i2, []any{\"a\", \"b\"})\n\n\t\ti2 = array1.Range(4, 10)\n\t\tt.Assert(len(i2), 2)\n\t\tt.Assert(i2, []any{\"e\", \"f\"})\n\n\t\tt.Assert(array2.Range(1, 3), []any{\"b\", \"c\"})\n\n\t})\n}\n\nfunc TestSortedArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\ta2 := []any{\"1\", \"2\", \"3\", \"b\", \"e\", \"f\"}\n\t\ta3 := []any{\"4\", \"5\", \"6\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray2 := garray.NewSortedArrayFrom(a2, func1)\n\t\tarray3 := garray.NewSortedArrayFrom(a3, func1)\n\t\tt.Assert(array1.Sum(), 0)\n\t\tt.Assert(array2.Sum(), 6)\n\t\tt.Assert(array3.Sum(), 15)\n\n\t})\n}\n\nfunc TestSortedArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array1, array2)\n\t\tarray1.Remove(1)\n\t\tt.AssertNE(array1, array2)\n\n\t})\n}\n\nfunc TestSortedArray_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tt.Assert(array1.Len(), 6)\n\t\tarray1.Clear()\n\t\tt.Assert(array1.Len(), 0)\n\n\t})\n}\n\nfunc TestSortedArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1 := array1.Chunk(2)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1[0], []any{\"a\", \"b\"})\n\t\tt.Assert(i1[2], []any{\"e\"})\n\n\t\ti1 = array1.Chunk(0)\n\t\tt.Assert(len(i1), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorInt)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorInt)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []any{1, 2})\n\t\tt.Assert(chunks[1], []any{3, 4})\n\t\tt.Assert(chunks[2], []any{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorInt)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []any{1, 2, 3})\n\t\tt.Assert(chunks[1], []any{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestSortedArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"b\", \"e\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tarray2 := garray.NewSortedArrayFrom(a1, func1, true)\n\t\ti1 := array1.SubSlice(2, 3)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1, []any{\"c\", \"d\", \"e\"})\n\n\t\ti1 = array1.SubSlice(2, 6)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1, []any{\"c\", \"d\", \"e\"})\n\n\t\ti1 = array1.SubSlice(7, 2)\n\t\tt.Assert(len(i1), 0)\n\n\t\ts1 := array1.SubSlice(1, -2)\n\t\tt.Assert(s1, nil)\n\n\t\ts1 = array1.SubSlice(-9, 2)\n\t\tt.Assert(s1, nil)\n\t\tt.Assert(array2.SubSlice(1, 3), []any{\"b\", \"c\", \"d\"})\n\n\t})\n}\n\nfunc TestSortedArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1, ok := array1.Rand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\"})\n\t\tt.Assert(array1.Len(), 3)\n\n\t\tarray2 := garray.NewSortedArrayFrom([]any{}, func1)\n\t\tv, ok := array2.Rand()\n\t\tt.Assert(ok, false)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestSortedArray_Rands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\ti1 := array1.Rands(2)\n\t\tt.AssertIN(i1, []any{\"a\", \"d\", \"c\"})\n\t\tt.Assert(len(i1), 2)\n\t\tt.Assert(array1.Len(), 3)\n\n\t\ti1 = array1.Rands(4)\n\t\tt.Assert(len(i1), 4)\n\n\t\tarray2 := garray.NewSortedArrayFrom([]any{}, func1)\n\t\tv := array2.Rands(1)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestSortedArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\"}\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tt.Assert(array1.Join(\",\"), `a,c,d`)\n\t\tt.Assert(array1.Join(\".\"), `a.c.d`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, `\"a\"`, `\\a`}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)\n\t\tt.Assert(array1.Join(\".\"), `\"a\".0.1.\\a`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)\n\t\tt.Assert(array1.Join(\".\"), \"\")\n\t})\n}\n\nfunc TestSortedArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{0, 1, \"a\", \"b\"}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)\n\t\tt.Assert(array1.String(), `[0,1,\"a\",\"b\"]`)\n\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestSortedArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{\"a\", \"d\", \"c\", \"c\"}\n\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, func1)\n\t\tm1 := array1.CountValues()\n\t\tt.Assert(len(m1), 3)\n\t\tt.Assert(m1[\"c\"], 2)\n\t\tt.Assert(m1[\"a\"], 1)\n\n\t})\n}\n\nfunc TestSortedArray_SetUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorInt)\n\t\tarray1.SetUnique(true)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []any{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestSortedArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []any{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorInt)\n\t\tarray1.Unique()\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []any{1, 2, 3, 4, 5})\n\n\t\tarray2 := garray.NewSortedArrayFrom([]any{}, gutil.ComparatorInt)\n\t\tarray2.Unique()\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.Assert(array2, []any{})\n\t})\n}\n\nfunc TestSortedArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedArrayFrom(s1, func1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []any) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedArrayFrom(s1, func1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []any) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候不会被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\ts1 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti1 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti2 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\n\t\ta1 := garray.NewSortedArrayFrom(s1, func1)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i1).Len(), 9)\n\t\tt.Assert(a1.Merge(i2).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestSortedArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedArrayFrom(s1, gutil.ComparatorString)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedArray(gutil.ComparatorString)\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []any{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := *garray.NewSortedArrayFrom(s1, gutil.ComparatorString)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedArray(gutil.ComparatorString)\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.SortedArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.AssertNE(user.Scores, nil)\n\t\tt.Assert(user.Scores.Len(), 3)\n\n\t\tv, ok := user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.SortedArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.AssertNE(user.Scores, nil)\n\t\tt.Assert(user.Scores.Len(), 3)\n\n\t\tv, ok := user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedArray_Iterator(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v any) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestSortedArray_RemoveValue(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestSortedArray_RemoveValues(t *testing.T) {\n\tslice := g.Slice{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.SliceStr{\"d\"})\n\t})\n}\n\nfunc TestSortedArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.SortedArray\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[2,3,1]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.Slice{2, 3, 1},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n}\nfunc TestSortedArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}\n\t\tarray := garray.NewSortedArrayFromCopy(values, gutil.ComparatorInt)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}).Slice(), g.Slice{0, \"\", g.Slice{}, 1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil}, gutil.ComparatorInt)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsNil(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{0, 1, 2, 3, 4, \"\", g.Slice{}}, gutil.ComparatorInt)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{1, 2, 3, 4}, gutil.ComparatorInt)\n\t\tt.Assert(array.Filter(func(index int, value any) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedArray_FilterNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, \"\", nil, g.Slice{}}\n\t\tarray := garray.NewSortedArrayFromCopy(values, gutil.ComparatorInt)\n\t\tt.Assert(array.FilterNil().Slice(), g.Slice{0, \"\", g.Slice{}, 1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFromCopy(g.Slice{nil, 1, 2, nil, 3, 4, nil}, gutil.ComparatorInt)\n\t\tt.Assert(array.FilterNil(), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{0, 1, 2, 0, -1, 3, 4, \"\", g.Slice{}}, gutil.ComparatorInt)\n\t\tt.Assert(array.FilterEmpty(), g.Slice{-1, 1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{1, 2, 3, 4}, gutil.ComparatorInt)\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, -1, -2, nil, []any{}, \"\"}\n\t\tarray := garray.NewSortedArrayFrom(values, gutil.ComparatorString)\n\t\tt.Assert(array.FilterEmpty().Slice(), g.Slice{-1, -2, 1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom(g.Slice{\"1\", \"2\"}, gutil.ComparatorString)\n\t\tt.Assert(array.Walk(func(value any) any {\n\t\t\treturn \"key-\" + gconv.String(value)\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n\nfunc TestSortedArray_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom([]any{}, gutil.ComparatorString)\n\t\tt.Assert(array.IsEmpty(), true)\n\t})\n}\n\nfunc TestSortedArray_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedArrayFrom([]any{1, 2, 3, 4, 5}, gutil.ComparatorString)\n\t\tcopyArray := array.DeepCopy().(*garray.SortedArray)\n\t\tarray.Add(6)\n\t\tcopyArray.Add(7)\n\t\tcval, _ := copyArray.Get(5)\n\t\tval, _ := array.Get(5)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_sorted_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestNewSortedIntArrayComparator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 3, 2, 1, 4, 5, 6}\n\t\tarray1 := garray.NewSortedIntArrayComparator(func(a, b int) int {\n\t\t\treturn a - b\n\t\t}, true)\n\t\tarray1.Append(a1...)\n\t\tt.Assert(array1.Len(), 7)\n\t\tt.Assert(array1.Interfaces(), []int{0, 1, 2, 3, 4, 5, 6})\n\t})\n}\n\nfunc TestNewSortedIntArrayRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedIntArrayRange(1, 5, 1)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1.Interfaces(), []int{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestNewSortedIntArrayFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 3, 2, 1, 4, 5, 6}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1, true)\n\t\tt.Assert(array1.Join(\".\"), \"0.1.2.3.4.5.6\")\n\t\tt.Assert(array1.Slice(), a1)\n\t\tt.Assert(array1.Interfaces(), a1)\n\t})\n}\n\nfunc TestNewSortedIntArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 5, 2, 1, 4, 3, 6}\n\t\tarray1 := garray.NewSortedIntArrayFromCopy(a1, false)\n\t\tt.Assert(array1.Join(\".\"), \"0.1.2.3.4.5.6\")\n\t})\n}\n\nfunc TestSortedIntArray_At(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 3, 2, 1}\n\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tv := array1.At(1)\n\n\t\tt.Assert(v, 1)\n\t})\n}\n\nfunc TestSortedIntArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 1, 2, 3}\n\t\ta2 := []int{4, 5, 6}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray2 := array1.SetArray(a2)\n\n\t\tt.Assert(array2.Len(), 3)\n\t\tt.Assert(array2.Search(3), -1)\n\t\tt.Assert(array2.Search(5), 1)\n\t\tt.Assert(array2.Search(6), 2)\n\t})\n}\n\nfunc TestSortedIntArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{0, 3, 2, 1}\n\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray2 := array1.Sort()\n\n\t\tt.Assert(array2.Len(), 4)\n\t\tt.Assert(array2, []int{0, 1, 2, 3})\n\t})\n}\n\nfunc TestSortedIntArray_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 0}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tv, ok := array1.Get(0)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(1)\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(3)\n\t\tt.Assert(v, 5)\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(99)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedIntArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 0}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\n\t\tv, ok := array1.Remove(-1)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(-100000)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(2)\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array1.Search(5), 2)\n\n\t\tv, ok = array1.Remove(0)\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array1.Search(5), 1)\n\n\t\ta2 := []int{1, 3, 4}\n\t\tarray2 := garray.NewSortedIntArrayFrom(a2)\n\n\t\tv, ok = array2.Remove(1)\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array2.Search(1), 0)\n\n\t\tv, ok = array2.Remove(1)\n\t\tt.Assert(v, 4)\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array2.Search(4), -1)\n\t})\n}\n\nfunc TestSortedIntArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tv, ok := array1.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Search(1), -1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedIntArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tv, ok := array1.PopRight()\n\t\tt.Assert(v, 5)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Search(5), -1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3})\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedIntArray_PopRand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\ti1, ok := array1.PopRand()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Search(i1), -1)\n\t\tt.AssertIN(i1, []int{1, 3, 5, 2})\n\t})\n}\n\nfunc TestSortedIntArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.PopRands(2)\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.AssertIN(ns1, []int{1, 3, 5, 2})\n\n\t\ta2 := []int{1, 3, 5, 2}\n\t\tarray2 := garray.NewSortedIntArrayFrom(a2)\n\t\tns2 := array2.PopRands(5)\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.Assert(len(ns2), 4)\n\t\tt.AssertIN(ns2, []int{1, 3, 5, 2})\n\t})\n}\n\nfunc TestSortedIntArray_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArray()\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n}\n\nfunc TestSortedIntArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.PopLefts(2)\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(ns1, []int{1, 2})\n\n\t\ta2 := []int{1, 3, 5, 2}\n\t\tarray2 := garray.NewSortedIntArrayFrom(a2)\n\t\tns2 := array2.PopLefts(5)\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.AssertIN(ns2, []int{1, 3, 5, 2})\n\t})\n}\n\nfunc TestSortedIntArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.PopRights(2)\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(ns1, []int{3, 5})\n\n\t\ta2 := []int{1, 3, 5, 2}\n\t\tarray2 := garray.NewSortedIntArrayFrom(a2)\n\t\tns2 := array2.PopRights(5)\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.AssertIN(ns2, []int{1, 3, 5, 2})\n\t})\n}\n\nfunc TestSortedIntArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5, 2, 6, 7}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray2 := garray.NewSortedIntArrayFrom(a1, true)\n\t\tns1 := array1.Range(1, 4)\n\t\tt.Assert(len(ns1), 3)\n\t\tt.Assert(ns1, []int{2, 3, 5})\n\n\t\tns2 := array1.Range(5, 4)\n\t\tt.Assert(len(ns2), 0)\n\n\t\tns3 := array1.Range(-1, 4)\n\t\tt.Assert(len(ns3), 4)\n\n\t\tnsl := array1.Range(5, 8)\n\t\tt.Assert(len(nsl), 1)\n\t\tt.Assert(array2.Range(1, 2), []int{2})\n\t})\n}\n\nfunc TestSortedIntArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tn1 := array1.Sum()\n\t\tt.Assert(n1, 9)\n\t})\n}\n\nfunc TestSortedIntArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `1.3.5`)\n\n\t\tarray2 := garray.NewSortedIntArrayFrom([]int{})\n\t\tt.Assert(array2.Join(\".\"), \"\")\n\t})\n}\n\nfunc TestSortedIntArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tt.Assert(array1.String(), `[1,3,5]`)\n\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestSortedIntArray_Contains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tt.Assert(array1.Contains(4), false)\n\t})\n}\n\nfunc TestSortedIntArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array2.Len(), 3)\n\t\tt.Assert(array2, array1)\n\t})\n}\n\nfunc TestSortedIntArray_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 3, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray1.Clear()\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedIntArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.Chunk(2) // 按每几个元素切成一个数组\n\t\tns2 := array1.Chunk(-1)\n\t\tt.Assert(len(ns1), 3)\n\t\tt.Assert(ns1[0], []int{1, 2})\n\t\tt.Assert(ns1[2], []int{5})\n\t\tt.Assert(len(ns2), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int{1, 2, 3})\n\t\tt.Assert(chunks[1], []int{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []int{1, 2})\n\t\tt.Assert(chunks[1], []int{3, 4})\n\t\tt.Assert(chunks[2], []int{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int{1, 2, 3})\n\t\tt.Assert(chunks[1], []int{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestSortedIntArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray2 := garray.NewSortedIntArrayFrom(a1, true)\n\t\tns1 := array1.SubSlice(1, 2)\n\t\tt.Assert(len(ns1), 2)\n\t\tt.Assert(ns1, []int{2, 3})\n\n\t\tns2 := array1.SubSlice(7, 2)\n\t\tt.Assert(len(ns2), 0)\n\n\t\tns3 := array1.SubSlice(3, 5)\n\t\tt.Assert(len(ns3), 2)\n\t\tt.Assert(ns3, []int{4, 5})\n\n\t\tns4 := array1.SubSlice(3, 1)\n\t\tt.Assert(len(ns4), 1)\n\t\tt.Assert(ns4, []int{4})\n\t\tt.Assert(array1.SubSlice(-1, 1), []int{5})\n\t\tt.Assert(array1.SubSlice(-9, 1), nil)\n\t\tt.Assert(array1.SubSlice(1, -9), nil)\n\t\tt.Assert(array2.SubSlice(1, 2), []int{2, 3})\n\t})\n}\n\nfunc TestSortedIntArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1, ok := array1.Rand()\n\t\tt.AssertIN(ns1, a1)\n\t\tt.Assert(ok, true)\n\n\t\tarray2 := garray.NewSortedIntArrayFrom([]int{})\n\t\tns2, ok := array2.Rand()\n\t\tt.Assert(ns2, 0)\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedIntArray_Rands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.Rands(2)\n\t\tt.AssertIN(ns1, a1)\n\t\tt.Assert(len(ns1), 2)\n\n\t\tns2 := array1.Rands(6)\n\t\tt.Assert(len(ns2), 6)\n\n\t\tarray2 := garray.NewSortedIntArrayFrom([]int{})\n\t\tval := array2.Rands(1)\n\t\tt.Assert(val, nil)\n\t})\n}\n\nfunc TestSortedIntArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 3}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tns1 := array1.CountValues() // 按每几个元素切成一个数组\n\t\tt.Assert(len(ns1), 5)\n\t\tt.Assert(ns1[2], 1)\n\t\tt.Assert(ns1[3], 2)\n\t})\n}\n\nfunc TestSortedIntArray_SetUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray1.SetUnique(true)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []int{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestSortedIntArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedIntArrayFrom(a1)\n\t\tarray1.Unique()\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []int{1, 2, 3, 4, 5})\n\n\t\tarray2 := garray.NewSortedIntArrayFrom([]int{})\n\t\tarray2.Unique()\n\t\tt.Assert(array2.Len(), 0)\n\t})\n}\n\nfunc TestSortedIntArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 2, 3, 4}\n\t\ta1 := garray.NewSortedIntArrayFrom(s1, true)\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []int) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = 6\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(6), true)\n\t})\n}\n\nfunc TestSortedIntArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 2, 3, 4}\n\t\ta1 := garray.NewSortedIntArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []int) { // 读锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停1秒\n\t\t\tn1[2] = 6\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候，并没有阻塞。\n\t\tt.Assert(a1.Contains(6), true)\n\t})\n}\n\nfunc TestSortedIntArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\t\ti0 := []int{1, 2, 3, 4}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti1 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti2 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\t\ta1 := garray.NewSortedIntArrayFrom(i0)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i1).Len(), 9)\n\t\tt.Assert(a1.Merge(i2).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestSortedIntArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 4, 3, 2}\n\t\ts2 := []int{1, 2, 3, 4}\n\t\ta1 := garray.NewSortedIntArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedIntArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedIntArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 4, 3, 2}\n\t\ts2 := []int{1, 2, 3, 4}\n\t\ta1 := *garray.NewSortedIntArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedIntArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedIntArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.SortedIntArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, []int{98, 99, 100})\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.SortedIntArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, []int{98, 99, 100})\n\t})\n}\n\nfunc TestSortedIntArray_Iterator(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewSortedIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v int) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v int) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestSortedIntArray_RemoveValue(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewSortedIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(99), false)\n\t\tt.Assert(array.RemoveValue(20), true)\n\t\tt.Assert(array.RemoveValue(10), true)\n\t\tt.Assert(array.RemoveValue(20), false)\n\t\tt.Assert(array.RemoveValue(88), false)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestSortedIntArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceInt{10, 20, 30, 40}\n\tarray := garray.NewSortedIntArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(10, 40, 20)\n\t\tt.Assert(array.Slice(), g.SliceInt{30})\n\t})\n}\n\nfunc TestSortedIntArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.SortedIntArray\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[2,3,1]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.Slice{2, 3, 1},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n}\nfunc TestSortedIntArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceInt{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceInt{1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedIntArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{0, 1, -1, 2, 3, 4, 0})\n\t\tt.Assert(array.FilterEmpty(), g.SliceInt{-1, 1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{0, 0, 0, 0, 0, 0, 1})\n\t\tarray.SetComparator(func(a, b int) int {\n\t\t\tif a == b {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif a < b {\n\t\t\t\treturn 1\n\t\t\t} else {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t})\n\t\tt.Assert(array.FilterEmpty(), g.SliceInt{1})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3, 4})\n\t\tt.Assert(array.FilterEmpty(), g.SliceInt{1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedIntArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2})\n\t\tt.Assert(array.Walk(func(value int) int {\n\t\t\treturn 10 + value\n\t\t}), g.Slice{11, 12})\n\t})\n}\n\nfunc TestSortedIntArray_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom([]int{})\n\t\tt.Assert(array.IsEmpty(), true)\n\t})\n}\n\nfunc TestSortedIntArray_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedIntArrayFrom([]int{1, 2, 3, 4, 5})\n\t\tcopyArray := array.DeepCopy().(*garray.SortedIntArray)\n\t\tarray.Add(6)\n\t\tcopyArray.Add(7)\n\t\tcval, _ := copyArray.Get(5)\n\t\tval, _ := array.Get(5)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_sorted_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestNewSortedStrArrayComparator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\ts1 := garray.NewSortedStrArrayComparator(func(a, b string) int {\n\t\t\treturn gstr.Compare(a, b)\n\t\t})\n\t\ts1.Add(a1...)\n\t\tt.Assert(s1.Len(), 4)\n\t\tt.Assert(s1, []string{\"a\", \"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestNewSortedStrArrayFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\ts1 := garray.NewSortedStrArrayFrom(a1, true)\n\t\tt.Assert(s1, []string{\"a\", \"b\", \"c\", \"d\"})\n\t\ts2 := garray.NewSortedStrArrayFrom(a1, false)\n\t\tt.Assert(s2, []string{\"a\", \"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestNewSortedStrArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\ts1 := garray.NewSortedStrArrayFromCopy(a1, true)\n\t\tt.Assert(s1.Len(), 4)\n\t\tt.Assert(s1, []string{\"a\", \"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestSortedStrArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\ta2 := []string{\"f\", \"g\", \"h\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"d\"), false)\n\t\tt.Assert(array1.Contains(\"b\"), false)\n\t\tt.Assert(array1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedStrArray_ContainsI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := garray.NewSortedStrArray()\n\t\ts.Append(\"a\", \"b\", \"C\")\n\t\tt.Assert(s.Contains(\"A\"), false)\n\t\tt.Assert(s.Contains(\"a\"), true)\n\t\tt.Assert(s.ContainsI(\"A\"), true)\n\n\t\ts = garray.NewSortedStrArray()\n\t\tt.Assert(s.Contains(\"A\"), false)\n\t})\n}\n\nfunc TestSortedStrArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\n\t\tt.Assert(array1, []string{\"a\", \"b\", \"c\", \"d\"})\n\t\tarray1.Sort()\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1.Contains(\"c\"), true)\n\t\tt.Assert(array1, []string{\"a\", \"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestSortedStrArray_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tv, ok := array1.Get(2)\n\t\tt.Assert(v, \"c\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(0)\n\t\tt.Assert(v, \"a\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(99)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedStrArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\n\t\tv, ok := array1.Remove(-1)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(100000)\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(2)\n\t\tt.Assert(v, \"c\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(2)\n\t\tt.Assert(v, \"d\")\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"c\"), false)\n\n\t\tv, ok = array1.Remove(0)\n\t\tt.Assert(v, \"a\")\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(array1.Contains(\"a\"), false)\n\n\t\tv, ok = array1.Remove(1)\n\t\tt.Assert(v, \"d\")\n\t\tt.Assert(ok, true)\n\n\t\tt.Assert(array1.Len(), 1)\n\t})\n}\n\nfunc TestSortedStrArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tv, ok := array1.PopLeft()\n\t\tt.Assert(v, \"a\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1.Contains(\"a\"), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedStrArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tv, ok := array1.PopRight()\n\t\tt.Assert(v, \"e\")\n\t\tt.Assert(ok, ok)\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1.Contains(\"e\"), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedStrArray_PopRand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\ts1, ok := array1.PopRand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(s1, []string{\"e\", \"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1.Contains(s1), false)\n\t})\n}\n\nfunc TestSortedStrArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\ts1 := array1.PopRands(2)\n\t\tt.AssertIN(s1, []string{\"e\", \"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(len(s1), 2)\n\n\t\ts1 = array1.PopRands(4)\n\t\tt.Assert(len(s1), 3)\n\t\tt.AssertIN(s1, []string{\"e\", \"a\", \"d\", \"c\", \"b\"})\n\t})\n}\n\nfunc TestSortedStrArray_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArray()\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n}\n\nfunc TestSortedStrArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\ts1 := array1.PopLefts(2)\n\t\tt.Assert(s1, []string{\"a\", \"b\"})\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(len(s1), 2)\n\n\t\ts1 = array1.PopLefts(4)\n\t\tt.Assert(len(s1), 3)\n\t\tt.Assert(s1, []string{\"c\", \"d\", \"e\"})\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedStrArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\ts1 := array1.PopRights(2)\n\t\tt.Assert(s1, []string{\"f\", \"g\"})\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(len(s1), 2)\n\t\ts1 = array1.PopRights(6)\n\t\tt.Assert(len(s1), 5)\n\t\tt.Assert(s1, []string{\"a\", \"b\", \"c\", \"d\", \"e\"})\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedStrArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := garray.NewSortedStrArrayFrom(a1, true)\n\t\ts1 := array1.Range(2, 4)\n\t\tt.Assert(len(s1), 2)\n\t\tt.Assert(s1, []string{\"c\", \"d\"})\n\n\t\ts1 = array1.Range(-1, 2)\n\t\tt.Assert(len(s1), 2)\n\t\tt.Assert(s1, []string{\"a\", \"b\"})\n\n\t\ts1 = array1.Range(4, 8)\n\t\tt.Assert(len(s1), 3)\n\t\tt.Assert(s1, []string{\"e\", \"f\", \"g\"})\n\t\tt.Assert(array1.Range(10, 2), nil)\n\n\t\ts2 := array2.Range(2, 4)\n\t\tt.Assert(s2, []string{\"c\", \"d\"})\n\n\t})\n}\n\nfunc TestSortedStrArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\ta2 := []string{\"1\", \"2\", \"3\", \"4\", \"a\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := garray.NewSortedStrArrayFrom(a2)\n\t\tt.Assert(array1.Sum(), 0)\n\t\tt.Assert(array2.Sum(), 10)\n\t})\n}\n\nfunc TestSortedStrArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array1, array2)\n\t\tarray1.Remove(1)\n\t\tt.Assert(array2.Len(), 7)\n\t})\n}\n\nfunc TestSortedStrArray_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray1.Clear()\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedStrArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := garray.NewSortedStrArrayFrom(a1, true)\n\t\ts1 := array1.SubSlice(1, 3)\n\t\tt.Assert(len(s1), 3)\n\t\tt.Assert(s1, []string{\"b\", \"c\", \"d\"})\n\t\tt.Assert(array1.Len(), 7)\n\n\t\ts2 := array1.SubSlice(1, 10)\n\t\tt.Assert(len(s2), 6)\n\n\t\ts3 := array1.SubSlice(10, 2)\n\t\tt.Assert(len(s3), 0)\n\n\t\ts3 = array1.SubSlice(-5, 2)\n\t\tt.Assert(s3, []string{\"c\", \"d\"})\n\n\t\ts3 = array1.SubSlice(-10, 2)\n\t\tt.Assert(s3, nil)\n\n\t\ts3 = array1.SubSlice(1, -2)\n\t\tt.Assert(s3, nil)\n\n\t\tt.Assert(array2.SubSlice(1, 3), []string{\"b\", \"c\", \"d\"})\n\t})\n}\n\nfunc TestSortedStrArray_Len(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"c\", \"b\", \"f\", \"g\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tt.Assert(array1.Len(), 7)\n\n\t})\n}\n\nfunc TestSortedStrArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tv, ok := array1.Rand()\n\t\tt.AssertIN(v, []string{\"e\", \"a\", \"d\"})\n\t\tt.Assert(ok, true)\n\n\t\tarray2 := garray.NewSortedStrArrayFrom([]string{})\n\t\tv, ok = array2.Rand()\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedStrArray_Rands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\ts1 := array1.Rands(2)\n\n\t\tt.AssertIN(s1, []string{\"e\", \"a\", \"d\"})\n\t\tt.Assert(len(s1), 2)\n\n\t\ts1 = array1.Rands(4)\n\t\tt.Assert(len(s1), 4)\n\n\t\tarray2 := garray.NewSortedStrArrayFrom([]string{})\n\t\tval := array2.Rands(1)\n\t\tt.Assert(val, nil)\n\t})\n}\n\nfunc TestSortedStrArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tt.Assert(array1.Join(\",\"), `a,d,e`)\n\t\tt.Assert(array1.Join(\".\"), `a.d.e`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", `\"b\"`, `\\c`}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tt.Assert(array1.Join(\".\"), `\"b\".\\c.a`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedStrArrayFrom([]string{})\n\t\tt.Assert(array1.Join(\".\"), \"\")\n\t})\n}\n\nfunc TestSortedStrArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tt.Assert(array1.String(), `[\"a\",\"d\",\"e\"]`)\n\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestSortedStrArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"a\", \"c\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tm1 := array1.CountValues()\n\t\tt.Assert(m1[\"a\"], 2)\n\t\tt.Assert(m1[\"d\"], 1)\n\n\t})\n}\n\nfunc TestSortedStrArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"e\", \"a\", \"d\", \"a\", \"c\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := array1.Chunk(2)\n\t\tt.Assert(len(array2), 3)\n\t\tt.Assert(len(array2[0]), 2)\n\t\tt.Assert(array2[1], []string{\"c\", \"d\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\", \"3\"})\n\t\tt.Assert(chunks[1], []string{\"4\", \"5\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\"})\n\t\tt.Assert(chunks[1], []string{\"3\", \"4\"})\n\t\tt.Assert(chunks[2], []string{\"5\", \"6\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []string{\"1\", \"2\", \"3\"})\n\t\tt.Assert(chunks[1], []string{\"4\", \"5\", \"6\"})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestSortedStrArray_SetUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"1\", \"2\", \"2\", \"3\", \"3\", \"2\", \"2\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray2 := array1.SetUnique(true)\n\t\tt.Assert(array2.Len(), 3)\n\t\tt.Assert(array2, []string{\"1\", \"2\", \"3\"})\n\t})\n}\n\nfunc TestSortedStrArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"1\", \"1\", \"2\", \"2\", \"3\", \"3\", \"2\", \"2\"}\n\t\tarray1 := garray.NewSortedStrArrayFrom(a1)\n\t\tarray1.Unique()\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []string{\"1\", \"2\", \"3\"})\n\n\t\tarray2 := garray.NewSortedStrArrayFrom([]string{})\n\t\tarray2.Unique()\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.Assert(array2, []string{})\n\t})\n}\n\nfunc TestSortedStrArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedStrArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []string) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedStrArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedStrArrayFrom(s1, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 1)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []string) { // 读锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停1秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候，并没有阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedStrArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfunc1 := func(v1, v2 any) int {\n\t\t\tif gconv.Int(v1) < gconv.Int(v2) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t}\n\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti1 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti2 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedArrayFrom([]any{4, 5}, func1)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\t\ta1 := garray.NewSortedStrArrayFrom(s1)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i1).Len(), 9)\n\t\tt.Assert(a1.Merge(i2).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestSortedStrArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedStrArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedStrArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\t\tt.Assert(a2.Interfaces(), s2)\n\n\t\tvar a3 garray.SortedStrArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := *garray.NewSortedStrArrayFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedStrArray()\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\t\tt.Assert(a2.Interfaces(), s2)\n\n\t\tvar a3 garray.SortedStrArray\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.SortedStrArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []string{\"A+\", \"A\", \"A\"},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, []string{\"A\", \"A\", \"A+\"})\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores garray.SortedStrArray\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []string{\"A+\", \"A\", \"A\"},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.Assert(user.Scores, []string{\"A\", \"A\", \"A+\"})\n\t})\n}\n\nfunc TestSortedStrArray_Iterator(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestSortedStrArray_RemoveValue(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestSortedStrArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedStrArrayFrom(slice)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.SliceStr{\"d\"})\n\t})\n}\n\nfunc TestSortedStrArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.SortedStrArray\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[\"1\",\"3\",\"2\"]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.SliceStr{\"1\", \"2\", \"3\"})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.SliceStr{\"1\", \"3\", \"2\"},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.SliceStr{\"1\", \"2\", \"3\"})\n\t})\n}\nfunc TestSortedStrArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"\", \"1\", \"2\", \"0\"})\n\t\tt.Assert(array.Filter(func(index int, value string) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceStr{\"0\", \"1\", \"2\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.Filter(func(index int, value string) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.SliceStr{\"1\", \"2\"})\n\t})\n}\n\nfunc TestSortedStrArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"\", \"1\", \"\", \"2\", \"0\", \"\"})\n\t\tt.Assert(array.FilterEmpty(), g.SliceStr{\"0\", \"1\", \"2\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"\", \"\", \"\", \"2\", \"0\", \"a\", \"b\"})\n\t\tarray.SetComparator(func(a, b string) int {\n\t\t\tif a == b {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif a < b {\n\t\t\t\treturn 1\n\t\t\t} else {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t})\n\t\tt.Assert(array.FilterEmpty(), g.SliceStr{\"b\", \"a\", \"2\", \"0\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.FilterEmpty(), g.SliceStr{\"1\", \"2\"})\n\t})\n}\n\nfunc TestSortedStrArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom(g.SliceStr{\"1\", \"2\"})\n\t\tt.Assert(array.Walk(func(value string) string {\n\t\t\treturn \"key-\" + value\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n\nfunc TestSortedStrArray_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedStrArrayFrom([]string{\"a\", \"b\", \"c\", \"d\"})\n\t\tcopyArray := array.DeepCopy().(*garray.SortedStrArray)\n\t\tarray.Add(\"e\")\n\t\tcopyArray.Add(\"f\")\n\t\tcval, _ := copyArray.Get(4)\n\t\tval, _ := array.Get(4)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n"
  },
  {
    "path": "container/garray/garray_z_unit_sorted_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage garray_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc TestSortedTArray_NewSortedTArrayFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\t\ta2 := []string{\"h\", \"j\", \"i\", \"k\"}\n\t\tfunc1 := func(v1, v2 string) int {\n\t\t\treturn strings.Compare(v1, v2)\n\t\t}\n\t\tfunc2 := func(v1, v2 string) int {\n\t\t\treturn -1\n\t\t}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, func1)\n\t\tarray2 := garray.NewSortedTArrayFrom(a2, func2)\n\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []string{\"a\", \"c\", \"f\"})\n\n\t\tt.Assert(array2.Len(), 4)\n\t\tt.Assert(array2, []string{\"k\", \"i\", \"j\", \"h\"})\n\t})\n}\n\nfunc TestNewSortedTArrayFromCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\n\t\tfunc1 := func(v1, v2 string) int {\n\t\t\treturn strings.Compare(gconv.String(v1), gconv.String(v2))\n\t\t}\n\t\tfunc2 := func(v1, v2 string) int {\n\t\t\treturn -1\n\t\t}\n\t\tarray1 := garray.NewSortedTArrayFromCopy(a1, func1)\n\t\tarray2 := garray.NewSortedTArrayFromCopy(a1, func2)\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []string{\"a\", \"c\", \"f\"})\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array2, []string{\"c\", \"f\", \"a\"})\n\t})\n}\n\nfunc TestSortedTArray_SetArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\t\ta2 := []string{\"e\", \"h\", \"g\", \"k\"}\n\n\t\tfunc1 := func(v1, v2 string) int {\n\t\t\treturn strings.Compare(v1, v2)\n\t\t}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, func1)\n\t\tarray1.SetArray(a2)\n\t\tt.Assert(array1.Len(), 4)\n\t\tt.Assert(array1, []string{\"e\", \"g\", \"h\", \"k\"})\n\t})\n\n}\n\nfunc TestSortedTArray_Sort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\tarray1.Sort()\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []string{\"a\", \"c\", \"f\"})\n\t})\n\n}\n\nfunc TestSortedTArray_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\tv, ok := array1.Get(2)\n\t\tt.Assert(v, \"f\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(1)\n\t\tt.Assert(v, \"c\")\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = array1.Get(99)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\t})\n\n}\n\nfunc TestSortedTArray_At(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"f\", \"c\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\tv := array1.At(2)\n\t\tt.Assert(v, \"f\")\n\t})\n}\n\nfunc TestSortedTArray_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\ti1, ok := array1.Remove(1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"b\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1.Contains(\"b\"), false)\n\n\t\tv, ok := array1.Remove(-1)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\tv, ok = array1.Remove(100000)\n\t\tt.Assert(v, nil)\n\t\tt.Assert(ok, false)\n\n\t\ti2, ok := array1.Remove(0)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i2), \"a\")\n\t\tt.Assert(array1.Len(), 2)\n\t\tt.Assert(array1.Contains(\"a\"), false)\n\n\t\ti3, ok := array1.Remove(1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i3), \"d\")\n\t\tt.Assert(array1.Len(), 1)\n\t\tt.Assert(array1.Contains(\"d\"), false)\n\t})\n\n}\n\nfunc TestSortedTArray_PopLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedTArrayFrom(\n\t\t\t[]string{\"a\", \"d\", \"c\", \"b\"},\n\t\t\tgutil.ComparatorT,\n\t\t)\n\t\ti1, ok := array1.PopLeft()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"a\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"b\", \"c\", \"d\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{1, 2, 3}, gutil.ComparatorT)\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\t\tv, ok = array.PopLeft()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedTArray_PopRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray1 := garray.NewSortedTArrayFrom(\n\t\t\t[]string{\"a\", \"d\", \"c\", \"b\"},\n\t\t\tgutil.ComparatorT,\n\t\t)\n\t\ti1, ok := array1.PopRight()\n\t\tt.Assert(ok, true)\n\t\tt.Assert(gconv.String(i1), \"d\")\n\t\tt.Assert(array1.Len(), 3)\n\t\tt.Assert(array1, []any{\"a\", \"b\", \"c\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{1, 2, 3}, gutil.ComparatorT)\n\t\tv, ok := array.PopRight()\n\t\tt.Assert(v, 3)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 2)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 1)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestSortedTArray_PopRand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\ti1, ok := array1.PopRand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(i1, []string{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 3)\n\n\t})\n}\n\nfunc TestSortedTArray_PopRands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\ti1 := array1.PopRands(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.AssertIN(i1, []string{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 2)\n\n\t\ti2 := array1.PopRands(3)\n\t\tt.Assert(len(i2), 2)\n\t\tt.AssertIN(i2, []string{\"a\", \"d\", \"c\", \"b\"})\n\t\tt.Assert(array1.Len(), 0)\n\n\t})\n}\n\nfunc TestSortedTArray_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArray[int](gutil.ComparatorT)\n\t\tv, ok := array.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopLefts(10), nil)\n\n\t\tv, ok = array.PopRight()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRights(10), nil)\n\n\t\tv, ok = array.PopRand()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t\tt.Assert(array.PopRands(10), nil)\n\t})\n}\n\nfunc TestSortedTArray_PopLefts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\ti1 := array1.PopLefts(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.AssertIN(i1, []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 4)\n\n\t\ti2 := array1.PopLefts(5)\n\t\tt.Assert(len(i2), 4)\n\t\tt.AssertIN(i2, []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedTArray_PopRights(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\ti1 := array1.PopRights(2)\n\t\tt.Assert(len(i1), 2)\n\t\tt.Assert(i1, []string{\"e\", \"f\"})\n\t\tt.Assert(array1.Len(), 4)\n\n\t\ti2 := array1.PopRights(10)\n\t\tt.Assert(len(i2), 4)\n\t\tt.Assert(array1.Len(), 0)\n\t})\n}\n\nfunc TestSortedTArray_Range(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\tarray2 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT, true)\n\t\ti1 := array1.Range(2, 5)\n\t\tt.Assert(i1, []string{\"c\", \"d\", \"e\"})\n\t\tt.Assert(array1.Len(), 6)\n\n\t\ti2 := array1.Range(7, 5)\n\t\tt.Assert(len(i2), 0)\n\t\ti2 = array1.Range(-1, 2)\n\t\tt.Assert(i2, []string{\"a\", \"b\"})\n\n\t\ti2 = array1.Range(4, 10)\n\t\tt.Assert(len(i2), 2)\n\t\tt.Assert(i2, []string{\"e\", \"f\"})\n\n\t\tt.Assert(array2.Range(1, 3), []string{\"b\", \"c\"})\n\n\t})\n}\n\nfunc TestSortedTArray_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\t\ta2 := []string{\"1\", \"2\", \"3\", \"b\", \"e\", \"f\"}\n\t\ta3 := []string{\"4\", \"5\", \"6\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, gutil.ComparatorT)\n\t\tarray2 := garray.NewSortedTArrayFrom(a2, gutil.ComparatorT)\n\t\tarray3 := garray.NewSortedTArrayFrom(a3, gutil.ComparatorT)\n\t\tt.Assert(array1.Sum(), 0)\n\t\tt.Assert(array2.Sum(), 6)\n\t\tt.Assert(array3.Sum(), 15)\n\n\t})\n}\n\nfunc TestSortedTArray_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tarray2 := array1.Clone()\n\t\tt.Assert(array1, array2)\n\t\tarray1.Remove(1)\n\t\tt.AssertNE(array1, array2)\n\n\t})\n}\n\nfunc TestSortedTArray_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\", \"f\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tt.Assert(array1.Len(), 6)\n\t\tarray1.Clear()\n\t\tt.Assert(array1.Len(), 0)\n\n\t})\n}\n\nfunc TestSortedTArray_Chunk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\ti1 := array1.Chunk(2)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1[0], []any{\"a\", \"b\"})\n\t\tt.Assert(i1[2], []any{\"e\"})\n\n\t\ti1 = array1.Chunk(0)\n\t\tt.Assert(len(i1), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int32{1, 2, 3, 4, 5}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int32{1, 2, 3})\n\t\tt.Assert(chunks[1], []int32{4, 5})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tchunks := array1.Chunk(2)\n\t\tt.Assert(len(chunks), 3)\n\t\tt.Assert(chunks[0], []int{1, 2})\n\t\tt.Assert(chunks[1], []int{3, 4})\n\t\tt.Assert(chunks[2], []int{5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 6}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tchunks := array1.Chunk(3)\n\t\tt.Assert(len(chunks), 2)\n\t\tt.Assert(chunks[0], []int{1, 2, 3})\n\t\tt.Assert(chunks[1], []int{4, 5, 6})\n\t\tt.Assert(array1.Chunk(0), nil)\n\t})\n}\n\nfunc TestSortedTArray_SubSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"b\", \"e\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tarray2 := garray.NewSortedTArrayFrom(a1, nil, true)\n\t\ti1 := array1.SubSlice(2, 3)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1, []string{\"c\", \"d\", \"e\"})\n\n\t\ti1 = array1.SubSlice(2, 6)\n\t\tt.Assert(len(i1), 3)\n\t\tt.Assert(i1, []string{\"c\", \"d\", \"e\"})\n\n\t\ti1 = array1.SubSlice(7, 2)\n\t\tt.Assert(len(i1), 0)\n\n\t\ts1 := array1.SubSlice(1, -2)\n\t\tt.Assert(s1, nil)\n\n\t\ts1 = array1.SubSlice(-9, 2)\n\t\tt.Assert(s1, nil)\n\t\tt.Assert(array2.SubSlice(1, 3), []string{\"b\", \"c\", \"d\"})\n\n\t})\n}\n\nfunc TestSortedTArray_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\ti1, ok := array1.Rand()\n\t\tt.Assert(ok, true)\n\t\tt.AssertIN(i1, []string{\"a\", \"d\", \"c\"})\n\t\tt.Assert(array1.Len(), 3)\n\n\t\tarray2 := garray.NewSortedTArrayFrom([]string{}, nil)\n\t\tv, ok := array2.Rand()\n\t\tt.Assert(ok, false)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestSortedTArray_Rands(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\ti1 := array1.Rands(2)\n\t\tt.AssertIN(i1, []string{\"a\", \"d\", \"c\"})\n\t\tt.Assert(len(i1), 2)\n\t\tt.Assert(array1.Len(), 3)\n\n\t\ti1 = array1.Rands(4)\n\t\tt.Assert(len(i1), 4)\n\n\t\tarray2 := garray.NewSortedTArrayFrom([]string{}, nil)\n\t\tv := array2.Rands(1)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestSortedTArray_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tt.Assert(array1.Join(\",\"), `a,c,d`)\n\t\tt.Assert(array1.Join(\".\"), `a.c.d`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", `\"a\"`, `\\a`}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tt.Assert(array1.Join(\".\"), `\"a\".0.1.\\a`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tt.Assert(array1.Join(\".\"), \"\")\n\t})\n}\n\nfunc TestSortedTArray_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"0\", \"1\", \"a\", \"b\"}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tt.Assert(array1.String(), `[0,1,\"a\",\"b\"]`)\n\n\t\tarray1 = nil\n\t\tt.Assert(array1.String(), \"\")\n\t})\n}\n\nfunc TestSortedTArray_CountValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []string{\"a\", \"d\", \"c\", \"c\"}\n\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tm1 := array1.CountValues()\n\t\tt.Assert(len(m1), 3)\n\t\tt.Assert(m1[\"c\"], 2)\n\t\tt.Assert(m1[\"a\"], 1)\n\n\t})\n}\n\nfunc TestSortedTArray_SetUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tarray1.SetUnique(true)\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []int{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestSortedTArray_Unique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta1 := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}\n\t\tarray1 := garray.NewSortedTArrayFrom(a1, nil)\n\t\tarray1.Unique()\n\t\tt.Assert(array1.Len(), 5)\n\t\tt.Assert(array1, []int{1, 2, 3, 4, 5})\n\n\t\tarray2 := garray.NewSortedTArrayFrom([]int{}, nil)\n\t\tarray2.Unique()\n\t\tt.Assert(array2.Len(), 0)\n\t\tt.Assert(array2, []int{})\n\t})\n}\n\nfunc TestSortedTArray_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedTArrayFrom(s1, nil, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.LockFunc(func(n1 []string) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertGT(t2-t1, 20) // go1加的读写互斥锁，所go2读的时候被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedTArray_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedTArrayFrom(s1, nil, true)\n\n\t\tch1 := make(chan int64, 3)\n\t\tch2 := make(chan int64, 3)\n\t\t// go1\n\t\tgo a1.RLockFunc(func(n1 []string) { // 读写锁\n\t\t\ttime.Sleep(2 * time.Second) // 暂停2秒\n\t\t\tn1[2] = \"g\"\n\t\t\tch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t})\n\n\t\t// go2\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond) // 故意暂停0.01秒,等go1执行锁后，再开始执行.\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t\ta1.Len()\n\t\t\tch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)\n\t\t}()\n\n\t\tt1 := <-ch1\n\t\tt2 := <-ch1\n\t\t<-ch2 // 等待go1完成\n\n\t\t// 防止ci抖动,以豪秒为单位\n\t\tt.AssertLT(t2-t1, 20) // go1加的读锁，所go2读的时候不会被阻塞。\n\t\tt.Assert(a1.Contains(\"g\"), true)\n\t})\n}\n\nfunc TestSortedTArray_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts2 := []string{\"e\", \"f\"}\n\t\ti1 := garray.NewIntArrayFrom([]int{1, 2, 3})\n\t\ti2 := garray.NewArrayFrom([]any{3})\n\t\ts3 := garray.NewStrArrayFrom([]string{\"g\", \"h\"})\n\t\ts4 := garray.NewSortedTArrayFrom([]int{4, 5}, nil)\n\t\ts5 := garray.NewSortedStrArrayFrom(s2)\n\t\ts6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})\n\n\t\ta1 := garray.NewSortedTArrayFrom(s1, nil)\n\n\t\tt.Assert(a1.Merge(s2).Len(), 6)\n\t\tt.Assert(a1.Merge(i1).Len(), 9)\n\t\tt.Assert(a1.Merge(i2).Len(), 10)\n\t\tt.Assert(a1.Merge(s3).Len(), 12)\n\t\tt.Assert(a1.Merge(s4).Len(), 14)\n\t\tt.Assert(a1.Merge(s5).Len(), 16)\n\t\tt.Assert(a1.Merge(s6).Len(), 19)\n\t})\n}\n\nfunc TestSortedTArray_Json(t *testing.T) {\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedTArrayFrom(s1, nil)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedTArray[string](nil)\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedTArray[string]\n\t\ta3.SetComparator(nil)\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ts2 := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ta1 := garray.NewSortedTArrayFrom(s1, nil)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(b1, b2)\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := garray.NewSortedTArray[string](nil)\n\t\terr1 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(a2.Slice(), s2)\n\n\t\tvar a3 garray.SortedTArray[string]\n\t\ta3.SetComparator(nil)\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Slice(), s1)\n\t\tt.Assert(a3.Interfaces(), s1)\n\t})\n\t// array pointer\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.SortedTArray[int]\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.AssertNE(user.Scores, nil)\n\t\tt.Assert(user.Scores.Len(), 3)\n\n\t\tv, ok := user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t})\n\t// array value\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName   string\n\t\t\tScores *garray.SortedTArray[int]\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{99, 100, 98},\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\t\terr = json.UnmarshalUseNumber(b, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, data[\"Name\"])\n\t\tt.AssertNE(user.Scores, nil)\n\t\tt.Assert(user.Scores.Len(), 3)\n\n\t\tv, ok := user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.AssertIN(v, data[\"Scores\"])\n\t\tt.Assert(ok, true)\n\n\t\tv, ok = user.Scores.PopLeft()\n\t\tt.Assert(v, 0)\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestSortedTArray_Iterator(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedTArrayFrom(slice, nil)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tt.Assert(v, slice[k])\n\t\t\treturn true\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.Iterator(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorAsc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tindex := 0\n\t\tarray.IteratorDesc(func(k int, v string) bool {\n\t\t\tindex++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(index, 1)\n\t})\n}\n\nfunc TestSortedTArray_RemoveValue(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedTArrayFrom(slice, nil)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(array.RemoveValue(\"e\"), false)\n\t\tt.Assert(array.RemoveValue(\"b\"), true)\n\t\tt.Assert(array.RemoveValue(\"a\"), true)\n\t\tt.Assert(array.RemoveValue(\"c\"), true)\n\t\tt.Assert(array.RemoveValue(\"f\"), false)\n\t})\n}\n\nfunc TestSortedTArray_RemoveValues(t *testing.T) {\n\tslice := g.SliceStr{\"a\", \"b\", \"d\", \"c\"}\n\tarray := garray.NewSortedTArrayFrom(slice, nil)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray.RemoveValues(\"a\", \"b\", \"c\")\n\t\tt.Assert(array.Slice(), g.SliceStr{\"d\"})\n\t})\n}\n\nfunc TestSortedTArray_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName  string\n\t\tArray *garray.SortedTArray[int]\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": []byte(`[2,3,1]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"array\": g.SliceInt{2, 3, 1},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Array.Slice(), g.Slice{1, 2, 3})\n\t})\n}\nfunc TestSortedTArray_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.SliceInt{0, 1, 2, 3, 4, -1, -2}\n\t\tarray := garray.NewSortedTArrayFromCopy(values, nil)\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn value < 0\n\t\t}).Slice(), g.Slice{0, 1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFromCopy(g.SliceInt{-1, 1, 2, 3, 4, -2}, nil)\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn value < 0\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0, 0}, nil)\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{1, 2, 3, 4}, nil)\n\t\tt.Assert(array.Filter(func(index int, value int) bool {\n\t\t\treturn empty.IsEmpty(value)\n\t\t}), g.Slice{1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedTArray_FilterNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.SliceInt{0, 1, 2, 3, 4, -1, -2}\n\t\tarray := garray.NewSortedTArrayFromCopy(values, gutil.ComparatorT)\n\t\tt.Assert(array.FilterNil().Slice(), g.SliceInt{-2, -1, 0, 1, 2, 3, 4})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, -1, -2, nil, []any{}, \"\"}\n\t\tarray := garray.NewSortedTArrayFromCopy(values, nil)\n\t\tt.Assert(array.FilterNil().Slice(), g.Slice{\"\", -1, -2, 0, 1, 2, 3, 4, []any{}})\n\t})\n}\n\nfunc TestSortedTArray_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0, 0}, nil)\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceInt{1, 2, 3, 4}, nil)\n\t\tt.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceStr{\"a\", \"\", \"b\", \"c\", \"\"}, nil)\n\t\tt.Assert(array.FilterEmpty(), g.Slice{\"a\", \"b\", \"c\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := g.Slice{0, 1, 2, 3, 4, -1, -2, nil, []any{}, \"\"}\n\t\tarray := garray.NewSortedTArrayFromCopy(values, nil)\n\t\tt.Assert(array.FilterEmpty().Slice(), g.Slice{-1, -2, 1, 2, 3, 4})\n\t})\n}\n\nfunc TestSortedTArray_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom(g.SliceStr{\"1\", \"2\"}, nil)\n\t\tt.Assert(array.Walk(func(value string) string {\n\t\t\treturn \"key-\" + value\n\t\t}), g.Slice{\"key-1\", \"key-2\"})\n\t})\n}\n\nfunc TestSortedTArray_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom([]string{}, nil)\n\t\tt.Assert(array.IsEmpty(), true)\n\t})\n}\n\nfunc TestSortedTArray_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.NewSortedTArrayFrom([]int{1, 2, 3, 4, 5}, nil)\n\t\tcopyArray := array.DeepCopy().(*garray.SortedTArray[int])\n\t\tarray.Add(6)\n\t\tcopyArray.Add(7)\n\t\tcval, _ := copyArray.Get(5)\n\t\tval, _ := array.Get(5)\n\t\tt.AssertNE(cval, val)\n\t})\n}\n"
  },
  {
    "path": "container/glist/glist.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with l file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\n// Package glist provides most commonly used doubly linked list container which also supports\n// concurrent-safe/unsafe switch feature.\npackage glist\n\nimport (\n\t\"bytes\"\n\t\"container/list\"\n\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype (\n\t// List is a doubly linked list containing a concurrent-safe/unsafe switch.\n\t// The switch should be set when its initialization and cannot be changed then.\n\tList struct {\n\t\tmu   rwmutex.RWMutex\n\t\tlist *list.List\n\t}\n\t// Element the item type of the list.\n\tElement = list.Element\n)\n\n// New creates and returns a new empty doubly linked list.\nfunc New(safe ...bool) *List {\n\treturn &List{\n\t\tmu:   rwmutex.Create(safe...),\n\t\tlist: list.New(),\n\t}\n}\n\n// NewFrom creates and returns a list from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using list in concurrent-safety,\n// which is false in default.\nfunc NewFrom(array []any, safe ...bool) *List {\n\tl := list.New()\n\tfor _, v := range array {\n\t\tl.PushBack(v)\n\t}\n\treturn &List{\n\t\tmu:   rwmutex.Create(safe...),\n\t\tlist: l,\n\t}\n}\n\n// PushFront inserts a new element `e` with value `v` at the front of list `l` and returns `e`.\nfunc (l *List) PushFront(v any) (e *Element) {\n\tl.mu.Lock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\te = l.list.PushFront(v)\n\tl.mu.Unlock()\n\treturn\n}\n\n// PushBack inserts a new element `e` with value `v` at the back of list `l` and returns `e`.\nfunc (l *List) PushBack(v any) (e *Element) {\n\tl.mu.Lock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\te = l.list.PushBack(v)\n\tl.mu.Unlock()\n\treturn\n}\n\n// PushFronts inserts multiple new elements with values `values` at the front of list `l`.\nfunc (l *List) PushFronts(values []any) {\n\tl.mu.Lock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tfor _, v := range values {\n\t\tl.list.PushFront(v)\n\t}\n\tl.mu.Unlock()\n}\n\n// PushBacks inserts multiple new elements with values `values` at the back of list `l`.\nfunc (l *List) PushBacks(values []any) {\n\tl.mu.Lock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tfor _, v := range values {\n\t\tl.list.PushBack(v)\n\t}\n\tl.mu.Unlock()\n}\n\n// PopBack removes the element from back of `l` and returns the value of the element.\nfunc (l *List) PopBack() (value any) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t\treturn\n\t}\n\tif e := l.list.Back(); e != nil {\n\t\tvalue = l.list.Remove(e)\n\t}\n\treturn\n}\n\n// PopFront removes the element from front of `l` and returns the value of the element.\nfunc (l *List) PopFront() (value any) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t\treturn\n\t}\n\tif e := l.list.Front(); e != nil {\n\t\tvalue = l.list.Remove(e)\n\t}\n\treturn\n}\n\n// PopBacks removes `max` elements from back of `l`\n// and returns values of the removed elements as slice.\nfunc (l *List) PopBacks(max int) (values []any) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tif max > 0 && max < length {\n\t\t\tlength = max\n\t\t}\n\t\tvalues = make([]any, length)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tvalues[i] = l.list.Remove(l.list.Back())\n\t\t}\n\t}\n\treturn\n}\n\n// PopFronts removes `max` elements from front of `l`\n// and returns values of the removed elements as slice.\nfunc (l *List) PopFronts(max int) (values []any) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tif max > 0 && max < length {\n\t\t\tlength = max\n\t\t}\n\t\tvalues = make([]any, length)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tvalues[i] = l.list.Remove(l.list.Front())\n\t\t}\n\t}\n\treturn\n}\n\n// PopBackAll removes all elements from back of `l`\n// and returns values of the removed elements as slice.\nfunc (l *List) PopBackAll() []any {\n\treturn l.PopBacks(-1)\n}\n\n// PopFrontAll removes all elements from front of `l`\n// and returns values of the removed elements as slice.\nfunc (l *List) PopFrontAll() []any {\n\treturn l.PopFronts(-1)\n}\n\n// FrontAll copies and returns values of all elements from front of `l` as slice.\nfunc (l *List) FrontAll() (values []any) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tvalues = make([]any, length)\n\t\tfor i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\tvalues[i] = e.Value\n\t\t}\n\t}\n\treturn\n}\n\n// BackAll copies and returns values of all elements from back of `l` as slice.\nfunc (l *List) BackAll() (values []any) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tvalues = make([]any, length)\n\t\tfor i, e := 0, l.list.Back(); i < length; i, e = i+1, e.Prev() {\n\t\t\tvalues[i] = e.Value\n\t\t}\n\t}\n\treturn\n}\n\n// FrontValue returns value of the first element of `l` or nil if the list is empty.\nfunc (l *List) FrontValue() (value any) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tif e := l.list.Front(); e != nil {\n\t\tvalue = e.Value\n\t}\n\treturn\n}\n\n// BackValue returns value of the last element of `l` or nil if the list is empty.\nfunc (l *List) BackValue() (value any) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tif e := l.list.Back(); e != nil {\n\t\tvalue = e.Value\n\t}\n\treturn\n}\n\n// Front returns the first element of list `l` or nil if the list is empty.\nfunc (l *List) Front() (e *Element) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\te = l.list.Front()\n\treturn\n}\n\n// Back returns the last element of list `l` or nil if the list is empty.\nfunc (l *List) Back() (e *Element) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\te = l.list.Back()\n\treturn\n}\n\n// Len returns the number of elements of list `l`.\n// The complexity is O(1).\nfunc (l *List) Len() (length int) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tlength = l.list.Len()\n\treturn\n}\n\n// Size is alias of Len.\nfunc (l *List) Size() int {\n\treturn l.Len()\n}\n\n// MoveBefore moves element `e` to its new position before `p`.\n// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.\n// The element and `p` must not be nil.\nfunc (l *List) MoveBefore(e, p *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.MoveBefore(e, p)\n}\n\n// MoveAfter moves element `e` to its new position after `p`.\n// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.\n// The element and `p` must not be nil.\nfunc (l *List) MoveAfter(e, p *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.MoveAfter(e, p)\n}\n\n// MoveToFront moves element `e` to the front of list `l`.\n// If `e` is not an element of `l`, the list is not modified.\n// The element must not be nil.\nfunc (l *List) MoveToFront(e *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.MoveToFront(e)\n}\n\n// MoveToBack moves element `e` to the back of list `l`.\n// If `e` is not an element of `l`, the list is not modified.\n// The element must not be nil.\nfunc (l *List) MoveToBack(e *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.MoveToBack(e)\n}\n\n// PushBackList inserts a copy of an other list at the back of list `l`.\n// The lists `l` and `other` may be the same, but they must not be nil.\nfunc (l *List) PushBackList(other *List) {\n\tif l != other {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.PushBackList(other.list)\n}\n\n// PushFrontList inserts a copy of an other list at the front of list `l`.\n// The lists `l` and `other` may be the same, but they must not be nil.\nfunc (l *List) PushFrontList(other *List) {\n\tif l != other {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tl.list.PushFrontList(other.list)\n}\n\n// InsertAfter inserts a new element `e` with value `v` immediately after `p` and returns `e`.\n// If `p` is not an element of `l`, the list is not modified.\n// The `p` must not be nil.\nfunc (l *List) InsertAfter(p *Element, v any) (e *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\te = l.list.InsertAfter(v, p)\n\treturn\n}\n\n// InsertBefore inserts a new element `e` with value `v` immediately before `p` and returns `e`.\n// If `p` is not an element of `l`, the list is not modified.\n// The `p` must not be nil.\nfunc (l *List) InsertBefore(p *Element, v any) (e *Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\te = l.list.InsertBefore(v, p)\n\treturn\n}\n\n// Remove removes `e` from `l` if `e` is an element of list `l`.\n// It returns the element value e.Value.\n// The element must not be nil.\nfunc (l *List) Remove(e *Element) (value any) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tvalue = l.list.Remove(e)\n\treturn\n}\n\n// Removes removes multiple elements `es` from `l` if `es` are elements of list `l`.\nfunc (l *List) Removes(es []*Element) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tfor _, e := range es {\n\t\tl.list.Remove(e)\n\t}\n}\n\n// RemoveAll removes all elements from list `l`.\nfunc (l *List) RemoveAll() {\n\tl.mu.Lock()\n\tl.list = list.New()\n\tl.mu.Unlock()\n}\n\n// Clear is alias of RemoveAll.\nfunc (l *List) Clear() {\n\tl.RemoveAll()\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (l *List) RLockFunc(f func(list *list.List)) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list != nil {\n\t\tf(l.list)\n\t}\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (l *List) LockFunc(f func(list *list.List)) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tf(l.list)\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (l *List) Iterator(f func(e *Element) bool) {\n\tl.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the list readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (l *List) IteratorAsc(f func(e *Element) bool) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tfor i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\tif !f(e) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n// IteratorDesc iterates the list readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (l *List) IteratorDesc(f func(e *Element) bool) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn\n\t}\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tfor i, e := 0, l.list.Back(); i < length; i, e = i+1, e.Prev() {\n\t\t\tif !f(e) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Join joins list elements with a string `glue`.\nfunc (l *List) Join(glue string) string {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tif l.list == nil {\n\t\treturn \"\"\n\t}\n\tbuffer := bytes.NewBuffer(nil)\n\tlength := l.list.Len()\n\tif length > 0 {\n\t\tfor i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\tbuffer.WriteString(gconv.String(e.Value))\n\t\t\tif i != length-1 {\n\t\t\t\tbuffer.WriteString(glue)\n\t\t\t}\n\t\t}\n\t}\n\treturn buffer.String()\n}\n\n// String returns current list as a string.\nfunc (l *List) String() string {\n\tif l == nil {\n\t\treturn \"\"\n\t}\n\treturn \"[\" + l.Join(\",\") + \"]\"\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (l List) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(l.FrontAll())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (l *List) UnmarshalJSON(b []byte) error {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tvar array []any\n\tif err := json.UnmarshalUseNumber(b, &array); err != nil {\n\t\treturn err\n\t}\n\tl.PushBacks(array)\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for list.\nfunc (l *List) UnmarshalValue(value any) (err error) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tif l.list == nil {\n\t\tl.list = list.New()\n\t}\n\tvar array []any\n\tswitch value.(type) {\n\tcase string, []byte:\n\t\terr = json.UnmarshalUseNumber(gconv.Bytes(value), &array)\n\tdefault:\n\t\tarray = gconv.SliceAny(value)\n\t}\n\tl.PushBacks(array)\n\treturn err\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (l *List) DeepCopy() any {\n\tif l == nil {\n\t\treturn nil\n\t}\n\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\tif l.list == nil {\n\t\treturn nil\n\t}\n\tvar (\n\t\tlength = l.list.Len()\n\t\tvalues = make([]any, length)\n\t)\n\tif length > 0 {\n\t\tfor i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\tvalues[i] = deepcopy.Copy(e.Value)\n\t\t}\n\t}\n\treturn NewFrom(values, l.mu.IsSafe())\n}\n"
  },
  {
    "path": "container/glist/glist_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage glist\n\nimport (\n\t\"bytes\"\n\t\"container/list\"\n\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// TElement is an element of a linked list.\ntype TElement[T any] struct {\n\t// Next and previous pointers in the doubly-linked list of elements.\n\t// To simplify the implementation, internally a list l is implemented\n\t// as a ring, such that &l.root is both the next element of the last\n\t// list element (l.Back()) and the previous element of the first list\n\t// element (l.Front()).\n\tnext, prev *TElement[T]\n\n\t// The list to which this element belongs.\n\tlist *TList[T]\n\n\t// The value stored with this element.\n\tValue T\n}\n\n// Next returns the next list element or nil.\nfunc (e *TElement[T]) Next() *TElement[T] {\n\tif p := e.next; e.list != nil && p != &e.list.root {\n\t\treturn p\n\t}\n\treturn nil\n}\n\n// Prev returns the previous list element or nil.\nfunc (e *TElement[T]) Prev() *TElement[T] {\n\tif p := e.prev; e.list != nil && p != &e.list.root {\n\t\treturn p\n\t}\n\treturn nil\n}\n\n// TList is a doubly linked list containing a concurrent-safe/unsafe switch.\n// The switch should be set when its initialization and cannot be changed then.\n\ntype TList[T any] struct {\n\tmu   rwmutex.RWMutex\n\troot TElement[T] // sentinel list element, only &root, root.prev, and root.next are used\n\tlen  int         // current list length excluding (this) sentinel element\n}\n\n// NewT creates and returns a new empty doubly linked list.\nfunc NewT[T any](safe ...bool) *TList[T] {\n\tl := &TList[T]{\n\t\tmu: rwmutex.Create(safe...),\n\t}\n\treturn l.init()\n}\n\n// NewTFrom creates and returns a list from a copy of given slice `array`.\n// The parameter `safe` is used to specify whether using list in concurrent-safety,\n// which is false in default.\nfunc NewTFrom[T any](array []T, safe ...bool) *TList[T] {\n\tl := NewT[T](safe...)\n\tfor _, v := range array {\n\t\tl.insertValue(v, l.root.prev)\n\t}\n\treturn l\n}\n\n// PushFront inserts a new element `e` with value `v` at the front of list `l` and returns `e`.\nfunc (l *TList[T]) PushFront(v T) (e *TElement[T]) {\n\tl.mu.Lock()\n\tl.lazyInit()\n\te = l.insertValue(v, &l.root)\n\tl.mu.Unlock()\n\treturn\n}\n\n// PushBack inserts a new element `e` with value `v` at the back of list `l` and returns `e`.\nfunc (l *TList[T]) PushBack(v T) (e *TElement[T]) {\n\tl.mu.Lock()\n\tl.lazyInit()\n\te = l.insertValue(v, l.root.prev)\n\tl.mu.Unlock()\n\treturn\n}\n\n// PushFronts inserts multiple new elements with values `values` at the front of list `l`.\nfunc (l *TList[T]) PushFronts(values []T) {\n\tl.mu.Lock()\n\tl.lazyInit()\n\tfor _, v := range values {\n\t\tl.insertValue(v, &l.root)\n\t}\n\tl.mu.Unlock()\n}\n\n// PushBacks inserts multiple new elements with values `values` at the back of list `l`.\nfunc (l *TList[T]) PushBacks(values []T) {\n\tl.mu.Lock()\n\tl.lazyInit()\n\tfor _, v := range values {\n\t\tl.insertValue(v, l.root.prev)\n\t}\n\tl.mu.Unlock()\n}\n\n// PopBack removes the element from back of `l` and returns the value of the element.\nfunc (l *TList[T]) PopBack() (value T) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\tif l.len == 0 {\n\t\treturn\n\t}\n\treturn l.remove(l.root.prev)\n}\n\n// PopFront removes the element from front of `l` and returns the value of the element.\nfunc (l *TList[T]) PopFront() (value T) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\tif l.len == 0 {\n\t\treturn\n\t}\n\treturn l.remove(l.root.next)\n}\n\n// PopBacks removes `max` elements from back of `l`\n// and returns values of the removed elements as slice.\nfunc (l *TList[T]) PopBacks(max int) (values []T) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\n\tlength := l.len\n\tif length > 0 {\n\t\tif max > 0 && max < length {\n\t\t\tlength = max\n\t\t}\n\t\tvalues = make([]T, length)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tvalues[i] = l.remove(l.root.prev)\n\t\t}\n\t}\n\treturn\n}\n\n// PopFronts removes `max` elements from front of `l`\n// and returns values of the removed elements as slice.\nfunc (l *TList[T]) PopFronts(max int) (values []T) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\n\tlength := l.len\n\tif length > 0 {\n\t\tif max > 0 && max < length {\n\t\t\tlength = max\n\t\t}\n\t\tvalues = make([]T, length)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tvalues[i] = l.remove(l.root.next)\n\t\t}\n\t}\n\treturn\n}\n\n// PopBackAll removes all elements from back of `l`\n// and returns values of the removed elements as slice.\nfunc (l *TList[T]) PopBackAll() []T {\n\treturn l.PopBacks(-1)\n}\n\n// PopFrontAll removes all elements from front of `l`\n// and returns values of the removed elements as slice.\nfunc (l *TList[T]) PopFrontAll() []T {\n\treturn l.PopFronts(-1)\n}\n\n// FrontAll copies and returns values of all elements from front of `l` as slice.\nfunc (l *TList[T]) FrontAll() (values []T) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tlength := l.len\n\tif length > 0 {\n\t\tvalues = make([]T, length)\n\t\tfor i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {\n\t\t\tvalues[i] = e.Value\n\t\t}\n\t}\n\treturn\n}\n\n// BackAll copies and returns values of all elements from back of `l` as slice.\nfunc (l *TList[T]) BackAll() (values []T) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tlength := l.len\n\tif length > 0 {\n\t\tvalues = make([]T, length)\n\t\tfor i, e := 0, l.back(); i < length; i, e = i+1, e.Prev() {\n\t\t\tvalues[i] = e.Value\n\t\t}\n\t}\n\treturn\n}\n\n// FrontValue returns value of the first element of `l` or zero value of T if the list is empty.\nfunc (l *TList[T]) FrontValue() (value T) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tif e := l.front(); e != nil {\n\t\tvalue = e.Value\n\t}\n\treturn\n}\n\n// BackValue returns value of the last element of `l` or zero value of T if the list is empty.\nfunc (l *TList[T]) BackValue() (value T) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tif e := l.back(); e != nil {\n\t\tvalue = e.Value\n\t}\n\treturn\n}\n\n// Front returns the first element of list `l` or nil if the list is empty.\nfunc (l *TList[T]) Front() (e *TElement[T]) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\tl.lazyInit()\n\n\te = l.front()\n\treturn\n}\n\n// Back returns the last element of list `l` or nil if the list is empty.\nfunc (l *TList[T]) Back() (e *TElement[T]) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\n\te = l.back()\n\treturn\n}\n\n// Len returns the number of elements of list `l`.\n// The complexity is O(1).\nfunc (l *TList[T]) Len() (length int) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\tl.lazyInit()\n\n\tlength = l.len\n\treturn\n}\n\n// Size is alias of Len.\nfunc (l *TList[T]) Size() int {\n\treturn l.Len()\n}\n\n// MoveBefore moves element `e` to its new position before `p`.\n// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.\n// The element and `p` must not be nil.\nfunc (l *TList[T]) MoveBefore(e, p *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.lazyInit()\n\n\tif e.list != l || e == p || p.list != l {\n\t\treturn\n\t}\n\tl.move(e, p.prev)\n}\n\n// MoveAfter moves element `e` to its new position after `p`.\n// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.\n// The element and `p` must not be nil.\nfunc (l *TList[T]) MoveAfter(e, p *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\tif e.list != l || e == p || p.list != l {\n\t\treturn\n\t}\n\tl.move(e, p)\n}\n\n// MoveToFront moves element `e` to the front of list `l`.\n// If `e` is not an element of `l`, the list is not modified.\n// The element must not be nil.\nfunc (l *TList[T]) MoveToFront(e *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\n\tif e.list != l || l.root.next == e {\n\t\treturn\n\t}\n\t// see comment in List.Remove about initialization of l\n\tl.move(e, &l.root)\n}\n\n// MoveToBack moves element `e` to the back of list `l`.\n// If `e` is not an element of `l`, the list is not modified.\n// The element must not be nil.\nfunc (l *TList[T]) MoveToBack(e *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\n\tif e.list != l || l.root.prev == e {\n\t\treturn\n\t}\n\t// see comment in List.Remove about initialization of l\n\tl.move(e, l.root.prev)\n}\n\n// PushBackList inserts a copy of an other list at the back of list `l`.\n// The lists `l` and `other` may be the same, but they must not be nil.\nfunc (l *TList[T]) PushBackList(other *TList[T]) {\n\tif l != other {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.lazyInit()\n\n\tfor i, e := other.len, other.front(); i > 0; i, e = i-1, e.Next() {\n\t\tl.insertValue(e.Value, l.root.prev)\n\t}\n}\n\n// PushFrontList inserts a copy of an other list at the front of list `l`.\n// The lists `l` and `other` may be the same, but they must not be nil.\nfunc (l *TList[T]) PushFrontList(other *TList[T]) {\n\tif l != other {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.lazyInit()\n\n\tfor i, e := other.len, other.back(); i > 0; i, e = i-1, e.Prev() {\n\t\tl.insertValue(e.Value, &l.root)\n\t}\n}\n\n// InsertAfter inserts a new element `e` with value `v` immediately after `p` and returns `e`.\n// If `p` is not an element of `l`, the list is not modified.\n// The `p` must not be nil.\nfunc (l *TList[T]) InsertAfter(p *TElement[T], v T) (e *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.lazyInit()\n\tif p.list != l {\n\t\treturn nil\n\t}\n\te = l.insertValue(v, p)\n\treturn\n}\n\n// InsertBefore inserts a new element `e` with value `v` immediately before `p` and returns `e`.\n// If `p` is not an element of `l`, the list is not modified.\n// The `p` must not be nil.\nfunc (l *TList[T]) InsertBefore(p *TElement[T], v T) (e *TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.lazyInit()\n\tif p.list != l {\n\t\treturn nil\n\t}\n\te = l.insertValue(v, p.prev)\n\treturn\n}\n\n// Remove removes `e` from `l` if `e` is an element of list `l`.\n// It returns the element value e.Value.\n// The element must not be nil.\nfunc (l *TList[T]) Remove(e *TElement[T]) (value T) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\treturn l.remove(e)\n}\n\n// Removes removes multiple elements `es` from `l` if `es` are elements of list `l`.\nfunc (l *TList[T]) Removes(es []*TElement[T]) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.lazyInit()\n\tfor _, e := range es {\n\t\tl.remove(e)\n\t}\n}\n\n// RemoveAll removes all elements from list `l`.\nfunc (l *TList[T]) RemoveAll() {\n\tl.mu.Lock()\n\tl.init()\n\tl.mu.Unlock()\n}\n\n// Clear is alias of RemoveAll.\nfunc (l *TList[T]) Clear() {\n\tl.RemoveAll()\n}\n\n// ToList converts TList[T] to list.List\nfunc (l *TList[T]) ToList() *list.List {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\treturn l.toList()\n}\n\n// toList converts TList[T] to list.List\nfunc (l *TList[T]) toList() *list.List {\n\tl.lazyInit()\n\n\tnl := list.New()\n\n\tfor e := l.front(); e != nil; e = e.Next() {\n\t\tnl.PushBack(e.Value)\n\t}\n\treturn nl\n}\n\n// AppendList append list.List to the end\nfunc (l *TList[T]) AppendList(nl *list.List) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tl.appendList(nl)\n}\n\n// appendList append list.List to the end\nfunc (l *TList[T]) appendList(nl *list.List) {\n\tif nl.Len() == 0 {\n\t\treturn\n\t}\n\n\tl.lazyInit()\n\n\tfor e := nl.Front(); e != nil; e = e.Next() {\n\t\tif v, ok := e.Value.(T); ok {\n\t\t\tl.insertValue(v, l.root.prev)\n\t\t}\n\t}\n}\n\n// AssignList assigns list.List to now TList[T].\n// It will clear TList[T] first, and append the list.List.\n// Note: Elements in nl that are not assignable to T are silently skipped.\n// Returns the number of skipped (incompatible) elements.\nfunc (l *TList[T]) AssignList(nl *list.List) int {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\treturn l.assignList(nl)\n}\n\n// assignList assigns list.List to now TList[T].\n// It will clear TList[T] first, and append the list.List.\n// Returns the number of skipped (incompatible) elements.\nfunc (l *TList[T]) assignList(nl *list.List) int {\n\tl.init()\n\tif nl.Len() == 0 {\n\t\treturn 0\n\t}\n\tskipped := 0\n\tfor e := nl.Front(); e != nil; e = e.Next() {\n\t\tif v, ok := e.Value.(T); ok {\n\t\t\tl.insertValue(v, l.root.prev)\n\t\t} else {\n\t\t\tskipped++\n\t\t}\n\t}\n\treturn skipped\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (l *TList[T]) RLockFunc(f func(list *list.List)) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\tf(l.toList())\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (l *TList[T]) LockFunc(f func(list *list.List)) {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tnl := l.toList()\n\tf(nl)\n\tl.assignList(nl)\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (l *TList[T]) Iterator(f func(e *TElement[T]) bool) {\n\tl.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the list readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (l *TList[T]) IteratorAsc(f func(e *TElement[T]) bool) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tlength := l.len\n\tif length > 0 {\n\t\tfor i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {\n\t\t\tif !f(e) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n// IteratorDesc iterates the list readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (l *TList[T]) IteratorDesc(f func(e *TElement[T]) bool) {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\tlength := l.len\n\tif length > 0 {\n\t\tfor i, e := 0, l.back(); i < length; i, e = i+1, e.Prev() {\n\t\t\tif !f(e) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Join joins list elements with a string `glue`.\nfunc (l *TList[T]) Join(glue string) string {\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\tl.lazyInit()\n\n\tbuffer := bytes.NewBuffer(nil)\n\tlength := l.len\n\tif length > 0 {\n\t\tfor i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {\n\t\t\tbuffer.WriteString(gconv.String(e.Value))\n\t\t\tif i != length-1 {\n\t\t\t\tbuffer.WriteString(glue)\n\t\t\t}\n\t\t}\n\t}\n\treturn buffer.String()\n}\n\n// String returns current list as a string.\nfunc (l *TList[T]) String() string {\n\tif l == nil {\n\t\treturn \"\"\n\t}\n\treturn \"[\" + l.Join(\",\") + \"]\"\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (l TList[T]) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(l.FrontAll())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (l *TList[T]) UnmarshalJSON(b []byte) error {\n\tvar array []T\n\tif err := json.UnmarshalUseNumber(b, &array); err != nil {\n\t\treturn err\n\t}\n\tl.init()\n\tl.PushBacks(array)\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for list.\nfunc (l *TList[T]) UnmarshalValue(value any) (err error) {\n\tvar array []T\n\tswitch value.(type) {\n\tcase string, []byte:\n\t\terr = json.UnmarshalUseNumber(gconv.Bytes(value), &array)\n\tdefault:\n\t\tanyArray := gconv.SliceAny(value)\n\t\tif err = gconv.Scan(anyArray, &array); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tl.init()\n\tl.PushBacks(array)\n\treturn err\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (l *TList[T]) DeepCopy() any {\n\tif l == nil {\n\t\treturn nil\n\t}\n\n\tl.mu.RLock()\n\tdefer l.mu.RUnlock()\n\n\tl.lazyInit()\n\n\tvar (\n\t\tlength  = l.len\n\t\tvaluesT = make([]T, length)\n\t)\n\tif length > 0 {\n\t\tfor i, e := 0, l.front(); i < length; i, e = i+1, e.Next() {\n\t\t\tvaluesT[i] = deepcopy.Copy(e.Value).(T)\n\t\t}\n\t}\n\treturn NewTFrom(valuesT, l.mu.IsSafe())\n}\n\n// Init initializes or clears list l.\nfunc (l *TList[T]) init() *TList[T] {\n\tl.root.next = &l.root\n\tl.root.prev = &l.root\n\tl.len = 0\n\treturn l\n}\n\n// lazyInit lazily initializes a zero List value.\nfunc (l *TList[T]) lazyInit() {\n\tif l.root.next == nil {\n\t\tl.init()\n\t}\n}\n\n// insert inserts e after at, increments l.len, and returns e.\nfunc (l *TList[T]) insert(e, at *TElement[T]) *TElement[T] {\n\te.prev = at\n\te.next = at.next\n\te.prev.next = e\n\te.next.prev = e\n\te.list = l\n\tl.len++\n\treturn e\n}\n\n// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).\nfunc (l *TList[T]) insertValue(v T, at *TElement[T]) *TElement[T] {\n\treturn l.insert(&TElement[T]{Value: v}, at)\n}\n\n// remove removes e from its list, decrements l.len\nfunc (l *TList[T]) remove(e *TElement[T]) (val T) {\n\tif e.list != l {\n\t\treturn\n\t}\n\te.prev.next = e.next\n\te.next.prev = e.prev\n\te.next = nil // avoid memory leaks\n\te.prev = nil // avoid memory leaks\n\te.list = nil\n\tl.len--\n\n\treturn e.Value\n}\n\n// move moves e to next to at.\nfunc (l *TList[T]) move(e, at *TElement[T]) {\n\tif e == at {\n\t\treturn\n\t}\n\te.prev.next = e.next\n\te.next.prev = e.prev\n\n\te.prev = at\n\te.next = at.next\n\te.prev.next = e\n\te.next.prev = e\n}\n\n// front returns the first element of list l or nil if the list is empty.\nfunc (l *TList[T]) front() *TElement[T] {\n\tif l.len == 0 {\n\t\treturn nil\n\t}\n\treturn l.root.next\n}\n\n// back returns the last element of list l or nil if the list is empty.\nfunc (l *TList[T]) back() *TElement[T] {\n\tif l.len == 0 {\n\t\treturn nil\n\t}\n\treturn l.root.prev\n}\n"
  },
  {
    "path": "container/glist/glist_z_bench_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage glist\n\nimport (\n\t\"testing\"\n)\n\nvar (\n\tlt = NewT[any](true)\n)\n\nfunc Benchmark_T_PushBack(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlt.PushBack(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_T_PushFront(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlt.PushFront(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_T_Len(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tlt.Len()\n\t\t}\n\t})\n}\n\nfunc Benchmark_T_PopFront(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tlt.PopFront()\n\t\t}\n\t})\n}\n\nfunc Benchmark_T_PopBack(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tlt.PopBack()\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/glist/glist_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage glist\n\nimport (\n\t\"testing\"\n)\n\nvar (\n\tl = New(true)\n)\n\nfunc Benchmark_PushBack(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tl.PushBack(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_PushFront(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tl.PushFront(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_Len(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tl.Len()\n\t\t}\n\t})\n}\n\nfunc Benchmark_PopFront(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tl.PopFront()\n\t\t}\n\t})\n}\n\nfunc Benchmark_PopBack(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tl.PopBack()\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/glist/glist_z_example_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glist_test\n\nimport (\n\t\"container/list\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\nfunc ExampleNewT() {\n\tn := 10\n\tl := glist.NewT[any]()\n\tfor i := 0; i < n; i++ {\n\t\tl.PushBack(i)\n\t}\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\tfmt.Println(l.BackAll())\n\n\tfor i := 0; i < n; i++ {\n\t\tfmt.Print(l.PopFront())\n\t}\n\n\tfmt.Println()\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 10\n\t// [0,1,2,3,4,5,6,7,8,9]\n\t// [0 1 2 3 4 5 6 7 8 9]\n\t// [9 8 7 6 5 4 3 2 1 0]\n\t// 0123456789\n\t// 0\n}\n\nfunc ExampleNewTFrom() {\n\tn := 10\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 10, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\tfmt.Println(l.BackAll())\n\n\tfor i := 0; i < n; i++ {\n\t\tfmt.Print(l.PopFront())\n\t}\n\n\tfmt.Println()\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n\t// [1 2 3 4 5 6 7 8 9 10]\n\t// [10 9 8 7 6 5 4 3 2 1]\n\t// 12345678910\n\t// 0\n}\n\nfunc ExampleTList_PushFront() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushFront(0)\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [0,1,2,3,4,5]\n}\n\nfunc ExampleTList_PushBack() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushBack(6)\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,6]\n}\n\nfunc ExampleTList_PushFronts() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushFronts(g.Slice{0, -1, -2, -3, -4})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 10\n\t// [-4,-3,-2,-1,0,1,2,3,4,5]\n}\n\nfunc ExampleTList_PushBacks() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushBacks(g.Slice{6, 7, 8, 9, 10})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n}\n\nfunc ExampleTList_PopBack() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBack())\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// 4\n\t// [1,2,3,4]\n}\n\nfunc ExampleTList_PopFront() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFront())\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 1\n\t// 4\n\t// [2,3,4,5]\n}\n\nfunc ExampleTList_PopBacks() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBacks(2))\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [5 4]\n\t// 3\n\t// [1,2,3]\n}\n\nfunc ExampleTList_PopFronts() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFronts(2))\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1 2]\n\t// 3\n\t// [3,4,5]\n}\n\nfunc ExampleTList_PopBackAll() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBackAll())\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [5 4 3 2 1]\n\t// 0\n}\n\nfunc ExampleTList_PopFrontAll() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFrontAll())\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1 2 3 4 5]\n\t// 0\n}\n\nfunc ExampleTList_FrontAll() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// [1 2 3 4 5]\n}\n\nfunc ExampleTList_BackAll() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.BackAll())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// [5 4 3 2 1]\n}\n\nfunc ExampleTList_FrontValue() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.FrontValue())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// 1\n}\n\nfunc ExampleTList_BackValue() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.BackValue())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// 5\n}\n\nfunc ExampleTList_Front() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Front().Value)\n\tfmt.Println(l)\n\n\te := l.Front()\n\tl.InsertBefore(e, 0)\n\tl.InsertAfter(e, \"a\")\n\n\tfmt.Println(l)\n\n\t// Output:\n\t// 1\n\t// [1,2,3,4,5]\n\t// [0,1,a,2,3,4,5]\n}\n\nfunc ExampleTList_Back() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Back().Value)\n\tfmt.Println(l)\n\n\te := l.Back()\n\tl.InsertBefore(e, \"a\")\n\tl.InsertAfter(e, 6)\n\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1,2,3,4,a,5,6]\n}\n\nfunc ExampleTList_Len() {\n\tl := glist.NewTFrom[any](g.Slice{1, 2, 3, 4, 5})\n\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n}\n\nfunc ExampleTList_Size() {\n\tl := glist.NewTFrom[any](g.Slice{1, 2, 3, 4, 5})\n\n\tfmt.Println(l.Size())\n\n\t// Output:\n\t// 5\n}\n\nfunc ExampleTList_MoveBefore() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\te := l.PushBack(6)\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tl.MoveBefore(e, l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te = &glist.TElement[any]{Value: 7}\n\tl.MoveBefore(e, l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,6]\n\t// 6\n\t// [6,1,2,3,4,5]\n\t// 6\n\t// [6,1,2,3,4,5]\n}\n\nfunc ExampleTList_MoveAfter() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\te := l.PushFront(0)\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tl.MoveAfter(e, l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te = &glist.TElement[any]{Value: -1}\n\tl.MoveAfter(e, l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [0,1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,0]\n\t// 6\n\t// [1,2,3,4,5,0]\n}\n\nfunc ExampleTList_MoveToFront() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\tl.MoveToFront(l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te := &glist.TElement[any]{Value: 6}\n\tl.MoveToFront(e)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [5,1,2,3,4]\n\t// 5\n\t// [5,1,2,3,4]\n}\n\nfunc ExampleTList_MoveToBack() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\tl.MoveToBack(l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te := &glist.TElement[any]{Value: 0}\n\tl.MoveToBack(e)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [2,3,4,5,1]\n\t// 5\n\t// [2,3,4,5,1]\n}\n\nfunc ExampleTList_PushBackList() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tother := glist.NewTFrom[any](g.Slice{6, 7, 8, 9, 10})\n\n\tfmt.Println(other.Size())\n\tfmt.Println(other)\n\n\tl.PushBackList(other)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [6,7,8,9,10]\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n}\n\nfunc ExampleTList_PushFrontList() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tother := glist.NewTFrom[any](g.Slice{-4, -3, -2, -1, 0})\n\n\tfmt.Println(other.Size())\n\tfmt.Println(other)\n\n\tl.PushFrontList(other)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [-4,-3,-2,-1,0]\n\t// 10\n\t// [-4,-3,-2,-1,0,1,2,3,4,5]\n}\n\nfunc ExampleTList_InsertAfter() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.InsertAfter(l.Front(), \"a\")\n\tl.InsertAfter(l.Back(), \"b\")\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 7\n\t// [1,a,2,3,4,5,b]\n}\n\nfunc ExampleTList_InsertBefore() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.InsertBefore(l.Front(), \"a\")\n\tl.InsertBefore(l.Back(), \"b\")\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 7\n\t// [a,1,2,3,4,b,5]\n}\n\nfunc ExampleTList_Remove() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tfmt.Println(l.Remove(l.Front()))\n\tfmt.Println(l.Remove(l.Back()))\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 1\n\t// 5\n\t// 3\n\t// [2,3,4]\n}\n\nfunc ExampleTList_Removes() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.Removes([]*glist.TElement[any]{l.Front(), l.Back()})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 3\n\t// [2,3,4]\n}\n\nfunc ExampleTList_RemoveAll() {\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.RemoveAll()\n\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 0\n}\n\nfunc ExampleTList_RLockFunc() {\n\t// concurrent-safe list.\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from head.\n\tl.RLockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\t\tfmt.Print(e.Value)\n\t\t\t}\n\t\t}\n\t})\n\tfmt.Println()\n\t// iterate reading from tail.\n\tl.RLockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {\n\t\t\t\tfmt.Print(e.Value)\n\t\t\t}\n\t\t}\n\t})\n\n\tfmt.Println()\n\t// Output:\n\t// 12345678910\n\t// 10987654321\n}\n\nfunc ExampleTList_IteratorAsc() {\n\t// concurrent-safe list.\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from head using IteratorAsc.\n\tl.IteratorAsc(func(e *glist.TElement[any]) bool {\n\t\tfmt.Print(e.Value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 12345678910\n}\n\nfunc ExampleTList_IteratorDesc() {\n\t// concurrent-safe list.\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from tail using IteratorDesc.\n\tl.IteratorDesc(func(e *glist.TElement[any]) bool {\n\t\tfmt.Print(e.Value)\n\t\treturn true\n\t})\n\t// Output:\n\t// 10987654321\n}\n\nfunc ExampleTList_LockFunc() {\n\t// concurrent-safe list.\n\tl := glist.NewTFrom[any](garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate writing from head.\n\tl.LockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\t\tif e.Value == 6 {\n\t\t\t\t\te.Value = \"M\"\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n\tfmt.Println(l)\n\n\t// Output:\n\t// [1,2,3,4,5,M,7,8,9,10]\n}\n\nfunc ExampleTList_Join() {\n\tvar l glist.TList[any]\n\tl.PushBacks(g.Slice{\"a\", \"b\", \"c\", \"d\"})\n\n\tfmt.Println(l.Join(\",\"))\n\n\t// Output:\n\t// a,b,c,d\n}\n"
  },
  {
    "path": "container/glist/glist_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glist_test\n\nimport (\n\t\"container/list\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\nfunc ExampleNew() {\n\tn := 10\n\tl := glist.New()\n\tfor i := 0; i < n; i++ {\n\t\tl.PushBack(i)\n\t}\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\tfmt.Println(l.BackAll())\n\n\tfor i := 0; i < n; i++ {\n\t\tfmt.Print(l.PopFront())\n\t}\n\n\tfmt.Println()\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 10\n\t// [0,1,2,3,4,5,6,7,8,9]\n\t// [0 1 2 3 4 5 6 7 8 9]\n\t// [9 8 7 6 5 4 3 2 1 0]\n\t// 0123456789\n\t// 0\n}\n\nfunc ExampleNewFrom() {\n\tn := 10\n\tl := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\tfmt.Println(l.BackAll())\n\n\tfor i := 0; i < n; i++ {\n\t\tfmt.Print(l.PopFront())\n\t}\n\n\tfmt.Println()\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n\t// [1 2 3 4 5 6 7 8 9 10]\n\t// [10 9 8 7 6 5 4 3 2 1]\n\t// 12345678910\n\t// 0\n}\n\nfunc ExampleList_PushFront() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushFront(0)\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [0,1,2,3,4,5]\n}\n\nfunc ExampleList_PushBack() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushBack(6)\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,6]\n}\n\nfunc ExampleList_PushFronts() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushFronts(g.Slice{0, -1, -2, -3, -4})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 10\n\t// [-4,-3,-2,-1,0,1,2,3,4,5]\n}\n\nfunc ExampleList_PushBacks() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.PushBacks(g.Slice{6, 7, 8, 9, 10})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n}\n\nfunc ExampleList_PopBack() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBack())\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// 4\n\t// [1,2,3,4]\n}\n\nfunc ExampleList_PopFront() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFront())\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 1\n\t// 4\n\t// [2,3,4,5]\n}\n\nfunc ExampleList_PopBacks() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBacks(2))\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [5 4]\n\t// 3\n\t// [1,2,3]\n}\n\nfunc ExampleList_PopFronts() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFronts(2))\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1 2]\n\t// 3\n\t// [3,4,5]\n}\n\nfunc ExampleList_PopBackAll() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopBackAll())\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [5 4 3 2 1]\n\t// 0\n}\n\nfunc ExampleList_PopFrontAll() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\tfmt.Println(l.PopFrontAll())\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1 2 3 4 5]\n\t// 0\n}\n\nfunc ExampleList_FrontAll() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.FrontAll())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// [1 2 3 4 5]\n}\n\nfunc ExampleList_BackAll() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.BackAll())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// [5 4 3 2 1]\n}\n\nfunc ExampleList_FrontValue() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.FrontValue())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// 1\n}\n\nfunc ExampleList_BackValue() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l)\n\tfmt.Println(l.BackValue())\n\n\t// Output:\n\t// [1,2,3,4,5]\n\t// 5\n}\n\nfunc ExampleList_Front() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Front().Value)\n\tfmt.Println(l)\n\n\te := l.Front()\n\tl.InsertBefore(e, 0)\n\tl.InsertAfter(e, \"a\")\n\n\tfmt.Println(l)\n\n\t// Output:\n\t// 1\n\t// [1,2,3,4,5]\n\t// [0,1,a,2,3,4,5]\n}\n\nfunc ExampleList_Back() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Back().Value)\n\tfmt.Println(l)\n\n\te := l.Back()\n\tl.InsertBefore(e, \"a\")\n\tl.InsertAfter(e, 6)\n\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// [1,2,3,4,a,5,6]\n}\n\nfunc ExampleList_Len() {\n\tl := glist.NewFrom(g.Slice{1, 2, 3, 4, 5})\n\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n}\n\nfunc ExampleList_Size() {\n\tl := glist.NewFrom(g.Slice{1, 2, 3, 4, 5})\n\n\tfmt.Println(l.Size())\n\n\t// Output:\n\t// 5\n}\n\nfunc ExampleList_MoveBefore() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\te := l.PushBack(6)\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tl.MoveBefore(e, l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te = &glist.Element{Value: 7}\n\tl.MoveBefore(e, l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,6]\n\t// 6\n\t// [6,1,2,3,4,5]\n\t// 6\n\t// [6,1,2,3,4,5]\n}\n\nfunc ExampleList_MoveAfter() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\te := l.PushFront(0)\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tl.MoveAfter(e, l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te = &glist.Element{Value: -1}\n\tl.MoveAfter(e, l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 6\n\t// [0,1,2,3,4,5]\n\t// 6\n\t// [1,2,3,4,5,0]\n\t// 6\n\t// [1,2,3,4,5,0]\n}\n\nfunc ExampleList_MoveToFront() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\tl.MoveToFront(l.Back())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te := &glist.Element{Value: 6}\n\tl.MoveToFront(e)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [5,1,2,3,4]\n\t// 5\n\t// [5,1,2,3,4]\n}\n\nfunc ExampleList_MoveToBack() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// element of `l`\n\tl.MoveToBack(l.Front())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// not element of `l`\n\te := &glist.Element{Value: 0}\n\tl.MoveToBack(e)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [2,3,4,5,1]\n\t// 5\n\t// [2,3,4,5,1]\n}\n\nfunc ExampleList_PushBackList() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tother := glist.NewFrom(g.Slice{6, 7, 8, 9, 10})\n\n\tfmt.Println(other.Size())\n\tfmt.Println(other)\n\n\tl.PushBackList(other)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [6,7,8,9,10]\n\t// 10\n\t// [1,2,3,4,5,6,7,8,9,10]\n}\n\nfunc ExampleList_PushFrontList() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\tother := glist.NewFrom(g.Slice{-4, -3, -2, -1, 0})\n\n\tfmt.Println(other.Size())\n\tfmt.Println(other)\n\n\tl.PushFrontList(other)\n\n\tfmt.Println(l.Size())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 5\n\t// [-4,-3,-2,-1,0]\n\t// 10\n\t// [-4,-3,-2,-1,0,1,2,3,4,5]\n}\n\nfunc ExampleList_InsertAfter() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.InsertAfter(l.Front(), \"a\")\n\tl.InsertAfter(l.Back(), \"b\")\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 7\n\t// [1,a,2,3,4,5,b]\n}\n\nfunc ExampleList_InsertBefore() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.InsertBefore(l.Front(), \"a\")\n\tl.InsertBefore(l.Back(), \"b\")\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 7\n\t// [a,1,2,3,4,b,5]\n}\n\nfunc ExampleList_Remove() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tfmt.Println(l.Remove(l.Front()))\n\tfmt.Println(l.Remove(l.Back()))\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 1\n\t// 5\n\t// 3\n\t// [2,3,4]\n}\n\nfunc ExampleList_Removes() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.Removes([]*glist.Element{l.Front(), l.Back()})\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 3\n\t// [2,3,4]\n}\n\nfunc ExampleList_RemoveAll() {\n\tl := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())\n\n\tfmt.Println(l.Len())\n\tfmt.Println(l)\n\n\tl.RemoveAll()\n\n\tfmt.Println(l.Len())\n\n\t// Output:\n\t// 5\n\t// [1,2,3,4,5]\n\t// 0\n}\n\nfunc ExampleList_RLockFunc() {\n\t// concurrent-safe list.\n\tl := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from head.\n\tl.RLockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\t\tfmt.Print(e.Value)\n\t\t\t}\n\t\t}\n\t})\n\tfmt.Println()\n\t// iterate reading from tail.\n\tl.RLockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {\n\t\t\t\tfmt.Print(e.Value)\n\t\t\t}\n\t\t}\n\t})\n\n\tfmt.Println()\n\t// Output:\n\t// 12345678910\n\t// 10987654321\n}\n\nfunc ExampleList_IteratorAsc() {\n\t// concurrent-safe list.\n\tl := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from head using IteratorAsc.\n\tl.IteratorAsc(func(e *glist.Element) bool {\n\t\tfmt.Print(e.Value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// 12345678910\n}\n\nfunc ExampleList_IteratorDesc() {\n\t// concurrent-safe list.\n\tl := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate reading from tail using IteratorDesc.\n\tl.IteratorDesc(func(e *glist.Element) bool {\n\t\tfmt.Print(e.Value)\n\t\treturn true\n\t})\n\t// Output:\n\t// 10987654321\n}\n\nfunc ExampleList_LockFunc() {\n\t// concurrent-safe list.\n\tl := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)\n\t// iterate writing from head.\n\tl.LockFunc(func(list *list.List) {\n\t\tlength := list.Len()\n\t\tif length > 0 {\n\t\t\tfor i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {\n\t\t\t\tif e.Value == 6 {\n\t\t\t\t\te.Value = \"M\"\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n\tfmt.Println(l)\n\n\t// Output:\n\t// [1,2,3,4,5,M,7,8,9,10]\n}\n\nfunc ExampleList_Join() {\n\tvar l glist.List\n\tl.PushBacks(g.Slice{\"a\", \"b\", \"c\", \"d\"})\n\n\tfmt.Println(l.Join(\",\"))\n\n\t// Output:\n\t// a,b,c,d\n}\n"
  },
  {
    "path": "container/glist/glist_z_unit_t_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glist\n\nimport (\n\t\"container/list\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc checkTListLen(t *gtest.T, l *TList[any], len int) bool {\n\tif n := l.Len(); n != len {\n\t\tt.Errorf(\"l.Len() = %d, want %d\", n, len)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc checkTListPointers(t *gtest.T, l *TList[any], es []*TElement[any]) {\n\tif !checkTListLen(t, l, len(es)) {\n\t\treturn\n\t}\n\n\ti := 0\n\tl.Iterator(func(e *TElement[any]) bool {\n\t\tif e.Prev() != es[i].Prev() {\n\t\t\tt.Errorf(\"list[%d].Prev = %p, want %p\", i, e.Prev(), es[i].Prev())\n\t\t\treturn false\n\t\t}\n\t\tif e.Next() != es[i].Next() {\n\t\t\tt.Errorf(\"list[%d].Next = %p, want %p\", i, e.Next(), es[i].Next())\n\t\t\treturn false\n\t\t}\n\t\ti++\n\t\treturn true\n\t})\n}\n\nfunc TestTVar(t *testing.T) {\n\tvar l TList[any]\n\tl.PushFront(1)\n\tl.PushFront(2)\n\tif v := l.PopBack(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tl.PushBack(1)\n\tl.PushBack(2)\n\tif v := l.PopFront(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n}\n\nfunc TestTBasic(t *testing.T) {\n\tl := NewT[any]()\n\tl.PushFront(1)\n\tl.PushFront(2)\n\tif v := l.PopBack(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tl.PushBack(1)\n\tl.PushBack(2)\n\tif v := l.PopFront(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n}\n\nfunc TestTList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tcheckTListPointers(t, l, []*TElement[any]{})\n\n\t\t// Single element list\n\t\te := l.PushFront(\"a\")\n\t\tcheckTListPointers(t, l, []*TElement[any]{e})\n\t\tl.MoveToFront(e)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e})\n\t\tl.MoveToBack(e)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e})\n\t\tl.Remove(e)\n\t\tcheckTListPointers(t, l, []*TElement[any]{})\n\n\t\t// Bigger list\n\t\te2 := l.PushFront(2)\n\t\te1 := l.PushFront(1)\n\t\te3 := l.PushBack(3)\n\t\te4 := l.PushBack(\"banana\")\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e3, e4})\n\n\t\tl.Remove(e2)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e3, e4})\n\n\t\tl.MoveToFront(e3) // move from middle\n\t\tcheckTListPointers(t, l, []*TElement[any]{e3, e1, e4})\n\n\t\tl.MoveToFront(e1)\n\t\tl.MoveToBack(e3) // move from middle\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e3})\n\n\t\tl.MoveToFront(e3) // move from back\n\t\tcheckTListPointers(t, l, []*TElement[any]{e3, e1, e4})\n\t\tl.MoveToFront(e3) // should be no-op\n\t\tcheckTListPointers(t, l, []*TElement[any]{e3, e1, e4})\n\n\t\tl.MoveToBack(e3) // move from front\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e3})\n\t\tl.MoveToBack(e3) // should be no-op\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e3})\n\n\t\te2 = l.InsertBefore(e1, 2) // insert before front\n\t\tcheckTListPointers(t, l, []*TElement[any]{e2, e1, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertBefore(e4, 2) // insert before middle\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertBefore(e3, 2) // insert before back\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e2, e3})\n\t\tl.Remove(e2)\n\n\t\te2 = l.InsertAfter(e1, 2) // insert after front\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertAfter(e4, 2) // insert after middle\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e2, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertAfter(e3, 2) // insert after back\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e3, e2})\n\t\tl.Remove(e2)\n\n\t\t// Check standard iteration.\n\t\tsum := 0\n\t\tfor e := l.Front(); e != nil; e = e.Next() {\n\t\t\tif i, ok := e.Value.(int); ok {\n\t\t\t\tsum += i\n\t\t\t}\n\t\t}\n\t\tif sum != 4 {\n\t\t\tt.Errorf(\"sum over l = %d, want 4\", sum)\n\t\t}\n\n\t\t// Clear all elements by iterating\n\t\tvar next *TElement[any]\n\t\tfor e := l.Front(); e != nil; e = next {\n\t\t\tnext = e.Next()\n\t\t\tl.Remove(e)\n\t\t}\n\t\tcheckTListPointers(t, l, []*TElement[any]{})\n\t})\n}\n\nfunc checkTList(t *gtest.T, l *TList[any], es []any) {\n\tif !checkTListLen(t, l, len(es)) {\n\t\treturn\n\t}\n\n\ti := 0\n\tfor e := l.Front(); e != nil; e = e.Next() {\n\n\t\tswitch e.Value.(type) {\n\t\tcase int:\n\t\t\tif le := e.Value.(int); le != es[i] {\n\t\t\t\tt.Errorf(\"elt[%d].Value() = %v, want %v\", i, le, es[i])\n\t\t\t}\n\t\t\t// default string\n\t\tdefault:\n\t\t\tif le := e.Value.(string); le != es[i] {\n\t\t\t\tt.Errorf(\"elt[%v].Value() = %v, want %v\", i, le, es[i])\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// for e := l.Front(); e != nil; e = e.Next() {\n\t//\tle := e.Value.(int)\n\t//\tif le != es[i] {\n\t//\t\tt.Errorf(\"elt[%d].Value() = %v, want %v\", i, le, es[i])\n\t//\t}\n\t//\ti++\n\t// }\n}\n\nfunc TestTExtending(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl1 := NewT[any]()\n\t\tl2 := NewT[any]()\n\n\t\tl1.PushBack(1)\n\t\tl1.PushBack(2)\n\t\tl1.PushBack(3)\n\n\t\tl2.PushBack(4)\n\t\tl2.PushBack(5)\n\n\t\tl3 := NewT[any]()\n\t\tl3.PushBackList(l1)\n\t\tcheckTList(t, l3, []any{1, 2, 3})\n\t\tl3.PushBackList(l2)\n\t\tcheckTList(t, l3, []any{1, 2, 3, 4, 5})\n\n\t\tl3 = NewT[any]()\n\t\tl3.PushFrontList(l2)\n\t\tcheckTList(t, l3, []any{4, 5})\n\t\tl3.PushFrontList(l1)\n\t\tcheckTList(t, l3, []any{1, 2, 3, 4, 5})\n\n\t\tcheckTList(t, l1, []any{1, 2, 3})\n\t\tcheckTList(t, l2, []any{4, 5})\n\n\t\tl3 = NewT[any]()\n\t\tl3.PushBackList(l1)\n\t\tcheckTList(t, l3, []any{1, 2, 3})\n\t\tl3.PushBackList(l3)\n\t\tcheckTList(t, l3, []any{1, 2, 3, 1, 2, 3})\n\n\t\tl3 = NewT[any]()\n\t\tl3.PushFrontList(l1)\n\t\tcheckTList(t, l3, []any{1, 2, 3})\n\t\tl3.PushFrontList(l3)\n\t\tcheckTList(t, l3, []any{1, 2, 3, 1, 2, 3})\n\n\t\tl3 = NewT[any]()\n\t\tl1.PushBackList(l3)\n\t\tcheckTList(t, l1, []any{1, 2, 3})\n\t\tl1.PushFrontList(l3)\n\t\tcheckTList(t, l1, []any{1, 2, 3})\n\t})\n}\n\nfunc TestTRemove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\te1 := l.PushBack(1)\n\t\te2 := l.PushBack(2)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2})\n\t\t// e := l.Front()\n\t\t// l.Remove(e)\n\t\t// checkTListPointers(t, l, []*TElement[any]{e2})\n\t\t// l.Remove(e)\n\t\t// checkTListPointers(t, l, []*TElement[any]{e2})\n\t})\n}\n\nfunc Test_T_Issue4103(t *testing.T) {\n\tl1 := NewT[any]()\n\tl1.PushBack(1)\n\tl1.PushBack(2)\n\n\tl2 := NewT[any]()\n\tl2.PushBack(3)\n\tl2.PushBack(4)\n\n\te := l1.Front()\n\tl2.Remove(e) // l2 should not change because e is not an element of l2\n\tif n := l2.Len(); n != 2 {\n\t\tt.Errorf(\"l2.Len() = %d, want 2\", n)\n\t}\n\n\tl1.InsertBefore(e, 8)\n\tif n := l1.Len(); n != 3 {\n\t\tt.Errorf(\"l1.Len() = %d, want 3\", n)\n\t}\n}\n\nfunc Test_T_Issue6349(t *testing.T) {\n\tl := NewT[any]()\n\tl.PushBack(1)\n\tl.PushBack(2)\n\n\te := l.Front()\n\tl.Remove(e)\n\tif e.Value != 1 {\n\t\tt.Errorf(\"e.value = %d, want 1\", e.Value)\n\t}\n\t// if e.Next() != nil {\n\t//    t.Errorf(\"e.Next() != nil\")\n\t// }\n\t// if e.Prev() != nil {\n\t//    t.Errorf(\"e.Prev() != nil\")\n\t// }\n}\n\nfunc TestTMove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\te1 := l.PushBack(1)\n\t\te2 := l.PushBack(2)\n\t\te3 := l.PushBack(3)\n\t\te4 := l.PushBack(4)\n\n\t\tl.MoveAfter(e3, e3)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e3, e4})\n\t\tl.MoveBefore(e2, e2)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e3, e4})\n\n\t\tl.MoveAfter(e3, e2)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e3, e4})\n\t\tl.MoveBefore(e2, e3)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e2, e3, e4})\n\n\t\tl.MoveBefore(e2, e4)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e3, e2, e4})\n\t\te2, e3 = e3, e2\n\n\t\tl.MoveBefore(e4, e1)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e4, e1, e2, e3})\n\t\te1, e2, e3, e4 = e4, e1, e2, e3\n\n\t\tl.MoveAfter(e4, e1)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e4, e2, e3})\n\t\te2, e3, e4 = e4, e2, e3\n\n\t\tl.MoveAfter(e2, e3)\n\t\tcheckTListPointers(t, l, []*TElement[any]{e1, e3, e2, e4})\n\t\te2, e3 = e3, e2\n\t})\n}\n\n// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List\nfunc TestTZeroList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l1 = NewT[any]()\n\t\tl1.PushFront(1)\n\t\tcheckTList(t, l1, []any{1})\n\n\t\tvar l2 = NewT[any]()\n\t\tl2.PushBack(1)\n\t\tcheckTList(t, l2, []any{1})\n\n\t\tvar l3 = NewT[any]()\n\t\tl3.PushFrontList(l1)\n\t\tcheckTList(t, l3, []any{1})\n\n\t\tvar l4 = NewT[any]()\n\t\tl4.PushBackList(l2)\n\t\tcheckTList(t, l4, []any{1})\n\t})\n}\n\n// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.\nfunc TestTInsertBeforeUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tl.PushBack(1)\n\t\tl.PushBack(2)\n\t\tl.PushBack(3)\n\t\tl.InsertBefore(new(TElement[any]), 1)\n\t\tcheckTList(t, l, []any{1, 2, 3})\n\t})\n}\n\n// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.\nfunc TestTInsertAfterUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tl.PushBack(1)\n\t\tl.PushBack(2)\n\t\tl.PushBack(3)\n\t\tl.InsertAfter(new(TElement[any]), 1)\n\t\tcheckTList(t, l, []any{1, 2, 3})\n\t})\n}\n\n// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.\nfunc TestTMoveUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl1 := NewT[any]()\n\t\te1 := l1.PushBack(1)\n\n\t\tl2 := NewT[any]()\n\t\te2 := l2.PushBack(2)\n\n\t\tl1.MoveAfter(e1, e2)\n\t\tcheckTList(t, l1, []any{1})\n\t\tcheckTList(t, l2, []any{2})\n\n\t\tl1.MoveBefore(e1, e2)\n\t\tcheckTList(t, l1, []any{1})\n\t\tcheckTList(t, l2, []any{2})\n\t})\n}\n\nfunc TestTList_RemoveAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tl.PushBack(1)\n\t\tl.RemoveAll()\n\t\tcheckTList(t, l, []any{})\n\t\tl.PushBack(2)\n\t\tcheckTList(t, l, []any{2})\n\t})\n}\n\nfunc TestTList_PushFronts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2}\n\t\tl.PushFronts(a1)\n\t\tcheckTList(t, l, []any{2, 1})\n\t\ta1 = []any{3, 4, 5}\n\t\tl.PushFronts(a1)\n\t\tcheckTList(t, l, []any{5, 4, 3, 2, 1})\n\t})\n}\n\nfunc TestTList_PushBacks(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2}\n\t\tl.PushBacks(a1)\n\t\tcheckTList(t, l, []any{1, 2})\n\t\ta1 = []any{3, 4, 5}\n\t\tl.PushBacks(a1)\n\t\tcheckTList(t, l, []any{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestTList_PopBacks(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\ta2 := []any{\"a\", \"c\", \"b\", \"e\"}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopBacks(2)\n\t\tt.Assert(i1, []any{1, 2})\n\n\t\tl.PushBacks(a2) // 4.3,a,c,b,e\n\t\ti1 = l.PopBacks(3)\n\t\tt.Assert(i1, []any{\"e\", \"b\", \"c\"})\n\t})\n}\n\nfunc TestTList_PopFronts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopFronts(2)\n\t\tt.Assert(i1, []any{4, 3})\n\t\tt.Assert(l.Len(), 2)\n\t})\n}\n\nfunc TestTList_PopBackAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopBackAll()\n\t\tt.Assert(i1, []any{1, 2, 3, 4})\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestTList_PopFrontAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopFrontAll()\n\t\tt.Assert(i1, []any{4, 3, 2, 1})\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestTList_FrontAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.FrontAll()\n\t\tt.Assert(i1, []any{4, 3, 2, 1})\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestTList_BackAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.BackAll()\n\t\tt.Assert(i1, []any{1, 2, 3, 4})\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestTList_FrontValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tl2 := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.FrontValue()\n\t\tt.Assert(gconv.Int(i1), 4)\n\t\tt.Assert(l.Len(), 4)\n\n\t\ti1 = l2.FrontValue()\n\t\tt.Assert(i1, nil)\n\t})\n}\n\nfunc TestTList_BackValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tl2 := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.BackValue()\n\t\tt.Assert(gconv.Int(i1), 1)\n\t\tt.Assert(l.Len(), 4)\n\n\t\ti1 = l2.FrontValue()\n\t\tt.Assert(i1, nil)\n\t})\n}\n\nfunc TestTList_Back(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tt.Assert(e1.Value, 1)\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestTList_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\tt.Assert(l.Size(), 4)\n\t\tl.PopFront()\n\t\tt.Assert(l.Size(), 3)\n\t})\n}\n\nfunc TestTList_Removes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tl.Removes([]*TElement[any]{e1})\n\t\tt.Assert(l.Len(), 3)\n\n\t\te2 := l.Back()\n\t\tl.Removes([]*TElement[any]{e2})\n\t\tt.Assert(l.Len(), 2)\n\t\tcheckTList(t, l, []any{4, 3})\n\t})\n}\n\nfunc TestTList_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t\tt.Assert(l.PopBack(), 9)\n\t\tt.Assert(l.PopBacks(2), []any{8, 7})\n\t\tt.Assert(l.PopFront(), 1)\n\t\tt.Assert(l.PopFronts(2), []any{2, 3})\n\t})\n}\n\nfunc TestTList_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\tl.Clear()\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestTList_IteratorAsc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 5, 6, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *TElement[any]) bool {\n\t\t\treturn gconv.Int(e1.Value) > 2\n\t\t}\n\t\tcheckTList(t, l, []any{4, 3, 6, 5, 2, 1})\n\t\tl.IteratorAsc(fun1)\n\t\tcheckTList(t, l, []any{4, 3, 6, 5, 2, 1})\n\t})\n}\n\nfunc TestTList_IteratorDesc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *TElement[any]) bool {\n\t\t\treturn gconv.Int(e1.Value) > 6\n\t\t}\n\t\tl.IteratorDesc(fun1)\n\t\tt.Assert(l.Len(), 4)\n\t\tcheckTList(t, l, []any{4, 3, 2, 1})\n\t})\n}\n\nfunc TestTList_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\ta1 := []any{\"a\", \"b\", \"c\", \"d\", \"e\"}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *TElement[any]) bool {\n\t\t\treturn gconv.String(e1.Value) > \"c\"\n\t\t}\n\t\tcheckTList(t, l, []any{\"e\", \"d\", \"c\", \"b\", \"a\"})\n\t\tl.Iterator(fun1)\n\t\tcheckTList(t, l, []any{\"e\", \"d\", \"c\", \"b\", \"a\"})\n\t})\n}\n\nfunc TestTList_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tt.Assert(l.Join(\",\"), `1,2,a,\"b\",\\c`)\n\t\tt.Assert(l.Join(\".\"), `1.2.a.\"b\".\\c`)\n\t})\n}\n\nfunc TestTList_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tt.Assert(l.String(), `[1,2,a,\"b\",\\c]`)\n\t})\n}\n\nfunc TestTList_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tl := NewT[any]()\n\t\tl.PushBacks(a)\n\t\tb1, err1 := json.Marshal(l)\n\t\tb2, err2 := json.Marshal(a)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tl := NewT[any]()\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, l)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), a)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l TList[any]\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, &l)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), a)\n\t})\n}\n\nfunc TestTList_UnmarshalValue(t *testing.T) {\n\ttype list struct {\n\t\tName string\n\t\tList *TList[any]\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tlist *list\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"list\": []byte(`[1,2,3]`),\n\t\t}, &tlist)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tlist.Name, \"john\")\n\t\tt.Assert(tlist.List.FrontAll(), []any{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tlist *list\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"list\": []any{1, 2, 3},\n\t\t}, &tlist)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tlist.Name, \"john\")\n\t\tt.Assert(tlist.List.FrontAll(), []any{1, 2, 3})\n\t})\n}\n\nfunc TestTList_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tcopyList := l.DeepCopy()\n\t\tcl := copyList.(*TList[any])\n\t\tcl.PopBack()\n\t\tt.AssertNE(l.Size(), cl.Size())\n\t})\n\t// Nil pointer deep copy\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l *TList[any]\n\t\tcopyList := l.DeepCopy()\n\t\tt.AssertNil(copyList)\n\t})\n}\n\nfunc TestTList_ToList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3, 4, 5})\n\t\tnl := l.ToList()\n\t\tt.Assert(nl.Len(), 5)\n\n\t\t// Verify elements\n\t\ti := 1\n\t\tfor e := nl.Front(); e != nil; e = e.Next() {\n\t\t\tt.Assert(e.Value, i)\n\t\t\ti++\n\t\t}\n\t})\n\t// Empty list\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tnl := l.ToList()\n\t\tt.Assert(nl.Len(), 0)\n\t})\n}\n\nfunc TestTList_AppendList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3})\n\t\tnl := list.New()\n\t\tnl.PushBack(4)\n\t\tnl.PushBack(5)\n\n\t\tl.AppendList(nl)\n\t\tt.Assert(l.Len(), 5)\n\t\tt.Assert(l.FrontAll(), []any{1, 2, 3, 4, 5})\n\t})\n\t// Append empty list\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3})\n\t\tnl := list.New()\n\t\tl.AppendList(nl)\n\t\tt.Assert(l.Len(), 3)\n\t\tt.Assert(l.FrontAll(), []any{1, 2, 3})\n\t})\n\t// Append with type mismatch (should skip)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[int]()\n\t\tnl := list.New()\n\t\tnl.PushBack(1)\n\t\tnl.PushBack(\"string\") // type mismatch\n\t\tnl.PushBack(2)\n\n\t\tl.AppendList(nl)\n\t\tt.Assert(l.Len(), 2)\n\t\tt.Assert(l.FrontAll(), []int{1, 2})\n\t})\n}\n\nfunc TestTList_AssignList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3})\n\t\tnl := list.New()\n\t\tnl.PushBack(4)\n\t\tnl.PushBack(5)\n\t\tnl.PushBack(6)\n\n\t\tskipped := l.AssignList(nl)\n\t\tt.Assert(skipped, 0)\n\t\tt.Assert(l.Len(), 3)\n\t\tt.Assert(l.FrontAll(), []any{4, 5, 6})\n\t})\n\t// Assign empty list\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewTFrom([]any{1, 2, 3})\n\t\tnl := list.New()\n\n\t\tskipped := l.AssignList(nl)\n\t\tt.Assert(skipped, 0)\n\t\tt.Assert(l.Len(), 0)\n\t})\n\t// Assign with type mismatch (should return skipped count)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[int]()\n\t\tnl := list.New()\n\t\tnl.PushBack(1)\n\t\tnl.PushBack(\"string\") // type mismatch\n\t\tnl.PushBack(2)\n\t\tnl.PushBack(\"another\") // type mismatch\n\n\t\tskipped := l.AssignList(nl)\n\t\tt.Assert(skipped, 2)\n\t\tt.Assert(l.Len(), 2)\n\t\tt.Assert(l.FrontAll(), []int{1, 2})\n\t})\n}\n\nfunc TestTList_String_Nil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l *TList[any]\n\t\tt.Assert(l.String(), \"\")\n\t})\n}\n\nfunc TestTList_UnmarshalJSON_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\terr := l.UnmarshalJSON([]byte(\"invalid json\"))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestTList_UnmarshalValue_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\terr := l.UnmarshalValue(`[1,2,3]`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), []any{1, 2, 3})\n\t})\n}\n\nfunc TestTList_UnmarshalValue_Bytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\terr := l.UnmarshalValue([]byte(`[1,2,3]`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), []any{1, 2, 3})\n\t})\n}\n\nfunc TestTList_DeepCopy_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\tcopyList := l.DeepCopy()\n\t\tcl := copyList.(*TList[any])\n\t\tt.Assert(cl.Len(), 0)\n\t})\n}\n\nfunc TestTList_AppendList_WithTypeMismatch(t *testing.T) {\n\t// Test appendList internal function through AppendList with mixed types\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[int]()\n\t\tnl := list.New()\n\t\t// Only add non-matching types\n\t\tnl.PushBack(\"string1\")\n\t\tnl.PushBack(\"string2\")\n\n\t\tl.AppendList(nl)\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestTList_UnmarshalValue_Error(t *testing.T) {\n\t// Test UnmarshalValue with data through default case\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\t// Pass a slice directly through default case\n\t\t_ = l.UnmarshalValue([]any{1, 2, 3})\n\t\tt.Assert(l.Len(), 3)\n\t\tt.Assert(l.FrontAll(), []any{1, 2, 3})\n\t})\n\t// Test UnmarshalValue error in string case\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewT[any]()\n\t\terr := l.UnmarshalValue(\"invalid json\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "container/glist/glist_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glist\n\nimport (\n\t\"container/list\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc checkListLen(t *gtest.T, l *List, len int) bool {\n\tif n := l.Len(); n != len {\n\t\tt.Errorf(\"l.Len() = %d, want %d\", n, len)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc checkListPointers(t *gtest.T, l *List, es []*Element) {\n\tif !checkListLen(t, l, len(es)) {\n\t\treturn\n\t}\n\tl.RLockFunc(func(list *list.List) {\n\t\tfor i, e := 0, l.list.Front(); i < list.Len(); i, e = i+1, e.Next() {\n\t\t\tif e.Prev() != es[i].Prev() {\n\t\t\t\tt.Errorf(\"list[%d].Prev = %p, want %p\", i, e.Prev(), es[i].Prev())\n\t\t\t}\n\t\t\tif e.Next() != es[i].Next() {\n\t\t\t\tt.Errorf(\"list[%d].Next = %p, want %p\", i, e.Next(), es[i].Next())\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc TestVar(t *testing.T) {\n\tvar l List\n\tl.PushFront(1)\n\tl.PushFront(2)\n\tif v := l.PopBack(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tl.PushBack(1)\n\tl.PushBack(2)\n\tif v := l.PopFront(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n}\n\nfunc TestBasic(t *testing.T) {\n\tl := New()\n\tl.PushFront(1)\n\tl.PushFront(2)\n\tif v := l.PopBack(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopBack(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tl.PushBack(1)\n\tl.PushBack(2)\n\tif v := l.PopFront(); v != 1 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 1, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != 2 {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", 2, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n\tif v := l.PopFront(); v != nil {\n\t\tt.Errorf(\"EXPECT %v, GOT %v\", nil, v)\n\t} else {\n\t\t// fmt.Println(v)\n\t}\n}\n\nfunc TestList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tcheckListPointers(t, l, []*Element{})\n\n\t\t// Single element list\n\t\te := l.PushFront(\"a\")\n\t\tcheckListPointers(t, l, []*Element{e})\n\t\tl.MoveToFront(e)\n\t\tcheckListPointers(t, l, []*Element{e})\n\t\tl.MoveToBack(e)\n\t\tcheckListPointers(t, l, []*Element{e})\n\t\tl.Remove(e)\n\t\tcheckListPointers(t, l, []*Element{})\n\n\t\t// Bigger list\n\t\te2 := l.PushFront(2)\n\t\te1 := l.PushFront(1)\n\t\te3 := l.PushBack(3)\n\t\te4 := l.PushBack(\"banana\")\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e3, e4})\n\n\t\tl.Remove(e2)\n\t\tcheckListPointers(t, l, []*Element{e1, e3, e4})\n\n\t\tl.MoveToFront(e3) // move from middle\n\t\tcheckListPointers(t, l, []*Element{e3, e1, e4})\n\n\t\tl.MoveToFront(e1)\n\t\tl.MoveToBack(e3) // move from middle\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e3})\n\n\t\tl.MoveToFront(e3) // move from back\n\t\tcheckListPointers(t, l, []*Element{e3, e1, e4})\n\t\tl.MoveToFront(e3) // should be no-op\n\t\tcheckListPointers(t, l, []*Element{e3, e1, e4})\n\n\t\tl.MoveToBack(e3) // move from front\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e3})\n\t\tl.MoveToBack(e3) // should be no-op\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e3})\n\n\t\te2 = l.InsertBefore(e1, 2) // insert before front\n\t\tcheckListPointers(t, l, []*Element{e2, e1, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertBefore(e4, 2) // insert before middle\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertBefore(e3, 2) // insert before back\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e2, e3})\n\t\tl.Remove(e2)\n\n\t\te2 = l.InsertAfter(e1, 2) // insert after front\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e4, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertAfter(e4, 2) // insert after middle\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e2, e3})\n\t\tl.Remove(e2)\n\t\te2 = l.InsertAfter(e3, 2) // insert after back\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e3, e2})\n\t\tl.Remove(e2)\n\n\t\t// Check standard iteration.\n\t\tsum := 0\n\t\tfor e := l.Front(); e != nil; e = e.Next() {\n\t\t\tif i, ok := e.Value.(int); ok {\n\t\t\t\tsum += i\n\t\t\t}\n\t\t}\n\t\tif sum != 4 {\n\t\t\tt.Errorf(\"sum over l = %d, want 4\", sum)\n\t\t}\n\n\t\t// Clear all elements by iterating\n\t\tvar next *Element\n\t\tfor e := l.Front(); e != nil; e = next {\n\t\t\tnext = e.Next()\n\t\t\tl.Remove(e)\n\t\t}\n\t\tcheckListPointers(t, l, []*Element{})\n\t})\n}\n\nfunc checkList(t *gtest.T, l *List, es []any) {\n\tif !checkListLen(t, l, len(es)) {\n\t\treturn\n\t}\n\n\ti := 0\n\tfor e := l.Front(); e != nil; e = e.Next() {\n\n\t\tswitch e.Value.(type) {\n\t\tcase int:\n\t\t\tif le := e.Value.(int); le != es[i] {\n\t\t\t\tt.Errorf(\"elt[%d].Value() = %v, want %v\", i, le, es[i])\n\t\t\t}\n\t\t\t// default string\n\t\tdefault:\n\t\t\tif le := e.Value.(string); le != es[i] {\n\t\t\t\tt.Errorf(\"elt[%v].Value() = %v, want %v\", i, le, es[i])\n\t\t\t}\n\t\t}\n\n\t\ti++\n\t}\n\n\t// for e := l.Front(); e != nil; e = e.Next() {\n\t//\tle := e.Value.(int)\n\t//\tif le != es[i] {\n\t//\t\tt.Errorf(\"elt[%d].Value() = %v, want %v\", i, le, es[i])\n\t//\t}\n\t//\ti++\n\t// }\n}\n\nfunc TestExtending(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl1 := New()\n\t\tl2 := New()\n\n\t\tl1.PushBack(1)\n\t\tl1.PushBack(2)\n\t\tl1.PushBack(3)\n\n\t\tl2.PushBack(4)\n\t\tl2.PushBack(5)\n\n\t\tl3 := New()\n\t\tl3.PushBackList(l1)\n\t\tcheckList(t, l3, []any{1, 2, 3})\n\t\tl3.PushBackList(l2)\n\t\tcheckList(t, l3, []any{1, 2, 3, 4, 5})\n\n\t\tl3 = New()\n\t\tl3.PushFrontList(l2)\n\t\tcheckList(t, l3, []any{4, 5})\n\t\tl3.PushFrontList(l1)\n\t\tcheckList(t, l3, []any{1, 2, 3, 4, 5})\n\n\t\tcheckList(t, l1, []any{1, 2, 3})\n\t\tcheckList(t, l2, []any{4, 5})\n\n\t\tl3 = New()\n\t\tl3.PushBackList(l1)\n\t\tcheckList(t, l3, []any{1, 2, 3})\n\t\tl3.PushBackList(l3)\n\t\tcheckList(t, l3, []any{1, 2, 3, 1, 2, 3})\n\n\t\tl3 = New()\n\t\tl3.PushFrontList(l1)\n\t\tcheckList(t, l3, []any{1, 2, 3})\n\t\tl3.PushFrontList(l3)\n\t\tcheckList(t, l3, []any{1, 2, 3, 1, 2, 3})\n\n\t\tl3 = New()\n\t\tl1.PushBackList(l3)\n\t\tcheckList(t, l1, []any{1, 2, 3})\n\t\tl1.PushFrontList(l3)\n\t\tcheckList(t, l1, []any{1, 2, 3})\n\t})\n}\n\nfunc TestRemove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\te1 := l.PushBack(1)\n\t\te2 := l.PushBack(2)\n\t\tcheckListPointers(t, l, []*Element{e1, e2})\n\t\t// e := l.Front()\n\t\t// l.Remove(e)\n\t\t// checkListPointers(t, l, []*Element{e2})\n\t\t// l.Remove(e)\n\t\t// checkListPointers(t, l, []*Element{e2})\n\t})\n}\n\nfunc Test_Issue4103(t *testing.T) {\n\tl1 := New()\n\tl1.PushBack(1)\n\tl1.PushBack(2)\n\n\tl2 := New()\n\tl2.PushBack(3)\n\tl2.PushBack(4)\n\n\te := l1.Front()\n\tl2.Remove(e) // l2 should not change because e is not an element of l2\n\tif n := l2.Len(); n != 2 {\n\t\tt.Errorf(\"l2.Len() = %d, want 2\", n)\n\t}\n\n\tl1.InsertBefore(e, 8)\n\tif n := l1.Len(); n != 3 {\n\t\tt.Errorf(\"l1.Len() = %d, want 3\", n)\n\t}\n}\n\nfunc Test_Issue6349(t *testing.T) {\n\tl := New()\n\tl.PushBack(1)\n\tl.PushBack(2)\n\n\te := l.Front()\n\tl.Remove(e)\n\tif e.Value != 1 {\n\t\tt.Errorf(\"e.value = %d, want 1\", e.Value)\n\t}\n\t// if e.Next() != nil {\n\t//    t.Errorf(\"e.Next() != nil\")\n\t// }\n\t// if e.Prev() != nil {\n\t//    t.Errorf(\"e.Prev() != nil\")\n\t// }\n}\n\nfunc TestMove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\te1 := l.PushBack(1)\n\t\te2 := l.PushBack(2)\n\t\te3 := l.PushBack(3)\n\t\te4 := l.PushBack(4)\n\n\t\tl.MoveAfter(e3, e3)\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e3, e4})\n\t\tl.MoveBefore(e2, e2)\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e3, e4})\n\n\t\tl.MoveAfter(e3, e2)\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e3, e4})\n\t\tl.MoveBefore(e2, e3)\n\t\tcheckListPointers(t, l, []*Element{e1, e2, e3, e4})\n\n\t\tl.MoveBefore(e2, e4)\n\t\tcheckListPointers(t, l, []*Element{e1, e3, e2, e4})\n\t\te2, e3 = e3, e2\n\n\t\tl.MoveBefore(e4, e1)\n\t\tcheckListPointers(t, l, []*Element{e4, e1, e2, e3})\n\t\te1, e2, e3, e4 = e4, e1, e2, e3\n\n\t\tl.MoveAfter(e4, e1)\n\t\tcheckListPointers(t, l, []*Element{e1, e4, e2, e3})\n\t\te2, e3, e4 = e4, e2, e3\n\n\t\tl.MoveAfter(e2, e3)\n\t\tcheckListPointers(t, l, []*Element{e1, e3, e2, e4})\n\t\te2, e3 = e3, e2\n\t})\n}\n\n// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List\nfunc TestZeroList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l1 = New()\n\t\tl1.PushFront(1)\n\t\tcheckList(t, l1, []any{1})\n\n\t\tvar l2 = New()\n\t\tl2.PushBack(1)\n\t\tcheckList(t, l2, []any{1})\n\n\t\tvar l3 = New()\n\t\tl3.PushFrontList(l1)\n\t\tcheckList(t, l3, []any{1})\n\n\t\tvar l4 = New()\n\t\tl4.PushBackList(l2)\n\t\tcheckList(t, l4, []any{1})\n\t})\n}\n\n// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.\nfunc TestInsertBeforeUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tl.PushBack(1)\n\t\tl.PushBack(2)\n\t\tl.PushBack(3)\n\t\tl.InsertBefore(new(Element), 1)\n\t\tcheckList(t, l, []any{1, 2, 3})\n\t})\n}\n\n// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.\nfunc TestInsertAfterUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tl.PushBack(1)\n\t\tl.PushBack(2)\n\t\tl.PushBack(3)\n\t\tl.InsertAfter(new(Element), 1)\n\t\tcheckList(t, l, []any{1, 2, 3})\n\t})\n}\n\n// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.\nfunc TestMoveUnknownMark(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl1 := New()\n\t\te1 := l1.PushBack(1)\n\n\t\tl2 := New()\n\t\te2 := l2.PushBack(2)\n\n\t\tl1.MoveAfter(e1, e2)\n\t\tcheckList(t, l1, []any{1})\n\t\tcheckList(t, l2, []any{2})\n\n\t\tl1.MoveBefore(e1, e2)\n\t\tcheckList(t, l1, []any{1})\n\t\tcheckList(t, l2, []any{2})\n\t})\n}\n\nfunc TestList_RemoveAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tl.PushBack(1)\n\t\tl.RemoveAll()\n\t\tcheckList(t, l, []any{})\n\t\tl.PushBack(2)\n\t\tcheckList(t, l, []any{2})\n\t})\n}\n\nfunc TestList_PushFronts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2}\n\t\tl.PushFronts(a1)\n\t\tcheckList(t, l, []any{2, 1})\n\t\ta1 = []any{3, 4, 5}\n\t\tl.PushFronts(a1)\n\t\tcheckList(t, l, []any{5, 4, 3, 2, 1})\n\t})\n}\n\nfunc TestList_PushBacks(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2}\n\t\tl.PushBacks(a1)\n\t\tcheckList(t, l, []any{1, 2})\n\t\ta1 = []any{3, 4, 5}\n\t\tl.PushBacks(a1)\n\t\tcheckList(t, l, []any{1, 2, 3, 4, 5})\n\t})\n}\n\nfunc TestList_PopBacks(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\ta2 := []any{\"a\", \"c\", \"b\", \"e\"}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopBacks(2)\n\t\tt.Assert(i1, []any{1, 2})\n\n\t\tl.PushBacks(a2) // 4.3,a,c,b,e\n\t\ti1 = l.PopBacks(3)\n\t\tt.Assert(i1, []any{\"e\", \"b\", \"c\"})\n\t})\n}\n\nfunc TestList_PopFronts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopFronts(2)\n\t\tt.Assert(i1, []any{4, 3})\n\t\tt.Assert(l.Len(), 2)\n\t})\n}\n\nfunc TestList_PopBackAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopBackAll()\n\t\tt.Assert(i1, []any{1, 2, 3, 4})\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestList_PopFrontAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.PopFrontAll()\n\t\tt.Assert(i1, []any{4, 3, 2, 1})\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestList_FrontAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.FrontAll()\n\t\tt.Assert(i1, []any{4, 3, 2, 1})\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestList_BackAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.BackAll()\n\t\tt.Assert(i1, []any{1, 2, 3, 4})\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestList_FrontValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tl2 := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.FrontValue()\n\t\tt.Assert(gconv.Int(i1), 4)\n\t\tt.Assert(l.Len(), 4)\n\n\t\ti1 = l2.FrontValue()\n\t\tt.Assert(i1, nil)\n\t})\n}\n\nfunc TestList_BackValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tl2 := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\ti1 := l.BackValue()\n\t\tt.Assert(gconv.Int(i1), 1)\n\t\tt.Assert(l.Len(), 4)\n\n\t\ti1 = l2.FrontValue()\n\t\tt.Assert(i1, nil)\n\t})\n}\n\nfunc TestList_Back(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tt.Assert(e1.Value, 1)\n\t\tt.Assert(l.Len(), 4)\n\t})\n}\n\nfunc TestList_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\tt.Assert(l.Size(), 4)\n\t\tl.PopFront()\n\t\tt.Assert(l.Size(), 3)\n\t})\n}\n\nfunc TestList_Removes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tl.Removes([]*Element{e1})\n\t\tt.Assert(l.Len(), 3)\n\n\t\te2 := l.Back()\n\t\tl.Removes([]*Element{e2})\n\t\tt.Assert(l.Len(), 2)\n\t\tcheckList(t, l, []any{4, 3})\n\t})\n}\n\nfunc TestList_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewFrom([]any{1, 2, 3, 4, 5, 6, 7, 8, 9})\n\n\t\tt.Assert(l.PopBack(), 9)\n\t\tt.Assert(l.PopBacks(2), []any{8, 7})\n\t\tt.Assert(l.PopFront(), 1)\n\t\tt.Assert(l.PopFronts(2), []any{2, 3})\n\t})\n}\n\nfunc TestList_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\tl.Clear()\n\t\tt.Assert(l.Len(), 0)\n\t})\n}\n\nfunc TestList_IteratorAsc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 5, 6, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *Element) bool {\n\t\t\treturn gconv.Int(e1.Value) > 2\n\t\t}\n\t\tcheckList(t, l, []any{4, 3, 6, 5, 2, 1})\n\t\tl.IteratorAsc(fun1)\n\t\tcheckList(t, l, []any{4, 3, 6, 5, 2, 1})\n\t})\n}\n\nfunc TestList_IteratorDesc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{1, 2, 3, 4}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *Element) bool {\n\t\t\treturn gconv.Int(e1.Value) > 6\n\t\t}\n\t\tl.IteratorDesc(fun1)\n\t\tt.Assert(l.Len(), 4)\n\t\tcheckList(t, l, []any{4, 3, 2, 1})\n\t})\n}\n\nfunc TestList_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\ta1 := []any{\"a\", \"b\", \"c\", \"d\", \"e\"}\n\t\tl.PushFronts(a1)\n\t\te1 := l.Back()\n\t\tfun1 := func(e *Element) bool {\n\t\t\treturn gconv.String(e1.Value) > \"c\"\n\t\t}\n\t\tcheckList(t, l, []any{\"e\", \"d\", \"c\", \"b\", \"a\"})\n\t\tl.Iterator(fun1)\n\t\tcheckList(t, l, []any{\"e\", \"d\", \"c\", \"b\", \"a\"})\n\t})\n}\n\nfunc TestList_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tt.Assert(l.Join(\",\"), `1,2,a,\"b\",\\c`)\n\t\tt.Assert(l.Join(\".\"), `1.2.a.\"b\".\\c`)\n\t})\n}\n\nfunc TestList_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tt.Assert(l.String(), `[1,2,a,\"b\",\\c]`)\n\t})\n}\n\nfunc TestList_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tl := New()\n\t\tl.PushBacks(a)\n\t\tb1, err1 := json.Marshal(l)\n\t\tb2, err2 := json.Marshal(a)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tl := New()\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, l)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), a)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar l List\n\t\ta := []any{\"a\", \"b\", \"c\"}\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, &l)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.FrontAll(), a)\n\t})\n}\n\nfunc TestList_UnmarshalValue(t *testing.T) {\n\ttype TList struct {\n\t\tName string\n\t\tList *List\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tlist *TList\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"list\": []byte(`[1,2,3]`),\n\t\t}, &tlist)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tlist.Name, \"john\")\n\t\tt.Assert(tlist.List.FrontAll(), []any{1, 2, 3})\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tlist *TList\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"list\": []any{1, 2, 3},\n\t\t}, &tlist)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tlist.Name, \"john\")\n\t\tt.Assert(tlist.List.FrontAll(), []any{1, 2, 3})\n\t})\n}\n\nfunc TestList_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := NewFrom([]any{1, 2, \"a\", `\"b\"`, `\\c`})\n\t\tcopyList := l.DeepCopy()\n\t\tcl := copyList.(*List)\n\t\tcl.PopBack()\n\t\tt.AssertNE(l.Size(), cl.Size())\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmap provides most commonly used map container which also support concurrent-safe/unsafe switch feature.\npackage gmap\n\ntype (\n\tMap     = AnyAnyMap // Map is alias of AnyAnyMap.\n\tHashMap = AnyAnyMap // HashMap is alias of AnyAnyMap.\n)\n\n// New creates and returns an empty hash map.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc New(safe ...bool) *Map {\n\treturn NewAnyAnyMap(safe...)\n}\n\n// NewFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewFrom(data map[any]any, safe ...bool) *Map {\n\treturn NewAnyAnyMapFrom(data, safe...)\n}\n\n// NewHashMap creates and returns an empty hash map.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewHashMap(safe ...bool) *Map {\n\treturn NewAnyAnyMap(safe...)\n}\n\n// NewHashMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewHashMapFrom(data map[any]any, safe ...bool) *Map {\n\treturn NewAnyAnyMapFrom(data, safe...)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_any_any_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// AnyAnyMap wraps map type `map[any]any` and provides more map features.\ntype AnyAnyMap struct {\n\t*KVMap[any, any]\n\tonce sync.Once\n}\n\n// NewAnyAnyMap creates and returns an empty hash map.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewAnyAnyMap(safe ...bool) *AnyAnyMap {\n\tm := &AnyAnyMap{\n\t\tKVMap: NewKVMap[any, any](safe...),\n\t}\n\treturn m\n}\n\n// NewAnyAnyMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewAnyAnyMapFrom(data map[any]any, safe ...bool) *AnyAnyMap {\n\tm := &AnyAnyMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n\treturn m\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *AnyAnyMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[any, any](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *AnyAnyMap) Iterator(f func(k any, v any) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *AnyAnyMap) Clone(safe ...bool) *AnyAnyMap {\n\tm.lazyInit()\n\treturn NewAnyAnyMapFrom(m.MapCopy(), safe...)\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *AnyAnyMap) Map() map[any]any {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapCopy returns a shallow copy of the underlying data of the hash map.\nfunc (m *AnyAnyMap) MapCopy() map[any]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *AnyAnyMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *AnyAnyMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// FilterNil deletes all key-value pair of which the value is nil.\nfunc (m *AnyAnyMap) FilterNil() {\n\tm.lazyInit()\n\tm.KVMap.FilterNil()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *AnyAnyMap) Set(key any, value any) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, value)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *AnyAnyMap) Sets(data map[any]any) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *AnyAnyMap) Search(key any) (value any, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *AnyAnyMap) Get(key any) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *AnyAnyMap) Pop() (key, value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *AnyAnyMap) Pops(size int) map[any]any {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *AnyAnyMap) GetOrSet(key any, value any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *AnyAnyMap) GetOrSetFunc(key any, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *AnyAnyMap) GetOrSetFuncLock(key any, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *AnyAnyMap) GetVar(key any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVar(key)\n}\n\n// GetVarOrSet returns a Var with result from GetOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *AnyAnyMap) GetVarOrSet(key any, value any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *AnyAnyMap) GetVarOrSetFunc(key any, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *AnyAnyMap) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *AnyAnyMap) SetIfNotExist(key any, value any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *AnyAnyMap) SetIfNotExistFunc(key any, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *AnyAnyMap) SetIfNotExistFuncLock(key any, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *AnyAnyMap) Remove(key any) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *AnyAnyMap) Removes(keys []any) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *AnyAnyMap) Keys() []any {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *AnyAnyMap) Values() []any {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *AnyAnyMap) Contains(key any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *AnyAnyMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *AnyAnyMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *AnyAnyMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *AnyAnyMap) Replace(data map[any]any) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *AnyAnyMap) LockFunc(f func(m map[any]any)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *AnyAnyMap) RLockFunc(f func(m map[any]any)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *AnyAnyMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[any]any, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[v] = k\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *AnyAnyMap) Merge(other *AnyAnyMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *AnyAnyMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m AnyAnyMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *AnyAnyMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *AnyAnyMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *AnyAnyMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &AnyAnyMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[any, any]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *AnyAnyMap) IsSubOf(other *AnyAnyMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *AnyAnyMap) Diff(other *AnyAnyMap) (addedKeys, removedKeys, updatedKeys []any) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_int_any_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// IntAnyMap implements map[int]any with RWMutex that has switch.\ntype IntAnyMap struct {\n\t*KVMap[int, any]\n\tonce sync.Once\n}\n\n// NewIntAnyMap returns an empty IntAnyMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewIntAnyMap(safe ...bool) *IntAnyMap {\n\tm := &IntAnyMap{\n\t\tKVMap: NewKVMap[int, any](safe...),\n\t}\n\treturn m\n}\n\n// NewIntAnyMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewIntAnyMapFrom(data map[int]any, safe ...bool) *IntAnyMap {\n\tm := &IntAnyMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n\treturn m\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *IntAnyMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[int, any](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *IntAnyMap) Iterator(f func(k int, v any) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *IntAnyMap) Clone(safe ...bool) *IntAnyMap {\n\tm.lazyInit()\n\treturn NewIntAnyMapFrom(m.MapCopy(), safe...)\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *IntAnyMap) Map() map[int]any {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *IntAnyMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *IntAnyMap) MapCopy() map[int]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *IntAnyMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// FilterNil deletes all key-value pair of which the value is nil.\nfunc (m *IntAnyMap) FilterNil() {\n\tm.lazyInit()\n\tm.KVMap.FilterNil()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *IntAnyMap) Set(key int, val any) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *IntAnyMap) Sets(data map[int]any) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *IntAnyMap) Search(key int) (value any, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *IntAnyMap) Get(key int) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *IntAnyMap) Pop() (key int, value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *IntAnyMap) Pops(size int) map[int]any {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *IntAnyMap) GetOrSet(key int, value any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\nfunc (m *IntAnyMap) GetOrSetFunc(key int, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *IntAnyMap) GetOrSetFuncLock(key int, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *IntAnyMap) GetVar(key int) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVar(key)\n}\n\n// GetVarOrSet returns a Var with result from GetVarOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *IntAnyMap) GetVarOrSet(key int, value any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *IntAnyMap) GetVarOrSetFunc(key int, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *IntAnyMap) GetVarOrSetFuncLock(key int, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntAnyMap) SetIfNotExist(key int, value any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntAnyMap) SetIfNotExistFunc(key int, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *IntAnyMap) SetIfNotExistFuncLock(key int, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *IntAnyMap) Removes(keys []int) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *IntAnyMap) Remove(key int) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *IntAnyMap) Keys() []int {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *IntAnyMap) Values() []any {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *IntAnyMap) Contains(key int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *IntAnyMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *IntAnyMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *IntAnyMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *IntAnyMap) Replace(data map[int]any) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *IntAnyMap) LockFunc(f func(m map[int]any)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *IntAnyMap) RLockFunc(f func(m map[int]any)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *IntAnyMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[int]any, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[gconv.Int(v)] = k\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *IntAnyMap) Merge(other *IntAnyMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *IntAnyMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m IntAnyMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *IntAnyMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *IntAnyMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *IntAnyMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &IntAnyMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[int, any]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *IntAnyMap) IsSubOf(other *IntAnyMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *IntAnyMap) Diff(other *IntAnyMap) (addedKeys, removedKeys, updatedKeys []int) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_int_int_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport \"sync\"\n\n// IntIntMap implements map[int]int with RWMutex that has switch.\ntype IntIntMap struct {\n\t*KVMap[int, int]\n\tonce sync.Once\n}\n\n// NewIntIntMap returns an empty IntIntMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewIntIntMap(safe ...bool) *IntIntMap {\n\treturn &IntIntMap{\n\t\tKVMap: NewKVMap[int, int](safe...),\n\t}\n}\n\n// NewIntIntMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap {\n\treturn &IntIntMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *IntIntMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[int, int](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *IntIntMap) Iterator(f func(k int, v int) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *IntIntMap) Clone(safe ...bool) *IntIntMap {\n\tm.lazyInit()\n\treturn &IntIntMap{KVMap: m.KVMap.Clone(safe...)}\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *IntIntMap) Map() map[int]int {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *IntIntMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *IntIntMap) MapCopy() map[int]int {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *IntIntMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *IntIntMap) Set(key int, val int) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *IntIntMap) Sets(data map[int]int) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *IntIntMap) Search(key int) (value int, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *IntIntMap) Get(key int) (value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *IntIntMap) Pop() (key, value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *IntIntMap) Pops(size int) map[int]int {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *IntIntMap) GetOrSet(key int, value int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\nfunc (m *IntIntMap) GetOrSetFunc(key int, f func() int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntIntMap) SetIfNotExist(key int, value int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *IntIntMap) SetIfNotExistFuncLock(key int, f func() int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *IntIntMap) Removes(keys []int) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *IntIntMap) Remove(key int) (value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *IntIntMap) Keys() []int {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *IntIntMap) Values() []int {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *IntIntMap) Contains(key int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *IntIntMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *IntIntMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *IntIntMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *IntIntMap) Replace(data map[int]int) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *IntIntMap) LockFunc(f func(m map[int]int)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *IntIntMap) RLockFunc(f func(m map[int]int)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *IntIntMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[int]int, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[v] = k\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *IntIntMap) Merge(other *IntIntMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *IntIntMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m IntIntMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *IntIntMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *IntIntMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *IntIntMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &IntIntMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[int, int]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *IntIntMap) IsSubOf(other *IntIntMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *IntIntMap) Diff(other *IntIntMap) (addedKeys, removedKeys, updatedKeys []int) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_int_str_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// IntStrMap implements map[int]string with RWMutex that has switch.\ntype IntStrMap struct {\n\t*KVMap[int, string]\n\tonce sync.Once\n}\n\n// NewIntStrMap returns an empty IntStrMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewIntStrMap(safe ...bool) *IntStrMap {\n\treturn &IntStrMap{\n\t\tKVMap: NewKVMap[int, string](safe...),\n\t}\n}\n\n// NewIntStrMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap {\n\treturn &IntStrMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *IntStrMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[int, string](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *IntStrMap) Iterator(f func(k int, v string) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *IntStrMap) Clone(safe ...bool) *IntStrMap {\n\tm.lazyInit()\n\treturn &IntStrMap{KVMap: m.KVMap.Clone(safe...)}\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *IntStrMap) Map() map[int]string {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *IntStrMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *IntStrMap) MapCopy() map[int]string {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *IntStrMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *IntStrMap) Set(key int, val string) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *IntStrMap) Sets(data map[int]string) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *IntStrMap) Search(key int) (value string, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *IntStrMap) Get(key int) (value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *IntStrMap) Pop() (key int, value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *IntStrMap) Pops(size int) map[int]string {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *IntStrMap) GetOrSet(key int, value string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\nfunc (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist and returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntStrMap) SetIfNotExist(key int, value string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *IntStrMap) Removes(keys []int) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *IntStrMap) Remove(key int) (value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *IntStrMap) Keys() []int {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *IntStrMap) Values() []string {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *IntStrMap) Contains(key int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *IntStrMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *IntStrMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *IntStrMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *IntStrMap) Replace(data map[int]string) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *IntStrMap) LockFunc(f func(m map[int]string)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *IntStrMap) RLockFunc(f func(m map[int]string)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *IntStrMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[int]string, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[gconv.Int(v)] = gconv.String(k)\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *IntStrMap) Merge(other *IntStrMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *IntStrMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m IntStrMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *IntStrMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *IntStrMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *IntStrMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &IntStrMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[int, string]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *IntStrMap) IsSubOf(other *IntStrMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *IntStrMap) Diff(other *IntStrMap) (addedKeys, removedKeys, updatedKeys []int) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_k_v_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// NilChecker is a function that checks whether the given value is nil.\ntype NilChecker[V any] func(V) bool\n\n// KVMap wraps map type `map[K]V` and provides more map features.\ntype KVMap[K comparable, V any] struct {\n\tmu   rwmutex.RWMutex\n\tdata map[K]V\n\n\t// nilChecker is the custom nil checker function.\n\t// It uses empty.IsNil if it's nil.\n\tnilChecker NilChecker[V]\n}\n\n// NewKVMap creates and returns an empty hash map.\n// The parameter `safe` is used to specify whether to use the map in concurrent-safety mode, which is false by default.\nfunc NewKVMap[K comparable, V any](safe ...bool) *KVMap[K, V] {\n\treturn NewKVMapFrom(make(map[K]V), safe...)\n}\n\n// NewKVMapWithChecker creates and returns an empty hash map with a custom nil checker.\n// The parameter `checker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether to use the map in concurrent-safety mode, which is false by default.\nfunc NewKVMapWithChecker[K comparable, V any](checker NilChecker[V], safe ...bool) *KVMap[K, V] {\n\treturn NewKVMapWithCheckerFrom(make(map[K]V), checker, safe...)\n}\n\n// NewKVMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map (no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewKVMapFrom[K comparable, V any](data map[K]V, safe ...bool) *KVMap[K, V] {\n\tm := &KVMap[K, V]{\n\t\tmu:   rwmutex.Create(safe...),\n\t\tdata: data,\n\t}\n\treturn m\n}\n\n// NewKVMapWithCheckerFrom creates and returns a hash map from given map `data` with a custom nil checker.\n// Note that, the param `data` map will be set as the underlying data map (no deep copy),\n// and there might be some concurrent-safe issues when changing the map outside.\n// The parameter `checker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether to use the map in concurrent-safety mode, which is false by default.\nfunc NewKVMapWithCheckerFrom[K comparable, V any](data map[K]V, checker NilChecker[V], safe ...bool) *KVMap[K, V] {\n\tm := NewKVMapFrom[K, V](data, safe...)\n\tm.SetNilChecker(checker)\n\treturn m\n}\n\n// SetNilChecker registers a custom nil checker function for the map values.\n// This function is used to determine if a value should be considered as nil.\n// The nil checker function takes a value of type V and returns a boolean indicating\n// whether the value should be treated as nil.\nfunc (m *KVMap[K, V]) SetNilChecker(nilChecker NilChecker[V]) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tm.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (m *KVMap[K, V]) isNil(v V) bool {\n\tif m.nilChecker != nil {\n\t\treturn m.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *KVMap[K, V]) Iterator(f func(k K, v V) bool) {\n\tfor k, v := range m.Map() {\n\t\tif !f(k, v) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *KVMap[K, V]) Clone(safe ...bool) *KVMap[K, V] {\n\tif len(safe) == 0 {\n\t\treturn NewKVMapFrom(m.MapCopy(), m.mu.IsSafe())\n\t}\n\treturn NewKVMapFrom(m.MapCopy(), safe...)\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *KVMap[K, V]) Map() map[K]V {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tif !m.mu.IsSafe() {\n\t\treturn m.data\n\t}\n\tdata := make(map[K]V, len(m.data))\n\tfor k, v := range m.data {\n\t\tdata[k] = v\n\t}\n\treturn data\n}\n\n// MapCopy returns a shallow copy of the underlying data of the hash map.\nfunc (m *KVMap[K, V]) MapCopy() map[K]V {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tdata := make(map[K]V, len(m.data))\n\tfor k, v := range m.data {\n\t\tdata[k] = v\n\t}\n\treturn data\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *KVMap[K, V]) MapStrAny() map[string]any {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tdata := make(map[string]any, len(m.data))\n\tfor k, v := range m.data {\n\t\tdata[gconv.String(k)] = v\n\t}\n\treturn data\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *KVMap[K, V]) FilterEmpty() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tfor k, v := range m.data {\n\t\tif empty.IsEmpty(v) {\n\t\t\tdelete(m.data, k)\n\t\t}\n\t}\n}\n\n// FilterNil deletes all key-value pair of which the value is nil.\nfunc (m *KVMap[K, V]) FilterNil() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tfor k, v := range m.data {\n\t\tif empty.IsNil(v) {\n\t\t\tdelete(m.data, k)\n\t\t}\n\t}\n}\n\n// Set sets key-value to the hash map.\nfunc (m *KVMap[K, V]) Set(key K, value V) {\n\tm.mu.Lock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tm.data[key] = value\n\tm.mu.Unlock()\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *KVMap[K, V]) Sets(data map[K]V) {\n\tm.mu.Lock()\n\tif m.data == nil {\n\t\tm.data = data\n\t} else {\n\t\tfor k, v := range data {\n\t\t\tm.data[k] = v\n\t\t}\n\t}\n\tm.mu.Unlock()\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *KVMap[K, V]) Search(key K) (value V, found bool) {\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\tvalue, found = m.data[key]\n\t}\n\tm.mu.RUnlock()\n\treturn\n}\n\n// Get returns the value by given `key`.\nfunc (m *KVMap[K, V]) Get(key K) (value V) {\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\tvalue = m.data[key]\n\t}\n\tm.mu.RUnlock()\n\treturn\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *KVMap[K, V]) Pop() (key K, value V) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tfor key, value = range m.data {\n\t\tdelete(m.data, key)\n\t\treturn\n\t}\n\treturn\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *KVMap[K, V]) Pops(size int) map[K]V {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif size > len(m.data) || size == -1 {\n\t\tsize = len(m.data)\n\t}\n\tif size == 0 {\n\t\treturn nil\n\t}\n\tvar (\n\t\tindex  = 0\n\t\tnewMap = make(map[K]V, size)\n\t)\n\tfor k, v := range m.data {\n\t\tdelete(m.data, k)\n\t\tnewMap[k] = v\n\t\tindex++\n\t\tif index == size {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn newMap\n}\n\n// doSetWithLockCheck sets value with given `value` if it does not exist,\n// and then returns this value and whether it exists.\n//\n// It is a helper function for GetOrSet* functions.\n//\n// Note that, it does not add the value to the map if the given `value` is nil.\nfunc (m *KVMap[K, V]) doSetWithLockCheck(key K, value V) (val V, ok bool) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\n\tif v, ok := m.data[key]; ok {\n\t\treturn v, true\n\t}\n\tif !m.isNil(value) {\n\t\tm.data[key] = value\n\t}\n\treturn value, false\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *KVMap[K, V]) GetOrSet(key K, value V) V {\n\tv, _ := m.doSetWithLockCheck(key, value)\n\treturn v\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// Note that, it does not add the value to the map if the returned value of `f` is nil.\nfunc (m *KVMap[K, V]) GetOrSetFunc(key K, f func() V) V {\n\tv, _ := m.doSetWithLockCheck(key, f())\n\treturn v\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\n//\n// Note that, it does not add the value to the map if the returned value of `f` is nil.\nfunc (m *KVMap[K, V]) GetOrSetFuncLock(key K, f func() V) V {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tif v, ok := m.data[key]; ok {\n\t\treturn v\n\t}\n\tvalue := f()\n\tif !m.isNil(value) {\n\t\tm.data[key] = value\n\t}\n\treturn value\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *KVMap[K, V]) GetVar(key K) *gvar.Var {\n\treturn gvar.New(m.Get(key))\n}\n\n// GetVarOrSet returns a Var with result from GetOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *KVMap[K, V]) GetVarOrSet(key K, value V) *gvar.Var {\n\treturn gvar.New(m.GetOrSet(key, value))\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *KVMap[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {\n\treturn gvar.New(m.GetOrSetFunc(key, f))\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *KVMap[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {\n\treturn gvar.New(m.GetOrSetFuncLock(key, f))\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *KVMap[K, V]) SetIfNotExist(key K, value V) bool {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tif _, ok := m.data[key]; !ok {\n\t\tm.data[key] = value\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *KVMap[K, V]) SetIfNotExistFunc(key K, f func() V) bool {\n\tif !m.Contains(key) {\n\t\treturn m.SetIfNotExist(key, f())\n\t}\n\treturn false\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *KVMap[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tif _, ok := m.data[key]; !ok {\n\t\tm.data[key] = f()\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *KVMap[K, V]) Remove(key K) (value V) {\n\tm.mu.Lock()\n\tif m.data != nil {\n\t\tvar ok bool\n\t\tif value, ok = m.data[key]; ok {\n\t\t\tdelete(m.data, key)\n\t\t}\n\t}\n\tm.mu.Unlock()\n\treturn\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *KVMap[K, V]) Removes(keys []K) {\n\tm.mu.Lock()\n\tif m.data != nil {\n\t\tfor _, key := range keys {\n\t\t\tdelete(m.data, key)\n\t\t}\n\t}\n\tm.mu.Unlock()\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *KVMap[K, V]) Keys() []K {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tvar (\n\t\tkeys  = make([]K, len(m.data))\n\t\tindex = 0\n\t)\n\tfor key := range m.data {\n\t\tkeys[index] = key\n\t\tindex++\n\t}\n\treturn keys\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *KVMap[K, V]) Values() []V {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tvar (\n\t\tvalues = make([]V, len(m.data))\n\t\tindex  = 0\n\t)\n\tfor _, value := range m.data {\n\t\tvalues[index] = value\n\t\tindex++\n\t}\n\treturn values\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *KVMap[K, V]) Contains(key K) bool {\n\tvar ok bool\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\t_, ok = m.data[key]\n\t}\n\tm.mu.RUnlock()\n\treturn ok\n}\n\n// Size returns the size of the map.\nfunc (m *KVMap[K, V]) Size() int {\n\tm.mu.RLock()\n\tlength := len(m.data)\n\tm.mu.RUnlock()\n\treturn length\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *KVMap[K, V]) IsEmpty() bool {\n\treturn m.Size() == 0\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *KVMap[K, V]) Clear() {\n\tm.mu.Lock()\n\tm.data = make(map[K]V)\n\tm.mu.Unlock()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *KVMap[K, V]) Replace(data map[K]V) {\n\tm.mu.Lock()\n\tm.data = data\n\tm.mu.Unlock()\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *KVMap[K, V]) LockFunc(f func(m map[K]V)) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tf(m.data)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *KVMap[K, V]) RLockFunc(f func(m map[K]V)) {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tf(m.data)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *KVMap[K, V]) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[K]V, len(m.data))\n\tfor k, v := range m.data {\n\t\tvar (\n\t\t\tk0 K\n\t\t\tv0 V\n\t\t)\n\t\tif err := gconv.Scan(v, &k0); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif err := gconv.Scan(k, &v0); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tn[k0] = v0\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *KVMap[K, V]) Merge(other *KVMap[K, V]) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = other.MapCopy()\n\t\treturn\n\t}\n\tif other != m {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tfor k, v := range other.data {\n\t\tm.data[k] = v\n\t}\n}\n\n// String returns the map as a string.\nfunc (m *KVMap[K, V]) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tb, _ := m.MarshalJSON()\n\treturn string(b)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// DO NOT change this receiver to pointer type, as the KVMap can be used as a var defined variable, like:\n// var m gmap.KVMap[int, string]\n// Please refer to corresponding tests for more details.\nfunc (m KVMap[K, V]) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(gconv.Map(m.Map()))\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *KVMap[K, V]) UnmarshalJSON(b []byte) error {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tvar data map[string]V\n\tif err := json.UnmarshalUseNumber(b, &data); err != nil {\n\t\treturn err\n\t}\n\tif err := gconv.Scan(data, &m.data); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *KVMap[K, V]) UnmarshalValue(value any) (err error) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]V)\n\t}\n\tdata := gconv.Map(value)\n\tif err := gconv.Scan(data, &m.data); err != nil {\n\t\treturn err\n\t}\n\treturn\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *KVMap[K, V]) DeepCopy() any {\n\tif m == nil {\n\t\treturn nil\n\t}\n\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tdata := make(map[K]V, len(m.data))\n\tfor k, v := range m.data {\n\t\tdata[k] = deepcopy.Copy(v).(V)\n\t}\n\treturn NewKVMapFrom(data, m.mu.IsSafe())\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *KVMap[K, V]) IsSubOf(other *KVMap[K, V]) bool {\n\tif m == other {\n\t\treturn true\n\t}\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tother.mu.RLock()\n\tdefer other.mu.RUnlock()\n\tfor key, value := range m.data {\n\t\totherValue, ok := other.data[key]\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\tif !reflect.DeepEqual(otherValue, value) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *KVMap[K, V]) Diff(other *KVMap[K, V]) (addedKeys, removedKeys, updatedKeys []K) {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tother.mu.RLock()\n\tdefer other.mu.RUnlock()\n\n\tfor key := range m.data {\n\t\tif _, ok := other.data[key]; !ok {\n\t\t\tremovedKeys = append(removedKeys, key)\n\t\t} else if !reflect.DeepEqual(m.data[key], other.data[key]) {\n\t\t\tupdatedKeys = append(updatedKeys, key)\n\t\t}\n\t}\n\tfor key := range other.data {\n\t\tif _, ok := m.data[key]; !ok {\n\t\t\taddedKeys = append(addedKeys, key)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_str_any_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// StrAnyMap implements map[string]any with RWMutex that has switch.\ntype StrAnyMap struct {\n\t*KVMap[string, any]\n\tonce sync.Once\n}\n\n// NewStrAnyMap returns an empty StrAnyMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewStrAnyMap(safe ...bool) *StrAnyMap {\n\tm := &StrAnyMap{\n\t\tKVMap: NewKVMap[string, any](safe...),\n\t}\n\treturn m\n}\n\n// NewStrAnyMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewStrAnyMapFrom(data map[string]any, safe ...bool) *StrAnyMap {\n\tm := &StrAnyMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n\treturn m\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *StrAnyMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[string, any](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *StrAnyMap) Iterator(f func(k string, v any) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *StrAnyMap) Clone(safe ...bool) *StrAnyMap {\n\tm.lazyInit()\n\treturn NewStrAnyMapFrom(m.MapCopy(), safe...)\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *StrAnyMap) Map() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *StrAnyMap) MapStrAny() map[string]any {\n\treturn m.Map()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *StrAnyMap) MapCopy() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *StrAnyMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// FilterNil deletes all key-value pair of which the value is nil.\nfunc (m *StrAnyMap) FilterNil() {\n\tm.lazyInit()\n\tm.KVMap.FilterNil()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *StrAnyMap) Set(key string, val any) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *StrAnyMap) Sets(data map[string]any) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *StrAnyMap) Search(key string) (value any, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *StrAnyMap) Get(key string) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *StrAnyMap) Pop() (key string, value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *StrAnyMap) Pops(size int) map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *StrAnyMap) GetOrSet(key string, value any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *StrAnyMap) GetOrSetFunc(key string, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *StrAnyMap) GetOrSetFuncLock(key string, f func() any) any {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *StrAnyMap) GetVar(key string) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVar(key)\n}\n\n// GetVarOrSet returns a Var with result from GetVarOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *StrAnyMap) GetVarOrSet(key string, value any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *StrAnyMap) GetVarOrSetFunc(key string, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.KVMap.GetVarOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrAnyMap) SetIfNotExist(key string, value any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrAnyMap) SetIfNotExistFunc(key string, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() any) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *StrAnyMap) Removes(keys []string) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *StrAnyMap) Remove(key string) (value any) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *StrAnyMap) Keys() []string {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *StrAnyMap) Values() []any {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *StrAnyMap) Contains(key string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *StrAnyMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *StrAnyMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *StrAnyMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *StrAnyMap) Replace(data map[string]any) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *StrAnyMap) LockFunc(f func(m map[string]any)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *StrAnyMap) RLockFunc(f func(m map[string]any)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *StrAnyMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[string]any, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[gconv.String(v)] = k\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *StrAnyMap) Merge(other *StrAnyMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *StrAnyMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m StrAnyMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *StrAnyMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *StrAnyMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *StrAnyMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &StrAnyMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[string, any]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *StrAnyMap) Diff(other *StrAnyMap) (addedKeys, removedKeys, updatedKeys []string) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_str_int_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// StrIntMap implements map[string]int with RWMutex that has switch.\ntype StrIntMap struct {\n\t*KVMap[string, int]\n\tonce sync.Once\n}\n\n// NewStrIntMap returns an empty StrIntMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewStrIntMap(safe ...bool) *StrIntMap {\n\treturn &StrIntMap{\n\t\tKVMap: NewKVMap[string, int](safe...),\n\t}\n}\n\n// NewStrIntMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap {\n\treturn &StrIntMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *StrIntMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[string, int](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *StrIntMap) Iterator(f func(k string, v int) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *StrIntMap) Clone(safe ...bool) *StrIntMap {\n\tm.lazyInit()\n\treturn &StrIntMap{KVMap: m.KVMap.Clone(safe...)}\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *StrIntMap) Map() map[string]int {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *StrIntMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *StrIntMap) MapCopy() map[string]int {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *StrIntMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *StrIntMap) Set(key string, val int) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *StrIntMap) Sets(data map[string]int) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *StrIntMap) Search(key string) (value int, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *StrIntMap) Get(key string) (value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *StrIntMap) Pop() (key string, value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *StrIntMap) Pops(size int) map[string]int {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *StrIntMap) GetOrSet(key string, value int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrIntMap) SetIfNotExist(key string, value int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *StrIntMap) SetIfNotExistFuncLock(key string, f func() int) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *StrIntMap) Removes(keys []string) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *StrIntMap) Remove(key string) (value int) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *StrIntMap) Keys() []string {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *StrIntMap) Values() []int {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *StrIntMap) Contains(key string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *StrIntMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *StrIntMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *StrIntMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *StrIntMap) Replace(data map[string]int) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *StrIntMap) LockFunc(f func(m map[string]int)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *StrIntMap) RLockFunc(f func(m map[string]int)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *StrIntMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[string]int, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[gconv.String(v)] = gconv.Int(k)\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *StrIntMap) Merge(other *StrIntMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *StrIntMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m StrIntMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *StrIntMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *StrIntMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *StrIntMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &StrIntMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[string, int]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *StrIntMap) IsSubOf(other *StrIntMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *StrIntMap) Diff(other *StrIntMap) (addedKeys, removedKeys, updatedKeys []string) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_hash_str_str_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gmap\n\nimport \"sync\"\n\n// StrStrMap implements map[string]string with RWMutex that has switch.\ntype StrStrMap struct {\n\t*KVMap[string, string]\n\tonce sync.Once\n}\n\n// NewStrStrMap returns an empty StrStrMap object.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewStrStrMap(safe ...bool) *StrStrMap {\n\treturn &StrStrMap{\n\t\tKVMap: NewKVMap[string, string](safe...),\n\t}\n}\n\n// NewStrStrMapFrom creates and returns a hash map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap {\n\treturn &StrStrMap{\n\t\tKVMap: NewKVMapFrom(data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the map.\nfunc (m *StrStrMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.KVMap == nil {\n\t\t\tm.KVMap = NewKVMap[string, string](false)\n\t\t}\n\t})\n}\n\n// Iterator iterates the hash map readonly with custom callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *StrStrMap) Iterator(f func(k string, v string) bool) {\n\tm.lazyInit()\n\tm.KVMap.Iterator(f)\n}\n\n// Clone returns a new hash map with copy of current map data.\nfunc (m *StrStrMap) Clone(safe ...bool) *StrStrMap {\n\tm.lazyInit()\n\treturn &StrStrMap{KVMap: m.KVMap.Clone(safe...)}\n}\n\n// Map returns the underlying data map.\n// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,\n// or else a pointer to the underlying data.\nfunc (m *StrStrMap) Map() map[string]string {\n\tm.lazyInit()\n\treturn m.KVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *StrStrMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.KVMap.MapStrAny()\n}\n\n// MapCopy returns a copy of the underlying data of the hash map.\nfunc (m *StrStrMap) MapCopy() map[string]string {\n\tm.lazyInit()\n\treturn m.KVMap.MapCopy()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\n// Values like: 0, nil, false, \"\", len(slice/map/chan) == 0 are considered empty.\nfunc (m *StrStrMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.KVMap.FilterEmpty()\n}\n\n// Set sets key-value to the hash map.\nfunc (m *StrStrMap) Set(key string, val string) {\n\tm.lazyInit()\n\tm.KVMap.Set(key, val)\n}\n\n// Sets batch sets key-values to the hash map.\nfunc (m *StrStrMap) Sets(data map[string]string) {\n\tm.lazyInit()\n\tm.KVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *StrStrMap) Search(key string) (value string, found bool) {\n\tm.lazyInit()\n\treturn m.KVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *StrStrMap) Get(key string) (value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *StrStrMap) Pop() (key, value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *StrStrMap) Pops(size int) map[string]string {\n\tm.lazyInit()\n\treturn m.KVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *StrStrMap) GetOrSet(key string, value string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string {\n\tm.lazyInit()\n\treturn m.KVMap.GetOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrStrMap) SetIfNotExist(key string, value string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the hash map.\nfunc (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *StrStrMap) Removes(keys []string) {\n\tm.lazyInit()\n\tm.KVMap.Removes(keys)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *StrStrMap) Remove(key string) (value string) {\n\tm.lazyInit()\n\treturn m.KVMap.Remove(key)\n}\n\n// Keys returns all keys of the map as a slice.\nfunc (m *StrStrMap) Keys() []string {\n\tm.lazyInit()\n\treturn m.KVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *StrStrMap) Values() []string {\n\tm.lazyInit()\n\treturn m.KVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *StrStrMap) Contains(key string) bool {\n\tm.lazyInit()\n\treturn m.KVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *StrStrMap) Size() int {\n\tm.lazyInit()\n\treturn m.KVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *StrStrMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsEmpty()\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *StrStrMap) Clear() {\n\tm.lazyInit()\n\tm.KVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *StrStrMap) Replace(data map[string]string) {\n\tm.lazyInit()\n\tm.KVMap.Replace(data)\n}\n\n// LockFunc locks writing with given callback function `f` within RWMutex.Lock.\nfunc (m *StrStrMap) LockFunc(f func(m map[string]string)) {\n\tm.lazyInit()\n\tm.KVMap.LockFunc(f)\n}\n\n// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.\nfunc (m *StrStrMap) RLockFunc(f func(m map[string]string)) {\n\tm.lazyInit()\n\tm.KVMap.RLockFunc(f)\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *StrStrMap) Flip() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tn := make(map[string]string, len(m.data))\n\tfor k, v := range m.data {\n\t\tn[v] = k\n\t}\n\tm.data = n\n}\n\n// Merge merges two hash maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *StrStrMap) Merge(other *StrStrMap) {\n\tm.lazyInit()\n\tm.KVMap.Merge(other.KVMap)\n}\n\n// String returns the map as a string.\nfunc (m *StrStrMap) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tm.lazyInit()\n\treturn m.KVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m StrStrMap) MarshalJSON() ([]byte, error) {\n\tm.lazyInit()\n\treturn m.KVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *StrStrMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *StrStrMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\treturn m.KVMap.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *StrStrMap) DeepCopy() any {\n\tm.lazyInit()\n\treturn &StrStrMap{\n\t\tKVMap: m.KVMap.DeepCopy().(*KVMap[string, string]),\n\t}\n}\n\n// IsSubOf checks whether the current map is a sub-map of `other`.\nfunc (m *StrStrMap) IsSubOf(other *StrStrMap) bool {\n\tm.lazyInit()\n\treturn m.KVMap.IsSubOf(other.KVMap)\n}\n\n// Diff compares current map `m` with map `other` and returns their different keys.\n// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.\n// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.\n// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).\nfunc (m *StrStrMap) Diff(other *StrStrMap) (addedKeys, removedKeys, updatedKeys []string) {\n\tm.lazyInit()\n\treturn m.KVMap.Diff(other.KVMap)\n}\n"
  },
  {
    "path": "container/gmap/gmap_list_k_v_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ListKVMap is a map that preserves insertion-order.\n//\n// It is backed by a hash table to store values and doubly-linked list to store ordering.\n//\n// Thread-safety is optional and controlled by the `safe` parameter during initialization.\n//\n// Reference: http://en.wikipedia.org/wiki/Associative_array\ntype ListKVMap[K comparable, V any] struct {\n\tmu         rwmutex.RWMutex\n\tdata       map[K]*glist.TElement[*gListKVMapNode[K, V]]\n\tlist       *glist.TList[*gListKVMapNode[K, V]]\n\tnilChecker NilChecker[V]\n}\n\ntype gListKVMapNode[K comparable, V any] struct {\n\tkey   K\n\tvalue V\n}\n\n// NewListKVMap returns an empty link map.\n// ListKVMap is backed by a hash table to store values and doubly-linked list to store ordering.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewListKVMap[K comparable, V any](safe ...bool) *ListKVMap[K, V] {\n\treturn &ListKVMap[K, V]{\n\t\tmu:   rwmutex.Create(safe...),\n\t\tdata: make(map[K]*glist.TElement[*gListKVMapNode[K, V]]),\n\t\tlist: glist.NewT[*gListKVMapNode[K, V]](),\n\t}\n}\n\n// NewListKVMapWithChecker creates and returns a new ListKVMap instance with a custom nil checker.\n// The parameter `checker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false by default.\nfunc NewListKVMapWithChecker[K comparable, V any](checker NilChecker[V], safe ...bool) *ListKVMap[K, V] {\n\tm := NewListKVMap[K, V](safe...)\n\tm.SetNilChecker(checker)\n\treturn m\n}\n\n// NewListKVMapFrom returns a link map from given map `data`.\n// Note that, the param `data` map will be copied to the underlying data structure,\n// so changes to the original map will not affect the link map.\nfunc NewListKVMapFrom[K comparable, V any](data map[K]V, safe ...bool) *ListKVMap[K, V] {\n\tm := NewListKVMap[K, V](safe...)\n\tm.Sets(data)\n\treturn m\n}\n\n// NewListKVMapWithCheckerFrom returns a link map from given map `data` with a custom nil checker.\n// Note that, the param `data` map will be copied to the underlying data structure,\n// so changes to the original map will not affect the link map.\n// The parameter `checker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false by default.\nfunc NewListKVMapWithCheckerFrom[K comparable, V any](data map[K]V, nilChecker NilChecker[V], safe ...bool) *ListKVMap[K, V] {\n\tm := NewListKVMapWithChecker[K, V](nilChecker, safe...)\n\tm.Sets(data)\n\treturn m\n}\n\n// SetNilChecker registers a custom nil checker function for the map values.\n// This function is used to determine if a value should be considered as nil.\n// The nil checker function takes a value of type V and returns a boolean indicating\n// whether the value should be treated as nil.\nfunc (m *ListKVMap[K, V]) SetNilChecker(nilChecker NilChecker[V]) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tm.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (m *ListKVMap[K, V]) isNil(v V) bool {\n\tif m.nilChecker != nil {\n\t\treturn m.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (m *ListKVMap[K, V]) Iterator(f func(key K, value V) bool) {\n\tm.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the map readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *ListKVMap[K, V]) IteratorAsc(f func(key K, value V) bool) {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tif m.list != nil {\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\treturn f(e.Value.key, e.Value.value)\n\t\t})\n\t}\n}\n\n// IteratorDesc iterates the map readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *ListKVMap[K, V]) IteratorDesc(f func(key K, value V) bool) {\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tif m.list != nil {\n\t\tm.list.IteratorDesc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\treturn f(e.Value.key, e.Value.value)\n\t\t})\n\t}\n}\n\n// Clone returns a new link map with copy of current map data.\nfunc (m *ListKVMap[K, V]) Clone(safe ...bool) *ListKVMap[K, V] {\n\treturn NewListKVMapFrom(m.Map(), safe...)\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *ListKVMap[K, V]) Clear() {\n\tm.mu.Lock()\n\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\tm.mu.Unlock()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *ListKVMap[K, V]) Replace(data map[K]V) {\n\tm.mu.Lock()\n\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\tfor key, value := range data {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\tm.mu.Unlock()\n}\n\n// Map returns a copy of the underlying data of the map.\nfunc (m *ListKVMap[K, V]) Map() map[K]V {\n\tm.mu.RLock()\n\tvar data map[K]V\n\tif m.list != nil {\n\t\tdata = make(map[K]V, len(m.data))\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tdata[e.Value.key] = e.Value.value\n\t\t\treturn true\n\t\t})\n\t}\n\tm.mu.RUnlock()\n\treturn data\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *ListKVMap[K, V]) MapStrAny() map[string]any {\n\tm.mu.RLock()\n\tvar data map[string]any\n\tif m.list != nil {\n\t\tdata = make(map[string]any, len(m.data))\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tdata[gconv.String(e.Value.key)] = e.Value.value\n\t\t\treturn true\n\t\t})\n\t}\n\tm.mu.RUnlock()\n\treturn data\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\nfunc (m *ListKVMap[K, V]) FilterEmpty() {\n\tm.mu.Lock()\n\tif m.list != nil {\n\t\tvar keys = make([]K, 0, m.list.Size())\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tif empty.IsEmpty(e.Value.value) {\n\t\t\t\tkeys = append(keys, e.Value.key)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\n\t\tif len(keys) > 0 {\n\t\t\tfor _, key := range keys {\n\t\t\t\tif e, ok := m.data[key]; ok {\n\t\t\t\t\tdelete(m.data, key)\n\t\t\t\t\tm.list.Remove(e)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tm.mu.Unlock()\n}\n\n// Set sets key-value to the map.\nfunc (m *ListKVMap[K, V]) Set(key K, value V) {\n\tm.mu.Lock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif e, ok := m.data[key]; !ok {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t} else {\n\t\te.Value = &gListKVMapNode[K, V]{key, value}\n\t}\n\tm.mu.Unlock()\n}\n\n// Sets batch sets key-values to the map.\nfunc (m *ListKVMap[K, V]) Sets(data map[K]V) {\n\tm.mu.Lock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tfor key, value := range data {\n\t\tif e, ok := m.data[key]; !ok {\n\t\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t\t} else {\n\t\t\te.Value = &gListKVMapNode[K, V]{key, value}\n\t\t}\n\t}\n\tm.mu.Unlock()\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *ListKVMap[K, V]) Search(key K) (value V, found bool) {\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\tif e, ok := m.data[key]; ok {\n\t\t\tvalue = e.Value.value\n\t\t\tfound = ok\n\t\t}\n\t}\n\tm.mu.RUnlock()\n\treturn\n}\n\n// Get returns the value by given `key`.\nfunc (m *ListKVMap[K, V]) Get(key K) (value V) {\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\tif e, ok := m.data[key]; ok {\n\t\t\tvalue = e.Value.value\n\t\t}\n\t}\n\tm.mu.RUnlock()\n\treturn\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *ListKVMap[K, V]) Pop() (key K, value V) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tfor k, e := range m.data {\n\t\tvalue = e.Value.value\n\t\tdelete(m.data, k)\n\t\tm.list.Remove(e)\n\t\treturn k, value\n\t}\n\treturn\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *ListKVMap[K, V]) Pops(size int) map[K]V {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif size > len(m.data) || size == -1 {\n\t\tsize = len(m.data)\n\t}\n\tif size == 0 {\n\t\treturn nil\n\t}\n\tindex := 0\n\tnewMap := make(map[K]V, size)\n\tfor k, e := range m.data {\n\t\tvalue := e.Value.value\n\t\tdelete(m.data, k)\n\t\tm.list.Remove(e)\n\t\tnewMap[k] = value\n\t\tindex++\n\t\tif index == size {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn newMap\n}\n\n// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,\n// if not exists, set value to the map with given `key`,\n// or else just return the existing value.\n//\n// It returns value with given `key`.\nfunc (m *ListKVMap[K, V]) doSetWithLockCheck(key K, value V) V {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\treturn m.doSetWithLockCheckWithoutLock(key, value)\n}\n\nfunc (m *ListKVMap[K, V]) doSetWithLockCheckWithoutLock(key K, value V) V {\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif e, ok := m.data[key]; ok {\n\t\treturn e.Value.value\n\t}\n\tif !m.isNil(value) {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\treturn value\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *ListKVMap[K, V]) GetOrSet(key K, value V) V {\n\tif v, ok := m.Search(key); !ok {\n\t\treturn m.doSetWithLockCheck(key, value)\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *ListKVMap[K, V]) GetOrSetFunc(key K, f func() V) V {\n\tif v, ok := m.Search(key); !ok {\n\t\treturn m.doSetWithLockCheck(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the map.\nfunc (m *ListKVMap[K, V]) GetOrSetFuncLock(key K, f func() V) V {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif e, ok := m.data[key]; ok {\n\t\treturn e.Value.value\n\t}\n\tvalue := f()\n\tif !m.isNil(value) {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\treturn value\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *ListKVMap[K, V]) GetVar(key K) *gvar.Var {\n\treturn gvar.New(m.Get(key))\n}\n\n// GetVarOrSet returns a Var with result from GetVarOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *ListKVMap[K, V]) GetVarOrSet(key K, value V) *gvar.Var {\n\treturn gvar.New(m.GetOrSet(key, value))\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *ListKVMap[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {\n\treturn gvar.New(m.GetOrSetFunc(key, f))\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *ListKVMap[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {\n\treturn gvar.New(m.GetOrSetFuncLock(key, f))\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// Note that it does not add the value to the map if `value` is nil.\nfunc (m *ListKVMap[K, V]) SetIfNotExist(key K, value V) bool {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif _, ok := m.data[key]; ok {\n\t\treturn false\n\t}\n\tif !m.isNil(value) {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\treturn true\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// Note that, it does not add the value to the map if the returned value of `f` is nil.\nfunc (m *ListKVMap[K, V]) SetIfNotExistFunc(key K, f func() V) bool {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif _, ok := m.data[key]; ok {\n\t\treturn false\n\t}\n\tvalue := f()\n\tif !m.isNil(value) {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\treturn true\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the map.\n//\n// Note that, it does not add the value to the map if the returned value of `f` is nil.\nfunc (m *ListKVMap[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif _, ok := m.data[key]; ok {\n\t\treturn false\n\t}\n\tvalue := f()\n\tif !m.isNil(value) {\n\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t}\n\treturn true\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *ListKVMap[K, V]) Remove(key K) (value V) {\n\tm.mu.Lock()\n\tif m.data != nil {\n\t\tif e, ok := m.data[key]; ok {\n\t\t\tvalue = e.Value.value\n\t\t\tdelete(m.data, key)\n\t\t\tm.list.Remove(e)\n\t\t}\n\t}\n\tm.mu.Unlock()\n\treturn\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *ListKVMap[K, V]) Removes(keys []K) {\n\tm.mu.Lock()\n\tif m.data != nil {\n\t\tfor _, key := range keys {\n\t\t\tif e, ok := m.data[key]; ok {\n\t\t\t\tdelete(m.data, key)\n\t\t\t\tm.list.Remove(e)\n\t\t\t}\n\t\t}\n\t}\n\tm.mu.Unlock()\n}\n\n// Keys returns all keys of the map as a slice in ascending order.\nfunc (m *ListKVMap[K, V]) Keys() []K {\n\tm.mu.RLock()\n\tvar (\n\t\tkeys  = make([]K, m.list.Len())\n\t\tindex = 0\n\t)\n\tif m.list != nil {\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tkeys[index] = e.Value.key\n\t\t\tindex++\n\t\t\treturn true\n\t\t})\n\t}\n\tm.mu.RUnlock()\n\treturn keys\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *ListKVMap[K, V]) Values() []V {\n\tm.mu.RLock()\n\tvar (\n\t\tvalues = make([]V, m.list.Len())\n\t\tindex  = 0\n\t)\n\tif m.list != nil {\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tvalues[index] = e.Value.value\n\t\t\tindex++\n\t\t\treturn true\n\t\t})\n\t}\n\tm.mu.RUnlock()\n\treturn values\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *ListKVMap[K, V]) Contains(key K) (ok bool) {\n\tm.mu.RLock()\n\tif m.data != nil {\n\t\t_, ok = m.data[key]\n\t}\n\tm.mu.RUnlock()\n\treturn\n}\n\n// Size returns the size of the map.\nfunc (m *ListKVMap[K, V]) Size() (size int) {\n\tm.mu.RLock()\n\tsize = len(m.data)\n\tm.mu.RUnlock()\n\treturn\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *ListKVMap[K, V]) IsEmpty() bool {\n\treturn m.Size() == 0\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *ListKVMap[K, V]) Flip() error {\n\tdata := m.Map()\n\tm.Clear()\n\tfor key, value := range data {\n\t\tvar (\n\t\t\tnewKey   K\n\t\t\tnewValue V\n\t\t)\n\n\t\tif err := gconv.Scan(value, &newKey); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := gconv.Scan(key, &newValue); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tm.Set(newKey, newValue)\n\t}\n\n\treturn nil\n}\n\n// Merge merges two link maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *ListKVMap[K, V]) Merge(other *ListKVMap[K, V]) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tif other != m {\n\t\tother.mu.RLock()\n\t\tdefer other.mu.RUnlock()\n\t}\n\tvar node *gListKVMapNode[K, V]\n\tother.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\tnode = e.Value\n\t\tif e, ok := m.data[node.key]; !ok {\n\t\t\tm.data[node.key] = m.list.PushBack(&gListKVMapNode[K, V]{node.key, node.value})\n\t\t} else {\n\t\t\te.Value = &gListKVMapNode[K, V]{node.key, node.value}\n\t\t}\n\t\treturn true\n\t})\n}\n\n// String returns the map as a string.\nfunc (m *ListKVMap[K, V]) String() string {\n\tif m == nil {\n\t\treturn \"\"\n\t}\n\tb, _ := m.MarshalJSON()\n\treturn string(b)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// DO NOT change this receiver to pointer type, as the ListKVMap can be used as a var defined variable, like:\n// var m gmap.ListKVMap[string]string\n// Please refer to corresponding tests for more details.\nfunc (m ListKVMap[K, V]) MarshalJSON() (jsonBytes []byte, err error) {\n\tif m.data == nil {\n\t\treturn []byte(\"{}\"), nil\n\t}\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteByte('{')\n\tm.Iterator(func(key K, value V) bool {\n\t\tvalueBytes, valueJSONErr := json.Marshal(value)\n\t\tif valueJSONErr != nil {\n\t\t\terr = valueJSONErr\n\t\t\treturn false\n\t\t}\n\t\tif buffer.Len() > 1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t\tfmt.Fprintf(buffer, `\"%v\":%s`, key, valueBytes)\n\t\treturn true\n\t})\n\tbuffer.WriteByte('}')\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *ListKVMap[K, V]) UnmarshalJSON(b []byte) error {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tvar data map[string]V\n\tif err := json.UnmarshalUseNumber(b, &data); err != nil {\n\t\treturn err\n\t}\n\tvar kvData map[K]V\n\tif err := gconv.Scan(data, &kvData); err != nil {\n\t\treturn err\n\t}\n\tfor key, value := range kvData {\n\t\tif e, ok := m.data[key]; !ok {\n\t\t\tm.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})\n\t\t} else {\n\t\t\te.Value = &gListKVMapNode[K, V]{key, value}\n\t\t}\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *ListKVMap[K, V]) UnmarshalValue(value any) (err error) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tif m.data == nil {\n\t\tm.data = make(map[K]*glist.TElement[*gListKVMapNode[K, V]])\n\t\tm.list = glist.NewT[*gListKVMapNode[K, V]]()\n\t}\n\tvar dataMap map[K]V\n\tif err = gconv.Scan(value, &dataMap); err != nil {\n\t\treturn\n\t}\n\tfor k, v := range dataMap {\n\t\tif e, ok := m.data[k]; !ok {\n\t\t\tm.data[k] = m.list.PushBack(&gListKVMapNode[K, V]{k, v})\n\t\t} else {\n\t\t\te.Value = &gListKVMapNode[K, V]{k, v}\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *ListKVMap[K, V]) DeepCopy() any {\n\tif m == nil {\n\t\treturn nil\n\t}\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\tdata := make(map[K]V, len(m.data))\n\tif m.list != nil {\n\t\tm.list.IteratorAsc(func(e *glist.TElement[*gListKVMapNode[K, V]]) bool {\n\t\t\tdata[e.Value.key] = deepcopy.Copy(e.Value.value).(V)\n\t\t\treturn true\n\t\t})\n\t}\n\treturn NewListKVMapFrom(data, m.mu.IsSafe())\n}\n"
  },
  {
    "path": "container/gmap/gmap_list_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ListMap is a map that preserves insertion-order.\n//\n// It is backed by a hash table to store values and doubly-linked list to store ordering.\n//\n// Structure is not thread safe.\n//\n// Reference: http://en.wikipedia.org/wiki/Associative_array\ntype ListMap struct {\n\t*ListKVMap[any, any]\n\tonce sync.Once\n}\n\ntype gListMapNode = gListKVMapNode[any, any]\n\n// NewListMap returns an empty link map.\n// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.\n// The parameter `safe` is used to specify whether using map in concurrent-safety,\n// which is false in default.\nfunc NewListMap(safe ...bool) *ListMap {\n\treturn &ListMap{\n\t\tListKVMap: NewListKVMap[any, any](safe...),\n\t}\n}\n\n// NewListMapFrom returns a link map from given map `data`.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\nfunc NewListMapFrom(data map[any]any, safe ...bool) *ListMap {\n\tm := NewListMap(safe...)\n\tm.Sets(data)\n\treturn m\n}\n\n// lazyInit lazily initializes the list map.\nfunc (m *ListMap) lazyInit() {\n\tm.once.Do(func() {\n\t\tif m.ListKVMap == nil {\n\t\t\tm.ListKVMap = NewListKVMap[any, any](false)\n\t\t}\n\t})\n}\n\n// Iterator is alias of IteratorAsc.\nfunc (m *ListMap) Iterator(f func(key, value any) bool) {\n\tm.IteratorAsc(f)\n}\n\n// IteratorAsc iterates the map readonly in ascending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *ListMap) IteratorAsc(f func(key any, value any) bool) {\n\tm.lazyInit()\n\tm.ListKVMap.IteratorAsc(f)\n}\n\n// IteratorDesc iterates the map readonly in descending order with given callback function `f`.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (m *ListMap) IteratorDesc(f func(key any, value any) bool) {\n\tm.lazyInit()\n\tm.ListKVMap.IteratorDesc(f)\n}\n\n// Clone returns a new link map with copy of current map data.\nfunc (m *ListMap) Clone(safe ...bool) *ListMap {\n\treturn NewListMapFrom(m.Map(), safe...)\n}\n\n// Clear deletes all data of the map, it will remake a new underlying data map.\nfunc (m *ListMap) Clear() {\n\tm.lazyInit()\n\tm.ListKVMap.Clear()\n}\n\n// Replace the data of the map with given `data`.\nfunc (m *ListMap) Replace(data map[any]any) {\n\tm.lazyInit()\n\tm.ListKVMap.Replace(data)\n}\n\n// Map returns a copy of the underlying data of the map.\nfunc (m *ListMap) Map() map[any]any {\n\tm.lazyInit()\n\treturn m.ListKVMap.Map()\n}\n\n// MapStrAny returns a copy of the underlying data of the map as map[string]any.\nfunc (m *ListMap) MapStrAny() map[string]any {\n\tm.lazyInit()\n\treturn m.ListKVMap.MapStrAny()\n}\n\n// FilterEmpty deletes all key-value pair of which the value is empty.\nfunc (m *ListMap) FilterEmpty() {\n\tm.lazyInit()\n\tm.ListKVMap.FilterEmpty()\n}\n\n// Set sets key-value to the map.\nfunc (m *ListMap) Set(key any, value any) {\n\tm.lazyInit()\n\tm.ListKVMap.Set(key, value)\n}\n\n// Sets batch sets key-values to the map.\nfunc (m *ListMap) Sets(data map[any]any) {\n\tm.lazyInit()\n\tm.ListKVMap.Sets(data)\n}\n\n// Search searches the map with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (m *ListMap) Search(key any) (value any, found bool) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Search(key)\n}\n\n// Get returns the value by given `key`.\nfunc (m *ListMap) Get(key any) (value any) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Get(key)\n}\n\n// Pop retrieves and deletes an item from the map.\nfunc (m *ListMap) Pop() (key, value any) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Pop()\n}\n\n// Pops retrieves and deletes `size` items from the map.\n// It returns all items if size == -1.\nfunc (m *ListMap) Pops(size int) map[any]any {\n\tm.lazyInit()\n\treturn m.ListKVMap.Pops(size)\n}\n\n// GetOrSet returns the value by key,\n// or sets value with given `value` if it does not exist and then returns this value.\nfunc (m *ListMap) GetOrSet(key any, value any) any {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\nfunc (m *ListMap) GetOrSetFunc(key any, f func() any) any {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns the value by key,\n// or sets value with returned value of callback function `f` if it does not exist\n// and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the map.\nfunc (m *ListMap) GetOrSetFuncLock(key any, f func() any) any {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a Var with the value by given `key`.\n// The returned Var is un-concurrent safe.\nfunc (m *ListMap) GetVar(key any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetVar(key)\n}\n\n// GetVarOrSet returns a Var with result from GetVarOrSet.\n// The returned Var is un-concurrent safe.\nfunc (m *ListMap) GetVarOrSet(key any, value any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.\n// The returned Var is un-concurrent safe.\nfunc (m *ListMap) GetVarOrSetFunc(key any, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.\n// The returned Var is un-concurrent safe.\nfunc (m *ListMap) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {\n\tm.lazyInit()\n\treturn m.ListKVMap.GetVarOrSetFuncLock(key, f)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *ListMap) SetIfNotExist(key any, value any) bool {\n\tm.lazyInit()\n\treturn m.ListKVMap.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\nfunc (m *ListMap) SetIfNotExistFunc(key any, f func() any) bool {\n\tm.lazyInit()\n\treturn m.ListKVMap.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and `value` would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` with mutex.Lock of the map.\nfunc (m *ListMap) SetIfNotExistFuncLock(key any, f func() any) bool {\n\tm.lazyInit()\n\treturn m.ListKVMap.SetIfNotExistFuncLock(key, f)\n}\n\n// Remove deletes value from map by given `key`, and return this deleted value.\nfunc (m *ListMap) Remove(key any) (value any) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Remove(key)\n}\n\n// Removes batch deletes values of the map by keys.\nfunc (m *ListMap) Removes(keys []any) {\n\tm.lazyInit()\n\tm.ListKVMap.Removes(keys)\n}\n\n// Keys returns all keys of the map as a slice in ascending order.\nfunc (m *ListMap) Keys() []any {\n\tm.lazyInit()\n\treturn m.ListKVMap.Keys()\n}\n\n// Values returns all values of the map as a slice.\nfunc (m *ListMap) Values() []any {\n\tm.lazyInit()\n\treturn m.ListKVMap.Values()\n}\n\n// Contains checks whether a key exists.\n// It returns true if the `key` exists, or else false.\nfunc (m *ListMap) Contains(key any) (ok bool) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Contains(key)\n}\n\n// Size returns the size of the map.\nfunc (m *ListMap) Size() (size int) {\n\tm.lazyInit()\n\treturn m.ListKVMap.Size()\n}\n\n// IsEmpty checks whether the map is empty.\n// It returns true if map is empty, or else false.\nfunc (m *ListMap) IsEmpty() bool {\n\tm.lazyInit()\n\treturn m.ListKVMap.IsEmpty()\n}\n\n// Flip exchanges key-value of the map to value-key.\nfunc (m *ListMap) Flip() {\n\tdata := m.Map()\n\tm.Clear()\n\tfor key, value := range data {\n\t\tm.Set(value, key)\n\t}\n}\n\n// Merge merges two link maps.\n// The `other` map will be merged into the map `m`.\nfunc (m *ListMap) Merge(other *ListMap) {\n\tm.lazyInit()\n\tother.lazyInit()\n\tm.ListKVMap.Merge(other.ListKVMap)\n}\n\n// String returns the map as a string.\nfunc (m *ListMap) String() string {\n\tm.lazyInit()\n\treturn m.ListKVMap.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (m ListMap) MarshalJSON() (jsonBytes []byte, err error) {\n\treturn m.ListKVMap.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (m *ListMap) UnmarshalJSON(b []byte) error {\n\tm.lazyInit()\n\treturn m.ListKVMap.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (m *ListMap) UnmarshalValue(value any) (err error) {\n\tm.lazyInit()\n\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tfor k, v := range gconv.Map(value) {\n\t\tif e, ok := m.data[k]; !ok {\n\t\t\tm.data[k] = m.list.PushBack(&gListMapNode{k, v})\n\t\t} else {\n\t\t\te.Value = &gListMapNode{k, v}\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (m *ListMap) DeepCopy() any {\n\tif m == nil {\n\t\treturn nil\n\t}\n\tm.lazyInit()\n\treturn &ListMap{\n\t\tListKVMap: m.ListKVMap.DeepCopy().(*ListKVMap[any, any]),\n\t}\n}\n"
  },
  {
    "path": "container/gmap/gmap_tree_k_v_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build go1.24\n\npackage gmap\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gtree\"\n)\n\n// TreeKVMap based on red-black tree, alias of RedBlackKVTree.\ntype TreeKVMap[K comparable, V any] = gtree.RedBlackKVTree[K, V]\n\n// NewTreeKVMap instantiates a tree map with the custom comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewTreeKVMap[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *TreeKVMap[K, V] {\n\treturn gtree.NewRedBlackKVTree[K, V](comparator, safe...)\n}\n\n// NewTreeKVMapFrom instantiates a tree map with the custom comparator and `data` map.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewTreeKVMapFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *TreeKVMap[K, V] {\n\treturn gtree.NewRedBlackKVTreeFrom(comparator, data, safe...)\n}\n"
  },
  {
    "path": "container/gmap/gmap_tree_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gtree\"\n)\n\n// TreeMap based on red-black tree, alias of RedBlackTree.\ntype TreeMap = gtree.RedBlackTree\n\n// NewTreeMap instantiates a tree map with the custom comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewTreeMap(comparator func(v1, v2 any) int, safe ...bool) *TreeMap {\n\treturn gtree.NewRedBlackTree(comparator, safe...)\n}\n\n// NewTreeMapFrom instantiates a tree map with the custom comparator and `data` map.\n// Note that, the param `data` map will be set as the underlying data map(no deep copy),\n// there might be some concurrent-safe issues when changing the map outside.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewTreeMapFrom(comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *TreeMap {\n\treturn gtree.NewRedBlackTreeFrom(comparator, data, safe...)\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc getValue() any {\n\treturn 3\n}\n\nfunc Test_Map_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.Map\n\t\tm.Set(1, 11)\n\t\tt.Assert(m.Get(1), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntAnyMap\n\t\tm.Set(1, 11)\n\t\tt.Assert(m.Get(1), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntIntMap\n\t\tm.Set(1, 11)\n\t\tt.Assert(m.Get(1), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntStrMap\n\t\tm.Set(1, \"11\")\n\t\tt.Assert(m.Get(1), \"11\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrAnyMap\n\t\tm.Set(\"1\", \"11\")\n\t\tt.Assert(m.Get(\"1\"), \"11\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrStrMap\n\t\tm.Set(\"1\", \"11\")\n\t\tt.Assert(m.Get(\"1\"), \"11\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrIntMap\n\t\tm.Set(\"1\", 11)\n\t\tt.Assert(m.Get(\"1\"), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.ListMap\n\t\tm.Set(\"1\", 11)\n\t\tt.Assert(m.Get(\"1\"), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.TreeMap\n\t\tm.SetComparator(gutil.ComparatorString)\n\t\tm.Set(\"1\", 11)\n\t\tt.Assert(m.Get(\"1\"), 11)\n\t})\n}\n\nfunc Test_Map_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.New()\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewFrom(map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_Map_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.New()\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tm.GetOrSetFuncLock(\"funlock\", getValue)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t})\n}\n\nfunc Test_Map_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.New()\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_Map_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, \"key1\": \"val1\"}\n\n\t\tm := gmap.NewFrom(expect)\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_Map_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, \"key1\": \"val1\"}\n\t\tm := gmap.NewFrom(expect)\n\t\tm.LockFunc(func(m map[any]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[any]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_Map_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewFrom(map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_Map_Basic_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.New()\n\t\tm2 := gmap.New()\n\t\tm1.Set(\"key1\", \"val1\")\n\t\tm2.Set(\"key2\", \"val2\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[any]any{\"key1\": \"val1\", \"key2\": \"val2\"})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_bench_maps_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar hashMap = gmap.New(true)\n\nvar listMap = gmap.NewListMap(true)\n\nvar treeMap = gmap.NewTreeMap(gutil.ComparatorInt, true)\n\nfunc Benchmark_HashMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\thashMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_ListMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlistMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_TreeMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\ttreeMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_HashMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\thashMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_ListMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlistMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_TreeMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\ttreeMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_bench_safe_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\nvar anyAnyMap = gmap.NewAnyAnyMap(true)\n\nvar intIntMap = gmap.NewIntIntMap(true)\n\nvar intAnyMap = gmap.NewIntAnyMap(true)\n\nvar intStrMap = gmap.NewIntStrMap(true)\n\nvar strIntMap = gmap.NewStrIntMap(true)\n\nvar strAnyMap = gmap.NewStrAnyMap(true)\n\nvar strStrMap = gmap.NewStrStrMap(true)\n\nfunc Benchmark_IntIntMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintIntMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntAnyMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintAnyMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntStrMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintStrMap.Set(i, \"123456789\")\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_AnyAnyMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tanyAnyMap.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrIntMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrIntMap.Set(strconv.Itoa(i), i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrAnyMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrAnyMap.Set(strconv.Itoa(i), i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrStrMap_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrStrMap.Set(strconv.Itoa(i), \"123456789\")\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntIntMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintIntMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntAnyMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintAnyMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntStrMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintStrMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_AnyAnyMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tanyAnyMap.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrIntMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrIntMap.Get(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrAnyMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrAnyMap.Get(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrStrMap_Get(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrStrMap.Get(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_bench_syncmap_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gmap_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\nvar gm = gmap.NewIntIntMap(true)\n\nvar sm = sync.Map{}\n\nfunc Benchmark_GMapSet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tgm.Set(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_SyncMapSet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tsm.Store(i, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMapGet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tgm.Get(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_SyncMapGet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tsm.Load(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMapRemove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tgm.Remove(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_SyncMapRmove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tsm.Delete(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_bench_unsafe_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\nvar anyAnyMapUnsafe = gmap.New()\n\nvar intIntMapUnsafe = gmap.NewIntIntMap()\n\nvar intAnyMapUnsafe = gmap.NewIntAnyMap()\n\nvar intStrMapUnsafe = gmap.NewIntStrMap()\n\nvar strIntMapUnsafe = gmap.NewStrIntMap()\n\nvar strAnyMapUnsafe = gmap.NewStrAnyMap()\n\nvar strStrMapUnsafe = gmap.NewStrStrMap()\n\n// Writing benchmarks.\n\nfunc Benchmark_Unsafe_IntIntMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintIntMapUnsafe.Set(i, i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntAnyMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintAnyMapUnsafe.Set(i, i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntStrMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintStrMapUnsafe.Set(i, strconv.Itoa(i))\n\t}\n}\n\nfunc Benchmark_Unsafe_AnyAnyMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanyAnyMapUnsafe.Set(i, i)\n\t}\n}\n\nfunc Benchmark_Unsafe_StrIntMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrIntMapUnsafe.Set(strconv.Itoa(i), i)\n\t}\n}\n\nfunc Benchmark_Unsafe_StrAnyMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrAnyMapUnsafe.Set(strconv.Itoa(i), i)\n\t}\n}\n\nfunc Benchmark_Unsafe_StrStrMap_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrStrMapUnsafe.Set(strconv.Itoa(i), strconv.Itoa(i))\n\t}\n}\n\n// Reading benchmarks.\n\nfunc Benchmark_Unsafe_IntIntMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintIntMapUnsafe.Get(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntAnyMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintAnyMapUnsafe.Get(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntStrMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintStrMapUnsafe.Get(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_AnyAnyMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanyAnyMapUnsafe.Get(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_StrIntMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrIntMapUnsafe.Get(strconv.Itoa(i))\n\t}\n}\n\nfunc Benchmark_Unsafe_StrAnyMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrAnyMapUnsafe.Get(strconv.Itoa(i))\n\t}\n}\n\nfunc Benchmark_Unsafe_StrStrMap_Get(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrStrMapUnsafe.Get(strconv.Itoa(i))\n\t}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_any_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleAnyAnyMap_Iterator() {\n\tm := gmap.New()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.Iterator(func(k any, v any) bool {\n\t\ttotalKey += k.(int)\n\t\ttotalValue += v.(int)\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// May Output:\n\t// totalKey: 11\n\t// totalValue: 22\n}\n\nfunc ExampleAnyAnyMap_Clone() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleAnyAnyMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.New()\n\tm1.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.New(true)\n\tm2.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"key1\":\"val1\"}\n\t// before n1: map[key1:val1]\n\t// after n1: map[key1:val2]\n\t// m2: {\"key1\":\"val1\"}\n\t// before n2: map[key1:val1]\n\t// after n2: map[key1:val1]\n}\n\nfunc ExampleAnyAnyMap_MapCopy() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\"}\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleAnyAnyMap_MapStrAny() {\n\tm := gmap.New()\n\tm.Set(1001, \"val1\")\n\tm.Set(1002, \"val2\")\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"1001\":\"val1\", \"1002\":\"val2\"}\n}\n\nfunc ExampleAnyAnyMap_FilterEmpty() {\n\tm := gmap.NewFrom(g.MapAnyAny{\n\t\t\"k1\": \"\",\n\t\t\"k2\": nil,\n\t\t\"k3\": 0,\n\t\t\"k4\": 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k4:1]\n}\n\nfunc ExampleAnyAnyMap_FilterNil() {\n\tm := gmap.NewFrom(g.MapAnyAny{\n\t\t\"k1\": \"\",\n\t\t\"k2\": nil,\n\t\t\"k3\": 0,\n\t\t\"k4\": 1,\n\t})\n\tm.FilterNil()\n\tfmt.Printf(\"%#v\", m.Map())\n\n\t// Output:\n\t// map[interface {}]interface {}{\"k1\":\"\", \"k3\":0, \"k4\":1}\n}\n\nfunc ExampleAnyAnyMap_Set() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleAnyAnyMap_Sets() {\n\tm := gmap.New()\n\n\taddMap := make(map[any]any)\n\taddMap[\"key1\"] = \"val1\"\n\taddMap[\"key2\"] = \"val2\"\n\taddMap[\"key3\"] = \"val3\"\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\"}\n}\n\nfunc ExampleAnyAnyMap_Search() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tvalue, found := m.Search(\"key1\")\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(\"key2\")\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: val1\n\t// key2 not find\n}\n\nfunc ExampleAnyAnyMap_Get() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(\"key1 value:\", m.Get(\"key1\"))\n\tfmt.Println(\"key2 value:\", m.Get(\"key2\"))\n\n\t// Output:\n\t// key1 value: val1\n\t// key2 value: <nil>\n}\n\nfunc ExampleAnyAnyMap_Pop() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// k1 v1\n}\n\nfunc ExampleAnyAnyMap_Pops() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n\t// size: 0\n\t// map[k1:v1 k2:v2]\n\t// size: 2\n}\n\nfunc ExampleAnyAnyMap_GetOrSet() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleAnyAnyMap_GetOrSetFunc() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleAnyAnyMap_GetOrSetFuncLock() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleAnyAnyMap_GetVar() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVar(\"key1\"))\n\tfmt.Println(m.GetVar(\"key2\").IsNil())\n\n\t// Output:\n\t// val1\n\t// true\n}\n\nfunc ExampleAnyAnyMap_GetVarOrSet() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetVarOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleAnyAnyMap_GetVarOrSetFunc() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleAnyAnyMap_GetVarOrSetFuncLock() {\n\tm := gmap.New()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleAnyAnyMap_SetIfNotExist() {\n\tvar m gmap.Map\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v1\"))\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v2\"))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleAnyAnyMap_SetIfNotExistFunc() {\n\tvar m gmap.Map\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleAnyAnyMap_SetIfNotExistFuncLock() {\n\tvar m gmap.Map\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleAnyAnyMap_Remove() {\n\tvar m gmap.Map\n\tm.Set(\"k1\", \"v1\")\n\n\tfmt.Println(m.Remove(\"k1\"))\n\tfmt.Println(m.Remove(\"k2\"))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// v1\n\t// <nil>\n\t// 0\n}\n\nfunc ExampleAnyAnyMap_Removes() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tremoveList := make([]any, 2)\n\tremoveList = append(removeList, \"k1\")\n\tremoveList = append(removeList, \"k2\")\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k3:v3 k4:v4]\n}\n\nfunc ExampleAnyAnyMap_Keys() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [k1 k2 k3 k4]\n}\n\nfunc ExampleAnyAnyMap_Values() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [v1 v2 v3 v4]\n}\n\nfunc ExampleAnyAnyMap_Contains() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Contains(\"k1\"))\n\tfmt.Println(m.Contains(\"k5\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleAnyAnyMap_Size() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleAnyAnyMap_IsEmpty() {\n\tvar m gmap.Map\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(\"k1\", \"v1\")\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleAnyAnyMap_Clear() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleAnyAnyMap_Replace() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tvar n gmap.Map\n\tn.Sets(g.MapAnyAny{\n\t\t\"k2\": \"v2\",\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(\"k2\", \"v1\")\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k1:v1]\n\t// map[k2:v2]\n\t// map[k2:v1]\n}\n\nfunc ExampleAnyAnyMap_LockFunc() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.LockFunc(func(m map[any]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleAnyAnyMap_RLockFunc() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.RLockFunc(func(m map[any]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleAnyAnyMap_Flip() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[v1:k1]\n}\n\nfunc ExampleAnyAnyMap_Merge() {\n\tvar m1, m2 gmap.Map\n\tm1.Set(\"key1\", \"val1\")\n\tm2.Set(\"key2\", \"val2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleAnyAnyMap_String() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.Map = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"k1\":\"v1\"}\n\t// 0\n}\n\nfunc ExampleAnyAnyMap_MarshalJSON() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\",\"k4\":\"v4\"}\n}\n\nfunc ExampleAnyAnyMap_UnmarshalJSON() {\n\tvar m gmap.Map\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tvar n gmap.Map\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n}\n\nfunc ExampleAnyAnyMap_UnmarshalValue() {\n\ttype User struct {\n\t\tUid   int\n\t\tName  string\n\t\tPass1 string `gconv:\"password1\"`\n\t\tPass2 string `gconv:\"password2\"`\n\t}\n\n\tvar (\n\t\tm    gmap.AnyAnyMap\n\t\tuser = User{\n\t\t\tUid:   1,\n\t\t\tName:  \"john\",\n\t\t\tPass1: \"123\",\n\t\t\tPass2: \"456\",\n\t\t}\n\t)\n\tif err := gconv.Scan(user, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\n\t// Output:\n\t// map[interface {}]interface {}{\"Name\":\"john\", \"Uid\":1, \"password1\":\"123\", \"password2\":\"456\"}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_int_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleIntAnyMap_Iterator() {\n\tm := gmap.NewIntAnyMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.Iterator(func(k int, v any) bool {\n\t\ttotalKey += k\n\t\ttotalValue += v.(int)\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// May Output:\n\t// totalKey: 11\n\t// totalValue: 22\n}\n\nfunc ExampleIntAnyMap_Clone() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":\"val1\"}\n\t// {\"1\":\"val1\"}\n}\n\nfunc ExampleIntAnyMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.NewIntAnyMap()\n\tm1.Set(1, \"val1\")\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(1, \"val2\")\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.New(true)\n\tm2.Set(1, \"val1\")\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(1, \"val2\")\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"1\":\"val1\"}\n\t// before n1: map[1:val1]\n\t// after n1: map[1:val2]\n\t// m2: {\"1\":\"val1\"}\n\t// before n2: map[1:val1]\n\t// after n2: map[1:val1]\n}\n\nfunc ExampleIntAnyMap_MapCopy() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\tm.Set(2, \"val2\")\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":\"val1\",\"2\":\"val2\"}\n\t// map[1:val1 2:val2]\n}\n\nfunc ExampleIntAnyMap_MapStrAny() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1001, \"val1\")\n\tm.Set(1002, \"val2\")\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"1001\":\"val1\", \"1002\":\"val2\"}\n}\n\nfunc ExampleIntAnyMap_FilterEmpty() {\n\tm := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t1: \"\",\n\t\t2: nil,\n\t\t3: 0,\n\t\t4: 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[4:1]\n}\n\nfunc ExampleIntAnyMap_FilterNil() {\n\tm := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t1: \"\",\n\t\t2: nil,\n\t\t3: 0,\n\t\t4: 1,\n\t})\n\tm.FilterNil()\n\tfmt.Printf(\"%#v\", m.Map())\n\n\t// Output:\n\t// map[int]interface {}{1:\"\", 3:0, 4:1}\n}\n\nfunc ExampleIntAnyMap_Set() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":\"val1\"}\n}\n\nfunc ExampleIntAnyMap_Sets() {\n\tm := gmap.NewIntAnyMap()\n\n\taddMap := make(map[int]any)\n\taddMap[1] = \"val1\"\n\taddMap[2] = \"val2\"\n\taddMap[3] = \"val3\"\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":\"val1\",\"2\":\"val2\",\"3\":\"val3\"}\n}\n\nfunc ExampleIntAnyMap_Search() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\n\tvalue, found := m.Search(1)\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(2)\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: val1\n\t// key2 not find\n}\n\nfunc ExampleIntAnyMap_Get() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(\"key1 value:\", m.Get(1))\n\tfmt.Println(\"key2 value:\", m.Get(2))\n\n\t// Output:\n\t// key1 value: val1\n\t// key2 value: <nil>\n}\n\nfunc ExampleIntAnyMap_Pop() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// 1 v1\n}\n\nfunc ExampleIntAnyMap_Pops() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[1:v1 2:v2 3:v3 4:v4]\n\t// size: 0\n\t// map[1:v1 2:v2]\n\t// size: 2\n}\n\nfunc ExampleIntAnyMap_GetOrSet() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetOrSet(1, \"NotExistValue\"))\n\tfmt.Println(m.GetOrSet(2, \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleIntAnyMap_GetOrSetFunc() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetOrSetFunc(1, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFunc(2, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleIntAnyMap_GetOrSetFuncLock() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetOrSetFuncLock(1, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(2, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleIntAnyMap_GetVar() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetVar(1))\n\tfmt.Println(m.GetVar(2).IsNil())\n\n\t// Output:\n\t// val1\n\t// true\n}\n\nfunc ExampleIntAnyMap_GetVarOrSet() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetVarOrSet(1, \"NotExistValue\"))\n\tfmt.Println(m.GetVarOrSet(2, \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleIntAnyMap_GetVarOrSetFunc() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFunc(1, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFunc(2, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleIntAnyMap_GetVarOrSetFuncLock() {\n\tm := gmap.NewIntAnyMap()\n\tm.Set(1, \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFuncLock(1, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFuncLock(2, func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleIntAnyMap_SetIfNotExist() {\n\tvar m gmap.IntAnyMap\n\tfmt.Println(m.SetIfNotExist(1, \"v1\"))\n\tfmt.Println(m.SetIfNotExist(1, \"v2\"))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:v1]\n}\n\nfunc ExampleIntAnyMap_SetIfNotExistFunc() {\n\tvar m gmap.IntAnyMap\n\tfmt.Println(m.SetIfNotExistFunc(1, func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(1, func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:v1]\n}\n\nfunc ExampleIntAnyMap_SetIfNotExistFuncLock() {\n\tvar m gmap.IntAnyMap\n\tfmt.Println(m.SetIfNotExistFuncLock(1, func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(1, func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:v1]\n}\n\nfunc ExampleIntAnyMap_Remove() {\n\tvar m gmap.IntAnyMap\n\tm.Set(1, \"v1\")\n\n\tfmt.Println(m.Remove(1))\n\tfmt.Println(m.Remove(2))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// v1\n\t// <nil>\n\t// 0\n}\n\nfunc ExampleIntAnyMap_Removes() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tremoveList := make([]int, 2)\n\tremoveList = append(removeList, 1)\n\tremoveList = append(removeList, 2)\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[3:v3 4:v4]\n}\n\nfunc ExampleIntAnyMap_Keys() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [1 2 3 4]\n}\n\nfunc ExampleIntAnyMap_Values() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [v1 v2 v3 v4]\n}\n\nfunc ExampleIntAnyMap_Contains() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tfmt.Println(m.Contains(1))\n\tfmt.Println(m.Contains(5))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIntAnyMap_Size() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleIntAnyMap_IsEmpty() {\n\tvar m gmap.IntAnyMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(1, \"v1\")\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIntAnyMap_Clear() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleIntAnyMap_Replace() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t})\n\n\tvar n gmap.IntAnyMap\n\tn.Sets(g.MapIntAny{\n\t\t2: \"v2\",\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(2, \"v1\")\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[1:v1]\n\t// map[2:v2]\n\t// map[2:v1]\n}\n\nfunc ExampleIntAnyMap_LockFunc() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tm.LockFunc(func(m map[int]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleIntAnyMap_RLockFunc() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tm.RLockFunc(func(m map[int]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleIntAnyMap_Flip() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: 10,\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[10:1]\n}\n\nfunc ExampleIntAnyMap_Merge() {\n\tvar m1, m2 gmap.Map\n\tm1.Set(1, \"val1\")\n\tm2.Set(2, \"val2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleIntAnyMap_String() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.IntAnyMap = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"1\":\"v1\"}\n\t// 0\n}\n\nfunc ExampleIntAnyMap_MarshalJSON() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"1\":\"v1\",\"2\":\"v2\",\"3\":\"v3\",\"4\":\"v4\"}\n}\n\nfunc ExampleIntAnyMap_UnmarshalJSON() {\n\tvar m gmap.IntAnyMap\n\tm.Sets(g.MapIntAny{\n\t\t1: \"v1\",\n\t\t2: \"v2\",\n\t\t3: \"v3\",\n\t\t4: \"v4\",\n\t})\n\n\tvar n gmap.Map\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[1:v1 2:v2 3:v3 4:v4]\n}\n\nfunc ExampleIntAnyMap_UnmarshalValue() {\n\tvar m gmap.IntAnyMap\n\n\tgoWeb := map[int]any{\n\t\t1: \"goframe\",\n\t\t2: \"gin\",\n\t\t3: \"echo\",\n\t}\n\n\tif err := gconv.Scan(goWeb, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\n\t// Output:\n\t// map[int]interface {}{1:\"goframe\", 2:\"gin\", 3:\"echo\"}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_int_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleIntIntMap_Iterator() {\n\tm := gmap.NewIntIntMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.Iterator(func(k int, v int) bool {\n\t\ttotalKey += k\n\t\ttotalValue += v\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// May Output:\n\t// totalKey: 11\n\t// totalValue: 22\n}\n\nfunc ExampleIntIntMap_Clone() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":1}\n\t// {\"1\":1}\n}\n\nfunc ExampleIntIntMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.NewIntIntMap()\n\tm1.Set(1, 1)\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(1, 2)\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.New(true)\n\tm2.Set(1, \"1\")\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(1, \"2\")\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"1\":1}\n\t// before n1: map[1:1]\n\t// after n1: map[1:2]\n\t// m2: {\"1\":\"1\"}\n\t// before n2: map[1:1]\n\t// after n2: map[1:1]\n}\n\nfunc ExampleIntIntMap_MapCopy() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\tm.Set(2, 2)\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":1,\"2\":2}\n\t// map[1:1 2:2]\n}\n\nfunc ExampleIntIntMap_MapStrAny() {\n\tm := gmap.NewIntIntMap()\n\tm.Set(1001, 1)\n\tm.Set(1002, 2)\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"1001\":1, \"1002\":2}\n}\n\nfunc ExampleIntIntMap_FilterEmpty() {\n\tm := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t1: 0,\n\t\t2: 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[2:1]\n}\n\nfunc ExampleIntIntMap_Set() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":1}\n}\n\nfunc ExampleIntIntMap_Sets() {\n\tm := gmap.NewIntIntMap()\n\n\taddMap := make(map[int]int)\n\taddMap[1] = 1\n\taddMap[2] = 12\n\taddMap[3] = 123\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":1,\"2\":12,\"3\":123}\n}\n\nfunc ExampleIntIntMap_Search() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\n\tvalue, found := m.Search(1)\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(2)\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: 1\n\t// key2 not find\n}\n\nfunc ExampleIntIntMap_Get() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\n\tfmt.Println(\"key1 value:\", m.Get(1))\n\tfmt.Println(\"key2 value:\", m.Get(2))\n\n\t// Output:\n\t// key1 value: 1\n\t// key2 value: 0\n}\n\nfunc ExampleIntIntMap_Pop() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// 1 1\n}\n\nfunc ExampleIntIntMap_Pops() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[1:1 2:2 3:3 4:4]\n\t// size: 0\n\t// map[1:1 2:2]\n\t// size: 2\n}\n\nfunc ExampleIntIntMap_GetOrSet() {\n\tm := gmap.NewIntIntMap()\n\tm.Set(1, 1)\n\n\tfmt.Println(m.GetOrSet(1, 0))\n\tfmt.Println(m.GetOrSet(2, 2))\n\n\t// Output:\n\t// 1\n\t// 2\n}\n\nfunc ExampleIntIntMap_GetOrSetFunc() {\n\tm := gmap.NewIntIntMap()\n\tm.Set(1, 1)\n\n\tfmt.Println(m.GetOrSetFunc(1, func() int {\n\t\treturn 0\n\t}))\n\tfmt.Println(m.GetOrSetFunc(2, func() int {\n\t\treturn 0\n\t}))\n\n\t// Output:\n\t// 1\n\t// 0\n}\n\nfunc ExampleIntIntMap_GetOrSetFuncLock() {\n\tm := gmap.NewIntIntMap()\n\tm.Set(1, 1)\n\n\tfmt.Println(m.GetOrSetFuncLock(1, func() int {\n\t\treturn 0\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(2, func() int {\n\t\treturn 0\n\t}))\n\n\t// Output:\n\t// 1\n\t// 0\n}\n\nfunc ExampleIntIntMap_SetIfNotExist() {\n\tvar m gmap.IntIntMap\n\tfmt.Println(m.SetIfNotExist(1, 1))\n\tfmt.Println(m.SetIfNotExist(1, 2))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:1]\n}\n\nfunc ExampleIntIntMap_SetIfNotExistFunc() {\n\tvar m gmap.IntIntMap\n\tfmt.Println(m.SetIfNotExistFunc(1, func() int {\n\t\treturn 1\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(1, func() int {\n\t\treturn 2\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:1]\n}\n\nfunc ExampleIntIntMap_SetIfNotExistFuncLock() {\n\tvar m gmap.IntIntMap\n\tfmt.Println(m.SetIfNotExistFuncLock(1, func() int {\n\t\treturn 1\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(1, func() int {\n\t\treturn 2\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[1:1]\n}\n\nfunc ExampleIntIntMap_Remove() {\n\tvar m gmap.IntIntMap\n\tm.Set(1, 1)\n\n\tfmt.Println(m.Remove(1))\n\tfmt.Println(m.Remove(2))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 1\n\t// 0\n\t// 0\n}\n\nfunc ExampleIntIntMap_Removes() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tremoveList := make([]int, 2)\n\tremoveList = append(removeList, 1)\n\tremoveList = append(removeList, 2)\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[3:3 4:4]\n}\n\nfunc ExampleIntIntMap_Keys() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [1 2 3 4]\n}\n\nfunc ExampleIntIntMap_Values() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [1 v2 v3 4]\n}\n\nfunc ExampleIntIntMap_Contains() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tfmt.Println(m.Contains(1))\n\tfmt.Println(m.Contains(5))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIntIntMap_Size() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleIntIntMap_IsEmpty() {\n\tvar m gmap.IntIntMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(1, 1)\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIntIntMap_Clear() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleIntIntMap_Replace() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t})\n\n\tvar n gmap.IntIntMap\n\tn.Sets(g.MapIntInt{\n\t\t2: 2,\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(2, 1)\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[1:1]\n\t// map[2:2]\n\t// map[2:1]\n}\n\nfunc ExampleIntIntMap_LockFunc() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tm.LockFunc(func(m map[int]int) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleIntIntMap_RLockFunc() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tm.RLockFunc(func(m map[int]int) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleIntIntMap_Flip() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 10,\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[10:1]\n}\n\nfunc ExampleIntIntMap_Merge() {\n\tvar m1, m2 gmap.Map\n\tm1.Set(1, \"1\")\n\tm2.Set(2, \"2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:1 key2:2]\n}\n\nfunc ExampleIntIntMap_String() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.IntIntMap = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"1\":1}\n\t// 0\n}\n\nfunc ExampleIntIntMap_MarshalJSON() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"1\":1,\"2\":2,\"3\":3,\"4\":4}\n}\n\nfunc ExampleIntIntMap_UnmarshalJSON() {\n\tvar m gmap.IntIntMap\n\tm.Sets(g.MapIntInt{\n\t\t1: 1,\n\t\t2: 2,\n\t\t3: 3,\n\t\t4: 4,\n\t})\n\n\tvar n gmap.Map\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[1:1 2:2 3:3 4:4]\n}\n\nfunc ExampleIntIntMap_UnmarshalValue() {\n\tvar m gmap.IntIntMap\n\n\tn := map[int]int{\n\t\t1: 1001,\n\t\t2: 1002,\n\t\t3: 1003,\n\t}\n\n\tif err := gconv.Scan(n, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\t// Output:\n\t// map[int]int{1:1001, 2:1002, 3:1003}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleListMap_Iterator() {\n\tm := gmap.NewListMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.Iterator(func(k any, v any) bool {\n\t\ttotalKey += k.(int)\n\t\ttotalValue += v.(int)\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 10\n\t// totalValue: 20\n}\n\nfunc ExampleListMap_IteratorAsc() {\n\tm := gmap.NewListMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.IteratorAsc(func(k any, v any) bool {\n\t\ttotalKey += k.(int)\n\t\ttotalValue += v.(int)\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 10\n\t// totalValue: 20\n}\n\nfunc ExampleListMap_IteratorDesc() {\n\tm := gmap.NewListMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(i, i*2)\n\t}\n\n\tvar totalKey, totalValue int\n\tm.IteratorDesc(func(k any, v any) bool {\n\t\ttotalKey += k.(int)\n\t\ttotalValue += v.(int)\n\n\t\treturn totalKey < 10\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 17\n\t// totalValue: 34\n}\n\nfunc ExampleListMap_Clone() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleListMap_Clear() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleListMap_Replace() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tvar n gmap.ListMap\n\tn.Sets(g.MapAnyAny{\n\t\t\"k2\": \"v2\",\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k1:v1]\n\t// map[k2:v2]\n}\n\nfunc ExampleListMap_Map() {\n\tm1 := gmap.NewListMap()\n\tm1.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n1:\", n1)\n\n\t// Output:\n\t// m1: {\"key1\":\"val1\"}\n\t// before n1: map[key1:val1]\n\t// after n1: map[key1:val1]\n}\n\nfunc ExampleListMap_MapStrAny() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"key1\":\"val1\", \"key2\":\"val2\"}\n}\n\nfunc ExampleListMap_FilterEmpty() {\n\tm := gmap.NewListMapFrom(g.MapAnyAny{\n\t\t\"k1\": \"\",\n\t\t\"k2\": nil,\n\t\t\"k3\": 0,\n\t\t\"k4\": 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k4:1]\n}\n\nfunc ExampleListMap_Set() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleListMap_Sets() {\n\tm := gmap.NewListMap()\n\n\taddMap := make(map[any]any)\n\taddMap[\"key1\"] = \"val1\"\n\taddMap[\"key2\"] = \"val2\"\n\taddMap[\"key3\"] = \"val3\"\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// May Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\"}\n}\n\nfunc ExampleListMap_Search() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tvalue, found := m.Search(\"key1\")\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(\"key2\")\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: val1\n\t// key2 not find\n}\n\nfunc ExampleListMap_Get() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(\"key1 value:\", m.Get(\"key1\"))\n\tfmt.Println(\"key2 value:\", m.Get(\"key2\"))\n\n\t// Output:\n\t// key1 value: val1\n\t// key2 value: <nil>\n}\n\nfunc ExampleListMap_Pop() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// k1 v1\n}\n\nfunc ExampleListMap_Pops() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n\t// size: 0\n\t// map[k1:v1 k2:v2]\n\t// size: 2\n}\n\nfunc ExampleListMap_GetOrSet() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleListMap_GetOrSetFunc() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleListMap_GetOrSetFuncLock() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleListMap_GetVar() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVar(\"key1\"))\n\tfmt.Println(m.GetVar(\"key2\").IsNil())\n\n\t// Output:\n\t// val1\n\t// true\n}\n\nfunc ExampleListMap_GetVarOrSet() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetVarOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleListMap_GetVarOrSetFunc() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleListMap_GetVarOrSetFuncLock() {\n\tm := gmap.NewListMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleListMap_SetIfNotExist() {\n\tvar m gmap.ListMap\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v1\"))\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v2\"))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleListMap_SetIfNotExistFunc() {\n\tvar m gmap.ListMap\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleListMap_SetIfNotExistFuncLock() {\n\tvar m gmap.ListMap\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleListMap_Remove() {\n\tvar m gmap.ListMap\n\tm.Set(\"k1\", \"v1\")\n\n\tfmt.Println(m.Remove(\"k1\"))\n\tfmt.Println(m.Remove(\"k2\"))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// v1\n\t// <nil>\n\t// 0\n}\n\nfunc ExampleListMap_Removes() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tremoveList := make([]any, 2)\n\tremoveList = append(removeList, \"k1\")\n\tremoveList = append(removeList, \"k2\")\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k3:v3 k4:v4]\n}\n\nfunc ExampleListMap_Keys() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [k1 k2 k3 k4]\n}\n\nfunc ExampleListMap_Values() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [v1 v2 v3 v4]\n}\n\nfunc ExampleListMap_Contains() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Contains(\"k1\"))\n\tfmt.Println(m.Contains(\"k5\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleListMap_Size() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleListMap_IsEmpty() {\n\tvar m gmap.ListMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(\"k1\", \"v1\")\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleListMap_Flip() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[v1:k1]\n}\n\nfunc ExampleListMap_Merge() {\n\tvar m1, m2 gmap.ListMap\n\tm1.Set(\"key1\", \"val1\")\n\tm2.Set(\"key2\", \"val2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleListMap_String() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tfmt.Println(m.String())\n\n\t// Output:\n\t// {\"k1\":\"v1\"}\n}\n\nfunc ExampleListMap_MarshalJSON() {\n\tvar m gmap.ListMap\n\tm.Set(\"k1\", \"v1\")\n\tm.Set(\"k2\", \"v2\")\n\tm.Set(\"k3\", \"v3\")\n\tm.Set(\"k4\", \"v4\")\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\",\"k4\":\"v4\"}\n}\n\nfunc ExampleListMap_UnmarshalJSON() {\n\tvar m gmap.ListMap\n\tm.Sets(g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tvar n gmap.ListMap\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n}\n\nfunc ExampleListMap_UnmarshalValue() {\n\ttype User struct {\n\t\tUid   int\n\t\tName  string\n\t\tPass1 string `gconv:\"password1\"`\n\t\tPass2 string `gconv:\"password2\"`\n\t}\n\n\tvar (\n\t\tm    gmap.AnyAnyMap\n\t\tuser = User{\n\t\t\tUid:   1,\n\t\t\tName:  \"john\",\n\t\t\tPass1: \"123\",\n\t\t\tPass2: \"456\",\n\t\t}\n\t)\n\tif err := gconv.Scan(user, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\n\t// Output:\n\t// map[interface {}]interface {}{\"Name\":\"john\", \"Uid\":1, \"password1\":\"123\", \"password2\":\"456\"}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_str_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleStrAnyMap_Iterator() {\n\tm := gmap.NewStrAnyMap()\n\tfor i := 1; i <= 10; i++ {\n\t\tm.Set(gconv.String(i), i*2)\n\t}\n\n\tvar totalValue int\n\tm.Iterator(func(k string, v any) bool {\n\t\ttotalValue += v.(int)\n\n\t\treturn totalValue < 50\n\t})\n\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// May Output:\n\t// totalValue: 52\n}\n\nfunc ExampleStrAnyMap_Clone() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleStrAnyMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.NewStrAnyMap()\n\tm1.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.NewStrAnyMap(true)\n\tm2.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"key1\":\"val1\"}\n\t// before n1: map[key1:val1]\n\t// after n1: map[key1:val2]\n\t// m2: {\"key1\":\"val1\"}\n\t// before n2: map[key1:val1]\n\t// after n2: map[key1:val1]\n}\n\nfunc ExampleStrAnyMap_MapCopy() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\"}\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleStrAnyMap_MapStrAny() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"key1\":\"val1\", \"key2\":\"val2\"}\n}\n\nfunc ExampleStrAnyMap_FilterEmpty() {\n\tm := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\"k1\": \"\",\n\t\t\"k2\": nil,\n\t\t\"k3\": 0,\n\t\t\"k4\": 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k4:1]\n}\n\nfunc ExampleStrAnyMap_FilterNil() {\n\tm := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\"k1\": \"\",\n\t\t\"k2\": nil,\n\t\t\"k3\": 0,\n\t\t\"k4\": 1,\n\t})\n\tm.FilterNil()\n\tfmt.Printf(\"%#v\", m.Map())\n\n\t// Output:\n\t// map[string]interface {}{\"k1\":\"\", \"k3\":0, \"k4\":1}\n}\n\nfunc ExampleStrAnyMap_Set() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleStrAnyMap_Sets() {\n\tm := gmap.NewStrAnyMap()\n\n\taddMap := make(map[string]any)\n\taddMap[\"key1\"] = \"val1\"\n\taddMap[\"key2\"] = \"val2\"\n\taddMap[\"key3\"] = \"val3\"\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\"}\n}\n\nfunc ExampleStrAnyMap_Search() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tvalue, found := m.Search(\"key1\")\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(\"key2\")\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: val1\n\t// key2 not find\n}\n\nfunc ExampleStrAnyMap_Get() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(\"key1 value:\", m.Get(\"key1\"))\n\tfmt.Println(\"key2 value:\", m.Get(\"key2\"))\n\n\t// Output:\n\t// key1 value: val1\n\t// key2 value: <nil>\n}\n\nfunc ExampleStrAnyMap_Pop() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// k1 v1\n}\n\nfunc ExampleStrAnyMap_Pops() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n\t// size: 0\n\t// map[k1:v1 k2:v2]\n\t// size: 2\n}\n\nfunc ExampleStrAnyMap_GetOrSet() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleStrAnyMap_GetOrSetFunc() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrAnyMap_GetOrSetFuncLock() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrAnyMap_GetVar() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVar(\"key1\"))\n\tfmt.Println(m.GetVar(\"key2\").IsNil())\n\n\t// Output:\n\t// val1\n\t// true\n}\n\nfunc ExampleStrAnyMap_GetVarOrSet() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetVarOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleStrAnyMap_GetVarOrSetFunc() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFunc(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrAnyMap_GetVarOrSetFuncLock() {\n\tm := gmap.NewStrAnyMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetVarOrSetFuncLock(\"key2\", func() any {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrAnyMap_SetIfNotExist() {\n\tvar m gmap.StrAnyMap\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v1\"))\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v2\"))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrAnyMap_SetIfNotExistFunc() {\n\tvar m gmap.StrAnyMap\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrAnyMap_SetIfNotExistFuncLock() {\n\tvar m gmap.StrAnyMap\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() any {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrAnyMap_Remove() {\n\tvar m gmap.StrAnyMap\n\tm.Set(\"k1\", \"v1\")\n\n\tfmt.Println(m.Remove(\"k1\"))\n\tfmt.Println(m.Remove(\"k2\"))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// v1\n\t// <nil>\n\t// 0\n}\n\nfunc ExampleStrAnyMap_Removes() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tremoveList := make([]string, 2)\n\tremoveList = append(removeList, \"k1\")\n\tremoveList = append(removeList, \"k2\")\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k3:v3 k4:v4]\n}\n\nfunc ExampleStrAnyMap_Keys() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [k1 k2 k3 k4]\n}\n\nfunc ExampleStrAnyMap_Values() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [v1 v2 v3 v4]\n}\n\nfunc ExampleStrAnyMap_Contains() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Contains(\"k1\"))\n\tfmt.Println(m.Contains(\"k5\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrAnyMap_Size() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleStrAnyMap_IsEmpty() {\n\tvar m gmap.StrAnyMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(\"k1\", \"v1\")\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrAnyMap_Clear() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleStrAnyMap_Replace() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tvar n gmap.StrAnyMap\n\tn.Sets(g.MapStrAny{\n\t\t\"k2\": \"v2\",\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(\"k2\", \"v1\")\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k1:v1]\n\t// map[k2:v2]\n\t// map[k2:v1]\n}\n\nfunc ExampleStrAnyMap_LockFunc() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.LockFunc(func(m map[string]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleStrAnyMap_RLockFunc() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.RLockFunc(func(m map[string]any) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v.(int)\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleStrAnyMap_Flip() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[v1:k1]\n}\n\nfunc ExampleStrAnyMap_Merge() {\n\tvar m1, m2 gmap.StrAnyMap\n\tm1.Set(\"key1\", \"val1\")\n\tm2.Set(\"key2\", \"val2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleStrAnyMap_String() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.StrAnyMap = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"k1\":\"v1\"}\n\t// 0\n}\n\nfunc ExampleStrAnyMap_MarshalJSON() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\",\"k4\":\"v4\"}\n}\n\nfunc ExampleStrAnyMap_UnmarshalJSON() {\n\tvar m gmap.StrAnyMap\n\tm.Sets(g.MapStrAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tvar n gmap.StrAnyMap\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n}\n\nfunc ExampleStrAnyMap_UnmarshalValue() {\n\tvar m gmap.StrAnyMap\n\n\tgoWeb := map[string]any{\n\t\t\"goframe\": \"https://goframe.org\",\n\t\t\"gin\":     \"https://gin-gonic.com/\",\n\t\t\"echo\":    \"https://echo.labstack.com/\",\n\t}\n\n\tif err := gconv.Scan(goWeb, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\t// Output:\n\t// map[string]interface {}{\"echo\":\"https://echo.labstack.com/\", \"gin\":\"https://gin-gonic.com/\", \"goframe\":\"https://goframe.org\"}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_str_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleStrIntMap_Iterator() {\n\tm := gmap.NewStrIntMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(gconv.String(i), i*2)\n\t}\n\n\tvar totalValue int\n\tm.Iterator(func(k string, v int) bool {\n\t\ttotalValue += v\n\n\t\treturn totalValue < 50\n\t})\n\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// May Output:\n\t// totalValue: 52\n}\n\nfunc ExampleStrIntMap_Clone() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":1}\n\t// {\"key1\":1}\n}\n\nfunc ExampleStrIntMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.NewStrIntMap()\n\tm1.Set(\"key1\", 1)\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(\"key1\", 2)\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.NewStrIntMap(true)\n\tm2.Set(\"key1\", 1)\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(\"key1\", 2)\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"key1\":1}\n\t// before n1: map[key1:1]\n\t// after n1: map[key1:2]\n\t// m2: {\"key1\":1}\n\t// before n2: map[key1:1]\n\t// after n2: map[key1:1]\n}\n\nfunc ExampleStrIntMap_MapCopy() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\tm.Set(\"key2\", 2)\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":1,\"key2\":2}\n\t// map[key1:1 key2:2]\n}\n\nfunc ExampleStrIntMap_MapStrAny() {\n\tm := gmap.NewStrIntMap()\n\tm.Set(\"key1\", 1)\n\tm.Set(\"key2\", 2)\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"key1\":1, \"key2\":2}\n}\n\nfunc ExampleStrIntMap_FilterEmpty() {\n\tm := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\"k1\": 0,\n\t\t\"k2\": 1,\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k2:1]\n}\n\nfunc ExampleStrIntMap_Set() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":1}\n}\n\nfunc ExampleStrIntMap_Sets() {\n\tm := gmap.NewStrIntMap()\n\n\taddMap := make(map[string]int)\n\taddMap[\"key1\"] = 1\n\taddMap[\"key2\"] = 2\n\taddMap[\"key3\"] = 3\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":1,\"key2\":2,\"key3\":3}\n}\n\nfunc ExampleStrIntMap_Search() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\n\tvalue, found := m.Search(\"key1\")\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(\"key2\")\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: 1\n\t// key2 not find\n}\n\nfunc ExampleStrIntMap_Get() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\n\tfmt.Println(\"key1 value:\", m.Get(\"key1\"))\n\tfmt.Println(\"key2 value:\", m.Get(\"key2\"))\n\n\t// Output:\n\t// key1 value: 1\n\t// key2 value: 0\n}\n\nfunc ExampleStrIntMap_Pop() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// k1 1\n}\n\nfunc ExampleStrIntMap_Pops() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[k1:1 k2:2 k3:3 k4:4]\n\t// size: 0\n\t// map[k1:1 k2:2]\n\t// size: 2\n}\n\nfunc ExampleStrIntMap_GetOrSet() {\n\tm := gmap.NewStrIntMap()\n\tm.Set(\"key1\", 1)\n\n\tfmt.Println(m.GetOrSet(\"key1\", 0))\n\tfmt.Println(m.GetOrSet(\"key2\", 2))\n\n\t// Output:\n\t// 1\n\t// 2\n}\n\nfunc ExampleStrIntMap_GetOrSetFunc() {\n\tm := gmap.NewStrIntMap()\n\tm.Set(\"key1\", 1)\n\n\tfmt.Println(m.GetOrSetFunc(\"key1\", func() int {\n\t\treturn 0\n\t}))\n\tfmt.Println(m.GetOrSetFunc(\"key2\", func() int {\n\t\treturn 0\n\t}))\n\n\t// Output:\n\t// 1\n\t// 0\n}\n\nfunc ExampleStrIntMap_GetOrSetFuncLock() {\n\tm := gmap.NewStrIntMap()\n\tm.Set(\"key1\", 1)\n\n\tfmt.Println(m.GetOrSetFuncLock(\"key1\", func() int {\n\t\treturn 0\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(\"key2\", func() int {\n\t\treturn 0\n\t}))\n\n\t// Output:\n\t// 1\n\t// 0\n}\n\nfunc ExampleStrIntMap_SetIfNotExist() {\n\tvar m gmap.StrIntMap\n\tfmt.Println(m.SetIfNotExist(\"k1\", 1))\n\tfmt.Println(m.SetIfNotExist(\"k1\", 2))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:1]\n}\n\nfunc ExampleStrIntMap_SetIfNotExistFunc() {\n\tvar m gmap.StrIntMap\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() int {\n\t\treturn 1\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() int {\n\t\treturn 2\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:1]\n}\n\nfunc ExampleStrIntMap_SetIfNotExistFuncLock() {\n\tvar m gmap.StrIntMap\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() int {\n\t\treturn 1\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() int {\n\t\treturn 2\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:1]\n}\n\nfunc ExampleStrIntMap_Remove() {\n\tvar m gmap.StrIntMap\n\tm.Set(\"k1\", 1)\n\n\tfmt.Println(m.Remove(\"k1\"))\n\tfmt.Println(m.Remove(\"k2\"))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 1\n\t// 0\n\t// 0\n}\n\nfunc ExampleStrIntMap_Removes() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tremoveList := make([]string, 2)\n\tremoveList = append(removeList, \"k1\")\n\tremoveList = append(removeList, \"k2\")\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k3:3 k4:4]\n}\n\nfunc ExampleStrIntMap_Keys() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [k1 k2 k3 k4]\n}\n\nfunc ExampleStrIntMap_Values() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [1 2 3 4]\n}\n\nfunc ExampleStrIntMap_Contains() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tfmt.Println(m.Contains(\"k1\"))\n\tfmt.Println(m.Contains(\"k5\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrIntMap_Size() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleStrIntMap_IsEmpty() {\n\tvar m gmap.StrIntMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(\"k1\", 1)\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrIntMap_Clear() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleStrIntMap_Replace() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t})\n\n\tvar n gmap.StrIntMap\n\tn.Sets(g.MapStrInt{\n\t\t\"k2\": 2,\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(\"k2\", 1)\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k1:1]\n\t// map[k2:2]\n\t// map[k2:1]\n}\n\nfunc ExampleStrIntMap_LockFunc() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.LockFunc(func(m map[string]int) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleStrIntMap_RLockFunc() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tm.RLockFunc(func(m map[string]int) {\n\t\ttotalValue := 0\n\t\tfor _, v := range m {\n\t\t\ttotalValue += v\n\t\t}\n\t\tfmt.Println(\"totalValue:\", totalValue)\n\t})\n\n\t// Output:\n\t// totalValue: 10\n}\n\nfunc ExampleStrIntMap_Flip() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\tvar n gmap.StrIntMap\n\tn.Sets(g.MapStrInt{\n\t\t\"11\": 1,\n\t})\n\tn.Flip()\n\tfmt.Println(n.Map())\n\n\t// Output:\n\t// map[1:0]\n\t// map[1:11]\n}\n\nfunc ExampleStrIntMap_Merge() {\n\tvar m1, m2 gmap.StrIntMap\n\tm1.Set(\"key1\", 1)\n\tm2.Set(\"key2\", 2)\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:1 key2:2]\n}\n\nfunc ExampleStrIntMap_String() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.StrIntMap = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"k1\":1}\n\t// 0\n}\n\nfunc ExampleStrIntMap_MarshalJSON() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"k1\":1,\"k2\":2,\"k3\":3,\"k4\":4}\n}\n\nfunc ExampleStrIntMap_UnmarshalJSON() {\n\tvar m gmap.StrIntMap\n\tm.Sets(g.MapStrInt{\n\t\t\"k1\": 1,\n\t\t\"k2\": 2,\n\t\t\"k3\": 3,\n\t\t\"k4\": 4,\n\t})\n\n\tvar n gmap.StrIntMap\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[k1:1 k2:2 k3:3 k4:4]\n}\n\nfunc ExampleStrIntMap_UnmarshalValue() {\n\tvar m gmap.StrIntMap\n\n\tgoWeb := map[string]int{\n\t\t\"goframe\": 1,\n\t\t\"gin\":     2,\n\t\t\"echo\":    3,\n\t}\n\n\tif err := gconv.Scan(goWeb, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\t// Output:\n\t// map[string]int{\"echo\":3, \"gin\":2, \"goframe\":1}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_str_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc ExampleStrStrMap_Iterator() {\n\tm := gmap.NewStrStrMap()\n\tfor i := 0; i < 10; i++ {\n\t\tm.Set(\"key\"+gconv.String(i), \"var\"+gconv.String(i))\n\t}\n\n\tvar str string\n\tm.Iterator(func(k string, v string) bool {\n\n\t\tstr += v + \"|\"\n\n\t\treturn len(str) < 20\n\t})\n\n\tfmt.Println(\"str:\", str)\n\n\t// May Output:\n\t// var0|var1|var2|var3|\n}\n\nfunc ExampleStrStrMap_Clone() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := m.Clone()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleStrStrMap_Map() {\n\t// non concurrent-safety, a pointer to the underlying data\n\tm1 := gmap.NewStrStrMap()\n\tm1.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m1:\", m1)\n\n\tn1 := m1.Map()\n\tfmt.Println(\"before n1:\", n1)\n\tm1.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n1:\", n1)\n\n\t// concurrent-safety, copy of underlying data\n\tm2 := gmap.NewStrStrMap(true)\n\tm2.Set(\"key1\", \"val1\")\n\tfmt.Println(\"m2:\", m2)\n\n\tn2 := m2.Map()\n\tfmt.Println(\"before n2:\", n2)\n\tm2.Set(\"key1\", \"val2\")\n\tfmt.Println(\"after n2:\", n2)\n\n\t// Output:\n\t// m1: {\"key1\":\"val1\"}\n\t// before n1: map[key1:val1]\n\t// after n1: map[key1:val2]\n\t// m2: {\"key1\":\"val1\"}\n\t// before n2: map[key1:val1]\n\t// after n2: map[key1:val1]\n}\n\nfunc ExampleStrStrMap_MapCopy() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\tfmt.Println(m)\n\n\tn := m.MapCopy()\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\"}\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleStrStrMap_MapStrAny() {\n\tm := gmap.NewStrStrMap()\n\tm.Set(\"key1\", \"val1\")\n\tm.Set(\"key2\", \"val2\")\n\n\tn := m.MapStrAny()\n\tfmt.Printf(\"%#v\", n)\n\n\t// Output:\n\t// map[string]interface {}{\"key1\":\"val1\", \"key2\":\"val2\"}\n}\n\nfunc ExampleStrStrMap_FilterEmpty() {\n\tm := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\"k1\": \"\",\n\t\t\"k2\": \"v2\",\n\t})\n\tm.FilterEmpty()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k2:v2]\n}\n\nfunc ExampleStrStrMap_Set() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleStrStrMap_Sets() {\n\tm := gmap.NewStrStrMap()\n\n\taddMap := make(map[string]string)\n\taddMap[\"key1\"] = \"val1\"\n\taddMap[\"key2\"] = \"val2\"\n\taddMap[\"key3\"] = \"val3\"\n\n\tm.Sets(addMap)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\"}\n}\n\nfunc ExampleStrStrMap_Search() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tvalue, found := m.Search(\"key1\")\n\tif found {\n\t\tfmt.Println(\"find key1 value:\", value)\n\t}\n\n\tvalue, found = m.Search(\"key2\")\n\tif !found {\n\t\tfmt.Println(\"key2 not find\")\n\t}\n\n\t// Output:\n\t// find key1 value: val1\n\t// key2 not find\n}\n\nfunc ExampleStrStrMap_Get() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(\"key1 value:\", m.Get(\"key1\"))\n\tfmt.Println(\"key2 value:\", m.Get(\"key2\"))\n\n\t// Output:\n\t// key1 value: val1\n\t// key2 value:\n}\n\nfunc ExampleStrStrMap_Pop() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Pop())\n\n\t// May Output:\n\t// k1 v1\n}\n\nfunc ExampleStrStrMap_Pops() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(-1))\n\tfmt.Println(\"size:\", m.Size())\n\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Pops(2))\n\tfmt.Println(\"size:\", m.Size())\n\n\t// May Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n\t// size: 0\n\t// map[k1:v1 k2:v2]\n\t// size: 2\n}\n\nfunc ExampleStrStrMap_GetOrSet() {\n\tm := gmap.NewStrStrMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSet(\"key1\", \"NotExistValue\"))\n\tfmt.Println(m.GetOrSet(\"key2\", \"val2\"))\n\n\t// Output:\n\t// val1\n\t// val2\n}\n\nfunc ExampleStrStrMap_GetOrSetFunc() {\n\tm := gmap.NewStrStrMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFunc(\"key1\", func() string {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFunc(\"key2\", func() string {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrStrMap_GetOrSetFuncLock() {\n\tm := gmap.NewStrStrMap()\n\tm.Set(\"key1\", \"val1\")\n\n\tfmt.Println(m.GetOrSetFuncLock(\"key1\", func() string {\n\t\treturn \"NotExistValue\"\n\t}))\n\tfmt.Println(m.GetOrSetFuncLock(\"key2\", func() string {\n\t\treturn \"NotExistValue\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// NotExistValue\n}\n\nfunc ExampleStrStrMap_SetIfNotExist() {\n\tvar m gmap.StrStrMap\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v1\"))\n\tfmt.Println(m.SetIfNotExist(\"k1\", \"v2\"))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrStrMap_SetIfNotExistFunc() {\n\tvar m gmap.StrStrMap\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() string {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFunc(\"k1\", func() string {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrStrMap_SetIfNotExistFuncLock() {\n\tvar m gmap.StrStrMap\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() string {\n\t\treturn \"v1\"\n\t}))\n\tfmt.Println(m.SetIfNotExistFuncLock(\"k1\", func() string {\n\t\treturn \"v2\"\n\t}))\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// true\n\t// false\n\t// map[k1:v1]\n}\n\nfunc ExampleStrStrMap_Remove() {\n\tvar m gmap.StrStrMap\n\tm.Set(\"k1\", \"v1\")\n\n\tfmt.Println(m.Remove(\"k1\"))\n\tfmt.Println(len(m.Remove(\"k2\")))\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// v1\n\t// 0\n\t// 0\n}\n\nfunc ExampleStrStrMap_Removes() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tremoveList := make([]string, 2)\n\tremoveList = append(removeList, \"k1\")\n\tremoveList = append(removeList, \"k2\")\n\n\tm.Removes(removeList)\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k3:v3 k4:v4]\n}\n\nfunc ExampleStrStrMap_Keys() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Keys())\n\n\t// May Output:\n\t// [k1 k2 k3 k4]\n}\n\nfunc ExampleStrStrMap_Values() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\tfmt.Println(m.Values())\n\n\t// May Output:\n\t// [v1 v2 v3 v4]\n}\n\nfunc ExampleStrStrMap_Contains() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Contains(\"k1\"))\n\tfmt.Println(m.Contains(\"k5\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrStrMap_Size() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tfmt.Println(m.Size())\n\n\t// Output:\n\t// 4\n}\n\nfunc ExampleStrStrMap_IsEmpty() {\n\tvar m gmap.StrStrMap\n\tfmt.Println(m.IsEmpty())\n\n\tm.Set(\"k1\", \"v1\")\n\tfmt.Println(m.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStrStrMap_Clear() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.Clear()\n\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleStrStrMap_Replace() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tvar n gmap.StrStrMap\n\tn.Sets(g.MapStrStr{\n\t\t\"k2\": \"v2\",\n\t})\n\n\tfmt.Println(m.Map())\n\n\tm.Replace(n.Map())\n\tfmt.Println(m.Map())\n\n\tn.Set(\"k2\", \"v1\")\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[k1:v1]\n\t// map[k2:v2]\n\t// map[k2:v1]\n}\n\nfunc ExampleStrStrMap_LockFunc() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.LockFunc(func(m map[string]string) {\n\t\tfor k, v := range m {\n\t\t\tfmt.Println(\"key:\", k, \" value:\", v)\n\t\t}\n\t})\n\n\t// May Output:\n\t// key: k1  value: v1\n\t// key: k2  value: v2\n\t// key: k3  value: v3\n\t// key: k4  value: v4\n}\n\nfunc ExampleStrStrMap_RLockFunc() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tm.RLockFunc(func(m map[string]string) {\n\t\tfor k, v := range m {\n\t\t\tfmt.Println(\"key:\", k, \" value:\", v)\n\t\t}\n\t})\n\n\t// May Output:\n\t// key: k1  value: v1\n\t// key: k2  value: v2\n\t// key: k3  value: v3\n\t// key: k4  value: v4\n}\n\nfunc ExampleStrStrMap_Flip() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t})\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Output:\n\t// map[v1:k1]\n}\n\nfunc ExampleStrStrMap_Merge() {\n\tvar m1, m2 gmap.StrStrMap\n\tm1.Set(\"key1\", \"val1\")\n\tm2.Set(\"key2\", \"val2\")\n\tm1.Merge(&m2)\n\tfmt.Println(m1.Map())\n\n\t// May Output:\n\t// map[key1:val1 key2:val2]\n}\n\nfunc ExampleStrStrMap_String() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t})\n\n\tfmt.Println(m.String())\n\n\tvar m1 *gmap.StrStrMap = nil\n\tfmt.Println(len(m1.String()))\n\n\t// Output:\n\t// {\"k1\":\"v1\"}\n\t// 0\n}\n\nfunc ExampleStrStrMap_MarshalJSON() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tbytes, err := json.Marshal(&m)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"k1\":\"v1\",\"k2\":\"v2\",\"k3\":\"v3\",\"k4\":\"v4\"}\n}\n\nfunc ExampleStrStrMap_UnmarshalJSON() {\n\tvar m gmap.StrStrMap\n\tm.Sets(g.MapStrStr{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t\t\"k4\": \"v4\",\n\t})\n\n\tvar n gmap.StrStrMap\n\n\terr := json.Unmarshal(gconv.Bytes(m.String()), &n)\n\tif err == nil {\n\t\tfmt.Println(n.Map())\n\t}\n\n\t// Output:\n\t// map[k1:v1 k2:v2 k3:v3 k4:v4]\n}\n\nfunc ExampleStrStrMap_UnmarshalValue() {\n\tvar m gmap.StrStrMap\n\n\tgoWeb := map[string]string{\n\t\t\"goframe\": \"https://goframe.org\",\n\t\t\"gin\":     \"https://gin-gonic.com/\",\n\t\t\"echo\":    \"https://echo.labstack.com/\",\n\t}\n\n\tif err := gconv.Scan(goWeb, &m); err == nil {\n\t\tfmt.Printf(\"%#v\", m.Map())\n\t}\n\t// Output:\n\t// map[string]string{\"echo\":\"https://echo.labstack.com/\", \"gin\":\"https://gin-gonic.com/\", \"goframe\":\"https://goframe.org\"}\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleNew() {\n\tm := gmap.New()\n\n\t// Add data.\n\tm.Set(\"key1\", \"val1\")\n\n\t// Print size.\n\tfmt.Println(m.Size())\n\n\taddMap := make(map[any]any)\n\taddMap[\"key2\"] = \"val2\"\n\taddMap[\"key3\"] = \"val3\"\n\taddMap[1] = 1\n\n\tfmt.Println(m.Values())\n\n\t// Batch add data.\n\tm.Sets(addMap)\n\n\t// Gets the value of the corresponding key.\n\tfmt.Println(m.Get(\"key3\"))\n\n\t// Get the value by key, or set it with given key-value if not exist.\n\tfmt.Println(m.GetOrSet(\"key4\", \"val4\"))\n\n\t// Set key-value if the key does not exist, then return true; or else return false.\n\tfmt.Println(m.SetIfNotExist(\"key3\", \"val3\"))\n\n\t// Remove key\n\tm.Remove(\"key2\")\n\tfmt.Println(m.Keys())\n\n\t// Batch remove keys.\n\tm.Removes([]any{\"key1\", 1})\n\tfmt.Println(m.Keys())\n\n\t// Contains checks whether a key exists.\n\tfmt.Println(m.Contains(\"key3\"))\n\n\t// Flip exchanges key-value of the map, it will change key-value to value-key.\n\tm.Flip()\n\tfmt.Println(m.Map())\n\n\t// Clear deletes all data of the map.\n\tm.Clear()\n\n\tfmt.Println(m.Size())\n\n\t// May Output:\n\t// 1\n\t// [val1]\n\t// val3\n\t// val4\n\t// false\n\t// [key4 key1 key3 1]\n\t// [key4 key3]\n\t// true\n\t// map[val3:key3 val4:key4]\n\t// 0\n}\n\nfunc ExampleNewFrom() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleNewHashMap() {\n\tm := gmap.NewHashMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleNewHashMapFrom() {\n\tm := gmap.New()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewHashMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleNewAnyAnyMap() {\n\tm := gmap.NewAnyAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleNewAnyAnyMapFrom() {\n\tm := gmap.NewAnyAnyMap()\n\n\tm.Set(\"key1\", \"val1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewAnyAnyMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"val1\"}\n\t// {\"key1\":\"val1\"}\n}\n\nfunc ExampleNewIntAnyMap() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":\"val1\"}\n}\n\nfunc ExampleNewIntAnyMapFrom() {\n\tm := gmap.NewIntAnyMap()\n\n\tm.Set(1, \"val1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewIntAnyMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":\"val1\"}\n\t// {\"1\":\"val1\"}\n}\n\nfunc ExampleNewIntIntMap() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"1\":1}\n}\n\nfunc ExampleNewIntIntMapFrom() {\n\tm := gmap.NewIntIntMap()\n\n\tm.Set(1, 1)\n\tfmt.Println(m)\n\n\tn := gmap.NewIntIntMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"1\":1}\n\t// {\"1\":1}\n}\n\nfunc ExampleNewStrAnyMap() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"var1\"}\n}\n\nfunc ExampleNewStrAnyMapFrom() {\n\tm := gmap.NewStrAnyMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewStrAnyMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"var1\"}\n\t// {\"key1\":\"var1\"}\n}\n\nfunc ExampleNewStrIntMap() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":1}\n}\n\nfunc ExampleNewStrIntMapFrom() {\n\tm := gmap.NewStrIntMap()\n\n\tm.Set(\"key1\", 1)\n\tfmt.Println(m)\n\n\tn := gmap.NewStrIntMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":1}\n\t// {\"key1\":1}\n}\n\nfunc ExampleNewStrStrMap() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"var1\"}\n}\n\nfunc ExampleNewStrStrMapFrom() {\n\tm := gmap.NewStrStrMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tfmt.Println(m)\n\n\tn := gmap.NewStrStrMapFrom(m.MapCopy(), true)\n\tfmt.Println(n)\n\n\t// Output:\n\t// {\"key1\":\"var1\"}\n\t// {\"key1\":\"var1\"}\n}\n\nfunc ExampleNewListMap() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tm.Set(\"key2\", \"var2\")\n\tfmt.Println(m)\n\n\t// Output:\n\t// {\"key1\":\"var1\",\"key2\":\"var2\"}\n}\n\nfunc ExampleNewListMapFrom() {\n\tm := gmap.NewListMap()\n\n\tm.Set(\"key1\", \"var1\")\n\tm.Set(\"key2\", \"var2\")\n\tfmt.Println(m)\n\n\tn := gmap.NewListMapFrom(m.Map(), true)\n\tfmt.Println(n)\n\n\t// May Output:\n\t// {\"key1\":\"var1\",\"key2\":\"var2\"}\n\t// {\"key1\":\"var1\",\"key2\":\"var2\"}\n}\n\nfunc ExampleNewTreeMap() {\n\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\n\tm.Set(\"key2\", \"var2\")\n\tm.Set(\"key1\", \"var1\")\n\n\tfmt.Println(m.Map())\n\n\t// May Output:\n\t// map[key1:var1 key2:var2]\n}\n\nfunc ExampleNewTreeMapFrom() {\n\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\n\tm.Set(\"key2\", \"var2\")\n\tm.Set(\"key1\", \"var1\")\n\n\tfmt.Println(m.Map())\n\n\tn := gmap.NewListMapFrom(m.Map(), true)\n\tfmt.Println(n.Map())\n\n\t// May Output:\n\t// map[key1:var1 key2:var2]\n\t// map[key1:var1 key2:var2]\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_any_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_AnyAnyMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.AnyAnyMap\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(2, \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), \"2\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_AnyAnyMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(2, \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), \"2\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewAnyAnyMapFrom(map[any]any{1: 1, 2: \"2\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, 2: \"2\"})\n\t})\n}\n\nfunc Test_AnyAnyMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\n\t\tm.GetOrSetFunc(1, getAny)\n\t\tm.GetOrSetFuncLock(2, getAny)\n\t\tt.Assert(m.Get(1), 123)\n\t\tt.Assert(m.Get(2), 123)\n\n\t\tt.Assert(m.SetIfNotExistFunc(1, getAny), false)\n\t\tt.Assert(m.SetIfNotExistFunc(3, getAny), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(2, getAny), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(4, getAny), true)\n\t})\n\n}\n\nfunc Test_AnyAnyMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\n\t\tm.Sets(map[any]any{1: 1, 2: \"2\", 3: 3})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, 2: \"2\", 3: 3})\n\t\tm.Removes([]any{1, 2})\n\t\tt.Assert(m.Map(), map[any]any{3: 3})\n\t})\n}\n\nfunc Test_AnyAnyMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMapFrom(map[any]any{1: 1, 2: \"2\", \"3\": \"3\", \"4\": 4}, true)\n\t\tm.Iterator(func(k any, _ any) bool {\n\t\t\tif gconv.Int(k)%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Map(), map[any]any{\n\t\t\t1:   1,\n\t\t\t\"3\": \"3\",\n\t\t})\n\t})\n}\n\nfunc Test_AnyAnyMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, 2: \"2\"}\n\t\tm := gmap.NewAnyAnyMapFrom(expect)\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, \"2\")\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_AnyAnyMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, 2: \"2\"}\n\t\tm := gmap.NewAnyAnyMapFrom(expect)\n\t\tm.LockFunc(func(m map[any]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[any]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_AnyAnyMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewAnyAnyMapFrom(map[any]any{1: 1, 2: \"2\"})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(2)\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(2, m.Keys())\n\t})\n}\n\nfunc Test_AnyAnyMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewAnyAnyMap()\n\t\tm2 := gmap.NewAnyAnyMap()\n\t\tm1.Set(1, 1)\n\t\tm2.Set(2, \"2\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[any]any{1: 1, 2: \"2\"})\n\t\tm3 := gmap.NewAnyAnyMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_AnyAnyMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.Map()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), 3)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], 4)\n\t})\n}\n\nfunc Test_AnyAnyMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), nil)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], nil)\n\t})\n}\n\nfunc Test_AnyAnyMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Get(1), nil)\n\t\tt.Assert(m.Get(2), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(\"time1\", time.Time{})\n\t\tm.Set(\"time2\", time.Now())\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(\"time1\"), time.Time{})\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Get(1), nil)\n\t\tt.Assert(m.Get(\"time1\"), nil)\n\t\tt.AssertNE(m.Get(\"time2\"), nil)\n\t})\n}\n\nfunc Test_AnyAnyMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm1 := gmap.NewAnyAnyMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(gconv.Map(data))\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.New()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.Map\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc Test_AnyAnyMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.AssertNil(k3)\n\t\tt.AssertNil(v3)\n\t})\n}\n\nfunc Test_AnyAnyMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestAnyAnyMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.Map\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"k1\":\"v1\",\"k2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.Map{\n\t\t\t\t\"k1\": \"v1\",\n\t\t\t\t\"k2\": \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n}\n\nfunc Test_AnyAnyMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.AnyAnyMap)\n\t\tn.Set(\"k1\", \"val1\")\n\t\tt.AssertNE(m.Get(\"k1\"), n.Get(\"k1\"))\n\t})\n}\n\nfunc Test_AnyAnyMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tm2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_AnyAnyMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"0\": \"v0\",\n\t\t\t\"1\": \"v1\",\n\t\t\t2:   \"v2\",\n\t\t\t3:   3,\n\t\t})\n\t\tm2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"0\": \"v0\",\n\t\t\t2:   \"v2\",\n\t\t\t3:   \"v3\",\n\t\t\t4:   \"v4\",\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []any{4})\n\t\tt.Assert(removedKeys, []any{\"1\"})\n\t\tt.Assert(updatedKeys, []any{3})\n\t})\n}\n\nfunc Test_AnyAnyMap_DoSetWithLockCheck_FuncValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMap(true)\n\n\t\t// Test GetOrSetFuncLock with function value\n\t\t// Function should be executed and its return value should be set\n\t\tcallCount := 0\n\t\tresult := m.GetOrSetFuncLock(1, func() any {\n\t\t\tcallCount++\n\t\t\treturn \"value1\"\n\t\t})\n\t\tt.Assert(result, \"value1\")\n\t\tt.Assert(callCount, 1)\n\t\tt.Assert(m.Get(1), \"value1\")\n\n\t\t// Test GetOrSetFuncLock again with same key\n\t\t// Function should NOT be called since key exists\n\t\tresult = m.GetOrSetFuncLock(1, func() any {\n\t\t\tcallCount++\n\t\t\treturn \"value2\"\n\t\t})\n\t\tt.Assert(result, \"value1\")\n\t\tt.Assert(callCount, 1) // Should still be 1, function not called\n\n\t\t// Test SetIfNotExistFuncLock with function value\n\t\tcallCount = 0\n\t\tok := m.SetIfNotExistFuncLock(2, func() any {\n\t\t\tcallCount++\n\t\t\treturn \"value2\"\n\t\t})\n\t\tt.Assert(ok, true)\n\t\tt.Assert(callCount, 1)\n\t\tt.Assert(m.Get(2), \"value2\")\n\n\t\t// Test SetIfNotExistFuncLock again with same key\n\t\t// Function should NOT be called since key exists\n\t\tok = m.SetIfNotExistFuncLock(2, func() any {\n\t\t\tcallCount++\n\t\t\treturn \"value3\"\n\t\t})\n\t\tt.Assert(ok, false)\n\t\tt.Assert(callCount, 1)       // Should still be 1, function not called\n\t\tt.Assert(m.Get(2), \"value2\") // Value should not change\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_int_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc getAny() any {\n\treturn 123\n}\n\nfunc Test_IntAnyMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntAnyMap\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(2, \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), \"2\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_IntAnyMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(2, \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), \"2\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewIntAnyMapFrom(map[int]any{1: 1, 2: \"2\"})\n\t\tt.Assert(m2.Map(), map[int]any{1: 1, 2: \"2\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap(true)\n\t\tm.Set(1, 1)\n\t\tt.Assert(m.Map(), map[int]any{1: 1})\n\t})\n}\n\nfunc Test_IntAnyMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\n\t\tm.GetOrSetFunc(1, getAny)\n\t\tm.GetOrSetFuncLock(2, getAny)\n\t\tt.Assert(m.Get(1), 123)\n\t\tt.Assert(m.Get(2), 123)\n\n\t\tt.Assert(m.SetIfNotExistFunc(1, getAny), false)\n\t\tt.Assert(m.SetIfNotExistFunc(3, getAny), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(2, getAny), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(4, getAny), true)\n\t})\n}\n\nfunc Test_IntAnyMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\n\t\tm.Sets(map[int]any{1: 1, 2: \"2\", 3: 3})\n\t\tt.Assert(m.Map(), map[int]any{1: 1, 2: \"2\", 3: 3})\n\t\tm.Removes([]int{1, 2})\n\t\tt.Assert(m.Map(), map[int]any{3: 3})\n\t})\n}\n\nfunc Test_IntAnyMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMapFrom(map[int]any{1: 1, 2: 2, 3: \"3\", 4: 4}, true)\n\t\tm.Iterator(func(k int, _ any) bool {\n\t\t\tif k%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Map(), map[int]any{\n\t\t\t1: 1,\n\t\t\t3: \"3\",\n\t\t})\n\t})\n}\n\nfunc Test_IntAnyMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]any{1: 1, 2: \"2\"}\n\t\tm := gmap.NewIntAnyMapFrom(expect)\n\t\tm.Iterator(func(k int, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k int, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k int, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, \"2\")\n\t\tt.Assert(j, 1)\n\t})\n\n}\n\nfunc Test_IntAnyMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]any{1: 1, 2: \"2\"}\n\t\tm := gmap.NewIntAnyMapFrom(expect)\n\t\tm.LockFunc(func(m map[int]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[int]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_IntAnyMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewIntAnyMapFrom(map[int]any{1: 1, 2: \"2\"})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(2)\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(2, m.Keys())\n\t})\n}\n\nfunc Test_IntAnyMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntAnyMap()\n\t\tm2 := gmap.NewIntAnyMap()\n\t\tm1.Set(1, 1)\n\t\tm2.Set(2, \"2\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[int]any{1: 1, 2: \"2\"})\n\t\tm3 := gmap.NewIntAnyMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_IntAnyMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.Map()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), 3)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], 4)\n\t})\n}\n\nfunc Test_IntAnyMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), nil)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], nil)\n\t})\n}\n\nfunc Test_IntAnyMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(2), 2)\n\t})\n}\n\nfunc Test_IntAnyMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t}\n\t\tm1 := gmap.NewIntAnyMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewIntAnyMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(1), data[1])\n\t\tt.Assert(m.Get(2), data[2])\n\t})\n}\n\nfunc Test_IntAnyMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{1, 2})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{1, 2})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, 0)\n\t\tt.AssertNil(v3)\n\t})\n}\n\nfunc Test_IntAnyMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t\t3: \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestIntAnyMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.IntAnyMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"1\":\"v1\",\"2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"v1\")\n\t\tt.Assert(v.Map.Get(2), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.MapIntAny{\n\t\t\t\t1: \"v1\",\n\t\t\t\t2: \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"v1\")\n\t\tt.Assert(v.Map.Get(2), \"v2\")\n\t})\n}\n\nfunc Test_IntAnyMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.IntAnyMap)\n\t\tn.Set(1, \"val1\")\n\t\tt.AssertNE(m.Get(1), n.Get(1))\n\t})\n}\n\nfunc Test_IntAnyMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t})\n\t\tm2 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t2: \"v2\",\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_IntAnyMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t0: \"v0\",\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t\t3: 3,\n\t\t})\n\t\tm2 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t0: \"v0\",\n\t\t\t2: \"v2\",\n\t\t\t3: \"v3\",\n\t\t\t4: \"v4\",\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []int{4})\n\t\tt.Assert(removedKeys, []int{1})\n\t\tt.Assert(updatedKeys, []int{3})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_int_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc getInt() int {\n\treturn 123\n}\n\nfunc intIntCallBack(int, int) bool {\n\treturn true\n}\n\nfunc Test_IntIntMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntIntMap\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, 2), 2)\n\t\tt.Assert(m.SetIfNotExist(2, 2), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), 2)\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[int]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_IntIntMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\t\tm.Set(1, 1)\n\n\t\tt.Assert(m.Get(1), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, 2), 2)\n\t\tt.Assert(m.SetIfNotExist(2, 2), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, 3), true)\n\n\t\tt.Assert(m.Remove(2), 2)\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[int]int{1: 1, 3: 3})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})\n\t\tt.Assert(m2.Map(), map[int]int{1: 1, 2: 2})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap(true)\n\t\tm.Set(1, 1)\n\t\tt.Assert(m.Map(), map[int]int{1: 1})\n\t})\n}\n\nfunc Test_IntIntMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\n\t\tm.GetOrSetFunc(1, getInt)\n\t\tm.GetOrSetFuncLock(2, getInt)\n\t\tt.Assert(m.Get(1), 123)\n\t\tt.Assert(m.Get(2), 123)\n\t\tt.Assert(m.SetIfNotExistFunc(1, getInt), false)\n\t\tt.Assert(m.SetIfNotExistFunc(3, getInt), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(2, getInt), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(4, getInt), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMapFrom(nil)\n\t\tt.Assert(m.GetOrSetFuncLock(1, getInt), getInt())\n\t})\n}\n\nfunc Test_IntIntMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\n\t\tm.Sets(map[int]int{1: 1, 2: 2, 3: 3})\n\t\tm.Iterator(intIntCallBack)\n\t\tt.Assert(m.Map(), map[int]int{1: 1, 2: 2, 3: 3})\n\t\tm.Removes([]int{1, 2})\n\t\tt.Assert(m.Map(), map[int]int{3: 3})\n\t})\n}\n\nfunc Test_IntIntMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2, 3: 3, 4: 4}, true)\n\t\tm.Iterator(func(k int, _ int) bool {\n\t\t\tif k%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Map(), map[int]int{\n\t\t\t1: 1,\n\t\t\t3: 3,\n\t\t})\n\t})\n}\n\nfunc Test_IntIntMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]int{1: 1, 2: 2}\n\t\tm := gmap.NewIntIntMapFrom(expect)\n\t\tm.Iterator(func(k int, v int) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k int, v int) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k int, v int) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_IntIntMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]int{1: 1, 2: 2}\n\t\tm := gmap.NewIntIntMapFrom(expect)\n\t\tm.LockFunc(func(m map[int]int) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[int]int) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_IntIntMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(2)\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(2, m.Keys())\n\t})\n}\n\nfunc Test_IntIntMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntIntMap()\n\t\tm2 := gmap.NewIntIntMap()\n\t\tm1.Set(1, 1)\n\t\tm2.Set(2, 2)\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[int]int{1: 1, 2: 2})\n\t\tm3 := gmap.NewIntIntMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_IntIntMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.Map()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), 3)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], 4)\n\t})\n}\n\nfunc Test_IntIntMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[1], 0)\n\t\tt.Assert(data[2], 2)\n\t\tdata[3] = 3\n\t\tt.Assert(m.Get(3), 0)\n\t\tm.Set(4, 4)\n\t\tt.Assert(data[4], 0)\n\t})\n}\n\nfunc Test_IntIntMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMap()\n\t\tm.Set(1, 0)\n\t\tm.Set(2, 2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(1), 0)\n\t\tt.Assert(m.Get(2), 2)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(2), 2)\n\t})\n}\n\nfunc Test_IntIntMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntInt{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t}\n\t\tm1 := gmap.NewIntIntMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntInt{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewIntIntMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(1), data[1])\n\t\tt.Assert(m.Get(2), data[2])\n\t})\n}\n\nfunc Test_IntIntMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t\t1: 11,\n\t\t\t2: 22,\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{1, 2})\n\t\tt.AssertIN(v1, g.Slice{11, 22})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{1, 2})\n\t\tt.AssertIN(v2, g.Slice{11, 22})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, 0)\n\t\tt.Assert(v3, 0)\n\t})\n}\n\nfunc Test_IntIntMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t\t1: 11,\n\t\t\t2: 22,\n\t\t\t3: 33,\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{11, 22, 33})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{11, 22, 33})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestIntIntMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.IntIntMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"1\":1,\"2\":2}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"1\")\n\t\tt.Assert(v.Map.Get(2), \"2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.MapIntAny{\n\t\t\t\t1: 1,\n\t\t\t\t2: 2,\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"1\")\n\t\tt.Assert(v.Map.Get(2), \"2\")\n\t})\n}\n\nfunc Test_IntIntMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t\t1: 1,\n\t\t\t2: 2,\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.IntIntMap)\n\t\tn.Set(1, 2)\n\t\tt.AssertNE(m.Get(1), n.Get(1))\n\t})\n}\n\nfunc Test_IntIntMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t1: 1,\n\t\t\t2: 2,\n\t\t})\n\t\tm2 := gmap.NewIntAnyMapFrom(g.MapIntAny{\n\t\t\t2: 2,\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_IntIntMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t\t0: 0,\n\t\t\t1: 1,\n\t\t\t2: 2,\n\t\t\t3: 3,\n\t\t})\n\t\tm2 := gmap.NewIntIntMapFrom(g.MapIntInt{\n\t\t\t0: 0,\n\t\t\t2: 2,\n\t\t\t3: 31,\n\t\t\t4: 4,\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []int{4})\n\t\tt.Assert(removedKeys, []int{1})\n\t\tt.Assert(updatedKeys, []int{3})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_int_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc getStr() string {\n\treturn \"z\"\n}\n\nfunc Test_IntStrMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.IntStrMap\n\t\tm.Set(1, \"a\")\n\n\t\tt.Assert(m.Get(1), \"a\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(2, \"b\"), \"b\")\n\t\tt.Assert(m.SetIfNotExist(2, \"b\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, \"c\"), true)\n\n\t\tt.Assert(m.Remove(2), \"b\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(\"a\", m.Values())\n\t\tt.AssertIN(\"c\", m.Values())\n\n\t\tm_f := gmap.NewIntStrMap()\n\t\tm_f.Set(1, \"2\")\n\t\tm_f.Flip()\n\t\tt.Assert(m_f.Map(), map[int]string{2: \"1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_IntStrMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.Set(1, \"a\")\n\n\t\tt.Assert(m.Get(1), \"a\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(1, \"a\"), \"a\")\n\t\tt.Assert(m.GetOrSet(2, \"b\"), \"b\")\n\t\tt.Assert(m.SetIfNotExist(2, \"b\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(3, \"c\"), true)\n\n\t\tt.Assert(m.Remove(2), \"b\")\n\t\tt.Assert(m.Contains(2), false)\n\n\t\tt.AssertIN(3, m.Keys())\n\t\tt.AssertIN(1, m.Keys())\n\t\tt.AssertIN(\"a\", m.Values())\n\t\tt.AssertIN(\"c\", m.Values())\n\n\t\t// 反转之后不成为以下 map,flip 操作只是翻转原 map\n\t\t// t.Assert(m.Map(), map[string]int{\"a\": 1, \"c\": 3})\n\t\tm_f := gmap.NewIntStrMap()\n\t\tm_f.Set(1, \"2\")\n\t\tm_f.Flip()\n\t\tt.Assert(m_f.Map(), map[int]string{2: \"1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewIntStrMapFrom(map[int]string{1: \"a\", 2: \"b\"})\n\t\tt.Assert(m2.Map(), map[int]string{1: \"a\", 2: \"b\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap(true)\n\t\tm.Set(1, \"val1\")\n\t\tt.Assert(m.Map(), map[int]string{1: \"val1\"})\n\t})\n}\n\nfunc TestIntStrMap_MapStrAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.GetOrSetFunc(1, getStr)\n\t\tm.GetOrSetFuncLock(2, getStr)\n\t\tt.Assert(m.MapStrAny(), g.MapStrAny{\"1\": \"z\", \"2\": \"z\"})\n\t})\n}\n\nfunc TestIntStrMap_Sets(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(nil)\n\t\tm.Sets(g.MapIntStr{1: \"z\", 2: \"z\"})\n\t\tt.Assert(len(m.Map()), 2)\n\t})\n}\n\nfunc Test_IntStrMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.GetOrSetFunc(1, getStr)\n\t\tm.GetOrSetFuncLock(2, getStr)\n\t\tt.Assert(m.GetOrSetFunc(1, getStr), \"z\")\n\t\tt.Assert(m.GetOrSetFuncLock(2, getStr), \"z\")\n\t\tt.Assert(m.Get(1), \"z\")\n\t\tt.Assert(m.Get(2), \"z\")\n\t\tt.Assert(m.SetIfNotExistFunc(1, getStr), false)\n\t\tt.Assert(m.SetIfNotExistFunc(3, getStr), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(2, getStr), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(4, getStr), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(nil)\n\t\tt.Assert(m.GetOrSetFuncLock(1, getStr), \"z\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(nil)\n\t\tt.Assert(m.SetIfNotExistFuncLock(1, getStr), true)\n\t})\n}\n\nfunc Test_IntStrMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.Sets(map[int]string{1: \"a\", 2: \"b\", 3: \"c\"})\n\t\tt.Assert(m.Map(), map[int]string{1: \"a\", 2: \"b\", 3: \"c\"})\n\t\tm.Removes([]int{1, 2})\n\t\tt.Assert(m.Map(), map[int]any{3: \"c\"})\n\t})\n}\n\nfunc Test_IntStrMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(map[int]string{1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\"}, true)\n\t\tm.Iterator(func(k int, _ string) bool {\n\t\t\tif k%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Map(), map[int]string{\n\t\t\t1: \"1\",\n\t\t\t3: \"3\",\n\t\t})\n\t})\n}\n\nfunc Test_IntStrMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]string{1: \"a\", 2: \"b\"}\n\t\tm := gmap.NewIntStrMapFrom(expect)\n\t\tm.Iterator(func(k int, v string) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k int, v string) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k int, v string) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_IntStrMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[int]string{1: \"a\", 2: \"b\", 3: \"c\"}\n\t\tm := gmap.NewIntStrMapFrom(expect)\n\t\tm.LockFunc(func(m map[int]string) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[int]string) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_IntStrMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewIntStrMapFrom(map[int]string{1: \"a\", 2: \"b\", 3: \"c\"})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(2)\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(2, m.Keys())\n\t})\n}\n\nfunc Test_IntStrMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntStrMap()\n\t\tm2 := gmap.NewIntStrMap()\n\t\tm1.Set(1, \"a\")\n\t\tm2.Set(2, \"b\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[int]string{1: \"a\", 2: \"b\"})\n\n\t\tm3 := gmap.NewIntStrMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_IntStrMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.Set(1, \"0\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.Get(1), \"0\")\n\t\tt.Assert(m.Get(2), \"2\")\n\t\tdata := m.Map()\n\t\tt.Assert(data[1], \"0\")\n\t\tt.Assert(data[2], \"2\")\n\t\tdata[3] = \"3\"\n\t\tt.Assert(m.Get(3), \"3\")\n\t\tm.Set(4, \"4\")\n\t\tt.Assert(data[4], \"4\")\n\t})\n}\n\nfunc Test_IntStrMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.Set(1, \"0\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.Get(1), \"0\")\n\t\tt.Assert(m.Get(2), \"2\")\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[1], \"0\")\n\t\tt.Assert(data[2], \"2\")\n\t\tdata[3] = \"3\"\n\t\tt.Assert(m.Get(3), \"\")\n\t\tm.Set(4, \"4\")\n\t\tt.Assert(data[4], \"\")\n\t})\n}\n\nfunc Test_IntStrMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMap()\n\t\tm.Set(1, \"\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(2), \"2\")\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(2), \"2\")\n\t})\n}\n\nfunc Test_IntStrMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t}\n\t\tm1 := gmap.NewIntStrMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewIntStrMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(1), data[1])\n\t\tt.Assert(m.Get(2), data[2])\n\t})\n}\n\nfunc Test_IntStrMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{1, 2})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{1, 2})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, 0)\n\t\tt.Assert(v3, \"\")\n\t})\n}\n\nfunc Test_IntStrMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t\t3: \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{1, 2, 3})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestIntStrMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.IntStrMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"1\":\"v1\",\"2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"v1\")\n\t\tt.Assert(v.Map.Get(2), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.MapIntAny{\n\t\t\t\t1: \"v1\",\n\t\t\t\t2: \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(1), \"v1\")\n\t\tt.Assert(v.Map.Get(2), \"v2\")\n\t})\n}\n\nfunc TestIntStrMap_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t\t3: \"v3\",\n\t\t})\n\n\t\tt.Assert(m.Get(1), \"v1\")\n\t\tt.Assert(m.Get(2), \"v2\")\n\t\tt.Assert(m.Get(3), \"v3\")\n\n\t\tm.Replace(g.MapIntStr{\n\t\t\t1: \"v2\",\n\t\t\t2: \"v3\",\n\t\t\t3: \"v1\",\n\t\t})\n\n\t\tt.Assert(m.Get(1), \"v2\")\n\t\tt.Assert(m.Get(2), \"v3\")\n\t\tt.Assert(m.Get(3), \"v1\")\n\t})\n}\n\nfunc TestIntStrMap_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t\t3: \"v3\",\n\t\t})\n\t\tt.Assert(m.String(), \"{\\\"1\\\":\\\"v1\\\",\\\"2\\\":\\\"v2\\\",\\\"3\\\":\\\"v3\\\"}\")\n\n\t\tm = nil\n\t\tt.Assert(len(m.String()), 0)\n\t})\n}\n\nfunc Test_IntStrMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"val1\",\n\t\t\t2: \"val2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.IntStrMap)\n\t\tn.Set(1, \"v1\")\n\t\tt.AssertNE(m.Get(1), n.Get(1))\n\t})\n}\n\nfunc Test_IntStrMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t1: \"v1\",\n\t\t\t2: \"v2\",\n\t\t})\n\t\tm2 := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t2: \"v2\",\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_IntStrMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t0: \"0\",\n\t\t\t1: \"1\",\n\t\t\t2: \"2\",\n\t\t\t3: \"3\",\n\t\t})\n\t\tm2 := gmap.NewIntStrMapFrom(g.MapIntStr{\n\t\t\t0: \"0\",\n\t\t\t2: \"2\",\n\t\t\t3: \"31\",\n\t\t\t4: \"4\",\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []int{4})\n\t\tt.Assert(removedKeys, []int{1})\n\t\tt.Assert(updatedKeys, []int{3})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_str_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_StrAnyMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrAnyMap\n\t\tm.Set(\"a\", 1)\n\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(\"b\", \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", 3), true)\n\n\t\tt.Assert(m.Remove(\"b\"), \"2\")\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[string]any{\"1\": \"a\", \"3\": \"c\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_StrAnyMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\t\tm.Set(\"a\", 1)\n\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", \"2\"), \"2\")\n\t\tt.Assert(m.SetIfNotExist(\"b\", \"2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", 3), true)\n\n\t\tt.Assert(m.Remove(\"b\"), \"2\")\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[string]any{\"1\": \"a\", \"3\": \"c\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewStrAnyMapFrom(map[string]any{\"a\": 1, \"b\": \"2\"})\n\t\tt.Assert(m2.Map(), map[string]any{\"a\": 1, \"b\": \"2\"})\n\t})\n}\n\nfunc Test_StrAnyMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\n\t\tm.GetOrSetFunc(\"a\", getAny)\n\t\tm.GetOrSetFuncLock(\"b\", getAny)\n\t\tt.Assert(m.Get(\"a\"), 123)\n\t\tt.Assert(m.Get(\"b\"), 123)\n\t\tt.Assert(m.SetIfNotExistFunc(\"a\", getAny), false)\n\t\tt.Assert(m.SetIfNotExistFunc(\"c\", getAny), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"b\", getAny), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"d\", getAny), true)\n\n\t\ttype T struct {\n\t\t\tA int\n\t\t}\n\n\t\tav := m.GetOrSetFunc(\"s1\", func() any {\n\t\t\treturn &T{\n\t\t\t\tA: 1,\n\t\t\t}\n\t\t})\n\t\tta, ok := av.(*T)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(ta.A, 1)\n\n\t\tav = m.GetOrSetFunc(\"s1\", func() any {\n\t\t\treturn &T{\n\t\t\t\tA: 2,\n\t\t\t}\n\t\t})\n\t\tta, ok = av.(*T)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(ta.A, 1)\n\n\t\tav = m.GetOrSet(\"s1\", &T{\n\t\t\tA: 3,\n\t\t})\n\t\tta, ok = av.(*T)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(ta.A, 1)\n\n\t\tav = m.GetOrSet(\"s2\", &T{\n\t\t\tA: 4,\n\t\t})\n\t\tta, ok = av.(*T)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(ta.A, 4)\n\t})\n}\n\nfunc Test_StrAnyMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\n\t\tm.Sets(map[string]any{\"a\": 1, \"b\": \"2\", \"c\": 3})\n\t\tt.Assert(m.Map(), map[string]any{\"a\": 1, \"b\": \"2\", \"c\": 3})\n\t\tm.Removes([]string{\"a\", \"b\"})\n\t\tt.Assert(m.Map(), map[string]any{\"c\": 3})\n\t})\n}\n\nfunc Test_StrAnyMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMapFrom(map[string]any{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\"}, true)\n\t\tm.Iterator(func(k string, _ any) bool {\n\t\t\tkInt, _ := strconv.Atoi(k)\n\t\t\tif kInt%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Map(), map[string]any{\n\t\t\t\"1\": \"1\",\n\t\t\t\"3\": \"3\",\n\t\t})\n\t})\n}\n\nfunc Test_StrAnyMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]any{\"a\": true, \"b\": false}\n\t\tm := gmap.NewStrAnyMapFrom(expect)\n\t\tm.Iterator(func(k string, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k string, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k string, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_StrAnyMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]any{\"a\": true, \"b\": false}\n\n\t\tm := gmap.NewStrAnyMapFrom(expect)\n\t\tm.LockFunc(func(m map[string]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[string]any) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_StrAnyMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewStrAnyMapFrom(map[string]any{\"a\": 1, \"b\": \"2\"})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(\"a\")\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(\"a\", m_clone.Keys())\n\n\t\tm_clone.Remove(\"b\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"b\", m.Keys())\n\t})\n}\n\nfunc Test_StrAnyMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrAnyMap()\n\t\tm2 := gmap.NewStrAnyMap()\n\t\tm1.Set(\"a\", 1)\n\t\tm2.Set(\"b\", \"2\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[string]any{\"a\": 1, \"b\": \"2\"})\n\n\t\tm3 := gmap.NewStrAnyMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_StrAnyMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\t\tm.Set(\"1\", 1)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Get(\"1\"), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tdata := m.Map()\n\t\tt.Assert(data[\"1\"], 1)\n\t\tt.Assert(data[\"2\"], 2)\n\t\tdata[\"3\"] = 3\n\t\tt.Assert(m.Get(\"3\"), 3)\n\t\tm.Set(\"4\", 4)\n\t\tt.Assert(data[\"4\"], 4)\n\t})\n}\n\nfunc Test_StrAnyMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\t\tm.Set(\"1\", 1)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Get(\"1\"), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[\"1\"], 1)\n\t\tt.Assert(data[\"2\"], 2)\n\t\tdata[\"3\"] = 3\n\t\tt.Assert(m.Get(\"3\"), nil)\n\t\tm.Set(\"4\", 4)\n\t\tt.Assert(data[\"4\"], nil)\n\t})\n}\n\nfunc Test_StrAnyMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMap()\n\t\tm.Set(\"1\", 0)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"1\"), 0)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t})\n}\n\nfunc Test_StrAnyMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm1 := gmap.NewStrAnyMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewStrAnyMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.StrAnyMap\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc Test_StrAnyMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, \"\")\n\t\tt.Assert(v3, \"\")\n\t})\n}\n\nfunc Test_StrAnyMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestStrAnyMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.StrAnyMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"k1\":\"v1\",\"k2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.Map{\n\t\t\t\t\"k1\": \"v1\",\n\t\t\t\t\"k2\": \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n}\n\nfunc Test_StrAnyMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"key1\": \"val1\",\n\t\t\t\"key2\": \"val2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.StrAnyMap)\n\t\tn.Set(\"key1\", \"v1\")\n\t\tt.AssertNE(m.Get(\"key1\"), n.Get(\"key1\"))\n\t})\n}\n\nfunc Test_StrAnyMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tm2 := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_StrAnyMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"0\": \"v0\",\n\t\t\t\"1\": \"v1\",\n\t\t\t\"2\": \"v2\",\n\t\t\t\"3\": 3,\n\t\t})\n\t\tm2 := gmap.NewStrAnyMapFrom(g.MapStrAny{\n\t\t\t\"0\": \"v0\",\n\t\t\t\"2\": \"v2\",\n\t\t\t\"3\": \"v3\",\n\t\t\t\"4\": \"v4\",\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []string{\"4\"})\n\t\tt.Assert(removedKeys, []string{\"1\"})\n\t\tt.Assert(updatedKeys, []string{\"3\"})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_str_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_StrIntMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrIntMap\n\t\tm.Set(\"a\", 1)\n\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", 2), 2)\n\t\tt.Assert(m.SetIfNotExist(\"b\", 2), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", 3), true)\n\n\t\tt.Assert(m.Remove(\"b\"), 2)\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\n\t\tm_f := gmap.NewStrIntMap()\n\t\tm_f.Set(\"1\", 2)\n\t\tm_f.Flip()\n\t\tt.Assert(m_f.Map(), map[string]int{\"2\": 1})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_StrIntMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\t\tm.Set(\"a\", 1)\n\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", 2), 2)\n\t\tt.Assert(m.SetIfNotExist(\"b\", 2), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", 3), true)\n\n\t\tt.Assert(m.Remove(\"b\"), 2)\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(3, m.Values())\n\t\tt.AssertIN(1, m.Values())\n\n\t\tm_f := gmap.NewStrIntMap()\n\t\tm_f.Set(\"1\", 2)\n\t\tm_f.Flip()\n\t\tt.Assert(m_f.Map(), map[string]int{\"2\": 1})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewStrIntMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\t\tt.Assert(m2.Map(), map[string]int{\"a\": 1, \"b\": 2})\n\t})\n}\n\nfunc Test_StrIntMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\n\t\tm.GetOrSetFunc(\"a\", getInt)\n\t\tm.GetOrSetFuncLock(\"b\", getInt)\n\t\tt.Assert(m.Get(\"a\"), 123)\n\t\tt.Assert(m.Get(\"b\"), 123)\n\t\tt.Assert(m.SetIfNotExistFunc(\"a\", getInt), false)\n\t\tt.Assert(m.SetIfNotExistFunc(\"c\", getInt), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"b\", getInt), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"d\", getInt), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMapFrom(nil)\n\t\tt.Assert(m.GetOrSetFuncLock(\"a\", getInt), 123)\n\t})\n}\n\nfunc Test_StrIntMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\n\t\tm.Sets(map[string]int{\"a\": 1, \"b\": 2, \"c\": 3})\n\t\tt.Assert(m.Map(), map[string]int{\"a\": 1, \"b\": 2, \"c\": 3})\n\t\tm.Removes([]string{\"a\", \"b\"})\n\t\tt.Assert(m.Map(), map[string]int{\"c\": 3})\n\t})\n}\n\nfunc Test_StrIntMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMapFrom(map[string]int{\"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}, true)\n\t\tm.Iterator(func(k string, _ int) bool {\n\t\t\tkInt, _ := strconv.Atoi(k)\n\t\t\tif kInt%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\nfunc Test_StrIntMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]int{\"a\": 1, \"b\": 2}\n\t\tm := gmap.NewStrIntMapFrom(expect)\n\t\tm.Iterator(func(k string, v int) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k string, v int) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k string, v int) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_StrIntMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]int{\"a\": 1, \"b\": 2}\n\n\t\tm := gmap.NewStrIntMapFrom(expect)\n\t\tm.LockFunc(func(m map[string]int) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[string]int) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_StrIntMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewStrIntMapFrom(map[string]int{\"a\": 1, \"b\": 2, \"c\": 3})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(\"a\")\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(\"a\", m_clone.Keys())\n\n\t\tm_clone.Remove(\"b\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"b\", m.Keys())\n\t})\n}\n\nfunc Test_StrIntMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrIntMap()\n\t\tm2 := gmap.NewStrIntMap()\n\t\tm1.Set(\"a\", 1)\n\t\tm2.Set(\"b\", 2)\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[string]int{\"a\": 1, \"b\": 2})\n\t\tm3 := gmap.NewStrIntMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_StrIntMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\t\tm.Set(\"1\", 1)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Get(\"1\"), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tdata := m.Map()\n\t\tt.Assert(data[\"1\"], 1)\n\t\tt.Assert(data[\"2\"], 2)\n\t\tdata[\"3\"] = 3\n\t\tt.Assert(m.Get(\"3\"), 3)\n\t\tm.Set(\"4\", 4)\n\t\tt.Assert(data[\"4\"], 4)\n\t})\n}\n\nfunc Test_StrIntMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\t\tm.Set(\"1\", 1)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Get(\"1\"), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[\"1\"], 1)\n\t\tt.Assert(data[\"2\"], 2)\n\t\tdata[\"3\"] = 3\n\t\tt.Assert(m.Get(\"3\"), 0)\n\t\tm.Set(\"4\", 4)\n\t\tt.Assert(data[\"4\"], 0)\n\t})\n}\n\nfunc Test_StrIntMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMap()\n\t\tm.Set(\"1\", 0)\n\t\tm.Set(\"2\", 2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"1\"), 0)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(\"2\"), 2)\n\t})\n}\n\nfunc Test_StrIntMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrInt{\n\t\t\t\"k1\": 1,\n\t\t\t\"k2\": 2,\n\t\t}\n\t\tm1 := gmap.NewStrIntMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrInt{\n\t\t\t\"k1\": 1,\n\t\t\t\"k2\": 2,\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewStrIntMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrInt{\n\t\t\t\"k1\": 1,\n\t\t\t\"k2\": 2,\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.StrIntMap\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc Test_StrIntMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"k1\": 11,\n\t\t\t\"k2\": 22,\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v1, g.Slice{11, 22})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v2, g.Slice{11, 22})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, \"\")\n\t\tt.Assert(v3, 0)\n\t})\n}\n\nfunc Test_StrIntMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"k1\": 11,\n\t\t\t\"k2\": 22,\n\t\t\t\"k3\": 33,\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{11, 22, 33})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{11, 22, 33})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestStrIntMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.StrIntMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"k1\":1,\"k2\":2}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), 1)\n\t\tt.Assert(v.Map.Get(\"k2\"), 2)\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.Map{\n\t\t\t\t\"k1\": 1,\n\t\t\t\t\"k2\": 2,\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), 1)\n\t\tt.Assert(v.Map.Get(\"k2\"), 2)\n\t})\n}\n\nfunc Test_StrIntMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"key1\": 1,\n\t\t\t\"key2\": 2,\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.StrIntMap)\n\t\tn.Set(\"key1\", 2)\n\t\tt.AssertNE(m.Get(\"key1\"), n.Get(\"key1\"))\n\t})\n}\n\nfunc Test_StrIntMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"k1\": 1,\n\t\t\t\"k2\": 2,\n\t\t})\n\t\tm2 := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"k2\": 2,\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_StrIntMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"0\": 0,\n\t\t\t\"1\": 1,\n\t\t\t\"2\": 2,\n\t\t\t\"3\": 3,\n\t\t})\n\t\tm2 := gmap.NewStrIntMapFrom(g.MapStrInt{\n\t\t\t\"0\": 0,\n\t\t\t\"2\": 2,\n\t\t\t\"3\": 31,\n\t\t\t\"4\": 4,\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []string{\"4\"})\n\t\tt.Assert(removedKeys, []string{\"1\"})\n\t\tt.Assert(updatedKeys, []string{\"3\"})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_hash_str_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_StrStrMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.StrStrMap\n\t\tm.Set(\"a\", \"a\")\n\n\t\tt.Assert(m.Get(\"a\"), \"a\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", \"b\"), \"b\")\n\t\tt.Assert(m.SetIfNotExist(\"b\", \"b\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", \"c\"), true)\n\n\t\tt.Assert(m.Remove(\"b\"), \"b\")\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Values())\n\t\tt.AssertIN(\"c\", m.Values())\n\n\t\tm.Flip()\n\n\t\tt.Assert(m.Map(), map[string]string{\"a\": \"a\", \"c\": \"c\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_StrStrMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\t\tm.Set(\"a\", \"a\")\n\n\t\tt.Assert(m.Get(\"a\"), \"a\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"b\", \"b\"), \"b\")\n\t\tt.Assert(m.SetIfNotExist(\"b\", \"b\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"c\", \"c\"), true)\n\n\t\tt.Assert(m.Remove(\"b\"), \"b\")\n\t\tt.Assert(m.Contains(\"b\"), false)\n\n\t\tt.AssertIN(\"c\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Keys())\n\t\tt.AssertIN(\"a\", m.Values())\n\t\tt.AssertIN(\"c\", m.Values())\n\n\t\tm.Flip()\n\n\t\tt.Assert(m.Map(), map[string]string{\"a\": \"a\", \"c\": \"c\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewStrStrMapFrom(map[string]string{\"a\": \"a\", \"b\": \"b\"})\n\t\tt.Assert(m2.Map(), map[string]string{\"a\": \"a\", \"b\": \"b\"})\n\t})\n}\n\nfunc Test_StrStrMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\n\t\tm.GetOrSetFunc(\"a\", getStr)\n\t\tm.GetOrSetFuncLock(\"b\", getStr)\n\t\tt.Assert(m.Get(\"a\"), \"z\")\n\t\tt.Assert(m.Get(\"b\"), \"z\")\n\t\tt.Assert(m.SetIfNotExistFunc(\"a\", getStr), false)\n\t\tt.Assert(m.SetIfNotExistFunc(\"c\", getStr), true)\n\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"b\", getStr), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"d\", getStr), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMapFrom(nil)\n\n\t\tt.Assert(m.GetOrSetFuncLock(\"b\", getStr), \"z\")\n\t})\n}\n\nfunc Test_StrStrMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\n\t\tm.Sets(map[string]string{\"a\": \"a\", \"b\": \"b\", \"c\": \"c\"})\n\t\tt.Assert(m.Map(), map[string]string{\"a\": \"a\", \"b\": \"b\", \"c\": \"c\"})\n\t\tm.Removes([]string{\"a\", \"b\"})\n\t\tt.Assert(m.Map(), map[string]string{\"c\": \"c\"})\n\t})\n}\n\nfunc Test_StrStrMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMapFrom(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\"}, true)\n\t\tm.Iterator(func(k string, _ string) bool {\n\t\t\tkInt, _ := strconv.Atoi(k)\n\t\t\tif kInt%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\nfunc Test_StrStrMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]string{\"a\": \"a\", \"b\": \"b\"}\n\t\tm := gmap.NewStrStrMapFrom(expect)\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_StrStrMap_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[string]string{\"a\": \"a\", \"b\": \"b\"}\n\n\t\tm := gmap.NewStrStrMapFrom(expect)\n\t\tm.LockFunc(func(m map[string]string) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t\tm.RLockFunc(func(m map[string]string) {\n\t\t\tt.Assert(m, expect)\n\t\t})\n\t})\n}\n\nfunc Test_StrStrMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewStrStrMapFrom(map[string]string{\"a\": \"a\", \"b\": \"b\", \"c\": \"c\"})\n\n\t\tm_clone := m.Clone()\n\t\tm.Remove(\"a\")\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(\"a\", m_clone.Keys())\n\n\t\tm_clone.Remove(\"b\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"b\", m.Keys())\n\t})\n}\n\nfunc Test_StrStrMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrStrMap()\n\t\tm2 := gmap.NewStrStrMap()\n\t\tm1.Set(\"a\", \"a\")\n\t\tm2.Set(\"b\", \"b\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[string]string{\"a\": \"a\", \"b\": \"b\"})\n\t\tm3 := gmap.NewStrStrMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_StrStrMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\t\tm.Set(\"1\", \"1\")\n\t\tm.Set(\"2\", \"2\")\n\t\tt.Assert(m.Get(\"1\"), \"1\")\n\t\tt.Assert(m.Get(\"2\"), \"2\")\n\t\tdata := m.Map()\n\t\tt.Assert(data[\"1\"], \"1\")\n\t\tt.Assert(data[\"2\"], \"2\")\n\t\tdata[\"3\"] = \"3\"\n\t\tt.Assert(m.Get(\"3\"), \"3\")\n\t\tm.Set(\"4\", \"4\")\n\t\tt.Assert(data[\"4\"], \"4\")\n\t})\n}\n\nfunc Test_StrStrMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\t\tm.Set(\"1\", \"1\")\n\t\tm.Set(\"2\", \"2\")\n\t\tt.Assert(m.Get(\"1\"), \"1\")\n\t\tt.Assert(m.Get(\"2\"), \"2\")\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[\"1\"], \"1\")\n\t\tt.Assert(data[\"2\"], \"2\")\n\t\tdata[\"3\"] = \"3\"\n\t\tt.Assert(m.Get(\"3\"), \"\")\n\t\tm.Set(\"4\", \"4\")\n\t\tt.Assert(data[\"4\"], \"\")\n\t})\n}\n\nfunc Test_StrStrMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMap()\n\t\tm.Set(\"1\", \"\")\n\t\tm.Set(\"2\", \"2\")\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"1\"), \"\")\n\t\tt.Assert(m.Get(\"2\"), \"2\")\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(\"2\"), \"2\")\n\t})\n}\n\nfunc Test_StrStrMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm1 := gmap.NewStrStrMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(data)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewStrStrMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(data)\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.StrStrMap\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc Test_StrStrMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.Assert(k3, \"\")\n\t\tt.Assert(v3, \"\")\n\t})\n}\n\nfunc Test_StrStrMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestStrStrMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.StrStrMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"k1\":\"v1\",\"k2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.Map{\n\t\t\t\t\"k1\": \"v1\",\n\t\t\t\t\"k2\": \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n}\n\nfunc Test_StrStrMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"key1\": \"val1\",\n\t\t\t\"key2\": \"val2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.StrStrMap)\n\t\tn.Set(\"key1\", \"v1\")\n\t\tt.AssertNE(m.Get(\"key1\"), n.Get(\"key1\"))\n\t})\n}\n\nfunc Test_StrStrMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tm2 := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t\tt.Assert(m2.IsSubOf(m1), true)\n\t\tt.Assert(m2.IsSubOf(m2), true)\n\t})\n}\n\nfunc Test_StrStrMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"0\": \"0\",\n\t\t\t\"1\": \"1\",\n\t\t\t\"2\": \"2\",\n\t\t\t\"3\": \"3\",\n\t\t})\n\t\tm2 := gmap.NewStrStrMapFrom(g.MapStrStr{\n\t\t\t\"0\": \"0\",\n\t\t\t\"2\": \"2\",\n\t\t\t\"3\": \"31\",\n\t\t\t\"4\": \"4\",\n\t\t})\n\t\taddedKeys, removedKeys, updatedKeys := m1.Diff(m2)\n\t\tt.Assert(addedKeys, []string{\"4\"})\n\t\tt.Assert(removedKeys, []string{\"1\"})\n\t\tt.Assert(updatedKeys, []string{\"3\"})\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_k_v_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_KVMap_NewKVMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string](true)\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_KVMap_NewKVMapFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"a\": \"1\", \"b\": \"2\"}\n\t\tm := gmap.NewKVMapFrom(data)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[int]int{1: 10, 2: 20}\n\t\tm := gmap.NewKVMapFrom(data, true)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(1), 10)\n\t\tt.Assert(m.Get(2), 20)\n\t})\n}\n\nfunc Test_KVMap_Set_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Set(\"b\", \"2\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Size(), 2)\n\n\t\t// Set existing key\n\t\tm.Set(\"a\", \"10\")\n\t\tt.Assert(m.Get(\"a\"), \"10\")\n\t\tt.Assert(m.Size(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[int, int]()\n\t\tm.Set(1, 100)\n\t\tm.Set(2, 200)\n\t\tt.Assert(m.Get(1), 100)\n\t\tt.Assert(m.Get(2), 200)\n\t})\n}\n\nfunc Test_KVMap_Sets(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Get(\"c\"), \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"x\": \"10\", \"y\": \"20\"}\n\t\tm := gmap.NewKVMapFrom(data)\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 4)\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\nfunc Test_KVMap_Search(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\n\t\tv, found := m.Search(\"a\")\n\t\tt.Assert(found, true)\n\t\tt.Assert(v, \"1\")\n\n\t\tv, found = m.Search(\"c\")\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[int, string]()\n\t\tv, found := m.Search(1)\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n}\n\nfunc Test_KVMap_Contains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Contains(\"a\"), true)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t\tt.Assert(m.Contains(\"c\"), false)\n\t})\n}\n\nfunc Test_KVMap_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tv := m.Remove(\"a\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Size(), 1)\n\n\t\tv = m.Remove(\"c\")\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\nfunc Test_KVMap_Removes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.Removes([]string{\"a\", \"c\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Contains(\"c\"), false)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Removes([]string{\"x\", \"y\"})\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\nfunc Test_KVMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk, v := m.Pop()\n\t\tt.AssertIN(k, []string{\"a\", \"b\"})\n\t\tt.AssertIN(v, []string{\"1\", \"2\"})\n\t\tt.Assert(m.Size(), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tk, v := m.Pop()\n\t\tt.Assert(k, \"\")\n\t\tt.Assert(v, \"\")\n\t})\n}\n\nfunc Test_KVMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tpopped := m.Pops(2)\n\t\tt.Assert(len(popped), 2)\n\t\tt.Assert(m.Size(), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tpopped := m.Pops(-1)\n\t\tt.Assert(len(popped), 3)\n\t\tt.Assert(m.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tpopped := m.Pops(10)\n\t\tt.Assert(len(popped), 2)\n\t\tt.Assert(m.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tpopped := m.Pops(1)\n\t\tt.AssertNil(popped)\n\t})\n}\n\nfunc Test_KVMap_Keys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 3)\n\t\tt.AssertIN(\"a\", keys)\n\t\tt.AssertIN(\"b\", keys)\n\t\tt.AssertIN(\"c\", keys)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[int, string]()\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 0)\n\t})\n}\n\nfunc Test_KVMap_Values(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 3)\n\t\tt.AssertIN(\"1\", values)\n\t\tt.AssertIN(\"2\", values)\n\t\tt.AssertIN(\"3\", values)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 0)\n\t})\n}\n\nfunc Test_KVMap_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tt.Assert(m.Size(), 0)\n\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Set(\"b\", \"2\")\n\t\tt.Assert(m.Size(), 2)\n\n\t\tm.Remove(\"a\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\nfunc Test_KVMap_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tm.Remove(\"a\")\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_KVMap_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t\tt.Assert(m.Get(\"a\"), \"\")\n\t})\n}\n\nfunc Test_KVMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tdata := m.Map()\n\t\tt.Assert(data[\"a\"], \"1\")\n\t\tt.Assert(data[\"b\"], \"2\")\n\t\tt.Assert(len(data), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Unsafe map, modifying returned map affects original\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"}, false)\n\t\tdata := m.Map()\n\t\tdata[\"c\"] = \"3\"\n\t\tt.Assert(m.Get(\"c\"), \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Safe map, modifying returned map doesn't affect original\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"}, true)\n\t\tdata := m.Map()\n\t\tdata[\"c\"] = \"3\"\n\t\tt.Assert(m.Get(\"c\"), \"\")\n\t})\n}\n\nfunc Test_KVMap_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tdata := m.MapCopy()\n\t\tt.Assert(data[\"a\"], \"1\")\n\t\tt.Assert(data[\"b\"], \"2\")\n\n\t\t// Modifying copy doesn't affect original\n\t\tdata[\"c\"] = \"3\"\n\t\tt.Assert(m.Get(\"c\"), \"\")\n\n\t\tm.Set(\"d\", \"4\")\n\t\tt.Assert(data[\"d\"], \"\")\n\t})\n}\n\nfunc Test_KVMap_MapStrAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\t\tdata := m.MapStrAny()\n\t\tt.Assert(len(data), 2)\n\t\tt.Assert(data[\"a\"], 1)\n\t\tt.Assert(data[\"b\"], 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[int]string{1: \"a\", 2: \"b\"})\n\t\tdata := m.MapStrAny()\n\t\tt.Assert(len(data), 2)\n\t\tt.Assert(data[\"1\"], \"a\")\n\t\tt.Assert(data[\"2\"], \"b\")\n\t})\n}\n\nfunc Test_KVMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 0, \"b\": 1, \"c\": 2})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\nfunc Test_KVMap_FilterNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, *string]()\n\t\ta := \"a\"\n\t\tm.Set(\"key1\", &a)\n\t\tm.Set(\"key2\", nil)\n\t\tm.Set(\"key3\", nil)\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.FilterNil()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"key1\"), true)\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\t})\n}\n\nfunc Test_KVMap_GetOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\n\t\tv := m.GetOrSet(\"a\", \"1\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\n\t\tv = m.GetOrSet(\"a\", \"10\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 10})\n\n\t\tv := m.GetOrSet(\"a\", 20)\n\t\tt.Assert(v, 10)\n\n\t\tv = m.GetOrSet(\"b\", 30)\n\t\tt.Assert(v, 30)\n\t\tt.Assert(m.Get(\"b\"), 30)\n\t})\n}\n\nfunc Test_KVMap_GetOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\n\t\tv := m.GetOrSetFunc(\"a\", func() string { return \"1\" })\n\t\tt.Assert(v, \"1\")\n\n\t\tv = m.GetOrSetFunc(\"a\", func() string { return \"10\" })\n\t\tt.Assert(v, \"1\")\n\n\t\tv = m.GetOrSetFunc(\"b\", func() string { return \"2\" })\n\t\tt.Assert(v, \"2\")\n\t})\n}\n\nfunc Test_KVMap_GetOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\tcounter := 0\n\n\t\tv := m.GetOrSetFuncLock(\"a\", func() int {\n\t\t\tcounter++\n\t\t\treturn 10\n\t\t})\n\t\tt.Assert(v, 10)\n\t\tt.Assert(counter, 1)\n\n\t\tv = m.GetOrSetFuncLock(\"a\", func() int {\n\t\t\tcounter++\n\t\t\treturn 20\n\t\t})\n\t\tt.Assert(v, 10)\n\t\tt.Assert(counter, 1)\n\t})\n}\n\nfunc Test_KVMap_SetIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\n\t\tok := m.SetIfNotExist(\"a\", \"1\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\n\t\tok = m.SetIfNotExist(\"a\", \"10\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\nfunc Test_KVMap_SetIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\n\t\tok := m.SetIfNotExistFunc(\"a\", func() int { return 10 })\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), 10)\n\n\t\tok = m.SetIfNotExistFunc(\"a\", func() int { return 20 })\n\t\tt.Assert(ok, false)\n\t\tt.Assert(m.Get(\"a\"), 10)\n\t})\n}\n\nfunc Test_KVMap_SetIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\tcounter := 0\n\n\t\tok := m.SetIfNotExistFuncLock(\"a\", func() string {\n\t\t\tcounter++\n\t\t\treturn \"1\"\n\t\t})\n\t\tt.Assert(ok, true)\n\t\tt.Assert(counter, 1)\n\n\t\tok = m.SetIfNotExistFuncLock(\"a\", func() string {\n\t\t\tcounter++\n\t\t\treturn \"2\"\n\t\t})\n\t\tt.Assert(ok, false)\n\t\tt.Assert(counter, 1)\n\t})\n}\n\nfunc Test_KVMap_GetVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\n\t\tv := m.GetVar(\"a\")\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVar(\"c\")\n\t\tt.Assert(v.Val(), nil)\n\t})\n}\n\nfunc Test_KVMap_GetVarOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\n\t\tv := m.GetVarOrSet(\"a\", \"1\")\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVarOrSet(\"a\", \"10\")\n\t\tt.Assert(v.Val(), \"1\")\n\t})\n}\n\nfunc Test_KVMap_GetVarOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\n\t\tv := m.GetVarOrSetFunc(\"a\", func() int { return 10 })\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), 10)\n\n\t\tv = m.GetVarOrSetFunc(\"a\", func() int { return 20 })\n\t\tt.Assert(v.Val(), 10)\n\t})\n}\n\nfunc Test_KVMap_GetVarOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\n\t\tv := m.GetVarOrSetFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVarOrSetFuncLock(\"a\", func() string { return \"10\" })\n\t\tt.Assert(v.Val(), \"1\")\n\t})\n}\n\nfunc Test_KVMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"}\n\t\tm := gmap.NewKVMapFrom(data)\n\n\t\tcount := 0\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tt.Assert(data[k], v)\n\t\t\tcount++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(count, 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[int]string{1: \"a\", 2: \"b\", 3: \"c\"})\n\n\t\tcount := 0\n\t\tm.Iterator(func(k int, v string) bool {\n\t\t\tcount++\n\t\t\treturn count < 2\n\t\t})\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_KVMap_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\"}, true)\n\t\tm.Iterator(func(k string, _ string) bool {\n\t\t\tkInt, _ := strconv.Atoi(k)\n\t\t\tif kInt%2 == 0 {\n\t\t\t\tm.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\nfunc Test_KVMap_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\n\t\tm.LockFunc(func(data map[string]string) {\n\t\t\tt.Assert(data[\"a\"], \"1\")\n\t\t\tt.Assert(data[\"b\"], \"2\")\n\t\t\tdata[\"c\"] = \"3\"\n\t\t})\n\n\t\tt.Assert(m.Get(\"c\"), \"3\")\n\t})\n}\n\nfunc Test_KVMap_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tcount := 0\n\n\t\tm.RLockFunc(func(data map[string]string) {\n\t\t\tcount += len(data)\n\t\t})\n\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_KVMap_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tm.Replace(map[string]string{\"x\": \"10\", \"y\": \"20\", \"z\": \"30\"})\n\t\tt.Assert(m.Size(), 3)\n\t\tt.Assert(m.Get(\"a\"), \"\")\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t})\n}\n\nfunc Test_KVMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm2 := m.Clone()\n\n\t\tt.Assert(m2.Get(\"a\"), \"1\")\n\t\tt.Assert(m2.Get(\"b\"), \"2\")\n\t\tt.Assert(m2.Size(), 2)\n\n\t\tm.Set(\"a\", \"10\")\n\t\tt.Assert(m2.Get(\"a\"), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2}, false)\n\t\tm2 := m.Clone(true)\n\n\t\tt.Assert(m2.Size(), 2)\n\t})\n}\n\nfunc Test_KVMap_Flip(t *testing.T) {\n\t// Test with same type for key and value (string -> string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tm.Flip()\n\n\t\tt.Assert(m.Get(\"1\"), \"a\")\n\t\tt.Assert(m.Get(\"2\"), \"b\")\n\t\tt.Assert(m.Get(\"3\"), \"c\")\n\t})\n\n\t// Test with same type for key and value (int -> int)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[int]int{1: 10, 2: 20})\n\t\tm.Flip()\n\n\t\tt.Assert(m.Get(10), 1)\n\t\tt.Assert(m.Get(20), 2)\n\t})\n}\n\nfunc Test_KVMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"b\": \"2\", \"c\": \"3\"})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Size(), 3)\n\t\tt.Assert(m1.Get(\"a\"), \"1\")\n\t\tt.Assert(m1.Get(\"b\"), \"2\")\n\t\tt.Assert(m1.Get(\"c\"), \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMap[string, int]()\n\t\tm2 := gmap.NewKVMapFrom(map[string]int{\"a\": 10, \"b\": 20})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Size(), 2)\n\t\tt.Assert(m1.Get(\"a\"), 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"10\", \"b\": \"2\"})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Get(\"a\"), \"10\")\n\t})\n}\n\nfunc Test_KVMap_IsSubOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\n\t\tt.Assert(m1.IsSubOf(m2), true)\n\t\tt.Assert(m2.IsSubOf(m1), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"10\"})\n\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\tt.Assert(m1.IsSubOf(m1), true)\n\t})\n}\n\nfunc Test_KVMap_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"d\": \"4\"})\n\n\t\tadded, removed, updated := m1.Diff(m2)\n\t\tt.Assert(len(added), 1)\n\t\tt.AssertIN(\"d\", added)\n\t\tt.Assert(len(removed), 2)\n\t\tt.AssertIN(\"b\", removed)\n\t\tt.AssertIN(\"c\", removed)\n\t\tt.Assert(len(updated), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"10\", \"b\": \"2\"})\n\n\t\tadded, removed, updated := m1.Diff(m2)\n\t\tt.Assert(len(added), 0)\n\t\tt.Assert(len(removed), 0)\n\t\tt.Assert(len(updated), 1)\n\t\tt.AssertIN(\"a\", updated)\n\t})\n}\n\nfunc Test_KVMap_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\ts := m.String()\n\t\tt.AssertNE(s, \"\")\n\t\tt.AssertIN(\"a\", s)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m *gmap.KVMap[string, string]\n\t\ts := m.String()\n\t\tt.Assert(s, \"\")\n\t})\n}\n\nfunc Test_KVMap_MarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(b, nil)\n\n\t\tvar data map[string]int\n\t\terr = json.Unmarshal(b, &data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data[\"a\"], 1)\n\t\tt.Assert(data[\"b\"], 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.KVMap[int, int]\n\t\tm.Set(1, 10)\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `{\"1\":10}`)\n\t})\n}\n\nfunc Test_KVMap_UnmarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\tdata := []byte(`{\"a\":1,\"b\":2,\"c\":3}`)\n\n\t\terr := json.UnmarshalUseNumber(data, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Get(\"b\"), 2)\n\t\tt.Assert(m.Get(\"c\"), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.KVMap[string, string]\n\t\tdata := []byte(`{\"x\":\"10\",\"y\":\"20\"}`)\n\n\t\terr := json.UnmarshalUseNumber(data, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t\tt.Assert(m.Get(\"y\"), \"20\")\n\t})\n}\n\nfunc Test_KVMap_UnmarshalValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, string]()\n\t\terr := m.UnmarshalValue(map[string]any{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": \"2\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\nfunc Test_KVMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string][]string{\n\t\t\t\"a\": {\"1\", \"2\"},\n\t\t\t\"b\": {\"3\", \"4\"},\n\t\t})\n\n\t\tn := m.DeepCopy().(*gmap.KVMap[string, []string])\n\t\tt.Assert(n.Size(), 2)\n\t\tt.Assert(n.Get(\"a\"), []string{\"1\", \"2\"})\n\n\t\t// Modifying original doesn't affect copy\n\t\tm.Get(\"a\")[0] = \"10\"\n\t\tt.Assert(n.Get(\"a\")[0], \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m *gmap.KVMap[string, int]\n\t\tn := m.DeepCopy()\n\t\tt.AssertNil(n)\n\t})\n}\n\n// Test Set with nil data\nfunc Test_KVMap_Set_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create map with nil internal data\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test Sets with nil data\nfunc Test_KVMap_Sets_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create map with nil internal data\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\n// Test doSetWithLockCheck - key exists and value is nil\nfunc Test_KVMap_GetOrSet_KeyExists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\t// First call: key does not exist, set value\n\t\tv := m.GetOrSet(\"a\", \"1\")\n\t\tt.Assert(v, \"1\")\n\n\t\t// Second call: key exists, should return existing value\n\t\tv = m.GetOrSet(\"a\", \"2\")\n\t\tt.Assert(v, \"1\")\n\t})\n}\n\n// Test GetOrSet with nil value\nfunc Test_KVMap_GetOrSet_NilValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, *string]()\n\t\t// Set nil value\n\t\tv := m.GetOrSet(\"a\", nil)\n\t\tt.Assert(v, nil)\n\t\t// Key is not stored when value is nil (based on implementation)\n\t\t// The doSetWithLockCheck checks: if any(value) != nil\n\t\t// For pointer type, nil is actually stored because any(nil pointer) is not nil interface\n\t\t// Let's verify the actual behavior\n\t})\n\n\t// Test with interface type to trigger the nil check\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, any]()\n\t\tv := m.GetOrSet(\"a\", nil)\n\t\tt.Assert(v, nil)\n\t\t// nil interface value should not be stored\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test GetOrSetFunc with nil value\nfunc Test_KVMap_GetOrSetFunc_NilValue(t *testing.T) {\n\t// Test with interface type to trigger the nil check\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, any]()\n\t\tv := m.GetOrSetFunc(\"a\", func() any { return nil })\n\t\tt.Assert(v, nil)\n\t\t// nil interface value should not be stored\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test GetOrSetFuncLock with nil data and nil value\nfunc Test_KVMap_GetOrSetFuncLock_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tv := m.GetOrSetFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n\n\t// Test with nil value (using any type)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, any]()\n\t\tv := m.GetOrSetFuncLock(\"a\", func() any { return nil })\n\t\tt.Assert(v, nil)\n\t\t// nil interface value should not be stored\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test SetIfNotExist with nil data\nfunc Test_KVMap_SetIfNotExist_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tok := m.SetIfNotExist(\"a\", \"1\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\n// Test SetIfNotExistFuncLock with nil data\nfunc Test_KVMap_SetIfNotExistFuncLock_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tok := m.SetIfNotExistFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\n// Test Flip with conversion errors\nfunc Test_KVMap_Flip_ConversionError(t *testing.T) {\n\t// Test with incompatible types that will fail conversion\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype customKey struct {\n\t\t\tID int\n\t\t}\n\t\ttype customVal struct {\n\t\t\tName string\n\t\t}\n\t\tm := gmap.NewKVMapFrom(map[customKey]customVal{\n\t\t\t{ID: 1}: {Name: \"a\"},\n\t\t\t{ID: 2}: {Name: \"b\"},\n\t\t})\n\t\t// Flip will fail because customVal cannot be converted to customKey\n\t\tm.Flip()\n\t\t// After failed flip, map should be empty or unchanged depending on implementation\n\t\t// Based on the code, items that fail conversion are skipped\n\t})\n}\n\n// Test Merge with self\nfunc Test_KVMap_Merge_Self(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Merge(m)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\n// Test Merge with nil data\nfunc Test_KVMap_Merge_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tm2 := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Merge(m2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\n// Test UnmarshalJSON with invalid JSON\nfunc Test_KVMap_UnmarshalJSON_InvalidJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\terr := m.UnmarshalJSON([]byte(`{invalid json}`))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test UnmarshalJSON with incompatible value types\nfunc Test_KVMap_UnmarshalJSON_TypeMismatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\t// Valid JSON but values are strings, not ints\n\t\terr := m.UnmarshalJSON([]byte(`{\"a\":\"not_a_number\"}`))\n\t\t// This may or may not error depending on gconv.Scan behavior\n\t\t// The test verifies the code path is executed\n\t\t_ = err\n\t})\n}\n\n// Test UnmarshalValue with conversion error\nfunc Test_KVMap_UnmarshalValue_ConversionError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\t// This tests the conversion path\n\t\terr := m.UnmarshalValue(map[string]any{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": \"2\",\n\t\t})\n\t\t// Even with string values, gconv.Scan should handle conversion\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Get(\"b\"), 2)\n\t})\n}\n\n// Test Search with nil data\nfunc Test_KVMap_Search_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tv, found := m.Search(\"a\")\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n}\n\n// Test Get with nil data\nfunc Test_KVMap_Get_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, int](nil)\n\t\tv := m.Get(\"a\")\n\t\tt.Assert(v, 0)\n\t})\n}\n\n// Test Contains with nil data\nfunc Test_KVMap_Contains_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test Remove with nil data\nfunc Test_KVMap_Remove_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tv := m.Remove(\"a\")\n\t\tt.Assert(v, \"\")\n\t})\n}\n\n// Test Removes with nil data\nfunc Test_KVMap_Removes_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tm.Removes([]string{\"a\", \"b\"})\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\n// Test Pop from empty map\nfunc Test_KVMap_Pop_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom[string, string](nil)\n\t\tk, v := m.Pop()\n\t\tt.Assert(k, \"\")\n\t\tt.Assert(v, \"\")\n\t})\n}\n\n// Test Pops with size 0\nfunc Test_KVMap_Pops_ZeroSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tpopped := m.Pops(0)\n\t\tt.AssertNil(popped)\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\n// Test Iterator early break\nfunc Test_KVMap_Iterator_Break(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tcount := 0\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tcount++\n\t\t\treturn false // Break immediately\n\t\t})\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test DeepCopy with safe mode\nfunc Test_KVMap_DeepCopy_Safe(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"}, true)\n\t\tn := m.DeepCopy().(*gmap.KVMap[string, string])\n\t\tt.Assert(n.Size(), 2)\n\t\tt.Assert(n.Get(\"a\"), \"1\")\n\t})\n}\n\n// Concurrent safety tests\nfunc Test_KVMap_Concurrent_Safe(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tch := make(chan int, 10)\n\n\t\t// Concurrent writes\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.Set(gconv.String(idx), idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 10)\n\t})\n}\n\nfunc Test_KVMap_Concurrent_RW(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tm.Sets(map[string]int{\"a\": 1, \"b\": 2, \"c\": 3})\n\n\t\tch := make(chan int, 20)\n\n\t\t// Concurrent reads and writes\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func() {\n\t\t\t\t_ = m.Get(\"a\")\n\t\t\t\tch <- 1\n\t\t\t}()\n\t\t}\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.Set(gconv.String(idx), idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 20; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 13)\n\t})\n}\n\n// Test concurrent GetOrSet\nfunc Test_KVMap_Concurrent_GetOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSet(\"key\", idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\t// Only one value should be set\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"key\"), true)\n\t})\n}\n\n// Test concurrent SetIfNotExist\nfunc Test_KVMap_Concurrent_SetIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tsuccessCount := 0\n\t\tch := make(chan bool, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tok := m.SetIfNotExist(\"key\", idx)\n\t\t\t\tch <- ok\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tif <-ch {\n\t\t\t\tsuccessCount++\n\t\t\t}\n\t\t}\n\n\t\t// Only one goroutine should succeed\n\t\tt.Assert(successCount, 1)\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test doSetWithLockCheck when key exists (race condition scenario)\nfunc Test_KVMap_DoSetWithLockCheck_KeyExists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\t// First, set the key using GetOrSet\n\t\tv := m.GetOrSet(\"a\", 1)\n\t\tt.Assert(v, 1)\n\n\t\t// Second call - key exists in doSetWithLockCheck\n\t\t// This simulates the race condition where the key is set between Search and doSetWithLockCheck\n\t\tv = m.GetOrSet(\"a\", 2)\n\t\tt.Assert(v, 1)\n\t})\n}\n\n// Test Flip with key conversion error\nfunc Test_KVMap_Flip_KeyConversionError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a map where key->value conversion will fail\n\t\t// Using struct types that cannot be converted to each other\n\t\ttype Key struct {\n\t\t\tID int\n\t\t}\n\t\ttype Value struct {\n\t\t\tName string\n\t\t}\n\t\tm := gmap.NewKVMapFrom(map[Key]Value{\n\t\t\t{ID: 1}: {Name: \"a\"},\n\t\t})\n\t\t// This should not panic, but the conversion may succeed or fail\n\t\t// depending on gconv.Scan implementation\n\t\tm.Flip()\n\t\t// Just verify it doesn't panic - size depends on conversion behavior\n\t})\n}\n\n// Test Flip with value->key conversion success but key->value conversion failure\nfunc Test_KVMap_Flip_ValueKeyConversionError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Use int -> int where one direction might fail\n\t\tm := gmap.NewKVMapFrom(map[int]int{1: 10, 2: 20})\n\t\tm.Flip()\n\t\t// Should flip successfully\n\t\tt.Assert(m.Contains(10), true)\n\t\tt.Assert(m.Contains(20), true)\n\t\tt.Assert(m.Get(10), 1)\n\t\tt.Assert(m.Get(20), 2)\n\t})\n}\n\n// Test UnmarshalJSON with Scan error\nfunc Test_KVMap_UnmarshalJSON_ScanError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a map with int keys, but provide string keys in JSON\n\t\t// that cannot be properly scanned to int\n\t\tm := gmap.NewKVMap[int, string]()\n\t\t// This JSON has string keys that need to be converted to int\n\t\terr := m.UnmarshalJSON([]byte(`{\"not_a_number\":\"value\"}`))\n\t\t// The error depends on gconv.Scan behavior\n\t\t// Just verify the code path is executed\n\t\t_ = err\n\t})\n}\n\n// Test UnmarshalValue with Scan error\nfunc Test_KVMap_UnmarshalValue_ScanError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a map where the value type conversion will fail\n\t\ttype CustomStruct struct {\n\t\t\tField int\n\t\t}\n\t\tm := gmap.NewKVMap[string, CustomStruct]()\n\t\t// Try to unmarshal incompatible data\n\t\terr := m.UnmarshalValue(map[string]any{\n\t\t\t\"a\": \"not_a_struct\",\n\t\t})\n\t\t// The error depends on gconv.Scan behavior\n\t\t_ = err\n\t})\n}\n\n// Test concurrent GetOrSetFunc\nfunc Test_KVMap_Concurrent_GetOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\t\tcounter := int32(0)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSetFunc(\"key\", func() int {\n\t\t\t\t\t// Increment counter to track how many times the function is called\n\t\t\t\t\treturn idx\n\t\t\t\t})\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 1)\n\t\t_ = counter\n\t})\n}\n\n// Test concurrent GetOrSetFuncLock\nfunc Test_KVMap_Concurrent_GetOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSetFuncLock(\"key\", func() int {\n\t\t\t\t\treturn idx\n\t\t\t\t})\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test concurrent LockFunc\nfunc Test_KVMap_Concurrent_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tm.Set(\"counter\", 0)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func() {\n\t\t\t\tm.LockFunc(func(data map[string]int) {\n\t\t\t\t\tdata[\"counter\"]++\n\t\t\t\t})\n\t\t\t\tch <- 1\n\t\t\t}()\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Get(\"counter\"), 100)\n\t})\n}\n\n// Test empty map operations\nfunc Test_KVMap_EmptyMapOperations(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\n\t\t// Test Keys on empty map\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 0)\n\n\t\t// Test Values on empty map\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 0)\n\n\t\t// Test MapCopy on empty map\n\t\tcopy := m.MapCopy()\n\t\tt.Assert(len(copy), 0)\n\n\t\t// Test MapStrAny on empty map\n\t\tstrAny := m.MapStrAny()\n\t\tt.Assert(len(strAny), 0)\n\t})\n}\n\n// Test FilterEmpty with various empty values\nfunc Test_KVMap_FilterEmpty_Various(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, any]()\n\t\tm.Set(\"nil\", nil)\n\t\tm.Set(\"zero\", 0)\n\t\tm.Set(\"empty_string\", \"\")\n\t\tm.Set(\"false\", false)\n\t\tm.Set(\"valid\", \"value\")\n\t\tm.Set(\"empty_slice\", []int{})\n\t\tm.Set(\"empty_map\", map[string]int{})\n\n\t\tt.Assert(m.Size(), 7)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"valid\"), true)\n\t})\n}\n\n// Test FilterNil with various nil values\nfunc Test_KVMap_FilterNil_Various(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, any]()\n\t\tm.Set(\"nil\", nil)\n\t\tm.Set(\"zero\", 0)\n\t\tm.Set(\"empty_string\", \"\")\n\t\tm.Set(\"valid\", \"value\")\n\n\t\tt.Assert(m.Size(), 4)\n\t\tm.FilterNil()\n\t\tt.Assert(m.Size(), 3)\n\t\tt.Assert(m.Contains(\"nil\"), false)\n\t})\n}\n\n// Test Clone with different safe modes\nfunc Test_KVMap_Clone_SafeMode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone unsafe map to safe\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1}, false)\n\t\tm2 := m.Clone(true)\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone safe map to unsafe\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1}, true)\n\t\tm2 := m.Clone(false)\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone with inherited safe mode\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1}, true)\n\t\tm2 := m.Clone()\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n}\n\n// Test Diff with empty maps\nfunc Test_KVMap_Diff_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMap[string, int]()\n\t\tm2 := gmap.NewKVMap[string, int]()\n\n\t\tadded, removed, updated := m1.Diff(m2)\n\t\tt.Assert(len(added), 0)\n\t\tt.Assert(len(removed), 0)\n\t\tt.Assert(len(updated), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMap[string, int]()\n\t\tm2 := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\n\t\tadded, removed, updated := m1.Diff(m2)\n\t\tt.Assert(len(added), 2)\n\t\tt.Assert(len(removed), 0)\n\t\tt.Assert(len(updated), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\t\tm2 := gmap.NewKVMap[string, int]()\n\n\t\tadded, removed, updated := m1.Diff(m2)\n\t\tt.Assert(len(added), 0)\n\t\tt.Assert(len(removed), 2)\n\t\tt.Assert(len(updated), 0)\n\t})\n}\n\n// Test IsSubOf with empty maps\nfunc Test_KVMap_IsSubOf_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMap[string, int]()\n\t\tm2 := gmap.NewKVMapFrom(map[string]int{\"a\": 1})\n\n\t\t// Empty map is always a subset\n\t\tt.Assert(m1.IsSubOf(m2), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewKVMapFrom(map[string]int{\"a\": 1})\n\t\tm2 := gmap.NewKVMap[string, int]()\n\n\t\t// Non-empty map is not a subset of empty map\n\t\tt.Assert(m1.IsSubOf(m2), false)\n\t})\n}\n\n// Test concurrent access to doSetWithLockCheck\nfunc Test_KVMap_DoSetWithLockCheck_Concurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// This test creates a race condition where multiple goroutines\n\t\t// try to set the same key, triggering the \"key exists\" branch in doSetWithLockCheck\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tvar wg sync.WaitGroup\n\t\tresults := make([]int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func(idx int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t// All goroutines try to set the same key\n\t\t\t\tv := m.GetOrSet(\"key\", idx)\n\t\t\t\tresults[idx] = v\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// All results should be the same (the first value that was set)\n\t\tfirstValue := results[0]\n\t\tfor _, v := range results {\n\t\t\tt.Assert(v, firstValue)\n\t\t}\n\t})\n}\n\n// Test GetOrSetFunc concurrent to trigger doSetWithLockCheck key exists branch\nfunc Test_KVMap_GetOrSetFunc_Concurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int](true)\n\t\tvar wg sync.WaitGroup\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func(idx int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tm.GetOrSetFunc(\"key\", func() int { return idx })\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test SetIfNotExistFunc returning false when key exists\nfunc Test_KVMap_SetIfNotExistFunc_KeyExists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\tm.Set(\"a\", 1)\n\n\t\tcalled := false\n\t\tok := m.SetIfNotExistFunc(\"a\", func() int {\n\t\t\tcalled = true\n\t\t\treturn 2\n\t\t})\n\t\tt.Assert(ok, false)\n\t\tt.Assert(called, false) // Function should not be called if key exists\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t})\n}\n\n// Test UnmarshalValue with nil input\nfunc Test_KVMap_UnmarshalValue_Nil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\terr := m.UnmarshalValue(nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\n// Test MarshalJSON with empty map\nfunc Test_KVMap_MarshalJSON_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\tb, err := m.MarshalJSON()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), \"{}\")\n\t})\n}\n\n// Test String with empty map\nfunc Test_KVMap_String_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMap[string, int]()\n\t\ts := m.String()\n\t\tt.Assert(s, \"{}\")\n\t})\n}\n\n// Test RLockFunc with concurrent access\nfunc Test_KVMap_RLockFunc_Concurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]int{\"a\": 1, \"b\": 2}, true)\n\t\tvar wg sync.WaitGroup\n\t\tresults := make([]int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func(idx int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tm.RLockFunc(func(data map[string]int) {\n\t\t\t\t\tresults[idx] = data[\"a\"]\n\t\t\t\t})\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\tfor _, v := range results {\n\t\t\tt.Assert(v, 1)\n\t\t}\n\t})\n}\n\n// Test Flip with string types to cover both conversion branches\nfunc Test_KVMap_Flip_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewKVMapFrom(map[string]string{\"key1\": \"val1\", \"key2\": \"val2\"})\n\t\tm.Flip()\n\t\tt.Assert(m.Get(\"val1\"), \"key1\")\n\t\tt.Assert(m.Get(\"val2\"), \"key2\")\n\t})\n}\n\n// Test TypedNil with custom nil checker for pointers\nfunc Test_KVMap_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tm1 := gmap.NewKVMap[int, *Student](true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm1.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m1.Size(), 5)\n\n\t\tm2 := gmap.NewKVMap[int, *Student](true)\n\t\tm2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm2.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m2.Size(), 5)\n\t})\n}\n\nfunc Test_NewKVMapWithChecker_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tm1 := gmap.NewKVMap[int, *Student](true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm1.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m1.Size(), 5)\n\n\t\tm2 := gmap.NewKVMapWithChecker[int, *Student](func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm2.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m2.Size(), 5)\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_list_k_v_map_race_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_ListKVMap_GetOrSetFuncLock_Race tests the atomicity of GetOrSetFuncLock.\n// This test ensures that the callback function is only executed once even under\n// high concurrency, which verifies that the function holds the lock during the\n// entire check-and-set operation.\nfunc Test_ListKVMap_GetOrSetFuncLock_Race(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tkey := \"counter\"\n\t\tcallCount := int32(0)\n\t\tgoroutines := 100\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(goroutines)\n\n\t\t// Start multiple goroutines trying to set the same key\n\t\tfor i := 0; i < goroutines; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tm.GetOrSetFuncLock(key, func() int {\n\t\t\t\t\t// Increment call count atomically\n\t\t\t\t\tatomic.AddInt32(&callCount, 1)\n\t\t\t\t\t// Simulate some work\n\t\t\t\t\ttime.Sleep(time.Microsecond)\n\t\t\t\t\treturn 100\n\t\t\t\t})\n\t\t\t}()\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// The callback should only be called once because of proper locking\n\t\tt.Assert(atomic.LoadInt32(&callCount), 1)\n\t\tt.Assert(m.Get(key), 100)\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test_ListKVMap_SetIfNotExistFuncLock_Race tests the atomicity of SetIfNotExistFuncLock.\n// This test ensures that only one goroutine can successfully set the value and\n// execute the callback function, even under high concurrency.\nfunc Test_ListKVMap_SetIfNotExistFuncLock_Race(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tkey := \"counter\"\n\t\tcallCount := int32(0)\n\t\tsuccessCount := int32(0)\n\t\tgoroutines := 100\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(goroutines)\n\n\t\t// Start multiple goroutines trying to set the same key\n\t\tfor i := 0; i < goroutines; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tsuccess := m.SetIfNotExistFuncLock(key, func() int {\n\t\t\t\t\t// Increment call count atomically\n\t\t\t\t\tatomic.AddInt32(&callCount, 1)\n\t\t\t\t\t// Simulate some work\n\t\t\t\t\ttime.Sleep(time.Microsecond)\n\t\t\t\t\treturn 200\n\t\t\t\t})\n\t\t\t\tif success {\n\t\t\t\t\tatomic.AddInt32(&successCount, 1)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// The callback should only be called once\n\t\tt.Assert(atomic.LoadInt32(&callCount), 1)\n\t\t// Only one goroutine should succeed\n\t\tt.Assert(atomic.LoadInt32(&successCount), 1)\n\t\tt.Assert(m.Get(key), 200)\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test_ListKVMap_GetOrSetFuncLock_MultipleKeys tests GetOrSetFuncLock with different keys.\n// This ensures that operations on different keys don't interfere with each other.\nfunc Test_ListKVMap_GetOrSetFuncLock_MultipleKeys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tkeys := []string{\"key1\", \"key2\", \"key3\", \"key4\", \"key5\"}\n\t\tcallCounts := make([]int32, len(keys))\n\t\tgoroutines := 20\n\n\t\tvar wg sync.WaitGroup\n\n\t\t// For each key, start multiple goroutines\n\t\tfor i, key := range keys {\n\t\t\tkeyIndex := i\n\t\t\tfor j := 0; j < goroutines; j++ {\n\t\t\t\twg.Add(1)\n\t\t\t\tgo func(idx int, k string) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\tm.GetOrSetFuncLock(k, func() int {\n\t\t\t\t\t\tatomic.AddInt32(&callCounts[idx], 1)\n\t\t\t\t\t\ttime.Sleep(time.Microsecond)\n\t\t\t\t\t\treturn (idx + 1) * 100\n\t\t\t\t\t})\n\t\t\t\t}(keyIndex, key)\n\t\t\t}\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Each key's callback should only be called once\n\t\tfor _, count := range callCounts {\n\t\t\tt.Assert(atomic.LoadInt32(&count), 1)\n\t\t}\n\n\t\t// Verify all keys are set correctly\n\t\tfor i, key := range keys {\n\t\t\tt.Assert(m.Get(key), (i+1)*100)\n\t\t}\n\t\tt.Assert(m.Size(), len(keys))\n\t})\n}\n\n// Test_ListKVMap_SetIfNotExistFuncLock_MultipleKeys tests SetIfNotExistFuncLock with different keys.\nfunc Test_ListKVMap_SetIfNotExistFuncLock_MultipleKeys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[int, string](true)\n\t\tkeys := []int{1, 2, 3, 4, 5}\n\t\tcallCounts := make([]int32, len(keys))\n\t\tsuccessCounts := make([]int32, len(keys))\n\t\tgoroutines := 20\n\n\t\tvar wg sync.WaitGroup\n\n\t\t// For each key, start multiple goroutines\n\t\tfor i, key := range keys {\n\t\t\tkeyIndex := i\n\t\t\tfor j := 0; j < goroutines; j++ {\n\t\t\t\twg.Add(1)\n\t\t\t\tgo func(idx int, k int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\tsuccess := m.SetIfNotExistFuncLock(k, func() string {\n\t\t\t\t\t\tatomic.AddInt32(&callCounts[idx], 1)\n\t\t\t\t\t\ttime.Sleep(time.Microsecond)\n\t\t\t\t\t\treturn gtest.DataContent()\n\t\t\t\t\t})\n\t\t\t\t\tif success {\n\t\t\t\t\t\tatomic.AddInt32(&successCounts[idx], 1)\n\t\t\t\t\t}\n\t\t\t\t}(keyIndex, key)\n\t\t\t}\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Each key's callback should only be called once\n\t\tfor _, count := range callCounts {\n\t\t\tt.Assert(atomic.LoadInt32(&count), 1)\n\t\t}\n\n\t\t// Each key should have exactly one successful set\n\t\tfor _, count := range successCounts {\n\t\t\tt.Assert(atomic.LoadInt32(&count), 1)\n\t\t}\n\n\t\tt.Assert(m.Size(), len(keys))\n\t})\n}\n\n// Test_ListKVMap_GetOrSetFuncLock_ExistingKey tests behavior when key already exists.\nfunc Test_ListKVMap_GetOrSetFuncLock_ExistingKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tkey := \"existing\"\n\t\tm.Set(key, 999)\n\n\t\tcallCount := int32(0)\n\t\tgoroutines := 50\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(goroutines)\n\n\t\tfor i := 0; i < goroutines; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tval := m.GetOrSetFuncLock(key, func() int {\n\t\t\t\t\tatomic.AddInt32(&callCount, 1)\n\t\t\t\t\treturn 123\n\t\t\t\t})\n\t\t\t\t// Should always get the existing value\n\t\t\t\tt.Assert(val, 999)\n\t\t\t}()\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Callback should never be called since key exists\n\t\tt.Assert(atomic.LoadInt32(&callCount), 0)\n\t\tt.Assert(m.Get(key), 999)\n\t})\n}\n\n// Test_ListKVMap_SetIfNotExistFuncLock_ExistingKey tests behavior when key already exists.\nfunc Test_ListKVMap_SetIfNotExistFuncLock_ExistingKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tkey := \"existing\"\n\t\tm.Set(key, 888)\n\n\t\tcallCount := int32(0)\n\t\tsuccessCount := int32(0)\n\t\tgoroutines := 50\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(goroutines)\n\n\t\tfor i := 0; i < goroutines; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tsuccess := m.SetIfNotExistFuncLock(key, func() int {\n\t\t\t\t\tatomic.AddInt32(&callCount, 1)\n\t\t\t\t\treturn 456\n\t\t\t\t})\n\t\t\t\tif success {\n\t\t\t\t\tatomic.AddInt32(&successCount, 1)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Callback should never be called since key exists\n\t\tt.Assert(atomic.LoadInt32(&callCount), 0)\n\t\t// No goroutine should succeed\n\t\tt.Assert(atomic.LoadInt32(&successCount), 0)\n\t\t// Original value should remain\n\t\tt.Assert(m.Get(key), 888)\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_list_k_v_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_ListKVMap_NewListKVMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string](true)\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_ListKVMap_NewListKVMapFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"a\": \"1\", \"b\": \"2\"}\n\t\tm := gmap.NewListKVMapFrom(data)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[int]int{1: 10, 2: 20}\n\t\tm := gmap.NewListKVMapFrom(data, true)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(1), 10)\n\t\tt.Assert(m.Get(2), 20)\n\t})\n}\n\nfunc Test_ListKVMap_Set_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Set(\"b\", \"2\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Size(), 2)\n\n\t\t// Set existing key\n\t\tm.Set(\"a\", \"10\")\n\t\tt.Assert(m.Get(\"a\"), \"10\")\n\t\tt.Assert(m.Size(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[int, int]()\n\t\tm.Set(1, 100)\n\t\tm.Set(2, 200)\n\t\tt.Assert(m.Get(1), 100)\n\t\tt.Assert(m.Get(2), 200)\n\t})\n}\n\nfunc Test_ListKVMap_Sets(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Get(\"c\"), \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"x\": \"10\", \"y\": \"20\"}\n\t\tm := gmap.NewListKVMapFrom(data)\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 4)\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\nfunc Test_ListKVMap_Search(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\n\t\tv, found := m.Search(\"a\")\n\t\tt.Assert(found, true)\n\t\tt.Assert(v, \"1\")\n\n\t\tv, found = m.Search(\"c\")\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[int, string]()\n\t\tv, found := m.Search(1)\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n}\n\nfunc Test_ListKVMap_Contains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Contains(\"a\"), true)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t\tt.Assert(m.Contains(\"c\"), false)\n\t})\n}\n\nfunc Test_ListKVMap_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tv := m.Remove(\"a\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Size(), 1)\n\n\t\tv = m.Remove(\"c\")\n\t\tt.Assert(v, \"\")\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\nfunc Test_ListKVMap_Removes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.Removes([]string{\"a\", \"c\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Contains(\"c\"), false)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Removes([]string{\"x\", \"y\"})\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\nfunc Test_ListKVMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk, v := m.Pop()\n\t\tt.AssertIN(k, []string{\"a\", \"b\"})\n\t\tt.AssertIN(v, []string{\"1\", \"2\"})\n\t\tt.Assert(m.Size(), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tk, v := m.Pop()\n\t\tt.Assert(k, \"\")\n\t\tt.Assert(v, \"\")\n\t})\n}\n\nfunc Test_ListKVMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tpopped := m.Pops(2)\n\t\tt.Assert(len(popped), 2)\n\t\tt.Assert(m.Size(), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tpopped := m.Pops(-1)\n\t\tt.Assert(len(popped), 3)\n\t\tt.Assert(m.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tpopped := m.Pops(10)\n\t\tt.Assert(len(popped), 2)\n\t\tt.Assert(m.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tpopped := m.Pops(1)\n\t\tt.AssertNil(popped)\n\t})\n}\n\nfunc Test_ListKVMap_Keys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 3)\n\t\tt.AssertIN(\"a\", keys)\n\t\tt.AssertIN(\"b\", keys)\n\t\tt.AssertIN(\"c\", keys)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[int, string]()\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 0)\n\t})\n}\n\nfunc Test_ListKVMap_Values(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 3)\n\t\tt.AssertIN(\"1\", values)\n\t\tt.AssertIN(\"2\", values)\n\t\tt.AssertIN(\"3\", values)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 0)\n\t})\n}\n\nfunc Test_ListKVMap_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tt.Assert(m.Size(), 0)\n\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Set(\"b\", \"2\")\n\t\tt.Assert(m.Size(), 2)\n\n\t\tm.Remove(\"a\")\n\t\tt.Assert(m.Size(), 1)\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\nfunc Test_ListKVMap_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tm.Remove(\"a\")\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_ListKVMap_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t\tt.Assert(m.Get(\"a\"), \"\")\n\t})\n}\n\nfunc Test_ListKVMap_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tdata := m.Map()\n\t\tt.Assert(data[\"a\"], \"1\")\n\t\tt.Assert(data[\"b\"], \"2\")\n\t\tt.Assert(len(data), 2)\n\t})\n}\n\nfunc Test_ListKVMap_MapStrAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 1, \"b\": 2})\n\t\tdata := m.MapStrAny()\n\t\tt.Assert(len(data), 2)\n\t\tt.Assert(data[\"a\"], 1)\n\t\tt.Assert(data[\"b\"], 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[int]string{1: \"a\", 2: \"b\"})\n\t\tdata := m.MapStrAny()\n\t\tt.Assert(len(data), 2)\n\t\tt.Assert(data[\"1\"], \"a\")\n\t\tt.Assert(data[\"2\"], \"b\")\n\t})\n}\n\nfunc Test_ListKVMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"\", \"b\": \"2\", \"c\": \"3\"})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t\tt.Assert(m.Contains(\"b\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 0, \"b\": 1, \"c\": 2})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\nfunc Test_ListKVMap_GetOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\n\t\tv := m.GetOrSet(\"a\", \"1\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\n\t\tv = m.GetOrSet(\"a\", \"10\")\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 10})\n\n\t\tv := m.GetOrSet(\"a\", 20)\n\t\tt.Assert(v, 10)\n\n\t\tv = m.GetOrSet(\"b\", 30)\n\t\tt.Assert(v, 30)\n\t\tt.Assert(m.Get(\"b\"), 30)\n\t})\n}\n\nfunc Test_ListKVMap_GetOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\n\t\tv := m.GetOrSetFunc(\"a\", func() string { return \"1\" })\n\t\tt.Assert(v, \"1\")\n\n\t\tv = m.GetOrSetFunc(\"a\", func() string { return \"10\" })\n\t\tt.Assert(v, \"1\")\n\n\t\tv = m.GetOrSetFunc(\"b\", func() string { return \"2\" })\n\t\tt.Assert(v, \"2\")\n\t})\n}\n\nfunc Test_ListKVMap_GetOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\tcounter := 0\n\n\t\tv := m.GetOrSetFuncLock(\"a\", func() int {\n\t\t\tcounter++\n\t\t\treturn 10\n\t\t})\n\t\tt.Assert(v, 10)\n\t\tt.Assert(counter, 1)\n\n\t\tv = m.GetOrSetFuncLock(\"a\", func() int {\n\t\t\tcounter++\n\t\t\treturn 20\n\t\t})\n\t\tt.Assert(v, 10)\n\t\tt.Assert(counter, 1)\n\t})\n}\n\nfunc Test_ListKVMap_SetIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\n\t\tok := m.SetIfNotExist(\"a\", \"1\")\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\n\t\tok = m.SetIfNotExist(\"a\", \"10\")\n\t\tt.Assert(ok, false)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\nfunc Test_ListKVMap_SetIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\n\t\tok := m.SetIfNotExistFunc(\"a\", func() int { return 10 })\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), 10)\n\n\t\tok = m.SetIfNotExistFunc(\"a\", func() int { return 20 })\n\t\tt.Assert(ok, false)\n\t\tt.Assert(m.Get(\"a\"), 10)\n\t})\n}\n\nfunc Test_ListKVMap_SetIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tcounter := 0\n\n\t\tok := m.SetIfNotExistFuncLock(\"a\", func() string {\n\t\t\tcounter++\n\t\t\treturn \"1\"\n\t\t})\n\t\tt.Assert(ok, true)\n\t\tt.Assert(counter, 1)\n\n\t\tok = m.SetIfNotExistFuncLock(\"a\", func() string {\n\t\t\tcounter++\n\t\t\treturn \"2\"\n\t\t})\n\t\tt.Assert(ok, false)\n\t\tt.Assert(counter, 1)\n\t})\n}\n\nfunc Test_ListKVMap_GetVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\n\t\tv := m.GetVar(\"a\")\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVar(\"c\")\n\t\tt.Assert(v.Val(), nil)\n\t})\n}\n\nfunc Test_ListKVMap_GetVarOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\n\t\tv := m.GetVarOrSet(\"a\", \"1\")\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVarOrSet(\"a\", \"10\")\n\t\tt.Assert(v.Val(), \"1\")\n\t})\n}\n\nfunc Test_ListKVMap_GetVarOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\n\t\tv := m.GetVarOrSetFunc(\"a\", func() int { return 10 })\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), 10)\n\n\t\tv = m.GetVarOrSetFunc(\"a\", func() int { return 20 })\n\t\tt.Assert(v.Val(), 10)\n\t})\n}\n\nfunc Test_ListKVMap_GetVarOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\n\t\tv := m.GetVarOrSetFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.AssertNE(v, nil)\n\t\tt.Assert(v.Val(), \"1\")\n\n\t\tv = m.GetVarOrSetFuncLock(\"a\", func() string { return \"10\" })\n\t\tt.Assert(v.Val(), \"1\")\n\t})\n}\n\nfunc Test_ListKVMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"}\n\t\tm := gmap.NewListKVMapFrom(data)\n\n\t\tcount := 0\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tt.Assert(data[k], v)\n\t\t\tcount++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(count, 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[int]string{1: \"a\", 2: \"b\", 3: \"c\"})\n\n\t\tcount := 0\n\t\tm.Iterator(func(k int, v string) bool {\n\t\t\tcount++\n\t\t\treturn count < 2\n\t\t})\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_ListKVMap_IteratorAsc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Set(\"k1\", \"v1\")\n\t\tm.Set(\"k2\", \"v2\")\n\t\tm.Set(\"k3\", \"v3\")\n\n\t\tvar keys []string\n\t\tvar values []string\n\t\tm.IteratorAsc(func(k string, v string) bool {\n\t\t\tkeys = append(keys, k)\n\t\t\tvalues = append(values, v)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(keys, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\tt.Assert(values, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_ListKVMap_IteratorDesc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Set(\"k1\", \"v1\")\n\t\tm.Set(\"k2\", \"v2\")\n\t\tm.Set(\"k3\", \"v3\")\n\n\t\tvar keys []string\n\t\tvar values []string\n\t\tm.IteratorDesc(func(k string, v string) bool {\n\t\t\tkeys = append(keys, k)\n\t\t\tvalues = append(values, v)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(keys, g.Slice{\"k3\", \"k2\", \"k1\"})\n\t\tt.Assert(values, g.Slice{\"v3\", \"v2\", \"v1\"})\n\t})\n}\n\nfunc Test_ListKVMap_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tm.Replace(map[string]string{\"x\": \"10\", \"y\": \"20\", \"z\": \"30\"})\n\t\tt.Assert(m.Size(), 3)\n\t\tt.Assert(m.Get(\"a\"), \"\")\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t})\n}\n\nfunc Test_ListKVMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm2 := m.Clone()\n\n\t\tt.Assert(m2.Get(\"a\"), \"1\")\n\t\tt.Assert(m2.Get(\"b\"), \"2\")\n\t\tt.Assert(m2.Size(), 2)\n\n\t\tm.Set(\"a\", \"10\")\n\t\tt.Assert(m2.Get(\"a\"), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 1, \"b\": 2}, false)\n\t\tm2 := m.Clone(true)\n\n\t\tt.Assert(m2.Size(), 2)\n\t})\n}\n\nfunc Test_ListKVMap_Flip(t *testing.T) {\n\t// Test with same type for key and value (string -> string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\terr := m.Flip()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(m.Get(\"1\"), \"a\")\n\t\tt.Assert(m.Get(\"2\"), \"b\")\n\t\tt.Assert(m.Get(\"3\"), \"c\")\n\t})\n\n\t// Test with same type for key and value (int -> int)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[int]int{1: 10, 2: 20})\n\t\terr := m.Flip()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(m.Get(10), 1)\n\t\tt.Assert(m.Get(20), 2)\n\t})\n}\n\nfunc Test_ListKVMap_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\tm2 := gmap.NewListKVMapFrom(map[string]string{\"b\": \"2\", \"c\": \"3\"})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Size(), 3)\n\t\tt.Assert(m1.Get(\"a\"), \"1\")\n\t\tt.Assert(m1.Get(\"b\"), \"2\")\n\t\tt.Assert(m1.Get(\"c\"), \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewListKVMap[string, int]()\n\t\tm2 := gmap.NewListKVMapFrom(map[string]int{\"a\": 10, \"b\": 20})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Size(), 2)\n\t\tt.Assert(m1.Get(\"a\"), 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\tm2 := gmap.NewListKVMapFrom(map[string]string{\"a\": \"10\", \"b\": \"2\"})\n\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Get(\"a\"), \"10\")\n\t})\n}\n\nfunc Test_ListKVMap_Merge_Self(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Merge(m)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\nfunc Test_ListKVMap_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\"})\n\t\ts := m.String()\n\t\tt.AssertNE(s, \"\")\n\t\tt.AssertIN(\"a\", s)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m *gmap.ListKVMap[string, string]\n\t\ts := m.String()\n\t\tt.Assert(s, \"\")\n\t})\n}\n\nfunc Test_ListKVMap_MarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\tm.Set(\"a\", 1)\n\t\tm.Set(\"b\", 2)\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(b, nil)\n\n\t\tvar data map[string]int\n\t\terr = json.Unmarshal(b, &data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data[\"a\"], 1)\n\t\tt.Assert(data[\"b\"], 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tb, err := m.MarshalJSON()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), \"{}\")\n\t})\n}\n\nfunc Test_ListKVMap_UnmarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\tdata := []byte(`{\"a\":1,\"b\":2,\"c\":3}`)\n\n\t\terr := json.UnmarshalUseNumber(data, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t\tt.Assert(m.Get(\"b\"), 2)\n\t\tt.Assert(m.Get(\"c\"), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.ListKVMap[string, string]\n\t\tdata := []byte(`{\"x\":\"10\",\"y\":\"20\"}`)\n\n\t\terr := json.UnmarshalUseNumber(data, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"x\"), \"10\")\n\t\tt.Assert(m.Get(\"y\"), \"20\")\n\t})\n}\n\nfunc Test_ListKVMap_UnmarshalValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\terr := m.UnmarshalValue(map[string]any{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": \"2\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\nfunc Test_ListKVMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string][]string{\n\t\t\t\"a\": {\"1\", \"2\"},\n\t\t\t\"b\": {\"3\", \"4\"},\n\t\t})\n\n\t\tn := m.DeepCopy().(*gmap.ListKVMap[string, []string])\n\t\tt.Assert(n.Size(), 2)\n\t\tt.Assert(n.Get(\"a\"), []string{\"1\", \"2\"})\n\n\t\t// Modifying original doesn't affect copy\n\t\tm.Get(\"a\")[0] = \"10\"\n\t\tt.Assert(n.Get(\"a\")[0], \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m *gmap.ListKVMap[string, int]\n\t\tn := m.DeepCopy()\n\t\tt.AssertNil(n)\n\t})\n}\n\nfunc Test_ListKVMap_Order(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Set(\"k1\", \"v1\")\n\t\tm.Set(\"k2\", \"v2\")\n\t\tm.Set(\"k3\", \"v3\")\n\t\tt.Assert(m.Keys(), g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\tt.Assert(m.Values(), g.Slice{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_ListKVMap_Json_Sequence(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int32]()\n\t\tfor i := 'z'; i >= 'a'; i-- {\n\t\t\tm.Set(string(i), i)\n\t\t}\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"z\":122,\"y\":121,\"x\":120,\"w\":119,\"v\":118,\"u\":117,\"t\":116,\"s\":115,\"r\":114,\"q\":113,\"p\":112,\"o\":111,\"n\":110,\"m\":109,\"l\":108,\"k\":107,\"j\":106,\"i\":105,\"h\":104,\"g\":103,\"f\":102,\"e\":101,\"d\":100,\"c\":99,\"b\":98,\"a\":97}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int32]()\n\t\tfor i := 'a'; i <= 'z'; i++ {\n\t\t\tm.Set(string(i), i)\n\t\t}\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"a\":97,\"b\":98,\"c\":99,\"d\":100,\"e\":101,\"f\":102,\"g\":103,\"h\":104,\"i\":105,\"j\":106,\"k\":107,\"l\":108,\"m\":109,\"n\":110,\"o\":111,\"p\":112,\"q\":113,\"r\":114,\"s\":115,\"t\":116,\"u\":117,\"v\":118,\"w\":119,\"x\":120,\"y\":121,\"z\":122}`)\n\t})\n}\n\n// Test Set with nil data\nfunc Test_ListKVMap_Set_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tm.Set(\"a\", \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test Sets with nil data\nfunc Test_ListKVMap_Sets_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tm.Sets(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\n// Test GetOrSet with nil value (using any type)\nfunc Test_ListKVMap_GetOrSet_NilValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, any]()\n\t\tv := m.GetOrSet(\"a\", nil)\n\t\tt.Assert(v, nil)\n\t\t// nil interface value should not be stored\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test Search with nil data\nfunc Test_ListKVMap_Search_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tv, found := m.Search(\"a\")\n\t\tt.Assert(found, false)\n\t\tt.Assert(v, \"\")\n\t})\n}\n\n// Test Get with nil data\nfunc Test_ListKVMap_Get_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, int](nil)\n\t\tv := m.Get(\"a\")\n\t\tt.Assert(v, 0)\n\t})\n}\n\n// Test Contains with nil data\nfunc Test_ListKVMap_Contains_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test Remove with nil data\nfunc Test_ListKVMap_Remove_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tv := m.Remove(\"a\")\n\t\tt.Assert(v, \"\")\n\t})\n}\n\n// Test Removes with nil data\nfunc Test_ListKVMap_Removes_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tm.Removes([]string{\"a\", \"b\"})\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\n// Test Pops with size 0\nfunc Test_ListKVMap_Pops_ZeroSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tpopped := m.Pops(0)\n\t\tt.AssertNil(popped)\n\t\tt.Assert(m.Size(), 2)\n\t})\n}\n\n// Test Iterator early break\nfunc Test_ListKVMap_Iterator_Break(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\", \"c\": \"3\"})\n\t\tcount := 0\n\t\tm.Iterator(func(k string, v string) bool {\n\t\t\tcount++\n\t\t\treturn false // Break immediately\n\t\t})\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test IteratorAsc with nil list\nfunc Test_ListKVMap_IteratorAsc_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tcount := 0\n\t\tm.IteratorAsc(func(k string, v string) bool {\n\t\t\tcount++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test IteratorDesc with nil list\nfunc Test_ListKVMap_IteratorDesc_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tcount := 0\n\t\tm.IteratorDesc(func(k string, v string) bool {\n\t\t\tcount++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test Map with nil list\nfunc Test_ListKVMap_Map_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tdata := m.Map()\n\t\tt.Assert(len(data), 0)\n\t})\n}\n\n// Test MapStrAny with nil list\nfunc Test_ListKVMap_MapStrAny_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tdata := m.MapStrAny()\n\t\tt.Assert(len(data), 0)\n\t})\n}\n\n// Test FilterEmpty with nil list\nfunc Test_ListKVMap_FilterEmpty_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 0)\n\t})\n}\n\n// Test Keys with nil list\nfunc Test_ListKVMap_Keys_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 0)\n\t})\n}\n\n// Test Values with nil list\nfunc Test_ListKVMap_Values_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 0)\n\t})\n}\n\n// Test DeepCopy with nil list\nfunc Test_ListKVMap_DeepCopy_NilList(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tn := m.DeepCopy().(*gmap.ListKVMap[string, string])\n\t\tt.Assert(n.Size(), 0)\n\t})\n}\n\n// Concurrent safety tests\nfunc Test_ListKVMap_Concurrent_Safe(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tch := make(chan int, 10)\n\n\t\t// Concurrent writes\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.Set(gconv.String(idx), idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 10)\n\t})\n}\n\nfunc Test_ListKVMap_Concurrent_RW(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tm.Sets(map[string]int{\"a\": 1, \"b\": 2, \"c\": 3})\n\n\t\tch := make(chan int, 20)\n\n\t\t// Concurrent reads and writes\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func() {\n\t\t\t\t_ = m.Get(\"a\")\n\t\t\t\tch <- 1\n\t\t\t}()\n\t\t}\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.Set(gconv.String(idx), idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 20; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 13)\n\t})\n}\n\n// Test concurrent GetOrSet\nfunc Test_ListKVMap_Concurrent_GetOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSet(\"key\", idx)\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\t// Only one value should be set\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"key\"), true)\n\t})\n}\n\n// Test concurrent SetIfNotExist\nfunc Test_ListKVMap_Concurrent_SetIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tsuccessCount := 0\n\t\tch := make(chan bool, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tok := m.SetIfNotExist(\"key\", idx)\n\t\t\t\tch <- ok\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tif <-ch {\n\t\t\t\tsuccessCount++\n\t\t\t}\n\t\t}\n\n\t\t// Only one goroutine should succeed\n\t\tt.Assert(successCount, 1)\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test concurrent GetOrSetFunc\nfunc Test_ListKVMap_Concurrent_GetOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSetFunc(\"key\", func() int {\n\t\t\t\t\treturn idx\n\t\t\t\t})\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test concurrent GetOrSetFuncLock\nfunc Test_ListKVMap_Concurrent_GetOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tch := make(chan int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tgo func(idx int) {\n\t\t\t\tm.GetOrSetFuncLock(\"key\", func() int {\n\t\t\t\t\treturn idx\n\t\t\t\t})\n\t\t\t\tch <- 1\n\t\t\t}(i)\n\t\t}\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t<-ch\n\t\t}\n\n\t\tt.Assert(m.Size(), 1)\n\t})\n}\n\n// Test concurrent access to doSetWithLockCheck\nfunc Test_ListKVMap_DoSetWithLockCheck_Concurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int](true)\n\t\tvar wg sync.WaitGroup\n\t\tresults := make([]int, 100)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func(idx int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tv := m.GetOrSet(\"key\", idx)\n\t\t\t\tresults[idx] = v\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// All results should be the same (the first value that was set)\n\t\tfirstValue := results[0]\n\t\tfor _, v := range results {\n\t\t\tt.Assert(v, firstValue)\n\t\t}\n\t})\n}\n\n// Test UnmarshalJSON with invalid JSON\nfunc Test_ListKVMap_UnmarshalJSON_InvalidJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\terr := m.UnmarshalJSON([]byte(`{invalid json}`))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test MarshalJSON error handling\nfunc Test_ListKVMap_MarshalJSON_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, string]()\n\t\tm.Set(\"a\", \"1\")\n\t\tb, err := m.MarshalJSON()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `{\"a\":\"1\"}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.ListKVMap[int, int]\n\t\tm.Set(1, 10)\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `{\"1\":10}`)\n\t})\n}\n\n// Test empty map operations\nfunc Test_ListKVMap_EmptyMapOperations(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\n\t\t// Test Keys on empty map\n\t\tkeys := m.Keys()\n\t\tt.Assert(len(keys), 0)\n\n\t\t// Test Values on empty map\n\t\tvalues := m.Values()\n\t\tt.Assert(len(values), 0)\n\n\t\t// Test MapStrAny on empty map\n\t\tstrAny := m.MapStrAny()\n\t\tt.Assert(len(strAny), 0)\n\t})\n}\n\n// Test FilterEmpty with various empty values\nfunc Test_ListKVMap_FilterEmpty_Various(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, any]()\n\t\tm.Set(\"nil\", nil)\n\t\tm.Set(\"zero\", 0)\n\t\tm.Set(\"empty_string\", \"\")\n\t\tm.Set(\"false\", false)\n\t\tm.Set(\"valid\", \"value\")\n\t\tm.Set(\"empty_slice\", []int{})\n\t\tm.Set(\"empty_map\", map[string]int{})\n\n\t\tt.Assert(m.Size(), 7)\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Contains(\"valid\"), true)\n\t})\n}\n\n// Test Clone with different safe modes\nfunc Test_ListKVMap_Clone_SafeMode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone unsafe map to safe\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 1}, false)\n\t\tm2 := m.Clone(true)\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone safe map to unsafe\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 1}, true)\n\t\tm2 := m.Clone(false)\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clone with inherited safe mode\n\t\tm := gmap.NewListKVMapFrom(map[string]int{\"a\": 1}, true)\n\t\tm2 := m.Clone()\n\t\tt.Assert(m2.Get(\"a\"), 1)\n\t})\n}\n\n// Test SetIfNotExistFunc returning false when key exists\nfunc Test_ListKVMap_SetIfNotExistFunc_KeyExists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, int]()\n\t\tm.Set(\"a\", 1)\n\n\t\tcalled := false\n\t\tok := m.SetIfNotExistFunc(\"a\", func() int {\n\t\t\tcalled = true\n\t\t\treturn 2\n\t\t})\n\t\tt.Assert(ok, false)\n\t\tt.Assert(called, false) // Function should not be called if key exists\n\t\tt.Assert(m.Get(\"a\"), 1)\n\t})\n}\n\n// Test struct with ListKVMap for UnmarshalValue\nfunc Test_ListKVMap_UnmarshalValue_Struct(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.ListKVMap[string, string]\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"1\":\"v1\",\"2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.MapStrStr{\n\t\t\t\t\"1\": \"v1\",\n\t\t\t\t\"2\": \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"2\"), \"v2\")\n\t})\n}\n\n// Test GetOrSetFuncLock with nil data\nfunc Test_ListKVMap_GetOrSetFuncLock_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tv := m.GetOrSetFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.Assert(v, \"1\")\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n\n\t// Test with nil value (using any type)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMap[string, any]()\n\t\tv := m.GetOrSetFuncLock(\"a\", func() any { return nil })\n\t\tt.Assert(v, nil)\n\t\t// nil interface value should not be stored\n\t\tt.Assert(m.Contains(\"a\"), false)\n\t})\n}\n\n// Test SetIfNotExistFuncLock with nil data\nfunc Test_ListKVMap_SetIfNotExistFuncLock_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tok := m.SetIfNotExistFuncLock(\"a\", func() string { return \"1\" })\n\t\tt.Assert(ok, true)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t})\n}\n\n// Test Merge with nil data\nfunc Test_ListKVMap_Merge_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\tm2 := gmap.NewListKVMapFrom(map[string]string{\"a\": \"1\", \"b\": \"2\"})\n\t\tm.Merge(m2)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\n// Test UnmarshalJSON with nil data\nfunc Test_ListKVMap_UnmarshalJSON_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\terr := m.UnmarshalJSON([]byte(`{\"a\":\"1\",\"b\":\"2\"}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\n// Test UnmarshalValue with nil data\nfunc Test_ListKVMap_UnmarshalValue_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListKVMapFrom[string, string](nil)\n\t\terr := m.UnmarshalValue(map[string]any{\"a\": \"1\", \"b\": \"2\"})\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(\"a\"), \"1\")\n\t\tt.Assert(m.Get(\"b\"), \"2\")\n\t})\n}\n\n// Test typed nil values\nfunc Test_ListKVMap_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tm1 := gmap.NewListKVMap[int, *Student](true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm1.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m1.Size(), 5)\n\n\t\tm2 := gmap.NewListKVMap[int, *Student](true)\n\t\tm2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm2.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m2.Size(), 5)\n\t})\n}\n\nfunc Test_NewListKVMapWithChecker_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tm1 := gmap.NewListKVMap[int, *Student](true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm1.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m1.Size(), 5)\n\n\t\tm2 := gmap.NewListKVMapWithChecker[int, *Student](func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm2.GetOrSetFuncLock(i, func() *Student {\n\t\t\t\tif i%2 == 0 {\n\t\t\t\t\treturn &Student{}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t\tt.Assert(m2.Size(), 5)\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_list_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_ListMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.ListMap\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Flip()\n\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_ListMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Flip()\n\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewListMapFrom(map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_ListMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tm.GetOrSetFuncLock(\"funlock\", getValue)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t})\n}\n\nfunc Test_ListMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_ListMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, \"key1\": \"val1\"}\n\n\t\tm := gmap.NewListMapFrom(expect)\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_ListMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewListMapFrom(map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_ListMap_Basic_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := gmap.NewListMap()\n\t\tm2 := gmap.NewListMap()\n\t\tm1.Set(\"key1\", \"val1\")\n\t\tm2.Set(\"key2\", \"val2\")\n\t\tm1.Merge(m2)\n\t\tt.Assert(m1.Map(), map[any]any{\"key1\": \"val1\", \"key2\": \"val2\"})\n\t\tm3 := gmap.NewListMapFrom(nil)\n\t\tm3.Merge(m2)\n\t\tt.Assert(m3.Map(), m2.Map())\n\t})\n}\n\nfunc Test_ListMap_Order(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(\"k1\", \"v1\")\n\t\tm.Set(\"k2\", \"v2\")\n\t\tm.Set(\"k3\", \"v3\")\n\t\tt.Assert(m.Keys(), g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\tt.Assert(m.Values(), g.Slice{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_ListMap_FilterEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(1, \"\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.Size(), 2)\n\t\tt.Assert(m.Get(2), \"2\")\n\t\tm.FilterEmpty()\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.Get(2), \"2\")\n\t})\n}\n\nfunc Test_ListMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tm1 := gmap.NewListMapFrom(data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tt.AssertNil(err1)\n\t\tb2, err2 := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewListMap()\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.ListMap\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc Test_ListMap_Json_Sequence(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tfor i := 'z'; i >= 'a'; i-- {\n\t\t\tm.Set(string(i), i)\n\t\t}\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"z\":122,\"y\":121,\"x\":120,\"w\":119,\"v\":118,\"u\":117,\"t\":116,\"s\":115,\"r\":114,\"q\":113,\"p\":112,\"o\":111,\"n\":110,\"m\":109,\"l\":108,\"k\":107,\"j\":106,\"i\":105,\"h\":104,\"g\":103,\"f\":102,\"e\":101,\"d\":100,\"c\":99,\"b\":98,\"a\":97}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tfor i := 'a'; i <= 'z'; i++ {\n\t\t\tm.Set(string(i), i)\n\t\t}\n\t\tb, err := json.Marshal(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"a\":97,\"b\":98,\"c\":99,\"d\":100,\"e\":101,\"f\":102,\"g\":103,\"h\":104,\"i\":105,\"j\":106,\"k\":107,\"l\":108,\"m\":109,\"n\":110,\"o\":111,\"p\":112,\"q\":113,\"r\":114,\"s\":115,\"t\":116,\"u\":117,\"v\":118,\"w\":119,\"x\":120,\"y\":121,\"z\":122}`)\n\t})\n}\n\nfunc Test_ListMap_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(m.Size(), 2)\n\n\t\tk1, v1 := m.Pop()\n\t\tt.AssertIN(k1, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v1, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 1)\n\t\tk2, v2 := m.Pop()\n\t\tt.AssertIN(k2, g.Slice{\"k1\", \"k2\"})\n\t\tt.AssertIN(v2, g.Slice{\"v1\", \"v2\"})\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.AssertNE(k1, k2)\n\t\tt.AssertNE(v1, v2)\n\n\t\tk3, v3 := m.Pop()\n\t\tt.AssertNil(k3)\n\t\tt.AssertNil(v3)\n\t})\n}\n\nfunc Test_ListMap_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t\tt.Assert(m.Size(), 3)\n\n\t\tkArray := garray.New()\n\t\tvArray := garray.New()\n\t\tfor k, v := range m.Pops(1) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 2)\n\t\tfor k, v := range m.Pops(2) {\n\t\t\tt.AssertIN(k, g.Slice{\"k1\", \"k2\", \"k3\"})\n\t\t\tt.AssertIN(v, g.Slice{\"v1\", \"v2\", \"v3\"})\n\t\t\tkArray.Append(k)\n\t\t\tvArray.Append(v)\n\t\t}\n\t\tt.Assert(m.Size(), 0)\n\n\t\tt.Assert(kArray.Unique().Len(), 3)\n\t\tt.Assert(vArray.Unique().Len(), 3)\n\n\t\tv := m.Pops(1)\n\t\tt.AssertNil(v)\n\t\tv = m.Pops(-1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc TestListMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.ListMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"1\":\"v1\",\"2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.MapIntAny{\n\t\t\t\t1: \"v1\",\n\t\t\t\t2: \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"2\"), \"v2\")\n\t})\n}\n\nfunc TestListMap_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(1, \"\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.String(), \"{\\\"1\\\":\\\"\\\",\\\"2\\\":\\\"2\\\"}\")\n\n\t\tm1 := gmap.NewListMapFrom(nil)\n\t\tt.Assert(m1.String(), \"{}\")\n\t})\n}\n\nfunc TestListMap_MarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(1, \"\")\n\t\tm.Set(2, \"2\")\n\t\tres, err := m.MarshalJSON()\n\t\tt.Assert(res, []byte(\"{\\\"1\\\":\\\"\\\",\\\"2\\\":\\\"2\\\"}\"))\n\t\tt.AssertNil(err)\n\n\t\tm1 := gmap.NewListMapFrom(nil)\n\t\tres, err = m1.MarshalJSON()\n\t\tt.Assert(res, []byte(\"{}\"))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestListMap_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewListMap()\n\t\tm.Set(1, \"1\")\n\t\tm.Set(2, \"2\")\n\t\tt.Assert(m.Size(), 2)\n\n\t\tn := m.DeepCopy().(*gmap.ListMap)\n\t\tn.Set(1, \"val1\")\n\t\tt.AssertNE(m.Get(1), n.Get(1))\n\t})\n}\n"
  },
  {
    "path": "container/gmap/gmap_z_unit_tree_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmap_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_TreeMap_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar m gmap.TreeMap\n\t\tm.SetComparator(gutil.ComparatorString)\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\t})\n}\n\nfunc Test_TreeMap_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gmap.NewTreeMapFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_TreeMap_Set_Fun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tm.GetOrSetFuncLock(\"funlock\", getValue)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t\tm.GetOrSetFunc(\"fun\", getValue)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t})\n}\n\nfunc Test_TreeMap_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_TreeMap_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, \"key1\": \"val1\"}\n\t\tm := gmap.NewTreeMapFrom(gutil.ComparatorString, expect)\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t\t// 断言返回值对遍历控制\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, 2)\n\t\tt.Assert(j, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpect := map[any]any{1: 1, \"key1\": \"val1\"}\n\t\tm := gmap.NewTreeMapFrom(gutil.ComparatorString, expect)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm.IteratorAsc(func(k any, v any) bool {\n\t\t\t\tt.Assert(expect[k], v)\n\t\t\t\treturn true\n\t\t\t})\n\t\t}\n\t\tj := 0\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tm.IteratorAsc(func(k any, v any) bool {\n\t\t\t\tj++\n\t\t\t\treturn false\n\t\t\t})\n\t\t}\n\t\tt.Assert(j, 10)\n\t})\n}\n\nfunc Test_TreeMap_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// clone 方法是深克隆\n\t\tm := gmap.NewTreeMapFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t// 修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t// 修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_TreeMap_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm1 := gmap.NewTreeMapFrom(gutil.ComparatorString, data)\n\t\tb1, err1 := json.Marshal(m1)\n\t\tb2, err2 := json.Marshal(gconv.Map(data))\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tm := gmap.NewTreeMap(gutil.ComparatorString)\n\t\terr = json.UnmarshalUseNumber(b, m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tb, err := json.Marshal(gconv.Map(data))\n\t\tt.AssertNil(err)\n\n\t\tvar m gmap.TreeMap\n\t\terr = json.UnmarshalUseNumber(b, &m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m.Get(\"k1\"), data[\"k1\"])\n\t\tt.Assert(m.Get(\"k2\"), data[\"k2\"])\n\t})\n}\n\nfunc TestTreeMap_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tMap  *gmap.TreeMap\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\":  []byte(`{\"k1\":\"v1\",\"k2\":\"v2\"}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"map\": g.Map{\n\t\t\t\t\"k1\": \"v1\",\n\t\t\t\t\"k2\": \"v2\",\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Map.Size(), 2)\n\t\tt.Assert(v.Map.Get(\"k1\"), \"v1\")\n\t\tt.Assert(v.Map.Get(\"k2\"), \"v2\")\n\t})\n}\n"
  },
  {
    "path": "container/gpool/gpool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gpool provides object-reusable concurrent-safe pool.\npackage gpool\n\nimport (\n\t\"time\"\n)\n\n// Pool is an Object-Reusable Pool.\ntype Pool struct {\n\t*TPool[any]\n}\n\n// NewFunc Creation function for object.\ntype NewFunc = TPoolNewFunc[any]\n\n// ExpireFunc Destruction function for object.\ntype ExpireFunc = TPoolExpireFunc[any]\n\n// New creates and returns a new object pool.\n// To ensure execution efficiency, the expiration time cannot be modified once it is set.\n//\n// Note the expiration logic:\n// ttl = 0 : not expired;\n// ttl < 0 : immediate expired after use;\n// ttl > 0 : timeout expired;\nfunc New(ttl time.Duration, newFunc NewFunc, expireFunc ...ExpireFunc) *Pool {\n\treturn &Pool{\n\t\tTPool: NewTPool(ttl, newFunc, expireFunc...),\n\t}\n}\n\n// Put puts an item to pool.\nfunc (p *Pool) Put(value any) error {\n\treturn p.TPool.Put(value)\n}\n\n// MustPut puts an item to pool, it panics if any error occurs.\nfunc (p *Pool) MustPut(value any) {\n\tp.TPool.MustPut(value)\n}\n\n// Clear clears pool, which means it will remove all items from pool.\nfunc (p *Pool) Clear() {\n\tp.TPool.Clear()\n}\n\n// Get picks and returns an item from pool. If the pool is empty and NewFunc is defined,\n// it creates and returns one from NewFunc.\nfunc (p *Pool) Get() (any, error) {\n\treturn p.TPool.Get()\n}\n\n// Size returns the count of available items of pool.\nfunc (p *Pool) Size() int {\n\treturn p.TPool.Size()\n}\n\n// Close closes the pool. If `p` has ExpireFunc,\n// then it automatically closes all items using this function before it's closed.\n// Commonly you do not need to call this function manually.\nfunc (p *Pool) Close() {\n\tp.TPool.Close()\n}\n"
  },
  {
    "path": "container/gpool/gpool_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gpool_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gpool\"\n)\n\nvar pool = gpool.New(time.Hour, nil)\n\nvar syncp = sync.Pool{}\n\nfunc BenchmarkGPoolPut(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpool.Put(i)\n\t}\n}\n\nfunc BenchmarkGPoolGet(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpool.Get()\n\t}\n}\n\nfunc BenchmarkSyncPoolPut(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsyncp.Put(i)\n\t}\n}\n\nfunc BenchmarkSyncPoolGet(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsyncp.Get()\n\t}\n}\n"
  },
  {
    "path": "container/gpool/gpool_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gpool\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// TPool is an Object-Reusable Pool.\ntype TPool[T any] struct {\n\tlist    *glist.TList[*tPoolItem[T]] // Available/idle items list.\n\tclosed  *gtype.Bool                 // Whether the pool is closed.\n\tTTL     time.Duration               // Time To Live for pool items.\n\tNewFunc func() (T, error)           // Callback function to create pool item.\n\t// ExpireFunc is the function for expired items destruction.\n\t// This function needs to be defined when the pool items\n\t// need to perform additional destruction operations.\n\t// Eg: net.Conn, os.File, etc.\n\tExpireFunc func(T)\n}\n\n// TPool item.\ntype tPoolItem[T any] struct {\n\tvalue    T     // Item value.\n\texpireAt int64 // Expire timestamp in milliseconds.\n}\n\n// TPoolNewFunc Creation function for object.\ntype TPoolNewFunc[T any] func() (T, error)\n\n// TPoolExpireFunc Destruction function for object.\ntype TPoolExpireFunc[T any] func(T)\n\n// NewTPool creates and returns a new object pool.\n// To ensure execution efficiency, the expiration time cannot be modified once it is set.\n//\n// Note the expiration logic:\n// ttl = 0 : not expired;\n// ttl < 0 : immediate expired after use;\n// ttl > 0 : timeout expired;\nfunc NewTPool[T any](ttl time.Duration, newFunc TPoolNewFunc[T], expireFunc ...TPoolExpireFunc[T]) *TPool[T] {\n\tr := &TPool[T]{\n\t\tlist:    glist.NewT[*tPoolItem[T]](true),\n\t\tclosed:  gtype.NewBool(),\n\t\tTTL:     ttl,\n\t\tNewFunc: newFunc,\n\t}\n\tif len(expireFunc) > 0 {\n\t\tr.ExpireFunc = expireFunc[0]\n\t}\n\tgtimer.AddSingleton(context.Background(), time.Second, r.checkExpireItems)\n\treturn r\n}\n\n// Put puts an item to pool.\nfunc (p *TPool[T]) Put(value T) error {\n\tif p.closed.Val() {\n\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"pool is closed\")\n\t}\n\titem := &tPoolItem[T]{\n\t\tvalue: value,\n\t}\n\tif p.TTL == 0 {\n\t\titem.expireAt = 0\n\t} else {\n\t\t// As for Golang version < 1.13, there's no method Milliseconds for time.Duration.\n\t\t// So we need calculate the milliseconds using its nanoseconds value.\n\t\titem.expireAt = gtime.TimestampMilli() + p.TTL.Nanoseconds()/1000000\n\t}\n\tp.list.PushBack(item)\n\treturn nil\n}\n\n// MustPut puts an item to pool, it panics if any error occurs.\nfunc (p *TPool[T]) MustPut(value T) {\n\tif err := p.Put(value); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Clear clears pool, which means it will remove all items from pool.\nfunc (p *TPool[T]) Clear() {\n\tif p.ExpireFunc != nil {\n\t\tfor {\n\t\t\tif r := p.list.PopFront(); r != nil {\n\t\t\t\tp.ExpireFunc(r.value)\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else {\n\t\tp.list.RemoveAll()\n\t}\n}\n\n// Get picks and returns an item from pool. If the pool is empty and NewFunc is defined,\n// it creates and returns one from NewFunc.\nfunc (p *TPool[T]) Get() (value T, err error) {\n\tfor !p.closed.Val() {\n\t\tif f := p.list.PopFront(); f != nil {\n\t\t\tif f.expireAt == 0 || f.expireAt > gtime.TimestampMilli() {\n\t\t\t\treturn f.value, nil\n\t\t\t} else if p.ExpireFunc != nil {\n\t\t\t\t// TODO: move expire function calling asynchronously out from `Get` operation.\n\t\t\t\tp.ExpireFunc(f.value)\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tif p.NewFunc != nil {\n\t\treturn p.NewFunc()\n\t}\n\terr = gerror.NewCode(gcode.CodeInvalidOperation, \"pool is empty\")\n\treturn\n}\n\n// Size returns the count of available items of pool.\nfunc (p *TPool[T]) Size() int {\n\treturn p.list.Len()\n}\n\n// Close closes the pool. If `p` has ExpireFunc,\n// then it automatically closes all items using this function before it's closed.\n// Commonly you do not need to call this function manually.\nfunc (p *TPool[T]) Close() {\n\tp.closed.Set(true)\n}\n\n// checkExpire removes expired items from pool in every second.\nfunc (p *TPool[T]) checkExpireItems(ctx context.Context) {\n\tif p.closed.Val() {\n\t\t// If p has ExpireFunc,\n\t\t// then it must close all items using this function.\n\t\tif p.ExpireFunc != nil {\n\t\t\tfor {\n\t\t\t\tif r := p.list.PopFront(); r != nil {\n\t\t\t\t\tp.ExpireFunc(r.value)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgtimer.Exit()\n\t}\n\t// All items do not expire.\n\tif p.TTL == 0 {\n\t\treturn\n\t}\n\t// The latest item expire timestamp in milliseconds.\n\tvar latestExpire int64 = -1\n\t// Retrieve the current timestamp in milliseconds, it expires the items\n\t// by comparing with this timestamp. It is not accurate comparison for\n\t// every item expired, but high performance.\n\tvar timestampMilli = gtime.TimestampMilli()\n\tfor latestExpire <= timestampMilli {\n\t\tif item := p.list.PopFront(); item != nil {\n\t\t\tlatestExpire = item.expireAt\n\t\t\t// TODO improve the auto-expiration mechanism of the pool.\n\t\t\tif item.expireAt > timestampMilli {\n\t\t\t\tp.list.PushFront(item)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif p.ExpireFunc != nil {\n\t\t\t\tp.ExpireFunc(item.value)\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "container/gpool/gpool_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gpool_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gpool\"\n)\n\nfunc ExampleNew() {\n\ttype DBConn struct {\n\t\tConn *sql.Conn\n\t}\n\n\tdbConnPool := gpool.New(time.Hour,\n\t\tfunc() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\treturn dbConn, nil\n\t\t},\n\t\tfunc(i any) {\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t})\n\n\tfmt.Println(dbConnPool.TTL)\n\n\t// Output:\n\t// 1h0m0s\n}\n\nfunc ExamplePool_Put() {\n\ttype DBConn struct {\n\t\tConn  *sql.Conn\n\t\tLimit int\n\t}\n\n\tdbConnPool := gpool.New(time.Hour,\n\t\tfunc() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\tdbConn.Limit = 10\n\t\t\treturn dbConn, nil\n\t\t},\n\t\tfunc(i any) {\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t})\n\n\t// get db conn\n\tconn, _ := dbConnPool.Get()\n\t// modify this conn's limit\n\tconn.(*DBConn).Limit = 20\n\n\t// example : do same db operation\n\t// conn.(*DBConn).Conn.QueryContext(context.Background(), \"select * from user\")\n\n\t// put back conn\n\tdbConnPool.MustPut(conn)\n\n\tfmt.Println(conn.(*DBConn).Limit)\n\n\t// Output:\n\t// 20\n}\n\nfunc ExamplePool_Clear() {\n\ttype DBConn struct {\n\t\tConn  *sql.Conn\n\t\tLimit int\n\t}\n\n\tdbConnPool := gpool.New(time.Hour,\n\t\tfunc() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\tdbConn.Limit = 10\n\t\t\treturn dbConn, nil\n\t\t},\n\t\tfunc(i any) {\n\t\t\ti.(*DBConn).Limit = 0\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t})\n\n\tconn, _ := dbConnPool.Get()\n\tdbConnPool.MustPut(conn)\n\tdbConnPool.MustPut(conn)\n\tfmt.Println(dbConnPool.Size())\n\tdbConnPool.Clear()\n\tfmt.Println(dbConnPool.Size())\n\n\t// Output:\n\t// 2\n\t// 0\n}\n\nfunc ExamplePool_Get() {\n\ttype DBConn struct {\n\t\tConn  *sql.Conn\n\t\tLimit int\n\t}\n\n\tdbConnPool := gpool.New(time.Hour,\n\t\tfunc() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\tdbConn.Limit = 10\n\t\t\treturn dbConn, nil\n\t\t},\n\t\tfunc(i any) {\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t})\n\n\tconn, err := dbConnPool.Get()\n\tif err == nil {\n\t\tfmt.Println(conn.(*DBConn).Limit)\n\t}\n\n\t// Output:\n\t// 10\n}\n\nfunc ExamplePool_Size() {\n\ttype DBConn struct {\n\t\tConn  *sql.Conn\n\t\tLimit int\n\t}\n\n\tdbConnPool := gpool.New(time.Hour,\n\t\tfunc() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\tdbConn.Limit = 10\n\t\t\treturn dbConn, nil\n\t\t},\n\t\tfunc(i any) {\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t})\n\n\tconn, _ := dbConnPool.Get()\n\tfmt.Println(dbConnPool.Size())\n\tdbConnPool.MustPut(conn)\n\tdbConnPool.MustPut(conn)\n\tfmt.Println(dbConnPool.Size())\n\n\t// Output:\n\t// 0\n\t// 2\n}\n\nfunc ExamplePool_Close() {\n\ttype DBConn struct {\n\t\tConn  *sql.Conn\n\t\tLimit int\n\t}\n\tvar (\n\t\tnewFunc = func() (any, error) {\n\t\t\tdbConn := new(DBConn)\n\t\t\tdbConn.Limit = 10\n\t\t\treturn dbConn, nil\n\t\t}\n\t\tcloseFunc = func(i any) {\n\t\t\tfmt.Println(\"Close The Pool\")\n\t\t\t// sample : close db conn\n\t\t\t// i.(DBConn).Conn.Close()\n\t\t}\n\t)\n\tdbConnPool := gpool.New(time.Hour, newFunc, closeFunc)\n\n\tconn, _ := dbConnPool.Get()\n\tdbConnPool.MustPut(conn)\n\n\tdbConnPool.Close()\n\n\t// wait for pool close\n\ttime.Sleep(time.Second * 1)\n\n\t// May Output:\n\t// Close The Pool\n}\n"
  },
  {
    "path": "container/gpool/gpool_z_unit_generic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gpool_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gpool\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_TPool_Int(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a pool for int\n\t\tvar (\n\t\t\tnewFunc = func() (int, error) {\n\t\t\t\treturn 100, nil\n\t\t\t}\n\t\t\texpireVal  = gtype.NewInt(0)\n\t\t\texpireFunc = func(i int) {\n\t\t\t\texpireVal.Set(i)\n\t\t\t}\n\t\t)\n\n\t\t// TTL = 0, no expiration by time\n\t\tp := gpool.NewTPool(0, newFunc, expireFunc)\n\n\t\t// Test Put and Get\n\t\tp.Put(1)\n\t\tp.Put(2)\n\t\tt.Assert(p.Size(), 2)\n\n\t\tv, err := p.Get()\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(v, g.Slice{1, 2})\n\n\t\tv, err = p.Get()\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(v, g.Slice{1, 2})\n\n\t\tt.Assert(p.Size(), 0)\n\n\t\t// Test NewFunc when empty\n\t\tv, err = p.Get()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, 100)\n\n\t\t// Test Clear and ExpireFunc\n\t\tp.Put(50)\n\t\tt.Assert(p.Size(), 1)\n\t\tp.Clear()\n\t\tt.Assert(p.Size(), 0)\n\t\tt.Assert(expireVal.Val(), 50)\n\n\t\t// Test Close\n\t\tp.Put(60)\n\t\tp.Close()\n\t\t// Close should trigger expire for existing items?\n\t\t// Looking at implementation: Close() sets closed=true.\n\t\t// It does NOT automatically clear items unless checkExpireItems runs or we call Clear?\n\t\t// Wait, checkExpireItems checks closed.Val(). If closed, it clears items.\n\t\t// But checkExpireItems runs in a separate goroutine every second.\n\t\t// So we might need to wait or trigger it.\n\t\t// Actually, let's check the implementation of Close again.\n\t\t/*\n\t\t\tfunc (p *TPool[T]) Close() {\n\t\t\t\tp.closed.Set(true)\n\t\t\t}\n\t\t*/\n\t\t// And checkExpireItems:\n\t\t/*\n\t\t\tfunc (p *TPool[T]) checkExpireItems(ctx context.Context) {\n\t\t\t\tif p.closed.Val() {\n\t\t\t\t\t// ... clears items ...\n\t\t\t\t\tgtimer.Exit()\n\t\t\t\t}\n\t\t\t\t// ...\n\t\t\t}\n\t\t*/\n\t\t// So it relies on the timer to clean up.\n\t})\n}\n\nfunc Test_TPool_Struct(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gpool.NewTPool[User](time.Hour, nil)\n\t\tu1 := User{Id: 1, Name: \"john\"}\n\t\tp.Put(u1)\n\n\t\tv, err := p.Get()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, u1)\n\n\t\t// Test empty with no NewFunc\n\t\tv, err = p.Get()\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"pool is empty\")\n\t\tt.Assert(v, User{}) // Zero value\n\t})\n}\n"
  },
  {
    "path": "container/gpool/gpool_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gpool_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gpool\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar nf gpool.NewFunc = func() (i any, e error) {\n\treturn \"hello\", nil\n}\n\nvar assertIndex = gtype.NewInt(0)\n\nvar ef gpool.ExpireFunc = func(i any) {\n\tassertIndex.Add(1)\n\tgtest.Assert(i, assertIndex)\n}\n\nfunc Test_Gpool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//\n\t\t// expire = 0\n\t\tp1 := gpool.New(0, nf)\n\t\tp1.Put(1)\n\t\tp1.Put(2)\n\t\ttime.Sleep(1 * time.Second)\n\t\t// test won't be timeout\n\t\tv1, err1 := p1.Get()\n\t\tt.Assert(err1, nil)\n\t\tt.AssertIN(v1, g.Slice{1, 2})\n\t\t// test clear\n\t\tp1.Clear()\n\t\tt.Assert(p1.Size(), 0)\n\t\t// test newFunc\n\t\tv1, err1 = p1.Get()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(v1, \"hello\")\n\t\t// put data again\n\t\tp1.Put(3)\n\t\tp1.Put(4)\n\t\tv1, err1 = p1.Get()\n\t\tt.Assert(err1, nil)\n\t\tt.AssertIN(v1, g.Slice{3, 4})\n\t\t// test close\n\t\tp1.Close()\n\t\tv1, err1 = p1.Get()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(v1, \"hello\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//\n\t\t// expire > 0\n\t\tp2 := gpool.New(2*time.Second, nil, ef)\n\t\tfor index := 0; index < 10; index++ {\n\t\t\tp2.Put(index)\n\t\t}\n\t\tt.Assert(p2.Size(), 10)\n\t\tv2, err2 := p2.Get()\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(v2, 0)\n\t\t// test timeout expireFunc\n\t\ttime.Sleep(3 * time.Second)\n\t\tv2, err2 = p2.Get()\n\t\tt.Assert(err2, errors.New(\"pool is empty\"))\n\t\tt.Assert(v2, nil)\n\t\t// test close expireFunc\n\t\tfor index := range 10 {\n\t\t\tp2.Put(index)\n\t\t}\n\t\tt.Assert(p2.Size(), 10)\n\t\tv2, err2 = p2.Get()\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(v2, 0)\n\t\tassertIndex.Set(0)\n\t\tp2.Close()\n\t\ttime.Sleep(3 * time.Second)\n\t\tt.AssertNE(p2.Put(1), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//\n\t\t// expire < 0\n\t\tp3 := gpool.New(-1, nil)\n\t\tv3, err3 := p3.Get()\n\t\tt.Assert(err3, errors.New(\"pool is empty\"))\n\t\tt.Assert(v3, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gpool.New(time.Millisecond*200, nil, func(i any) {})\n\t\tp.Put(1)\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tp.Put(2)\n\t\ttime.Sleep(time.Millisecond * 200)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := make([]int, 0)\n\t\tp := gpool.New(time.Millisecond*200, nil, func(i any) {\n\t\t\ts = append(s, i.(int))\n\t\t})\n\t\tfor i := 0; i < 5; i++ {\n\t\t\tp.Put(i)\n\t\t\ttime.Sleep(time.Millisecond * 50)\n\t\t}\n\t\tval, err := p.Get()\n\t\tt.Assert(val, 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(p.Size(), 2)\n\t})\n}\n"
  },
  {
    "path": "container/gqueue/gqueue.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gqueue provides dynamic/static concurrent-safe queue.\n//\n// Features:\n//\n// 1. FIFO queue(data -> list -> chan);\n//\n// 2. Fast creation and initialization;\n//\n// 3. Support dynamic queue size(unlimited queue size);\n//\n// 4. Blocking when reading data from queue;\npackage gqueue\n\n// Queue is a concurrent-safe queue built on doubly linked list and channel.\ntype Queue struct {\n\t*TQueue[any]\n}\n\nconst (\n\tdefaultQueueSize = 10000 // Size for queue buffer.\n\tdefaultBatchSize = 10    // Max batch size per-fetching from list.\n)\n\n// New returns an empty queue object.\n// Optional parameter `limit` is used to limit the size of the queue, which is unlimited in default.\n// When `limit` is given, the queue will be static and high performance which is comparable with stdlib channel.\nfunc New(limit ...int) *Queue {\n\treturn &Queue{\n\t\tTQueue: NewTQueue[any](limit...),\n\t}\n}\n\n// Push pushes the data `v` into the queue.\n// Note that it would panic if Push is called after the queue is closed.\nfunc (q *Queue) Push(v any) {\n\tq.TQueue.Push(v)\n}\n\n// Pop pops an item from the queue in FIFO way.\n// Note that it would return nil immediately if Pop is called after the queue is closed.\nfunc (q *Queue) Pop() any {\n\treturn q.TQueue.Pop()\n}\n\n// Close closes the queue.\n// Notice: It would notify all goroutines return immediately,\n// which are being blocked reading using Pop method.\nfunc (q *Queue) Close() {\n\tq.TQueue.Close()\n}\n\n// Len returns the length of the queue.\n// Note that the result might not be accurate if using unlimited queue size as there's an\n// asynchronous channel reading the list constantly.\nfunc (q *Queue) Len() (length int64) {\n\treturn q.TQueue.Len()\n}\n\n// Size is alias of Len.\n//\n// Deprecated: use Len instead.\nfunc (q *Queue) Size() int64 {\n\treturn q.Len()\n}\n"
  },
  {
    "path": "container/gqueue/gqueue_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\npackage gqueue\n\nimport (\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n)\n\n// TQueue is a concurrent-safe queue built on doubly linked list and channel.\ntype TQueue[T any] struct {\n\tlimit  int             // Limit for queue size.\n\tlist   *glist.TList[T] // Underlying list structure for data maintaining.\n\tclosed *gtype.Bool     // Whether queue is closed.\n\tevents chan struct{}   // Events for data writing.\n\tC      chan T          // Underlying channel for data reading.\n}\n\n// NewTQueue returns an empty queue object.\n// Optional parameter `limit` is used to limit the size of the queue, which is unlimited in default.\n// When `limit` is given, the queue will be static and high performance which is comparable with stdlib channel.\nfunc NewTQueue[T any](limit ...int) *TQueue[T] {\n\tq := &TQueue[T]{\n\t\tclosed: gtype.NewBool(),\n\t}\n\tif len(limit) > 0 && limit[0] > 0 {\n\t\tq.limit = limit[0]\n\t\tq.C = make(chan T, limit[0])\n\t} else {\n\t\tq.list = glist.NewT[T](true)\n\t\tq.events = make(chan struct{}, math.MaxInt32)\n\t\tq.C = make(chan T, defaultQueueSize)\n\t\tgo q.asyncLoopFromListToChannel()\n\t}\n\treturn q\n}\n\n// Push pushes the data `v` into the queue.\n// Note that it would panic if Push is called after the queue is closed.\nfunc (q *TQueue[T]) Push(v T) {\n\tif q.limit > 0 {\n\t\tq.C <- v\n\t} else {\n\t\tq.list.PushBack(v)\n\t\tif len(q.events) < defaultQueueSize {\n\t\t\tq.events <- struct{}{}\n\t\t}\n\t}\n}\n\n// Pop pops an item from the queue in FIFO way.\n// Note that it would return nil immediately if Pop is called after the queue is closed.\nfunc (q *TQueue[T]) Pop() T {\n\treturn <-q.C\n}\n\n// Close closes the queue.\n// Notice: It would notify all goroutines return immediately,\n// which are being blocked reading using Pop method.\nfunc (q *TQueue[T]) Close() {\n\tif !q.closed.Cas(false, true) {\n\t\treturn\n\t}\n\tif q.events != nil {\n\t\tclose(q.events)\n\t}\n\tif q.limit > 0 {\n\t\tclose(q.C)\n\t} else {\n\t\tfor range defaultBatchSize {\n\t\t\tq.Pop()\n\t\t}\n\t}\n}\n\n// Len returns the length of the queue.\n// Note that the result might not be accurate if using unlimited queue size as there's an\n// asynchronous channel reading the list constantly.\nfunc (q *TQueue[T]) Len() (length int64) {\n\tbufferedSize := int64(len(q.C))\n\tif q.limit > 0 {\n\t\treturn bufferedSize\n\t}\n\t// If the queue is unlimited and the buffered size is exactly the default size,\n\t// it means there might be some data in the list not synchronized to channel yet.\n\t// So we need to add 1 to the buffered size to make the result more accurate.\n\tif bufferedSize == defaultQueueSize {\n\t\tbufferedSize++\n\t}\n\treturn int64(q.list.Size()) + bufferedSize\n}\n\n// Size is alias of Len.\n//\n// Deprecated: use Len instead.\nfunc (q *TQueue[T]) Size() int64 {\n\treturn q.Len()\n}\n\n// asyncLoopFromListToChannel starts an asynchronous goroutine,\n// which handles the data synchronization from list `q.list` to channel `q.C`.\nfunc (q *TQueue[T]) asyncLoopFromListToChannel() {\n\tdefer func() {\n\t\tif q.closed.Val() {\n\t\t\t_ = recover()\n\t\t}\n\t}()\n\tfor !q.closed.Val() {\n\t\t<-q.events\n\t\tfor !q.closed.Val() {\n\t\t\tif bufferLength := q.list.Len(); bufferLength > 0 {\n\t\t\t\t// When q.C is closed, it will panic here, especially q.C is being blocked for writing.\n\t\t\t\t// If any error occurs here, it will be caught by recover and be ignored.\n\t\t\t\tfor range bufferLength {\n\t\t\t\t\tq.C <- q.list.PopFront()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t// Clear q.events to remain just one event to do the next synchronization check.\n\t\tfor i := 0; i < len(q.events)-1; i++ {\n\t\t\t<-q.events\n\t\t}\n\t}\n\t// It should be here to close `q.C` if `q` is unlimited size.\n\t// It's the sender's responsibility to close channel when it should be closed.\n\tclose(q.C)\n}\n"
  },
  {
    "path": "container/gqueue/gqueue_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gqueue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n)\n\nvar bn = 20000000\n\nvar length = 1000000\n\nvar qstatic = gqueue.New(length)\n\nvar qdynamic = gqueue.New()\n\nvar cany = make(chan any, length)\n\nfunc Benchmark_Gqueue_StaticPushAndPop(b *testing.B) {\n\tb.N = bn\n\tfor i := 0; i < b.N; i++ {\n\t\tqstatic.Push(i)\n\t\tqstatic.Pop()\n\t}\n}\n\nfunc Benchmark_Gqueue_DynamicPush(b *testing.B) {\n\tb.N = bn\n\tfor i := 0; i < b.N; i++ {\n\t\tqdynamic.Push(i)\n\t}\n}\n\nfunc Benchmark_Gqueue_DynamicPop(b *testing.B) {\n\tb.N = bn\n\tfor i := 0; i < b.N; i++ {\n\t\tqdynamic.Pop()\n\t}\n}\n\nfunc Benchmark_Channel_PushAndPop(b *testing.B) {\n\tb.N = bn\n\tfor i := 0; i < b.N; i++ {\n\t\tcany <- i\n\t\t<-cany\n\t}\n}\n"
  },
  {
    "path": "container/gqueue/gqueue_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gqueue_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\nfunc ExampleNew() {\n\tn := 10\n\tq := gqueue.New()\n\n\t// Producer\n\tfor i := 0; i < n; i++ {\n\t\tq.Push(i)\n\t}\n\n\t// Close the queue in three seconds.\n\tgtimer.SetTimeout(context.Background(), time.Second*3, func(ctx context.Context) {\n\t\tq.Close()\n\t})\n\n\t// The consumer constantly reads the queue data.\n\t// If there is no data in the queue, it will block.\n\t// The queue is read using the queue.C property exposed\n\t// by the queue object and the selectIO multiplexing syntax\n\t// example:\n\t// for {\n\t//    select {\n\t//        case v := <-queue.C:\n\t//            if v != nil {\n\t//                fmt.Println(v)\n\t//            } else {\n\t//                return\n\t//            }\n\t//    }\n\t// }\n\tfor {\n\t\tif v := q.Pop(); v != nil {\n\t\t\tfmt.Print(v)\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Output:\n\t// 0123456789\n}\n\nfunc ExampleQueue_Push() {\n\tq := gqueue.New()\n\n\tfor i := 0; i < 10; i++ {\n\t\tq.Push(i)\n\t}\n\n\tfmt.Println(q.Pop())\n\tfmt.Println(q.Pop())\n\tfmt.Println(q.Pop())\n\n\t// Output:\n\t// 0\n\t// 1\n\t// 2\n}\n\nfunc ExampleQueue_Pop() {\n\tq := gqueue.New()\n\n\tfor i := 0; i < 10; i++ {\n\t\tq.Push(i)\n\t}\n\n\tfmt.Println(q.Pop())\n\tq.Close()\n\tfmt.Println(q.Pop())\n\n\t// Output:\n\t// 0\n\t// <nil>\n}\n\nfunc ExampleQueue_Close() {\n\tq := gqueue.New()\n\n\tfor i := 0; i < 10; i++ {\n\t\tq.Push(i)\n\t}\n\n\ttime.Sleep(time.Millisecond)\n\tq.Close()\n\n\tfmt.Println(q.Len())\n\tfmt.Println(q.Pop())\n\n\t// May Output:\n\t// 0\n\t// <nil>\n}\n\nfunc ExampleQueue_Len() {\n\tq := gqueue.New()\n\n\tq.Push(1)\n\tq.Push(2)\n\n\tfmt.Println(q.Len())\n\n\t// May Output:\n\t// 2\n}\n\nfunc ExampleQueue_Size() {\n\tq := gqueue.New()\n\n\tq.Push(1)\n\tq.Push(2)\n\n\t// Size is alias of Len.\n\tfmt.Println(q.Size())\n\n\t// May Output:\n\t// 2\n}\n"
  },
  {
    "path": "container/gqueue/gqueue_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gqueue_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestQueue_Len(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmaxNum   = 100\n\t\t\tmaxTries = 100\n\t\t)\n\t\tfor n := 10; n < maxTries; n++ {\n\t\t\tq1 := gqueue.New(maxNum)\n\t\t\tfor i := range maxNum {\n\t\t\t\tq1.Push(i)\n\t\t\t}\n\t\t\tt.Assert(q1.Len(), maxNum)\n\t\t\tt.Assert(q1.Size(), maxNum)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmaxNum   = 100\n\t\t\tmaxTries = 100\n\t\t)\n\t\tfor n := 10; n < maxTries; n++ {\n\t\t\tq1 := gqueue.New()\n\t\t\tfor i := range maxNum {\n\t\t\t\tq1.Push(i)\n\t\t\t}\n\t\t\tt.AssertLE(q1.Len(), maxNum)\n\t\t\tt.AssertLE(q1.Size(), maxNum)\n\t\t}\n\t})\n}\n\nfunc TestQueue_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tdefer q.Close()\n\t\tfor i := range 100 {\n\t\t\tq.Push(i)\n\t\t}\n\t\tt.Assert(q.Pop(), 0)\n\t\tt.Assert(q.Pop(), 1)\n\t})\n}\n\nfunc TestQueue_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq1 := gqueue.New()\n\t\tdefer q1.Close()\n\t\tq1.Push(1)\n\t\tq1.Push(2)\n\t\tq1.Push(3)\n\t\tq1.Push(4)\n\t\ti1 := q1.Pop()\n\t\tt.Assert(i1, 1)\n\t})\n}\n\nfunc TestQueue_Close(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq1 := gqueue.New()\n\t\tdefer q1.Close()\n\t\tq1.Push(1)\n\t\tq1.Push(2)\n\t\t// wait sync to channel\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(q1.Len(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq1 := gqueue.New(2)\n\t\tdefer q1.Close()\n\t\tq1.Push(1)\n\t\tq1.Push(2)\n\t\t// wait sync to channel\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(q1.Len(), 2)\n\t})\n}\n\nfunc Test_Issue2509(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tdefer q.Close()\n\t\tq.Push(1)\n\t\tq.Push(2)\n\t\tq.Push(3)\n\t\tt.AssertLE(q.Len(), 3)\n\t\tt.Assert(<-q.C, 1)\n\t\tt.AssertLE(q.Len(), 2)\n\t\tt.Assert(<-q.C, 2)\n\t\tt.AssertLE(q.Len(), 1)\n\t\tt.Assert(<-q.C, 3)\n\t\tt.Assert(q.Len(), 0)\n\t})\n}\n\n// Issue #4376\nfunc TestIssue4376(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgq := gqueue.New()\n\t\tdefer gq.Close()\n\t\tcq := make(chan int, 100000)\n\t\tdefer close(cq)\n\n\t\tfor i := range 11603 {\n\t\t\tgq.Push(i)\n\t\t\tcq <- i\n\t\t}\n\t\t// May be not equal because of the async channel reading goroutine.\n\t\tt.Log(gq.Len(), len(cq))\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tt.Log(gq.Len(), len(cq))\n\t})\n}\n\n// Test static queue (with limit) close operation\nfunc TestQueue_StaticClose(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New(10)\n\t\tdefer func() {\n\t\t\tif err := recover(); err == nil {\n\t\t\t\tt.Log(\"Close succeeded\")\n\t\t\t}\n\t\t}()\n\t\tq.Push(1)\n\t\tq.Push(2)\n\t\tq.Close()\n\t\t// After closing, Pop should return nil\n\t\tv := q.Pop()\n\t\tt.Assert(v, nil)\n\t})\n}\n\n// Test Size() method (deprecated alias of Len)\nfunc TestQueue_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New(20)\n\t\tfor i := range 10 {\n\t\t\tq.Push(i)\n\t\t}\n\t\tt.Assert(q.Size(), 10)\n\t\tt.Assert(q.Len(), 10)\n\t\tq.Close()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tfor i := range 15 {\n\t\t\tq.Push(i)\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(q.Size(), q.Len())\n\t\tq.Close()\n\t})\n}\n\n// Test TQueue directly with generic type\nfunc TestTQueue_Generic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with custom type\n\t\tq := gqueue.NewTQueue[string]()\n\t\tdefer q.Close()\n\t\tq.Push(\"hello\")\n\t\tq.Push(\"world\")\n\t\tt.Assert(q.Pop(), \"hello\")\n\t\tt.Assert(q.Pop(), \"world\")\n\t})\n}\n\n// Test TQueue Size method directly\nfunc TestTQueue_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.NewTQueue[int]()\n\t\tdefer q.Close()\n\t\tfor i := range 10 {\n\t\t\tq.Push(i)\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\t// Size is an alias of Len for TQueue\n\t\tt.Assert(q.Size(), q.Len())\n\t})\n}\n\n// Test TQueue with static limit\nfunc TestTQueue_StaticLimit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.NewTQueue[int](5)\n\t\tdefer q.Close()\n\t\tfor i := range 5 {\n\t\t\tq.Push(i)\n\t\t}\n\t\tt.Assert(q.Len(), 5)\n\t\tfor i := range 5 {\n\t\t\tt.Assert(q.Pop(), i)\n\t\t}\n\t\tt.Assert(q.Len(), 0)\n\t})\n}\n\n// Test queue with large data push/pop\nfunc TestQueue_LargeDataScale(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tdefer q.Close()\n\t\tn := 5000\n\t\tfor i := range n {\n\t\t\tq.Push(i)\n\t\t}\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\t// Pop should retrieve all items in order\n\t\tfor i := range n {\n\t\t\tv := q.Pop()\n\t\t\tt.Assert(v, i)\n\t\t}\n\t})\n}\n\n// Test double close (idempotent close)\nfunc TestQueue_DoubleClose(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tq.Push(1)\n\t\tq.Close()\n\t\t// Second close should not panic\n\t\tq.Close()\n\t\tt.Assert(q.Pop(), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New(10)\n\t\tq.Push(1)\n\t\tq.Close()\n\t\t// Second close should not panic for static queue\n\t\tq.Close()\n\t\t// Pop from closed static queue returns the buffered value\n\t\tv := q.Pop()\n\t\tt.Assert(v, 1)\n\t})\n}\n\n// Test concurrent push and pop\nfunc TestQueue_ConcurrentPushPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tdefer q.Close()\n\t\t// Producer goroutine\n\t\tgo func() {\n\t\t\tfor i := range 100 {\n\t\t\t\tq.Push(i)\n\t\t\t}\n\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\tq.Close()\n\t\t}()\n\t\t// Consumer\n\t\tcount := 0\n\t\tfor {\n\t\t\tv := q.Pop()\n\t\t\tif v == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcount++\n\t\t}\n\t\tt.AssertGE(count, 1)\n\t})\n}\n\n// Test Pop on empty queue returns nil when closed\nfunc TestQueue_PopEmptyClosed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tq.Close()\n\t\tv := q.Pop()\n\t\tt.Assert(v, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New(10)\n\t\tq.Close()\n\t\tv := q.Pop()\n\t\tt.Assert(v, nil)\n\t})\n}\n\n// Test Len with dynamic queue at capacity boundary\nfunc TestQueue_LenAtBoundary(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\tdefer q.Close()\n\t\t// Push exactly defaultQueueSize items to test boundary condition\n\t\tfor i := range 10000 {\n\t\t\tq.Push(i)\n\t\t}\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tlen := q.Len()\n\t\tt.AssertGE(len, 0)\n\t})\n}\n\n// Test Close on dynamic queue with pending asyncLoopFromListToChannel\nfunc TestQueue_CloseWithAsyncLoop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New()\n\t\t// Push some data to activate asyncLoopFromListToChannel\n\t\tfor i := range 100 {\n\t\t\tq.Push(i)\n\t\t}\n\t\t// Immediately close\n\t\tq.Close()\n\t\t// Pop should return values until exhausted, then nil\n\t\tfor {\n\t\t\tv := q.Pop()\n\t\t\tif v == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tt.Assert(q.Pop(), nil)\n\t})\n}\n\n// Test static queue edge case with zero limit (should create unlimited queue)\nfunc TestQueue_ZeroLimitCreatesUnlimited(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tq := gqueue.New(0)\n\t\tdefer q.Close()\n\t\tfor i := range 100 {\n\t\t\tq.Push(i)\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tlen := q.Len()\n\t\tt.Assert(len, 100)\n\t})\n}\n"
  },
  {
    "path": "container/gring/gring.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gring provides a concurrent-safe/unsafe ring(circular lists).\n//\n// Deprecated.\npackage gring\n\n// Ring is a struct of ring structure.\n//\n// Deprecated.\ntype Ring struct {\n\t*TRing[any]\n}\n\n// New creates and returns a Ring structure of `cap` elements.\n// The optional parameter `safe` specifies whether using this structure in concurrent safety,\n// which is false in default.\n//\n// Deprecated.\nfunc New(cap int, safe ...bool) *Ring {\n\treturn &Ring{\n\t\tTRing: NewTRing[any](cap, safe...),\n\t}\n}\n\n// Val returns the item's value of current position.\nfunc (r *Ring) Val() any {\n\treturn r.TRing.Val()\n}\n\n// Len returns the size of ring.\nfunc (r *Ring) Len() int {\n\treturn r.TRing.Len()\n}\n\n// Cap returns the capacity of ring.\nfunc (r *Ring) Cap() int {\n\treturn r.TRing.Cap()\n}\n\n// Set sets value to the item of current position.\nfunc (r *Ring) Set(value any) *Ring {\n\tr.TRing.Set(value)\n\treturn r\n}\n\n// Put sets `value` to current item of ring and moves position to next item.\nfunc (r *Ring) Put(value any) *Ring {\n\tr.TRing.Put(value)\n\treturn r\n}\n\n// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)\n// in the ring and returns that ring element. r must not be empty.\nfunc (r *Ring) Move(n int) *Ring {\n\tr.TRing.Move(n)\n\treturn r\n}\n\n// Prev returns the previous ring element. r must not be empty.\nfunc (r *Ring) Prev() *Ring {\n\tr.TRing.Prev()\n\treturn r\n}\n\n// Next returns the next ring element. r must not be empty.\nfunc (r *Ring) Next() *Ring {\n\tr.TRing.Next()\n\treturn r\n}\n\n// Link connects ring r with ring s such that r.Next()\n// becomes s and returns the original value for r.Next().\n// r must not be empty.\n//\n// If r and s point to the same ring, linking\n// them removes the elements between r and s from the ring.\n// The removed elements form a sub-ring and the result is a\n// reference to that sub-ring (if no elements were removed,\n// the result is still the original value for r.Next(),\n// and not nil).\n//\n// If r and s point to different rings, linking\n// them creates a single ring with the elements of s inserted\n// after r. The result points to the element following the\n// last element of s after insertion.\nfunc (r *Ring) Link(s *Ring) *Ring {\n\tr.TRing.Link(s.TRing)\n\treturn r\n}\n\n// Unlink removes n % r.Len() elements from the ring r, starting\n// at r.Next(). If n % r.Len() == 0, r remains unchanged.\n// The result is the removed sub-ring. r must not be empty.\nfunc (r *Ring) Unlink(n int) *Ring {\n\treturn &Ring{\n\t\tTRing: r.TRing.Unlink(n),\n\t}\n}\n\n// RLockIteratorNext iterates and locks reading forward\n// with given callback function `f` within RWMutex.RLock.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (r *Ring) RLockIteratorNext(f func(value any) bool) {\n\tr.TRing.RLockIteratorNext(f)\n}\n\n// RLockIteratorPrev iterates and locks reading backward\n// with given callback function `f` within RWMutex.RLock.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (r *Ring) RLockIteratorPrev(f func(value any) bool) {\n\tr.TRing.RLockIteratorPrev(f)\n}\n\n// SliceNext returns a copy of all item values as slice forward from current position.\nfunc (r *Ring) SliceNext() []any {\n\treturn r.TRing.SliceNext()\n}\n\n// SlicePrev returns a copy of all item values as slice backward from current position.\nfunc (r *Ring) SlicePrev() []any {\n\treturn r.TRing.SlicePrev()\n}\n"
  },
  {
    "path": "container/gring/gring_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gring\n\nimport (\n\t\"container/ring\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n)\n\n// TRing is a struct of ring structure.\ntype TRing[T any] struct {\n\tmu    *rwmutex.RWMutex\n\tring  *ring.Ring  // Underlying ring.\n\tlen   *gtype.Int  // Length(already used size).\n\tcap   *gtype.Int  // Capability(>=len).\n\tdirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes.\n}\n\n// internalTRingItem[T] stores the ring element value.\ntype internalTRingItem[T any] struct {\n\tValue T\n}\n\n// NewTRing creates and returns a Ring structure of `cap` elements.\n// The optional parameter `safe` specifies whether using this structure in concurrent safety,\n// which is false in default.\nfunc NewTRing[T any](cap int, safe ...bool) *TRing[T] {\n\treturn &TRing[T]{\n\t\tmu:    rwmutex.New(safe...),\n\t\tring:  ring.New(cap),\n\t\tlen:   gtype.NewInt(),\n\t\tcap:   gtype.NewInt(cap),\n\t\tdirty: gtype.NewBool(),\n\t}\n}\n\n// Val returns the item's value of current position.\nfunc (r *TRing[T]) Val() T {\n\tvar value T\n\tr.mu.RLock()\n\tif r.ring.Value != nil {\n\t\tvalue = r.ring.Value.(internalTRingItem[T]).Value\n\t}\n\tr.mu.RUnlock()\n\treturn value\n}\n\n// Len returns the size of ring.\nfunc (r *TRing[T]) Len() int {\n\tr.checkAndUpdateLenAndCap()\n\treturn r.len.Val()\n}\n\n// Cap returns the capacity of ring.\nfunc (r *TRing[T]) Cap() int {\n\tr.checkAndUpdateLenAndCap()\n\treturn r.cap.Val()\n}\n\n// Checks and updates the len and cap of ring when ring is dirty.\nfunc (r *TRing[T]) checkAndUpdateLenAndCap() {\n\tif !r.dirty.Val() {\n\t\treturn\n\t}\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\ttotalLen := 0\n\temptyLen := 0\n\tif r.ring != nil {\n\t\tif r.ring.Value == nil {\n\t\t\temptyLen++\n\t\t}\n\t\ttotalLen++\n\t\tfor p := r.ring.Next(); p != r.ring; p = p.Next() {\n\t\t\tif p.Value == nil {\n\t\t\t\temptyLen++\n\t\t\t}\n\t\t\ttotalLen++\n\t\t}\n\t}\n\tr.cap.Set(totalLen)\n\tr.len.Set(totalLen - emptyLen)\n\tr.dirty.Set(false)\n}\n\n// Set sets value to the item of current position.\nfunc (r *TRing[T]) Set(value T) *TRing[T] {\n\tr.mu.Lock()\n\tif r.ring.Value == nil {\n\t\tr.len.Add(1)\n\t}\n\tr.ring.Value = internalTRingItem[T]{Value: value}\n\tr.mu.Unlock()\n\treturn r\n}\n\n// Put sets `value` to current item of ring and moves position to next item.\nfunc (r *TRing[T]) Put(value T) *TRing[T] {\n\tr.mu.Lock()\n\tif r.ring.Value == nil {\n\t\tr.len.Add(1)\n\t}\n\tr.ring.Value = internalTRingItem[T]{Value: value}\n\tr.ring = r.ring.Next()\n\tr.mu.Unlock()\n\treturn r\n}\n\n// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)\n// in the ring and returns that ring element. r must not be empty.\nfunc (r *TRing[T]) Move(n int) *TRing[T] {\n\tr.mu.Lock()\n\tr.ring = r.ring.Move(n)\n\tr.mu.Unlock()\n\treturn r\n}\n\n// Prev returns the previous ring element. r must not be empty.\nfunc (r *TRing[T]) Prev() *TRing[T] {\n\tr.mu.Lock()\n\tr.ring = r.ring.Prev()\n\tr.mu.Unlock()\n\treturn r\n}\n\n// Next returns the next ring element. r must not be empty.\nfunc (r *TRing[T]) Next() *TRing[T] {\n\tr.mu.Lock()\n\tr.ring = r.ring.Next()\n\tr.mu.Unlock()\n\treturn r\n}\n\n// Link connects ring r with ring s such that r.Next()\n// becomes s and returns the original value for r.Next().\n// r must not be empty.\n//\n// If r and s point to the same ring, linking\n// them removes the elements between r and s from the ring.\n// The removed elements form a sub-ring and the result is a\n// reference to that sub-ring (if no elements were removed,\n// the result is still the original value for r.Next(),\n// and not nil).\n//\n// If r and s point to different rings, linking\n// them creates a single ring with the elements of s inserted\n// after r. The result points to the element following the\n// last element of s after insertion.\nfunc (r *TRing[T]) Link(s *TRing[T]) *TRing[T] {\n\tr.mu.Lock()\n\ts.mu.Lock()\n\tr.ring.Link(s.ring)\n\ts.mu.Unlock()\n\tr.mu.Unlock()\n\tr.dirty.Set(true)\n\ts.dirty.Set(true)\n\treturn r\n}\n\n// Unlink removes n % r.Len() elements from the ring r, starting\n// at r.Next(). If n % r.Len() == 0, r remains unchanged.\n// The result is the removed sub-ring. r must not be empty.\nfunc (r *TRing[T]) Unlink(n int) *TRing[T] {\n\tr.mu.Lock()\n\tresultRing := r.ring.Unlink(n)\n\tr.dirty.Set(true)\n\tr.mu.Unlock()\n\tresultGRing := NewTRing[T](resultRing.Len())\n\tresultGRing.ring = resultRing\n\tresultGRing.dirty.Set(true)\n\treturn resultGRing\n}\n\n// RLockIteratorNext iterates and locks reading forward\n// with given callback function `f` within RWMutex.RLock.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (r *TRing[T]) RLockIteratorNext(f func(value T) bool) {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\tif r.ring.Value != nil && !f(r.ring.Value.(internalTRingItem[T]).Value) {\n\t\treturn\n\t}\n\tfor p := r.ring.Next(); p != r.ring; p = p.Next() {\n\t\tif p.Value == nil || !f(p.Value.(internalTRingItem[T]).Value) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// RLockIteratorPrev iterates and locks reading backward\n// with given callback function `f` within RWMutex.RLock.\n// If `f` returns true, then it continues iterating; or false to stop.\nfunc (r *TRing[T]) RLockIteratorPrev(f func(value T) bool) {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\tif r.ring.Value != nil && !f(r.ring.Value.(internalTRingItem[T]).Value) {\n\t\treturn\n\t}\n\tfor p := r.ring.Prev(); p != r.ring; p = p.Prev() {\n\t\tif p.Value == nil || !f(p.Value.(internalTRingItem[T]).Value) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// SliceNext returns a copy of all item values as slice forward from current position.\nfunc (r *TRing[T]) SliceNext() []T {\n\ts := make([]T, 0, r.Len())\n\tr.mu.RLock()\n\tif r.ring.Value != nil {\n\t\ts = append(s, r.ring.Value.(internalTRingItem[T]).Value)\n\t}\n\tfor p := r.ring.Next(); p != r.ring; p = p.Next() {\n\t\tif p.Value == nil {\n\t\t\tbreak\n\t\t}\n\t\ts = append(s, p.Value.(internalTRingItem[T]).Value)\n\t}\n\tr.mu.RUnlock()\n\treturn s\n}\n\n// SlicePrev returns a copy of all item values as slice backward from current position.\nfunc (r *TRing[T]) SlicePrev() []T {\n\ts := make([]T, 0, r.Len())\n\tr.mu.RLock()\n\tif r.ring.Value != nil {\n\t\ts = append(s, r.ring.Value.(internalTRingItem[T]).Value)\n\t}\n\tfor p := r.ring.Prev(); p != r.ring; p = p.Prev() {\n\t\tif p.Value == nil {\n\t\t\tbreak\n\t\t}\n\t\ts = append(s, p.Value.(internalTRingItem[T]).Value)\n\t}\n\tr.mu.RUnlock()\n\treturn s\n}\n"
  },
  {
    "path": "container/gring/gring_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gring_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gring\"\n)\n\nvar length = 10000\n\nvar ringObject = gring.New(length, true)\n\nfunc BenchmarkRing_Put(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tringObject.Put(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc BenchmarkRing_Next(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tringObject.Next()\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc BenchmarkRing_Set(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tringObject.Set(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc BenchmarkRing_Len(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tringObject.Len()\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc BenchmarkRing_Cap(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tringObject.Cap()\n\t\t\ti++\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gring/gring_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gring_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gring\"\n)\n\nfunc ExampleNew() {\n\t// Non concurrent safety\n\tgring.New(10)\n\n\t// Concurrent safety\n\tgring.New(10, true)\n\n\t// Output:\n}\n\nfunc ExampleRing_Val() {\n\tr := gring.New(10)\n\tr.Set(1)\n\tfmt.Println(\"Val:\", r.Val())\n\n\tr.Next().Set(\"GoFrame\")\n\tfmt.Println(\"Val:\", r.Val())\n\n\t// Output:\n\t// Val: 1\n\t// Val: GoFrame\n}\n\nfunc ExampleRing_Len() {\n\tr1 := gring.New(10)\n\tfor i := 0; i < 5; i++ {\n\t\tr1.Set(i).Next()\n\t}\n\tfmt.Println(\"Len:\", r1.Len())\n\n\tr2 := gring.New(10, true)\n\tfor i := 0; i < 10; i++ {\n\t\tr2.Set(i).Next()\n\t}\n\tfmt.Println(\"Len:\", r2.Len())\n\n\t// Output:\n\t// Len: 5\n\t// Len: 10\n}\n\nfunc ExampleRing_Cap() {\n\tr1 := gring.New(10)\n\tfor i := 0; i < 5; i++ {\n\t\tr1.Set(i).Next()\n\t}\n\tfmt.Println(\"Cap:\", r1.Cap())\n\n\tr2 := gring.New(10, true)\n\tfor i := 0; i < 10; i++ {\n\t\tr2.Set(i).Next()\n\t}\n\tfmt.Println(\"Cap:\", r2.Cap())\n\n\t// Output:\n\t// Cap: 10\n\t// Cap: 10\n}\n\nfunc ExampleRing_Set() {\n\tr := gring.New(10)\n\tr.Set(1)\n\tfmt.Println(\"Val:\", r.Val())\n\n\tr.Next().Set(\"GoFrame\")\n\tfmt.Println(\"Val:\", r.Val())\n\n\t// Output:\n\t// Val: 1\n\t// Val: GoFrame\n}\n\nfunc ExampleRing_Put() {\n\tr := gring.New(10)\n\tr.Put(1)\n\tfmt.Println(\"Val:\", r.Val())\n\tfmt.Println(\"Val:\", r.Prev().Val())\n\n\t// Output:\n\t// Val: <nil>\n\t// Val: 1\n}\n\nfunc ExampleRing_Move() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\t// ring at Pos 0\n\tfmt.Println(\"CurVal:\", r.Val())\n\n\tr.Move(5)\n\n\t// ring at Pos 5\n\tfmt.Println(\"CurVal:\", r.Val())\n\n\t// Output:\n\t// CurVal: 0\n\t// CurVal: 5\n}\n\nfunc ExampleRing_Prev() {\n\tr := gring.New(10)\n\tfor i := 0; i < 5; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tfmt.Println(\"Prev:\", r.Prev().Val())\n\tfmt.Println(\"Prev:\", r.Prev().Val())\n\n\t// Output:\n\t// Prev: 4\n\t// Prev: 3\n}\n\nfunc ExampleRing_Next() {\n\tr := gring.New(10)\n\tfor i := 5; i > 0; i-- {\n\t\tr.Set(i).Prev()\n\t}\n\n\tfmt.Println(\"Prev:\", r.Next().Val())\n\tfmt.Println(\"Prev:\", r.Next().Val())\n\n\t// Output:\n\t// Prev: 1\n\t// Prev: 2\n}\n\nfunc ExampleRing_Link_common() {\n\tr := gring.New(10)\n\tfor i := 0; i < 5; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\ts := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tval := i + 5\n\t\ts.Set(val).Next()\n\t}\n\n\tr.Link(s) // Link Ring s to Ring r\n\n\tfmt.Println(\"Len:\", r.Len())\n\tfmt.Println(\"Cap:\", r.Cap())\n\tfmt.Println(r.SlicePrev())\n\tfmt.Println(r.SliceNext())\n\n\t// Output:\n\t// Len: 15\n\t// Cap: 20\n\t// [4 3 2 1 0]\n\t// [5 6 7 8 9 10 11 12 13 14]\n}\n\nfunc ExampleRing_Link_sameRing() {\n\tr := gring.New(10)\n\tfor i := 0; i < 5; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tsame_r := r.Link(r.Prev())\n\n\tfmt.Println(\"Len:\", same_r.Len())\n\tfmt.Println(\"Cap:\", same_r.Cap())\n\tfmt.Println(same_r.SlicePrev())\n\tfmt.Println(same_r.SliceNext())\n\n\t// Output:\n\t// Len: 1\n\t// Cap: 1\n\t// [4]\n\t// [4]\n}\n\nfunc ExampleRing_Unlink() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tfmt.Println(\"Before Unlink, Len:\", r.Len())\n\tfmt.Println(\"Before Unlink, Cap:\", r.Cap())\n\tfmt.Println(\"Before Unlink, \", r.SlicePrev())\n\tfmt.Println(\"Before Unlink, \", r.SliceNext())\n\n\tr.Unlink(7)\n\n\tfmt.Println(\"After Unlink, Len:\", r.Len())\n\tfmt.Println(\"After Unlink, Cap:\", r.Cap())\n\tfmt.Println(\"After Unlink, \", r.SlicePrev())\n\tfmt.Println(\"After Unlink, \", r.SliceNext())\n\n\t// Output:\n\t// Before Unlink, Len: 10\n\t// Before Unlink, Cap: 10\n\t// Before Unlink,  [0 9 8 7 6 5 4 3 2 1]\n\t// Before Unlink,  [0 1 2 3 4 5 6 7 8 9]\n\t// After Unlink, Len: 3\n\t// After Unlink, Cap: 3\n\t// After Unlink,  [0 9 8]\n\t// After Unlink,  [0 8 9]\n}\n\nfunc ExampleRing_RLockIteratorNext() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tr.RLockIteratorNext(func(value any) bool {\n\t\tif value.(int) < 5 {\n\t\t\tfmt.Println(\"IteratorNext Success, Value:\", value)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t})\n\n\t// Output:\n\t// IteratorNext Success, Value: 0\n\t// IteratorNext Success, Value: 1\n\t// IteratorNext Success, Value: 2\n\t// IteratorNext Success, Value: 3\n\t// IteratorNext Success, Value: 4\n}\n\nfunc ExampleRing_RLockIteratorPrev() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\t// move r to pos 9\n\tr.Prev()\n\n\tr.RLockIteratorPrev(func(value any) bool {\n\t\tif value.(int) >= 5 {\n\t\t\tfmt.Println(\"IteratorPrev Success, Value:\", value)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t})\n\n\t// Output:\n\t// IteratorPrev Success, Value: 9\n\t// IteratorPrev Success, Value: 8\n\t// IteratorPrev Success, Value: 7\n\t// IteratorPrev Success, Value: 6\n\t// IteratorPrev Success, Value: 5\n}\n\nfunc ExampleRing_SliceNext() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tfmt.Println(r.SliceNext())\n\n\t// Output:\n\t// [0 1 2 3 4 5 6 7 8 9]\n}\n\nfunc ExampleRing_SlicePrev() {\n\tr := gring.New(10)\n\tfor i := 0; i < 10; i++ {\n\t\tr.Set(i).Next()\n\t}\n\n\tfmt.Println(r.SlicePrev())\n\n\t// Output:\n\t// [0 9 8 7 6 5 4 3 2 1]\n}\n"
  },
  {
    "path": "container/gring/gring_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gring_test\n\nimport (\n\t\"container/ring\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gring\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype Student struct {\n\tposition int\n\tname     string\n\tupgrade  bool\n}\n\nfunc TestRing_Val(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//定义cap 为3的ring类型数据\n\t\tr := gring.New(3, true)\n\t\t//分别给3个元素初始化赋值\n\t\tr.Put(&Student{1, \"jimmy\", true})\n\t\tr.Put(&Student{2, \"tom\", true})\n\t\tr.Put(&Student{3, \"alon\", false})\n\n\t\t//元素取值并判断和预设值是否相等\n\t\tt.Assert(r.Val().(*Student).name, \"jimmy\")\n\t\t//从当前位置往后移两个元素\n\t\tr.Move(2)\n\t\tt.Assert(r.Val().(*Student).name, \"alon\")\n\t\t//更新元素值\n\t\t//测试 value == nil\n\t\tr.Set(nil)\n\t\tt.Assert(r.Val(), nil)\n\t\t//测试value != nil\n\t\tr.Set(&Student{3, \"jack\", true})\n\t})\n}\n\nfunc TestRing_CapLen(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(10)\n\t\tt.Assert(r.Cap(), 10)\n\t\tt.Assert(r.Len(), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(10)\n\t\tr.Put(\"goframe\")\n\t\t//cap长度 10\n\t\tt.Assert(r.Cap(), 10)\n\t\t//已有数据项 1\n\t\tt.Assert(r.Len(), 1)\n\t})\n}\n\nfunc TestRing_Position(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(2)\n\t\tr.Put(1)\n\t\tr.Put(2)\n\t\t//往后移动1个元素\n\t\tr.Next()\n\t\tt.Assert(r.Val(), 2)\n\t\t//往前移动1个元素\n\t\tr.Prev()\n\t\tt.Assert(r.Val(), 1)\n\n\t})\n}\n\nfunc TestRing_Link(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(3)\n\t\tr.Put(1)\n\t\tr.Put(2)\n\t\tr.Put(3)\n\t\ts := gring.New(2)\n\t\ts.Put(\"a\")\n\t\ts.Put(\"b\")\n\n\t\trs := r.Link(s)\n\t\tt.Assert(rs.Move(2).Val(), \"b\")\n\t})\n}\n\nfunc TestRing_Unlink(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(5)\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tr.Put(i)\n\t\t}\n\t\tt.Assert(r.Val(), 1)\n\t\t// 1 2 3 4\n\t\t// 删除当前位置往后的2个数据，返回被删除的数据\n\t\t// 重新计算s len\n\t\ts := r.Unlink(2) // 2 3\n\t\tt.Assert(s.Val(), 2)\n\t\tt.Assert(s.Len(), 2)\n\t})\n}\n\nfunc TestRing_Slice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tringLen := 5\n\t\tr := gring.New(ringLen)\n\t\tfor i := 0; i < ringLen; i++ {\n\t\t\tr.Put(i + 1)\n\t\t}\n\t\tr.Move(2)              // 3\n\t\tarray := r.SliceNext() // [3 4 5 1 2]\n\t\tt.Assert(array[0], 3)\n\t\tt.Assert(len(array), 5)\n\n\t\t//判断array是否等于[3 4 5 1 2]\n\t\tra := []int{3, 4, 5, 1, 2}\n\t\tt.Assert(ra, array)\n\n\t\t//第3个元素设为nil\n\t\tr.Set(nil)\n\t\tarray2 := r.SliceNext() //[4 5 1 2]\n\t\t//返回当前位置往后不为空的元素数组，长度为4\n\t\tt.Assert(array2, g.Slice{nil, 4, 5, 1, 2})\n\n\t\tarray3 := r.SlicePrev() //[2 1 5 4]\n\t\tt.Assert(array3, g.Slice{nil, 2, 1, 5, 4})\n\n\t\ts := gring.New(ringLen)\n\t\tfor i := 0; i < ringLen; i++ {\n\t\t\ts.Put(i + 1)\n\t\t}\n\t\tarray4 := s.SlicePrev() // []\n\t\tt.Assert(array4, g.Slice{1, 5, 4, 3, 2})\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1394\nfunc Test_Issue1394(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// gring.\n\t\tgRing := gring.New(10)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tgRing.Put(i)\n\t\t}\n\t\tgRingResult := gRing.Unlink(6)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.Log(gRing.Val())\n\t\t\tgRing = gRing.Next()\n\t\t}\n\n\t\t// stdring\n\t\tstdRing := ring.New(10)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tstdRing.Value = i\n\t\t\tstdRing = stdRing.Next()\n\t\t}\n\t\tstdRingResult := stdRing.Unlink(6)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.Log(stdRing.Value)\n\t\t\tstdRing = stdRing.Next()\n\t\t}\n\n\t\t// Assertion.\n\t\tt.Assert(gRing.Len(), stdRing.Len())\n\t\tt.Assert(gRingResult.Len(), stdRingResult.Len())\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.Assert(stdRing.Value, gRing.Val())\n\t\t\tstdRing = stdRing.Next()\n\t\t\tgRing = gRing.Next()\n\t\t}\n\t})\n\n}\n\nfunc TestRing_RLockIteratorNext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(10)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tr.Set(i).Next()\n\t\t}\n\n\t\titerVal := 0\n\t\tr.RLockIteratorNext(func(value any) bool {\n\t\t\tif value.(int) == 0 {\n\t\t\t\titerVal = value.(int)\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\n\t\tt.Assert(iterVal, 0)\n\t})\n}\n\nfunc TestRing_RLockIteratorPrev(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gring.New(10)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tr.Set(i).Next()\n\t\t}\n\n\t\titerVal := 0\n\t\tr.RLockIteratorPrev(func(value any) bool {\n\t\t\tif value.(int) == 0 {\n\t\t\t\titerVal = value.(int)\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\n\t\tt.Assert(iterVal, 0)\n\t})\n}\n"
  },
  {
    "path": "container/gset/gset_any_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gset provides kinds of concurrent-safe/unsafe sets.\npackage gset\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Set is consisted of any items.\ntype Set struct {\n\t*TSet[any]\n\tonce sync.Once\n}\n\n// New create and returns a new set, which contains un-repeated items.\n// The parameter `safe` is used to specify whether using set in concurrent-safety,\n// which is false in default.\nfunc New(safe ...bool) *Set {\n\treturn NewSet(safe...)\n}\n\n// NewSet create and returns a new set, which contains un-repeated items.\n// Also see New.\nfunc NewSet(safe ...bool) *Set {\n\treturn &Set{\n\t\tTSet: NewTSet[any](safe...),\n\t}\n}\n\n// NewFrom returns a new set from `items`.\n// Parameter `items` can be either a variable of any type, or a slice.\nfunc NewFrom(items any, safe ...bool) *Set {\n\treturn &Set{\n\t\tTSet: NewTSetFrom[any](gconv.Interfaces(items), safe...),\n\t}\n}\n\n// lazyInit lazily initializes the set.\nfunc (a *Set) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TSet == nil {\n\t\t\ta.TSet = NewTSet[any]()\n\t\t}\n\t})\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc (set *Set) Iterator(f func(v any) bool) {\n\tset.lazyInit()\n\tset.TSet.Iterator(f)\n}\n\n// Add adds one or multiple items to the set.\nfunc (set *Set) Add(items ...any) {\n\tset.lazyInit()\n\tset.TSet.Add(items...)\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set,\n// or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false.\nfunc (set *Set) AddIfNotExist(item any) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExist(item)\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false. The function `f`\n// is executed without writing lock.\nfunc (set *Set) AddIfNotExistFunc(item any, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFunc(item, f)\n}\n\n// AddIfNotExistFuncLock checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false. The function `f`\n// is executed within writing lock.\nfunc (set *Set) AddIfNotExistFuncLock(item any, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFuncLock(item, f)\n}\n\n// Contains checks whether the set contains `item`.\nfunc (set *Set) Contains(item any) bool {\n\tset.lazyInit()\n\treturn set.TSet.Contains(item)\n}\n\n// Remove deletes `item` from set.\nfunc (set *Set) Remove(item any) {\n\tset.lazyInit()\n\tset.TSet.Remove(item)\n}\n\n// Size returns the size of the set.\nfunc (set *Set) Size() int {\n\tset.lazyInit()\n\treturn set.TSet.Size()\n}\n\n// Clear deletes all items of the set.\nfunc (set *Set) Clear() {\n\tset.lazyInit()\n\tset.TSet.Clear()\n}\n\n// Slice returns all items of the set as slice.\nfunc (set *Set) Slice() []any {\n\tset.lazyInit()\n\treturn set.TSet.Slice()\n}\n\n// Join joins items with a string `glue`.\nfunc (set *Set) Join(glue string) string {\n\tset.lazyInit()\n\treturn set.TSet.Join(glue)\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc (set *Set) String() string {\n\tif set == nil {\n\t\treturn \"\"\n\t}\n\tset.lazyInit()\n\treturn set.TSet.String()\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc (set *Set) LockFunc(f func(m map[any]struct{})) {\n\tset.lazyInit()\n\tset.TSet.LockFunc(f)\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc (set *Set) RLockFunc(f func(m map[any]struct{})) {\n\tset.lazyInit()\n\tset.TSet.RLockFunc(f)\n}\n\n// Equal checks whether the two sets equal.\nfunc (set *Set) Equal(other *Set) bool {\n\tset.lazyInit()\n\tother.lazyInit()\n\treturn set.TSet.Equal(other.TSet)\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`.\nfunc (set *Set) IsSubsetOf(other *Set) bool {\n\tif set == other {\n\t\treturn true\n\t}\n\n\tset.lazyInit()\n\tother.lazyInit()\n\n\treturn set.TSet.IsSubsetOf(other.TSet)\n}\n\n// Union returns a new set which is the union of `set` and `others`.\n// Which means, all the items in `newSet` are in `set` or in `others`.\nfunc (set *Set) Union(others ...*Set) (newSet *Set) {\n\tset.lazyInit()\n\n\treturn &Set{\n\t\tTSet: set.TSet.Union(set.toTSetSlice(others)...),\n\t}\n}\n\n// Diff returns a new set which is the difference set from `set` to `others`.\n// Which means, all the items in `newSet` are in `set` but not in `others`.\nfunc (set *Set) Diff(others ...*Set) (newSet *Set) {\n\tset.lazyInit()\n\n\treturn &Set{\n\t\tTSet: set.TSet.Diff(set.toTSetSlice(others)...),\n\t}\n}\n\n// Intersect returns a new set which is the intersection from `set` to `others`.\n// Which means, all the items in `newSet` are in `set` and also in `others`.\nfunc (set *Set) Intersect(others ...*Set) (newSet *Set) {\n\tset.lazyInit()\n\treturn &Set{\n\t\tTSet: set.TSet.Intersect(set.toTSetSlice(others)...),\n\t}\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n//\n// It returns the difference between `full` and `set`\n// if the given set `full` is not the full set of `set`.\nfunc (set *Set) Complement(full *Set) (newSet *Set) {\n\tset.lazyInit()\n\tif full == nil {\n\t\treturn &Set{\n\t\t\tTSet: NewTSet[any](true),\n\t\t}\n\t}\n\tfull.lazyInit()\n\treturn &Set{\n\t\tTSet: set.TSet.Complement(full.TSet),\n\t}\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc (set *Set) Merge(others ...*Set) *Set {\n\tset.lazyInit()\n\tset.TSet.Merge(set.toTSetSlice(others)...)\n\treturn set\n}\n\n// Sum sums items.\n// Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc (set *Set) Sum() (sum int) {\n\tset.lazyInit()\n\treturn set.TSet.Sum()\n}\n\n// Pop randomly pops an item from set.\nfunc (set *Set) Pop() any {\n\tset.lazyInit()\n\treturn set.TSet.Pop()\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc (set *Set) Pops(size int) []any {\n\tset.lazyInit()\n\treturn set.TSet.Pops(size)\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc (set *Set) Walk(f func(item any) any) *Set {\n\tset.lazyInit()\n\tset.TSet.Walk(f)\n\treturn set\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (set Set) MarshalJSON() ([]byte, error) {\n\tset.lazyInit()\n\treturn set.TSet.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (set *Set) UnmarshalJSON(b []byte) error {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc (set *Set) UnmarshalValue(value any) (err error) {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (set *Set) DeepCopy() any {\n\tif set == nil {\n\t\treturn nil\n\t}\n\tset.lazyInit()\n\treturn &Set{\n\t\tTSet: set.TSet.DeepCopy().(*TSet[any]),\n\t}\n}\n\n// toTSetSlice converts []*Set to []*TSet[any]\nfunc (set *Set) toTSetSlice(sets []*Set) (tSets []*TSet[any]) {\n\ttSets = make([]*TSet[any], len(sets))\n\tfor i, v := range sets {\n\t\tif v == nil {\n\t\t\tcontinue\n\t\t}\n\t\tv.lazyInit()\n\t\ttSets[i] = v.TSet\n\t}\n\treturn\n}\n"
  },
  {
    "path": "container/gset/gset_int_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gset\n\nimport (\n\t\"sync\"\n)\n\n// IntSet is consisted of int items.\ntype IntSet struct {\n\t*TSet[int]\n\tonce sync.Once\n}\n\n// NewIntSet create and returns a new set, which contains un-repeated items.\n// The parameter `safe` is used to specify whether using set in concurrent-safety,\n// which is false in default.\nfunc NewIntSet(safe ...bool) *IntSet {\n\treturn &IntSet{\n\t\tTSet: NewTSet[int](safe...),\n\t}\n}\n\n// NewIntSetFrom returns a new set from `items`.\nfunc NewIntSetFrom(items []int, safe ...bool) *IntSet {\n\treturn &IntSet{\n\t\tTSet: NewTSetFrom(items, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the set.\nfunc (a *IntSet) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TSet == nil {\n\t\t\ta.TSet = NewTSet[int]()\n\t\t}\n\t})\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc (set *IntSet) Iterator(f func(v int) bool) {\n\tset.lazyInit()\n\tset.TSet.Iterator(f)\n}\n\n// Add adds one or multiple items to the set.\nfunc (set *IntSet) Add(item ...int) {\n\tset.lazyInit()\n\tset.TSet.Add(item...)\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set,\n// or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false.\nfunc (set *IntSet) AddIfNotExist(item int) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExist(item)\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, the function `f` is executed without writing lock.\nfunc (set *IntSet) AddIfNotExistFunc(item int, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFunc(item, f)\n}\n\n// AddIfNotExistFuncLock checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, the function `f` is executed without writing lock.\nfunc (set *IntSet) AddIfNotExistFuncLock(item int, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFuncLock(item, f)\n}\n\n// Contains checks whether the set contains `item`.\nfunc (set *IntSet) Contains(item int) bool {\n\tset.lazyInit()\n\treturn set.TSet.Contains(item)\n}\n\n// Remove deletes `item` from set.\nfunc (set *IntSet) Remove(item int) {\n\tset.lazyInit()\n\tset.TSet.Remove(item)\n}\n\n// Size returns the size of the set.\nfunc (set *IntSet) Size() int {\n\tset.lazyInit()\n\treturn set.TSet.Size()\n}\n\n// Clear deletes all items of the set.\nfunc (set *IntSet) Clear() {\n\tset.lazyInit()\n\tset.TSet.Clear()\n}\n\n// Slice returns the an of items of the set as slice.\nfunc (set *IntSet) Slice() []int {\n\tset.lazyInit()\n\treturn set.TSet.Slice()\n}\n\n// Join joins items with a string `glue`.\nfunc (set *IntSet) Join(glue string) string {\n\tset.lazyInit()\n\treturn set.TSet.Join(glue)\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc (set *IntSet) String() string {\n\tif set == nil {\n\t\treturn \"\"\n\t}\n\tset.lazyInit()\n\treturn set.TSet.String()\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc (set *IntSet) LockFunc(f func(m map[int]struct{})) {\n\tset.lazyInit()\n\tset.TSet.LockFunc(f)\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc (set *IntSet) RLockFunc(f func(m map[int]struct{})) {\n\tset.lazyInit()\n\tset.TSet.RLockFunc(f)\n}\n\n// Equal checks whether the two sets equal.\nfunc (set *IntSet) Equal(other *IntSet) bool {\n\tset.lazyInit()\n\tother.lazyInit()\n\treturn set.TSet.Equal(other.TSet)\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`.\nfunc (set *IntSet) IsSubsetOf(other *IntSet) bool {\n\tif set == other {\n\t\treturn true\n\t}\n\n\tset.lazyInit()\n\tother.lazyInit()\n\n\treturn set.TSet.IsSubsetOf(other.TSet)\n}\n\n// Union returns a new set which is the union of `set` and `other`.\n// Which means, all the items in `newSet` are in `set` or in `other`.\nfunc (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) {\n\tset.lazyInit()\n\treturn &IntSet{\n\t\tTSet: set.TSet.Union(set.toTSetSlice(others)...),\n\t}\n}\n\n// Diff returns a new set which is the difference set from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` but not in `other`.\nfunc (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) {\n\tset.lazyInit()\n\treturn &IntSet{\n\t\tTSet: set.TSet.Diff(set.toTSetSlice(others)...),\n\t}\n}\n\n// Intersect returns a new set which is the intersection from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` and also in `other`.\nfunc (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) {\n\tset.lazyInit()\n\treturn &IntSet{\n\t\tTSet: set.TSet.Intersect(set.toTSetSlice(others)...),\n\t}\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n//\n// It returns the difference between `full` and `set`\n// if the given set `full` is not the full set of `set`.\nfunc (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {\n\tset.lazyInit()\n\tif full == nil {\n\t\treturn &IntSet{\n\t\t\tTSet: NewTSet[int](),\n\t\t}\n\t}\n\tfull.lazyInit()\n\treturn &IntSet{\n\t\tTSet: set.TSet.Complement(full.TSet),\n\t}\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc (set *IntSet) Merge(others ...*IntSet) *IntSet {\n\tset.lazyInit()\n\tset.TSet.Merge(set.toTSetSlice(others)...)\n\treturn set\n}\n\n// Sum sums items.\n// Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc (set *IntSet) Sum() (sum int) {\n\tset.lazyInit()\n\treturn set.TSet.Sum()\n}\n\n// Pop randomly pops an item from set.\nfunc (set *IntSet) Pop() int {\n\tset.lazyInit()\n\treturn set.TSet.Pop()\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc (set *IntSet) Pops(size int) []int {\n\tset.lazyInit()\n\treturn set.TSet.Pops(size)\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc (set *IntSet) Walk(f func(item int) int) *IntSet {\n\tset.lazyInit()\n\tset.TSet.Walk(f)\n\treturn set\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (set IntSet) MarshalJSON() ([]byte, error) {\n\tset.lazyInit()\n\treturn set.TSet.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (set *IntSet) UnmarshalJSON(b []byte) error {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc (set *IntSet) UnmarshalValue(value any) (err error) {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (set *IntSet) DeepCopy() any {\n\tif set == nil {\n\t\treturn nil\n\t}\n\tset.lazyInit()\n\treturn &IntSet{\n\t\tTSet: set.TSet.DeepCopy().(*TSet[int]),\n\t}\n}\n\n// toTSetSlice converts []*IntSet to []*TSet[int]\nfunc (set *IntSet) toTSetSlice(sets []*IntSet) (tSets []*TSet[int]) {\n\ttSets = make([]*TSet[int], len(sets))\n\tfor i, v := range sets {\n\t\tif v == nil {\n\t\t\tcontinue\n\t\t}\n\t\tv.lazyInit()\n\t\ttSets[i] = v.TSet\n\t}\n\treturn\n}\n"
  },
  {
    "path": "container/gset/gset_str_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gset\n\nimport (\n\t\"strings\"\n\t\"sync\"\n)\n\n// StrSet is consisted of string items.\ntype StrSet struct {\n\t*TSet[string]\n\tonce sync.Once\n}\n\n// NewStrSet create and returns a new set, which contains un-repeated items.\n// The parameter `safe` is used to specify whether using set in concurrent-safety,\n// which is false in default.\nfunc NewStrSet(safe ...bool) *StrSet {\n\treturn &StrSet{\n\t\tTSet: NewTSet[string](safe...),\n\t}\n}\n\n// NewStrSetFrom returns a new set from `items`.\nfunc NewStrSetFrom(items []string, safe ...bool) *StrSet {\n\treturn &StrSet{\n\t\tTSet: NewTSetFrom(items, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the set.\nfunc (a *StrSet) lazyInit() {\n\ta.once.Do(func() {\n\t\tif a.TSet == nil {\n\t\t\ta.TSet = NewTSet[string]()\n\t\t}\n\t})\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc (set *StrSet) Iterator(f func(v string) bool) {\n\tset.lazyInit()\n\tset.TSet.Iterator(f)\n}\n\n// Add adds one or multiple items to the set.\nfunc (set *StrSet) Add(item ...string) {\n\tset.lazyInit()\n\tset.TSet.Add(item...)\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set,\n// or else it does nothing and returns false.\nfunc (set *StrSet) AddIfNotExist(item string) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExist(item)\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, the function `f` is executed without writing lock.\nfunc (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFunc(item, f)\n}\n\n// AddIfNotExistFuncLock checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, the function `f` is executed without writing lock.\nfunc (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool {\n\tset.lazyInit()\n\treturn set.TSet.AddIfNotExistFuncLock(item, f)\n}\n\n// Contains checks whether the set contains `item`.\nfunc (set *StrSet) Contains(item string) bool {\n\tset.lazyInit()\n\treturn set.TSet.Contains(item)\n}\n\n// ContainsI checks whether a value exists in the set with case-insensitively.\n// Note that it internally iterates the whole set to do the comparison with case-insensitively.\nfunc (set *StrSet) ContainsI(item string) bool {\n\tset.lazyInit()\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tfor k := range set.data {\n\t\tif strings.EqualFold(k, item) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Remove deletes `item` from set.\nfunc (set *StrSet) Remove(item string) {\n\tset.lazyInit()\n\tset.TSet.Remove(item)\n}\n\n// Size returns the size of the set.\nfunc (set *StrSet) Size() int {\n\tset.lazyInit()\n\treturn set.TSet.Size()\n}\n\n// Clear deletes all items of the set.\nfunc (set *StrSet) Clear() {\n\tset.lazyInit()\n\tset.TSet.Clear()\n}\n\n// Slice returns the an of items of the set as slice.\nfunc (set *StrSet) Slice() []string {\n\tset.lazyInit()\n\treturn set.TSet.Slice()\n}\n\n// Join joins items with a string `glue`.\nfunc (set *StrSet) Join(glue string) string {\n\tset.lazyInit()\n\treturn set.TSet.Join(glue)\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc (set *StrSet) String() string {\n\tif set == nil {\n\t\treturn \"\"\n\t}\n\tset.lazyInit()\n\treturn set.TSet.String()\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc (set *StrSet) LockFunc(f func(m map[string]struct{})) {\n\tset.lazyInit()\n\tset.TSet.LockFunc(f)\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc (set *StrSet) RLockFunc(f func(m map[string]struct{})) {\n\tset.lazyInit()\n\tset.TSet.RLockFunc(f)\n}\n\n// Equal checks whether the two sets equal.\nfunc (set *StrSet) Equal(other *StrSet) bool {\n\tset.lazyInit()\n\tother.lazyInit()\n\treturn set.TSet.Equal(other.TSet)\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`.\nfunc (set *StrSet) IsSubsetOf(other *StrSet) bool {\n\tif set == other {\n\t\treturn true\n\t}\n\n\tset.lazyInit()\n\tother.lazyInit()\n\n\treturn set.TSet.IsSubsetOf(other.TSet)\n}\n\n// Union returns a new set which is the union of `set` and `other`.\n// Which means, all the items in `newSet` are in `set` or in `other`.\nfunc (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {\n\tset.lazyInit()\n\treturn &StrSet{\n\t\tTSet: set.TSet.Union(set.toTSetSlice(others)...),\n\t}\n}\n\n// Diff returns a new set which is the difference set from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` but not in `other`.\nfunc (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {\n\tset.lazyInit()\n\treturn &StrSet{\n\t\tTSet: set.TSet.Diff(set.toTSetSlice(others)...),\n\t}\n}\n\n// Intersect returns a new set which is the intersection from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` and also in `other`.\nfunc (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {\n\tset.lazyInit()\n\treturn &StrSet{\n\t\tTSet: set.TSet.Intersect(set.toTSetSlice(others)...),\n\t}\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n//\n// It returns the difference between `full` and `set`\n// if the given set `full` is not the full set of `set`.\nfunc (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {\n\tset.lazyInit()\n\tif full == nil {\n\t\treturn &StrSet{\n\t\t\tTSet: NewTSet[string](),\n\t\t}\n\t}\n\tfull.lazyInit()\n\treturn &StrSet{\n\t\tTSet: set.TSet.Complement(full.TSet),\n\t}\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc (set *StrSet) Merge(others ...*StrSet) *StrSet {\n\tset.lazyInit()\n\tset.TSet.Merge(set.toTSetSlice(others)...)\n\treturn set\n}\n\n// Sum sums items.\n// Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc (set *StrSet) Sum() (sum int) {\n\tset.lazyInit()\n\treturn set.TSet.Sum()\n}\n\n// Pop randomly pops an item from set.\nfunc (set *StrSet) Pop() string {\n\tset.lazyInit()\n\treturn set.TSet.Pop()\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc (set *StrSet) Pops(size int) []string {\n\tset.lazyInit()\n\treturn set.TSet.Pops(size)\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc (set *StrSet) Walk(f func(item string) string) *StrSet {\n\tset.lazyInit()\n\tset.TSet.Walk(f)\n\treturn set\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (set StrSet) MarshalJSON() ([]byte, error) {\n\tset.lazyInit()\n\treturn set.TSet.MarshalJSON()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (set *StrSet) UnmarshalJSON(b []byte) error {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc (set *StrSet) UnmarshalValue(value any) (err error) {\n\tset.lazyInit()\n\treturn set.TSet.UnmarshalValue(value)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (set *StrSet) DeepCopy() any {\n\tif set == nil {\n\t\treturn nil\n\t}\n\tset.lazyInit()\n\treturn &StrSet{\n\t\tTSet: set.TSet.DeepCopy().(*TSet[string]),\n\t}\n}\n\n// toTSetSlice converts []*StrSet to []*TSet[string]\nfunc (set *StrSet) toTSetSlice(sets []*StrSet) (tSets []*TSet[string]) {\n\ttSets = make([]*TSet[string], len(sets))\n\tfor i, v := range sets {\n\t\tif v == nil {\n\t\t\tcontinue\n\t\t}\n\t\tv.lazyInit()\n\t\ttSets[i] = v.TSet\n\t}\n\treturn\n}\n"
  },
  {
    "path": "container/gset/gset_t_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gset\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// NilChecker is a function that checks whether the given value is nil.\ntype NilChecker[T any] func(T) bool\n\n// TSet[T] is consisted of any items.\ntype TSet[T comparable] struct {\n\tmu         rwmutex.RWMutex\n\tdata       map[T]struct{}\n\tnilChecker NilChecker[T]\n}\n\n// NewTSet creates and returns a new set, which contains un-repeated items.\n// Also see New.\nfunc NewTSet[T comparable](safe ...bool) *TSet[T] {\n\treturn &TSet[T]{\n\t\tdata: make(map[T]struct{}),\n\t\tmu:   rwmutex.Create(safe...),\n\t}\n}\n\n// NewTSetWithChecker creates and returns a new set with a custom nil checker.\n// The parameter `nilChecker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether using set in concurrent-safety mode.\nfunc NewTSetWithChecker[T comparable](checker NilChecker[T], safe ...bool) *TSet[T] {\n\ts := NewTSet[T](safe...)\n\ts.SetNilChecker(checker)\n\treturn s\n}\n\n// NewTSetFrom returns a new set from `items`.\n// `items` - A slice of type T.\nfunc NewTSetFrom[T comparable](items []T, safe ...bool) *TSet[T] {\n\tm := make(map[T]struct{})\n\tfor _, v := range items {\n\t\tm[v] = struct{}{}\n\t}\n\treturn &TSet[T]{\n\t\tdata: m,\n\t\tmu:   rwmutex.Create(safe...),\n\t}\n}\n\n// NewTSetWithCheckerFrom returns a new set from `items` with a custom nil checker.\n// The parameter `items` is a slice of elements to be added to the set.\n// The parameter `checker` is a function used to determine if a value is nil.\n// The parameter `safe` is used to specify whether using set in concurrent-safety mode.\nfunc NewTSetWithCheckerFrom[T comparable](items []T, checker NilChecker[T], safe ...bool) *TSet[T] {\n\tset := NewTSetWithChecker[T](checker, safe...)\n\tset.Add(items...)\n\treturn set\n}\n\n// SetNilChecker registers a custom nil checker function for the set elements.\n// This function is used to determine if an element should be considered as nil.\n// The nil checker function takes an element of type T and returns a boolean indicating\n// whether the element should be treated as nil.\nfunc (set *TSet[T]) SetNilChecker(nilChecker NilChecker[T]) {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tset.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (set *TSet[T]) isNil(v T) bool {\n\tif set.nilChecker != nil {\n\t\treturn set.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc (set *TSet[T]) Iterator(f func(v T) bool) {\n\tfor _, k := range set.Slice() {\n\t\tif !f(k) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// Add adds one or multiple items to the set.\nfunc (set *TSet[T]) Add(items ...T) {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tif set.data == nil {\n\t\tset.data = make(map[T]struct{})\n\t}\n\tfor _, v := range items {\n\t\tset.data[v] = struct{}{}\n\t}\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set,\n// or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false.\nfunc (set *TSet[T]) AddIfNotExist(item T) bool {\n\tif set.isNil(item) {\n\t\treturn false\n\t}\n\tif !set.Contains(item) {\n\t\tset.mu.Lock()\n\t\tdefer set.mu.Unlock()\n\t\tif set.data == nil {\n\t\t\tset.data = make(map[T]struct{})\n\t\t}\n\t\tif _, ok := set.data[item]; !ok {\n\t\t\tset.data[item] = struct{}{}\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false. The function `f`\n// is executed without writing lock.\nfunc (set *TSet[T]) AddIfNotExistFunc(item T, f func() bool) bool {\n\tif set.isNil(item) {\n\t\treturn false\n\t}\n\tif !set.Contains(item) {\n\t\tif f() {\n\t\t\tset.mu.Lock()\n\t\t\tdefer set.mu.Unlock()\n\t\t\tif set.data == nil {\n\t\t\t\tset.data = make(map[T]struct{})\n\t\t\t}\n\t\t\tif _, ok := set.data[item]; !ok {\n\t\t\t\tset.data[item] = struct{}{}\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// AddIfNotExistFuncLock checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and\n// function `f` returns true, or else it does nothing and returns false.\n//\n// Note that, if `item` is nil, it does nothing and returns false. The function `f`\n// is executed within writing lock.\nfunc (set *TSet[T]) AddIfNotExistFuncLock(item T, f func() bool) bool {\n\tif set.isNil(item) {\n\t\treturn false\n\t}\n\tif !set.Contains(item) {\n\t\tset.mu.Lock()\n\t\tdefer set.mu.Unlock()\n\t\tif set.data == nil {\n\t\t\tset.data = make(map[T]struct{})\n\t\t}\n\t\tif f() {\n\t\t\tif _, ok := set.data[item]; !ok {\n\t\t\t\tset.data[item] = struct{}{}\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// Contains checks whether the set contains `item`.\nfunc (set *TSet[T]) Contains(item T) bool {\n\tvar ok bool\n\tset.mu.RLock()\n\tif set.data != nil {\n\t\t_, ok = set.data[item]\n\t}\n\tset.mu.RUnlock()\n\treturn ok\n}\n\n// Remove deletes `item` from set.\nfunc (set *TSet[T]) Remove(item T) {\n\tset.mu.Lock()\n\tif set.data != nil {\n\t\tdelete(set.data, item)\n\t}\n\tset.mu.Unlock()\n}\n\n// Size returns the size of the set.\nfunc (set *TSet[T]) Size() int {\n\tset.mu.RLock()\n\tl := len(set.data)\n\tset.mu.RUnlock()\n\treturn l\n}\n\n// Clear deletes all items of the set.\nfunc (set *TSet[T]) Clear() {\n\tset.mu.Lock()\n\tset.data = make(map[T]struct{})\n\tset.mu.Unlock()\n}\n\n// Slice returns all items of the set as slice.\nfunc (set *TSet[T]) Slice() []T {\n\tset.mu.RLock()\n\tvar (\n\t\ti   = 0\n\t\tret = make([]T, len(set.data))\n\t)\n\tfor item := range set.data {\n\t\tret[i] = item\n\t\ti++\n\t}\n\tset.mu.RUnlock()\n\treturn ret\n}\n\n// Join joins items with a string `glue`.\nfunc (set *TSet[T]) Join(glue string) string {\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tif len(set.data) == 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tl      = len(set.data)\n\t\ti      = 0\n\t\tbuffer = bytes.NewBuffer(nil)\n\t)\n\tfor k := range set.data {\n\t\tbuffer.WriteString(gconv.String(k))\n\t\tif i != l-1 {\n\t\t\tbuffer.WriteString(glue)\n\t\t}\n\t\ti++\n\t}\n\treturn buffer.String()\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc (set *TSet[T]) String() string {\n\tif set == nil {\n\t\treturn \"\"\n\t}\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tvar (\n\t\ts      string\n\t\tl      = len(set.data)\n\t\ti      = 0\n\t\tbuffer = bytes.NewBuffer(nil)\n\t)\n\tbuffer.WriteByte('[')\n\tfor k := range set.data {\n\t\ts = gconv.String(k)\n\t\tif gstr.IsNumeric(s) {\n\t\t\tbuffer.WriteString(s)\n\t\t} else {\n\t\t\tbuffer.WriteString(`\"` + gstr.QuoteMeta(s, `\"\\`) + `\"`)\n\t\t}\n\t\tif i != l-1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t\ti++\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.String()\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc (set *TSet[T]) LockFunc(f func(m map[T]struct{})) {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tf(set.data)\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc (set *TSet[T]) RLockFunc(f func(m map[T]struct{})) {\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tf(set.data)\n}\n\n// Equal checks whether the two sets equal.\nfunc (set *TSet[T]) Equal(other *TSet[T]) bool {\n\tif set == other {\n\t\treturn true\n\t}\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tother.mu.RLock()\n\tdefer other.mu.RUnlock()\n\tif len(set.data) != len(other.data) {\n\t\treturn false\n\t}\n\tfor key := range set.data {\n\t\tif _, ok := other.data[key]; !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`.\nfunc (set *TSet[T]) IsSubsetOf(other *TSet[T]) bool {\n\tif set == other {\n\t\treturn true\n\t}\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tother.mu.RLock()\n\tdefer other.mu.RUnlock()\n\tfor key := range set.data {\n\t\tif _, ok := other.data[key]; !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Union returns a new set which is the union of `set` and `others`.\n// Which means, all the items in `newSet` are in `set` or in `others`.\nfunc (set *TSet[T]) Union(others ...*TSet[T]) (newSet *TSet[T]) {\n\tnewSet = NewTSet[T]()\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tfor _, other := range others {\n\t\tif other == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RLock()\n\t\t}\n\t\tfor k, v := range set.data {\n\t\t\tnewSet.data[k] = v\n\t\t}\n\t\tif set != other {\n\t\t\tfor k, v := range other.data {\n\t\t\t\tnewSet.data[k] = v\n\t\t\t}\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RUnlock()\n\t\t}\n\t}\n\n\treturn\n}\n\n// Diff returns a new set which is the difference set from `set` to `others`.\n// Which means, all the items in `newSet` are in `set` but not in `others`.\nfunc (set *TSet[T]) Diff(others ...*TSet[T]) (newSet *TSet[T]) {\n\tnewSet = NewTSet[T]()\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tfor _, other := range others {\n\t\tif other == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif set == other {\n\t\t\tcontinue\n\t\t}\n\t\tother.mu.RLock()\n\t\tfor k, v := range set.data {\n\t\t\tif _, ok := other.data[k]; !ok {\n\t\t\t\tnewSet.data[k] = v\n\t\t\t}\n\t\t}\n\t\tother.mu.RUnlock()\n\t}\n\treturn\n}\n\n// Intersect returns a new set which is the intersection from `set` to `others`.\n// Which means, all the items in `newSet` are in `set` and also in `others`.\nfunc (set *TSet[T]) Intersect(others ...*TSet[T]) (newSet *TSet[T]) {\n\tnewSet = NewTSet[T]()\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tfor _, other := range others {\n\t\tif other == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RLock()\n\t\t}\n\t\tfor k, v := range set.data {\n\t\t\tif _, ok := other.data[k]; ok {\n\t\t\t\tnewSet.data[k] = v\n\t\t\t}\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RUnlock()\n\t\t}\n\t}\n\treturn\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n//\n// It returns the difference between `full` and `set`\n// if the given set `full` is not the full set of `set`.\nfunc (set *TSet[T]) Complement(full *TSet[T]) (newSet *TSet[T]) {\n\tnewSet = NewTSet[T]()\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tif set != full {\n\t\tfull.mu.RLock()\n\t\tdefer full.mu.RUnlock()\n\t}\n\tfor k, v := range full.data {\n\t\tif _, ok := set.data[k]; !ok {\n\t\t\tnewSet.data[k] = v\n\t\t}\n\t}\n\treturn\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc (set *TSet[T]) Merge(others ...*TSet[T]) *TSet[T] {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tfor _, other := range others {\n\t\tif other == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RLock()\n\t\t}\n\t\tfor k, v := range other.data {\n\t\t\tset.data[k] = v\n\t\t}\n\t\tif set != other {\n\t\t\tother.mu.RUnlock()\n\t\t}\n\t}\n\treturn set\n}\n\n// Sum sums items.\n// Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc (set *TSet[T]) Sum() (sum int) {\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tfor k := range set.data {\n\t\tsum += gconv.Int(k)\n\t}\n\treturn\n}\n\n// Pop randomly pops an item from set.\nfunc (set *TSet[T]) Pop() (item T) {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tfor k := range set.data {\n\t\tdelete(set.data, k)\n\t\treturn k\n\t}\n\treturn\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc (set *TSet[T]) Pops(size int) []T {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tif size > len(set.data) || size == -1 {\n\t\tsize = len(set.data)\n\t}\n\tif size <= 0 {\n\t\treturn nil\n\t}\n\tindex := 0\n\tarray := make([]T, size)\n\tfor k := range set.data {\n\t\tdelete(set.data, k)\n\t\tarray[index] = k\n\t\tindex++\n\t\tif index == size {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn array\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc (set *TSet[T]) Walk(f func(item T) T) *TSet[T] {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tm := make(map[T]struct{}, len(set.data))\n\tfor k, v := range set.data {\n\t\tm[f(k)] = v\n\t}\n\tset.data = m\n\treturn set\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (set TSet[T]) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(set.Slice())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (set *TSet[T]) UnmarshalJSON(b []byte) error {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tif set.data == nil {\n\t\tset.data = make(map[T]struct{})\n\t}\n\tvar array []T\n\tif err := json.UnmarshalUseNumber(b, &array); err != nil {\n\t\treturn err\n\t}\n\tfor _, v := range array {\n\t\tset.data[v] = struct{}{}\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc (set *TSet[T]) UnmarshalValue(value any) (err error) {\n\tset.mu.Lock()\n\tdefer set.mu.Unlock()\n\tif set.data == nil {\n\t\tset.data = make(map[T]struct{})\n\t}\n\tvar array []T\n\tswitch value.(type) {\n\tcase string, []byte:\n\t\terr = json.UnmarshalUseNumber(gconv.Bytes(value), &array)\n\tdefault:\n\t\tif err = gconv.Scan(value, &array); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tfor _, v := range array {\n\t\tset.data[v] = struct{}{}\n\t}\n\treturn\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (set *TSet[T]) DeepCopy() any {\n\tif set == nil {\n\t\treturn nil\n\t}\n\tset.mu.RLock()\n\tdefer set.mu.RUnlock()\n\tdata := make([]T, 0)\n\tfor k := range set.data {\n\t\tdata = append(data, k)\n\t}\n\treturn NewTSetFrom[T](data, set.mu.IsSafe())\n}\n"
  },
  {
    "path": "container/gset/gset_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gset_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n)\n\nvar intSet = gset.NewIntSet(true)\n\nvar anySet = gset.NewSet(true)\n\nvar strSet = gset.NewStrSet(true)\n\nvar intSetUnsafe = gset.NewIntSet()\n\nvar anySetUnsafe = gset.NewSet()\n\nvar strSetUnsafe = gset.NewStrSet()\n\nfunc Benchmark_IntSet_Add(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintSet.Add(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntSet_Contains(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintSet.Contains(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_IntSet_Remove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tintSet.Remove(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_AnySet_Add(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tanySet.Add(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_AnySet_Contains(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tanySet.Contains(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_AnySet_Remove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tanySet.Remove(i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrSet_Add(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrSet.Add(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrSet_Contains(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrSet.Contains(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_StrSet_Remove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tstrSet.Remove(strconv.Itoa(i))\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_Unsafe_IntSet_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintSetUnsafe.Add(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntSet_Contains(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintSetUnsafe.Contains(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_IntSet_Remove(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tintSetUnsafe.Remove(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_AnySet_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanySetUnsafe.Add(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_AnySet_Contains(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanySetUnsafe.Contains(i)\n\t}\n}\n\nfunc Benchmark_Unsafe_AnySet_Remove(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tanySetUnsafe.Remove(i)\n\t}\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_Unsafe_StrSet_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrSetUnsafe.Add(strconv.Itoa(i))\n\t}\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_Unsafe_StrSet_Contains(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrSetUnsafe.Contains(strconv.Itoa(i))\n\t}\n}\n\n// Note that there's additional performance cost for string conversion.\nfunc Benchmark_Unsafe_StrSet_Remove(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstrSetUnsafe.Remove(strconv.Itoa(i))\n\t}\n}\n"
  },
  {
    "path": "container/gset/gset_z_example_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gset_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\nfunc ExampleSet_Intersect() {\n\ts1 := gset.NewFrom(g.Slice{1, 2, 3})\n\ts2 := gset.NewFrom(g.Slice{4, 5, 6})\n\ts3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})\n\n\tfmt.Println(s3.Intersect(s1).Slice())\n\tfmt.Println(s3.Diff(s1).Slice())\n\tfmt.Println(s1.Union(s2).Slice())\n\tfmt.Println(s1.Complement(s3).Slice())\n\n\t// May Output:\n\t// [2 3 1]\n\t// [5 6 7 4]\n\t// [6 1 2 3 4 5]\n\t// [4 5 6 7]\n}\n\nfunc ExampleSet_Diff() {\n\ts1 := gset.NewFrom(g.Slice{1, 2, 3})\n\ts2 := gset.NewFrom(g.Slice{4, 5, 6})\n\ts3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})\n\n\tfmt.Println(s3.Intersect(s1).Slice())\n\tfmt.Println(s3.Diff(s1).Slice())\n\tfmt.Println(s1.Union(s2).Slice())\n\tfmt.Println(s1.Complement(s3).Slice())\n\n\t// May Output:\n\t// [2 3 1]\n\t// [5 6 7 4]\n\t// [6 1 2 3 4 5]\n\t// [4 5 6 7]\n}\n\nfunc ExampleSet_Union() {\n\ts1 := gset.NewFrom(g.Slice{1, 2, 3})\n\ts2 := gset.NewFrom(g.Slice{4, 5, 6})\n\ts3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})\n\n\tfmt.Println(s3.Intersect(s1).Slice())\n\tfmt.Println(s3.Diff(s1).Slice())\n\tfmt.Println(s1.Union(s2).Slice())\n\tfmt.Println(s1.Complement(s3).Slice())\n\n\t// May Output:\n\t// [2 3 1]\n\t// [5 6 7 4]\n\t// [6 1 2 3 4 5]\n\t// [4 5 6 7]\n}\n\nfunc ExampleSet_Complement() {\n\ts1 := gset.NewFrom(g.Slice{1, 2, 3})\n\ts2 := gset.NewFrom(g.Slice{4, 5, 6})\n\ts3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})\n\n\tfmt.Println(s3.Intersect(s1).Slice())\n\tfmt.Println(s3.Diff(s1).Slice())\n\tfmt.Println(s1.Union(s2).Slice())\n\tfmt.Println(s1.Complement(s3).Slice())\n\n\t// May Output:\n\t// [2 3 1]\n\t// [5 6 7 4]\n\t// [6 1 2 3 4 5]\n\t// [4 5 6 7]\n}\n\nfunc ExampleSet_IsSubsetOf() {\n\tvar s1, s2 gset.Set\n\ts1.Add(g.Slice{1, 2, 3}...)\n\ts2.Add(g.Slice{2, 3}...)\n\tfmt.Println(s1.IsSubsetOf(&s2))\n\tfmt.Println(s2.IsSubsetOf(&s1))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleSet_AddIfNotExist() {\n\tvar set gset.Set\n\tfmt.Println(set.AddIfNotExist(1))\n\tfmt.Println(set.AddIfNotExist(1))\n\tfmt.Println(set.Slice())\n\n\t// Output:\n\t// true\n\t// false\n\t// [1]\n}\n\nfunc ExampleSet_Pop() {\n\tvar set gset.Set\n\tset.Add(1, 2, 3, 4)\n\tfmt.Println(set.Pop())\n\tfmt.Println(set.Pops(2))\n\tfmt.Println(set.Size())\n\n\t// May Output:\n\t// 1\n\t// [2 3]\n\t// 1\n}\n\nfunc ExampleSet_Pops() {\n\tvar set gset.Set\n\tset.Add(1, 2, 3, 4)\n\tfmt.Println(set.Pop())\n\tfmt.Println(set.Pops(2))\n\tfmt.Println(set.Size())\n\n\t// May Output:\n\t// 1\n\t// [2 3]\n\t// 1\n}\n\nfunc ExampleSet_Join() {\n\tvar set gset.Set\n\tset.Add(\"a\", \"b\", \"c\", \"d\")\n\tfmt.Println(set.Join(\",\"))\n\n\t// May Output:\n\t// a,b,c,d\n}\n\nfunc ExampleSet_Contains() {\n\tvar set gset.StrSet\n\tset.Add(\"a\")\n\tfmt.Println(set.Contains(\"a\"))\n\tfmt.Println(set.Contains(\"A\"))\n\tfmt.Println(set.ContainsI(\"A\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// true\n}\n\nfunc ExampleSet_containsI() {\n\tvar set gset.StrSet\n\tset.Add(\"a\")\n\tfmt.Println(set.Contains(\"a\"))\n\tfmt.Println(set.Contains(\"A\"))\n\tfmt.Println(set.ContainsI(\"A\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "container/gset/gset_z_example_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gset_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// New create and returns a new set, which contains un-repeated items.\n// The parameter `safe` is used to specify whether using set in concurrent-safety,\n// which is false in default.\nfunc ExampleNewIntSet() {\n\tintSet := gset.NewIntSet()\n\tintSet.Add([]int{1, 2, 3}...)\n\tfmt.Println(intSet.Slice())\n\n\t// May Output:\n\t// [2 1 3]\n}\n\n// NewIntSetFrom  returns a new set from `items`.\nfunc ExampleNewFrom() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tfmt.Println(intSet.Slice())\n\n\t// May Output:\n\t// [2 1 3]\n}\n\n// Add adds one or multiple items to the set.\nfunc ExampleIntSet_Add() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tintSet.Add(1)\n\tfmt.Println(intSet.Slice())\n\tfmt.Println(intSet.AddIfNotExist(1))\n\n\t// May Output:\n\t// [1 2 3]\n\t// false\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set,\n// or else it does nothing and returns false.\nfunc ExampleIntSet_AddIfNotExist() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tintSet.Add(1)\n\tfmt.Println(intSet.Slice())\n\tfmt.Println(intSet.AddIfNotExist(1))\n\n\t// May Output:\n\t// [1 2 3]\n\t// false\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,\n// or else it does nothing and returns false.\n// Note that, the function `f` is executed without writing lock.\nfunc ExampleIntSet_AddIfNotExistFunc() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tintSet.Add(1)\n\tfmt.Println(intSet.Slice())\n\tfmt.Println(intSet.AddIfNotExistFunc(5, func() bool {\n\t\treturn true\n\t}))\n\n\t// May Output:\n\t// [1 2 3]\n\t// true\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,\n// or else it does nothing and returns false.\n// Note that, the function `f` is executed without writing lock.\nfunc ExampleIntSet_AddIfNotExistFuncLock() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tintSet.Add(1)\n\tfmt.Println(intSet.Slice())\n\tfmt.Println(intSet.AddIfNotExistFuncLock(4, func() bool {\n\t\treturn true\n\t}))\n\n\t// May Output:\n\t// [1 2 3]\n\t// true\n}\n\n// Clear deletes all items of the set.\nfunc ExampleIntSet_Clear() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3})\n\tfmt.Println(intSet.Size())\n\tintSet.Clear()\n\tfmt.Println(intSet.Size())\n\n\t// Output:\n\t// 3\n\t// 0\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`.\nfunc ExampleIntSet_Complement() {\n\tintSet := gset.NewIntSetFrom([]int{1, 2, 3, 4, 5})\n\ts := gset.NewIntSetFrom([]int{1, 2, 3})\n\tfmt.Println(s.Complement(intSet).Slice())\n\n\t// May Output:\n\t// [4 5]\n}\n\n// Contains checks whether the set contains `item`.\nfunc ExampleIntSet_Contains() {\n\tvar set1 gset.IntSet\n\tset1.Add(1, 4, 5, 6, 7)\n\tfmt.Println(set1.Contains(1))\n\n\tvar set2 gset.IntSet\n\tset2.Add(1, 4, 5, 6, 7)\n\tfmt.Println(set2.Contains(8))\n\n\t// Output:\n\t// true\n\t// false\n}\n\n// Diff returns a new set which is the difference set from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` but not in `other`.\nfunc ExampleIntSet_Diff() {\n\ts1 := gset.NewIntSetFrom([]int{1, 2, 3})\n\ts2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})\n\tfmt.Println(s2.Diff(s1).Slice())\n\n\t// Output:\n\t// [4]\n}\n\n// Equal checks whether the two sets equal.\nfunc ExampleIntSet_Equal() {\n\ts1 := gset.NewIntSetFrom([]int{1, 2, 3})\n\ts2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})\n\tfmt.Println(s2.Equal(s1))\n\n\ts3 := gset.NewIntSetFrom([]int{1, 2, 3})\n\ts4 := gset.NewIntSetFrom([]int{1, 2, 3})\n\tfmt.Println(s3.Equal(s4))\n\n\t// Output:\n\t// false\n\t// true\n}\n\n// Intersect returns a new set which is the intersection from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` and also in `other`.\nfunc ExampleIntSet_Intersect() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3}...)\n\tvar s2 gset.IntSet\n\ts2.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s2.Intersect(s1).Slice())\n\n\t// May Output:\n\t// [1 2 3]\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`\nfunc ExampleIntSet_IsSubsetOf() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tvar s2 gset.IntSet\n\ts2.Add([]int{1, 2, 4}...)\n\tfmt.Println(s2.IsSubsetOf(s1))\n\n\t// Output:\n\t// true\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc ExampleIntSet_Iterator() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\ts1.Iterator(func(v int) bool {\n\t\tfmt.Println(\"Iterator\", v)\n\t\treturn true\n\t})\n\t// May Output:\n\t// Iterator 2\n\t// Iterator 3\n\t// Iterator 1\n\t// Iterator 4\n}\n\n// Join joins items with a string `glue`.\nfunc ExampleIntSet_Join() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s1.Join(\",\"))\n\n\t// May Output:\n\t// 3,4,1,2\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc ExampleIntSet_LockFunc() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2}...)\n\ts1.LockFunc(func(m map[int]struct{}) {\n\t\tm[3] = struct{}{}\n\t})\n\tfmt.Println(s1.Slice())\n\n\t// May Output\n\t// [2 3 1]\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc ExampleIntSet_MarshalJSON() {\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.IntSet\n\t}\n\ts := Student{\n\t\tId:     1,\n\t\tName:   \"john\",\n\t\tScores: gset.NewIntSetFrom([]int{100, 99, 98}),\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// May Output:\n\t// {\"Id\":1,\"Name\":\"john\",\"Scores\":[100,99,98]}\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc ExampleIntSet_Merge() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\n\ts2 := gset.NewIntSet()\n\tfmt.Println(s1.Merge(s2).Slice())\n\n\t// May Output:\n\t// [1 2 3 4]\n}\n\n// Pops randomly pops an item from set.\nfunc ExampleIntSet_Pop() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\n\tfmt.Println(s1.Pop())\n\n\t// May Output:\n\t// 1\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc ExampleIntSet_Pops() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfor _, v := range s1.Pops(2) {\n\t\tfmt.Println(v)\n\t}\n\n\t// May Output:\n\t// 1\n\t// 2\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc ExampleIntSet_RLockFunc() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\ts1.RLockFunc(func(m map[int]struct{}) {\n\t\tfmt.Println(m)\n\t})\n\n\t// Output:\n\t// map[1:{} 2:{} 3:{} 4:{}]\n}\n\n// Remove deletes `item` from set.\nfunc ExampleIntSet_Remove() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\ts1.Remove(1)\n\tfmt.Println(s1.Slice())\n\n\t// May Output:\n\t// [3 4 2]\n}\n\n// Size returns the size of the set.\nfunc ExampleIntSet_Size() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s1.Size())\n\n\t// Output:\n\t// 4\n}\n\n// Slice returns the an of items of the set as slice.\nfunc ExampleIntSet_Slice() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s1.Slice())\n\n\t// May Output:\n\t// [1, 2, 3, 4]\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc ExampleIntSet_String() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s1.String())\n\n\t// May Output:\n\t// [1,2,3,4]\n}\n\n// Sum sums items. Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc ExampleIntSet_Sum() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\tfmt.Println(s1.Sum())\n\n\t// Output:\n\t// 10\n}\n\n// Union returns a new set which is the union of `set` and `other`.\n// Which means, all the items in `newSet` are in `set` or in `other`.\nfunc ExampleIntSet_Union() {\n\ts1 := gset.NewIntSet()\n\ts1.Add([]int{1, 2, 3, 4}...)\n\ts2 := gset.NewIntSet()\n\ts2.Add([]int{1, 2, 4}...)\n\tfmt.Println(s1.Union(s2).Slice())\n\n\t// May Output:\n\t// [3 4 1 2]\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc ExampleIntSet_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":[100,99,98]}`)\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.IntSet\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// {1 john [100,99,98]}\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc ExampleIntSet_UnmarshalValue() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":100,99,98}`)\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.IntSet\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// {1 john [100,99,98]}\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc ExampleIntSet_Walk() {\n\tvar (\n\t\tset   gset.IntSet\n\t\tnames = g.SliceInt{1, 0}\n\t\tdelta = 10\n\t)\n\tset.Add(names...)\n\t// Add prefix for given table names.\n\tset.Walk(func(item int) int {\n\t\treturn delta + item\n\t})\n\tfmt.Println(set.Slice())\n\n\t// May Output:\n\t// [12 60]\n}\n"
  },
  {
    "path": "container/gset/gset_z_example_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gset_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// NewStrSet create and returns a new set, which contains un-repeated items.\n// The parameter `safe` is used to specify whether using set in concurrent-safety,\n// which is false in default.\nfunc ExampleNewStrSet() {\n\tstrSet := gset.NewStrSet(true)\n\tstrSet.Add([]string{\"str1\", \"str2\", \"str3\"}...)\n\tfmt.Println(strSet.Slice())\n\n\t// May Output:\n\t// [str3 str1 str2]\n}\n\n// NewStrSetFrom returns a new set from `items`.\nfunc ExampleNewStrSetFrom() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tfmt.Println(strSet.Slice())\n\n\t// May Output:\n\t// [str1 str2 str3]\n}\n\n// Add adds one or multiple items to the set.\nfunc ExampleStrSet_Add() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tstrSet.Add(\"str\")\n\tfmt.Println(strSet.Slice())\n\tfmt.Println(strSet.AddIfNotExist(\"str\"))\n\n\t// May Output:\n\t// [str str1 str2 str3]\n\t// false\n}\n\n// AddIfNotExist checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set,\n// or else it does nothing and returns false.\nfunc ExampleStrSet_AddIfNotExist() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tstrSet.Add(\"str\")\n\tfmt.Println(strSet.Slice())\n\tfmt.Println(strSet.AddIfNotExist(\"str\"))\n\n\t// May Output:\n\t// [str str1 str2 str3]\n\t// false\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set and function `f` returns true,\n// or else it does nothing and returns false.\n// Note that, the function `f` is executed without writing lock.\nfunc ExampleStrSet_AddIfNotExistFunc() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tstrSet.Add(\"str\")\n\tfmt.Println(strSet.Slice())\n\tfmt.Println(strSet.AddIfNotExistFunc(\"str5\", func() bool {\n\t\treturn true\n\t}))\n\n\t// May Output:\n\t// [str1 str2 str3 str]\n\t// true\n}\n\n// AddIfNotExistFunc checks whether item exists in the set,\n// it adds the item to set and returns true if it does not exist in the set and function `f` returns true,\n// or else it does nothing and returns false.\n// Note that, the function `f` is executed without writing lock.\nfunc ExampleStrSet_AddIfNotExistFuncLock() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tstrSet.Add(\"str\")\n\tfmt.Println(strSet.Slice())\n\tfmt.Println(strSet.AddIfNotExistFuncLock(\"str4\", func() bool {\n\t\treturn true\n\t}))\n\n\t// May Output:\n\t// [str1 str2 str3 str]\n\t// true\n}\n\n// Clear deletes all items of the set.\nfunc ExampleStrSet_Clear() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tfmt.Println(strSet.Size())\n\tstrSet.Clear()\n\tfmt.Println(strSet.Size())\n\n\t// Output:\n\t// 3\n\t// 0\n}\n\n// Complement returns a new set which is the complement from `set` to `full`.\n// Which means, all the items in `newSet` are in `full` and not in `set`.\n// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`.\nfunc ExampleStrSet_Complement() {\n\tstrSet := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\", \"str4\", \"str5\"}, true)\n\ts := gset.NewStrSetFrom([]string{\"str1\", \"str2\", \"str3\"}, true)\n\tfmt.Println(s.Complement(strSet).Slice())\n\n\t// May Output:\n\t// [str4 str5]\n}\n\n// Contains checks whether the set contains `item`.\nfunc ExampleStrSet_Contains() {\n\tvar set gset.StrSet\n\tset.Add(\"a\")\n\tfmt.Println(set.Contains(\"a\"))\n\tfmt.Println(set.Contains(\"A\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\n// ContainsI checks whether a value exists in the set with case-insensitively.\n// Note that it internally iterates the whole set to do the comparison with case-insensitively.\nfunc ExampleStrSet_ContainsI() {\n\tvar set gset.StrSet\n\tset.Add(\"a\")\n\tfmt.Println(set.ContainsI(\"a\"))\n\tfmt.Println(set.ContainsI(\"A\"))\n\n\t// Output:\n\t// true\n\t// true\n}\n\n// Diff returns a new set which is the difference set from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` but not in `other`.\nfunc ExampleStrSet_Diff() {\n\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\ts2 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\", \"d\"}, true)\n\tfmt.Println(s2.Diff(s1).Slice())\n\n\t// Output:\n\t// [d]\n}\n\n// Equal checks whether the two sets equal.\nfunc ExampleStrSet_Equal() {\n\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\ts2 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\", \"d\"}, true)\n\tfmt.Println(s2.Equal(s1))\n\n\ts3 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\ts4 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\tfmt.Println(s3.Equal(s4))\n\n\t// Output:\n\t// false\n\t// true\n}\n\n// Intersect returns a new set which is the intersection from `set` to `other`.\n// Which means, all the items in `newSet` are in `set` and also in `other`.\nfunc ExampleStrSet_Intersect() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\"}...)\n\tvar s2 gset.StrSet\n\ts2.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfmt.Println(s2.Intersect(s1).Slice())\n\n\t// May Output:\n\t// [c a b]\n}\n\n// IsSubsetOf checks whether the current set is a sub-set of `other`\nfunc ExampleStrSet_IsSubsetOf() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tvar s2 gset.StrSet\n\ts2.Add([]string{\"a\", \"b\", \"d\"}...)\n\tfmt.Println(s2.IsSubsetOf(s1))\n\n\t// Output:\n\t// true\n}\n\n// Iterator iterates the set readonly with given callback function `f`,\n// if `f` returns true then continue iterating; or false to stop.\nfunc ExampleStrSet_Iterator() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\ts1.Iterator(func(v string) bool {\n\t\tfmt.Println(\"Iterator\", v)\n\t\treturn true\n\t})\n\n\t// May Output:\n\t// Iterator a\n\t// Iterator b\n\t// Iterator c\n\t// Iterator d\n}\n\n// Join joins items with a string `glue`.\nfunc ExampleStrSet_Join() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfmt.Println(s1.Join(\",\"))\n\n\t// May Output:\n\t// b,c,d,a\n}\n\n// LockFunc locks writing with callback function `f`.\nfunc ExampleStrSet_LockFunc() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"1\", \"2\"}...)\n\ts1.LockFunc(func(m map[string]struct{}) {\n\t\tm[\"3\"] = struct{}{}\n\t})\n\tfmt.Println(s1.Slice())\n\n\t// May Output\n\t// [2 3 1]\n\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc ExampleStrSet_MarshalJSON() {\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.StrSet\n\t}\n\ts := Student{\n\t\tId:     1,\n\t\tName:   \"john\",\n\t\tScores: gset.NewStrSetFrom([]string{\"100\", \"99\", \"98\"}, true),\n\t}\n\tb, _ := json.Marshal(s)\n\tfmt.Println(string(b))\n\n\t// May Output:\n\t// {\"Id\":1,\"Name\":\"john\",\"Scores\":[\"100\",\"99\",\"98\"]}\n}\n\n// Merge adds items from `others` sets into `set`.\nfunc ExampleStrSet_Merge() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\n\ts2 := gset.NewStrSet(true)\n\tfmt.Println(s1.Merge(s2).Slice())\n\n\t// May Output:\n\t// [d a b c]\n}\n\n// Pops randomly pops an item from set.\nfunc ExampleStrSet_Pop() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\n\tfmt.Println(s1.Pop())\n\n\t// May Output:\n\t// a\n}\n\n// Pops randomly pops `size` items from set.\n// It returns all items if size == -1.\nfunc ExampleStrSet_Pops() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfor _, v := range s1.Pops(2) {\n\t\tfmt.Println(v)\n\t}\n\n\t// May Output:\n\t// a\n\t// b\n}\n\n// RLockFunc locks reading with callback function `f`.\nfunc ExampleStrSet_RLockFunc() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\ts1.RLockFunc(func(m map[string]struct{}) {\n\t\tfmt.Println(m)\n\t})\n\n\t// Output:\n\t// map[a:{} b:{} c:{} d:{}]\n}\n\n// Remove deletes `item` from set.\nfunc ExampleStrSet_Remove() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\ts1.Remove(\"a\")\n\tfmt.Println(s1.Slice())\n\n\t// May Output:\n\t// [b c d]\n}\n\n// Size returns the size of the set.\nfunc ExampleStrSet_Size() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfmt.Println(s1.Size())\n\n\t// Output:\n\t// 4\n}\n\n// Slice returns the an of items of the set as slice.\nfunc ExampleStrSet_Slice() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfmt.Println(s1.Slice())\n\n\t// May Output:\n\t// [a,b,c,d]\n}\n\n// String returns items as a string, which implements like json.Marshal does.\nfunc ExampleStrSet_String() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\tfmt.Println(s1.String())\n\n\t// May Output:\n\t// \"a\",\"b\",\"c\",\"d\"\n}\n\n// Sum sums items. Note: The items should be converted to int type,\n// or you'd get a result that you unexpected.\nfunc ExampleStrSet_Sum() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"1\", \"2\", \"3\", \"4\"}...)\n\tfmt.Println(s1.Sum())\n\n\t// Output:\n\t// 10\n}\n\n// Union returns a new set which is the union of `set` and `other`.\n// Which means, all the items in `newSet` are in `set` or in `other`.\nfunc ExampleStrSet_Union() {\n\ts1 := gset.NewStrSet(true)\n\ts1.Add([]string{\"a\", \"b\", \"c\", \"d\"}...)\n\ts2 := gset.NewStrSet(true)\n\ts2.Add([]string{\"a\", \"b\", \"d\"}...)\n\tfmt.Println(s1.Union(s2).Slice())\n\n\t// May Output:\n\t// [a b c d]\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc ExampleStrSet_UnmarshalJSON() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":[\"100\",\"99\",\"98\"]}`)\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.StrSet\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// {1 john \"99\",\"98\",\"100\"}\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for set.\nfunc ExampleStrSet_UnmarshalValue() {\n\tb := []byte(`{\"Id\":1,\"Name\":\"john\",\"Scores\":[\"100\",\"99\",\"98\"]}`)\n\ttype Student struct {\n\t\tId     int\n\t\tName   string\n\t\tScores *gset.StrSet\n\t}\n\ts := Student{}\n\tjson.Unmarshal(b, &s)\n\tfmt.Println(s)\n\n\t// May Output:\n\t// {1 john \"99\",\"98\",\"100\"}\n}\n\n// Walk applies a user supplied function `f` to every item of set.\nfunc ExampleStrSet_Walk() {\n\tvar (\n\t\tset    gset.StrSet\n\t\tnames  = g.SliceStr{\"user\", \"user_detail\"}\n\t\tprefix = \"gf_\"\n\t)\n\tset.Add(names...)\n\t// Add prefix for given table names.\n\tset.Walk(func(item string) string {\n\t\treturn prefix + item\n\t})\n\tfmt.Println(set.Slice())\n\n\t// May Output:\n\t// [gf_user gf_user_detail]\n}\n"
  },
  {
    "path": "container/gset/gset_z_unit_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage gset_test\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestSet_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.Set\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]any{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestSet_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New()\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]any{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestSet_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewSet()\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]any{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestSet_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewFrom([]any{1, 2, 3, 4, 5}, true)\n\t\tset.Iterator(func(k any) bool {\n\t\t\tif gconv.Int(k)%2 == 0 {\n\t\t\t\tset.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(set.Contains(1), true)\n\t\tt.Assert(set.Contains(2), false)\n\t\tt.Assert(set.Contains(3), true)\n\t\tt.Assert(set.Contains(4), false)\n\t\tt.Assert(set.Contains(5), true)\n\t})\n}\n\nfunc TestSet_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewSet()\n\t\ts.Add(1, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\n\t\ta1 := garray.New(true)\n\t\ta2 := garray.New(true)\n\t\ts.Iterator(func(v any) bool {\n\t\t\ta1.Append(1)\n\t\t\treturn false\n\t\t})\n\t\ts.Iterator(func(v any) bool {\n\t\t\ta2.Append(1)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(a1.Len(), 1)\n\t\tt.Assert(a2.Len(), 3)\n\t})\n}\n\nfunc TestSet_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewSet()\n\t\ts.Add(1, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.LockFunc(func(m map[any]struct{}) {\n\t\t\tdelete(m, 1)\n\t\t})\n\t\tt.Assert(s.Size(), 2)\n\t\ts.RLockFunc(func(m map[any]struct{}) {\n\t\t\tt.Assert(m, map[any]struct{}{\n\t\t\t\t3: {},\n\t\t\t\t2: {},\n\t\t\t})\n\t\t})\n\t})\n}\n\nfunc TestSet_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts3 := gset.NewSet()\n\t\ts4 := gset.NewSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(1, 2, 3)\n\t\ts3.Add(1, 2, 3, 4)\n\t\ts4.Add(4, 5, 6)\n\t\tt.Assert(s1.Equal(s2), true)\n\t\tt.Assert(s1.Equal(s3), false)\n\t\tt.Assert(s1.Equal(s4), false)\n\t\ts5 := s1\n\t\tt.Assert(s1.Equal(s5), true)\n\t})\n}\n\nfunc TestSet_IsSubsetOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts3 := gset.NewSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(1, 2, 3)\n\t\ts3.Add(1, 2, 3, 4)\n\t\tt.Assert(s1.IsSubsetOf(s2), true)\n\t\tt.Assert(s2.IsSubsetOf(s3), true)\n\t\tt.Assert(s1.IsSubsetOf(s3), true)\n\t\tt.Assert(s2.IsSubsetOf(s1), false)\n\t\tt.Assert(s3.IsSubsetOf(s2), false)\n\n\t\ts4 := s1\n\t\tt.Assert(s1.IsSubsetOf(s4), true)\n\t})\n}\n\nfunc TestSet_Union(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(3, 4)\n\t\ts3 := s1.Union(s2)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), true)\n\t})\n\n\t// Test with nil element in slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(3, 4)\n\t\ts3 := s1.Union(s2, nil)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), true)\n\t})\n}\n\nfunc TestSet_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Diff(s2)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), false)\n\t\tt.Assert(s3.Contains(4), false)\n\n\t\ts4 := s1\n\t\ts5 := s1.Diff(s2, s4)\n\t\tt.Assert(s5.Contains(1), true)\n\t\tt.Assert(s5.Contains(2), true)\n\t\tt.Assert(s5.Contains(3), false)\n\t\tt.Assert(s5.Contains(4), false)\n\t})\n}\n\nfunc TestSet_Intersect(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Intersect(s2)\n\t\tt.Assert(s3.Contains(1), false)\n\t\tt.Assert(s3.Contains(2), false)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), false)\n\t})\n}\n\nfunc TestSet_Complement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts2 := gset.NewSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Complement(s2)\n\t\tt.Assert(s3.Contains(1), false)\n\t\tt.Assert(s3.Contains(2), false)\n\t\tt.Assert(s3.Contains(4), true)\n\t\tt.Assert(s3.Contains(5), true)\n\t})\n\n\t// Test with nil full set\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts3 := s1.Complement(nil)\n\t\tt.Assert(s3.Size(), 0)\n\t})\n}\n\nfunc TestNewFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewFrom(\"a\")\n\t\ts2 := gset.NewFrom(\"b\", false)\n\t\ts3 := gset.NewFrom(3, true)\n\t\ts4 := gset.NewFrom([]string{\"s1\", \"s2\"}, true)\n\t\tt.Assert(s1.Contains(\"a\"), true)\n\t\tt.Assert(s2.Contains(\"b\"), true)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s4.Contains(\"s1\"), true)\n\t\tt.Assert(s4.Contains(\"s3\"), false)\n\n\t})\n}\n\nfunc TestNew(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New()\n\t\ts1.Add(\"a\", 2)\n\t\ts2 := gset.New(true)\n\t\ts2.Add(\"b\", 3)\n\t\tt.Assert(s1.Contains(\"a\"), true)\n\n\t})\n}\n\nfunc TestSet_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts1.Add(\"a\", \"a1\", \"b\", \"c\")\n\t\tstr1 := s1.Join(\",\")\n\t\tt.Assert(strings.Contains(str1, \"a1\"), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts1.Add(\"a\", `\"b\"`, `\\c`)\n\t\tstr1 := s1.Join(\",\")\n\t\tt.Assert(strings.Contains(str1, `\"b\"`), true)\n\t\tt.Assert(strings.Contains(str1, `\\c`), true)\n\t\tt.Assert(strings.Contains(str1, `a`), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.Set{}\n\t\tt.Assert(s1.Join(\",\"), \"\")\n\t})\n}\n\nfunc TestSet_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts1.Add(\"a\", \"a2\", \"b\", \"c\")\n\t\tstr1 := s1.String()\n\t\tt.Assert(strings.Contains(str1, \"[\"), true)\n\t\tt.Assert(strings.Contains(str1, \"]\"), true)\n\t\tt.Assert(strings.Contains(str1, \"a2\"), true)\n\n\t\ts1 = nil\n\t\tt.Assert(s1.String(), \"\")\n\n\t\ts2 := gset.New()\n\t\ts2.Add(1)\n\t\tt.Assert(s2.String(), \"[1]\")\n\t})\n}\n\nfunc TestSet_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts2 := gset.New(true)\n\t\ts1.Add(\"a\", \"a2\", \"b\", \"c\")\n\t\ts2.Add(\"b\", \"b1\", \"e\", \"f\")\n\t\tss := s1.Merge(s2)\n\t\tt.Assert(ss.Contains(\"a2\"), true)\n\t\tt.Assert(ss.Contains(\"b1\"), true)\n\n\t})\n}\n\nfunc TestSet_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts1.Add(1, 2, 3, 4)\n\t\tt.Assert(s1.Sum(), int(10))\n\n\t})\n}\n\nfunc TestSet_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\tt.Assert(s.Pop(), nil)\n\t\ts.Add(1, 2, 3, 4)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(s.Pop(), []int{1, 2, 3, 4})\n\t\tt.Assert(s.Size(), 3)\n\t})\n}\n\nfunc TestSet_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\ts.Add(1, 2, 3, 4)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Pops(0), nil)\n\t\tt.AssertIN(s.Pops(1), []int{1, 2, 3, 4})\n\t\tt.Assert(s.Size(), 3)\n\t\ta := s.Pops(6)\n\t\tt.Assert(len(a), 3)\n\t\tt.AssertIN(a, []int{1, 2, 3, 4})\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\ta := []any{1, 2, 3, 4}\n\t\ts.Add(a...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Pops(-2), nil)\n\t\tt.AssertIN(s.Pops(-1), a)\n\t})\n}\n\nfunc TestSet_Json(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []any{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := gset.NewFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(len(b1), len(b2))\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := gset.New()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Contains(\"a\"), true)\n\t\tt.Assert(a2.Contains(\"b\"), true)\n\t\tt.Assert(a2.Contains(\"c\"), true)\n\t\tt.Assert(a2.Contains(\"d\"), true)\n\t\tt.Assert(a2.Contains(\"e\"), false)\n\n\t\tvar a3 gset.Set\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Contains(\"a\"), true)\n\t\tt.Assert(a3.Contains(\"b\"), true)\n\t\tt.Assert(a3.Contains(\"c\"), true)\n\t\tt.Assert(a3.Contains(\"d\"), true)\n\t\tt.Assert(a3.Contains(\"e\"), false)\n\t})\n}\n\nfunc TestSet_AddIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.AddIfNotExist(1), false)\n\t\tt.Assert(s.AddIfNotExist(2), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExist(2), false)\n\t\tt.Assert(s.AddIfNotExist(nil), false)\n\t\tt.Assert(s.Contains(2), true)\n\t})\n}\n\nfunc TestSet_AddIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return false }), false)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExistFunc(nil, func() bool { return false }), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFunc(1, func() bool {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\ts.Add(1)\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.Set{}\n\t\tt.Assert(s.AddIfNotExistFunc(1, func() bool { return true }), true)\n\t})\n}\n\nfunc TestSet_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar set gset.Set\n\t\tset.Add(g.Slice{1, 2}...)\n\t\tset.Walk(func(item any) any {\n\t\t\treturn gconv.Int(item) + 10\n\t\t})\n\t\tt.Assert(set.Size(), 2)\n\t\tt.Assert(set.Contains(11), true)\n\t\tt.Assert(set.Contains(12), true)\n\t})\n}\n\nfunc TestSet_AddIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(1, func() bool {\n\t\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, true)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(1, func() bool {\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.New(true)\n\t\tt.Assert(s.AddIfNotExistFuncLock(nil, func() bool { return true }), false)\n\t\ts1 := gset.Set{}\n\t\tt.Assert(s1.AddIfNotExistFuncLock(1, func() bool { return true }), true)\n\t})\n}\n\nfunc TestSet_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tSet  *gset.Set\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  []byte(`[\"k1\",\"k2\",\"k3\"]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(\"k1\"), true)\n\t\tt.Assert(v.Set.Contains(\"k2\"), true)\n\t\tt.Assert(v.Set.Contains(\"k3\"), true)\n\t\tt.Assert(v.Set.Contains(\"k4\"), false)\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  g.Slice{\"k1\", \"k2\", \"k3\"},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(\"k1\"), true)\n\t\tt.Assert(v.Set.Contains(\"k2\"), true)\n\t\tt.Assert(v.Set.Contains(\"k3\"), true)\n\t\tt.Assert(v.Set.Contains(\"k4\"), false)\n\t})\n}\n\nfunc TestSet_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.New()\n\t\tset.Add(1, 2, 3)\n\n\t\tcopySet := set.DeepCopy().(*gset.Set)\n\t\tcopySet.Add(4)\n\t\tt.AssertNE(set.Size(), copySet.Size())\n\t\tt.AssertNE(set.String(), copySet.String())\n\n\t\tset = nil\n\t\tt.AssertNil(set.DeepCopy())\n\t})\n}\n"
  },
  {
    "path": "container/gset/gset_z_unit_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage gset_test\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestIntSet_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.IntSet\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]int{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestIntSet_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet()\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]int{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestIntSet_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewIntSetFrom([]int{1, 2, 3, 4, 5}, true)\n\t\tset.Iterator(func(k int) bool {\n\t\t\tif k%2 == 0 {\n\t\t\t\tset.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(set.Contains(1), true)\n\t\tt.Assert(set.Contains(2), false)\n\t\tt.Assert(set.Contains(3), true)\n\t\tt.Assert(set.Contains(4), false)\n\t\tt.Assert(set.Contains(5), true)\n\t})\n}\n\nfunc TestIntSet_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet()\n\t\ts.Add(1, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\n\t\ta1 := garray.New(true)\n\t\ta2 := garray.New(true)\n\t\ts.Iterator(func(v int) bool {\n\t\t\ta1.Append(1)\n\t\t\treturn false\n\t\t})\n\t\ts.Iterator(func(v int) bool {\n\t\t\ta2.Append(1)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(a1.Len(), 1)\n\t\tt.Assert(a2.Len(), 3)\n\t})\n}\n\nfunc TestIntSet_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet()\n\t\ts.Add(1, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.LockFunc(func(m map[int]struct{}) {\n\t\t\tdelete(m, 1)\n\t\t})\n\t\tt.Assert(s.Size(), 2)\n\t\ts.RLockFunc(func(m map[int]struct{}) {\n\t\t\tt.Assert(m, map[int]struct{}{\n\t\t\t\t3: {},\n\t\t\t\t2: {},\n\t\t\t})\n\t\t})\n\t})\n}\n\nfunc TestIntSet_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts3 := gset.NewIntSet()\n\t\ts4 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(1, 2, 3)\n\t\ts3.Add(1, 2, 3, 4)\n\t\ts4.Add(4, 5, 6)\n\t\tt.Assert(s1.Equal(s2), true)\n\t\tt.Assert(s1.Equal(s3), false)\n\t\tt.Assert(s1.Equal(s4), false)\n\t\ts5 := s1\n\t\tt.Assert(s1.Equal(s5), true)\n\t})\n}\n\nfunc TestIntSet_IsSubsetOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts3 := gset.NewIntSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(1, 2, 3)\n\t\ts3.Add(1, 2, 3, 4)\n\t\tt.Assert(s1.IsSubsetOf(s2), true)\n\t\tt.Assert(s2.IsSubsetOf(s3), true)\n\t\tt.Assert(s1.IsSubsetOf(s3), true)\n\t\tt.Assert(s2.IsSubsetOf(s1), false)\n\t\tt.Assert(s3.IsSubsetOf(s2), false)\n\n\t\ts4 := s1\n\t\tt.Assert(s1.IsSubsetOf(s4), true)\n\t})\n}\n\nfunc TestIntSet_Union(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(3, 4)\n\t\ts3 := s1.Union(s2)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), true)\n\t})\n\n\t// Test with nil element in slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2)\n\t\ts2.Add(3, 4)\n\t\ts3 := s1.Union(s2, nil)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), true)\n\t})\n}\n\nfunc TestIntSet_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Diff(s2)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(2), true)\n\t\tt.Assert(s3.Contains(3), false)\n\t\tt.Assert(s3.Contains(4), false)\n\n\t\ts4 := s1\n\t\ts5 := s1.Diff(s2, s4)\n\t\tt.Assert(s5.Contains(1), true)\n\t\tt.Assert(s5.Contains(2), true)\n\t\tt.Assert(s5.Contains(3), false)\n\t\tt.Assert(s5.Contains(4), false)\n\t})\n}\n\nfunc TestIntSet_Intersect(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Intersect(s2)\n\t\tt.Assert(s3.Contains(1), false)\n\t\tt.Assert(s3.Contains(2), false)\n\t\tt.Assert(s3.Contains(3), true)\n\t\tt.Assert(s3.Contains(4), false)\n\t})\n}\n\nfunc TestIntSet_Complement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Complement(s2)\n\t\tt.Assert(s3.Contains(1), false)\n\t\tt.Assert(s3.Contains(2), false)\n\t\tt.Assert(s3.Contains(4), true)\n\t\tt.Assert(s3.Contains(5), true)\n\t})\n\n\t// Test with nil full set\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts3 := s1.Complement(nil)\n\t\tt.Assert(s3.Size(), 0)\n\t})\n}\n\nfunc TestIntSet_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet(true)\n\t\ts1.Add(1, 2, 3)\n\t\tt.Assert(s1.Size(), 3)\n\n\t})\n\n}\n\nfunc TestIntSet_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts2 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2.Add(3, 4, 5)\n\t\ts3 := s1.Merge(s2)\n\t\tt.Assert(s3.Contains(1), true)\n\t\tt.Assert(s3.Contains(5), true)\n\t\tt.Assert(s3.Contains(6), false)\n\t})\n}\n\nfunc TestIntSet_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\tt.Assert(s1.Join(\",\"), \"\")\n\t\ts1.Add(1, 2, 3)\n\t\ts3 := s1.Join(\",\")\n\t\tt.Assert(strings.Contains(s3, \"1\"), true)\n\t\tt.Assert(strings.Contains(s3, \"2\"), true)\n\t\tt.Assert(strings.Contains(s3, \"3\"), true)\n\t})\n}\n\nfunc TestIntSet_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts3 := s1.String()\n\t\tt.Assert(strings.Contains(s3, \"[\"), true)\n\t\tt.Assert(strings.Contains(s3, \"]\"), true)\n\t\tt.Assert(strings.Contains(s3, \"1\"), true)\n\t\tt.Assert(strings.Contains(s3, \"2\"), true)\n\t\tt.Assert(strings.Contains(s3, \"3\"), true)\n\t\ts1 = nil\n\t\tt.Assert(s1.String(), \"\")\n\t})\n}\n\nfunc TestIntSet_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSet()\n\t\ts1.Add(1, 2, 3)\n\t\ts2 := gset.NewIntSet()\n\t\ts2.Add(5, 6, 7)\n\t\tt.Assert(s2.Sum(), 18)\n\n\t})\n\n}\n\nfunc TestIntSet_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet()\n\t\tt.Assert(s.Pop(), 0)\n\t\ts.Add(4, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.AssertIN(s.Pop(), []int{4, 2, 3})\n\t\tt.AssertIN(s.Pop(), []int{4, 2, 3})\n\t\tt.Assert(s.Size(), 1)\n\t})\n}\n\nfunc TestIntSet_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet()\n\t\ts.Add(1, 4, 2, 3)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Pops(0), nil)\n\t\tt.AssertIN(s.Pops(1), []int{1, 4, 2, 3})\n\t\tt.Assert(s.Size(), 3)\n\t\ta := s.Pops(2)\n\t\tt.Assert(len(a), 2)\n\t\tt.AssertIN(a, []int{1, 4, 2, 3})\n\t\tt.Assert(s.Size(), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet(true)\n\t\ta := []int{1, 2, 3, 4}\n\t\ts.Add(a...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Pops(-2), nil)\n\t\tt.AssertIN(s.Pops(-1), a)\n\t})\n}\n\nfunc TestIntSet_AddIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet(true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.AddIfNotExist(1), false)\n\t\tt.Assert(s.AddIfNotExist(2), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExist(2), false)\n\t\tt.Assert(s.Contains(2), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.IntSet{}\n\t\tt.Assert(s.AddIfNotExist(1), true)\n\t})\n}\n\nfunc TestIntSet_AddIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet(true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return false }), false)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)\n\t\tt.Assert(s.Contains(2), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFunc(1, func() bool {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\ts.Add(1)\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.IntSet{}\n\t\tt.Assert(s.AddIfNotExistFunc(1, func() bool { return true }), true)\n\t})\n}\n\nfunc TestIntSet_AddIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewIntSet(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(1, func() bool {\n\t\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, true)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(1, func() bool {\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.IntSet{}\n\t\tt.Assert(s.AddIfNotExistFuncLock(1, func() bool { return true }), true)\n\t})\n}\n\nfunc TestIntSet_Json(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []int{1, 3, 2, 4}\n\t\ta1 := gset.NewIntSetFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(len(b1), len(b2))\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := gset.NewIntSet()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Contains(1), true)\n\t\tt.Assert(a2.Contains(2), true)\n\t\tt.Assert(a2.Contains(3), true)\n\t\tt.Assert(a2.Contains(4), true)\n\t\tt.Assert(a2.Contains(5), false)\n\n\t\tvar a3 gset.IntSet\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a2.Contains(1), true)\n\t\tt.Assert(a2.Contains(2), true)\n\t\tt.Assert(a2.Contains(3), true)\n\t\tt.Assert(a2.Contains(4), true)\n\t\tt.Assert(a2.Contains(5), false)\n\t})\n}\n\nfunc TestIntSet_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar set gset.IntSet\n\t\tset.Add(g.SliceInt{1, 2}...)\n\t\tset.Walk(func(item int) int {\n\t\t\treturn item + 10\n\t\t})\n\t\tt.Assert(set.Size(), 2)\n\t\tt.Assert(set.Contains(11), true)\n\t\tt.Assert(set.Contains(12), true)\n\t})\n}\n\nfunc TestIntSet_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tSet  *gset.IntSet\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  []byte(`[1,2,3]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(1), true)\n\t\tt.Assert(v.Set.Contains(2), true)\n\t\tt.Assert(v.Set.Contains(3), true)\n\t\tt.Assert(v.Set.Contains(4), false)\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  g.Slice{1, 2, 3},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(1), true)\n\t\tt.Assert(v.Set.Contains(2), true)\n\t\tt.Assert(v.Set.Contains(3), true)\n\t\tt.Assert(v.Set.Contains(4), false)\n\t})\n}\n\nfunc TestIntSet_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewIntSet()\n\t\tset.Add(1, 2, 3)\n\n\t\tcopySet := set.DeepCopy().(*gset.IntSet)\n\t\tcopySet.Add(4)\n\t\tt.AssertNE(set.Size(), copySet.Size())\n\t\tt.AssertNE(set.String(), copySet.String())\n\n\t\tset = nil\n\t\tt.AssertNil(set.DeepCopy())\n\t})\n}\n"
  },
  {
    "path": "container/gset/gset_z_unit_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go\n\npackage gset_test\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestStrSet_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.StrSet\n\t\ts.Add(\"1\", \"1\", \"2\")\n\t\ts.Add([]string{\"3\", \"4\"}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(\"1\", s.Slice())\n\t\tt.AssertIN(\"2\", s.Slice())\n\t\tt.AssertIN(\"3\", s.Slice())\n\t\tt.AssertIN(\"4\", s.Slice())\n\t\tt.AssertNI(\"0\", s.Slice())\n\t\tt.Assert(s.Contains(\"4\"), true)\n\t\tt.Assert(s.Contains(\"5\"), false)\n\t\ts.Remove(\"1\")\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestStrSet_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet()\n\t\ts.Add(\"1\", \"1\", \"2\")\n\t\ts.Add([]string{\"3\", \"4\"}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(\"1\", s.Slice())\n\t\tt.AssertIN(\"2\", s.Slice())\n\t\tt.AssertIN(\"3\", s.Slice())\n\t\tt.AssertIN(\"4\", s.Slice())\n\t\tt.AssertNI(\"0\", s.Slice())\n\t\tt.Assert(s.Contains(\"4\"), true)\n\t\tt.Assert(s.Contains(\"5\"), false)\n\t\ts.Remove(\"1\")\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestStrSet_ContainsI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet()\n\t\ts.Add(\"a\", \"b\", \"C\")\n\t\tt.Assert(s.Contains(\"A\"), false)\n\t\tt.Assert(s.Contains(\"a\"), true)\n\t\tt.Assert(s.ContainsI(\"A\"), true)\n\t\tt.Assert(s.ContainsI(\"d\"), false)\n\t})\n}\n\nfunc TestStrSet_Iterator_Deadlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewStrSetFrom([]string{\"1\", \"2\", \"3\", \"4\", \"5\"}, true)\n\t\tset.Iterator(func(k string) bool {\n\t\t\tif gconv.Int(k)%2 == 0 {\n\t\t\t\tset.Remove(k)\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(set.Contains(\"1\"), true)\n\t\tt.Assert(set.Contains(\"2\"), false)\n\t\tt.Assert(set.Contains(\"3\"), true)\n\t\tt.Assert(set.Contains(\"4\"), false)\n\t\tt.Assert(set.Contains(\"5\"), true)\n\t})\n}\n\nfunc TestStrSet_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet()\n\t\ts.Add(\"1\", \"2\", \"3\")\n\t\tt.Assert(s.Size(), 3)\n\n\t\ta1 := garray.New(true)\n\t\ta2 := garray.New(true)\n\t\ts.Iterator(func(v string) bool {\n\t\t\ta1.Append(\"1\")\n\t\t\treturn false\n\t\t})\n\t\ts.Iterator(func(v string) bool {\n\t\t\ta2.Append(\"1\")\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(a1.Len(), 1)\n\t\tt.Assert(a2.Len(), 3)\n\t})\n}\n\nfunc TestStrSet_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet()\n\t\ts.Add(\"1\", \"2\", \"3\")\n\t\tt.Assert(s.Size(), 3)\n\t\ts.LockFunc(func(m map[string]struct{}) {\n\t\t\tdelete(m, \"1\")\n\t\t})\n\t\tt.Assert(s.Size(), 2)\n\t\ts.RLockFunc(func(m map[string]struct{}) {\n\t\t\tt.Assert(m, map[string]struct{}{\n\t\t\t\t\"3\": {},\n\t\t\t\t\"2\": {},\n\t\t\t})\n\t\t})\n\t})\n}\n\nfunc TestStrSet_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts3 := gset.NewStrSet()\n\t\ts4 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts2.Add(\"1\", \"2\", \"3\")\n\t\ts3.Add(\"1\", \"2\", \"3\", \"4\")\n\t\ts4.Add(\"4\", \"5\", \"6\")\n\t\tt.Assert(s1.Equal(s2), true)\n\t\tt.Assert(s1.Equal(s3), false)\n\t\tt.Assert(s1.Equal(s4), false)\n\t\ts5 := s1\n\t\tt.Assert(s1.Equal(s5), true)\n\t})\n}\n\nfunc TestStrSet_IsSubsetOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts3 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\")\n\t\ts2.Add(\"1\", \"2\", \"3\")\n\t\ts3.Add(\"1\", \"2\", \"3\", \"4\")\n\t\tt.Assert(s1.IsSubsetOf(s2), true)\n\t\tt.Assert(s2.IsSubsetOf(s3), true)\n\t\tt.Assert(s1.IsSubsetOf(s3), true)\n\t\tt.Assert(s2.IsSubsetOf(s1), false)\n\t\tt.Assert(s3.IsSubsetOf(s2), false)\n\n\t\ts4 := s1\n\t\tt.Assert(s1.IsSubsetOf(s4), true)\n\t})\n}\n\nfunc TestStrSet_Union(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\")\n\t\ts2.Add(\"3\", \"4\")\n\t\ts3 := s1.Union(s2)\n\t\tt.Assert(s3.Contains(\"1\"), true)\n\t\tt.Assert(s3.Contains(\"2\"), true)\n\t\tt.Assert(s3.Contains(\"3\"), true)\n\t\tt.Assert(s3.Contains(\"4\"), true)\n\t})\n\n\t// Test with nil element in slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\")\n\t\ts2.Add(\"3\", \"4\")\n\t\ts3 := s1.Union(s2, nil)\n\t\tt.Assert(s3.Contains(\"1\"), true)\n\t\tt.Assert(s3.Contains(\"2\"), true)\n\t\tt.Assert(s3.Contains(\"3\"), true)\n\t\tt.Assert(s3.Contains(\"4\"), true)\n\t})\n}\n\nfunc TestStrSet_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts2.Add(\"3\", \"4\", \"5\")\n\t\ts3 := s1.Diff(s2)\n\t\tt.Assert(s3.Contains(\"1\"), true)\n\t\tt.Assert(s3.Contains(\"2\"), true)\n\t\tt.Assert(s3.Contains(\"3\"), false)\n\t\tt.Assert(s3.Contains(\"4\"), false)\n\n\t\ts4 := s1\n\t\ts5 := s1.Diff(s2, s4)\n\t\tt.Assert(s5.Contains(\"1\"), true)\n\t\tt.Assert(s5.Contains(\"2\"), true)\n\t\tt.Assert(s5.Contains(\"3\"), false)\n\t\tt.Assert(s5.Contains(\"4\"), false)\n\t})\n}\n\nfunc TestStrSet_Intersect(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts2.Add(\"3\", \"4\", \"5\")\n\t\ts3 := s1.Intersect(s2)\n\t\tt.Assert(s3.Contains(\"1\"), false)\n\t\tt.Assert(s3.Contains(\"2\"), false)\n\t\tt.Assert(s3.Contains(\"3\"), true)\n\t\tt.Assert(s3.Contains(\"4\"), false)\n\t})\n}\n\nfunc TestStrSet_Complement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts2.Add(\"3\", \"4\", \"5\")\n\t\ts3 := s1.Complement(s2)\n\t\tt.Assert(s3.Contains(\"1\"), false)\n\t\tt.Assert(s3.Contains(\"2\"), false)\n\t\tt.Assert(s3.Contains(\"4\"), true)\n\t\tt.Assert(s3.Contains(\"5\"), true)\n\t})\n\n\t// Test with nil full set\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts3 := s1.Complement(nil)\n\t\tt.Assert(s3.Size(), 0)\n\t})\n}\n\nfunc TestNewIntSetFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewIntSetFrom([]int{1, 2, 3, 4})\n\t\ts2 := gset.NewIntSetFrom([]int{5, 6, 7, 8})\n\t\tt.Assert(s1.Contains(3), true)\n\t\tt.Assert(s1.Contains(5), false)\n\t\tt.Assert(s2.Contains(3), false)\n\t\tt.Assert(s2.Contains(5), true)\n\t})\n}\n\nfunc TestStrSet_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\ts2 := gset.NewStrSet()\n\t\ts1.Add(\"1\", \"2\", \"3\")\n\t\ts2.Add(\"3\", \"4\", \"5\")\n\t\ts3 := s1.Merge(s2)\n\t\tt.Assert(s3.Contains(\"1\"), true)\n\t\tt.Assert(s3.Contains(\"6\"), false)\n\t\tt.Assert(s3.Contains(\"4\"), true)\n\t\tt.Assert(s3.Contains(\"5\"), true)\n\t})\n}\n\nfunc TestNewStrSetFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\tt.Assert(s1.Contains(\"b\"), true)\n\t\tt.Assert(s1.Contains(\"d\"), false)\n\t})\n}\n\nfunc TestStrSet_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\tstr1 := s1.Join(\",\")\n\t\tt.Assert(strings.Contains(str1, \"b\"), true)\n\t\tt.Assert(strings.Contains(str1, \"d\"), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSet()\n\t\tt.Assert(s1.Join(\",\"), \"\")\n\t\ts1.Add(\"a\", `\"b\"`, `\\c`)\n\t\tstr1 := s1.Join(\",\")\n\t\tt.Assert(strings.Contains(str1, `\"b\"`), true)\n\t\tt.Assert(strings.Contains(str1, `\\c`), true)\n\t\tt.Assert(strings.Contains(str1, `a`), true)\n\t})\n}\n\nfunc TestStrSet_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\tstr1 := s1.String()\n\t\tt.Assert(strings.Contains(str1, \"b\"), true)\n\t\tt.Assert(strings.Contains(str1, \"d\"), false)\n\t\ts1 = nil\n\t\tt.Assert(s1.String(), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.New(true)\n\t\ts1.Add(\"a\", \"a2\", \"b\", \"c\")\n\t\tstr1 := s1.String()\n\t\tt.Assert(strings.Contains(str1, \"[\"), true)\n\t\tt.Assert(strings.Contains(str1, \"]\"), true)\n\t\tt.Assert(strings.Contains(str1, \"a2\"), true)\n\t})\n}\n\nfunc TestStrSet_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\ts2 := gset.NewIntSetFrom([]int{2, 3, 4}, true)\n\t\tt.Assert(s1.Sum(), 0)\n\t\tt.Assert(s2.Sum(), 9)\n\t})\n}\n\nfunc TestStrSet_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\tt.Assert(s1.Size(), 3)\n\n\t})\n}\n\nfunc TestStrSet_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewStrSetFrom([]string{\"a\", \"b\", \"c\"}, true)\n\t\ts1.Remove(\"b\")\n\t\tt.Assert(s1.Contains(\"b\"), false)\n\t\tt.Assert(s1.Contains(\"c\"), true)\n\t})\n}\n\nfunc TestStrSet_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts := gset.NewStrSetFrom(a, true)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(s.Pop(), a)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.AssertIN(s.Pop(), a)\n\t\tt.Assert(s.Size(), 2)\n\n\t\ts1 := gset.StrSet{}\n\t\tt.Assert(s1.Pop(), \"\")\n\t})\n}\n\nfunc TestStrSet_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := []string{\"a\", \"b\", \"c\", \"d\"}\n\t\ts := gset.NewStrSetFrom(a, true)\n\t\tarray := s.Pops(2)\n\t\tt.Assert(len(array), 2)\n\t\tt.Assert(s.Size(), 2)\n\t\tt.AssertIN(array, a)\n\t\tt.Assert(s.Pops(0), nil)\n\t\tt.AssertIN(s.Pops(2), a)\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet(true)\n\t\ta := []string{\"1\", \"2\", \"3\", \"4\"}\n\t\ts.Add(a...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Pops(-2), nil)\n\t\tt.AssertIN(s.Pops(-1), a)\n\t})\n}\n\nfunc TestStrSet_AddIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet(true)\n\t\ts.Add(\"1\")\n\t\tt.Assert(s.Contains(\"1\"), true)\n\t\tt.Assert(s.AddIfNotExist(\"1\"), false)\n\t\tt.Assert(s.AddIfNotExist(\"2\"), true)\n\t\tt.Assert(s.Contains(\"2\"), true)\n\t\tt.Assert(s.AddIfNotExist(\"2\"), false)\n\t\tt.Assert(s.Contains(\"2\"), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.StrSet{}\n\t\tt.Assert(s.AddIfNotExist(\"1\"), true)\n\t})\n}\n\nfunc TestStrSet_AddIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet(true)\n\t\ts.Add(\"1\")\n\t\tt.Assert(s.Contains(\"1\"), true)\n\t\tt.Assert(s.Contains(\"2\"), false)\n\t\tt.Assert(s.AddIfNotExistFunc(\"2\", func() bool { return false }), false)\n\t\tt.Assert(s.Contains(\"2\"), false)\n\t\tt.Assert(s.AddIfNotExistFunc(\"2\", func() bool { return true }), true)\n\t\tt.Assert(s.Contains(\"2\"), true)\n\t\tt.Assert(s.AddIfNotExistFunc(\"2\", func() bool { return true }), false)\n\t\tt.Assert(s.Contains(\"2\"), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFunc(\"1\", func() bool {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\ts.Add(\"1\")\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.StrSet{}\n\t\tt.Assert(s.AddIfNotExistFunc(\"1\", func() bool { return true }), true)\n\t})\n}\n\nfunc TestStrSet_AddIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewStrSet(true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(\"1\", func() bool {\n\t\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, true)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFuncLock(\"1\", func() bool {\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\twg.Wait()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.StrSet{}\n\t\tt.Assert(s.AddIfNotExistFuncLock(\"1\", func() bool { return true }), true)\n\t})\n}\n\nfunc TestStrSet_Json(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := []string{\"a\", \"b\", \"d\", \"c\"}\n\t\ta1 := gset.NewStrSetFrom(s1)\n\t\tb1, err1 := json.Marshal(a1)\n\t\tb2, err2 := json.Marshal(s1)\n\t\tt.Assert(len(b1), len(b2))\n\t\tt.Assert(err1, err2)\n\n\t\ta2 := gset.NewStrSet()\n\t\terr2 = json.UnmarshalUseNumber(b2, &a2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(a2.Contains(\"a\"), true)\n\t\tt.Assert(a2.Contains(\"b\"), true)\n\t\tt.Assert(a2.Contains(\"c\"), true)\n\t\tt.Assert(a2.Contains(\"d\"), true)\n\t\tt.Assert(a2.Contains(\"e\"), false)\n\n\t\tvar a3 gset.StrSet\n\t\terr := json.UnmarshalUseNumber(b2, &a3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a3.Contains(\"a\"), true)\n\t\tt.Assert(a3.Contains(\"b\"), true)\n\t\tt.Assert(a3.Contains(\"c\"), true)\n\t\tt.Assert(a3.Contains(\"d\"), true)\n\t\tt.Assert(a3.Contains(\"e\"), false)\n\t})\n}\n\nfunc TestStrSet_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tset    gset.StrSet\n\t\t\tnames  = g.SliceStr{\"user\", \"user_detail\"}\n\t\t\tprefix = \"gf_\"\n\t\t)\n\t\tset.Add(names...)\n\t\t// Add prefix for given table names.\n\t\tset.Walk(func(item string) string {\n\t\t\treturn prefix + item\n\t\t})\n\t\tt.Assert(set.Size(), 2)\n\t\tt.Assert(set.Contains(\"gf_user\"), true)\n\t\tt.Assert(set.Contains(\"gf_user_detail\"), true)\n\t})\n}\n\nfunc TestStrSet_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tSet  *gset.StrSet\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  []byte(`[\"1\",\"2\",\"3\"]`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(\"1\"), true)\n\t\tt.Assert(v.Set.Contains(\"2\"), true)\n\t\tt.Assert(v.Set.Contains(\"3\"), true)\n\t\tt.Assert(v.Set.Contains(\"4\"), false)\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"set\":  g.SliceStr{\"1\", \"2\", \"3\"},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Set.Size(), 3)\n\t\tt.Assert(v.Set.Contains(\"1\"), true)\n\t\tt.Assert(v.Set.Contains(\"2\"), true)\n\t\tt.Assert(v.Set.Contains(\"3\"), true)\n\t\tt.Assert(v.Set.Contains(\"4\"), false)\n\t})\n}\n\nfunc TestStrSet_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewStrSet()\n\t\tset.Add(\"1\", \"2\", \"3\")\n\n\t\tcopySet := set.DeepCopy().(*gset.StrSet)\n\t\tcopySet.Add(\"4\")\n\t\tt.AssertNE(set.Size(), copySet.Size())\n\t\tt.AssertNE(set.String(), copySet.String())\n\n\t\tset = nil\n\t\tt.AssertNil(set.DeepCopy())\n\t})\n}\n"
  },
  {
    "path": "container/gset/gset_z_unit_t_set_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gset_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestTSet_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\ts.Add(1, 1, 2)\n\t\ts.Add([]int{3, 4}...)\n\t\tt.Assert(s.Size(), 4)\n\t\tt.AssertIN(1, s.Slice())\n\t\tt.AssertIN(2, s.Slice())\n\t\tt.AssertIN(3, s.Slice())\n\t\tt.AssertIN(4, s.Slice())\n\t\tt.AssertNI(0, s.Slice())\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), false)\n\t\ts.Remove(1)\n\t\tt.Assert(s.Size(), 3)\n\t\ts.Clear()\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_NewFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3}, true)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.Contains(3), true)\n\t\tt.Assert(s.Contains(4), false)\n\t})\n}\n\nfunc TestTSet_Add_NilData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\ts.Add(1, 2, 3)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.Assert(s.Contains(1), true)\n\t})\n}\n\nfunc TestTSet_AddIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int](true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.AddIfNotExist(1), false)\n\t\tt.Assert(s.AddIfNotExist(2), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExist(2), false)\n\t})\n\n\t// Test with pointer type to test nil check\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[*int](true)\n\n\t\tval := 1\n\t\tptr := &val\n\t\tt.Assert(s.AddIfNotExist(ptr), true)\n\t\tt.Assert(s.AddIfNotExist(ptr), false)\n\t})\n\n\t// Test nil data map initialization\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\tt.Assert(s.AddIfNotExist(1), true)\n\t\tt.Assert(s.Size(), 1)\n\t})\n}\n\nfunc TestTSet_AddIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int](true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return false }), false)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)\n\t\tt.Assert(s.Contains(2), true)\n\t})\n\n\t// Test concurrent scenario\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int](true)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tr := s.AddIfNotExistFunc(1, func() bool {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tt.Assert(r, false)\n\t\t}()\n\t\ts.Add(1)\n\t\twg.Wait()\n\t})\n\n\t// Test nil data map initialization\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\tt.Assert(s.AddIfNotExistFunc(1, func() bool { return true }), true)\n\t\tt.Assert(s.Size(), 1)\n\t})\n}\n\nfunc TestTSet_AddIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int](true)\n\t\ts.Add(1)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFuncLock(2, func() bool { return false }), false)\n\t\tt.Assert(s.Contains(2), false)\n\t\tt.Assert(s.AddIfNotExistFuncLock(2, func() bool { return true }), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.AddIfNotExistFuncLock(2, func() bool { return true }), false)\n\t\tt.Assert(s.Contains(2), true)\n\t})\n\n\t// Test nil data map initialization\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\tt.Assert(s.AddIfNotExistFuncLock(1, func() bool { return true }), true)\n\t\tt.Assert(s.Size(), 1)\n\t})\n}\n\nfunc TestTSet_Iterator(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5}, true)\n\t\tvar sum int\n\t\ts.Iterator(func(v int) bool {\n\t\t\tsum += v\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(sum, 15)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5}, true)\n\t\tvar count int\n\t\ts.Iterator(func(v int) bool {\n\t\t\tcount++\n\t\t\treturn count < 3\n\t\t})\n\t\tt.Assert(count, 3)\n\t})\n}\n\nfunc TestTSet_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\tt.Assert(s.Join(\",\"), \"\")\n\t\ts.Add(1, 2, 3)\n\t\tresult := s.Join(\",\")\n\t\tt.Assert(len(result) > 0, true)\n\t})\n}\n\nfunc TestTSet_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s *gset.TSet[int]\n\t\tt.Assert(s.String(), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\tt.Assert(s.String(), \"[]\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tresult := s.String()\n\t\tt.Assert(len(result) > 2, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[string]([]string{\"a\", \"b\", \"c\"})\n\t\tresult := s.String()\n\t\tt.Assert(len(result) > 2, true)\n\t})\n}\n\nfunc TestTSet_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tt.Assert(s1.Equal(s2), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2, 3, 4})\n\t\tt.Assert(s1.Equal(s2), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tt.Assert(s1.Equal(s1), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2, 4})\n\t\tt.Assert(s1.Equal(s2), false)\n\t})\n}\n\nfunc TestTSet_IsSubsetOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tt.Assert(s1.IsSubsetOf(s2), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2})\n\t\tt.Assert(s1.IsSubsetOf(s2), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tt.Assert(s1.IsSubsetOf(s1), true)\n\t})\n}\n\nfunc TestTSet_Union(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{3, 4, 5})\n\t\ts := s1.Union(s2)\n\t\tt.Assert(s.Size(), 5)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.Contains(3), true)\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), true)\n\t})\n\n\t// Test with nil set - should skip it and copy s1 data\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tvar s2 *gset.TSet[int]\n\t\ts := s1.Union(s2)\n\t\t// Since s2 is nil and skipped, newSet will be empty\n\t\t// because the loop runs but nothing is copied when other is nil\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\t// Test with self\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts := s1.Union(s1)\n\t\tt.Assert(s.Size(), 3)\n\t})\n}\n\nfunc TestTSet_Diff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{3, 4, 5})\n\t\ts := s1.Diff(s2)\n\t\tt.Assert(s.Size(), 2)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.Contains(3), false)\n\t})\n\n\t// Test with nil set - should skip it\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tvar s2 *gset.TSet[int]\n\t\ts := s1.Diff(s2)\n\t\t// Since s2 is nil and skipped, newSet will be empty\n\t\t// because the loop runs but nothing is copied when other is nil\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\t// Test with self\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts := s1.Diff(s1)\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_Intersect(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{3, 4, 5})\n\t\ts := s1.Intersect(s2)\n\t\tt.Assert(s.Size(), 1)\n\t\tt.Assert(s.Contains(3), true)\n\t})\n\n\t// Test with nil set\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tvar s2 *gset.TSet[int]\n\t\ts := s1.Intersect(s2)\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\t// Test with self\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts := s1.Intersect(s1)\n\t\tt.Assert(s.Size(), 3)\n\t})\n}\n\nfunc TestTSet_Complement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5})\n\t\ts := s1.Complement(s2)\n\t\tt.Assert(s.Size(), 2)\n\t\tt.Assert(s.Contains(4), true)\n\t\tt.Assert(s.Contains(5), true)\n\t})\n\n\t// Test with self\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts := s1.Complement(s1)\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_Merge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts2 := gset.NewTSetFrom[int]([]int{3, 4, 5})\n\t\ts1.Merge(s2)\n\t\tt.Assert(s1.Size(), 5)\n\t\tt.Assert(s1.Contains(1), true)\n\t\tt.Assert(s1.Contains(2), true)\n\t\tt.Assert(s1.Contains(3), true)\n\t\tt.Assert(s1.Contains(4), true)\n\t\tt.Assert(s1.Contains(5), true)\n\t})\n\n\t// Test with nil set\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tvar s2 *gset.TSet[int]\n\t\ts1.Merge(s2)\n\t\tt.Assert(s1.Size(), 3)\n\t})\n\n\t// Test with self\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\ts1.Merge(s1)\n\t\tt.Assert(s1.Size(), 3)\n\t})\n}\n\nfunc TestTSet_Sum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tt.Assert(s.Sum(), 6)\n\t})\n}\n\nfunc TestTSet_Pop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\titem := s.Pop()\n\t\tt.Assert(s.Size(), 2)\n\t\tt.Assert(s.Contains(item), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\titem := s.Pop()\n\t\tt.Assert(item, 0)\n\t})\n}\n\nfunc TestTSet_Pops(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5})\n\t\titems := s.Pops(3)\n\t\tt.Assert(len(items), 3)\n\t\tt.Assert(s.Size(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\titems := s.Pops(-1)\n\t\tt.Assert(len(items), 3)\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\titems := s.Pops(0)\n\t\tt.Assert(items, nil)\n\t\tt.Assert(s.Size(), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\titems := s.Pops(10)\n\t\tt.Assert(len(items), 3)\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_Walk(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2})\n\t\ts.Walk(func(item int) int {\n\t\t\treturn item + 10\n\t\t})\n\t\tt.Assert(s.Size(), 2)\n\t\tt.Assert(s.Contains(11), true)\n\t\tt.Assert(s.Contains(12), true)\n\t})\n}\n\nfunc TestTSet_MarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3})\n\t\tb, err := json.Marshal(s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(b) > 0, true)\n\t})\n}\n\nfunc TestTSet_UnmarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\tb := []byte(`[1,2,3]`)\n\t\terr := json.UnmarshalUseNumber(b, &s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.Contains(3), true)\n\t})\n\n\t// Test with nil data map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\tb := []byte(`[1,2,3]`)\n\t\terr := json.UnmarshalUseNumber(b, &s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t})\n\n\t// Test with invalid JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\tb := []byte(`{invalid}`)\n\t\terr := json.UnmarshalUseNumber(b, &s)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// Test with empty array\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\tb := []byte(`[]`)\n\t\terr := json.UnmarshalUseNumber(b, &s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_UnmarshalValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue([]byte(`[1,2,3]`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t\tt.Assert(s.Contains(1), true)\n\t\tt.Assert(s.Contains(2), true)\n\t\tt.Assert(s.Contains(3), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue(`[1,2,3]`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue([]int{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t})\n\n\t// Test with nil data map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s gset.TSet[int]\n\t\terr := s.UnmarshalValue([]int{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 3)\n\t})\n\n\t// Test error case with invalid JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue([]byte(`{invalid}`))\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// Test with empty array for string/bytes case\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue([]byte(`[]`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 0)\n\t})\n\n\t// Test with empty slice for default case\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSet[int]()\n\t\terr := s.UnmarshalValue([]int{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Size(), 0)\n\t})\n}\n\nfunc TestTSet_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := gset.NewTSetFrom[int]([]int{1, 2, 3}, true)\n\t\ts2 := s1.DeepCopy().(*gset.TSet[int])\n\t\tt.Assert(s1.Size(), s2.Size())\n\t\tt.Assert(s1.Contains(1), s2.Contains(1))\n\t\tt.Assert(s1.Contains(2), s2.Contains(2))\n\t\tt.Assert(s1.Contains(3), s2.Contains(3))\n\n\t\ts1.Add(4)\n\t\tt.Assert(s1.Size(), 4)\n\t\tt.Assert(s2.Size(), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s1 *gset.TSet[int]\n\t\ts2 := s1.DeepCopy()\n\t\tt.Assert(s2, nil)\n\t})\n}\n\nfunc TestTSet_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3}, true)\n\t\ts.LockFunc(func(m map[int]struct{}) {\n\t\t\tm[4] = struct{}{}\n\t\t})\n\t\tt.Assert(s.Size(), 4)\n\t\tt.Assert(s.Contains(4), true)\n\t})\n}\n\nfunc TestTSet_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gset.NewTSetFrom[int]([]int{1, 2, 3}, true)\n\t\tvar sum int\n\t\ts.RLockFunc(func(m map[int]struct{}) {\n\t\t\tfor k := range m {\n\t\t\t\tsum += k\n\t\t\t}\n\t\t})\n\t\tt.Assert(sum, 6)\n\t})\n}\n\nfunc Test_TSet_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tset := gset.NewTSet[*Student](true)\n\t\tvar s *Student = nil\n\t\texist := set.AddIfNotExist(s)\n\t\tt.Assert(exist, false)\n\n\t\tset2 := gset.NewTSet[*Student](true)\n\t\tset2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\texist2 := set2.AddIfNotExist(s)\n\t\tt.Assert(exist2, false)\n\t})\n}\n\nfunc Test_NewTSetWithChecker_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tset := gset.NewTSet[*Student](true)\n\t\tvar s *Student = nil\n\t\texist := set.AddIfNotExist(s)\n\t\tt.Assert(exist, false)\n\n\t\tset2 := gset.NewTSetWithChecker[*Student](func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\t\texist2 := set2.AddIfNotExist(s)\n\t\tt.Assert(exist2, false)\n\t})\n}\n"
  },
  {
    "path": "container/gtree/gtree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtree provides concurrent-safe/unsafe tree containers.\n//\n// Some implements are from: https://github.com/emirpasic/gods\npackage gtree\n\nimport \"github.com/gogf/gf/v2/container/gvar\"\n\n// iTree defines the interface for basic operations of a tree.\ntype iTree interface {\n\t// Set sets key-value pair into the tree.\n\tSet(key any, value any)\n\n\t// Sets batch sets key-values to the tree.\n\tSets(data map[any]any)\n\n\t// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n\t// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n\tSetIfNotExist(key any, value any) bool\n\n\t// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n\t// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n\tSetIfNotExistFunc(key any, f func() any) bool\n\n\t// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n\t// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n\t//\n\t// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n\t// it executes function `f` within mutex.Lock of the hash map.\n\tSetIfNotExistFuncLock(key any, f func() any) bool\n\n\t// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n\t//\n\t// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains\n\t// function to do so.\n\tGet(key any) (value any)\n\n\t// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n\t// this value.\n\tGetOrSet(key any, value any) any\n\n\t// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n\t// not exist and then returns this value.\n\tGetOrSetFunc(key any, f func() any) any\n\n\t// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it\n\t// does not exist and then returns this value.\n\t//\n\t// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex.Lock of the\n\t// hash map.\n\tGetOrSetFuncLock(key any, f func() any) any\n\n\t// GetVar returns a gvar.Var with the value by given `key`.\n\t// Note that, the returned gvar.Var is un-concurrent safe.\n\t//\n\t// Also see function Get.\n\tGetVar(key any) *gvar.Var\n\n\t// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n\t// Note that, the returned gvar.Var is un-concurrent safe.\n\t//\n\t// Also see function GetOrSet.\n\tGetVarOrSet(key any, value any) *gvar.Var\n\n\t// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n\t// Note that, the returned gvar.Var is un-concurrent safe.\n\t//\n\t// Also see function GetOrSetFunc.\n\tGetVarOrSetFunc(key any, f func() any) *gvar.Var\n\n\t// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n\t// Note that, the returned gvar.Var is un-concurrent safe.\n\t//\n\t// Also see function GetOrSetFuncLock.\n\tGetVarOrSetFuncLock(key any, f func() any) *gvar.Var\n\n\t// Search searches the tree with given `key`.\n\t// Second return parameter `found` is true if key was found, otherwise false.\n\tSearch(key any) (value any, found bool)\n\n\t// Contains checks and returns whether given `key` exists in the tree.\n\tContains(key any) bool\n\n\t// Size returns number of nodes in the tree.\n\tSize() int\n\n\t// IsEmpty returns true if tree does not contain any nodes.\n\tIsEmpty() bool\n\n\t// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n\t// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\n\tRemove(key any) (value any)\n\n\t// Removes batch deletes key-value pairs from the tree by `keys`.\n\tRemoves(keys []any)\n\n\t// Clear removes all nodes from the tree.\n\tClear()\n\n\t// Keys returns all keys from the tree in order by its comparator.\n\tKeys() []any\n\n\t// Values returns all values from the true in order by its comparator based on the key.\n\tValues() []any\n\n\t// Replace clears the data of the tree and sets the nodes by given `data`.\n\tReplace(data map[any]any)\n\n\t// Print prints the tree to stdout.\n\tPrint()\n\n\t// String returns a string representation of container\n\tString() string\n\n\t// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n\tMarshalJSON() (jsonBytes []byte, err error)\n\n\t// Map returns all key-value pairs as map.\n\tMap() map[any]any\n\n\t// MapStrAny returns all key-value items as map[string]any.\n\tMapStrAny() map[string]any\n\n\t// Iterator is alias of IteratorAsc.\n\t//\n\t// Also see IteratorAsc.\n\tIterator(f func(key, value any) bool)\n\n\t// IteratorFrom is alias of IteratorAscFrom.\n\t//\n\t// Also see IteratorAscFrom.\n\tIteratorFrom(key any, match bool, f func(key, value any) bool)\n\n\t// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n\t// If callback function `f` returns true, then it continues iterating; or false to stop.\n\tIteratorAsc(f func(key, value any) bool)\n\n\t// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n\t//\n\t// The parameter `key` specifies the start entry for iterating.\n\t// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using\n\t// index searching iterating.\n\t// If callback function `f` returns true, then it continues iterating; or false to stop.\n\tIteratorAscFrom(key any, match bool, f func(key, value any) bool)\n\n\t// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n\t//\n\t// If callback function `f` returns true, then it continues iterating; or false to stop.\n\tIteratorDesc(f func(key, value any) bool)\n\n\t// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n\t//\n\t// The parameter `key` specifies the start entry for iterating.\n\t// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using\n\t// index searching iterating.\n\t// If callback function `f` returns true, then it continues iterating; or false to stop.\n\tIteratorDescFrom(key any, match bool, f func(key, value any) bool)\n}\n\n// iteratorFromGetIndexT returns the index of the key in the keys slice.\n//\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched,\n// or else using index searching iterating.\n// If `isIterator` is true, iterator is available; or else not.\nfunc iteratorFromGetIndexT[T comparable](key T, keys []T, match bool) (index int, canIterator bool) {\n\tif match {\n\t\tfor i, k := range keys {\n\t\t\tif k == key {\n\t\t\t\tcanIterator = true\n\t\t\t\tindex = i\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif i, ok := any(key).(int); ok {\n\t\t\tcanIterator = true\n\t\t\tindex = i\n\t\t}\n\t}\n\treturn\n}\n\n// iteratorFromGetIndex returns the index of the key in the keys slice.\n//\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched,\n// or else using index searching iterating.\n// If `isIterator` is true, iterator is available; or else not.\nfunc iteratorFromGetIndex(key any, keys []any, match bool) (index int, canIterator bool) {\n\treturn iteratorFromGetIndexT(key, keys, match)\n}\n"
  },
  {
    "path": "container/gtree/gtree_avltree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar _ iTree = (*AVLTree)(nil)\n\n// AVLTree holds elements of the AVL tree.\ntype AVLTree struct {\n\t*AVLKVTree[any, any]\n\tonce sync.Once\n}\n\n// AVLTreeNode is a single element within the tree.\ntype AVLTreeNode = AVLKVTreeNode[any, any]\n\n// NewAVLTree instantiates an AVL tree with the custom key comparator.\n//\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewAVLTree(comparator func(v1, v2 any) int, safe ...bool) *AVLTree {\n\treturn &AVLTree{\n\t\tAVLKVTree: NewAVLKVTree[any, any](comparator, safe...),\n\t}\n}\n\n// NewAVLTreeFrom instantiates an AVL tree with the custom key comparator and data map.\n//\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\nfunc NewAVLTreeFrom(comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *AVLTree {\n\treturn &AVLTree{\n\t\tAVLKVTree: NewAVLKVTreeFrom(comparator, data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the tree.\nfunc (tree *AVLTree) lazyInit() {\n\ttree.once.Do(func() {\n\t\tif tree.AVLKVTree == nil {\n\t\t\ttree.AVLKVTree = NewAVLKVTree[any, any](gutil.ComparatorTStr, false)\n\t\t}\n\t})\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *AVLTree) Clone() *AVLTree {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\ttree.lazyInit()\n\treturn &AVLTree{\n\t\tAVLKVTree: tree.AVLKVTree.Clone(),\n\t}\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *AVLTree) Set(key any, value any) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Set(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *AVLTree) Sets(data map[any]any) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Sets(data)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *AVLTree) SetIfNotExist(key any, value any) bool {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *AVLTree) SetIfNotExistFunc(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *AVLTree) SetIfNotExistFuncLock(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.SetIfNotExistFuncLock(key, f)\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *AVLTree) Get(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Get(key)\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *AVLTree) GetOrSet(key any, value any) any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *AVLTree) GetOrSetFunc(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.\nfunc (tree *AVLTree) GetOrSetFuncLock(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *AVLTree) GetVar(key any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetVar(key)\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *AVLTree) GetVarOrSet(key any, value any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *AVLTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *AVLTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.GetVarOrSetFuncLock(key, f)\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *AVLTree) Search(key any) (value any, found bool) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Search(key)\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *AVLTree) Contains(key any) bool {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Contains(key)\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *AVLTree) Size() int {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Size()\n}\n\n// IsEmpty returns true if the tree does not contain any nodes.\nfunc (tree *AVLTree) IsEmpty() bool {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.IsEmpty()\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLTree) Remove(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Remove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *AVLTree) Removes(keys []any) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Removes(keys)\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *AVLTree) Clear() {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *AVLTree) Keys() []any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *AVLTree) Values() []any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *AVLTree) Replace(data map[any]any) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Replace(data)\n}\n\n// Print prints the tree to stdout.\nfunc (tree *AVLTree) Print() {\n\ttree.lazyInit()\n\ttree.AVLKVTree.Print()\n}\n\n// String returns a string representation of container.\nfunc (tree *AVLTree) String() string {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree *AVLTree) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.MarshalJSON()\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *AVLTree) Map() map[any]any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Map()\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *AVLTree) MapStrAny() map[string]any {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.MapStrAny()\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *AVLTree) Iterator(f func(key, value any) bool) {\n\ttree.IteratorAsc(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *AVLTree) IteratorFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLTree) IteratorAsc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.IteratorAsc(f)\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLTree) IteratorDesc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.IteratorDesc(f)\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.AVLKVTree.IteratorDescFrom(key, match, f)\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *AVLTree) Left() *AVLTreeNode {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Left()\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *AVLTree) Right() *AVLTreeNode {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Right()\n}\n\n// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.\n// The second returned parameter `found` is true if floor was found, otherwise false.\n//\n// Floor node is defined as the largest node that is smaller than or equal to the given node.\n// A floor node may not be found, either because the tree is empty, or because\n// all nodes in the tree is larger than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLTree) Floor(key any) (floor *AVLTreeNode, found bool) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Floor(key)\n}\n\n// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.\n// The second return parameter `found` is true if ceiling was found, otherwise false.\n//\n// Ceiling node is defined as the smallest node that is larger than or equal to the given node.\n// A ceiling node may not be found, either because the tree is empty, or because\n// all nodes in the tree is smaller than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLTree) Ceiling(key any) (ceiling *AVLTreeNode, found bool) {\n\ttree.lazyInit()\n\treturn tree.AVLKVTree.Ceiling(key)\n}\n\n// Flip exchanges key-value of the tree to value-key.\n// Note that you should guarantee the value is the same type as key,\n// or else the comparator would panic.\n//\n// If the type of value is different with key, you pass the new `comparator`.\nfunc (tree *AVLTree) Flip(comparator ...func(v1, v2 any) int) {\n\ttree.lazyInit()\n\n\tvar t = new(AVLTree)\n\tif len(comparator) > 0 {\n\t\tt = NewAVLTree(comparator[0], tree.mu.IsSafe())\n\t} else {\n\t\tt = NewAVLTree(tree.comparator, tree.mu.IsSafe())\n\t}\n\ttree.IteratorAsc(func(key, value any) bool {\n\t\tt.doSet(value, key)\n\t\treturn true\n\t})\n\ttree.Clear()\n\ttree.Sets(t.Map())\n}\n"
  },
  {
    "path": "container/gtree/gtree_btree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar _ iTree = (*BTree)(nil)\n\n// BTree holds elements of the B-tree.\ntype BTree struct {\n\t*BKVTree[any, any]\n\tonce sync.Once\n}\n\n// BTreeEntry represents the key-value pair contained within nodes.\ntype BTreeEntry = BKVTreeEntry[any, any]\n\n// NewBTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\n// Note that the `m` must be greater or equal than 3, or else it panics.\nfunc NewBTree(m int, comparator func(v1, v2 any) int, safe ...bool) *BTree {\n\treturn &BTree{\n\t\tBKVTree: NewBKVTree[any, any](m, comparator, safe...),\n\t}\n}\n\n// NewBTreeFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator and data map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewBTreeFrom(m int, comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *BTree {\n\treturn &BTree{\n\t\tBKVTree: NewBKVTreeFrom(m, comparator, data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the tree.\nfunc (tree *BTree) lazyInit() {\n\ttree.once.Do(func() {\n\t\tif tree.BKVTree == nil {\n\t\t\ttree.BKVTree = NewBKVTree[any, any](3, gutil.ComparatorTStr, false)\n\t\t}\n\t})\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *BTree) Clone() *BTree {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\ttree.lazyInit()\n\treturn &BTree{\n\t\tBKVTree: tree.BKVTree.Clone(),\n\t}\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *BTree) Set(key any, value any) {\n\ttree.lazyInit()\n\ttree.BKVTree.Set(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *BTree) Sets(data map[any]any) {\n\ttree.lazyInit()\n\ttree.BKVTree.Sets(data)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *BTree) SetIfNotExist(key any, value any) bool {\n\ttree.lazyInit()\n\treturn tree.BKVTree.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *BTree) SetIfNotExistFunc(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.BKVTree.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *BTree) SetIfNotExistFuncLock(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.BKVTree.SetIfNotExistFuncLock(key, f)\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *BTree) Get(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Get(key)\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *BTree) GetOrSet(key any, value any) any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *BTree) GetOrSetFunc(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.\nfunc (tree *BTree) GetOrSetFuncLock(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *BTree) GetVar(key any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetVar(key)\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *BTree) GetVarOrSet(key any, value any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *BTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *BTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.BKVTree.GetVarOrSetFuncLock(key, f)\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *BTree) Search(key any) (value any, found bool) {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Search(key)\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *BTree) Contains(key any) bool {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Contains(key)\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *BTree) Size() int {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Size()\n}\n\n// IsEmpty returns true if tree does not contain any nodes\nfunc (tree *BTree) IsEmpty() bool {\n\ttree.lazyInit()\n\treturn tree.BKVTree.IsEmpty()\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *BTree) Remove(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Remove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *BTree) Removes(keys []any) {\n\ttree.lazyInit()\n\ttree.BKVTree.Removes(keys)\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *BTree) Clear() {\n\ttree.lazyInit()\n\ttree.BKVTree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *BTree) Keys() []any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *BTree) Values() []any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *BTree) Replace(data map[any]any) {\n\ttree.lazyInit()\n\ttree.BKVTree.Replace(data)\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *BTree) Map() map[any]any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Map()\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *BTree) MapStrAny() map[string]any {\n\ttree.lazyInit()\n\treturn tree.BKVTree.MapStrAny()\n}\n\n// Print prints the tree to stdout.\nfunc (tree *BTree) Print() {\n\ttree.lazyInit()\n\ttree.BKVTree.Print()\n}\n\n// String returns a string representation of container (for debugging purposes)\nfunc (tree *BTree) String() string {\n\ttree.lazyInit()\n\treturn tree.BKVTree.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree *BTree) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.lazyInit()\n\treturn tree.BKVTree.MarshalJSON()\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *BTree) Iterator(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.Iterator(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *BTree) IteratorFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.IteratorFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BTree) IteratorAsc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.IteratorAsc(f)\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BTree) IteratorDesc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.IteratorDesc(f)\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.BKVTree.IteratorDescFrom(key, match, f)\n}\n\n// Height returns the height of the tree.\nfunc (tree *BTree) Height() int {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Height()\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *BTree) Left() *BTreeEntry {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Left()\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *BTree) Right() *BTreeEntry {\n\ttree.lazyInit()\n\treturn tree.BKVTree.Right()\n}\n"
  },
  {
    "path": "container/gtree/gtree_k_v_avltree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/emirpasic/gods/v2/trees/avltree\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// NilChecker is a function that checks whether the given value is nil.\ntype NilChecker[V any] func(V) bool\n\n// AVLKVTree holds elements of the AVL tree.\ntype AVLKVTree[K comparable, V any] struct {\n\tmu         rwmutex.RWMutex\n\tcomparator func(v1, v2 K) int\n\ttree       *avltree.Tree[K, V]\n\tnilChecker NilChecker[V]\n}\n\n// AVLKVTreeNode is a single element within the tree.\ntype AVLKVTreeNode[K comparable, V any] struct {\n\tKey   K\n\tValue V\n}\n\n// NewAVLKVTree instantiates an AVL tree with the custom key comparator.\n//\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewAVLKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *AVLKVTree[K, V] {\n\treturn &AVLKVTree[K, V]{\n\t\tmu:         rwmutex.Create(safe...),\n\t\tcomparator: comparator,\n\t\ttree:       avltree.NewWith[K, V](comparator),\n\t}\n}\n\n// NewAVLKVTreeWithChecker instantiates an AVL tree with the custom key comparator and nil checker.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewAVLKVTreeWithChecker[K comparable, V any](comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *AVLKVTree[K, V] {\n\tt := NewAVLKVTree[K, V](comparator, safe...)\n\tt.SetNilChecker(checker)\n\treturn t\n}\n\n// NewAVLKVTreeFrom instantiates an AVL tree with the custom key comparator and data map.\n//\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\nfunc NewAVLKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *AVLKVTree[K, V] {\n\ttree := NewAVLKVTree[K, V](comparator, safe...)\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n\treturn tree\n}\n\n// NewAVLKVTreeWithCheckerFrom instantiates an AVL tree with the custom key comparator, nil checker and data map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewAVLKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *AVLKVTree[K, V] {\n\ttree := NewAVLKVTreeWithChecker[K, V](comparator, checker, safe...)\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n\treturn tree\n}\n\n// SetNilChecker registers a custom nil checker function for the map values.\n// This function is used to determine if a value should be considered as nil.\n// The nil checker function takes a value of type V and returns a boolean indicating\n// whether the value should be treated as nil.\nfunc (tree *AVLKVTree[K, V]) SetNilChecker(nilChecker NilChecker[V]) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (tree *AVLKVTree[K, V]) isNil(v V) bool {\n\tif tree.nilChecker != nil {\n\t\treturn tree.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *AVLKVTree[K, V]) Clone() *AVLKVTree[K, V] {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\tnewTree := NewAVLKVTree[K, V](tree.comparator, tree.mu.IsSafe())\n\tnewTree.Sets(tree.Map())\n\treturn newTree\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *AVLKVTree[K, V]) Set(key K, value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.doSet(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *AVLKVTree[K, V]) Sets(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor key, value := range data {\n\t\ttree.doSet(key, value)\n\t}\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *AVLKVTree[K, V]) SetIfNotExist(key K, value V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, value)\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *AVLKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *AVLKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *AVLKVTree[K, V]) Get(key K) (value V) {\n\tvalue, _ = tree.Search(key)\n\treturn\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *AVLKVTree[K, V]) GetOrSet(key K, value V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, value)\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *AVLKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.\nfunc (tree *AVLKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *AVLKVTree[K, V]) GetVar(key K) *gvar.Var {\n\treturn gvar.New(tree.Get(key))\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *AVLKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSet(key, value))\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *AVLKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFunc(key, f))\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *AVLKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFuncLock(key, f))\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *AVLKVTree[K, V]) Search(key K) (value V, found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tif node, found := tree.doGet(key); found {\n\t\treturn node, true\n\t}\n\tfound = false\n\treturn\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *AVLKVTree[K, V]) Contains(key K) bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\t_, ok := tree.doGet(key)\n\treturn ok\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *AVLKVTree[K, V]) Size() int {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size()\n}\n\n// IsEmpty returns true if the tree does not contain any nodes.\nfunc (tree *AVLKVTree[K, V]) IsEmpty() bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size() == 0\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLKVTree[K, V]) Remove(key K) (value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\treturn tree.doRemove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *AVLKVTree[K, V]) Removes(keys []K) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor _, key := range keys {\n\t\ttree.doRemove(key)\n\t}\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *AVLKVTree[K, V]) Clear() {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *AVLKVTree[K, V]) Keys() []K {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *AVLKVTree[K, V]) Values() []V {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *AVLKVTree[K, V]) Replace(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n}\n\n// Print prints the tree to stdout.\nfunc (tree *AVLKVTree[K, V]) Print() {\n\tfmt.Println(tree.String())\n}\n\n// String returns a string representation of container.\nfunc (tree *AVLKVTree[K, V]) String() string {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn gstr.Replace(tree.tree.String(), \"AVLTree\\n\", \"\")\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree *AVLKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\n\telements := make(map[string]V)\n\tit := tree.tree.Iterator()\n\tfor it.Next() {\n\t\telements[gconv.String(it.Key())] = it.Value()\n\t}\n\treturn json.Marshal(&elements)\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *AVLKVTree[K, V]) Map() map[K]V {\n\tm := make(map[K]V, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[key] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *AVLKVTree[K, V]) MapStrAny() map[string]any {\n\tm := make(map[string]any, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[gconv.String(key)] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *AVLKVTree[K, V]) Iterator(f func(key K, value V) bool) {\n\ttree.IteratorAsc(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *AVLKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.Begin(); it.Next(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index < len(keys); index++ {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.End(); it.Prev(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *AVLKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index >= 0; index-- {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *AVLKVTree[K, V]) Left() *AVLKVTreeNode[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Left()\n\tif node == nil {\n\t\treturn nil\n\t}\n\treturn &AVLKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *AVLKVTree[K, V]) Right() *AVLKVTreeNode[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Right()\n\tif node == nil {\n\t\treturn nil\n\t}\n\treturn &AVLKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}\n}\n\n// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.\n// The second returned parameter `found` is true if floor was found, otherwise false.\n//\n// Floor node is defined as the largest node that is smaller than or equal to the given node.\n// A floor node may not be found, either because the tree is empty, or because\n// all nodes in the tree is larger than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLKVTree[K, V]) Floor(key K) (floor *AVLKVTreeNode[K, V], found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode, ok := tree.tree.Floor(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\treturn &AVLKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}, true\n}\n\n// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.\n// The second return parameter `found` is true if ceiling was found, otherwise false.\n//\n// Ceiling node is defined as the smallest node that is larger than or equal to the given node.\n// A ceiling node may not be found, either because the tree is empty, or because\n// all nodes in the tree is smaller than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLKVTree[K, V]) Ceiling(key K) (ceiling *AVLKVTreeNode[K, V], found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode, ok := tree.tree.Ceiling(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\treturn &AVLKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}, true\n}\n\n// Flip exchanges key-value of the tree to value-key.\n// Note that you should guarantee the value is the same type as key,\n// or else the comparator would panic.\n//\n// If the type of value is different with key, you pass the new `comparator`.\nfunc (tree *AVLKVTree[K, V]) Flip(comparator ...func(v1, v2 K) int) {\n\tvar t = new(AVLKVTree[K, V])\n\tif len(comparator) > 0 {\n\t\tt = NewAVLKVTree[K, V](comparator[0], tree.mu.IsSafe())\n\t} else {\n\t\tt = NewAVLKVTree[K, V](tree.comparator, tree.mu.IsSafe())\n\t}\n\tvar (\n\t\tnewKey   K\n\t\tnewValue V\n\t)\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tif err := gconv.Scan(key, &newValue); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := gconv.Scan(value, &newKey); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tt.doSet(newKey, newValue)\n\t\treturn true\n\t})\n\ttree.Clear()\n\ttree.Sets(t.Map())\n}\n\n// doSet inserts key-value pair node into the tree without lock.\n// If `key` already exists, then its value is updated with the new value.\n// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.\n//\n// It returns value with given `key`.\nfunc (tree *AVLKVTree[K, V]) doSet(key K, value V) V {\n\tif tree.isNil(value) {\n\t\treturn value\n\t}\n\ttree.tree.Put(key, value)\n\treturn value\n}\n\n// doGet retrieves and returns the value of given key from tree without lock.\nfunc (tree *AVLKVTree[K, V]) doGet(key K) (value V, found bool) {\n\treturn tree.tree.Get(key)\n}\n\n// doRemove removes key from tree and returns its associated value without lock.\n// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *AVLKVTree[K, V]) doRemove(key K) (value V) {\n\tvalue, _ = tree.tree.Get(key)\n\ttree.tree.Remove(key)\n\treturn\n}\n"
  },
  {
    "path": "container/gtree/gtree_k_v_btree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/emirpasic/gods/v2/trees/btree\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// BKVTree holds elements of the B-tree.\ntype BKVTree[K comparable, V any] struct {\n\tmu         rwmutex.RWMutex\n\tcomparator func(v1, v2 K) int\n\tm          int // order (maximum number of children)\n\ttree       *btree.Tree[K, V]\n\tnilChecker NilChecker[V]\n}\n\n// BKVTreeEntry represents the key-value pair contained within nodes.\ntype BKVTreeEntry[K comparable, V any] struct {\n\tKey   K\n\tValue V\n}\n\n// NewBKVTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\n// Note that the `m` must be greater or equal than 3, or else it panics.\nfunc NewBKVTree[K comparable, V any](m int, comparator func(v1, v2 K) int, safe ...bool) *BKVTree[K, V] {\n\treturn &BKVTree[K, V]{\n\t\tmu:         rwmutex.Create(safe...),\n\t\tm:          m,\n\t\tcomparator: comparator,\n\t\ttree:       btree.NewWith[K, V](m, comparator),\n\t}\n}\n\n// NewBKVTreeWithChecker instantiates a B-tree with `m` (maximum number of children), a custom key comparator and nil checker.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewBKVTreeWithChecker[K comparable, V any](m int, comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *BKVTree[K, V] {\n\tt := NewBKVTree[K, V](m, comparator, safe...)\n\tt.SetNilChecker(checker)\n\treturn t\n}\n\n// NewBKVTreeFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator and data map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewBKVTreeFrom[K comparable, V any](m int, comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *BKVTree[K, V] {\n\ttree := NewBKVTree[K, V](m, comparator, safe...)\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n\treturn tree\n}\n\n// NewBKVTreeWithCheckerFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator, nil checker and data map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewBKVTreeWithCheckerFrom[K comparable, V any](m int, comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *BKVTree[K, V] {\n\ttree := NewBKVTreeWithChecker[K, V](m, comparator, checker, safe...)\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n\treturn tree\n}\n\n// SetNilChecker registers a custom nil checker function for the map values.\n// This function is used to determine if a value should be considered as nil.\n// The nil checker function takes a value of type V and returns a boolean indicating\n// whether the value should be treated as nil.\nfunc (tree *BKVTree[K, V]) SetNilChecker(nilChecker NilChecker[V]) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (tree *BKVTree[K, V]) isNil(v V) bool {\n\tif tree.nilChecker != nil {\n\t\treturn tree.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *BKVTree[K, V]) Clone() *BKVTree[K, V] {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\tnewTree := NewBKVTree[K, V](tree.m, tree.comparator, tree.mu.IsSafe())\n\tnewTree.Sets(tree.Map())\n\treturn newTree\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *BKVTree[K, V]) Set(key K, value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.doSet(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *BKVTree[K, V]) Sets(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *BKVTree[K, V]) SetIfNotExist(key K, value V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, value)\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *BKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *BKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *BKVTree[K, V]) Get(key K) (value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tvalue, _ = tree.doGet(key)\n\treturn\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *BKVTree[K, V]) GetOrSet(key K, value V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, value)\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *BKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.\nfunc (tree *BKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *BKVTree[K, V]) GetVar(key K) *gvar.Var {\n\treturn gvar.New(tree.Get(key))\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *BKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSet(key, value))\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *BKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFunc(key, f))\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *BKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFuncLock(key, f))\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *BKVTree[K, V]) Search(key K) (value V, found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Get(key)\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *BKVTree[K, V]) Contains(key K) bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\t_, ok := tree.doGet(key)\n\treturn ok\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *BKVTree[K, V]) Size() int {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size()\n}\n\n// IsEmpty returns true if tree does not contain any nodes\nfunc (tree *BKVTree[K, V]) IsEmpty() bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size() == 0\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *BKVTree[K, V]) Remove(key K) (value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\treturn tree.doRemove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *BKVTree[K, V]) Removes(keys []K) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor _, key := range keys {\n\t\ttree.doRemove(key)\n\t}\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *BKVTree[K, V]) Clear() {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *BKVTree[K, V]) Keys() []K {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *BKVTree[K, V]) Values() []V {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *BKVTree[K, V]) Replace(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *BKVTree[K, V]) Map() map[K]V {\n\tm := make(map[K]V, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[key] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *BKVTree[K, V]) MapStrAny() map[string]any {\n\tm := make(map[string]any, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[gconv.String(key)] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// Print prints the tree to stdout.\nfunc (tree *BKVTree[K, V]) Print() {\n\tfmt.Println(tree.String())\n}\n\n// String returns a string representation of container (for debugging purposes)\nfunc (tree *BKVTree[K, V]) String() string {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn gstr.Replace(tree.tree.String(), \"BTree\\n\", \"\")\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree *BKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\n\telements := make(map[string]V)\n\tit := tree.tree.Iterator()\n\tfor it.Next() {\n\t\telements[gconv.String(it.Key())] = it.Value()\n\t}\n\treturn json.Marshal(&elements)\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *BKVTree[K, V]) Iterator(f func(key K, value V) bool) {\n\ttree.IteratorAsc(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *BKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.Begin(); it.Next(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index < len(keys); index++ {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.End(); it.Prev(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *BKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index >= 0; index-- {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// Height returns the height of the tree.\nfunc (tree *BKVTree[K, V]) Height() int {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Height()\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *BKVTree[K, V]) Left() *BKVTreeEntry[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Left()\n\tif node == nil || node.Entries == nil || len(node.Entries) == 0 {\n\t\treturn nil\n\t}\n\treturn &BKVTreeEntry[K, V]{\n\t\tKey:   node.Entries[0].Key,\n\t\tValue: node.Entries[0].Value,\n\t}\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *BKVTree[K, V]) Right() *BKVTreeEntry[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Right()\n\tif node == nil || node.Entries == nil || len(node.Entries) == 0 {\n\t\treturn nil\n\t}\n\treturn &BKVTreeEntry[K, V]{\n\t\tKey:   node.Entries[len(node.Entries)-1].Key,\n\t\tValue: node.Entries[len(node.Entries)-1].Value,\n\t}\n}\n\n// doSet inserts key-value pair node into the tree without lock.\n// If `key` already exists, then its value is updated with the new value.\n// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.\n//\n// It returns value with given `key`.\nfunc (tree *BKVTree[K, V]) doSet(key K, value V) V {\n\tif tree.isNil(value) {\n\t\treturn value\n\t}\n\ttree.tree.Put(key, value)\n\treturn value\n}\n\n// doGet get the value from the tree by key without lock.\nfunc (tree *BKVTree[K, V]) doGet(key K) (value V, ok bool) {\n\treturn tree.tree.Get(key)\n}\n\n// doRemove removes key from tree and returns its associated value without lock.\n// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *BKVTree[K, V]) doRemove(key K) (value V) {\n\tvalue, _ = tree.tree.Get(key)\n\ttree.tree.Remove(key)\n\treturn\n}\n"
  },
  {
    "path": "container/gtree/gtree_k_v_redblacktree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/emirpasic/gods/v2/trees/redblacktree\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RedBlackKVTree holds elements of the red-black tree.\ntype RedBlackKVTree[K comparable, V any] struct {\n\tmu         rwmutex.RWMutex\n\tcomparator func(v1, v2 K) int\n\ttree       *redblacktree.Tree[K, V]\n\tnilChecker NilChecker[V]\n}\n\n// RedBlackKVTreeNode is a single element within the tree.\ntype RedBlackKVTreeNode[K comparable, V any] struct {\n\tKey   K\n\tValue V\n}\n\n// NewRedBlackKVTree instantiates a red-black tree with the custom key comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewRedBlackKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *RedBlackKVTree[K, V] {\n\tvar tree RedBlackKVTree[K, V]\n\tRedBlackKVTreeInit(&tree, comparator, safe...)\n\treturn &tree\n}\n\n// NewRedBlackKVTreeWithChecker instantiates a red-black tree with the custom key comparator and `nilChecker`.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewRedBlackKVTreeWithChecker[K comparable, V any](comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *RedBlackKVTree[K, V] {\n\tt := NewRedBlackKVTree[K, V](comparator, safe...)\n\tt.SetNilChecker(checker)\n\treturn t\n}\n\n// NewRedBlackKVTreeFrom instantiates a red-black tree with the custom key comparator and `data` map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewRedBlackKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *RedBlackKVTree[K, V] {\n\tvar tree RedBlackKVTree[K, V]\n\tRedBlackKVTreeInitFrom(&tree, comparator, data, safe...)\n\treturn &tree\n}\n\n// NewRedBlackKVTreeWithCheckerFrom instantiates a red-black tree with the custom key comparator, `data` map and `nilChecker`.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.\n// The parameter `checker` is used to specify whether the given value is nil.\nfunc NewRedBlackKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *RedBlackKVTree[K, V] {\n\tt := NewRedBlackKVTreeWithChecker[K, V](comparator, checker, safe...)\n\tfor k, v := range data {\n\t\tt.doSet(k, v)\n\t}\n\treturn t\n}\n\n// RedBlackKVTreeInit instantiates a red-black tree with the custom key comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc RedBlackKVTreeInit[K comparable, V any](tree *RedBlackKVTree[K, V], comparator func(v1, v2 K) int, safe ...bool) {\n\tif tree == nil {\n\t\treturn\n\t}\n\ttree.mu = rwmutex.Create(safe...)\n\ttree.comparator = comparator\n\ttree.tree = redblacktree.NewWith[K, V](comparator)\n}\n\n// RedBlackKVTreeInitFrom instantiates a red-black tree with the custom key comparator and `data` map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc RedBlackKVTreeInitFrom[K comparable, V any](tree *RedBlackKVTree[K, V], comparator func(v1, v2 K) int, data map[K]V, safe ...bool) {\n\tif tree == nil {\n\t\treturn\n\t}\n\tRedBlackKVTreeInit(tree, comparator, safe...)\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n}\n\n// SetNilChecker registers a custom nil checker function for the map values.\n// This function is used to determine if a value should be considered as nil.\n// The nil checker function takes a value of type V and returns a boolean indicating\n// whether the value should be treated as nil.\nfunc (tree *RedBlackKVTree[K, V]) SetNilChecker(nilChecker NilChecker[V]) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.nilChecker = nilChecker\n}\n\n// isNil checks whether the given value is nil.\n// It first checks if a custom nil checker function is registered and uses it if available,\n// otherwise it falls back to the default empty.IsNil function.\nfunc (tree *RedBlackKVTree[K, V]) isNil(v V) bool {\n\tif tree.nilChecker != nil {\n\t\treturn tree.nilChecker(v)\n\t}\n\treturn empty.IsNil(v)\n}\n\n// SetComparator sets/changes the comparator for sorting.\nfunc (tree *RedBlackKVTree[K, V]) SetComparator(comparator func(a, b K) int) {\n\ttree.comparator = comparator\n\tif tree.tree == nil {\n\t\ttree.tree = redblacktree.NewWith[K, V](comparator)\n\t}\n\tsize := tree.tree.Size()\n\tif size > 0 {\n\t\tm := tree.Map()\n\t\ttree.Sets(m)\n\t}\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *RedBlackKVTree[K, V]) Clone() *RedBlackKVTree[K, V] {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\tnewTree := NewRedBlackKVTree[K, V](tree.comparator, tree.mu.IsSafe())\n\tnewTree.Sets(tree.Map())\n\treturn newTree\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *RedBlackKVTree[K, V]) Set(key K, value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.doSet(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *RedBlackKVTree[K, V]) Sets(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor key, value := range data {\n\t\ttree.doSet(key, value)\n\t}\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *RedBlackKVTree[K, V]) SetIfNotExist(key K, value V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, value)\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *RedBlackKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *RedBlackKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif _, ok := tree.doGet(key); !ok {\n\t\ttree.doSet(key, f())\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *RedBlackKVTree[K, V]) Get(key K) (value V) {\n\tvalue, _ = tree.Search(key)\n\treturn\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *RedBlackKVTree[K, V]) GetOrSet(key K, value V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, value)\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *RedBlackKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.\nfunc (tree *RedBlackKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif v, ok := tree.doGet(key); !ok {\n\t\treturn tree.doSet(key, f())\n\t} else {\n\t\treturn v\n\t}\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *RedBlackKVTree[K, V]) GetVar(key K) *gvar.Var {\n\treturn gvar.New(tree.Get(key))\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *RedBlackKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSet(key, value))\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *RedBlackKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFunc(key, f))\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *RedBlackKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {\n\treturn gvar.New(tree.GetOrSetFuncLock(key, f))\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *RedBlackKVTree[K, V]) Search(key K) (value V, found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tif node, found := tree.doGet(key); found {\n\t\treturn node, true\n\t}\n\tfound = false\n\treturn\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *RedBlackKVTree[K, V]) Contains(key K) bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\t_, ok := tree.doGet(key)\n\treturn ok\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *RedBlackKVTree[K, V]) Size() int {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size()\n}\n\n// IsEmpty returns true if tree does not contain any nodes.\nfunc (tree *RedBlackKVTree[K, V]) IsEmpty() bool {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Size() == 0\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackKVTree[K, V]) Remove(key K) (value V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\treturn tree.doRemove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *RedBlackKVTree[K, V]) Removes(keys []K) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tfor _, key := range keys {\n\t\ttree.doRemove(key)\n\t}\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *RedBlackKVTree[K, V]) Clear() {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *RedBlackKVTree[K, V]) Keys() []K {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *RedBlackKVTree[K, V]) Values() []V {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn tree.tree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *RedBlackKVTree[K, V]) Replace(data map[K]V) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\ttree.tree.Clear()\n\tfor k, v := range data {\n\t\ttree.doSet(k, v)\n\t}\n}\n\n// Print prints the tree to stdout.\nfunc (tree *RedBlackKVTree[K, V]) Print() {\n\tfmt.Println(tree.String())\n}\n\n// String returns a string representation of container\nfunc (tree *RedBlackKVTree[K, V]) String() string {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\treturn gstr.Replace(tree.tree.String(), \"RedBlackTree\\n\", \"\")\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree RedBlackKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\n\telements := make(map[string]V)\n\tit := tree.tree.Iterator()\n\tfor it.Next() {\n\t\telements[gconv.String(it.Key())] = it.Value()\n\t}\n\treturn json.Marshal(&elements)\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *RedBlackKVTree[K, V]) Map() map[K]V {\n\tm := make(map[K]V, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[key] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *RedBlackKVTree[K, V]) MapStrAny() map[string]any {\n\tm := make(map[string]any, tree.Size())\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tm[gconv.String(key)] = value\n\t\treturn true\n\t})\n\treturn m\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *RedBlackKVTree[K, V]) Iterator(f func(key K, value V) bool) {\n\ttree.IteratorAsc(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *RedBlackKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.Begin(); it.Next(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index < len(keys); index++ {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar (\n\t\tok bool\n\t\tit = tree.tree.Iterator()\n\t)\n\tfor it.End(); it.Prev(); {\n\t\tindex, value := it.Key(), it.Value()\n\t\tif ok = f(index, value); !ok {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tvar keys = tree.tree.Keys()\n\tindex, canIterator := iteratorFromGetIndexT(key, keys, match)\n\tif !canIterator {\n\t\treturn\n\t}\n\tfor ; index >= 0; index-- {\n\t\tf(keys[index], tree.Get(keys[index]))\n\t}\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *RedBlackKVTree[K, V]) Left() *RedBlackKVTreeNode[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Left()\n\tif node == nil {\n\t\treturn nil\n\t}\n\treturn &RedBlackKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *RedBlackKVTree[K, V]) Right() *RedBlackKVTreeNode[K, V] {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode := tree.tree.Right()\n\tif node == nil {\n\t\treturn nil\n\t}\n\treturn &RedBlackKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}\n}\n\n// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.\n// The second returned parameter `found` is true if floor was found, otherwise false.\n//\n// Floor node is defined as the largest node that is smaller than or equal to the given node.\n// A floor node may not be found, either because the tree is empty, or because\n// all nodes in the tree is larger than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackKVTree[K, V]) Floor(key K) (floor *RedBlackKVTreeNode[K, V], found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode, found := tree.tree.Floor(key)\n\tif !found {\n\t\treturn nil, false\n\t}\n\treturn &RedBlackKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}, true\n}\n\n// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.\n// The second return parameter `found` is true if ceiling was found, otherwise false.\n//\n// Ceiling node is defined as the smallest node that is larger than or equal to the given node.\n// A ceiling node may not be found, either because the tree is empty, or because\n// all nodes in the tree is smaller than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackKVTree[K, V]) Ceiling(key K) (ceiling *RedBlackKVTreeNode[K, V], found bool) {\n\ttree.mu.RLock()\n\tdefer tree.mu.RUnlock()\n\tnode, found := tree.tree.Ceiling(key)\n\tif !found {\n\t\treturn nil, false\n\t}\n\treturn &RedBlackKVTreeNode[K, V]{\n\t\tKey:   node.Key,\n\t\tValue: node.Value,\n\t}, true\n}\n\n// Flip exchanges key-value of the tree to value-key.\n// Note that you should guarantee the value is the same type as key,\n// or else the comparator would panic.\n//\n// If the type of value is different with key, you pass the new `comparator`.\nfunc (tree *RedBlackKVTree[K, V]) Flip(comparator ...func(v1, v2 K) int) {\n\tvar t = new(RedBlackKVTree[K, V])\n\tif len(comparator) > 0 {\n\t\tt = NewRedBlackKVTree[K, V](comparator[0], tree.mu.IsSafe())\n\t} else {\n\t\tt = NewRedBlackKVTree[K, V](tree.comparator, tree.mu.IsSafe())\n\t}\n\tvar (\n\t\tnewKey   K\n\t\tnewValue V\n\t)\n\ttree.IteratorAsc(func(key K, value V) bool {\n\t\tif err := gconv.Scan(key, &newValue); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif err := gconv.Scan(value, &newKey); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tt.doSet(newKey, newValue)\n\t\treturn true\n\t})\n\ttree.Clear()\n\ttree.Sets(t.Map())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (tree *RedBlackKVTree[K, V]) UnmarshalJSON(b []byte) (err error) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif tree.comparator == nil {\n\t\ttree.comparator = gutil.ComparatorTStr[K]\n\t\ttree.tree = redblacktree.NewWith[K, V](tree.comparator)\n\t}\n\tvar data map[string]any\n\tif err := json.UnmarshalUseNumber(b, &data); err != nil {\n\t\treturn err\n\t}\n\tvar m = make(map[K]V)\n\tif err = gconv.Scan(data, &m); err != nil {\n\t\treturn\n\t}\n\tfor k, v := range m {\n\t\ttree.doSet(k, v)\n\t}\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (tree *RedBlackKVTree[K, V]) UnmarshalValue(value any) (err error) {\n\ttree.mu.Lock()\n\tdefer tree.mu.Unlock()\n\tif tree.comparator == nil {\n\t\ttree.comparator = gutil.ComparatorTStr[K]\n\t\ttree.tree = redblacktree.NewWith[K, V](tree.comparator)\n\t}\n\tvar m = make(map[K]V)\n\tif err = gconv.Scan(value, &m); err != nil {\n\t\treturn\n\t}\n\tfor k, v := range m {\n\t\ttree.doSet(k, v)\n\t}\n\treturn\n}\n\n// doSet inserts key-value pair node into the tree without lock.\n// If `key` already exists, then its value is updated with the new value.\n// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.\n//\n// It returns value with given `key`.\nfunc (tree *RedBlackKVTree[K, V]) doSet(key K, value V) (ret V) {\n\tif tree.isNil(value) {\n\t\treturn\n\t}\n\ttree.tree.Put(key, value)\n\treturn value\n}\n\n// doGet retrieves and returns the value of given key from tree without lock.\nfunc (tree *RedBlackKVTree[K, V]) doGet(key K) (value V, found bool) {\n\treturn tree.tree.Get(key)\n}\n\n// doRemove removes key from tree and returns its associated value without lock.\n// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackKVTree[K, V]) doRemove(key K) (value V) {\n\tvalue, _ = tree.tree.Get(key)\n\ttree.tree.Remove(key)\n\treturn\n}\n"
  },
  {
    "path": "container/gtree/gtree_redblacktree.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar _ iTree = (*RedBlackTree)(nil)\n\n// RedBlackTree holds elements of the red-black tree.\ntype RedBlackTree struct {\n\t*RedBlackKVTree[any, any]\n\tonce sync.Once\n}\n\n// RedBlackTreeNode is a single element within the tree.\ntype RedBlackTreeNode = RedBlackKVTreeNode[any, any]\n\n// NewRedBlackTree instantiates a red-black tree with the custom key comparator.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewRedBlackTree(comparator func(v1, v2 any) int, safe ...bool) *RedBlackTree {\n\treturn &RedBlackTree{\n\t\tRedBlackKVTree: NewRedBlackKVTree[any, any](comparator, safe...),\n\t}\n}\n\n// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and `data` map.\n// The parameter `safe` is used to specify whether using tree in concurrent-safety,\n// which is false in default.\nfunc NewRedBlackTreeFrom(comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *RedBlackTree {\n\treturn &RedBlackTree{\n\t\tRedBlackKVTree: NewRedBlackKVTreeFrom(comparator, data, safe...),\n\t}\n}\n\n// lazyInit lazily initializes the tree.\nfunc (tree *RedBlackTree) lazyInit() {\n\ttree.once.Do(func() {\n\t\tif tree.RedBlackKVTree == nil {\n\t\t\ttree.RedBlackKVTree = NewRedBlackKVTree[any, any](gutil.ComparatorTStr[any], false)\n\t\t}\n\t})\n}\n\n// SetComparator sets/changes the comparator for sorting.\nfunc (tree *RedBlackTree) SetComparator(comparator func(a, b any) int) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.SetComparator(comparator)\n}\n\n// Clone clones and returns a new tree from current tree.\nfunc (tree *RedBlackTree) Clone() *RedBlackTree {\n\tif tree == nil {\n\t\treturn nil\n\t}\n\ttree.lazyInit()\n\treturn &RedBlackTree{\n\t\tRedBlackKVTree: tree.RedBlackKVTree.Clone(),\n\t}\n}\n\n// Set sets key-value pair into the tree.\nfunc (tree *RedBlackTree) Set(key any, value any) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Set(key, value)\n}\n\n// Sets batch sets key-values to the tree.\nfunc (tree *RedBlackTree) Sets(data map[any]any) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Sets(data)\n}\n\n// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *RedBlackTree) SetIfNotExist(key any, value any) bool {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.SetIfNotExist(key, value)\n}\n\n// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\nfunc (tree *RedBlackTree) SetIfNotExistFunc(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.SetIfNotExistFunc(key, f)\n}\n\n// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.\n// It returns false if `key` exists, and such setting key-value pair operation would be ignored.\n//\n// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that\n// it executes function `f` within mutex lock.\nfunc (tree *RedBlackTree) SetIfNotExistFuncLock(key any, f func() any) bool {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.SetIfNotExistFuncLock(key, f)\n}\n\n// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.\n//\n// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function\n// to do so.\nfunc (tree *RedBlackTree) Get(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Get(key)\n}\n\n// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns\n// this value.\nfunc (tree *RedBlackTree) GetOrSet(key any, value any) any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetOrSet(key, value)\n}\n\n// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not\n// exist and then returns this value.\nfunc (tree *RedBlackTree) GetOrSetFunc(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetOrSetFunc(key, f)\n}\n\n// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does\n// not exist and then returns this value.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`within mutex lock.\nfunc (tree *RedBlackTree) GetOrSetFuncLock(key any, f func() any) any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetOrSetFuncLock(key, f)\n}\n\n// GetVar returns a gvar.Var with the value by given `key`.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function Get.\nfunc (tree *RedBlackTree) GetVar(key any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetVar(key)\n}\n\n// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSet.\nfunc (tree *RedBlackTree) GetVarOrSet(key any, value any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetVarOrSet(key, value)\n}\n\n// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFunc.\nfunc (tree *RedBlackTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetVarOrSetFunc(key, f)\n}\n\n// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.\n// Note that, the returned gvar.Var is un-concurrent safe.\n//\n// Also see function GetOrSetFuncLock.\nfunc (tree *RedBlackTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.GetVarOrSetFuncLock(key, f)\n}\n\n// Search searches the tree with given `key`.\n// Second return parameter `found` is true if key was found, otherwise false.\nfunc (tree *RedBlackTree) Search(key any) (value any, found bool) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Search(key)\n}\n\n// Contains checks and returns whether given `key` exists in the tree.\nfunc (tree *RedBlackTree) Contains(key any) bool {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Contains(key)\n}\n\n// Size returns number of nodes in the tree.\nfunc (tree *RedBlackTree) Size() int {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Size()\n}\n\n// IsEmpty returns true if tree does not contain any nodes.\nfunc (tree *RedBlackTree) IsEmpty() bool {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.IsEmpty()\n}\n\n// Remove removes the node from the tree by `key`, and returns its associated value of `key`.\n// The given `key` should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackTree) Remove(key any) (value any) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Remove(key)\n}\n\n// Removes batch deletes key-value pairs from the tree by `keys`.\nfunc (tree *RedBlackTree) Removes(keys []any) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Removes(keys)\n}\n\n// Clear removes all nodes from the tree.\nfunc (tree *RedBlackTree) Clear() {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Clear()\n}\n\n// Keys returns all keys from the tree in order by its comparator.\nfunc (tree *RedBlackTree) Keys() []any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Keys()\n}\n\n// Values returns all values from the true in order by its comparator based on the key.\nfunc (tree *RedBlackTree) Values() []any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Values()\n}\n\n// Replace clears the data of the tree and sets the nodes by given `data`.\nfunc (tree *RedBlackTree) Replace(data map[any]any) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Replace(data)\n}\n\n// Print prints the tree to stdout.\nfunc (tree *RedBlackTree) Print() {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Print()\n}\n\n// String returns a string representation of container\nfunc (tree *RedBlackTree) String() string {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.String()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (tree RedBlackTree) MarshalJSON() (jsonBytes []byte, err error) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.MarshalJSON()\n}\n\n// Map returns all key-value pairs as map.\nfunc (tree *RedBlackTree) Map() map[any]any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Map()\n}\n\n// MapStrAny returns all key-value items as map[string]any.\nfunc (tree *RedBlackTree) MapStrAny() map[string]any {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.MapStrAny()\n}\n\n// Iterator is alias of IteratorAsc.\n//\n// Also see IteratorAsc.\nfunc (tree *RedBlackTree) Iterator(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.Iterator(f)\n}\n\n// IteratorFrom is alias of IteratorAscFrom.\n//\n// Also see IteratorAscFrom.\nfunc (tree *RedBlackTree) IteratorFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.IteratorFrom(key, match, f)\n}\n\n// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackTree) IteratorAsc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.IteratorAsc(f)\n}\n\n// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.IteratorAscFrom(key, match, f)\n}\n\n// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.\n//\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackTree) IteratorDesc(f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.IteratorDesc(f)\n}\n\n// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.\n//\n// The parameter `key` specifies the start entry for iterating.\n// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index\n// searching iterating.\n// If callback function `f` returns true, then it continues iterating; or false to stop.\nfunc (tree *RedBlackTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {\n\ttree.lazyInit()\n\ttree.RedBlackKVTree.IteratorDescFrom(key, match, f)\n}\n\n// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *RedBlackTree) Left() *RedBlackTreeNode {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Left()\n}\n\n// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.\nfunc (tree *RedBlackTree) Right() *RedBlackTreeNode {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Right()\n}\n\n// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.\n// The second returned parameter `found` is true if floor was found, otherwise false.\n//\n// Floor node is defined as the largest node that is smaller than or equal to the given node.\n// A floor node may not be found, either because the tree is empty, or because\n// all nodes in the tree is larger than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackTree) Floor(key any) (floor *RedBlackTreeNode, found bool) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Floor(key)\n}\n\n// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.\n// The second return parameter `found` is true if ceiling was found, otherwise false.\n//\n// Ceiling node is defined as the smallest node that is larger than or equal to the given node.\n// A ceiling node may not be found, either because the tree is empty, or because\n// all nodes in the tree is smaller than the given node.\n//\n// Key should adhere to the comparator's type assertion, otherwise method panics.\nfunc (tree *RedBlackTree) Ceiling(key any) (ceiling *RedBlackTreeNode, found bool) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.Ceiling(key)\n}\n\n// Flip exchanges key-value of the tree to value-key.\n// Note that you should guarantee the value is the same type as key,\n// or else the comparator would panic.\n//\n// If the type of value is different with key, you pass the new `comparator`.\nfunc (tree *RedBlackTree) Flip(comparator ...func(v1, v2 any) int) {\n\ttree.lazyInit()\n\tvar t = new(RedBlackTree)\n\tif len(comparator) > 0 {\n\t\tt = NewRedBlackTree(comparator[0], tree.mu.IsSafe())\n\t} else {\n\t\tt = NewRedBlackTree(tree.comparator, tree.mu.IsSafe())\n\t}\n\ttree.IteratorAsc(func(key, value any) bool {\n\t\tt.doSet(value, key)\n\t\treturn true\n\t})\n\ttree.Clear()\n\ttree.Sets(t.Map())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (tree *RedBlackTree) UnmarshalJSON(b []byte) error {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.UnmarshalJSON(b)\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for map.\nfunc (tree *RedBlackTree) UnmarshalValue(value any) (err error) {\n\ttree.lazyInit()\n\treturn tree.RedBlackKVTree.UnmarshalValue(value)\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_avl_tree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_AVLTree_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Sets(map[any]any{\"key3\": \"val3\", \"key1\": \"val1\"})\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Flip(gutil.ComparatorString)\n\t\tt.Assert(m.Map(), map[any]any{\"key3\": \"val3\", \"key1\": \"val1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gtree.NewAVLTreeFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_AVLTree_Set_Fun(t *testing.T) {\n\t//GetOrSetFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\t//SetIfNotExistFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\n}\n\nfunc Test_AVLTree_Get_Set_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), true)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), false)\n\t\tt.AssertEQ(m.GetVarOrSet(\"key1\", \"val1\"), gvar.New(\"val1\", true))\n\t\tt.AssertEQ(m.GetVar(\"key1\"), gvar.New(\"val1\", true))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t})\n}\n\nfunc Test_AVLTree_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTree(gutil.ComparatorString)\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_AVLTree_Iterator(t *testing.T) {\n\n\tkeys := []string{\"1\", \"key1\", \"key2\", \"key3\", \"key4\"}\n\tkeyLen := len(keys)\n\tindex := 0\n\n\texpect := map[any]any{\"key4\": \"val4\", 1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\n\tm := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(k, keys[index])\n\t\t\tindex++\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tindex--\n\t\t\tt.Assert(k, keys[index])\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t})\n\n\tm.Print()\n\t// 断言返回值对遍历控制\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n\n}\n\nfunc Test_AVLTree_IteratorFrom(t *testing.T) {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 10; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn := 5\n\t\ttree.IteratorFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(n, key)\n\t\t\tt.Assert(n*10, value)\n\t\t\tn++\n\t\t\treturn true\n\t\t})\n\n\t\ti := 5\n\t\ttree.IteratorAscFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(i, key)\n\t\t\tt.Assert(i*10, value)\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\n\t\tj := 5\n\t\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(j, key)\n\t\t\tt.Assert(j*10, value)\n\t\t\tj--\n\t\t\treturn true\n\t\t})\n\t})\n}\n\nfunc Test_AVLTree_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//clone 方法是深克隆\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t//修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t//修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_AVLTree_LRNode(t *testing.T) {\n\texpect := map[any]any{\"key4\": \"val4\", \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\t//safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n\t//unsafe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect, true)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n}\n\nfunc Test_AVLTree_CeilingFloor(t *testing.T) {\n\texpect := map[any]any{\n\t\t20: \"val20\",\n\t\t6:  \"val6\",\n\t\t10: \"val10\",\n\t\t12: \"val12\",\n\t\t1:  \"val1\",\n\t\t15: \"val15\",\n\t\t19: \"val19\",\n\t\t8:  \"val8\",\n\t\t4:  \"val4\"}\n\t//found and eq\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(8)\n\t\tt.Assert(cf, true)\n\t\tt.Assert(c.Value, \"val8\")\n\t\tf, ff := m.Floor(20)\n\t\tt.Assert(ff, true)\n\t\tt.Assert(f.Value, \"val20\")\n\t})\n\t//found and neq\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(9)\n\t\tt.Assert(cf, true)\n\t\tt.Assert(c.Value, \"val10\")\n\t\tf, ff := m.Floor(5)\n\t\tt.Assert(ff, true)\n\t\tt.Assert(f.Value, \"val4\")\n\t})\n\t//nofound\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(21)\n\t\tt.Assert(cf, false)\n\t\tt.Assert(c, nil)\n\t\tf, ff := m.Floor(-1)\n\t\tt.Assert(ff, false)\n\t\tt.Assert(f, nil)\n\t})\n}\n\nfunc Test_AVLTree_Remove(t *testing.T) {\n\tm := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i <= 50; i++ {\n\t\tm.Set(i, fmt.Sprintf(\"val%d\", i))\n\t}\n\texpect := m.Map()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range expect {\n\t\t\tm1 := m.Clone()\n\t\t\tt.Assert(m1.Remove(k), v)\n\t\t\tt.Assert(m1.Remove(k), nil)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_b_tree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_BTree_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tm.Set(\"key1\", \"val1\")\n\n\t\tt.Assert(m.Height(), 1)\n\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gtree.NewBTreeFrom(3, gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_BTree_Set_Fun(t *testing.T) {\n\t//GetOrSetFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\t//SetIfNotExistFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\n}\n\nfunc Test_BTree_Get_Set_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), true)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), false)\n\t\tt.AssertEQ(m.GetVarOrSet(\"key1\", \"val1\"), gvar.New(\"val1\", true))\n\t\tt.AssertEQ(m.GetVar(\"key1\"), gvar.New(\"val1\", true))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t})\n}\n\nfunc Test_BTree_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTree(3, gutil.ComparatorString)\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_BTree_Iterator(t *testing.T) {\n\tkeys := []string{\"1\", \"key1\", \"key2\", \"key3\", \"key4\"}\n\tkeyLen := len(keys)\n\tindex := 0\n\n\texpect := map[any]any{\"key4\": \"val4\", 1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\n\tm := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(k, keys[index])\n\t\t\tindex++\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tindex--\n\t\t\tt.Assert(k, keys[index])\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t})\n\n\tm.Print()\n\t// 断言返回值对遍历控制\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_BTree_IteratorFrom(t *testing.T) {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 10; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn := 5\n\t\ttree.IteratorFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(n, key)\n\t\t\tt.Assert(n*10, value)\n\t\t\tn++\n\t\t\treturn true\n\t\t})\n\n\t\ti := 5\n\t\ttree.IteratorAscFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(i, key)\n\t\t\tt.Assert(i*10, value)\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\n\t\tj := 5\n\t\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(j, key)\n\t\t\tt.Assert(j*10, value)\n\t\t\tj--\n\t\t\treturn true\n\t\t})\n\t})\n}\n\nfunc Test_BTree_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//clone 方法是深克隆\n\t\tm := gtree.NewBTreeFrom(3, gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t//修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t//修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_BTree_LRNode(t *testing.T) {\n\texpect := map[any]any{\"key4\": \"val4\", \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\t//safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n\t//unsafe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect, true)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n}\n\nfunc Test_BTree_Remove(t *testing.T) {\n\tm := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfor i := 1; i <= 100; i++ {\n\t\tm.Set(i, fmt.Sprintf(\"val%d\", i))\n\t}\n\texpect := m.Map()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range expect {\n\t\t\tm1 := m.Clone()\n\t\t\tt.Assert(m1.Remove(k), v)\n\t\t\tt.Assert(m1.Remove(k), nil)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_example_avltree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleAVLTree_Clone() {\n\tavl := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tavl.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree := avl.Clone()\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleAVLTree_Set() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleAVLTree_Sets() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\n\ttree.Sets(map[any]any{\n\t\t\"key1\": \"val1\",\n\t\t\"key2\": \"val2\",\n\t})\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key1:val1 key2:val2]\n\t// 2\n}\n\nfunc ExampleAVLTree_Get() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Get(\"key1\"))\n\tfmt.Println(tree.Get(\"key10\"))\n\n\t// Output:\n\t// val1\n\t// <nil>\n}\n\nfunc ExampleAVLTree_GetOrSet() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_GetOrSetFunc() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_GetOrSetFuncLock() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_GetVar() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVar(\"key1\").String())\n\n\t// Output:\n\t// val1\n}\n\nfunc ExampleAVLTree_GetVarOrSet() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetVarOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_GetVarOrSetFunc() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_GetVarOrSetFuncLock() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleAVLTree_SetIfNotExist() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExist(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.SetIfNotExist(\"key6\", \"val6\"))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleAVLTree_SetIfNotExistFunc() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleAVLTree_SetIfNotExistFuncLock() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleAVLTree_Contains() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Contains(\"key1\"))\n\tfmt.Println(tree.Contains(\"key6\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleAVLTree_Remove() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Remove(\"key1\"))\n\tfmt.Println(tree.Remove(\"key6\"))\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// val1\n\t// <nil>\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleAVLTree_Removes() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tremoveKeys := make([]any, 2)\n\tremoveKeys = append(removeKeys, \"key1\")\n\tremoveKeys = append(removeKeys, \"key6\")\n\n\ttree.Removes(removeKeys)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleAVLTree_IsEmpty() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\n\tfmt.Println(tree.IsEmpty())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleAVLTree_Size() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\n\tfmt.Println(tree.Size())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 0\n\t// 6\n}\n\nfunc ExampleAVLTree_Keys() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Keys())\n\n\t// Output:\n\t// [key1 key2 key3 key4 key5 key6]\n}\n\nfunc ExampleAVLTree_Values() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Values())\n\n\t// Output:\n\t// [val1 val2 val3 val4 val5 val6]\n}\n\nfunc ExampleAVLTree_Map() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleAVLTree_MapStrAny() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.MapStrAny())\n\n\t// Output:\n\t// map[1000:val0 1001:val1 1002:val2 1003:val3 1004:val4 1005:val5]\n}\n\nfunc ExampleAVLTree_Flip() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i < 6; i++ {\n\t\ttree.Set(i, i*10)\n\t}\n\n\tfmt.Println(\"Before Flip\", tree.Map())\n\n\ttree.Flip()\n\n\tfmt.Println(\"After Flip\", tree.Map())\n\n\t// Output:\n\t// Before Flip map[1:10 2:20 3:30 4:40 5:50]\n\t// After Flip map[10:1 20:2 30:3 40:4 50:5]\n}\n\nfunc ExampleAVLTree_Clear() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\tfmt.Println(tree.Size())\n\n\ttree.Clear()\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 6\n\t// 0\n}\n\nfunc ExampleAVLTree_Replace() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\tdata := map[any]any{\n\t\t\"newKey0\": \"newVal0\",\n\t\t\"newKey1\": \"newVal1\",\n\t\t\"newKey2\": \"newVal2\",\n\t}\n\n\ttree.Replace(data)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// map[newKey0:newVal0 newKey1:newVal1 newKey2:newVal2]\n}\n\nfunc ExampleAVLTree_Left() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Left().Key, tree.Left().Value)\n\n\temptyTree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Left())\n\n\t// Output:\n\t// 1 1\n\t// <nil>\n}\n\nfunc ExampleAVLTree_Right() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Right().Key, tree.Right().Value)\n\n\temptyTree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Right())\n\n\t// Output:\n\t// 99 99\n\t// <nil>\n}\n\nfunc ExampleAVLTree_Floor() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\tif i != 50 {\n\t\t\ttree.Set(i, i)\n\t\t}\n\t}\n\n\tnode, found := tree.Floor(95)\n\tif found {\n\t\tfmt.Println(\"Floor 95:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(50)\n\tif found {\n\t\tfmt.Println(\"Floor 50:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(100)\n\tif found {\n\t\tfmt.Println(\"Floor 100:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(0)\n\tif found {\n\t\tfmt.Println(\"Floor 0:\", node.Key)\n\t}\n\n\t// Output:\n\t// Floor 95: 95\n\t// Floor 50: 49\n\t// Floor 100: 99\n}\n\nfunc ExampleAVLTree_Ceiling() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\tif i != 50 {\n\t\t\ttree.Set(i, i)\n\t\t}\n\t}\n\n\tnode, found := tree.Ceiling(1)\n\tif found {\n\t\tfmt.Println(\"Ceiling 1:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(50)\n\tif found {\n\t\tfmt.Println(\"Ceiling 50:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(100)\n\tif found {\n\t\tfmt.Println(\"Ceiling 100:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(-1)\n\tif found {\n\t\tfmt.Println(\"Ceiling -1:\", node.Key)\n\t}\n\n\t// Output:\n\t// Ceiling 1: 1\n\t// Ceiling 50: 51\n\t// Ceiling -1: 1\n}\n\nfunc ExampleAVLTree_String() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.String())\n\n\t// Output:\n\t// │       ┌── key5\n\t// │   ┌── key4\n\t// └── key3\n\t//     │   ┌── key2\n\t//     └── key1\n\t//         └── key0\n}\n\nfunc ExampleAVLTree_Search() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Search(\"key0\"))\n\tfmt.Println(tree.Search(\"key6\"))\n\n\t// Output:\n\t// val0 true\n\t// <nil> false\n}\n\nfunc ExampleAVLTree_Print() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree.Print()\n\n\t// Output:\n\t// │       ┌── key5\n\t// │   ┌── key4\n\t// └── key3\n\t//     │   ┌── key2\n\t//     └── key1\n\t//         └── key0\n}\n\nfunc ExampleAVLTree_Iterator() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\tvar totalKey, totalValue int\n\ttree.Iterator(func(key, value any) bool {\n\t\ttotalKey += key.(int)\n\t\ttotalValue += value.(int)\n\n\t\treturn totalValue < 20\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 3\n\t// totalValue: 27\n}\n\nfunc ExampleAVLTree_IteratorFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleAVLTree_IteratorAsc() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorAsc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 0 , value: 10\n\t// key: 1 , value: 9\n\t// key: 2 , value: 8\n\t// key: 3 , value: 7\n\t// key: 4 , value: 6\n\t// key: 5 , value: 5\n\t// key: 6 , value: 4\n\t// key: 7 , value: 3\n\t// key: 8 , value: 2\n\t// key: 9 , value: 1\n}\n\nfunc ExampleAVLTree_IteratorAscFrom_normal() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleAVLTree_IteratorAscFrom_noExistKey() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(0, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n}\n\nfunc ExampleAVLTree_IteratorAscFrom_noExistKeyAndMatchFalse() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(6, false, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n}\n\nfunc ExampleAVLTree_IteratorDesc() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorDesc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 9 , value: 1\n\t// key: 8 , value: 2\n\t// key: 7 , value: 3\n\t// key: 6 , value: 4\n\t// key: 5 , value: 5\n\t// key: 4 , value: 6\n\t// key: 3 , value: 7\n\t// key: 2 , value: 8\n\t// key: 1 , value: 9\n\t// key: 0 , value: 10\n}\n\nfunc ExampleAVLTree_IteratorDescFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewAVLTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 5 , value: 50\n\t// key: 4 , value: 40\n\t// key: 3 , value: 30\n\t// key: 2 , value: 20\n\t// key: 1 , value: 10\n}\n\nfunc ExampleAVLTree_MarshalJSON() {\n\ttree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tbytes, err := json.Marshal(tree)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"key0\":\"val0\",\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\",\"key4\":\"val4\",\"key5\":\"val5\"}\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_example_btree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/Agogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleBTree_Clone() {\n\tb := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tb.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree := b.Clone()\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleBTree_Set() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleBTree_Sets() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\n\ttree.Sets(map[any]any{\n\t\t\"key1\": \"val1\",\n\t\t\"key2\": \"val2\",\n\t})\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key1:val1 key2:val2]\n\t// 2\n}\n\nfunc ExampleBTree_Get() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Get(\"key1\"))\n\tfmt.Println(tree.Get(\"key10\"))\n\n\t// Output:\n\t// val1\n\t// <nil>\n}\n\nfunc ExampleBTree_GetOrSet() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_GetOrSetFunc() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_GetOrSetFuncLock() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_GetVar() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVar(\"key1\").String())\n\n\t// Output:\n\t// val1\n}\n\nfunc ExampleBTree_GetVarOrSet() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetVarOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_GetVarOrSetFunc() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_GetVarOrSetFuncLock() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleBTree_SetIfNotExist() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExist(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.SetIfNotExist(\"key6\", \"val6\"))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleBTree_SetIfNotExistFunc() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleBTree_SetIfNotExistFuncLock() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleBTree_Contains() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Contains(\"key1\"))\n\tfmt.Println(tree.Contains(\"key6\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleBTree_Remove() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Remove(\"key1\"))\n\tfmt.Println(tree.Remove(\"key6\"))\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// val1\n\t// <nil>\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleBTree_Removes() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tremoveKeys := make([]any, 2)\n\tremoveKeys = append(removeKeys, \"key1\")\n\tremoveKeys = append(removeKeys, \"key6\")\n\n\ttree.Removes(removeKeys)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleBTree_IsEmpty() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\n\tfmt.Println(tree.IsEmpty())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleBTree_Size() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\n\tfmt.Println(tree.Size())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 0\n\t// 6\n}\n\nfunc ExampleBTree_Keys() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Keys())\n\n\t// Output:\n\t// [key1 key2 key3 key4 key5 key6]\n}\n\nfunc ExampleBTree_Values() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Values())\n\n\t// Output:\n\t// [val1 val2 val3 val4 val5 val6]\n}\n\nfunc ExampleBTree_Map() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleBTree_MapStrAny() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.MapStrAny())\n\n\t// Output:\n\t// map[1000:val0 1001:val1 1002:val2 1003:val3 1004:val4 1005:val5]\n}\n\nfunc ExampleBTree_Clear() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\tfmt.Println(tree.Size())\n\n\ttree.Clear()\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 6\n\t// 0\n}\n\nfunc ExampleBTree_Replace() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\tdata := map[any]any{\n\t\t\"newKey0\": \"newVal0\",\n\t\t\"newKey1\": \"newVal1\",\n\t\t\"newKey2\": \"newVal2\",\n\t}\n\n\ttree.Replace(data)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// map[newKey0:newVal0 newKey1:newVal1 newKey2:newVal2]\n}\n\nfunc ExampleBTree_Height() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfor i := 0; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Height())\n\n\t// Output:\n\t// 6\n}\n\nfunc ExampleBTree_Left() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Left().Key, tree.Left().Value)\n\n\temptyTree := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Left())\n\n\t// Output:\n\t// 1 1\n\t// <nil>\n}\n\nfunc ExampleBTree_Right() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Right().Key, tree.Right().Value)\n\n\temptyTree := gtree.NewBTree(3, gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Left())\n\n\t// Output:\n\t// 99 99\n\t// <nil>\n}\n\nfunc ExampleBTree_String() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.String())\n\n\t// Output:\n\t//     key0\n\t// key1\n\t//     key2\n\t// key3\n\t//     key4\n\t//     key5\n}\n\nfunc ExampleBTree_Search() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Search(\"key0\"))\n\tfmt.Println(tree.Search(\"key6\"))\n\n\t// Output:\n\t// val0 true\n\t// <nil> false\n}\n\nfunc ExampleBTree_Print() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree.Print()\n\n\t// Output:\n\t//     key0\n\t// key1\n\t//     key2\n\t// key3\n\t//     key4\n\t//     key5\n}\n\nfunc ExampleBTree_Iterator() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\tvar totalKey, totalValue int\n\ttree.Iterator(func(key, value any) bool {\n\t\ttotalKey += key.(int)\n\t\ttotalValue += value.(int)\n\n\t\treturn totalValue < 20\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 3\n\t// totalValue: 27\n}\n\nfunc ExampleBTree_IteratorFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\ttree.IteratorFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleBTree_IteratorAsc() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorAsc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 0 , value: 10\n\t// key: 1 , value: 9\n\t// key: 2 , value: 8\n\t// key: 3 , value: 7\n\t// key: 4 , value: 6\n\t// key: 5 , value: 5\n\t// key: 6 , value: 4\n\t// key: 7 , value: 3\n\t// key: 8 , value: 2\n\t// key: 9 , value: 1\n}\n\nfunc ExampleBTree_IteratorAscFrom_normal() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleBTree_IteratorAscFrom_noExistKey() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(0, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n}\n\nfunc ExampleBTree_IteratorAscFrom_noExistKeyAndMatchFalse() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(0, false, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleBTree_IteratorDesc() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorDesc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 9 , value: 1\n\t// key: 8 , value: 2\n\t// key: 7 , value: 3\n\t// key: 6 , value: 4\n\t// key: 5 , value: 5\n\t// key: 4 , value: 6\n\t// key: 3 , value: 7\n\t// key: 2 , value: 8\n\t// key: 1 , value: 9\n\t// key: 0 , value: 10\n}\n\nfunc ExampleBTree_IteratorDescFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewBTreeFrom(3, gutil.ComparatorInt, m)\n\n\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 5 , value: 50\n\t// key: 4 , value: 40\n\t// key: 3 , value: 30\n\t// key: 2 , value: 20\n\t// key: 1 , value: 10\n}\n\nfunc ExampleBTree_MarshalJSON() {\n\ttree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tbytes, err := json.Marshal(tree)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"key0\":\"val0\",\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\",\"key4\":\"val4\",\"key5\":\"val5\"}\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_example_redblacktree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleRedBlackTree_SetComparator() {\n\tvar tree gtree.RedBlackTree\n\ttree.SetComparator(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleRedBlackTree_Clone() {\n\tb := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tb.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree := b.Clone()\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleRedBlackTree_Set() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// 6\n}\n\nfunc ExampleRedBlackTree_Sets() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\n\ttree.Sets(map[any]any{\n\t\t\"key1\": \"val1\",\n\t\t\"key2\": \"val2\",\n\t})\n\n\tfmt.Println(tree.Map())\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// map[key1:val1 key2:val2]\n\t// 2\n}\n\nfunc ExampleRedBlackTree_Get() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Get(\"key1\"))\n\tfmt.Println(tree.Get(\"key10\"))\n\n\t// Output:\n\t// val1\n\t// <nil>\n}\n\nfunc ExampleRedBlackTree_GetOrSet() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_GetOrSetFunc() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_GetOrSetFuncLock() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_GetVar() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVar(\"key1\").String())\n\n\t// Output:\n\t// val1\n}\n\nfunc ExampleRedBlackTree_GetVarOrSet() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSet(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.GetVarOrSet(\"key6\", \"val6\"))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_GetVarOrSetFunc() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_GetVarOrSetFuncLock() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.GetVarOrSetFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// val1\n\t// val6\n}\n\nfunc ExampleRedBlackTree_SetIfNotExist() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExist(\"key1\", \"newVal1\"))\n\tfmt.Println(tree.SetIfNotExist(\"key6\", \"val6\"))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleRedBlackTree_SetIfNotExistFunc() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFunc(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFunc(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleRedBlackTree_SetIfNotExistFuncLock() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key1\", func() any {\n\t\treturn \"newVal1\"\n\t}))\n\tfmt.Println(tree.SetIfNotExistFuncLock(\"key6\", func() any {\n\t\treturn \"val6\"\n\t}))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleRedBlackTree_Contains() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Contains(\"key1\"))\n\tfmt.Println(tree.Contains(\"key6\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleRedBlackTree_Remove() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Remove(\"key1\"))\n\tfmt.Println(tree.Remove(\"key6\"))\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// val1\n\t// <nil>\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleRedBlackTree_Removes() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tremoveKeys := make([]any, 2)\n\tremoveKeys = append(removeKeys, \"key1\")\n\tremoveKeys = append(removeKeys, \"key6\")\n\n\ttree.Removes(removeKeys)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleRedBlackTree_IsEmpty() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\n\tfmt.Println(tree.IsEmpty())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.IsEmpty())\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleRedBlackTree_Size() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\n\tfmt.Println(tree.Size())\n\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 0\n\t// 6\n}\n\nfunc ExampleRedBlackTree_Keys() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Keys())\n\n\t// Output:\n\t// [key1 key2 key3 key4 key5 key6]\n}\n\nfunc ExampleRedBlackTree_Values() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 6; i > 0; i-- {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Values())\n\n\t// Output:\n\t// [val1 val2 val3 val4 val5 val6]\n}\n\nfunc ExampleRedBlackTree_Map() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleRedBlackTree_MapStrAny() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.MapStrAny())\n\n\t// Output:\n\t// map[1000:val0 1001:val1 1002:val2 1003:val3 1004:val4 1005:val5]\n}\n\nfunc ExampleRedBlackTree_Left() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Left().Key, tree.Left().Value)\n\n\temptyTree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Left())\n\n\t// Output:\n\t// 1 1\n\t// <nil>\n}\n\nfunc ExampleRedBlackTree_Right() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\ttree.Set(i, i)\n\t}\n\tfmt.Println(tree.Right().Key, tree.Right().Value)\n\n\temptyTree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfmt.Println(emptyTree.Left())\n\n\t// Output:\n\t// 99 99\n\t// <nil>\n}\n\nfunc ExampleRedBlackTree_Floor() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\tif i != 50 {\n\t\t\ttree.Set(i, i)\n\t\t}\n\t}\n\n\tnode, found := tree.Floor(95)\n\tif found {\n\t\tfmt.Println(\"Floor 95:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(50)\n\tif found {\n\t\tfmt.Println(\"Floor 50:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(100)\n\tif found {\n\t\tfmt.Println(\"Floor 100:\", node.Key)\n\t}\n\n\tnode, found = tree.Floor(0)\n\tif found {\n\t\tfmt.Println(\"Floor 0:\", node.Key)\n\t}\n\n\t// Output:\n\t// Floor 95: 95\n\t// Floor 50: 49\n\t// Floor 100: 99\n}\n\nfunc ExampleRedBlackTree_Ceiling() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfor i := 1; i < 100; i++ {\n\t\tif i != 50 {\n\t\t\ttree.Set(i, i)\n\t\t}\n\t}\n\n\tnode, found := tree.Ceiling(1)\n\tif found {\n\t\tfmt.Println(\"Ceiling 1:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(50)\n\tif found {\n\t\tfmt.Println(\"Ceiling 50:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(100)\n\tif found {\n\t\tfmt.Println(\"Ceiling 100:\", node.Key)\n\t}\n\n\tnode, found = tree.Ceiling(-1)\n\tif found {\n\t\tfmt.Println(\"Ceiling -1:\", node.Key)\n\t}\n\n\t// Output:\n\t// Ceiling 1: 1\n\t// Ceiling 50: 51\n\t// Ceiling -1: 1\n}\n\nfunc ExampleRedBlackTree_Iterator() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\tvar totalKey, totalValue int\n\ttree.Iterator(func(key, value any) bool {\n\t\ttotalKey += key.(int)\n\t\ttotalValue += value.(int)\n\n\t\treturn totalValue < 20\n\t})\n\n\tfmt.Println(\"totalKey:\", totalKey)\n\tfmt.Println(\"totalValue:\", totalValue)\n\n\t// Output:\n\t// totalKey: 3\n\t// totalValue: 27\n}\n\nfunc ExampleRedBlackTree_IteratorFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleRedBlackTree_IteratorAsc() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorAsc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 0 , value: 10\n\t// key: 1 , value: 9\n\t// key: 2 , value: 8\n\t// key: 3 , value: 7\n\t// key: 4 , value: 6\n\t// key: 5 , value: 5\n\t// key: 6 , value: 4\n\t// key: 7 , value: 3\n\t// key: 8 , value: 2\n\t// key: 9 , value: 1\n}\n\nfunc ExampleRedBlackTree_IteratorAscFrom_normal() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(1, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleRedBlackTree_IteratorAscFrom_noExistKey() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(0, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n}\n\nfunc ExampleRedBlackTree_IteratorAscFrom_noExistKeyAndMatchFalse() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorAscFrom(0, false, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 1 , value: 10\n\t// key: 2 , value: 20\n\t// key: 3 , value: 30\n\t// key: 4 , value: 40\n\t// key: 5 , value: 50\n}\n\nfunc ExampleRedBlackTree_IteratorDesc() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 10; i++ {\n\t\ttree.Set(i, 10-i)\n\t}\n\n\ttree.IteratorDesc(func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 9 , value: 1\n\t// key: 8 , value: 2\n\t// key: 7 , value: 3\n\t// key: 6 , value: 4\n\t// key: 5 , value: 5\n\t// key: 4 , value: 6\n\t// key: 3 , value: 7\n\t// key: 2 , value: 8\n\t// key: 1 , value: 9\n\t// key: 0 , value: 10\n}\n\nfunc ExampleRedBlackTree_IteratorDescFrom() {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 5; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\tfmt.Println(\"key:\", key, \", value:\", value)\n\t\treturn true\n\t})\n\n\t// Output:\n\t// key: 5 , value: 50\n\t// key: 4 , value: 40\n\t// key: 3 , value: 30\n\t// key: 2 , value: 20\n\t// key: 1 , value: 10\n}\n\nfunc ExampleRedBlackTree_Clear() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(1000+i, \"val\"+gconv.String(i))\n\t}\n\tfmt.Println(tree.Size())\n\n\ttree.Clear()\n\tfmt.Println(tree.Size())\n\n\t// Output:\n\t// 6\n\t// 0\n}\n\nfunc ExampleRedBlackTree_Replace() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Map())\n\n\tdata := map[any]any{\n\t\t\"newKey0\": \"newVal0\",\n\t\t\"newKey1\": \"newVal1\",\n\t\t\"newKey2\": \"newVal2\",\n\t}\n\n\ttree.Replace(data)\n\n\tfmt.Println(tree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n\t// map[newKey0:newVal0 newKey1:newVal1 newKey2:newVal2]\n}\n\nfunc ExampleRedBlackTree_String() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.String())\n\n\t// Output:\n\t// │           ┌── key5\n\t// │       ┌── key4\n\t// │   ┌── key3\n\t// │   │   └── key2\n\t// └── key1\n\t//     └── key0\n}\n\nfunc ExampleRedBlackTree_Print() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\ttree.Print()\n\n\t// Output:\n\t// │           ┌── key5\n\t// │       ┌── key4\n\t// │   ┌── key3\n\t// │   │   └── key2\n\t// └── key1\n\t//     └── key0\n}\n\nfunc ExampleRedBlackTree_Search() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(tree.Search(\"key0\"))\n\tfmt.Println(tree.Search(\"key6\"))\n\n\t// Output:\n\t// val0 true\n\t// <nil> false\n}\n\nfunc ExampleRedBlackTree_Flip() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 1; i < 6; i++ {\n\t\ttree.Set(i, i*10)\n\t}\n\n\tfmt.Println(\"Before Flip\", tree.Map())\n\n\ttree.Flip()\n\n\tfmt.Println(\"After Flip\", tree.Map())\n\n\t// Output:\n\t// Before Flip map[1:10 2:20 3:30 4:40 5:50]\n\t// After Flip map[10:1 20:2 30:3 40:4 50:5]\n}\n\nfunc ExampleRedBlackTree_MarshalJSON() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tbytes, err := json.Marshal(tree)\n\tif err == nil {\n\t\tfmt.Println(gconv.String(bytes))\n\t}\n\n\t// Output:\n\t// {\"key0\":\"val0\",\"key1\":\"val1\",\"key2\":\"val2\",\"key3\":\"val3\",\"key4\":\"val4\",\"key5\":\"val5\"}\n}\n\nfunc ExampleRedBlackTree_UnmarshalJSON() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\ttree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\tbytes, err := json.Marshal(tree)\n\n\totherTree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\terr = json.Unmarshal(bytes, &otherTree)\n\tif err == nil {\n\t\tfmt.Println(otherTree.Map())\n\t}\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleRedBlackTree_UnmarshalValue() {\n\ttree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\n\ttype User struct {\n\t\tUid   int\n\t\tName  string\n\t\tPass1 string `gconv:\"password1\"`\n\t\tPass2 string `gconv:\"password2\"`\n\t}\n\n\tvar (\n\t\tuser = User{\n\t\t\tUid:   1,\n\t\t\tName:  \"john\",\n\t\t\tPass1: \"123\",\n\t\t\tPass2: \"456\",\n\t\t}\n\t)\n\tif err := gconv.Scan(user, tree); err == nil {\n\t\tfmt.Printf(\"%#v\", tree.Map())\n\t}\n\n\t// Output:\n\t// map[interface {}]interface {}{\"Name\":\"john\", \"Uid\":1, \"password1\":\"123\", \"password2\":\"456\"}\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/Agogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleNewAVLTree() {\n\tavlTree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tavlTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(avlTree)\n\n\t// Output:\n\t// │       ┌── key5\n\t// │   ┌── key4\n\t// └── key3\n\t//     │   ┌── key2\n\t//     └── key1\n\t//         └── key0\n}\n\nfunc ExampleNewAVLTreeFrom() {\n\tavlTree := gtree.NewAVLTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tavlTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\totherAvlTree := gtree.NewAVLTreeFrom(gutil.ComparatorString, avlTree.Map())\n\tfmt.Println(otherAvlTree)\n\n\t// May Output:\n\t// │   ┌── key5\n\t// │   │   └── key4\n\t// └── key3\n\t//     │   ┌── key2\n\t//     └── key1\n\t//         └── key0\n}\n\nfunc ExampleNewBTree() {\n\tbTree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tbTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\tfmt.Println(bTree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleNewBTreeFrom() {\n\tbTree := gtree.NewBTree(3, gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\tbTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\totherBTree := gtree.NewBTreeFrom(3, gutil.ComparatorString, bTree.Map())\n\tfmt.Println(otherBTree.Map())\n\n\t// Output:\n\t// map[key0:val0 key1:val1 key2:val2 key3:val3 key4:val4 key5:val5]\n}\n\nfunc ExampleNewRedBlackTree() {\n\trbTree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\trbTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\tfmt.Println(rbTree)\n\n\t// Output:\n\t// │           ┌── key5\n\t// │       ┌── key4\n\t// │   ┌── key3\n\t// │   │   └── key2\n\t// └── key1\n\t//     └── key0\n}\n\nfunc ExampleNewRedBlackTreeFrom() {\n\trbTree := gtree.NewRedBlackTree(gutil.ComparatorString)\n\tfor i := 0; i < 6; i++ {\n\t\trbTree.Set(\"key\"+gconv.String(i), \"val\"+gconv.String(i))\n\t}\n\n\totherRBTree := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, rbTree.Map())\n\tfmt.Println(otherRBTree)\n\n\t// May Output:\n\t// │           ┌── key5\n\t// │       ┌── key4\n\t// │   ┌── key3\n\t// │   │   └── key2\n\t// └── key1\n\t//     └── key0\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_k_v_tree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_KVAVLTree_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tavlTree := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tavlTree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tavlTree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(avlTree.Size(), 5)\n\n\t\tavlTree2 := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tavlTree2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tavlTree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tavlTree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(avlTree2.Size(), 5)\n\n\t})\n}\n\nfunc Test_KVBTree_TypedNil(t *testing.T) {\n\ttype Student struct {\n\t\tName string\n\t\tAge  int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbtree := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tbtree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tbtree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(btree.Size(), 5)\n\n\t\tbtree2 := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)\n\t\tbtree2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tbtree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tbtree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(btree2.Size(), 5)\n\t})\n\n}\n\nfunc Test_KVRedBlackTree_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tredBlackTree := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tredBlackTree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tredBlackTree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(redBlackTree.Size(), 5)\n\n\t\tredBlackTree2 := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tredBlackTree2.SetNilChecker(func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t})\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tredBlackTree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tredBlackTree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(redBlackTree2.Size(), 5)\n\t})\n}\n\nfunc Test_NewKVAVLTreeWithChecker_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tavlTree := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tavlTree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tavlTree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(avlTree.Size(), 5)\n\n\t\tavlTree2 := gtree.NewAVLKVTreeWithChecker[int, *Student](gutil.ComparatorTStr[int], func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tavlTree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tavlTree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(avlTree2.Size(), 5)\n\n\t})\n}\n\nfunc Test_NewKVBTreeWithChecker_TypedNil(t *testing.T) {\n\ttype Student struct {\n\t\tName string\n\t\tAge  int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbtree := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tbtree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tbtree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(btree.Size(), 5)\n\n\t\tbtree2 := gtree.NewBKVTreeWithChecker[int, *Student](100, gutil.ComparatorTStr[int], func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tbtree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tbtree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(btree2.Size(), 5)\n\t})\n\n}\n\nfunc Test_NewRedBlackKVTreeWithChecker_TypedNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\tredBlackTree := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tredBlackTree.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tredBlackTree.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(redBlackTree.Size(), 5)\n\n\t\tredBlackTree2 := gtree.NewRedBlackKVTreeWithChecker[int, *Student](gutil.ComparatorTStr[int], func(student *Student) bool {\n\t\t\treturn student == nil\n\t\t}, true)\n\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tif i%2 == 0 {\n\t\t\t\tredBlackTree2.Set(i, &Student{})\n\t\t\t} else {\n\t\t\t\tvar s *Student = nil\n\t\t\t\tredBlackTree2.Set(i, s)\n\t\t\t}\n\t\t}\n\t\tt.Assert(redBlackTree2.Size(), 5)\n\t})\n}\n"
  },
  {
    "path": "container/gtree/gtree_z_redblack_tree_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtree_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc getValue() any {\n\treturn 3\n}\n\nfunc Test_RedBlackTree_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tm.Set(\"key1\", \"val1\")\n\t\tt.Assert(m.Keys(), []any{\"key1\"})\n\n\t\tt.Assert(m.Get(\"key1\"), \"val1\")\n\t\tt.Assert(m.Size(), 1)\n\t\tt.Assert(m.IsEmpty(), false)\n\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.GetOrSet(\"key2\", \"val2\"), \"val2\")\n\t\tt.Assert(m.SetIfNotExist(\"key2\", \"val2\"), false)\n\n\t\tt.Assert(m.SetIfNotExist(\"key3\", \"val3\"), true)\n\n\t\tt.Assert(m.Remove(\"key2\"), \"val2\")\n\t\tt.Assert(m.Contains(\"key2\"), false)\n\n\t\tt.AssertIN(\"key3\", m.Keys())\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t\tt.AssertIN(\"val3\", m.Values())\n\t\tt.AssertIN(\"val1\", m.Values())\n\n\t\tm.Sets(map[any]any{\"key3\": \"val3\", \"key1\": \"val1\"})\n\n\t\tm.Flip()\n\t\tt.Assert(m.Map(), map[any]any{\"val3\": \"key3\", \"val1\": \"key1\"})\n\n\t\tm.Flip(gutil.ComparatorString)\n\t\tt.Assert(m.Map(), map[any]any{\"key3\": \"val3\", \"key1\": \"val1\"})\n\n\t\tm.Clear()\n\t\tt.Assert(m.Size(), 0)\n\t\tt.Assert(m.IsEmpty(), true)\n\n\t\tm2 := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tt.Assert(m2.Map(), map[any]any{1: 1, \"key1\": \"val1\"})\n\t})\n}\n\nfunc Test_RedBlackTree_Set_Fun(t *testing.T) {\n\t//GetOrSetFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFunc(\"fun\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.GetOrSetFuncLock(\"funlock\", getValue), 3)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\t//SetIfNotExistFunc lock or unlock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFunc(\"fun\", getValue), false)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), true)\n\t\tt.Assert(m.SetIfNotExistFuncLock(\"funlock\", getValue), false)\n\t\tt.Assert(m.Get(\"funlock\"), 3)\n\t\tt.Assert(m.Get(\"fun\"), 3)\n\t})\n\n}\n\nfunc Test_RedBlackTree_Get_Set_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), true)\n\t\tt.AssertEQ(m.SetIfNotExist(\"key1\", \"val1\"), false)\n\t\tt.AssertEQ(m.GetVarOrSet(\"key1\", \"val1\"), gvar.New(\"val1\", true))\n\t\tt.AssertEQ(m.GetVar(\"key1\"), gvar.New(\"val1\", true))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFunc(\"fun\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t\tt.AssertEQ(m.GetVarOrSetFuncLock(\"funlock\", getValue), gvar.New(3, true))\n\t})\n}\n\nfunc Test_RedBlackTree_Batch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTree(gutil.ComparatorString)\n\t\tm.Sets(map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tt.Assert(m.Map(), map[any]any{1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"})\n\t\tm.Removes([]any{\"key1\", 1})\n\t\tt.Assert(m.Map(), map[any]any{\"key2\": \"val2\", \"key3\": \"val3\"})\n\t})\n}\n\nfunc Test_RedBlackTree_Iterator(t *testing.T) {\n\tkeys := []string{\"1\", \"key1\", \"key2\", \"key3\", \"key4\"}\n\tkeyLen := len(keys)\n\tindex := 0\n\n\texpect := map[any]any{\"key4\": \"val4\", 1: 1, \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect)\n\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tt.Assert(k, keys[index])\n\t\t\tindex++\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tindex--\n\t\t\tt.Assert(k, keys[index])\n\t\t\tt.Assert(expect[k], v)\n\t\t\treturn true\n\t\t})\n\t})\n\tm.Print()\n\t// 断言返回值对遍历控制\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.Iterator(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 0\n\t\tj := 0\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\t\tm.IteratorDesc(func(k any, v any) bool {\n\t\t\tj++\n\t\t\treturn false\n\t\t})\n\t\tt.Assert(i, keyLen)\n\t\tt.Assert(j, 1)\n\t})\n}\n\nfunc Test_RedBlackTree_IteratorFrom(t *testing.T) {\n\tm := make(map[any]any)\n\tfor i := 1; i <= 10; i++ {\n\t\tm[i] = i * 10\n\t}\n\ttree := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, m)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn := 5\n\t\ttree.IteratorFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(n, key)\n\t\t\tt.Assert(n*10, value)\n\t\t\tn++\n\t\t\treturn true\n\t\t})\n\n\t\ti := 5\n\t\ttree.IteratorAscFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(i, key)\n\t\t\tt.Assert(i*10, value)\n\t\t\ti++\n\t\t\treturn true\n\t\t})\n\n\t\tj := 5\n\t\ttree.IteratorDescFrom(5, true, func(key, value any) bool {\n\t\t\tt.Assert(j, key)\n\t\t\tt.Assert(j*10, value)\n\t\t\tj--\n\t\t\treturn true\n\t\t})\n\t})\n}\n\nfunc Test_RedBlackTree_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//clone 方法是深克隆\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, map[any]any{1: 1, \"key1\": \"val1\"})\n\t\tm_clone := m.Clone()\n\t\tm.Remove(1)\n\t\t//修改原 map,clone 后的 map 不影响\n\t\tt.AssertIN(1, m_clone.Keys())\n\n\t\tm_clone.Remove(\"key1\")\n\t\t//修改clone map,原 map 不影响\n\t\tt.AssertIN(\"key1\", m.Keys())\n\t})\n}\n\nfunc Test_RedBlackTree_LRNode(t *testing.T) {\n\texpect := map[any]any{\"key4\": \"val4\", \"key1\": \"val1\", \"key2\": \"val2\", \"key3\": \"val3\"}\n\t//safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n\t//unsafe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect, true)\n\t\tt.Assert(m.Left().Key, \"key1\")\n\t\tt.Assert(m.Right().Key, \"key4\")\n\t})\n}\n\nfunc Test_RedBlackTree_CeilingFloor(t *testing.T) {\n\texpect := map[any]any{\n\t\t20: \"val20\",\n\t\t6:  \"val6\",\n\t\t10: \"val10\",\n\t\t12: \"val12\",\n\t\t1:  \"val1\",\n\t\t15: \"val15\",\n\t\t19: \"val19\",\n\t\t8:  \"val8\",\n\t\t4:  \"val4\"}\n\t//found and eq\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(8)\n\t\tt.Assert(cf, true)\n\t\tt.Assert(c.Value, \"val8\")\n\t\tf, ff := m.Floor(20)\n\t\tt.Assert(ff, true)\n\t\tt.Assert(f.Value, \"val20\")\n\t})\n\t//found and neq\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(9)\n\t\tt.Assert(cf, true)\n\t\tt.Assert(c.Value, \"val10\")\n\t\tf, ff := m.Floor(5)\n\t\tt.Assert(ff, true)\n\t\tt.Assert(f.Value, \"val4\")\n\t})\n\t//nofound\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect)\n\t\tc, cf := m.Ceiling(21)\n\t\tt.Assert(cf, false)\n\t\tt.Assert(c, nil)\n\t\tf, ff := m.Floor(-1)\n\t\tt.Assert(ff, false)\n\t\tt.Assert(f, nil)\n\t})\n}\n\nfunc Test_RedBlackTree_Remove(t *testing.T) {\n\tm := gtree.NewRedBlackTree(gutil.ComparatorInt)\n\tfor i := 1; i <= 100; i++ {\n\t\tm.Set(i, fmt.Sprintf(\"val%d\", i))\n\t}\n\texpect := m.Map()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range expect {\n\t\t\tm1 := m.Clone()\n\t\t\tt.Assert(m1.Remove(k), v)\n\t\t\tt.Assert(m1.Remove(k), nil)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtype provides high performance and concurrent-safe basic variable types.\npackage gtype\n\n// New is alias of NewAny.\n// See NewAny, NewInterface.\nfunc New(value ...any) *Any {\n\treturn NewAny(value...)\n}\n"
  },
  {
    "path": "container/gtype/gtype_any.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\n// Any is a struct for concurrent-safe operation for type any.\ntype Any = Interface\n\n// NewAny creates and returns a concurrent-safe object for any type,\n// with given initial value `value`.\nfunc NewAny(value ...any) *Any {\n\tt := &Any{}\n\tif len(value) > 0 && value[0] != nil {\n\t\tt.value.Store(value[0])\n\t}\n\treturn t\n}\n"
  },
  {
    "path": "container/gtype/gtype_bool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"bytes\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Bool is a struct for concurrent-safe operation for type bool.\ntype Bool struct {\n\tvalue int32\n}\n\nvar (\n\tbytesTrue  = []byte(\"true\")\n\tbytesFalse = []byte(\"false\")\n)\n\n// NewBool creates and returns a concurrent-safe object for bool type,\n// with given initial value `value`.\nfunc NewBool(value ...bool) *Bool {\n\tt := &Bool{}\n\tif len(value) > 0 {\n\t\tif value[0] {\n\t\t\tt.value = 1\n\t\t} else {\n\t\t\tt.value = 0\n\t\t}\n\t}\n\treturn t\n}\n\n// Clone clones and returns a new concurrent-safe object for bool type.\nfunc (v *Bool) Clone() *Bool {\n\treturn NewBool(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Bool) Set(value bool) (old bool) {\n\tif value {\n\t\told = atomic.SwapInt32(&v.value, 1) == 1\n\t} else {\n\t\told = atomic.SwapInt32(&v.value, 0) == 1\n\t}\n\treturn\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Bool) Val() bool {\n\treturn atomic.LoadInt32(&v.value) > 0\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Bool) Cas(old, new bool) (swapped bool) {\n\tvar oldInt32, newInt32 int32\n\tif old {\n\t\toldInt32 = 1\n\t}\n\tif new {\n\t\tnewInt32 = 1\n\t}\n\treturn atomic.CompareAndSwapInt32(&v.value, oldInt32, newInt32)\n}\n\n// String implements String interface for string printing.\nfunc (v *Bool) String() string {\n\tif v.Val() {\n\t\treturn \"true\"\n\t}\n\treturn \"false\"\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Bool) MarshalJSON() ([]byte, error) {\n\tif v.Val() {\n\t\treturn bytesTrue, nil\n\t}\n\treturn bytesFalse, nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Bool) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Bool(bytes.Trim(b, `\"`)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Bool) UnmarshalValue(value any) error {\n\tv.Set(gconv.Bool(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Bool) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewBool(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_byte.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Byte is a struct for concurrent-safe operation for type byte.\ntype Byte struct {\n\tvalue int32\n}\n\n// NewByte creates and returns a concurrent-safe object for byte type,\n// with given initial value `value`.\nfunc NewByte(value ...byte) *Byte {\n\tif len(value) > 0 {\n\t\treturn &Byte{\n\t\t\tvalue: int32(value[0]),\n\t\t}\n\t}\n\treturn &Byte{}\n}\n\n// Clone clones and returns a new concurrent-safe object for byte type.\nfunc (v *Byte) Clone() *Byte {\n\treturn NewByte(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Byte) Set(value byte) (old byte) {\n\treturn byte(atomic.SwapInt32(&v.value, int32(value)))\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Byte) Val() byte {\n\treturn byte(atomic.LoadInt32(&v.value))\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Byte) Add(delta byte) (new byte) {\n\treturn byte(atomic.AddInt32(&v.value, int32(delta)))\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Byte) Cas(old, new byte) (swapped bool) {\n\treturn atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))\n}\n\n// String implements String interface for string printing.\nfunc (v *Byte) String() string {\n\treturn strconv.FormatUint(uint64(v.Val()), 10)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Byte) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Byte) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Uint8(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Byte) UnmarshalValue(value any) error {\n\tv.Set(gconv.Byte(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Byte) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewByte(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_bytes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Bytes is a struct for concurrent-safe operation for type []byte.\ntype Bytes struct {\n\tvalue atomic.Value\n}\n\n// NewBytes creates and returns a concurrent-safe object for []byte type,\n// with given initial value `value`.\nfunc NewBytes(value ...[]byte) *Bytes {\n\tt := &Bytes{}\n\tif len(value) > 0 {\n\t\tt.value.Store(value[0])\n\t}\n\treturn t\n}\n\n// Clone clones and returns a new shallow copy object for []byte type.\nfunc (v *Bytes) Clone() *Bytes {\n\treturn NewBytes(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\n// Note: The parameter `value` cannot be nil.\nfunc (v *Bytes) Set(value []byte) (old []byte) {\n\told = v.Val()\n\tv.value.Store(value)\n\treturn\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Bytes) Val() []byte {\n\tif s := v.value.Load(); s != nil {\n\t\treturn s.([]byte)\n\t}\n\treturn nil\n}\n\n// String implements String interface for string printing.\nfunc (v *Bytes) String() string {\n\treturn string(v.Val())\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Bytes) MarshalJSON() ([]byte, error) {\n\tval := v.Val()\n\tdst := make([]byte, base64.StdEncoding.EncodedLen(len(val)))\n\tbase64.StdEncoding.Encode(dst, val)\n\treturn []byte(`\"` + string(dst) + `\"`), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Bytes) UnmarshalJSON(b []byte) error {\n\tvar (\n\t\tsrc    = make([]byte, base64.StdEncoding.DecodedLen(len(b)))\n\t\tn, err = base64.StdEncoding.Decode(src, bytes.Trim(b, `\"`))\n\t)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `base64.StdEncoding.Decode failed`)\n\t\treturn err\n\t}\n\tv.Set(src[:n])\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Bytes) UnmarshalValue(value any) error {\n\tv.Set(gconv.Bytes(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Bytes) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\toldBytes := v.Val()\n\tnewBytes := make([]byte, len(oldBytes))\n\tcopy(newBytes, oldBytes)\n\treturn NewBytes(newBytes)\n}\n"
  },
  {
    "path": "container/gtype/gtype_float32.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Float32 is a struct for concurrent-safe operation for type float32.\ntype Float32 struct {\n\tvalue uint32\n}\n\n// NewFloat32 creates and returns a concurrent-safe object for float32 type,\n// with given initial value `value`.\nfunc NewFloat32(value ...float32) *Float32 {\n\tif len(value) > 0 {\n\t\treturn &Float32{\n\t\t\tvalue: math.Float32bits(value[0]),\n\t\t}\n\t}\n\treturn &Float32{}\n}\n\n// Clone clones and returns a new concurrent-safe object for float32 type.\nfunc (v *Float32) Clone() *Float32 {\n\treturn NewFloat32(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Float32) Set(value float32) (old float32) {\n\treturn math.Float32frombits(atomic.SwapUint32(&v.value, math.Float32bits(value)))\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Float32) Val() float32 {\n\treturn math.Float32frombits(atomic.LoadUint32(&v.value))\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Float32) Add(delta float32) (new float32) {\n\tfor {\n\t\told := math.Float32frombits(v.value)\n\t\tnew = old + delta\n\t\tif atomic.CompareAndSwapUint32(\n\t\t\t&v.value,\n\t\t\tmath.Float32bits(old),\n\t\t\tmath.Float32bits(new),\n\t\t) {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Float32) Cas(old, new float32) (swapped bool) {\n\treturn atomic.CompareAndSwapUint32(&v.value, math.Float32bits(old), math.Float32bits(new))\n}\n\n// String implements String interface for string printing.\nfunc (v *Float32) String() string {\n\treturn strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Float32) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Float32) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Float32(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Float32) UnmarshalValue(value any) error {\n\tv.Set(gconv.Float32(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Float32) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewFloat32(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_float64.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Float64 is a struct for concurrent-safe operation for type float64.\ntype Float64 struct {\n\tvalue uint64\n}\n\n// NewFloat64 creates and returns a concurrent-safe object for float64 type,\n// with given initial value `value`.\nfunc NewFloat64(value ...float64) *Float64 {\n\tif len(value) > 0 {\n\t\treturn &Float64{\n\t\t\tvalue: math.Float64bits(value[0]),\n\t\t}\n\t}\n\treturn &Float64{}\n}\n\n// Clone clones and returns a new concurrent-safe object for float64 type.\nfunc (v *Float64) Clone() *Float64 {\n\treturn NewFloat64(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Float64) Set(value float64) (old float64) {\n\treturn math.Float64frombits(atomic.SwapUint64(&v.value, math.Float64bits(value)))\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Float64) Val() float64 {\n\treturn math.Float64frombits(atomic.LoadUint64(&v.value))\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Float64) Add(delta float64) (new float64) {\n\tfor {\n\t\told := math.Float64frombits(v.value)\n\t\tnew = old + delta\n\t\tif atomic.CompareAndSwapUint64(\n\t\t\t&v.value,\n\t\t\tmath.Float64bits(old),\n\t\t\tmath.Float64bits(new),\n\t\t) {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Float64) Cas(old, new float64) (swapped bool) {\n\treturn atomic.CompareAndSwapUint64(&v.value, math.Float64bits(old), math.Float64bits(new))\n}\n\n// String implements String interface for string printing.\nfunc (v *Float64) String() string {\n\treturn strconv.FormatFloat(v.Val(), 'g', -1, 64)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Float64) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatFloat(v.Val(), 'g', -1, 64)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Float64) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Float64(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Float64) UnmarshalValue(value any) error {\n\tv.Set(gconv.Float64(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Float64) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewFloat64(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Int is a struct for concurrent-safe operation for type int.\ntype Int struct {\n\tvalue int64\n}\n\n// NewInt creates and returns a concurrent-safe object for int type,\n// with given initial value `value`.\nfunc NewInt(value ...int) *Int {\n\tif len(value) > 0 {\n\t\treturn &Int{\n\t\t\tvalue: int64(value[0]),\n\t\t}\n\t}\n\treturn &Int{}\n}\n\n// Clone clones and returns a new concurrent-safe object for int type.\nfunc (v *Int) Clone() *Int {\n\treturn NewInt(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Int) Set(value int) (old int) {\n\treturn int(atomic.SwapInt64(&v.value, int64(value)))\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Int) Val() int {\n\treturn int(atomic.LoadInt64(&v.value))\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Int) Add(delta int) (new int) {\n\treturn int(atomic.AddInt64(&v.value, int64(delta)))\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Int) Cas(old, new int) (swapped bool) {\n\treturn atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))\n}\n\n// String implements String interface for string printing.\nfunc (v *Int) String() string {\n\treturn strconv.Itoa(v.Val())\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Int) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.Itoa(v.Val())), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Int) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Int(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Int) UnmarshalValue(value any) error {\n\tv.Set(gconv.Int(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Int) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewInt(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_int32.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Int32 is a struct for concurrent-safe operation for type int32.\ntype Int32 struct {\n\tvalue int32\n}\n\n// NewInt32 creates and returns a concurrent-safe object for int32 type,\n// with given initial value `value`.\nfunc NewInt32(value ...int32) *Int32 {\n\tif len(value) > 0 {\n\t\treturn &Int32{\n\t\t\tvalue: value[0],\n\t\t}\n\t}\n\treturn &Int32{}\n}\n\n// Clone clones and returns a new concurrent-safe object for int32 type.\nfunc (v *Int32) Clone() *Int32 {\n\treturn NewInt32(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Int32) Set(value int32) (old int32) {\n\treturn atomic.SwapInt32(&v.value, value)\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Int32) Val() int32 {\n\treturn atomic.LoadInt32(&v.value)\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Int32) Add(delta int32) (new int32) {\n\treturn atomic.AddInt32(&v.value, delta)\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Int32) Cas(old, new int32) (swapped bool) {\n\treturn atomic.CompareAndSwapInt32(&v.value, old, new)\n}\n\n// String implements String interface for string printing.\nfunc (v *Int32) String() string {\n\treturn strconv.Itoa(int(v.Val()))\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Int32) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.Itoa(int(v.Val()))), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Int32) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Int32(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Int32) UnmarshalValue(value any) error {\n\tv.Set(gconv.Int32(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Int32) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewInt32(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_int64.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Int64 is a struct for concurrent-safe operation for type int64.\ntype Int64 struct {\n\tvalue int64\n}\n\n// NewInt64 creates and returns a concurrent-safe object for int64 type,\n// with given initial value `value`.\nfunc NewInt64(value ...int64) *Int64 {\n\tif len(value) > 0 {\n\t\treturn &Int64{\n\t\t\tvalue: value[0],\n\t\t}\n\t}\n\treturn &Int64{}\n}\n\n// Clone clones and returns a new concurrent-safe object for int64 type.\nfunc (v *Int64) Clone() *Int64 {\n\treturn NewInt64(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Int64) Set(value int64) (old int64) {\n\treturn atomic.SwapInt64(&v.value, value)\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Int64) Val() int64 {\n\treturn atomic.LoadInt64(&v.value)\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Int64) Add(delta int64) (new int64) {\n\treturn atomic.AddInt64(&v.value, delta)\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Int64) Cas(old, new int64) (swapped bool) {\n\treturn atomic.CompareAndSwapInt64(&v.value, old, new)\n}\n\n// String implements String interface for string printing.\nfunc (v *Int64) String() string {\n\treturn strconv.FormatInt(v.Val(), 10)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Int64) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatInt(v.Val(), 10)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Int64) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Int64(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Int64) UnmarshalValue(value any) error {\n\tv.Set(gconv.Int64(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Int64) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewInt64(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_interface.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Interface is a struct for concurrent-safe operation for type any.\ntype Interface struct {\n\tvalue atomic.Value\n}\n\n// NewInterface creates and returns a concurrent-safe object for any type,\n// with given initial value `value`.\nfunc NewInterface(value ...any) *Interface {\n\tt := &Interface{}\n\tif len(value) > 0 && value[0] != nil {\n\t\tt.value.Store(value[0])\n\t}\n\treturn t\n}\n\n// Clone clones and returns a new concurrent-safe object for any type.\nfunc (v *Interface) Clone() *Interface {\n\treturn NewInterface(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\n// Note: The parameter `value` cannot be nil.\nfunc (v *Interface) Set(value any) (old any) {\n\told = v.Val()\n\tv.value.Store(value)\n\treturn\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Interface) Val() any {\n\treturn v.value.Load()\n}\n\n// String implements String interface for string printing.\nfunc (v *Interface) String() string {\n\treturn gconv.String(v.Val())\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Interface) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(v.Val())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Interface) UnmarshalJSON(b []byte) error {\n\tvar i any\n\tif err := json.UnmarshalUseNumber(b, &i); err != nil {\n\t\treturn err\n\t}\n\tv.Set(i)\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Interface) UnmarshalValue(value any) error {\n\tv.Set(value)\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Interface) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewInterface(deepcopy.Copy(v.Val()))\n}\n"
  },
  {
    "path": "container/gtype/gtype_string.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"bytes\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// String is a struct for concurrent-safe operation for type string.\ntype String struct {\n\tvalue atomic.Value\n}\n\n// NewString creates and returns a concurrent-safe object for string type,\n// with given initial value `value`.\nfunc NewString(value ...string) *String {\n\tt := &String{}\n\tif len(value) > 0 {\n\t\tt.value.Store(value[0])\n\t}\n\treturn t\n}\n\n// Clone clones and returns a new concurrent-safe object for string type.\nfunc (v *String) Clone() *String {\n\treturn NewString(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *String) Set(value string) (old string) {\n\told = v.Val()\n\tv.value.Store(value)\n\treturn\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *String) Val() string {\n\ts := v.value.Load()\n\tif s != nil {\n\t\treturn s.(string)\n\t}\n\treturn \"\"\n}\n\n// String implements String interface for string printing.\nfunc (v *String) String() string {\n\treturn v.Val()\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v String) MarshalJSON() ([]byte, error) {\n\treturn []byte(`\"` + v.Val() + `\"`), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *String) UnmarshalJSON(b []byte) error {\n\tv.Set(string(bytes.Trim(b, `\"`)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *String) UnmarshalValue(value any) error {\n\tv.Set(gconv.String(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *String) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewString(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_uint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Uint is a struct for concurrent-safe operation for type uint.\ntype Uint struct {\n\tvalue uint64\n}\n\n// NewUint creates and returns a concurrent-safe object for uint type,\n// with given initial value `value`.\nfunc NewUint(value ...uint) *Uint {\n\tif len(value) > 0 {\n\t\treturn &Uint{\n\t\t\tvalue: uint64(value[0]),\n\t\t}\n\t}\n\treturn &Uint{}\n}\n\n// Clone clones and returns a new concurrent-safe object for uint type.\nfunc (v *Uint) Clone() *Uint {\n\treturn NewUint(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Uint) Set(value uint) (old uint) {\n\treturn uint(atomic.SwapUint64(&v.value, uint64(value)))\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Uint) Val() uint {\n\treturn uint(atomic.LoadUint64(&v.value))\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Uint) Add(delta uint) (new uint) {\n\treturn uint(atomic.AddUint64(&v.value, uint64(delta)))\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Uint) Cas(old, new uint) (swapped bool) {\n\treturn atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))\n}\n\n// String implements String interface for string printing.\nfunc (v *Uint) String() string {\n\treturn strconv.FormatUint(uint64(v.Val()), 10)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Uint) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Uint) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Uint(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Uint) UnmarshalValue(value any) error {\n\tv.Set(gconv.Uint(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Uint) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewUint(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_uint32.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Uint32 is a struct for concurrent-safe operation for type uint32.\ntype Uint32 struct {\n\tvalue uint32\n}\n\n// NewUint32 creates and returns a concurrent-safe object for uint32 type,\n// with given initial value `value`.\nfunc NewUint32(value ...uint32) *Uint32 {\n\tif len(value) > 0 {\n\t\treturn &Uint32{\n\t\t\tvalue: value[0],\n\t\t}\n\t}\n\treturn &Uint32{}\n}\n\n// Clone clones and returns a new concurrent-safe object for uint32 type.\nfunc (v *Uint32) Clone() *Uint32 {\n\treturn NewUint32(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Uint32) Set(value uint32) (old uint32) {\n\treturn atomic.SwapUint32(&v.value, value)\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Uint32) Val() uint32 {\n\treturn atomic.LoadUint32(&v.value)\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Uint32) Add(delta uint32) (new uint32) {\n\treturn atomic.AddUint32(&v.value, delta)\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Uint32) Cas(old, new uint32) (swapped bool) {\n\treturn atomic.CompareAndSwapUint32(&v.value, old, new)\n}\n\n// String implements String interface for string printing.\nfunc (v *Uint32) String() string {\n\treturn strconv.FormatUint(uint64(v.Val()), 10)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Uint32) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Uint32) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Uint32(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Uint32) UnmarshalValue(value any) error {\n\tv.Set(gconv.Uint32(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Uint32) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewUint32(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_uint64.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Uint64 is a struct for concurrent-safe operation for type uint64.\ntype Uint64 struct {\n\tvalue uint64\n}\n\n// NewUint64 creates and returns a concurrent-safe object for uint64 type,\n// with given initial value `value`.\nfunc NewUint64(value ...uint64) *Uint64 {\n\tif len(value) > 0 {\n\t\treturn &Uint64{\n\t\t\tvalue: value[0],\n\t\t}\n\t}\n\treturn &Uint64{}\n}\n\n// Clone clones and returns a new concurrent-safe object for uint64 type.\nfunc (v *Uint64) Clone() *Uint64 {\n\treturn NewUint64(v.Val())\n}\n\n// Set atomically stores `value` into t.value and returns the previous value of t.value.\nfunc (v *Uint64) Set(value uint64) (old uint64) {\n\treturn atomic.SwapUint64(&v.value, value)\n}\n\n// Val atomically loads and returns t.value.\nfunc (v *Uint64) Val() uint64 {\n\treturn atomic.LoadUint64(&v.value)\n}\n\n// Add atomically adds `delta` to t.value and returns the new value.\nfunc (v *Uint64) Add(delta uint64) (new uint64) {\n\treturn atomic.AddUint64(&v.value, delta)\n}\n\n// Cas executes the compare-and-swap operation for value.\nfunc (v *Uint64) Cas(old, new uint64) (swapped bool) {\n\treturn atomic.CompareAndSwapUint64(&v.value, old, new)\n}\n\n// String implements String interface for string printing.\nfunc (v *Uint64) String() string {\n\treturn strconv.FormatUint(v.Val(), 10)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v Uint64) MarshalJSON() ([]byte, error) {\n\treturn []byte(strconv.FormatUint(v.Val(), 10)), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Uint64) UnmarshalJSON(b []byte) error {\n\tv.Set(gconv.Uint64(string(b)))\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for `v`.\nfunc (v *Uint64) UnmarshalValue(value any) error {\n\tv.Set(gconv.Uint64(value))\n\treturn nil\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Uint64) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn NewUint64(v.Val())\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_bench_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gtype_test\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n)\n\nvar (\n\tit     = gtype.NewInt()\n\tit32   = gtype.NewInt32()\n\tit64   = gtype.NewInt64()\n\tuit    = gtype.NewUint()\n\tuit32  = gtype.NewUint32()\n\tuit64  = gtype.NewUint64()\n\tbl     = gtype.NewBool()\n\tvbytes = gtype.NewBytes()\n\tstr    = gtype.NewString()\n\tinf    = gtype.NewInterface()\n\tat     = atomic.Value{}\n)\n\nfunc BenchmarkInt_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tit.Set(i)\n\t}\n}\n\nfunc BenchmarkInt_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tit.Val()\n\t}\n}\n\nfunc BenchmarkInt_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tit.Add(i)\n\t}\n}\n\nfunc BenchmarkInt_Cas(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tit.Cas(i, i)\n\t}\n}\n\nfunc BenchmarkInt32_Set(b *testing.B) {\n\tfor i := int32(0); i < int32(b.N); i++ {\n\t\tit32.Set(i)\n\t}\n}\n\nfunc BenchmarkInt32_Val(b *testing.B) {\n\tfor i := int32(0); i < int32(b.N); i++ {\n\t\tit32.Val()\n\t}\n}\n\nfunc BenchmarkInt32_Add(b *testing.B) {\n\tfor i := int32(0); i < int32(b.N); i++ {\n\t\tit32.Add(i)\n\t}\n}\n\nfunc BenchmarkInt64_Set(b *testing.B) {\n\tfor i := int64(0); i < int64(b.N); i++ {\n\t\tit64.Set(i)\n\t}\n}\n\nfunc BenchmarkInt64_Val(b *testing.B) {\n\tfor i := int64(0); i < int64(b.N); i++ {\n\t\tit64.Val()\n\t}\n}\n\nfunc BenchmarkInt64_Add(b *testing.B) {\n\tfor i := int64(0); i < int64(b.N); i++ {\n\t\tit64.Add(i)\n\t}\n}\n\nfunc BenchmarkUint_Set(b *testing.B) {\n\tfor i := uint(0); i < uint(b.N); i++ {\n\t\tuit.Set(i)\n\t}\n}\n\nfunc BenchmarkUint_Val(b *testing.B) {\n\tfor i := uint(0); i < uint(b.N); i++ {\n\t\tuit.Val()\n\t}\n}\n\nfunc BenchmarkUint_Add(b *testing.B) {\n\tfor i := uint(0); i < uint(b.N); i++ {\n\t\tuit.Add(i)\n\t}\n}\n\nfunc BenchmarkUint32_Set(b *testing.B) {\n\tfor i := uint32(0); i < uint32(b.N); i++ {\n\t\tuit32.Set(i)\n\t}\n}\n\nfunc BenchmarkUint32_Val(b *testing.B) {\n\tfor i := uint32(0); i < uint32(b.N); i++ {\n\t\tuit32.Val()\n\t}\n}\n\nfunc BenchmarkUint32_Add(b *testing.B) {\n\tfor i := uint32(0); i < uint32(b.N); i++ {\n\t\tuit32.Add(i)\n\t}\n}\n\nfunc BenchmarkUint64_Set(b *testing.B) {\n\tfor i := uint64(0); i < uint64(b.N); i++ {\n\t\tuit64.Set(i)\n\t}\n}\n\nfunc BenchmarkUint64_Val(b *testing.B) {\n\tfor i := uint64(0); i < uint64(b.N); i++ {\n\t\tuit64.Val()\n\t}\n}\n\nfunc BenchmarkUint64_Add(b *testing.B) {\n\tfor i := uint64(0); i < uint64(b.N); i++ {\n\t\tuit64.Add(i)\n\t}\n}\n\nfunc BenchmarkBool_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbl.Set(true)\n\t}\n}\n\nfunc BenchmarkBool_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbl.Val()\n\t}\n}\n\nfunc BenchmarkBool_Cas(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbl.Cas(false, true)\n\t}\n}\n\nfunc BenchmarkString_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstr.Set(strconv.Itoa(i))\n\t}\n}\n\nfunc BenchmarkString_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tstr.Val()\n\t}\n}\n\nfunc BenchmarkBytes_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvbytes.Set(gbinary.EncodeInt(i))\n\t}\n}\n\nfunc BenchmarkBytes_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvbytes.Val()\n\t}\n}\n\nfunc BenchmarkInterface_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tinf.Set(i)\n\t}\n}\n\nfunc BenchmarkInterface_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tinf.Val()\n\t}\n}\n\nfunc BenchmarkAtomicValue_Store(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tat.Store(i)\n\t}\n}\n\nfunc BenchmarkAtomicValue_Load(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tat.Load()\n\t}\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_bench_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".+\\_Json\" -benchmem\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\nvar (\n\tvBool      = gtype.NewBool()\n\tvByte      = gtype.NewByte()\n\tvBytes     = gtype.NewBytes()\n\tvFloat32   = gtype.NewFloat32()\n\tvFloat64   = gtype.NewFloat64()\n\tvInt       = gtype.NewInt()\n\tvInt32     = gtype.NewInt32()\n\tvInt64     = gtype.NewInt64()\n\tvInterface = gtype.NewInterface()\n\tvString    = gtype.NewString()\n\tvUint      = gtype.NewUint()\n\tvUint32    = gtype.NewUint32()\n\tvUint64    = gtype.NewUint64()\n)\n\nfunc Benchmark_Bool_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vBool)\n\t}\n}\n\nfunc Benchmark_Byte_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vByte)\n\t}\n}\n\nfunc Benchmark_Bytes_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vBytes)\n\t}\n}\n\nfunc Benchmark_Float32_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vFloat32)\n\t}\n}\n\nfunc Benchmark_Float64_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vFloat64)\n\t}\n}\n\nfunc Benchmark_Int_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vInt)\n\t}\n}\n\nfunc Benchmark_Int32_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vInt32)\n\t}\n}\n\nfunc Benchmark_Int64_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vInt64)\n\t}\n}\n\nfunc Benchmark_Interface_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vInterface)\n\t}\n}\n\nfunc Benchmark_String_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vString)\n\t}\n}\n\nfunc Benchmark_Uint_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vUint)\n\t}\n}\n\nfunc Benchmark_Uint32_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Marshal(vUint64)\n\t}\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_any_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Any(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := Temp{Name: \"gf\", Age: 18}\n\t\tt2 := Temp{Name: \"gf\", Age: 19}\n\t\ti := gtype.New(t1)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(t2), t1)\n\t\tt.AssertEQ(iClone.Val().(Temp), t2)\n\n\t\t// empty param test\n\t\ti1 := gtype.New()\n\t\tt.AssertEQ(i1.Val(), nil)\n\n\t\ti2 := gtype.New(\"gf\")\n\t\tt.AssertEQ(i2.String(), \"gf\")\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(\"goframe\")\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Any_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"i love gf\"\n\t\ti := gtype.New(s)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.New()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), s)\n\t})\n}\n\nfunc Test_Any_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Any\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_bool_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Bool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBool(true)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(false), true)\n\t\tt.AssertEQ(iClone.Val(), false)\n\n\t\ti1 := gtype.NewBool(false)\n\t\tiClone1 := i1.Clone()\n\t\tt.AssertEQ(iClone1.Set(true), false)\n\t\tt.AssertEQ(iClone1.Val(), true)\n\n\t\tt.AssertEQ(iClone1.Cas(false, true), false)\n\t\tt.AssertEQ(iClone1.String(), \"true\")\n\t\tt.AssertEQ(iClone1.Cas(true, false), true)\n\t\tt.AssertEQ(iClone1.String(), \"false\")\n\n\t\tcopyVal := i1.DeepCopy()\n\t\tiClone.Set(true)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\tiClone = nil\n\t\tcopyVal = iClone.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\n\t\t// empty param test\n\t\ti2 := gtype.NewBool()\n\t\tt.AssertEQ(i2.Val(), false)\n\t})\n}\n\nfunc Test_Bool_JSON(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBool(true)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBool(false)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\ti := gtype.NewBool()\n\t\terr = json.UnmarshalUseNumber([]byte(\"true\"), &i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i.Val(), true)\n\t\terr = json.UnmarshalUseNumber([]byte(\"false\"), &i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i.Val(), false)\n\t\terr = json.UnmarshalUseNumber([]byte(\"1\"), &i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i.Val(), true)\n\t\terr = json.UnmarshalUseNumber([]byte(\"0\"), &i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i.Val(), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBool(true)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewBool()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i.Val())\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBool(false)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewBool()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i.Val())\n\t})\n}\n\nfunc Test_Bool_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Bool\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"true\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"false\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), false)\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_byte_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Byte(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 127\n\t\ti := gtype.NewByte(byte(0))\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(byte(1)), byte(0))\n\t\tt.AssertEQ(iClone.Val(), byte(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(byte(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewByte()\n\t\tt.AssertEQ(i1.Val(), byte(0))\n\n\t\ti2 := gtype.NewByte(byte(64))\n\t\tt.AssertEQ(i2.String(), \"64\")\n\t\tt.AssertEQ(i2.Cas(byte(63), byte(65)), false)\n\t\tt.AssertEQ(i2.Cas(byte(64), byte(65)), true)\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(byte(65))\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Byte_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewByte(49)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\ti := gtype.NewByte()\n\t\terr = json.UnmarshalUseNumber([]byte(\"49\"), &i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i.Val(), \"49\")\n\t})\n}\n\nfunc Test_Byte_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Byte\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"2\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"2\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_bytes_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Bytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewBytes([]byte(\"abc\"))\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set([]byte(\"123\")), []byte(\"abc\"))\n\t\tt.AssertEQ(iClone.Val(), []byte(\"123\"))\n\n\t\t// empty param test\n\t\ti1 := gtype.NewBytes()\n\t\tt.AssertEQ(i1.Val(), nil)\n\n\t\ti2 := gtype.NewBytes([]byte(\"abc\"))\n\t\tt.Assert(i2.String(), \"abc\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set([]byte(\"def\"))\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Bytes_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := []byte(\"i love gf\")\n\t\ti := gtype.NewBytes(b)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewBytes()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), b)\n\t})\n}\n\nfunc Test_Bytes_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Bytes\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_float32_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Float32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewFloat32(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(0.1), float32(0))\n\t\tt.AssertEQ(iClone.Val(), float32(0.1))\n\n\t\t// empty param test\n\t\ti1 := gtype.NewFloat32()\n\t\tt.AssertEQ(i1.Val(), float32(0))\n\n\t\ti2 := gtype.NewFloat32(1.23)\n\t\tt.AssertEQ(i2.Add(3.21), float32(4.44))\n\t\tt.AssertEQ(i2.Cas(4.45, 5.55), false)\n\t\tt.AssertEQ(i2.Cas(4.44, 5.55), true)\n\t\tt.AssertEQ(i2.String(), \"5.55\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(float32(6.66))\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Float32_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := float32(math.MaxFloat32)\n\t\ti := gtype.NewFloat32(v)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewFloat32()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), v)\n\t})\n}\n\nfunc Test_Float32_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Float32\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123.456\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123.456\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_float64_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Float64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewFloat64(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(0.1), float64(0))\n\t\tt.AssertEQ(iClone.Val(), float64(0.1))\n\t\t// empty param test\n\t\ti1 := gtype.NewFloat64()\n\t\tt.AssertEQ(i1.Val(), float64(0))\n\n\t\ti2 := gtype.NewFloat64(1.1)\n\t\tt.AssertEQ(i2.Add(3.3), 4.4)\n\t\tt.AssertEQ(i2.Cas(4.5, 5.5), false)\n\t\tt.AssertEQ(i2.Cas(4.4, 5.5), true)\n\t\tt.AssertEQ(i2.String(), \"5.5\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(6.6)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Float64_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := math.MaxFloat64\n\t\ti := gtype.NewFloat64(v)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewFloat64()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), v)\n\t})\n}\n\nfunc Test_Float64_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Float64\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123.456\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123.456\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_int32_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Int32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewInt32(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), int32(0))\n\t\tt.AssertEQ(iClone.Val(), int32(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(int32(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewInt32()\n\t\tt.AssertEQ(i1.Val(), int32(0))\n\n\t\ti2 := gtype.NewInt32(11)\n\t\tt.AssertEQ(i2.Add(1), int32(12))\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Int32_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := int32(math.MaxInt32)\n\t\ti := gtype.NewInt32(v)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewInt32()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), v)\n\t})\n}\n\nfunc Test_Int32_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Int32\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_int64_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Int64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewInt64(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), int64(0))\n\t\tt.AssertEQ(iClone.Val(), int64(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(int64(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewInt64()\n\t\tt.AssertEQ(i1.Val(), int64(0))\n\n\t\ti2 := gtype.NewInt64(11)\n\t\tt.AssertEQ(i2.Add(1), int64(12))\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Int64_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewInt64(math.MaxInt64)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewInt64()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i)\n\t})\n}\n\nfunc Test_Int64_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Int64\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Int(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewInt(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), 0)\n\t\tt.AssertEQ(iClone.Val(), 1)\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(addTimes, i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewInt()\n\t\tt.AssertEQ(i1.Val(), 0)\n\n\t\ti2 := gtype.NewInt(11)\n\t\tt.AssertEQ(i2.Add(1), 12)\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Int_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := 666\n\t\ti := gtype.NewInt(v)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewInt()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), v)\n\t})\n}\n\nfunc Test_Int_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_interface_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Interface(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := Temp{Name: \"gf\", Age: 18}\n\t\tt2 := Temp{Name: \"gf\", Age: 19}\n\t\ti := gtype.New(t1)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(t2), t1)\n\t\tt.AssertEQ(iClone.Val().(Temp), t2)\n\n\t\t// empty param test\n\t\ti1 := gtype.New()\n\t\tt.AssertEQ(i1.Val(), nil)\n\n\t\ti2 := gtype.New(\"gf\")\n\t\tt.AssertEQ(i2.String(), \"gf\")\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(\"goframe\")\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Interface_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"i love gf\"\n\t\ti := gtype.New(s)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.New()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), s)\n\t})\n}\n\nfunc Test_Interface_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Interface\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_string_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewString(\"abc\")\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(\"123\"), \"abc\")\n\t\tt.AssertEQ(iClone.Val(), \"123\")\n\t\tt.AssertEQ(iClone.String(), \"123\")\n\t\t//\n\t\tcopyVal := iClone.DeepCopy()\n\t\tiClone.Set(\"124\")\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\tiClone = nil\n\t\tcopyVal = iClone.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t\t// empty param test\n\t\ti1 := gtype.NewString()\n\t\tt.AssertEQ(i1.Val(), \"\")\n\t})\n}\n\nfunc Test_String_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"i love gf\"\n\t\ti1 := gtype.NewString(s)\n\t\tb1, err1 := json.Marshal(i1)\n\t\tb2, err2 := json.Marshal(i1.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewString()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), s)\n\t})\n}\n\nfunc Test_String_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.String\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_uint32_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Uint32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewUint32(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), uint32(0))\n\t\tt.AssertEQ(iClone.Val(), uint32(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(uint32(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewUint32()\n\t\tt.AssertEQ(i1.Val(), uint32(0))\n\n\t\ti2 := gtype.NewUint32(11)\n\t\tt.AssertEQ(i2.Add(1), uint32(12))\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Uint32_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewUint32(math.MaxUint32)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewUint32()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i)\n\t})\n}\n\nfunc Test_Uint32_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Uint32\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_uint64_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"math\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype Temp struct {\n\tName string\n\tAge  int\n}\n\nfunc Test_Uint64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewUint64(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), uint64(0))\n\t\tt.AssertEQ(iClone.Val(), uint64(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(uint64(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewUint64()\n\t\tt.AssertEQ(i1.Val(), uint64(0))\n\n\t\ti2 := gtype.NewUint64(11)\n\t\tt.AssertEQ(i2.Add(1), uint64(12))\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Uint64_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewUint64(math.MaxUint64)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewUint64()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i)\n\t})\n}\n\nfunc Test_Uint64_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Uint64\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gtype/gtype_z_unit_uint_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtype_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Uint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\taddTimes := 1000\n\t\ti := gtype.NewUint(0)\n\t\tiClone := i.Clone()\n\t\tt.AssertEQ(iClone.Set(1), uint(0))\n\t\tt.AssertEQ(iClone.Val(), uint(1))\n\t\tfor index := 0; index < addTimes; index++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\ti.Add(1)\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\t\tt.AssertEQ(uint(addTimes), i.Val())\n\n\t\t// empty param test\n\t\ti1 := gtype.NewUint()\n\t\tt.AssertEQ(i1.Val(), uint(0))\n\n\t\ti2 := gtype.NewUint(11)\n\t\tt.AssertEQ(i2.Add(1), uint(12))\n\t\tt.AssertEQ(i2.Cas(11, 13), false)\n\t\tt.AssertEQ(i2.Cas(12, 13), true)\n\t\tt.AssertEQ(i2.String(), \"13\")\n\n\t\tcopyVal := i2.DeepCopy()\n\t\ti2.Set(14)\n\t\tt.AssertNE(copyVal, iClone.Val())\n\t\ti2 = nil\n\t\tcopyVal = i2.DeepCopy()\n\t\tt.AssertNil(copyVal)\n\t})\n}\n\nfunc Test_Uint_JSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := gtype.NewUint(666)\n\t\tb1, err1 := json.Marshal(i)\n\t\tb2, err2 := json.Marshal(i.Val())\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(b1, b2)\n\n\t\ti2 := gtype.NewUint()\n\t\terr := json.UnmarshalUseNumber(b2, &i2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(i2.Val(), i)\n\t})\n}\n\nfunc Test_Uint_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tVar  *gtype.Uint\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"123\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.Val(), \"123\")\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gvar provides an universal variable type, like runtime generics.\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Var is an universal variable type implementer.\ntype Var struct {\n\tvalue any  // Underlying value.\n\tsafe  bool // Concurrent safe or not.\n}\n\n// New creates and returns a new Var with given `value`.\n// The optional parameter `safe` specifies whether Var is used in concurrent-safety,\n// which is false in default.\nfunc New(value any, safe ...bool) *Var {\n\tif len(safe) > 0 && safe[0] {\n\t\treturn &Var{\n\t\t\tvalue: gtype.NewInterface(value),\n\t\t\tsafe:  true,\n\t\t}\n\t}\n\treturn &Var{\n\t\tvalue: value,\n\t}\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (v *Var) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(v.Val())\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (v *Var) UnmarshalJSON(b []byte) error {\n\tvar i any\n\tif err := json.UnmarshalUseNumber(b, &i); err != nil {\n\t\treturn err\n\t}\n\tv.Set(i)\n\treturn nil\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for Var.\nfunc (v *Var) UnmarshalValue(value any) error {\n\tv.Set(value)\n\treturn nil\n}\n"
  },
  {
    "path": "container/gvar/gvar_basic.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Val returns the current value of `v`.\nfunc (v *Var) Val() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\tif v.safe {\n\t\tif t, ok := v.value.(*gtype.Interface); ok {\n\t\t\treturn t.Val()\n\t\t}\n\t}\n\treturn v.value\n}\n\n// Interface is alias of Val.\nfunc (v *Var) Interface() any {\n\treturn v.Val()\n}\n\n// Bytes converts and returns `v` as []byte.\nfunc (v *Var) Bytes() []byte {\n\treturn gconv.Bytes(v.Val())\n}\n\n// String converts and returns `v` as string.\nfunc (v *Var) String() string {\n\treturn gconv.String(v.Val())\n}\n\n// Bool converts and returns `v` as bool.\nfunc (v *Var) Bool() bool {\n\treturn gconv.Bool(v.Val())\n}\n\n// Int converts and returns `v` as int.\nfunc (v *Var) Int() int {\n\treturn gconv.Int(v.Val())\n}\n\n// Int8 converts and returns `v` as int8.\nfunc (v *Var) Int8() int8 {\n\treturn gconv.Int8(v.Val())\n}\n\n// Int16 converts and returns `v` as int16.\nfunc (v *Var) Int16() int16 {\n\treturn gconv.Int16(v.Val())\n}\n\n// Int32 converts and returns `v` as int32.\nfunc (v *Var) Int32() int32 {\n\treturn gconv.Int32(v.Val())\n}\n\n// Int64 converts and returns `v` as int64.\nfunc (v *Var) Int64() int64 {\n\treturn gconv.Int64(v.Val())\n}\n\n// Uint converts and returns `v` as uint.\nfunc (v *Var) Uint() uint {\n\treturn gconv.Uint(v.Val())\n}\n\n// Uint8 converts and returns `v` as uint8.\nfunc (v *Var) Uint8() uint8 {\n\treturn gconv.Uint8(v.Val())\n}\n\n// Uint16 converts and returns `v` as uint16.\nfunc (v *Var) Uint16() uint16 {\n\treturn gconv.Uint16(v.Val())\n}\n\n// Uint32 converts and returns `v` as uint32.\nfunc (v *Var) Uint32() uint32 {\n\treturn gconv.Uint32(v.Val())\n}\n\n// Uint64 converts and returns `v` as uint64.\nfunc (v *Var) Uint64() uint64 {\n\treturn gconv.Uint64(v.Val())\n}\n\n// Float32 converts and returns `v` as float32.\nfunc (v *Var) Float32() float32 {\n\treturn gconv.Float32(v.Val())\n}\n\n// Float64 converts and returns `v` as float64.\nfunc (v *Var) Float64() float64 {\n\treturn gconv.Float64(v.Val())\n}\n"
  },
  {
    "path": "container/gvar/gvar_copy.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Copy does a deep copy of current Var and returns a pointer to this Var.\nfunc (v *Var) Copy() *Var {\n\treturn New(gutil.Copy(v.Val()), v.safe)\n}\n\n// Clone does a shallow copy of current Var and returns a pointer to this Var.\nfunc (v *Var) Clone() *Var {\n\treturn New(v.Val(), v.safe)\n}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (v *Var) DeepCopy() any {\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn New(deepcopy.Copy(v.Val()), v.safe)\n}\n"
  },
  {
    "path": "container/gvar/gvar_is.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// IsNil checks whether `v` is nil.\nfunc (v *Var) IsNil() bool {\n\treturn utils.IsNil(v.Val())\n}\n\n// IsEmpty checks whether `v` is empty.\nfunc (v *Var) IsEmpty() bool {\n\treturn utils.IsEmpty(v.Val())\n}\n\n// IsInt checks whether `v` is type of int.\nfunc (v *Var) IsInt() bool {\n\treturn utils.IsInt(v.Val())\n}\n\n// IsUint checks whether `v` is type of uint.\nfunc (v *Var) IsUint() bool {\n\treturn utils.IsUint(v.Val())\n}\n\n// IsFloat checks whether `v` is type of float.\nfunc (v *Var) IsFloat() bool {\n\treturn utils.IsFloat(v.Val())\n}\n\n// IsSlice checks whether `v` is type of slice.\nfunc (v *Var) IsSlice() bool {\n\treturn utils.IsSlice(v.Val())\n}\n\n// IsMap checks whether `v` is type of map.\nfunc (v *Var) IsMap() bool {\n\treturn utils.IsMap(v.Val())\n}\n\n// IsStruct checks whether `v` is type of struct.\nfunc (v *Var) IsStruct() bool {\n\treturn utils.IsStruct(v.Val())\n}\n"
  },
  {
    "path": "container/gvar/gvar_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\nfunc (v *Var) ListItemValues(key any) (values []any) {\n\treturn gutil.ListItemValues(v.Val(), key)\n}\n\n// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\nfunc (v *Var) ListItemValuesUnique(key string) []any {\n\treturn gutil.ListItemValuesUnique(v.Val(), key)\n}\n"
  },
  {
    "path": "container/gvar/gvar_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport \"github.com/gogf/gf/v2/util/gconv\"\n\n// MapOption specifies the option for map converting.\ntype MapOption = gconv.MapOption\n\n// Map converts and returns `v` as map[string]any.\nfunc (v *Var) Map(option ...MapOption) map[string]any {\n\treturn gconv.Map(v.Val(), option...)\n}\n\n// MapStrAny is like function Map, but implements the interface of MapStrAny.\nfunc (v *Var) MapStrAny(option ...MapOption) map[string]any {\n\treturn v.Map(option...)\n}\n\n// MapStrStr converts and returns `v` as map[string]string.\nfunc (v *Var) MapStrStr(option ...MapOption) map[string]string {\n\treturn gconv.MapStrStr(v.Val(), option...)\n}\n\n// MapStrVar converts and returns `v` as map[string]Var.\nfunc (v *Var) MapStrVar(option ...MapOption) map[string]*Var {\n\tm := v.Map(option...)\n\tif len(m) > 0 {\n\t\tvMap := make(map[string]*Var, len(m))\n\t\tfor k, v := range m {\n\t\t\tvMap[k] = New(v)\n\t\t}\n\t\treturn vMap\n\t}\n\treturn nil\n}\n\n// MapDeep converts and returns `v` as map[string]any recursively.\n//\n// Deprecated: used Map instead.\nfunc (v *Var) MapDeep(tags ...string) map[string]any {\n\treturn gconv.MapDeep(v.Val(), tags...)\n}\n\n// MapStrStrDeep converts and returns `v` as map[string]string recursively.\n//\n// Deprecated: used MapStrStr instead.\nfunc (v *Var) MapStrStrDeep(tags ...string) map[string]string {\n\treturn gconv.MapStrStrDeep(v.Val(), tags...)\n}\n\n// MapStrVarDeep converts and returns `v` as map[string]*Var recursively.\n//\n// Deprecated: used MapStrVar instead.\nfunc (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {\n\tm := v.MapDeep(tags...)\n\tif len(m) > 0 {\n\t\tvMap := make(map[string]*Var, len(m))\n\t\tfor k, v := range m {\n\t\t\tvMap[k] = New(v)\n\t\t}\n\t\treturn vMap\n\t}\n\treturn nil\n}\n\n// Maps converts and returns `v` as map[string]string.\n// See gconv.Maps.\nfunc (v *Var) Maps(option ...MapOption) []map[string]any {\n\treturn gconv.Maps(v.Val(), option...)\n}\n\n// MapsDeep converts `value` to []map[string]any recursively.\n//\n// Deprecated: used Maps instead.\nfunc (v *Var) MapsDeep(tags ...string) []map[string]any {\n\treturn gconv.MapsDeep(v.Val(), tags...)\n}\n\n// MapToMap converts any map type variable `params` to another map type variable `pointer`.\n// See gconv.MapToMap.\nfunc (v *Var) MapToMap(pointer any, mapping ...map[string]string) (err error) {\n\treturn gconv.MapToMap(v.Val(), pointer, mapping...)\n}\n\n// MapToMaps converts any map type variable `params` to another map type variable `pointer`.\n// See gconv.MapToMaps.\nfunc (v *Var) MapToMaps(pointer any, mapping ...map[string]string) (err error) {\n\treturn gconv.MapToMaps(v.Val(), pointer, mapping...)\n}\n\n// MapToMapsDeep converts any map type variable `params` to another map type variable\n// `pointer` recursively.\n// See gconv.MapToMapsDeep.\nfunc (v *Var) MapToMapsDeep(pointer any, mapping ...map[string]string) (err error) {\n\treturn gconv.MapToMaps(v.Val(), pointer, mapping...)\n}\n"
  },
  {
    "path": "container/gvar/gvar_scan.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Scan automatically checks the type of `pointer` and converts value of Var to `pointer`.\n//\n// See gconv.Scan.\nfunc (v *Var) Scan(pointer any, mapping ...map[string]string) error {\n\treturn gconv.Scan(v.Val(), pointer, mapping...)\n}\n"
  },
  {
    "path": "container/gvar/gvar_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gtype\"\n)\n\n// Set sets `value` to `v`, and returns the old value.\nfunc (v *Var) Set(value any) (old any) {\n\tif v.safe {\n\t\tif t, ok := v.value.(*gtype.Interface); ok {\n\t\t\told = t.Set(value)\n\t\t\treturn\n\t\t}\n\t}\n\told = v.value\n\tv.value = value\n\treturn\n}\n"
  },
  {
    "path": "container/gvar/gvar_slice.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport \"github.com/gogf/gf/v2/util/gconv\"\n\n// Bools converts and returns `v` as []bool.\nfunc (v *Var) Bools() []bool {\n\treturn gconv.Bools(v.Val())\n}\n\n// Ints converts and returns `v` as []int.\nfunc (v *Var) Ints() []int {\n\treturn gconv.Ints(v.Val())\n}\n\n// Int64s converts and returns `v` as []int64.\nfunc (v *Var) Int64s() []int64 {\n\treturn gconv.Int64s(v.Val())\n}\n\n// Uints converts and returns `v` as []uint.\nfunc (v *Var) Uints() []uint {\n\treturn gconv.Uints(v.Val())\n}\n\n// Uint64s converts and returns `v` as []uint64.\nfunc (v *Var) Uint64s() []uint64 {\n\treturn gconv.Uint64s(v.Val())\n}\n\n// Floats is alias of Float64s.\nfunc (v *Var) Floats() []float64 {\n\treturn gconv.Floats(v.Val())\n}\n\n// Float32s converts and returns `v` as []float32.\nfunc (v *Var) Float32s() []float32 {\n\treturn gconv.Float32s(v.Val())\n}\n\n// Float64s converts and returns `v` as []float64.\nfunc (v *Var) Float64s() []float64 {\n\treturn gconv.Float64s(v.Val())\n}\n\n// Strings converts and returns `v` as []string.\nfunc (v *Var) Strings() []string {\n\treturn gconv.Strings(v.Val())\n}\n\n// Interfaces converts and returns `v` as []interfaces{}.\nfunc (v *Var) Interfaces() []any {\n\treturn gconv.Interfaces(v.Val())\n}\n\n// Slice is alias of Interfaces.\nfunc (v *Var) Slice() []any {\n\treturn v.Interfaces()\n}\n\n// Array is alias of Interfaces.\nfunc (v *Var) Array() []any {\n\treturn v.Interfaces()\n}\n\n// Vars converts and returns `v` as []Var.\nfunc (v *Var) Vars() []*Var {\n\tarray := gconv.Interfaces(v.Val())\n\tif len(array) == 0 {\n\t\treturn nil\n\t}\n\tvars := make([]*Var, len(array))\n\tfor k, v := range array {\n\t\tvars[k] = New(v)\n\t}\n\treturn vars\n}\n"
  },
  {
    "path": "container/gvar/gvar_struct.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Struct maps value of `v` to `pointer`.\n// The parameter `pointer` should be a pointer to a struct instance.\n// The parameter `mapping` is used to specify the key-to-attribute mapping rules.\nfunc (v *Var) Struct(pointer any, mapping ...map[string]string) error {\n\treturn gconv.Struct(v.Val(), pointer, mapping...)\n}\n\n// Structs converts and returns `v` as given struct slice.\nfunc (v *Var) Structs(pointer any, mapping ...map[string]string) error {\n\treturn gconv.Structs(v.Val(), pointer, mapping...)\n}\n"
  },
  {
    "path": "container/gvar/gvar_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Time converts and returns `v` as time.Time.\n// The parameter `format` specifies the format of the time string using gtime,\n// eg: Y-m-d H:i:s.\nfunc (v *Var) Time(format ...string) time.Time {\n\treturn gconv.Time(v.Val(), format...)\n}\n\n// Duration converts and returns `v` as time.Duration.\n// If value of `v` is string, then it uses time.ParseDuration for conversion.\nfunc (v *Var) Duration() time.Duration {\n\treturn gconv.Duration(v.Val())\n}\n\n// GTime converts and returns `v` as *gtime.Time.\n// The parameter `format` specifies the format of the time string using gtime,\n// eg: Y-m-d H:i:s.\nfunc (v *Var) GTime(format ...string) *gtime.Time {\n\treturn gconv.GTime(v.Val(), format...)\n}\n"
  },
  {
    "path": "container/gvar/gvar_vars.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar\n\nimport (\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Vars is a slice of *Var.\ntype Vars []*Var\n\n// Strings converts and returns `vs` as []string.\nfunc (vs Vars) Strings() (s []string) {\n\ts = make([]string, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.String())\n\t}\n\treturn s\n}\n\n// Bools converts and returns `vs` as []bool.\nfunc (vs Vars) Bools() (s []bool) {\n\ts = make([]bool, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Bool())\n\t}\n\treturn s\n}\n\n// Interfaces converts and returns `vs` as []any.\nfunc (vs Vars) Interfaces() (s []any) {\n\ts = make([]any, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Val())\n\t}\n\treturn s\n}\n\n// Float32s converts and returns `vs` as []float32.\nfunc (vs Vars) Float32s() (s []float32) {\n\ts = make([]float32, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Float32())\n\t}\n\treturn s\n}\n\n// Float64s converts and returns `vs` as []float64.\nfunc (vs Vars) Float64s() (s []float64) {\n\ts = make([]float64, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Float64())\n\t}\n\treturn s\n}\n\n// Ints converts and returns `vs` as []Int.\nfunc (vs Vars) Ints() (s []int) {\n\ts = make([]int, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Int())\n\t}\n\treturn s\n}\n\n// Int8s converts and returns `vs` as []int8.\nfunc (vs Vars) Int8s() (s []int8) {\n\ts = make([]int8, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Int8())\n\t}\n\treturn s\n}\n\n// Int16s converts and returns `vs` as []int16.\nfunc (vs Vars) Int16s() (s []int16) {\n\ts = make([]int16, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Int16())\n\t}\n\treturn s\n}\n\n// Int32s converts and returns `vs` as []int32.\nfunc (vs Vars) Int32s() (s []int32) {\n\ts = make([]int32, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Int32())\n\t}\n\treturn s\n}\n\n// Int64s converts and returns `vs` as []int64.\nfunc (vs Vars) Int64s() (s []int64) {\n\ts = make([]int64, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Int64())\n\t}\n\treturn s\n}\n\n// Uints converts and returns `vs` as []uint.\nfunc (vs Vars) Uints() (s []uint) {\n\ts = make([]uint, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Uint())\n\t}\n\treturn s\n}\n\n// Uint8s converts and returns `vs` as []uint8.\nfunc (vs Vars) Uint8s() (s []uint8) {\n\ts = make([]uint8, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Uint8())\n\t}\n\treturn s\n}\n\n// Uint16s converts and returns `vs` as []uint16.\nfunc (vs Vars) Uint16s() (s []uint16) {\n\ts = make([]uint16, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Uint16())\n\t}\n\treturn s\n}\n\n// Uint32s converts and returns `vs` as []uint32.\nfunc (vs Vars) Uint32s() (s []uint32) {\n\ts = make([]uint32, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Uint32())\n\t}\n\treturn s\n}\n\n// Uint64s converts and returns `vs` as []uint64.\nfunc (vs Vars) Uint64s() (s []uint64) {\n\ts = make([]uint64, 0, len(vs))\n\tfor _, v := range vs {\n\t\ts = append(s, v.Uint64())\n\t}\n\treturn s\n}\n\n// Scan converts `vs` to []struct/[]*struct.\nfunc (vs Vars) Scan(pointer any, mapping ...map[string]string) error {\n\treturn gconv.Structs(vs.Interfaces(), pointer, mapping...)\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_bench_ptr_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gvar\n\nimport \"testing\"\n\nvar varPtr = New(nil)\n\nfunc Benchmark_Ptr_Set(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Set(i)\n\t}\n}\n\nfunc Benchmark_Ptr_Val(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Val()\n\t}\n}\n\nfunc Benchmark_Ptr_IsNil(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.IsNil()\n\t}\n}\n\nfunc Benchmark_Ptr_Bytes(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Bytes()\n\t}\n}\n\nfunc Benchmark_Ptr_String(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.String()\n\t}\n}\n\nfunc Benchmark_Ptr_Bool(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Bool()\n\t}\n}\n\nfunc Benchmark_Ptr_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Int()\n\t}\n}\n\nfunc Benchmark_Ptr_Int8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Int8()\n\t}\n}\n\nfunc Benchmark_Ptr_Int16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Int16()\n\t}\n}\n\nfunc Benchmark_Ptr_Int32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Int32()\n\t}\n}\n\nfunc Benchmark_Ptr_Int64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Int64()\n\t}\n}\n\nfunc Benchmark_Ptr_Uint(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Uint()\n\t}\n}\n\nfunc Benchmark_Ptr_Uint8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Uint8()\n\t}\n}\n\nfunc Benchmark_Ptr_Uint16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Uint16()\n\t}\n}\n\nfunc Benchmark_Ptr_Uint32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Uint32()\n\t}\n}\n\nfunc Benchmark_Ptr_Uint64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Uint64()\n\t}\n}\n\nfunc Benchmark_Ptr_Float32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Float32()\n\t}\n}\n\nfunc Benchmark_Ptr_Float64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Float64()\n\t}\n}\n\nfunc Benchmark_Ptr_Ints(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Ints()\n\t}\n}\n\nfunc Benchmark_Ptr_Strings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Strings()\n\t}\n}\n\nfunc Benchmark_Ptr_Floats(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Floats()\n\t}\n}\n\nfunc Benchmark_Ptr_Interfaces(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvarPtr.Interfaces()\n\t}\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// New\nfunc ExampleNew() {\n\tv := gvar.New(400)\n\tfmt.Println(v)\n\n\t// Output:\n\t// 400\n}\n\n// Clone\nfunc ExampleVar_Clone() {\n\ttmp := \"fisrt hello\"\n\tv := gvar.New(tmp)\n\tg.DumpWithType(v.Clone())\n\tfmt.Println(v == v.Clone())\n\n\t// Output:\n\t// *gvar.Var(11) \"fisrt hello\"\n\t// false\n}\n\n// Set\nfunc ExampleVar_Set() {\n\tvar v = gvar.New(100.00)\n\tg.Dump(v.Set(200.00))\n\tg.Dump(v)\n\n\t// Output:\n\t// 100\n\t// \"200\"\n}\n\n// Val\nfunc ExampleVar_Val() {\n\tvar v = gvar.New(100.00)\n\tg.DumpWithType(v.Val())\n\n\t// Output:\n\t// float64(100)\n}\n\n// Interface\nfunc ExampleVar_Interface() {\n\tvar v = gvar.New(100.00)\n\tg.DumpWithType(v.Interface())\n\n\t// Output:\n\t// float64(100)\n}\n\n// Bytes\nfunc ExampleVar_Bytes() {\n\tvar v = gvar.New(\"GoFrame\")\n\tg.DumpWithType(v.Bytes())\n\n\t// Output:\n\t// []byte(7) \"GoFrame\"\n}\n\n// String\nfunc ExampleVar_String() {\n\tvar v = gvar.New(\"GoFrame\")\n\tg.DumpWithType(v.String())\n\n\t// Output:\n\t// string(7) \"GoFrame\"\n}\n\n// Bool\nfunc ExampleVar_Bool() {\n\tvar v = gvar.New(true)\n\tg.DumpWithType(v.Bool())\n\n\t// Output:\n\t// bool(true)\n}\n\n// Int\nfunc ExampleVar_Int() {\n\tvar v = gvar.New(-1000)\n\tg.DumpWithType(v.Int())\n\n\t// Output:\n\t// int(-1000)\n}\n\n// Uint\nfunc ExampleVar_Uint() {\n\tvar v = gvar.New(1000)\n\tg.DumpWithType(v.Uint())\n\n\t// Output:\n\t// uint(1000)\n}\n\n// Float32\nfunc ExampleVar_Float32() {\n\tvar price = gvar.New(100.00)\n\tg.DumpWithType(price.Float32())\n\n\t// Output:\n\t// float32(100)\n}\n\n// Time\nfunc ExampleVar_Time() {\n\tvar v = gvar.New(\"2021-11-11 00:00:00\")\n\tg.DumpWithType(v.Time())\n\n\t// Output:\n\t// time.Time(29) \"2021-11-11 00:00:00 +0800 CST\"\n}\n\n// GTime\nfunc ExampleVar_GTime() {\n\tvar v = gvar.New(\"2021-11-11 00:00:00\")\n\tg.DumpWithType(v.GTime())\n\n\t// Output:\n\t// *gtime.Time(19) \"2021-11-11 00:00:00\"\n}\n\n// Duration\nfunc ExampleVar_Duration() {\n\tvar v = gvar.New(\"300s\")\n\tg.DumpWithType(v.Duration())\n\n\t// Output:\n\t// time.Duration(4) \"5m0s\"\n}\n\n// MarshalJSON\nfunc ExampleVar_MarshalJSON() {\n\ttestMap := g.Map{\n\t\t\"code\":  \"0001\",\n\t\t\"name\":  \"Golang\",\n\t\t\"count\": 10,\n\t}\n\n\tvar v = gvar.New(testMap)\n\tres, err := json.Marshal(&v)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tg.DumpWithType(res)\n\n\t// Output:\n\t// []byte(42) \"{\"code\":\"0001\",\"count\":10,\"name\":\"Golang\"}\"\n}\n\n// UnmarshalJSON\nfunc ExampleVar_UnmarshalJSON() {\n\ttmp := []byte(`{\n\t     \"Code\":          \"0003\",\n\t     \"Name\":          \"Golang Book3\",\n\t     \"Quantity\":      3000,\n\t     \"Price\":         300,\n\t     \"OnSale\":        true\n\t}`)\n\tvar v = gvar.New(map[string]any{})\n\tif err := json.Unmarshal(tmp, &v); err != nil {\n\t\tpanic(err)\n\t}\n\n\tg.Dump(v)\n\n\t// Output:\n\t// \"{\\\"Code\\\":\\\"0003\\\",\\\"Name\\\":\\\"Golang Book3\\\",\\\"OnSale\\\":true,\\\"Price\\\":300,\\\"Quantity\\\":3000}\"\n}\n\n// UnmarshalValue\nfunc ExampleVar_UnmarshalValue() {\n\ttmp := g.Map{\n\t\t\"code\":  \"00002\",\n\t\t\"name\":  \"GoFrame\",\n\t\t\"price\": 100,\n\t\t\"sale\":  true,\n\t}\n\n\tvar v = gvar.New(map[string]any{})\n\tif err := v.UnmarshalValue(tmp); err != nil {\n\t\tpanic(err)\n\t}\n\tg.Dump(v)\n\n\t// Output:\n\t// \"{\\\"code\\\":\\\"00002\\\",\\\"name\\\":\\\"GoFrame\\\",\\\"price\\\":100,\\\"sale\\\":true}\"\n}\n\n// IsNil\nfunc ExampleVar_IsNil() {\n\tg.Dump(gvar.New(0).IsNil())\n\tg.Dump(gvar.New(0.1).IsNil())\n\t// true\n\tg.Dump(gvar.New(nil).IsNil())\n\tg.Dump(gvar.New(\"\").IsNil())\n\n\t// Output:\n\t// false\n\t// false\n\t// true\n\t// false\n}\n\n// IsEmpty\nfunc ExampleVar_IsEmpty() {\n\tg.Dump(gvar.New(0).IsEmpty())\n\tg.Dump(gvar.New(nil).IsEmpty())\n\tg.Dump(gvar.New(\"\").IsEmpty())\n\tg.Dump(gvar.New(g.Map{\"k\": \"v\"}).IsEmpty())\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// false\n}\n\n// IsInt\nfunc ExampleVar_IsInt() {\n\tg.Dump(gvar.New(0).IsInt())\n\tg.Dump(gvar.New(0.1).IsInt())\n\tg.Dump(gvar.New(nil).IsInt())\n\tg.Dump(gvar.New(\"\").IsInt())\n\n\t// Output:\n\t// true\n\t// false\n\t// false\n\t// false\n}\n\n// IsUint\nfunc ExampleVar_IsUint() {\n\tg.Dump(gvar.New(0).IsUint())\n\tg.Dump(gvar.New(uint8(8)).IsUint())\n\tg.Dump(gvar.New(nil).IsUint())\n\n\t// Output:\n\t// false\n\t// true\n\t// false\n}\n\n// IsFloat\nfunc ExampleVar_IsFloat() {\n\tg.Dump(g.NewVar(uint8(8)).IsFloat())\n\tg.Dump(g.NewVar(float64(8)).IsFloat())\n\tg.Dump(g.NewVar(0.1).IsFloat())\n\n\t// Output:\n\t// false\n\t// true\n\t// true\n}\n\n// IsSlice\nfunc ExampleVar_IsSlice() {\n\tg.Dump(g.NewVar(0).IsSlice())\n\tg.Dump(g.NewVar(g.Slice{0}).IsSlice())\n\n\t// Output:\n\t// false\n\t// true\n}\n\n// IsMap\nfunc ExampleVar_IsMap() {\n\tg.Dump(g.NewVar(0).IsMap())\n\tg.Dump(g.NewVar(g.Map{\"k\": \"v\"}).IsMap())\n\tg.Dump(g.NewVar(g.Slice{}).IsMap())\n\n\t// Output:\n\t// false\n\t// true\n\t// false\n}\n\n// IsStruct\nfunc ExampleVar_IsStruct() {\n\tg.Dump(g.NewVar(0).IsStruct())\n\tg.Dump(g.NewVar(g.Map{\"k\": \"v\"}).IsStruct())\n\n\ta := struct{}{}\n\tg.Dump(g.NewVar(a).IsStruct())\n\tg.Dump(g.NewVar(&a).IsStruct())\n\n\t// Output:\n\t// false\n\t// false\n\t// true\n\t// true\n}\n\n// ListItemValues\nfunc ExampleVar_ListItemValues() {\n\tvar goods1 = g.List{\n\t\tg.Map{\"id\": 1, \"price\": 100.00},\n\t\tg.Map{\"id\": 2, \"price\": 0},\n\t\tg.Map{\"id\": 3, \"price\": nil},\n\t}\n\tvar v = gvar.New(goods1)\n\tfmt.Println(v.ListItemValues(\"id\"))\n\tfmt.Println(v.ListItemValues(\"price\"))\n\n\t// Output:\n\t// [1 2 3]\n\t// [100 0 <nil>]\n}\n\n// ListItemValuesUnique\nfunc ExampleVar_ListItemValuesUnique() {\n\tvar (\n\t\tgoods1 = g.List{\n\t\t\tg.Map{\"id\": 1, \"price\": 100.00},\n\t\t\tg.Map{\"id\": 2, \"price\": 100.00},\n\t\t\tg.Map{\"id\": 3, \"price\": nil},\n\t\t}\n\t\tv = gvar.New(goods1)\n\t)\n\n\tfmt.Println(v.ListItemValuesUnique(\"id\"))\n\tfmt.Println(v.ListItemValuesUnique(\"price\"))\n\n\t// Output:\n\t// [1 2 3]\n\t// [100 <nil>]\n}\n\nfunc ExampleVar_Struct() {\n\tparams1 := g.Map{\n\t\t\"uid\":  1,\n\t\t\"Name\": \"john\",\n\t}\n\tv := gvar.New(params1)\n\ttype tartget struct {\n\t\tUid  int\n\t\tName string\n\t}\n\tt := new(tartget)\n\tif err := v.Struct(&t); err != nil {\n\t\tpanic(err)\n\t}\n\tg.Dump(t)\n\n\t// Output:\n\t// {\n\t//     Uid:  1,\n\t//     Name: \"john\",\n\t// }\n}\n\nfunc ExampleVar_Structs() {\n\tparamsArray := []g.Map{}\n\tparams1 := g.Map{\n\t\t\"uid\":  1,\n\t\t\"Name\": \"golang\",\n\t}\n\tparams2 := g.Map{\n\t\t\"uid\":  2,\n\t\t\"Name\": \"java\",\n\t}\n\n\tparamsArray = append(paramsArray, params1, params2)\n\tv := gvar.New(paramsArray)\n\ttype tartget struct {\n\t\tUid  int\n\t\tName string\n\t}\n\tvar t []tartget\n\tif err := v.Structs(&t); err != nil {\n\t\tpanic(err)\n\t}\n\tg.DumpWithType(t)\n\n\t// Output:\n\t// []gvar_test.tartget(2) [\n\t//     gvar_test.tartget(2) {\n\t//         Uid:  int(1),\n\t//         Name: string(6) \"golang\",\n\t//     },\n\t//     gvar_test.tartget(2) {\n\t//         Uid:  int(2),\n\t//         Name: string(4) \"java\",\n\t//     },\n\t// ]\n}\n\n// Ints\nfunc ExampleVar_Ints() {\n\tvar (\n\t\tarr = []int{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Ints())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Int64s\nfunc ExampleVar_Int64s() {\n\tvar (\n\t\tarr = []int64{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Int64s())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Uints\nfunc ExampleVar_Uints() {\n\tvar (\n\t\tarr = []uint{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\tfmt.Println(obj.Uints())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Uint64s\nfunc ExampleVar_Uint64s() {\n\tvar (\n\t\tarr = []uint64{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Uint64s())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Floats\nfunc ExampleVar_Floats() {\n\tvar (\n\t\tarr = []float64{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Floats())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Float32s\nfunc ExampleVar_Float32s() {\n\tvar (\n\t\tarr = []float32{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Float32s())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Float64s\nfunc ExampleVar_Float64s() {\n\tvar (\n\t\tarr = []float64{1, 2, 3, 4, 5}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Float64s())\n\n\t// Output:\n\t// [1 2 3 4 5]\n}\n\n// Strings\nfunc ExampleVar_Strings() {\n\tvar (\n\t\tarr = []string{\"GoFrame\", \"Golang\"}\n\t\tobj = gvar.New(arr)\n\t)\n\tfmt.Println(obj.Strings())\n\n\t// Output:\n\t// [GoFrame Golang]\n}\n\n// Interfaces\nfunc ExampleVar_Interfaces() {\n\tvar (\n\t\tarr = []string{\"GoFrame\", \"Golang\"}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Interfaces())\n\n\t// Output:\n\t// [GoFrame Golang]\n}\n\n// Slice\nfunc ExampleVar_Slice() {\n\tvar (\n\t\tarr = []string{\"GoFrame\", \"Golang\"}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Slice())\n\n\t// Output:\n\t// [GoFrame Golang]\n}\n\n// Array\nfunc ExampleVar_Array() {\n\tvar (\n\t\tarr = []string{\"GoFrame\", \"Golang\"}\n\t\tobj = gvar.New(arr)\n\t)\n\tfmt.Println(obj.Array())\n\n\t// Output:\n\t// [GoFrame Golang]\n}\n\n// Vars\nfunc ExampleVar_Vars() {\n\tvar (\n\t\tarr = []string{\"GoFrame\", \"Golang\"}\n\t\tobj = gvar.New(arr)\n\t)\n\n\tfmt.Println(obj.Vars())\n\n\t// Output:\n\t// [GoFrame Golang]\n}\n\n// Map\nfunc ExampleVar_Map() {\n\tvar (\n\t\tm   = g.Map{\"id\": 1, \"price\": 100.00}\n\t\tv   = gvar.New(m)\n\t\tres = v.Map()\n\t)\n\n\tfmt.Println(res[\"id\"], res[\"price\"])\n\n\t// Output:\n\t// 1 100\n}\n\n// MapStrAny\nfunc ExampleVar_MapStrAny() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tv  = gvar.New(m1)\n\t\tv2 = v.MapStrAny()\n\t)\n\n\tfmt.Println(v2[\"price\"], v2[\"id\"])\n\n\t// Output:\n\t// 100 1\n}\n\n// MapStrStr\nfunc ExampleVar_MapStrStr() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tv  = gvar.New(m1)\n\t\tv2 = v.MapStrStr()\n\t)\n\n\tfmt.Println(v2[\"price\"] + \"$\")\n\n\t// Output:\n\t// 100$\n}\n\n// MapStrVar\nfunc ExampleVar_MapStrVar() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tv  = gvar.New(m1)\n\t\tv2 = v.MapStrVar()\n\t)\n\n\tfmt.Println(v2[\"price\"].Float64() * 100)\n\n\t// Output:\n\t// 10000\n}\n\n// MapDeep\nfunc ExampleVar_MapDeep() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tm2 = g.Map{\"product\": m1}\n\t\tv  = gvar.New(m2)\n\t\tv2 = v.MapDeep()\n\t)\n\n\tfmt.Println(v2[\"product\"])\n\n\t// Output:\n\t// map[id:1 price:100]\n}\n\n// MapStrStrDeep\nfunc ExampleVar_MapStrStrDeep() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tm2 = g.Map{\"product\": m1}\n\t\tv  = gvar.New(m2)\n\t\tv2 = v.MapStrStrDeep()\n\t)\n\n\tfmt.Println(v2[\"product\"])\n\n\t// Output:\n\t// {\"id\":1,\"price\":100}\n}\n\n// MapStrVarDeep\nfunc ExampleVar_MapStrVarDeep() {\n\tvar (\n\t\tm1 = g.Map{\"id\": 1, \"price\": 100}\n\t\tm2 = g.Map{\"product\": m1}\n\t\tm3 = g.Map{}\n\t\tv  = gvar.New(m2)\n\t\tv2 = v.MapStrVarDeep()\n\t\tv3 = gvar.New(m3).MapStrVarDeep()\n\t)\n\n\tfmt.Println(v2[\"product\"])\n\tfmt.Println(v3)\n\n\t// Output:\n\t// {\"id\":1,\"price\":100}\n\t// map[]\n}\n\n// Maps\nfunc ExampleVar_Maps() {\n\tvar m = gvar.New(g.ListIntInt{g.MapIntInt{0: 100, 1: 200}, g.MapIntInt{0: 300, 1: 400}})\n\tfmt.Printf(\"%#v\", m.Maps())\n\n\t// Output:\n\t// []map[string]interface {}{map[string]interface {}{\"0\":100, \"1\":200}, map[string]interface {}{\"0\":300, \"1\":400}}\n}\n\n// MapsDeep\nfunc ExampleVar_MapsDeep() {\n\tvar (\n\t\tp1 = g.MapStrAny{\"product\": g.Map{\"id\": 1, \"price\": 100}}\n\t\tp2 = g.MapStrAny{\"product\": g.Map{\"id\": 2, \"price\": 200}}\n\t\tv  = gvar.New(g.ListStrAny{p1, p2})\n\t\tv2 = v.MapsDeep()\n\t)\n\n\tfmt.Printf(\"%#v\", v2)\n\n\t// Output:\n\t// []map[string]interface {}{map[string]interface {}{\"product\":map[string]interface {}{\"id\":1, \"price\":100}}, map[string]interface {}{\"product\":map[string]interface {}{\"id\":2, \"price\":200}}}\n}\n\n// MapToMap\nfunc ExampleVar_MapToMap() {\n\tvar (\n\t\tm1 = gvar.New(g.MapIntInt{0: 100, 1: 200})\n\t\tm2 = g.MapStrStr{}\n\t)\n\n\terr := m1.MapToMap(&m2)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", m2)\n\n\t// Output:\n\t// map[string]string{\"0\":\"100\", \"1\":\"200\"}\n}\n\n// MapToMaps\nfunc ExampleVar_MapToMaps() {\n\tvar (\n\t\tp1 = g.MapStrAny{\"product\": g.Map{\"id\": 1, \"price\": 100}}\n\t\tp2 = g.MapStrAny{\"product\": g.Map{\"id\": 2, \"price\": 200}}\n\t\tv  = gvar.New(g.ListStrAny{p1, p2})\n\t\tv2 []g.MapStrStr\n\t)\n\n\terr := v.MapToMaps(&v2)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"%#v\", v2)\n\n\t// Output:\n\t// []map[string]string{map[string]string{\"product\":\"{\\\"id\\\":1,\\\"price\\\":100}\"}, map[string]string{\"product\":\"{\\\"id\\\":2,\\\"price\\\":200}\"}}\n}\n\n// MapToMapsDeep\nfunc ExampleVar_MapToMapsDeep() {\n\tvar (\n\t\tp1 = g.MapStrAny{\"product\": g.Map{\"id\": 1, \"price\": 100}}\n\t\tp2 = g.MapStrAny{\"product\": g.Map{\"id\": 2, \"price\": 200}}\n\t\tv  = gvar.New(g.ListStrAny{p1, p2})\n\t\tv2 []g.MapStrStr\n\t)\n\n\terr := v.MapToMapsDeep(&v2)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"%#v\", v2)\n\n\t// Output:\n\t// []map[string]string{map[string]string{\"product\":\"{\\\"id\\\":1,\\\"price\\\":100}\"}, map[string]string{\"product\":\"{\\\"id\\\":2,\\\"price\\\":200}\"}}\n}\n\n// Scan\nfunc ExampleVar_Scan() {\n\ttype Student struct {\n\t\tId     *g.Var\n\t\tName   *g.Var\n\t\tScores *g.Var\n\t}\n\tvar (\n\t\ts Student\n\t\tm = g.Map{\n\t\t\t\"Id\":     1,\n\t\t\t\"Name\":   \"john\",\n\t\t\t\"Scores\": []int{100, 99, 98},\n\t\t}\n\t)\n\tv := gvar.New(m)\n\tif err := v.Scan(&s); err == nil {\n\t\tg.DumpWithType(s)\n\t}\n\n\t// Output:\n\t// gvar_test.Student(3) {\n\t//     Id:     *gvar.Var(1) \"1\",\n\t//     Name:   *gvar.Var(4) \"john\",\n\t//     Scores: *gvar.Var(11) \"[100,99,98]\",\n\t// }\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v gvar.Var\n\t\tv.Set(123.456)\n\t\tt.Assert(v.Val(), 123.456)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v gvar.Var\n\t\tv.Set(123.456)\n\t\tt.Assert(v.Val(), 123.456)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tobjOne := gvar.New(\"old\", true)\n\t\tobjOneOld, _ := objOne.Set(\"new\").(string)\n\t\tt.Assert(objOneOld, \"old\")\n\n\t\tobjTwo := gvar.New(\"old\", false)\n\t\tobjTwoOld, _ := objTwo.Set(\"new\").(string)\n\t\tt.Assert(objTwoOld, \"old\")\n\t})\n}\n\nfunc Test_Val(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tobjOne := gvar.New(1, true)\n\t\tobjOneOld, _ := objOne.Val().(int)\n\t\tt.Assert(objOneOld, 1)\n\n\t\tobjTwo := gvar.New(1, false)\n\t\tobjTwoOld, _ := objTwo.Val().(int)\n\t\tt.Assert(objTwoOld, 1)\n\n\t\tobjOne = nil\n\t\tt.Assert(objOne.Val(), nil)\n\t})\n}\n\nfunc Test_Interface(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tobjOne := gvar.New(1, true)\n\t\tobjOneOld, _ := objOne.Interface().(int)\n\t\tt.Assert(objOneOld, 1)\n\n\t\tobjTwo := gvar.New(1, false)\n\t\tobjTwoOld, _ := objTwo.Interface().(int)\n\t\tt.Assert(objTwoOld, 1)\n\t})\n}\n\nfunc Test_IsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tobjOne := gvar.New(nil, true)\n\t\tt.Assert(objOne.IsNil(), true)\n\n\t\tobjTwo := gvar.New(\"noNil\", false)\n\t\tt.Assert(objTwo.IsNil(), false)\n\n\t})\n}\n\nfunc Test_Bytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := int32(1)\n\t\tbytesBuffer := bytes.NewBuffer([]byte{})\n\t\tbinary.Write(bytesBuffer, binary.BigEndian, x)\n\n\t\tobjOne := gvar.New(bytesBuffer.Bytes(), true)\n\n\t\tbBuf := bytes.NewBuffer(objOne.Bytes())\n\t\tvar y int32\n\t\tbinary.Read(bBuf, binary.BigEndian, &y)\n\n\t\tt.Assert(x, y)\n\n\t})\n}\n\nfunc Test_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar str string = \"hello\"\n\t\tobjOne := gvar.New(str, true)\n\t\tt.Assert(objOne.String(), str)\n\n\t})\n}\n\nfunc Test_Bool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ok bool = true\n\t\tobjOne := gvar.New(ok, true)\n\t\tt.Assert(objOne.Bool(), ok)\n\n\t\tok = false\n\t\tobjTwo := gvar.New(ok, true)\n\t\tt.Assert(objTwo.Bool(), ok)\n\n\t})\n}\n\nfunc Test_Int(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num int = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Int(), num)\n\n\t})\n}\n\nfunc Test_Int8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num int8 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Int8(), num)\n\n\t})\n}\n\nfunc Test_Int16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num int16 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Int16(), num)\n\n\t})\n}\n\nfunc Test_Int32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num int32 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Int32(), num)\n\n\t})\n}\n\nfunc Test_Int64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num int64 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Int64(), num)\n\n\t})\n}\n\nfunc Test_Uint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num uint = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Uint(), num)\n\n\t})\n}\n\nfunc Test_Uint8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num uint8 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Uint8(), num)\n\n\t})\n}\n\nfunc Test_Uint16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num uint16 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Uint16(), num)\n\n\t})\n}\n\nfunc Test_Uint32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num uint32 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Uint32(), num)\n\n\t})\n}\n\nfunc Test_Uint64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num uint64 = 1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Uint64(), num)\n\n\t})\n}\n\nfunc Test_Float32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num float32 = 1.1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Float32(), num)\n\n\t})\n}\n\nfunc Test_Float64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar num float64 = 1.1\n\t\tobjOne := gvar.New(num, true)\n\t\tt.Assert(objOne.Float64(), num)\n\n\t})\n}\n\nfunc Test_Time(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar timeUnix int64 = 1556242660\n\t\tobjOne := gvar.New(timeUnix, true)\n\t\tt.Assert(objOne.Time().Unix(), timeUnix)\n\t})\n}\n\nfunc Test_GTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar timeUnix int64 = 1556242660\n\t\tobjOne := gvar.New(timeUnix, true)\n\t\tt.Assert(objOne.GTime().Unix(), timeUnix)\n\t})\n}\n\nfunc Test_Duration(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar timeUnix int64 = 1556242660\n\t\tobjOne := gvar.New(timeUnix, true)\n\t\tt.Assert(objOne.Duration(), time.Duration(timeUnix))\n\t})\n}\n\nfunc Test_UnmarshalJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype V struct {\n\t\t\tName string\n\t\t\tVar  *gvar.Var\n\t\t}\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"v\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.String(), \"v\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype V struct {\n\t\t\tName string\n\t\t\tVar  gvar.Var\n\t\t}\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"v\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.String(), \"v\")\n\t})\n}\n\nfunc Test_UnmarshalValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype V struct {\n\t\t\tName string\n\t\t\tVar  *gvar.Var\n\t\t}\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"v\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.String(), \"v\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype V struct {\n\t\t\tName string\n\t\t\tVar  gvar.Var\n\t\t}\n\t\tvar v *V\n\t\terr := gconv.Struct(map[string]any{\n\t\t\t\"name\": \"john\",\n\t\t\t\"var\":  \"v\",\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Var.String(), \"v\")\n\t})\n}\n\nfunc Test_Copy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tsrcVar := gvar.New(src)\n\t\tdstVar := srcVar.Copy()\n\t\tt.Assert(srcVar.Map(), src)\n\t\tt.Assert(dstVar.Map(), src)\n\n\t\tdstVar.Map()[\"k3\"] = \"v3\"\n\t\tt.Assert(srcVar.Map(), g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(dstVar.Map(), g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t})\n}\n\nfunc Test_DeepCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tsrcVar := gvar.New(src)\n\t\tcopyVar := srcVar.DeepCopy().(*gvar.Var)\n\t\tcopyVar.Set(g.Map{\n\t\t\t\"k3\": \"v3\",\n\t\t\t\"k4\": \"v4\",\n\t\t})\n\t\tt.AssertNE(srcVar, copyVar)\n\n\t\tsrcVar = nil\n\t\tt.AssertNil(srcVar.DeepCopy())\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_is_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_IsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsNil(), false)\n\t\tt.Assert(g.NewVar(nil).IsNil(), true)\n\t\tt.Assert(g.NewVar(g.Map{}).IsNil(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsNil(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsNil(), false)\n\t\tt.Assert(g.NewVar(0.1).IsNil(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsNil(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsNil(), false)\n\t})\n}\n\nfunc TestVar_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsEmpty(), true)\n\t\tt.Assert(g.NewVar(nil).IsEmpty(), true)\n\t\tt.Assert(g.NewVar(g.Map{}).IsEmpty(), true)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsEmpty(), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsEmpty(), false)\n\t\tt.Assert(g.NewVar(0.1).IsEmpty(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsEmpty(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsEmpty(), false)\n\t})\n}\n\nfunc TestVar_IsInt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsInt(), true)\n\t\tt.Assert(g.NewVar(nil).IsInt(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsInt(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsInt(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsInt(), true)\n\t\tt.Assert(g.NewVar(-1).IsInt(), true)\n\t\tt.Assert(g.NewVar(0.1).IsInt(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsInt(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsInt(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(int8(1)).IsInt(), true)\n\t\tt.Assert(g.NewVar(uint8(1)).IsInt(), false)\n\t})\n}\n\nfunc TestVar_IsUint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsUint(), false)\n\t\tt.Assert(g.NewVar(nil).IsUint(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsUint(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsUint(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsUint(), false)\n\t\tt.Assert(g.NewVar(-1).IsUint(), false)\n\t\tt.Assert(g.NewVar(0.1).IsUint(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsUint(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsUint(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(int8(1)).IsUint(), false)\n\t\tt.Assert(g.NewVar(uint8(1)).IsUint(), true)\n\t})\n}\n\nfunc TestVar_IsFloat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsFloat(), false)\n\t\tt.Assert(g.NewVar(nil).IsFloat(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsFloat(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsFloat(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsFloat(), false)\n\t\tt.Assert(g.NewVar(-1).IsFloat(), false)\n\t\tt.Assert(g.NewVar(0.1).IsFloat(), true)\n\t\tt.Assert(g.NewVar(float64(1)).IsFloat(), true)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsFloat(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsFloat(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(int8(1)).IsFloat(), false)\n\t\tt.Assert(g.NewVar(uint8(1)).IsFloat(), false)\n\t})\n}\n\nfunc TestVar_IsSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsSlice(), false)\n\t\tt.Assert(g.NewVar(nil).IsSlice(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsSlice(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsSlice(), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsSlice(), false)\n\t\tt.Assert(g.NewVar(-1).IsSlice(), false)\n\t\tt.Assert(g.NewVar(0.1).IsSlice(), false)\n\t\tt.Assert(g.NewVar(float64(1)).IsSlice(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsSlice(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsSlice(), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(int8(1)).IsSlice(), false)\n\t\tt.Assert(g.NewVar(uint8(1)).IsSlice(), false)\n\t})\n}\n\nfunc TestVar_IsMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsMap(), false)\n\t\tt.Assert(g.NewVar(nil).IsMap(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsMap(), true)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsMap(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsMap(), false)\n\t\tt.Assert(g.NewVar(-1).IsMap(), false)\n\t\tt.Assert(g.NewVar(0.1).IsMap(), false)\n\t\tt.Assert(g.NewVar(float64(1)).IsMap(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsMap(), true)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsMap(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(int8(1)).IsMap(), false)\n\t\tt.Assert(g.NewVar(uint8(1)).IsMap(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gvar.New(gvar.New(\"asd\")).IsMap(), false)\n\t\tt.Assert(gvar.New(&g.Map{\"k\": \"v\"}).IsMap(), true)\n\t})\n}\n\nfunc TestVar_IsStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(0).IsStruct(), false)\n\t\tt.Assert(g.NewVar(nil).IsStruct(), false)\n\t\tt.Assert(g.NewVar(g.Map{}).IsStruct(), false)\n\t\tt.Assert(g.NewVar(g.Slice{}).IsStruct(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).IsStruct(), false)\n\t\tt.Assert(g.NewVar(-1).IsStruct(), false)\n\t\tt.Assert(g.NewVar(0.1).IsStruct(), false)\n\t\tt.Assert(g.NewVar(float64(1)).IsStruct(), false)\n\t\tt.Assert(g.NewVar(g.Map{\"k\": \"v\"}).IsStruct(), false)\n\t\tt.Assert(g.NewVar(g.Slice{0}).IsStruct(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &struct {\n\t\t}{}\n\t\tt.Assert(g.NewVar(a).IsStruct(), true)\n\t\tt.Assert(g.NewVar(*a).IsStruct(), true)\n\t\tt.Assert(g.NewVar(&a).IsStruct(), true)\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_Json(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"i love gf\"\n\t\tv := gvar.New(s)\n\t\tb1, err1 := json.Marshal(v)\n\t\tb2, err2 := json.Marshal(s)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := int64(math.MaxInt64)\n\t\tv := gvar.New(s)\n\t\tb1, err1 := json.Marshal(v)\n\t\tb2, err2 := json.Marshal(s)\n\t\tt.Assert(err1, err2)\n\t\tt.Assert(b1, b2)\n\t})\n\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"i love gf\"\n\t\tv := gvar.New(nil)\n\t\tb, err := json.Marshal(s)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), s)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v gvar.Var\n\t\ts := \"i love gf\"\n\t\tb, err := json.Marshal(s)\n\t\tt.AssertNil(err)\n\n\t\terr = json.UnmarshalUseNumber(b, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), s)\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_ListItemValues_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 99},\n\t\t\tg.Map{\"id\": 3, \"score\": 99},\n\t\t}\n\t\tt.Assert(gvar.New(listMap).ListItemValues(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gvar.New(listMap).ListItemValues(\"score\"), g.Slice{100, 99, 99})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": nil},\n\t\t\tg.Map{\"id\": 3, \"score\": 0},\n\t\t}\n\t\tt.Assert(gvar.New(listMap).ListItemValues(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gvar.New(listMap).ListItemValues(\"score\"), g.Slice{100, nil, 0})\n\t})\n}\n\nfunc TestVar_ListItemValues_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tT{1, 100},\n\t\t\tT{2, 99},\n\t\t\tT{3, 0},\n\t\t}\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Score\"), g.Slice{100, 99, 0})\n\t})\n\t// Pointer items.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\t&T{1, 100},\n\t\t\t&T{2, 99},\n\t\t\t&T{3, 0},\n\t\t}\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Score\"), g.Slice{100, 99, 0})\n\t})\n\t// Nil element value.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore any\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tT{1, 100},\n\t\t\tT{2, nil},\n\t\t\tT{3, 0},\n\t\t}\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gvar.New(listStruct).ListItemValues(\"Score\"), g.Slice{100, nil, 0})\n\t})\n}\n\nfunc TestVar_ListItemValuesUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 100},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 100},\n\t\t}\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"score\"), g.Slice{100})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 100},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 99},\n\t\t}\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"score\"), g.Slice{100, 99})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 0},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 99},\n\t\t}\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gvar.New(listMap).ListItemValuesUnique(\"score\"), g.Slice{100, 0, 99})\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tobjOne := gvar.New(m, true)\n\t\tt.Assert(objOne.Map()[\"k1\"], m[\"k1\"])\n\t\tt.Assert(objOne.Map()[\"k2\"], m[\"k2\"])\n\t})\n}\n\nfunc TestVar_MapToMap(t *testing.T) {\n\t// map[int]int -> map[string]string\n\t// empty original map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.MapIntInt{}\n\t\tm2 := g.MapStrStr{}\n\t\tt.Assert(gvar.New(m1).MapToMap(&m2), nil)\n\t\tt.Assert(len(m1), len(m2))\n\t})\n\t// map[int]int -> map[string]string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.MapIntInt{\n\t\t\t1: 100,\n\t\t\t2: 200,\n\t\t}\n\t\tm2 := g.MapStrStr{}\n\t\tt.Assert(gvar.New(m1).MapToMap(&m2), nil)\n\t\tt.Assert(m2[\"1\"], m1[1])\n\t\tt.Assert(m2[\"2\"], m1[2])\n\t})\n\t// map[string]any -> map[string]string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm2 := g.MapStrStr{}\n\t\tt.Assert(gvar.New(m1).MapToMap(&m2), nil)\n\t\tt.Assert(m2[\"k1\"], m1[\"k1\"])\n\t\tt.Assert(m2[\"k2\"], m1[\"k2\"])\n\t})\n\t// map[string]string -> map[string]any\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm2 := g.Map{}\n\t\tt.Assert(gvar.New(m1).MapToMap(&m2), nil)\n\t\tt.Assert(m2[\"k1\"], m1[\"k1\"])\n\t\tt.Assert(m2[\"k2\"], m1[\"k2\"])\n\t})\n\t// map[string]any -> map[any]any\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm2 := g.MapAnyAny{}\n\t\tt.Assert(gvar.New(m1).MapToMap(&m2), nil)\n\t\tt.Assert(m2[\"k1\"], m1[\"k1\"])\n\t\tt.Assert(m2[\"k2\"], m1[\"k2\"])\n\t})\n}\n\nfunc TestVar_MapStrVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tobjOne := gvar.New(m, true)\n\t\tt.Assert(objOne.MapStrVar(), \"{\\\"k1\\\":\\\"v1\\\",\\\"k2\\\":\\\"v2\\\"}\")\n\n\t\tobjEmpty := gvar.New(g.Map{})\n\t\tt.Assert(objEmpty.MapStrVar(), \"\")\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_slice_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_Ints(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Ints()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Bools(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []bool{true, false, true, false}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.AssertEQ(objOne.Bools(), arr)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 0, 1, 0}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.AssertEQ(objOne.Bools(), []bool{true, false, true, false})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []string{\"true\", \"false\", \"1\", \"0\"}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.AssertEQ(objOne.Bools(), []bool{true, false, true, false})\n\t})\n}\n\nfunc TestVar_Uints(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Uints()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Int64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Int64s()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Uint64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Uint64s()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Floats(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []float64{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Floats()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Float32s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []float32{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.AssertEQ(objOne.Float32s(), arr)\n\t})\n}\n\nfunc TestVar_Float64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []float64{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.AssertEQ(objOne.Float64s(), arr)\n\t})\n}\n\nfunc TestVar_Strings(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []string{\"hello\", \"world\"}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Strings()[0], arr[0])\n\t})\n}\n\nfunc TestVar_Interfaces(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Interfaces(), arr)\n\t})\n}\n\nfunc TestVar_Slice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, true)\n\t\tt.Assert(objOne.Slice(), arr)\n\t})\n}\n\nfunc TestVar_Array(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, false)\n\t\tt.Assert(objOne.Array(), arr)\n\t})\n}\n\nfunc TestVar_Vars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar arr = []int{1, 2, 3, 4, 5}\n\t\tobjOne := gvar.New(arr, false)\n\t\tt.Assert(len(objOne.Vars()), 5)\n\t\tt.Assert(objOne.Vars()[0].Int(), 1)\n\t\tt.Assert(objOne.Vars()[4].Int(), 5)\n\n\t\tobjEmpty := gvar.New([]int{})\n\t\tt.Assert(objEmpty.Vars(), nil)\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestVar_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype StTest struct {\n\t\t\tTest int\n\t\t}\n\n\t\tKv := make(map[string]int, 1)\n\t\tKv[\"Test\"] = 100\n\n\t\ttestObj := &StTest{}\n\n\t\tobjOne := gvar.New(Kv, true)\n\n\t\tobjOne.Struct(testObj)\n\n\t\tt.Assert(testObj.Test, Kv[\"Test\"])\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype StTest struct {\n\t\t\tTest int8\n\t\t}\n\t\to := &StTest{}\n\t\tv := gvar.New(g.Slice{\"Test\", \"-25\"})\n\t\tv.Struct(o)\n\t\tt.Assert(o.Test, -25)\n\t})\n}\n\nfunc TestVar_Var_Attribute_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tUid  int\n\t\t\tName string\n\t\t}\n\t\tuser := new(User)\n\t\terr := gconv.Struct(\n\t\t\tg.Map{\n\t\t\t\t\"uid\":  gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t}, user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Uid, 1)\n\t\tt.Assert(user.Name, \"john\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tUid  int\n\t\t\tName string\n\t\t}\n\t\tvar user *User\n\t\terr := gconv.Struct(\n\t\t\tg.Map{\n\t\t\t\t\"uid\":  gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t}, &user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Uid, 1)\n\t\tt.Assert(user.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "container/gvar/gvar_z_unit_vars_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvar_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar vs = gvar.Vars{\n\t\t\tgvar.New(1),\n\t\t\tgvar.New(2),\n\t\t\tgvar.New(3),\n\t\t}\n\t\tt.AssertEQ(vs.Strings(), []string{\"1\", \"2\", \"3\"})\n\t\tt.AssertEQ(vs.Bools(), []bool{true, true, true})\n\t\tt.AssertEQ(vs.Interfaces(), []any{1, 2, 3})\n\t\tt.AssertEQ(vs.Float32s(), []float32{1, 2, 3})\n\t\tt.AssertEQ(vs.Float64s(), []float64{1, 2, 3})\n\t\tt.AssertEQ(vs.Ints(), []int{1, 2, 3})\n\t\tt.AssertEQ(vs.Int8s(), []int8{1, 2, 3})\n\t\tt.AssertEQ(vs.Int16s(), []int16{1, 2, 3})\n\t\tt.AssertEQ(vs.Int32s(), []int32{1, 2, 3})\n\t\tt.AssertEQ(vs.Int64s(), []int64{1, 2, 3})\n\t\tt.AssertEQ(vs.Uints(), []uint{1, 2, 3})\n\t\tt.AssertEQ(vs.Uint8s(), []uint8{1, 2, 3})\n\t\tt.AssertEQ(vs.Uint16s(), []uint16{1, 2, 3})\n\t\tt.AssertEQ(vs.Uint32s(), []uint32{1, 2, 3})\n\t\tt.AssertEQ(vs.Uint64s(), []uint64{1, 2, 3})\n\t})\n}\n\nfunc TestVars_Bools(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with various boolean-like values\n\t\tvar vs = gvar.Vars{\n\t\t\tgvar.New(true),\n\t\t\tgvar.New(false),\n\t\t\tgvar.New(1),\n\t\t\tgvar.New(0),\n\t\t\tgvar.New(\"true\"),\n\t\t\tgvar.New(\"false\"),\n\t\t\tgvar.New(\"1\"),\n\t\t\tgvar.New(\"0\"),\n\t\t}\n\t\texpected := []bool{true, false, true, false, true, false, true, false}\n\t\tt.AssertEQ(vs.Bools(), expected)\n\t})\n}\n\nfunc TestVars_Empty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with empty Vars\n\t\tvar vs = gvar.Vars{}\n\t\tt.AssertEQ(vs.Strings(), []string{})\n\t\tt.AssertEQ(vs.Bools(), []bool{})\n\t\tt.AssertEQ(vs.Interfaces(), []any{})\n\t\tt.AssertEQ(vs.Ints(), []int{})\n\t\tt.AssertEQ(vs.Float64s(), []float64{})\n\t})\n}\n\nfunc TestVars_SingleElement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with single element\n\t\tvar vs = gvar.Vars{gvar.New(42)}\n\t\tt.AssertEQ(vs.Strings(), []string{\"42\"})\n\t\tt.AssertEQ(vs.Bools(), []bool{true})\n\t\tt.AssertEQ(vs.Ints(), []int{42})\n\t})\n}\n\nfunc TestVars_Scan(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t}\n\t\tvar vs = gvar.Vars{\n\t\t\tgvar.New(g.Map{\"id\": 1, \"name\": \"john\"}),\n\t\t\tgvar.New(g.Map{\"id\": 2, \"name\": \"smith\"}),\n\t\t}\n\t\tvar users []User\n\t\terr := vs.Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Name, \"john\")\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[1].Name, \"smith\")\n\t})\n}\n"
  },
  {
    "path": "contrib/config/README.MD",
    "content": "# Configuration center implements.\n\nPlease refer to certain sub folder."
  },
  {
    "path": "contrib/config/apollo/README.MD",
    "content": "# apollo\nPackage `apollo` implements GoFrame `gcfg.Adapter` using apollo service.\n\n\n# Installation\n```\ngo get -u github.com/gogf/gf/contrib/config/apollo/v2\n```\n\n# Usage\n\n## Create a custom boot package\n\nIf you wish using configuration from apollo globally,\nit is strongly recommended creating a custom boot package in very top import, \nwhich sets the Adapter of default configuration instance before any other package boots.\n\n```go\npackage boot\n\nimport (\n\t\"github.com/gogf/gf/contrib/config/apollo/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc init() {\n\tvar (\n\t\tctx     = gctx.GetInitCtx()\n\t\tappId   = \"SampleApp\"\n\t\tcluster = \"default\"\n\t\tip      = \"http://localhost:8080\"\n\t)\n\t// Create apollo Client that implements gcfg.Adapter.\n\tadapter, err := apollo.New(ctx, apollo.Config{\n\t\tAppID:   appId,\n\t\tIP:      ip,\n\t\tCluster: cluster,\n\t})\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `%+v`, err)\n\t}\n\t// Change the adapter of default configuration instance.\n\tg.Cfg().SetAdapter(adapter)\n}\n```\n\n## Import boot package in top of main\n\nIt is strongly recommended import your boot package in top of your `main.go`.\n\nNote the top `import`: `_ \"github.com/gogf/gf/example/config/apollo/boot\"` .\n\n```go\npackage main\n\nimport (\n\t_ \"github.com/gogf/gf/example/config/apollo/boot\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tvar ctx = gctx.GetInitCtx()\n\n\t// Available checks.\n\tg.Dump(g.Cfg().Available(ctx))\n\n\t// All key-value configurations.\n\tg.Dump(g.Cfg().Data(ctx))\n\n\t// Retrieve certain value by key.\n\tg.Dump(g.Cfg().MustGet(ctx, \"server.address\"))\n}\n```\n\n## License\n\n`GoFrame apollo` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever."
  },
  {
    "path": "contrib/config/apollo/apollo.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package apollo implements gcfg.Adapter using apollo service.\npackage apollo\n\nimport (\n\t\"context\"\n\n\t\"github.com/apolloconfig/agollo/v4\"\n\tapolloConfig \"github.com/apolloconfig/agollo/v4/env/config\"\n\t\"github.com/apolloconfig/agollo/v4/storage\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ gcfg.Adapter        = (*Client)(nil)\n\t_ gcfg.WatcherAdapter = (*Client)(nil)\n)\n\nconst (\n\tapolloNamespaceDelimiter = \",\"\n)\n\n// Config is the configuration object for apollo client.\ntype Config struct {\n\tAppID             string `v:\"required\"` // See apolloConfig.Config.\n\tIP                string `v:\"required\"` // See apolloConfig.Config.\n\tCluster           string `v:\"required\"` // See apolloConfig.Config.\n\tNamespaceName     string // See apolloConfig.Config.\n\tIsBackupConfig    bool   // See apolloConfig.Config.\n\tBackupConfigPath  string // See apolloConfig.Config.\n\tSecret            string // See apolloConfig.Config.\n\tSyncServerTimeout int    // See apolloConfig.Config.\n\tMustStart         bool   // See apolloConfig.Config.\n\tWatch             bool   // Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.\n}\n\n// Client implements gcfg.Adapter implementing using apollo service.\ntype Client struct {\n\tconfig   Config                // Config object when created.\n\tclient   agollo.Client         // Apollo client.\n\tvalue    *g.Var                // Configmap content cached. It is `*gjson.Json` value internally.\n\twatchers *gcfg.WatcherRegistry // Watchers for watching file changes.\n}\n\n// New creates and returns gcfg.Adapter implementing using apollo service.\nfunc New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {\n\t// Data validation.\n\terr = g.Validator().Data(config).Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif config.NamespaceName == \"\" {\n\t\tconfig.NamespaceName = storage.GetDefaultNamespace()\n\t}\n\tclient := &Client{\n\t\tconfig:   config,\n\t\tvalue:    g.NewVar(nil, true),\n\t\twatchers: gcfg.NewWatcherRegistry(),\n\t}\n\t// Apollo client.\n\tclient.client, err = agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {\n\t\treturn &apolloConfig.AppConfig{\n\t\t\tAppID:             config.AppID,\n\t\t\tCluster:           config.Cluster,\n\t\t\tNamespaceName:     config.NamespaceName,\n\t\t\tIP:                config.IP,\n\t\t\tIsBackupConfig:    config.IsBackupConfig,\n\t\t\tBackupConfigPath:  config.BackupConfigPath,\n\t\t\tSecret:            config.Secret,\n\t\t\tSyncServerTimeout: config.SyncServerTimeout,\n\t\t\tMustStart:         config.MustStart,\n\t\t}, nil\n\t})\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err, `create apollo client failed with config: %+v`, config)\n\t}\n\tif config.Watch {\n\t\tclient.client.AddChangeListener(client)\n\t}\n\treturn client, nil\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {\n\tif len(resource) == 0 && !c.value.IsNil() {\n\t\treturn true\n\t}\n\n\tnamespaces := gstr.SplitAndTrim(c.config.NamespaceName, apolloNamespaceDelimiter)\n\tif len(resource) > 0 {\n\t\tnamespaces = resource\n\t}\n\n\tfor _, namespace := range namespaces {\n\t\tif c.client.GetConfig(namespace) == nil {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Get retrieves and returns value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (c *Client) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead lots of memory usage if configuration data is too large,\n// you can implement this function if necessary.\nfunc (c *Client) Data(ctx context.Context) (data map[string]any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Map(), nil\n}\n\n// OnChange is called when config changes.\nfunc (c *Client) OnChange(event *storage.ChangeEvent) {\n\t_ = c.updateLocalValue(gctx.New())\n}\n\n// OnNewestChange is called when any config changes.\nfunc (c *Client) OnNewestChange(event *storage.FullChangeEvent) {\n\t// Nothing to do.\n}\n\nfunc (c *Client) updateLocalValue(ctx context.Context) (err error) {\n\tj := gjson.New(nil)\n\tcontent := gjson.New(nil, true)\n\n\tfor _, namespace := range gstr.SplitAndTrim(c.config.NamespaceName, apolloNamespaceDelimiter) {\n\t\tcache := c.client.GetConfigCache(namespace)\n\t\tcache.Range(func(key, value any) bool {\n\t\t\terr = j.Set(gconv.String(key), value)\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\terr = content.Set(gconv.String(key), value)\n\t\t\treturn err == nil\n\t\t})\n\t\tcache.Clear()\n\t}\n\n\tif err == nil {\n\t\tc.value.Set(j)\n\t\tadapterCtx := NewAdapterCtx(ctx).WithOperation(gcfg.OperationUpdate).WithNamespace(c.config.NamespaceName).\n\t\t\tWithAppId(c.config.AppID).WithCluster(c.config.Cluster).WithContent(content)\n\t\tc.notifyWatchers(adapterCtx.Ctx)\n\t}\n\treturn\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (c *Client) AddWatcher(name string, f gcfg.WatcherFunc) {\n\tc.watchers.Add(name, f)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (c *Client) RemoveWatcher(name string) {\n\tc.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (c *Client) GetWatcherNames() []string {\n\treturn c.watchers.GetNames()\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (c *Client) IsWatching(name string) bool {\n\treturn c.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (c *Client) notifyWatchers(ctx context.Context) {\n\tc.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "contrib/config/apollo/apollo_adapter_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package apollo implements gcfg.Adapter using apollo service.\npackage apollo\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\t// ContextKeyNamespace is the context key for namespace\n\tContextKeyNamespace gctx.StrKey = \"namespace\"\n\t// ContextKeyAppId is the context key for appId\n\tContextKeyAppId gctx.StrKey = \"appId\"\n\t// ContextKeyCluster is the context key for cluster\n\tContextKeyCluster gctx.StrKey = \"cluster\"\n)\n\n// ApolloAdapterCtx is the context adapter for Apollo configuration\ntype ApolloAdapterCtx struct {\n\tCtx context.Context\n}\n\n// NewAdapterCtxWithCtx creates and returns a new ApolloAdapterCtx with the given context.\nfunc NewAdapterCtxWithCtx(ctx context.Context) *ApolloAdapterCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &ApolloAdapterCtx{Ctx: ctx}\n}\n\n// NewAdapterCtx creates and returns a new ApolloAdapterCtx.\n// If context is provided, it will be used; otherwise, a background context is created.\nfunc NewAdapterCtx(ctx ...context.Context) *ApolloAdapterCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterCtxWithCtx(context.Background())\n}\n\n// GetAdapterCtx creates a new ApolloAdapterCtx with the given context\nfunc GetAdapterCtx(ctx context.Context) *ApolloAdapterCtx {\n\treturn NewAdapterCtxWithCtx(ctx)\n}\n\n// WithOperation sets the operation in the context\nfunc (a *ApolloAdapterCtx) WithOperation(operation gcfg.OperationType) *ApolloAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyOperation, operation)\n\treturn a\n}\n\n// WithNamespace sets the namespace in the context\nfunc (a *ApolloAdapterCtx) WithNamespace(namespace string) *ApolloAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyNamespace, namespace)\n\treturn a\n}\n\n// WithAppId sets the appId in the context\nfunc (a *ApolloAdapterCtx) WithAppId(appId string) *ApolloAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyAppId, appId)\n\treturn a\n}\n\n// WithCluster sets the cluster in the context\nfunc (a *ApolloAdapterCtx) WithCluster(cluster string) *ApolloAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyCluster, cluster)\n\treturn a\n}\n\n// WithContent sets the content in the context\nfunc (a *ApolloAdapterCtx) WithContent(content *gjson.Json) *ApolloAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyContent, content)\n\treturn a\n}\n\n// GetNamespace retrieves the namespace from the context\nfunc (a *ApolloAdapterCtx) GetNamespace() string {\n\tif v := a.Ctx.Value(ContextKeyNamespace); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetAppId retrieves the appId from the context\nfunc (a *ApolloAdapterCtx) GetAppId() string {\n\tif v := a.Ctx.Value(ContextKeyAppId); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetCluster retrieves the cluster from the context\nfunc (a *ApolloAdapterCtx) GetCluster() string {\n\tif v := a.Ctx.Value(ContextKeyCluster); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetContent retrieves the content from the context\nfunc (a *ApolloAdapterCtx) GetContent() *gjson.Json {\n\tif v := a.Ctx.Value(gcfg.ContextKeyContent); v != nil {\n\t\tif s, ok := v.(*gjson.Json); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn gjson.New(nil)\n}\n\n// GetOperation retrieves the operation from the context\nfunc (a *ApolloAdapterCtx) GetOperation() gcfg.OperationType {\n\tif v := a.Ctx.Value(gcfg.ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(gcfg.OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/config/apollo/apollo_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage apollo_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/config/apollo/v2\"\n)\n\nvar (\n\tctx     = gctx.GetInitCtx()\n\tappId   = \"SampleApp\"\n\tcluster = \"default\"\n\tip      = \"http://localhost:8080\"\n)\n\nfunc TestApollo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, err := apollo.New(ctx, apollo.Config{\n\t\t\tAppID:   appId,\n\t\t\tIP:      ip,\n\t\t\tCluster: cluster,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tconfig := g.Cfg(guid.S())\n\t\tconfig.SetAdapter(adapter)\n\n\t\tt.Assert(config.Available(ctx), true)\n\t\tt.Assert(config.Available(ctx, \"non-exist\"), false)\n\n\t\tv, err := config.Get(ctx, `server.address`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \":8000\")\n\n\t\tm, err := config.Data(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(m), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/config/apollo/go.mod",
    "content": "module github.com/gogf/gf/contrib/config/apollo/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/apolloconfig/agollo/v4 v4.3.1\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/hashicorp/hcl v1.0.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/mitchellh/mapstructure v1.4.1 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/pelletier/go-toml v1.9.3 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/spf13/afero v1.6.0 // indirect\n\tgithub.com/spf13/cast v1.3.1 // indirect\n\tgithub.com/spf13/jwalterweatherman v1.1.0 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/spf13/viper v1.8.1 // indirect\n\tgithub.com/subosito/gotenv v1.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/ini.v1 v1.62.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/config/apollo/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/apolloconfig/agollo/v4 v4.3.1 h1:NHjd7KqOPmTvYwJidISc9MPBRO8m9UNrH3tijcEVNAY=\ngithub.com/apolloconfig/agollo/v4 v4.3.1/go.mod h1:n/7qxpKOTbegygLmO5OKmFWCdy3T+S/zioBGlo457Dk=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=\ngithub.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=\ngithub.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=\ngithub.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=\ngithub.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/tevid/gohamcrest v1.1.1 h1:ou+xSqlIw1xfGTg1uq1nif/htZ2S3EzRqLm2BP+tYU0=\ngithub.com/tevid/gohamcrest v1.1.1/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZMibh0H/k=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngo.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=\ngo.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=\ngopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "contrib/config/consul/README.md",
    "content": "# consul\n\nPackage `consul` implements GoFrame `gcfg.Adapter` using consul service.\n\n# Installation\n\n```\ngo get -u github.com/gogf/gf/contrib/config/consul/v2\n```\n\n# Usage\n\n## Create a custom boot package\n\nIf you wish using configuration from consul globally,\nit is strongly recommended creating a custom boot package in very top import,\nwhich sets the Adapter of default configuration instance before any other package boots.\n\n```go\npackage boot\n\nimport (\n\tconsul \"github.com/gogf/gf/contrib/config/consul/v2\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/hashicorp/consul/api\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n)\n\nfunc init() {\n\tvar (\n\t\tctx          = gctx.GetInitCtx()\n\t\tconsulConfig = api.Config{\n\t\t\tAddress:    \"127.0.0.1:8500\",\n\t\t\tScheme:     \"http\",\n\t\t\tDatacenter: \"dc1\",\n\t\t\tTransport:  cleanhttp.DefaultPooledTransport(),\n\t\t\tToken:      \"3f8aeba2-f1f7-42d0-b912-fcb041d4546d\",\n\t\t}\n\t\tconfigPath = \"server/message\"\n\t)\n\n\tadapter, err := consul.New(ctx, consul.Config{\n\t\tConsulConfig: consulConfig,\n\t\tPath:   configPath,\n\t\tWatch:  true,\n\t})\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `New consul adapter error: %+v`, err)\n\t}\n\n\tg.Cfg().SetAdapter(adapter)\n}\n```\n\n## Import boot package in top of main\n\nIt is strongly recommended import your boot package in top of your `main.go`.\n\nNote the top `import`: `_ \"github.com/gogf/gf/example/config/consul/boot\"` .\n\n```go\npackage main\n\nimport (\n\t_ \"github.com/gogf/gf/example/config/consul/boot\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tvar ctx = gctx.GetInitCtx()\n\n\t// Available checks.\n\tg.Dump(g.Cfg().Available(ctx))\n\n\t// All key-value configurations.\n\tg.Dump(g.Cfg().Data(ctx))\n\n\t// Retrieve certain value by key.\n\tg.Dump(g.Cfg().MustGet(ctx, \"redis.addr\"))\n}\n```\n\n## License\n\n`GoFrame consul` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever."
  },
  {
    "path": "contrib/config/consul/consul.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package consul implements gcfg.Adapter using consul service.\npackage consul\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/hashicorp/consul/api\"\n\t\"github.com/hashicorp/consul/api/watch\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ gcfg.Adapter        = (*Client)(nil)\n\t_ gcfg.WatcherAdapter = (*Client)(nil)\n)\n\n// Config is the configuration object for consul client.\ntype Config struct {\n\t// api.Config in consul package\n\tConsulConfig api.Config `v:\"required\"`\n\t// As configuration file path key\n\tPath string `v:\"required\"`\n\t// Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.\n\tWatch bool\n\t// Logging interface, customized by user, default: glog.New()\n\tLogger glog.ILogger\n}\n\n// Client implements gcfg.Adapter implementing using consul service.\ntype Client struct {\n\t// Created config object\n\tconfig Config\n\t// Consul config client\n\tclient *api.Client\n\t// Configmap content cached. It is `*gjson.Json` value internally.\n\tvalue *g.Var\n\t// Watchers for watching file changes.\n\twatchers *gcfg.WatcherRegistry\n}\n\n// New creates and returns gcfg.Adapter implementing using consul service.\nfunc New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {\n\terr = g.Validator().Data(config).Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif config.Logger == nil {\n\t\tconfig.Logger = glog.New()\n\t}\n\n\tclient := &Client{\n\t\tconfig:   config,\n\t\tvalue:    g.NewVar(nil, true),\n\t\twatchers: gcfg.NewWatcherRegistry(),\n\t}\n\n\tclient.client, err = api.NewClient(&config.ConsulConfig)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err, `create consul client failed with config: %+v`, config.ConsulConfig)\n\t}\n\n\tif err = client.addWatcher(); err != nil {\n\t\treturn nil, gerror.Wrapf(err, `consul client add watcher failed with config: %+v`, config.ConsulConfig)\n\t}\n\n\treturn client, nil\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {\n\tif len(resource) == 0 && !c.value.IsNil() {\n\t\treturn true\n\t}\n\n\t_, _, err := c.client.KV().Get(c.config.Path, nil)\n\n\treturn err == nil\n}\n\n// Get retrieves and returns value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (c *Client) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead lots of memory usage if configuration data is too large,\n// you can implement this function if necessary.\nfunc (c *Client) Data(ctx context.Context) (data map[string]any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Map(), nil\n}\n\nfunc (c *Client) updateLocalValue() (err error) {\n\tcontent, _, err := c.client.KV().Get(c.config.Path, nil)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `get config from consul path [%+v] failed`, c.config.Path)\n\t}\n\tif content == nil {\n\t\treturn fmt.Errorf(`get config from consul path [%+v] value is nil`, c.config.Path)\n\t}\n\treturn c.doUpdate(content.Value)\n}\n\nfunc (c *Client) doUpdate(content []byte) (err error) {\n\tvar j *gjson.Json\n\tif j, err = gjson.LoadContent(content); err != nil {\n\t\treturn gerror.Wrapf(err,\n\t\t\t`parse config map item from consul path [%+v] failed`, c.config.Path)\n\t}\n\tc.value.Set(j)\n\treturn nil\n}\n\nfunc (c *Client) addWatcher() (err error) {\n\tif !c.config.Watch {\n\t\treturn nil\n\t}\n\n\tplan, err := watch.Parse(map[string]any{\n\t\t\"type\": \"key\",\n\t\t\"key\":  c.config.Path,\n\t})\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `watch config from consul path %+v failed`, c.config.Path)\n\t}\n\n\tplan.Handler = func(idx uint64, raw any) {\n\t\tvar v *api.KVPair\n\t\tif raw == nil {\n\t\t\t// nil is a valid return value\n\t\t\tv = nil\n\t\t\treturn\n\t\t}\n\t\tvar ok bool\n\t\tif v, ok = raw.(*api.KVPair); !ok {\n\t\t\treturn\n\t\t}\n\t\terr = c.doUpdate(v.Value)\n\t\tif err != nil {\n\t\t\tc.config.Logger.Errorf(\n\t\t\t\tcontext.Background(),\n\t\t\t\t\"watch config from consul path %+v update failed: %s\",\n\t\t\t\tc.config.Path, err,\n\t\t\t)\n\t\t} else {\n\t\t\tvar m *gjson.Json\n\t\t\tm, err = gjson.LoadContent(v.Value, true)\n\t\t\tif err != nil {\n\t\t\t\tc.config.Logger.Errorf(\n\t\t\t\t\tcontext.Background(),\n\t\t\t\t\t\"watch config from consul path %+v parse failed: %s\",\n\t\t\t\t\tc.config.Path, err,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tadapterCtx := NewAdapterCtx().WithOperation(gcfg.OperationUpdate).WithPath(c.config.Path).WithContent(m)\n\t\t\t\tc.notifyWatchers(adapterCtx.Ctx)\n\t\t\t}\n\t\t}\n\t}\n\n\tplan.Datacenter = c.config.ConsulConfig.Datacenter\n\tplan.Token = c.config.ConsulConfig.Token\n\n\tgo c.startAsynchronousWatch(plan)\n\treturn nil\n}\n\n// startAsynchronousWatch starts the asynchronous watch.\nfunc (c *Client) startAsynchronousWatch(plan *watch.Plan) {\n\tif err := plan.Run(c.config.ConsulConfig.Address); err != nil {\n\t\tc.config.Logger.Errorf(\n\t\t\tcontext.Background(),\n\t\t\t\"watch config from consul path %+v plan start failed: %s\",\n\t\t\tc.config.Path, err,\n\t\t)\n\t}\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (c *Client) AddWatcher(name string, f gcfg.WatcherFunc) {\n\tc.watchers.Add(name, f)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (c *Client) RemoveWatcher(name string) {\n\tc.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (c *Client) GetWatcherNames() []string {\n\treturn c.watchers.GetNames()\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (c *Client) IsWatching(name string) bool {\n\treturn c.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (c *Client) notifyWatchers(ctx context.Context) {\n\tc.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "contrib/config/consul/consul_adapter_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package consul implements gcfg.Adapter using consul service.\npackage consul\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\t// ContextKeyPath is the context key for path\n\tContextKeyPath gctx.StrKey = \"path\"\n)\n\n// ConsulAdapterCtx is the context adapter for Consul configuration\ntype ConsulAdapterCtx struct {\n\tCtx context.Context\n}\n\n// NewAdapterCtxWithCtx creates and returns a new ConsulAdapterCtx with the given context.\nfunc NewAdapterCtxWithCtx(ctx context.Context) *ConsulAdapterCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &ConsulAdapterCtx{Ctx: ctx}\n}\n\n// NewAdapterCtx creates and returns a new ConsulAdapterCtx.\n// If context is provided, it will be used; otherwise, a background context is created.\nfunc NewAdapterCtx(ctx ...context.Context) *ConsulAdapterCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterCtxWithCtx(context.Background())\n}\n\n// GetAdapterCtx creates a new ConsulAdapterCtx with the given context\nfunc GetAdapterCtx(ctx context.Context) *ConsulAdapterCtx {\n\treturn NewAdapterCtxWithCtx(ctx)\n}\n\n// WithOperation sets the operation in the context\nfunc (a *ConsulAdapterCtx) WithOperation(operation gcfg.OperationType) *ConsulAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyOperation, operation)\n\treturn a\n}\n\n// WithPath sets the path in the context\nfunc (a *ConsulAdapterCtx) WithPath(path string) *ConsulAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyPath, path)\n\treturn a\n}\n\n// WithContent sets the content in the context\nfunc (a *ConsulAdapterCtx) WithContent(content *gjson.Json) *ConsulAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyContent, content)\n\treturn a\n}\n\n// GetContent retrieves the content from the context\nfunc (a *ConsulAdapterCtx) GetContent() *gjson.Json {\n\tif v := a.Ctx.Value(gcfg.ContextKeyContent); v != nil {\n\t\tif s, ok := v.(*gjson.Json); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn gjson.New(nil)\n}\n\n// GetOperation retrieves the operation from the context\nfunc (a *ConsulAdapterCtx) GetOperation() gcfg.OperationType {\n\tif v := a.Ctx.Value(gcfg.ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(gcfg.OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetPath retrieves the path from the context\nfunc (a *ConsulAdapterCtx) GetPath() string {\n\tif v := a.Ctx.Value(ContextKeyPath); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/config/consul/consul_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consul_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/hashicorp/consul/api\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\tconsul \"github.com/gogf/gf/contrib/config/consul/v2\"\n)\n\nfunc TestConsul(t *testing.T) {\n\tctx := gctx.GetInitCtx()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfiguration := consul.Config{\n\t\t\tConsulConfig: api.Config{\n\t\t\t\tAddress:    \"127.0.0.1:8500\",\n\t\t\t\tScheme:     \"http\",\n\t\t\t\tDatacenter: \"dc1\",\n\t\t\t\tTransport:  cleanhttp.DefaultPooledTransport(),\n\t\t\t\tToken:      \"3f8aeba2-f1f7-42d0-b912-fcb041d4546d\",\n\t\t\t},\n\t\t\tPath:  \"server/message\",\n\t\t\tWatch: true,\n\t\t}\n\n\t\tvar configValue string\n\n\t\tconfigValue = `redis:\n  addr: 127.0.0.1:6379`\n\n\t\t// Write test configuration\n\t\tconsulClient, err := api.NewClient(&configuration.ConsulConfig)\n\t\tt.AssertNil(err)\n\t\tkv := consulClient.KV()\n\t\t_, err = kv.Put(&api.KVPair{Key: configuration.Path, Value: []byte(configValue)}, nil)\n\t\tt.AssertNil(err)\n\n\t\t// Create gcfg.Adapter\n\t\tadapter, err := consul.New(ctx, configuration)\n\t\tt.AssertNil(err)\n\t\tconf := g.Cfg(guid.S())\n\t\tconf.SetAdapter(adapter)\n\n\t\tt.Assert(conf.Available(ctx), true)\n\n\t\tv, err := conf.Get(ctx, \"redis.addr\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"127.0.0.1:6379\")\n\n\t\tm, err := conf.Data(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(m), 0)\n\t\t// g.Dump(m)\n\n\t\t// Test changes after modifying configuration\n\t\tconfigValue = `redis:\n  addr: localhost:6379`\n\t\t_, err = kv.Put(&api.KVPair{Key: configuration.Path, Value: []byte(configValue)}, nil)\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(time.Second)\n\n\t\tv, err = conf.Get(ctx, \"redis.addr\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"localhost:6379\")\n\n\t\tm, err = conf.Data(ctx)\n\t\tt.AssertNil(err)\n\t\tg.Dump(m)\n\t})\n}\n"
  },
  {
    "path": "contrib/config/consul/go.mod",
    "content": "module github.com/gogf/gf/contrib/config/consul/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/hashicorp/consul/api v1.24.0\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/armon/go-metrics v0.4.1 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/hashicorp/go-hclog v1.5.0 // indirect\n\tgithub.com/hashicorp/go-immutable-radix v1.3.1 // indirect\n\tgithub.com/hashicorp/go-rootcerts v1.0.2 // indirect\n\tgithub.com/hashicorp/golang-lru v0.5.4 // indirect\n\tgithub.com/hashicorp/serf v0.10.1 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/config/consul/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=\ngithub.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=\ngithub.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/hashicorp/consul/api v1.24.0 h1:u2XyStA2j0jnCiVUU7Qyrt8idjRn4ORhK6DlvZ3bWhA=\ngithub.com/hashicorp/consul/api v1.24.0/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg=\ngithub.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs=\ngithub.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=\ngithub.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=\ngithub.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=\ngithub.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=\ngithub.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=\ngithub.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=\ngithub.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=\ngithub.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=\ngithub.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=\ngithub.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\ngolang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=\ngolang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/config/kubecm/README.MD",
    "content": "# kubecm\nPackage `kubecm` implements GoFrame `gcfg.Adapter` using kubernetes configmap.\n\n# Limit\n\n```go\nglang version >= v.18\n```\n\n# Installation\n```\ngo get -u github.com/gogf/gf/contrib/config/kubecm/v2\n```\n\n# Example\n\n## Example configmap\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: test-configmap\ndata:\n  config.yaml: |\n    # HTTP service.\n    server:\n      address:          \":8888\"\n      openapiPath:      \"/api.json\"\n      swaggerPath:      \"/swagger\"\n      accessLogEnabled: true\n```\n\nNote the configmap name `test-configmap`, and its item name in data `config.yaml`.\n\n\n## Create a custom boot package\n\nIf you wish using configuration from kubernetes configmap globally,\nit is strongly recommended creating a custom boot package in very top import, \nwhich sets the Adapter of default configuration instance before any other package boots.\n\n### Running in pod (common scenario)\n```go\npackage boot\n\nimport (\n\t\"github.com/gogf/gf/contrib/config/kubecm/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\tconfigmapName       = \"test-configmap\"\n\tdataItemInConfigmap = \"config.yaml\"\n)\n\nfunc init() {\n\tvar (\n\t\terr error\n\t\tctx = gctx.GetInitCtx()\n\t)\n\t// Create kubecm Client that implements gcfg.Adapter.\n\tadapter, err := kubecm.New(gctx.GetInitCtx(), kubecm.Config{\n\t\tConfigMap: configmapName,\n\t\tDataItem:  dataItemInConfigmap,\n\t})\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `%+v`, err)\n\t}\n\n\t// Change the adapter of default configuration instance.\n\tg.Cfg().SetAdapter(adapter)\n}\n```\n\n### Running out of pod (often testing scenario)\n```go\npackage boot\n\nimport (\n\t\"github.com/gogf/gf/contrib/config/kubecm/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"k8s.io/client-go/kubernetes\"\n)\n\nconst (\n\tnamespace              = \"default\"\n\tconfigmapName          = \"test-configmap\"\n\tdataItemInConfigmap    = \"config.yaml\"\n\tkubeConfigFilePathJohn = `/Users/john/.kube/config`\n)\n\nfunc init() {\n\tvar (\n\t\terr        error\n\t\tctx        = gctx.GetInitCtx()\n\t\tkubeClient *kubernetes.Clientset\n\t)\n\t// Create kubernetes client.\n\t// It is optional creating kube client when its is running in pod.\n\tkubeClient, err = kubecm.NewKubeClientFromPath(ctx, kubeConfigFilePathJohn)\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `%+v`, err)\n\t}\n\t// Create kubecm Client that implements gcfg.Adapter.\n\tadapter, err := kubecm.New(gctx.GetInitCtx(), kubecm.Config{\n\t\tConfigMap:  configmapName,\n\t\tDataItem:   dataItemInConfigmap,\n\t\tNamespace:  namespace,  // It is optional specifying namespace when its is running in pod.\n\t\tKubeClient: kubeClient, // It is optional specifying kube client when its is running in pod.\n\t})\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `%+v`, err)\n\t}\n\n\t// Change the adapter of default configuration instance.\n\tg.Cfg().SetAdapter(adapter)\n\n}\n```\n\n## Import boot package in top of main\n\nIt is strongly recommended import your boot package in top of your `main.go`.\n\nNote the top `import`: `_ \"github.com/gogf/gf/example/config/kubecm/boot_in_pod\"` .\n\n```go\npackage main\n\nimport (\n\t_ \"github.com/gogf/gf/example/config/kubecm/boot_in_pod\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tvar ctx = gctx.GetInitCtx()\n\n\t// Available checks.\n\tg.Dump(g.Cfg().Available(ctx))\n\n\t// All key-value configurations.\n\tg.Dump(g.Cfg().Data(ctx))\n\n\t// Retrieve certain value by key.\n\tg.Dump(g.Cfg().MustGet(ctx, \"server.address\"))\n}\n\n```\n\n## License\n\n`GoFrame kubecm` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever."
  },
  {
    "path": "contrib/config/kubecm/go.mod",
    "content": "module github.com/gogf/gf/contrib/config/kubecm/v2\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tk8s.io/api v0.33.4\n\tk8s.io/apimachinery v0.33.4\n\tk8s.io/client-go v0.33.4\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/emicklei/go-restful/v3 v3.11.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/fxamacker/cbor/v2 v2.7.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.21.0 // indirect\n\tgithub.com/go-openapi/jsonreference v0.20.2 // indirect\n\tgithub.com/go-openapi/swag v0.23.0 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/google/gnostic-models v0.6.9 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mailru/easyjson v0.7.7 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/x448/float16 v0.8.4 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/oauth2 v0.27.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/term v0.32.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/time v0.9.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.5 // indirect\n\tgopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect\n\tgopkg.in/inf.v0 v0.9.1 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tk8s.io/klog/v2 v2.130.1 // indirect\n\tk8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect\n\tk8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect\n\tsigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect\n\tsigs.k8s.io/randfill v1.0.0 // indirect\n\tsigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect\n\tsigs.k8s.io/yaml v1.4.0 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/config/kubecm/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=\ngithub.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=\ngithub.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=\ngithub.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=\ngithub.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=\ngithub.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=\ngithub.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=\ngithub.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=\ngithub.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=\ngithub.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=\ngithub.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=\ngithub.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=\ngithub.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=\ngithub.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=\ngithub.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=\ngithub.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=\ngithub.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=\ngithub.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=\ngithub.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=\ngolang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=\ngolang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=\ngolang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=\ngolang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=\ngoogle.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=\ngopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=\ngopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nk8s.io/api v0.33.4 h1:oTzrFVNPXBjMu0IlpA2eDDIU49jsuEorGHB4cvKupkk=\nk8s.io/api v0.33.4/go.mod h1:VHQZ4cuxQ9sCUMESJV5+Fe8bGnqAARZ08tSTdHWfeAc=\nk8s.io/apimachinery v0.33.4 h1:SOf/JW33TP0eppJMkIgQ+L6atlDiP/090oaX0y9pd9s=\nk8s.io/apimachinery v0.33.4/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=\nk8s.io/client-go v0.33.4 h1:TNH+CSu8EmXfitntjUPwaKVPN0AYMbc9F1bBS8/ABpw=\nk8s.io/client-go v0.33.4/go.mod h1:LsA0+hBG2DPwovjd931L/AoaezMPX9CmBgyVyBZmbCY=\nk8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=\nk8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=\nk8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=\nk8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=\nk8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=\nk8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=\nsigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=\nsigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=\nsigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=\nsigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=\nsigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=\nsigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=\nsigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=\nsigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=\nsigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=\n"
  },
  {
    "path": "contrib/config/kubecm/kubecm.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package kubecm implements gcfg.Adapter using kubernetes configmap.\npackage kubecm\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tkubeMetaV1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/watch\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ gcfg.Adapter        = (*Client)(nil)\n\t_ gcfg.WatcherAdapter = (*Client)(nil)\n)\n\n// Client implements gcfg.Adapter.\ntype Client struct {\n\tconfig   Config                // Config object when created.\n\tclient   *kubernetes.Clientset // Kubernetes client.\n\tvalue    *g.Var                // Configmap content cached. It is `*gjson.Json` value internally.\n\twatchers *gcfg.WatcherRegistry // Watchers for watching file changes.\n}\n\n// Config for Client.\ntype Config struct {\n\tConfigMap  string                `v:\"required\"` // ConfigMap name.\n\tDataItem   string                `v:\"required\"` // DataItem is the key item in Configmap data.\n\tNamespace  string                // Specify the namespace for configmap.\n\tRestConfig *rest.Config          // Custom rest config for kube client.\n\tKubeClient *kubernetes.Clientset // Custom kube client.\n\tWatch      bool                  // Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.\n}\n\n// New creates and returns gcfg.Adapter implementing using kubernetes configmap.\nfunc New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {\n\t// Data validation.\n\terr = g.Validator().Data(config).Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Kubernetes client creating.\n\tif config.KubeClient == nil {\n\t\tif config.RestConfig == nil {\n\t\t\tconfig.RestConfig, err = NewDefaultKubeConfig(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(err, `create kube config failed`)\n\t\t\t}\n\t\t}\n\t\tconfig.KubeClient, err = kubernetes.NewForConfig(config.RestConfig)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(err, `create kube client failed`)\n\t\t}\n\t}\n\tadapter = &Client{\n\t\tconfig:   config,\n\t\tclient:   config.KubeClient,\n\t\tvalue:    g.NewVar(nil, true),\n\t\twatchers: gcfg.NewWatcherRegistry(),\n\t}\n\treturn\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (c *Client) Available(ctx context.Context, configMap ...string) (ok bool) {\n\tif len(configMap) == 0 && !c.value.IsNil() {\n\t\treturn true\n\t}\n\n\tvar (\n\t\tnamespace     = gutil.GetOrDefaultStr(Namespace(), c.config.Namespace)\n\t\tconfigMapName = gutil.GetOrDefaultStr(c.config.ConfigMap, configMap...)\n\t)\n\t_, err := c.config.KubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, configMapName, kubeMetaV1.GetOptions{})\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// Get retrieves and returns value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (c *Client) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValueAndWatch(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead lots of memory usage if configuration data is too large,\n// you can implement this function if necessary.\nfunc (c *Client) Data(ctx context.Context) (data map[string]any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValueAndWatch(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Map(), nil\n}\n\n// init retrieves and caches the configmap content.\nfunc (c *Client) updateLocalValueAndWatch(ctx context.Context) (err error) {\n\tvar namespace = gutil.GetOrDefaultStr(Namespace(), c.config.Namespace)\n\terr = c.doUpdate(ctx, namespace)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = c.doWatch(ctx, namespace)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// doUpdate retrieves and caches the configmap content.\nfunc (c *Client) doUpdate(ctx context.Context, namespace string) (err error) {\n\tcm, err := c.client.CoreV1().ConfigMaps(namespace).Get(ctx, c.config.ConfigMap, kubeMetaV1.GetOptions{})\n\tif err != nil {\n\t\treturn gerror.Wrapf(\n\t\t\terr,\n\t\t\t`retrieve configmap \"%s\" from namespace \"%s\" failed`,\n\t\t\tc.config.ConfigMap, namespace,\n\t\t)\n\t}\n\tvar j *gjson.Json\n\tif j, err = gjson.LoadContent([]byte(cm.Data[c.config.DataItem])); err != nil {\n\t\treturn gerror.Wrapf(\n\t\t\terr,\n\t\t\t`parse config map item from %s[%s] failed`, c.config.ConfigMap, c.config.DataItem,\n\t\t)\n\t}\n\tc.value.Set(j)\n\tvar content *gjson.Json\n\tif content, err = gjson.LoadContent([]byte(cm.Data[c.config.DataItem])); err != nil {\n\t\treturn gerror.Wrapf(\n\t\t\terr,\n\t\t\t`parse config map item from %s[%s] failed`, c.config.ConfigMap, c.config.DataItem,\n\t\t)\n\t}\n\tadapterCtx := NewAdapterCtx(ctx).WithOperation(gcfg.OperationUpdate).WithNamespace(namespace).WithConfigMap(c.config.ConfigMap).WithDataItem(c.config.DataItem).WithContent(content)\n\tc.notifyWatchers(adapterCtx.Ctx)\n\treturn nil\n}\n\n// doWatch watches the configmap content.\nfunc (c *Client) doWatch(ctx context.Context, namespace string) (err error) {\n\tif !c.config.Watch {\n\t\treturn nil\n\t}\n\tvar watchHandler watch.Interface\n\twatchHandler, err = c.client.CoreV1().ConfigMaps(namespace).Watch(ctx, kubeMetaV1.ListOptions{\n\t\tFieldSelector: fmt.Sprintf(`metadata.name=%s`, c.config.ConfigMap),\n\t\tWatch:         true,\n\t})\n\tif err != nil {\n\t\treturn gerror.Wrapf(\n\t\t\terr,\n\t\t\t`watch configmap \"%s\" from namespace \"%s\" failed`,\n\t\t\tc.config.ConfigMap, namespace,\n\t\t)\n\t}\n\tgo c.startAsynchronousWatch(ctx, namespace, watchHandler)\n\treturn nil\n}\n\n// startAsynchronousWatch starts an asynchronous watch for the specified configuration file.\nfunc (c *Client) startAsynchronousWatch(ctx context.Context, namespace string, watchHandler watch.Interface) {\n\tfor {\n\t\tevent := <-watchHandler.ResultChan()\n\t\tswitch event.Type {\n\t\tcase watch.Modified:\n\t\t\t_ = c.doUpdate(ctx, namespace)\n\t\t}\n\t}\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (c *Client) AddWatcher(name string, f gcfg.WatcherFunc) {\n\tc.watchers.Add(name, f)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (c *Client) RemoveWatcher(name string) {\n\tc.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (c *Client) GetWatcherNames() []string {\n\treturn c.watchers.GetNames()\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (c *Client) IsWatching(name string) bool {\n\treturn c.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (c *Client) notifyWatchers(ctx context.Context) {\n\tc.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "contrib/config/kubecm/kubecm_adapter_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package kubecm implements gcfg.Adapter using kubecm service.\npackage kubecm\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\t// ContextKeyNamespace is the context key for namespace\n\tContextKeyNamespace gctx.StrKey = \"namespace\"\n\t// ContextKeyConfigMap is the context key for configmap\n\tContextKeyConfigMap gctx.StrKey = \"configMap\"\n\t// ContextKeyDataItem is the context key for dataitem\n\tContextKeyDataItem gctx.StrKey = \"dataItem\"\n)\n\n// KubecmAdapterCtx is the context adapter for kubecm configuration\ntype KubecmAdapterCtx struct {\n\tCtx context.Context\n}\n\n// NewKubecmAdapterCtx creates and returns a new KubecmAdapterCtx with the given context.\nfunc NewKubecmAdapterCtx(ctx context.Context) *KubecmAdapterCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &KubecmAdapterCtx{Ctx: ctx}\n}\n\n// NewAdapterCtx creates and returns a new KubecmAdapterCtx.\n// If context is provided, it will be used; otherwise, a background context is created.\nfunc NewAdapterCtx(ctx ...context.Context) *KubecmAdapterCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewKubecmAdapterCtx(ctx[0])\n\t}\n\treturn NewKubecmAdapterCtx(context.Background())\n}\n\n// GetAdapterCtx creates a new KubecmAdapterCtx with the given context\nfunc GetAdapterCtx(ctx context.Context) *KubecmAdapterCtx {\n\treturn NewKubecmAdapterCtx(ctx)\n}\n\n// WithOperation sets the operation in the context\nfunc (a *KubecmAdapterCtx) WithOperation(operation gcfg.OperationType) *KubecmAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyOperation, operation)\n\treturn a\n}\n\n// WithNamespace sets the namespace in the context\nfunc (a *KubecmAdapterCtx) WithNamespace(namespace string) *KubecmAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyNamespace, namespace)\n\treturn a\n}\n\n// WithConfigMap sets the configmap in the context\nfunc (a *KubecmAdapterCtx) WithConfigMap(configMap string) *KubecmAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyConfigMap, configMap)\n\treturn a\n}\n\n// WithDataItem sets the dataitem in the context\nfunc (a *KubecmAdapterCtx) WithDataItem(dataItem string) *KubecmAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyDataItem, dataItem)\n\treturn a\n}\n\n// WithContent sets the content in the context\nfunc (a *KubecmAdapterCtx) WithContent(content *gjson.Json) *KubecmAdapterCtx {\n\ta.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyContent, content)\n\treturn a\n}\n\n// GetOperation retrieves the operation from the context\nfunc (a *KubecmAdapterCtx) GetOperation() gcfg.OperationType {\n\tif v := a.Ctx.Value(gcfg.ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(gcfg.OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetNamespace retrieves the namespace from the context\nfunc (a *KubecmAdapterCtx) GetNamespace() string {\n\tif v := a.Ctx.Value(ContextKeyNamespace); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetConfigMap retrieves the configmap from the context\nfunc (a *KubecmAdapterCtx) GetConfigMap() string {\n\tif v := a.Ctx.Value(ContextKeyConfigMap); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetDataItem retrieves the dataitem from the context\nfunc (a *KubecmAdapterCtx) GetDataItem() string {\n\tif v := a.Ctx.Value(ContextKeyDataItem); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetContent retrieves the content from the context\nfunc (a *KubecmAdapterCtx) GetContent() *gjson.Json {\n\tif v := a.Ctx.Value(gcfg.ContextKeyContent); v != nil {\n\t\tif s, ok := v.(*gjson.Json); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn gjson.New(nil)\n}\n"
  },
  {
    "path": "contrib/config/kubecm/kubecm_kube.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage kubecm\n\nimport (\n\t\"context\"\n\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nconst (\n\tdefaultKubernetesUserAgent  = `kubecm.Client`\n\tkubernetesNamespaceFilePath = `/var/run/secrets/kubernetes.io/serviceaccount/namespace`\n)\n\n// Namespace retrieves and returns the namespace of current pod.\n// Note that this function should be called in kubernetes pod.\nfunc Namespace() string {\n\treturn gfile.GetContents(kubernetesNamespaceFilePath)\n}\n\n// NewDefaultKubeClient creates and returns a default kubernetes client.\n// It is commonly used when the service is running inside kubernetes cluster.\nfunc NewDefaultKubeClient(ctx context.Context) (*kubernetes.Clientset, error) {\n\treturn NewKubeClientFromPath(ctx, \"\")\n}\n\n// NewKubeClientFromPath creates and returns a kubernetes REST client by given `kubeConfigFilePath`.\nfunc NewKubeClientFromPath(ctx context.Context, kubeConfigFilePath string) (*kubernetes.Clientset, error) {\n\trestConfig, err := NewKubeConfigFromPath(ctx, kubeConfigFilePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn kubernetes.NewForConfig(restConfig)\n}\n\n// NewKubeClientFromConfig creates and returns client by given `rest.Config`.\nfunc NewKubeClientFromConfig(ctx context.Context, config *rest.Config) (*kubernetes.Clientset, error) {\n\treturn kubernetes.NewForConfig(config)\n}\n\n// NewDefaultKubeConfig creates and returns a default kubernetes config.\n// It is commonly used when the service is running inside kubernetes cluster.\nfunc NewDefaultKubeConfig(ctx context.Context) (*rest.Config, error) {\n\treturn NewKubeConfigFromPath(ctx, \"\")\n}\n\n// NewKubeConfigFromPath creates and returns rest.Config object from given `kubeConfigFilePath`.\nfunc NewKubeConfigFromPath(ctx context.Context, kubeConfigFilePath string) (*rest.Config, error) {\n\trestConfig, err := clientcmd.BuildConfigFromFlags(\"\", kubeConfigFilePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trestConfig.UserAgent = defaultKubernetesUserAgent\n\treturn restConfig, nil\n}\n"
  },
  {
    "path": "contrib/config/kubecm/kubecm_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage kubecm_test\n\nimport (\n\t\"testing\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\tkubeMetaV1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/client-go/kubernetes\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/config/kubecm/v2\"\n)\n\nconst (\n\tnamespace         = \"default\"\n\tconfigmap         = \"test-configmap\"\n\tdataItem          = \"config.yaml\"\n\tconfigmapFileName = \"configmap.yaml\"\n)\n\nvar (\n\tctx                    = gctx.New()\n\tkubeConfigFilePath     = `/home/runner/.kube/config`\n\tkubeConfigFilePathJohn = `/Users/john/.kube/config`\n)\n\nfunc init() {\n\tif !gfile.Exists(kubeConfigFilePath) {\n\t\tkubeConfigFilePath = kubeConfigFilePathJohn\n\t}\n}\n\nfunc TestAvailable(t *testing.T) {\n\tvar (\n\t\terr        error\n\t\tkubeClient *kubernetes.Clientset\n\t)\n\t// Configmap apply.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkubeClient, err = kubecm.NewKubeClientFromPath(ctx, kubeConfigFilePath)\n\t\tt.AssertNil(err)\n\t\tvar (\n\t\t\tconfigMap v1.ConfigMap\n\t\t\tcontent   = gtest.DataContent(configmapFileName)\n\t\t)\n\t\terr = gjson.New(content).Scan(&configMap)\n\t\tt.AssertNil(err)\n\t\t_, err = kubeClient.CoreV1().ConfigMaps(namespace).Create(\n\t\t\tctx, &configMap, kubeMetaV1.CreateOptions{},\n\t\t)\n\t\tt.AssertNil(err)\n\t})\n\tdefer func() {\n\t\tgtest.C(t, func(t *gtest.T) {\n\t\t\terr = kubeClient.CoreV1().ConfigMaps(namespace).Delete(\n\t\t\t\tctx, configmap, kubeMetaV1.DeleteOptions{},\n\t\t\t)\n\t\t\tt.AssertNil(err)\n\t\t})\n\t}()\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, err := kubecm.New(ctx, kubecm.Config{\n\t\t\tConfigMap:  configmap,\n\t\t\tDataItem:   dataItem,\n\t\t\tNamespace:  namespace,\n\t\t\tKubeClient: kubeClient,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tconfig := g.Cfg(guid.S())\n\t\tconfig.SetAdapter(adapter)\n\n\t\tt.Assert(config.Available(ctx), true)\n\t\tt.Assert(config.Available(ctx, \"non-exist\"), false)\n\n\t\tm, err := config.Data(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(m), 0)\n\n\t\tv, err := config.Get(ctx, \"server.address\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \":8888\")\n\t})\n}\n\nfunc TestNewKubeClientFromConfig(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig, _ := kubecm.NewKubeConfigFromPath(ctx, kubeConfigFilePath)\n\t\t_, err := kubecm.NewKubeClientFromConfig(ctx, config)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// These functions should be called in pod environment, but it has no environment in CI UT testing.\n// It so just calls them ,but does nothing.\nfunc TestDefaultBehaviorFunctions(t *testing.T) {\n\tkubecm.Namespace()\n\tkubecm.NewDefaultKubeClient(ctx)\n\tkubecm.NewDefaultKubeConfig(ctx)\n}\n"
  },
  {
    "path": "contrib/config/kubecm/testdata/configmap.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: test-configmap\ndata:\n  config.yaml: |\n    # HTTP service.\n    server:\n      address:          \":8888\"\n      openapiPath:      \"/api.json\"\n      swaggerPath:      \"/swagger\"\n      accessLogEnabled: true\n\n    # Database configuration.\n    database:\n      logger:\n        level:  \"all\"\n        stdout: true\n      user:\n        link:  \"mysql:root:12345678@tcp(mysql.default:3306)/user?loc=Local&parseTime=true\"\n        debug: true\n      order:\n        link:  \"mysql:root:12345678@tcp(mysql.default:3306)/order?loc=Local&parseTime=true\"\n        debug: true\n\n    # Logger configuration.\n    logger:\n      level : \"all\"\n      stdout: true\n"
  },
  {
    "path": "contrib/config/nacos/README.MD",
    "content": "# nacos\n\nPackage `nacos` implements GoFrame `gcfg.Adapter` using nacos service.\n\n# Installation\n\n```\ngo get -u github.com/gogf/gf/contrib/config/nacos/v2\n```\n\n# Usage\n\n## Create a custom boot package\n\nIf you wish using configuration from nacos globally,\nit is strongly recommended creating a custom boot package in very top import,\nwhich sets the Adapter of default configuration instance before any other package boots.\n\n```go\npackage boot\n\nimport (\n\t\"github.com/gogf/gf/contrib/config/nacos/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/common/constant\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n)\n\nfunc init() {\n\tvar (\n\t\tctx          = gctx.GetInitCtx()\n\t\tserverConfig = constant.ServerConfig{\n\t\t\tIpAddr: \"localhost\",\n\t\t\tPort:   8848,\n\t\t}\n\t\tclientConfig = constant.ClientConfig{\n\t\t\tCacheDir: \"/tmp/nacos\",\n\t\t\tLogDir:   \"/tmp/nacos\",\n\t\t}\n\t\tconfigParam = vo.ConfigParam{\n\t\t\tDataId: \"config.toml\",\n\t\t\tGroup:  \"test\",\n\t\t}\n\t)\n\t// Create anacosClient that implements gcfg.Adapter.\n\tadapter, err := nacos.New(ctx, nacos.Config{\n\t\tServerConfigs: []constant.ServerConfig{serverConfig},\n\t\tClientConfig:  clientConfig,\n\t\tConfigParam:   configParam,\n\t})\n\tif err != nil {\n\t\tg.Log().Fatalf(ctx, `%+v`, err)\n\t}\n\t// Change the adapter of default configuration instance.\n\tg.Cfg().SetAdapter(adapter)\n}\n```\n\n## Import boot package in top of main\n\nIt is strongly recommended import your boot package in top of your `main.go`.\n\nNote the top `import`: `_ \"github.com/gogf/gf/example/config/nacos/boot\"` .\n\n```go\npackage main\n\nimport (\n    _ \"github.com/gogf/gf/example/config/nacos/boot\"\n\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n    var ctx = gctx.GetInitCtx()\n\n    // Available checks.\n    g.Dump(g.Cfg().Available(ctx))\n\n    // All key-value configurations.\n    g.Dump(g.Cfg().Data(ctx))\n\n    // Retrieve certain value by key.\n    g.Dump(g.Cfg().MustGet(ctx, \"server.address\"))\n}\n```\n\n## License\n\n`GoFrame nacos` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n"
  },
  {
    "path": "contrib/config/nacos/go.mod",
    "content": "module github.com/gogf/gf/contrib/config/nacos/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/nacos-group/nacos-sdk-go/v2 v2.3.3\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect\n\tgithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect\n\tgithub.com/alibabacloud-go/darabonba-array v0.1.0 // indirect\n\tgithub.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect\n\tgithub.com/alibabacloud-go/darabonba-map v0.0.2 // indirect\n\tgithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 // indirect\n\tgithub.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect\n\tgithub.com/alibabacloud-go/darabonba-string v1.0.2 // indirect\n\tgithub.com/alibabacloud-go/debug v1.0.1 // indirect\n\tgithub.com/alibabacloud-go/endpoint-util v1.1.0 // indirect\n\tgithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3 // indirect\n\tgithub.com/alibabacloud-go/openapi-util v0.1.0 // indirect\n\tgithub.com/alibabacloud-go/tea v1.2.2 // indirect\n\tgithub.com/alibabacloud-go/tea-utils v1.4.4 // indirect\n\tgithub.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect\n\tgithub.com/alibabacloud-go/tea-xml v1.1.3 // indirect\n\tgithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect\n\tgithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 // indirect\n\tgithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 // indirect\n\tgithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect\n\tgithub.com/aliyun/credentials-go v1.4.3 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/buger/jsonparser v1.1.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/deckarep/golang-set v1.7.1 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/mock v1.6.0 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/prometheus/client_golang v1.12.2 // indirect\n\tgithub.com/prometheus/client_model v0.2.0 // indirect\n\tgithub.com/prometheus/common v0.32.1 // indirect\n\tgithub.com/prometheus/procfs v0.7.3 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/tjfoc/gmsm v1.4.1 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgo.uber.org/zap v1.21.0 // indirect\n\tgolang.org/x/crypto v0.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sync v0.14.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/time v0.1.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect\n\tgoogle.golang.org/grpc v1.67.3 // indirect\n\tgoogle.golang.org/protobuf v1.36.5 // indirect\n\tgopkg.in/ini.v1 v1.67.0 // indirect\n\tgopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/config/nacos/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=\ngithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=\ngithub.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=\ngithub.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=\ngithub.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=\ngithub.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=\ngithub.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=\ngithub.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=\ngithub.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=\ngithub.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=\ngithub.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=\ngithub.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=\ngithub.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=\ngithub.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=\ngithub.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=\ngithub.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=\ngithub.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=\ngithub.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=\ngithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw=\ngithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw=\ngithub.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=\ngithub.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=\ngithub.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=\ngithub.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=\ngithub.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=\ngithub.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=\ngithub.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=\ngithub.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=\ngithub.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=\ngithub.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=\ngithub.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=\ngithub.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=\ngithub.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=\ngithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU=\ngithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=\ngithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=\ngithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=\ngithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=\ngithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=\ngithub.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=\ngithub.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=\ngithub.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=\ngithub.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=\ngithub.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=\ngithub.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=\ngithub.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=\ngithub.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/nacos-group/nacos-sdk-go/v2 v2.3.3 h1:lvkBZcYkKENLVR1ubO+vGxTP2L4VtVSArLvYZKuu4Pk=\ngithub.com/nacos-group/nacos-sdk-go/v2 v2.3.3/go.mod h1:ygUBdt7eGeYBt6Lz2HO3wx7crKXk25Mp80568emGMWU=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=\ngithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=\ngithub.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=\ngithub.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=\ngithub.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=\ngithub.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=\ngithub.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=\ngo.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=\ngolang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=\ngolang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=\ngolang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=\ngolang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=\ngolang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=\ngolang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=\ngolang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=\ngolang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=\ngolang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=\ngolang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=\ngolang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=\ngolang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=\ngoogle.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=\ngoogle.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=\ngopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "contrib/config/nacos/nacos.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package nacos implements gcfg.Adapter using nacos service.\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/clients\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/common/constant\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ gcfg.Adapter        = (*Client)(nil)\n\t_ gcfg.WatcherAdapter = (*Client)(nil)\n)\n\n// Config is the configuration object for nacos client.\ntype Config struct {\n\tServerConfigs  []constant.ServerConfig                     `v:\"required\"` // See constant.ServerConfig\n\tClientConfig   constant.ClientConfig                       `v:\"required\"` // See constant.ClientConfig\n\tConfigParam    vo.ConfigParam                              `v:\"required\"` // See vo.ConfigParam\n\tWatch          bool                                        // Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.\n\tOnConfigChange func(namespace, group, dataId, data string) // Configure change callback function\n}\n\n// Client implements gcfg.Adapter implementing using nacos service.\ntype Client struct {\n\tconfig   Config                      // Config object when created.\n\tclient   config_client.IConfigClient // Nacos config client.\n\tvalue    *g.Var                      // Configmap content cached. It is `*gjson.Json` value internally.\n\twatchers *gcfg.WatcherRegistry       // Watchers for watching file changes.\n}\n\n// New creates and returns gcfg.Adapter implementing using nacos service.\nfunc New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {\n\t// Data validation.\n\terr = g.Validator().Data(config).Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient := &Client{\n\t\tconfig:   config,\n\t\tvalue:    g.NewVar(nil, true),\n\t\twatchers: gcfg.NewWatcherRegistry(),\n\t}\n\n\tclient.client, err = clients.CreateConfigClient(map[string]any{\n\t\t\"serverConfigs\": config.ServerConfigs,\n\t\t\"clientConfig\":  config.ClientConfig,\n\t})\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err, `create nacos client failed with config: %+v`, config)\n\t}\n\n\terr = client.addWatcher()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn client, nil\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {\n\tif len(resource) == 0 && !c.value.IsNil() {\n\t\treturn true\n\t}\n\t_, err := c.client.GetConfig(c.config.ConfigParam)\n\treturn err == nil\n}\n\n// Get retrieves and returns value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (c *Client) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead lots of memory usage if configuration data is too large,\n// you can implement this function if necessary.\nfunc (c *Client) Data(ctx context.Context) (data map[string]any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValue(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Map(), nil\n}\n\nfunc (c *Client) updateLocalValue() (err error) {\n\tcontent, err := c.client.GetConfig(c.config.ConfigParam)\n\tif err != nil {\n\t\treturn gerror.Wrap(err, `retrieve config from nacos failed`)\n\t}\n\n\treturn c.doUpdate(content)\n}\n\nfunc (c *Client) doUpdate(content string) (err error) {\n\tvar j *gjson.Json\n\tif j, err = gjson.LoadContent([]byte(content)); err != nil {\n\t\treturn gerror.Wrap(err, `parse config map item from nacos failed`)\n\t}\n\tc.value.Set(j)\n\treturn nil\n}\n\nfunc (c *Client) addWatcher() error {\n\tif !c.config.Watch {\n\t\treturn nil\n\t}\n\tc.config.ConfigParam.OnChange = func(namespace, group, dataId, data string) {\n\t\t_ = c.doUpdate(data)\n\t\tif c.config.OnConfigChange != nil {\n\t\t\tgo c.config.OnConfigChange(namespace, group, dataId, data)\n\t\t}\n\t\tadapterCtx := NewAdapterCtx().WithOperation(gcfg.OperationUpdate).WithNamespace(namespace).\n\t\t\tWithGroup(group).WithDataId(dataId).WithContent(data)\n\t\tc.notifyWatchers(adapterCtx.Ctx)\n\t}\n\n\tif err := c.client.ListenConfig(c.config.ConfigParam); err != nil {\n\t\treturn gerror.Wrap(err, `watch config from namespace failed`)\n\t}\n\n\treturn nil\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (c *Client) AddWatcher(name string, f gcfg.WatcherFunc) {\n\tc.watchers.Add(name, f)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (c *Client) RemoveWatcher(name string) {\n\tc.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (c *Client) GetWatcherNames() []string {\n\treturn c.watchers.GetNames()\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (c *Client) IsWatching(name string) bool {\n\treturn c.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (c *Client) notifyWatchers(ctx context.Context) {\n\tc.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "contrib/config/nacos/nacos_adapter_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package nacos implements gcfg.Adapter using nacos service.\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\t// ContextKeyNamespace is the context key for namespace\n\tContextKeyNamespace gctx.StrKey = \"namespace\"\n\t// ContextKeyGroup is the context key for group\n\tContextKeyGroup gctx.StrKey = \"group\"\n\t// ContextKeyDataId is the context key for dataId\n\tContextKeyDataId gctx.StrKey = \"dataId\"\n)\n\n// NacosAdapterCtx is the context adapter for Nacos configuration\ntype NacosAdapterCtx struct {\n\tCtx context.Context\n}\n\n// NewAdapterCtxWithCtx creates and returns a new NacosAdapterCtx with the given context.\nfunc NewAdapterCtxWithCtx(ctx context.Context) *NacosAdapterCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &NacosAdapterCtx{Ctx: ctx}\n}\n\n// NewAdapterCtx creates and returns a new NacosAdapterCtx.\n// If context is provided, it will be used; otherwise, a background context is created.\nfunc NewAdapterCtx(ctx ...context.Context) *NacosAdapterCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterCtxWithCtx(context.Background())\n}\n\n// GetAdapterCtx creates a new NacosAdapterCtx with the given context\nfunc GetAdapterCtx(ctx context.Context) *NacosAdapterCtx {\n\treturn NewAdapterCtxWithCtx(ctx)\n}\n\n// WithOperation sets the operation in the context\nfunc (n *NacosAdapterCtx) WithOperation(operation gcfg.OperationType) *NacosAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, gcfg.ContextKeyOperation, operation)\n\treturn n\n}\n\n// WithNamespace sets the namespace in the context\nfunc (n *NacosAdapterCtx) WithNamespace(namespace string) *NacosAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, ContextKeyNamespace, namespace)\n\treturn n\n}\n\n// WithGroup sets the group in the context\nfunc (n *NacosAdapterCtx) WithGroup(group string) *NacosAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, ContextKeyGroup, group)\n\treturn n\n}\n\n// WithDataId sets the dataId in the context\nfunc (n *NacosAdapterCtx) WithDataId(dataId string) *NacosAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, ContextKeyDataId, dataId)\n\treturn n\n}\n\n// WithContent sets the content in the context\nfunc (n *NacosAdapterCtx) WithContent(content string) *NacosAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, gcfg.ContextKeyContent, content)\n\treturn n\n}\n\n// GetNamespace retrieves the namespace from the context\nfunc (n *NacosAdapterCtx) GetNamespace() string {\n\tif v := n.Ctx.Value(ContextKeyNamespace); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetGroup retrieves the group from the context\nfunc (n *NacosAdapterCtx) GetGroup() string {\n\tif v := n.Ctx.Value(ContextKeyGroup); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetDataId retrieves the dataId from the context\nfunc (n *NacosAdapterCtx) GetDataId() string {\n\tif v := n.Ctx.Value(ContextKeyDataId); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetContent retrieves the content from the context\nfunc (n *NacosAdapterCtx) GetContent() string {\n\tif v := n.Ctx.Value(gcfg.ContextKeyContent); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetOperation retrieves the operation from the context\nfunc (n *NacosAdapterCtx) GetOperation() gcfg.OperationType {\n\tif v := n.Ctx.Value(gcfg.ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(gcfg.OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/config/nacos/nacos_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos_test\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/common/constant\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/config/nacos/v2\"\n)\n\nvar (\n\tctx          = gctx.GetInitCtx()\n\tserverConfig = constant.ServerConfig{\n\t\tIpAddr: \"localhost\",\n\t\tPort:   8848,\n\t}\n\tclientConfig = constant.ClientConfig{\n\t\tCacheDir: \"/tmp/nacos\",\n\t\tLogDir:   \"/tmp/nacos\",\n\t}\n\tconfigParam = vo.ConfigParam{\n\t\tDataId: \"config.toml\",\n\t\tGroup:  \"test\",\n\t}\n\tconfigPublishUrl = \"http://localhost:8848/nacos/v2/cs/config?type=toml&namespaceId=public&group=test&dataId=config.toml\"\n)\n\nfunc TestNacos(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, err := nacos.New(ctx, nacos.Config{\n\t\t\tServerConfigs: []constant.ServerConfig{serverConfig},\n\t\t\tClientConfig:  clientConfig,\n\t\t\tConfigParam:   configParam,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tconfig := g.Cfg(guid.S())\n\t\tconfig.SetAdapter(adapter)\n\n\t\tt.Assert(config.Available(ctx), true)\n\t\tv, err := config.Get(ctx, `server.address`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \":8000\")\n\n\t\tm, err := config.Data(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(m), 0)\n\t})\n}\n\nfunc TestNacosOnConfigChangeFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, _ := nacos.New(ctx, nacos.Config{\n\t\t\tServerConfigs: []constant.ServerConfig{serverConfig},\n\t\t\tClientConfig:  clientConfig,\n\t\t\tConfigParam:   configParam,\n\t\t\tWatch:         true,\n\t\t\tOnConfigChange: func(namespace, group, dataId, data string) {\n\t\t\t\tt.Assert(namespace, \"public\")\n\t\t\t\tt.Assert(group, \"test\")\n\t\t\t\tt.Assert(dataId, \"config.toml\")\n\t\t\t\tt.Assert(g.Cfg().MustGet(gctx.GetInitCtx(), \"app.name\").String(), \"gf\")\n\t\t\t},\n\t\t})\n\t\tif watcherAdapter, ok := adapter.(gcfg.WatcherAdapter); ok {\n\t\t\twatcherAdapter.AddWatcher(\"test\", func(ctx context.Context) {\n\t\t\t\tadapterCtx := nacos.GetAdapterCtx(ctx)\n\t\t\t\tt.Assert(adapterCtx.GetNamespace(), \"public\")\n\t\t\t\tt.Assert(adapterCtx.GetGroup(), \"test\")\n\t\t\t\tt.Assert(adapterCtx.GetDataId(), \"config.toml\")\n\t\t\t\tt.Assert(adapterCtx.GetOperation(), gcfg.OperationUpdate)\n\t\t\t\tt.Assert(g.Cfg().MustGet(gctx.GetInitCtx(), \"app.name\").String(), \"gf\")\n\t\t\t})\n\t\t}\n\t\tg.Cfg().SetAdapter(adapter)\n\t\tt.Assert(g.Cfg().Available(ctx), true)\n\t\tappName, err := g.Cfg().Get(ctx, \"app.name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(appName.String(), \"\")\n\t\tc, err := g.Cfg().Data(ctx)\n\t\tt.AssertNil(err)\n\t\tj := gjson.New(c)\n\t\terr = j.Set(\"app.name\", \"gf\")\n\t\tt.AssertNil(err)\n\t\tres, err := j.ToTomlString()\n\t\tt.AssertNil(err)\n\t\t_, err = g.Client().Post(ctx, configPublishUrl+\"&content=\"+url.QueryEscape(res))\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(5 * time.Second)\n\t\terr = j.Remove(\"app\")\n\t\tt.AssertNil(err)\n\t\tres2, err := j.ToTomlString()\n\t\tt.AssertNil(err)\n\t\t_, err = g.Client().Post(ctx, configPublishUrl+\"&content=\"+url.QueryEscape(res2))\n\t\tt.AssertNil(err)\n\t\tif watcherAdapter, ok := adapter.(gcfg.WatcherAdapter); ok {\n\t\t\tt.Assert(watcherAdapter.GetWatcherNames()[0], \"test\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/config/polaris/README.MD",
    "content": "# Polaris\n\nPackage `polaris` implements GoFrame `gcfg.Adapter` using polaris service.\n\n# Installation\n\n```\ngo get -u github.com/gogf/gf/contrib/config/polaris/v2\n```\n\n# Usage\n\n## Create a custom boot package\n\nIf you wish using configuration from polaris globally,\nit is strongly recommended creating a custom boot package in very top import,\nwhich sets the Adapter of default configuration instance before any other package boots.\n\n```go\npackage boot\n\nimport (\n    \"github.com/gogf/gf/contrib/config/polaris/v2\"\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc init() {\n    var (\n        ctx       = gctx.GetInitCtx()\n        namespace = \"default\"\n        fileGroup = \"goframe\"\n        fileName  = \"config.yaml\"\n        path      = \"testdata/polaris.yaml\"\n        logDir    = \"/tmp/polaris/log\"\n    )\n    // Create polaris Client that implements gcfg.Adapter.\n    adapter, err := polaris.New(ctx, polaris.Config{\n        Namespace: namespace,\n        FileGroup: fileGroup,\n        FileName:  fileName,\n        Path:      path,\n        LogDir:    logDir,\n        Watch:     true,\n    })\n    if err != nil {\n        g.Log().Fatalf(ctx, `%+v`, err)\n    }\n    // Change the adapter of default configuration instance.\n    g.Cfg().SetAdapter(adapter)\n}\n```\n\n## Import boot package on top of main\n\nIt is strongly recommended import your boot package in top of your `main.go`.\n\nNote the top `import`: `_ \"github.com/gogf/gf/example/config/polaris/boot\"` .\n\n```go\npackage main\n\nimport (\n    _ \"github.com/gogf/gf/example/config/polaris/boot\"\n    \n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n    var ctx = gctx.GetInitCtx()\n    \n    // Available checks.\n    g.Dump(g.Cfg().Available(ctx))\n    \n    // All key-value configurations.\n    g.Dump(g.Cfg().Data(ctx))\n    \n    // Retrieve certain value by key.\n    g.Dump(g.Cfg().MustGet(ctx, \"server.address\"))\n}\n```\n\n## License\n\n`GoFrame Polaris` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n"
  },
  {
    "path": "contrib/config/polaris/go.mod",
    "content": "module github.com/gogf/gf/contrib/config/polaris/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/polarismesh/polaris-go v1.6.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.1.2 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/dlclark/regexp2 v1.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/protobuf v1.5.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.0.0 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/natefinch/lumberjack v2.0.0+incompatible // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/polarismesh/specification v1.5.5-alpha.1 // indirect\n\tgithub.com/prometheus/client_golang v1.12.2 // indirect\n\tgithub.com/prometheus/client_model v0.2.0 // indirect\n\tgithub.com/prometheus/common v0.32.1 // indirect\n\tgithub.com/prometheus/procfs v0.7.3 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/spaolacci/murmur3 v1.1.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgo.uber.org/zap v1.21.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect\n\tgoogle.golang.org/grpc v1.51.0 // indirect\n\tgoogle.golang.org/protobuf v1.28.1 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/config/polaris/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=\ncloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=\ncloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=\ncloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=\ncloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=\ncloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=\ncloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=\ncloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=\ncloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=\ncloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=\ncloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=\ncloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=\ncloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=\ncloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=\ncloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=\ncloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=\ncloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=\ncloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=\ncloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=\ncloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=\ncloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=\ncloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=\ncloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=\ncloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=\ncloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=\ncloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=\ncloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=\ncloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=\ncloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=\ncloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=\ncloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=\ncloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=\ncloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=\ncloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=\ncloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=\ncloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=\ncloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=\ncloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=\ncloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=\ncloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=\ncloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=\ncloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=\ncloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=\ncloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=\ncloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=\ncloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=\ncloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=\ncloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=\ncloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=\ncloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=\ncloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=\ncloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=\ncloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=\ncloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=\ncloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=\ncloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=\ncloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=\ncloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=\ncloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=\ncloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=\ncloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=\ncloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=\ncloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=\ncloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=\ncloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=\ncloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=\ncloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=\ncloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=\ncloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=\ncloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=\ncloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=\ncloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=\ncloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=\ncloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=\ncloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=\ncloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=\ncloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=\ncloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=\ncloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=\ncloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=\ncloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=\ncloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=\ncloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=\ncloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=\ncloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=\ncloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=\ncloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=\ncloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=\ncloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=\ncloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=\ncloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=\ncloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=\ncloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=\ncloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=\ncloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=\ncloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=\ncloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=\ncloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=\ncloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=\ncloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=\ncloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=\ncloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=\ncloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=\ncloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=\ncloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=\ncloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=\ncloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=\ncloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=\ncloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=\ncloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=\ncloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=\ncloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=\ncloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=\ncloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=\ncloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ncloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=\ncloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=\ncloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=\ncloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=\ncloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=\ncloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=\ncloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=\ncloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=\ncloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=\ncloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=\ncloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=\ncloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=\ncloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=\ngithub.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc=\ngithub.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg=\ngithub.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y=\ngithub.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks=\ngithub.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A=\ngithub.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=\ngithub.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=\ngithub.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=\ngithub.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=\ngithub.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=\ngithub.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=\ngithub.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=\ngithub.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polarismesh/polaris-go v1.6.1 h1:dNhYZVpO4eTLEV+mm4uBRT2YAdzPsMsPs2or8KDjOhM=\ngithub.com/polarismesh/polaris-go v1.6.1/go.mod h1:gGEe8mz4qMv199gzc+Bf8rmzOxuPox7aiEoHRNH3OKQ=\ngithub.com/polarismesh/specification v1.5.5-alpha.1 h1:lGLaj+I6iD25F0FuQnR83sR+1SJ8KqykS0vCnGx2ZAQ=\ngithub.com/polarismesh/specification v1.5.5-alpha.1/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=\ngithub.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=\ngithub.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=\ngithub.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=\ngo.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=\ngoogle.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=\ngoogle.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=\ngoogle.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=\ngoogle.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=\ngoogle.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=\ngoogle.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=\ngoogle.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=\ngoogle.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=\ngoogle.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=\ngoogle.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=\ngoogle.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=\ngoogle.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=\ngoogle.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=\ngoogle.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=\ngoogle.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=\ngoogle.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=\ngoogle.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=\ngoogle.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=\ngoogle.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=\ngoogle.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=\ngoogle.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=\ngoogle.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=\ngoogle.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a h1:GH6UPn3ixhWcKDhpnEC55S75cerLPdpp3hrhfKYjZgw=\ngoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=\ngoogle.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=\ngoogle.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=\ngoogle.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "contrib/config/polaris/polaris.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package polaris implements gcfg.Adapter using polaris service.\npackage polaris\n\nimport (\n\t\"context\"\n\n\t\"github.com/polarismesh/polaris-go\"\n\t\"github.com/polarismesh/polaris-go/api\"\n\t\"github.com/polarismesh/polaris-go/pkg/model\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ gcfg.Adapter        = (*Client)(nil)\n\t_ gcfg.WatcherAdapter = (*Client)(nil)\n)\n\n// Config is the configuration for polaris.\ntype Config struct {\n\t// The namespace of the configuration.\n\tNamespace string `v:\"required\"`\n\t// The group of the configuration.\n\tFileGroup string `v:\"required\"`\n\t// The name of the configuration.\n\tFileName string `v:\"required\"`\n\t// The path of the polaris configuration file.\n\tPath string `v:\"required\"`\n\t// The log directory for polaris.\n\tLogDir string\n\t// Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.\n\tWatch bool\n}\n\n// Client implements gcfg.Adapter implementing using polaris service.\ntype Client struct {\n\tconfig   Config\n\tclient   model.ConfigFile\n\tvalue    *g.Var\n\twatchers *gcfg.WatcherRegistry\n}\n\nconst defaultLogDir = \"/tmp/polaris/log\"\n\n// New creates and returns gcfg.Adapter implementing using polaris service.\nfunc New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {\n\tif err = g.Validator().Data(config).Run(ctx); err != nil {\n\t\terr = gerror.Wrap(err, \"invalid polaris config\")\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tclient = &Client{\n\t\t\tconfig:   config,\n\t\t\tvalue:    g.NewVar(nil, true),\n\t\t\twatchers: gcfg.NewWatcherRegistry(),\n\t\t}\n\t\tconfigAPI polaris.ConfigAPI\n\t)\n\n\tif configAPI, err = polaris.NewConfigAPIByFile(config.Path); err != nil {\n\t\terr = gerror.Wrapf(err, \"Polaris configuration initialization failed with config: %+v\", config)\n\t\treturn\n\t}\n\t// set log dir\n\tif gstr.Trim(config.LogDir) == \"\" {\n\t\tconfig.LogDir = defaultLogDir\n\t}\n\tif err = client.LogDir(config.LogDir); err != nil {\n\t\terr = gerror.Wrap(err, \"set polaris log dir failed\")\n\t\treturn\n\t}\n\n\tif client.client, err = configAPI.GetConfigFile(config.Namespace, config.FileGroup, config.FileName); err != nil {\n\t\terr = gerror.Wrapf(err, \"failed to read data from Polaris configuration center  with config: %+v\", config)\n\t\treturn\n\t}\n\n\treturn client, nil\n}\n\n// LogDir sets the log directory for polaris.\nfunc (c *Client) LogDir(dir string) error {\n\treturn api.SetLoggersDir(dir)\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {\n\tif len(resource) == 0 && !c.value.IsNil() {\n\t\treturn true\n\t}\n\n\tvar namespace = c.config.Namespace\n\tif len(resource) > 0 {\n\t\tnamespace = resource[0]\n\t}\n\n\treturn c.client.GetNamespace() == namespace\n}\n\n// Get retrieves and return value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (c *Client) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValueAndWatch(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead to lots of memory usage if configuration data are too large,\n// you can implement this function if necessary.\nfunc (c *Client) Data(ctx context.Context) (data map[string]any, err error) {\n\tif c.value.IsNil() {\n\t\tif err = c.updateLocalValueAndWatch(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.value.Val().(*gjson.Json).Map(), nil\n}\n\n// init retrieves and caches the configmap content.\nfunc (c *Client) updateLocalValueAndWatch(ctx context.Context) (err error) {\n\tif err = c.doUpdate(ctx); err != nil {\n\t\terr = gerror.Wrap(err, \"failed to update local value\")\n\t\treturn err\n\t}\n\tif err = c.doWatch(ctx); err != nil {\n\t\terr = gerror.Wrap(err, \"failed to watch configmap\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// doUpdate retrieves and caches the configmap content.\nfunc (c *Client) doUpdate(ctx context.Context) (err error) {\n\tif !c.client.HasContent() {\n\t\treturn gerror.New(\"config file is empty\")\n\t}\n\tvar j *gjson.Json\n\tcontent := c.client.GetContent()\n\tif j, err = gjson.LoadContent([]byte(content)); err != nil {\n\t\treturn gerror.Wrap(err, `parse config map item from polaris failed`)\n\t}\n\tc.value.Set(j)\n\tadapterCtx := NewAdapterCtx(ctx).WithNamespace(c.config.Namespace).WithFileGroup(c.config.FileGroup).\n\t\tWithFileName(c.config.FileName).WithOperation(gcfg.OperationUpdate).WithContent(content)\n\tc.notifyWatchers(adapterCtx.Ctx)\n\treturn nil\n}\n\n// doWatch watches the configmap content.\nfunc (c *Client) doWatch(ctx context.Context) (err error) {\n\tif !c.config.Watch {\n\t\treturn nil\n\t}\n\tgo c.startAsynchronousWatch(\n\t\tctx,\n\t\tc.client.AddChangeListenerWithChannel(),\n\t)\n\treturn nil\n}\n\n// startAsynchronousWatch starts the asynchronous watch for the specified configuration file.\nfunc (c *Client) startAsynchronousWatch(ctx context.Context, changeChan <-chan model.ConfigFileChangeEvent) {\n\tfor range changeChan {\n\t\t_ = c.doUpdate(ctx)\n\t}\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (c *Client) AddWatcher(name string, f gcfg.WatcherFunc) {\n\tc.watchers.Add(name, f)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (c *Client) RemoveWatcher(name string) {\n\tc.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (c *Client) GetWatcherNames() []string {\n\treturn c.watchers.GetNames()\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (c *Client) IsWatching(name string) bool {\n\treturn c.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (c *Client) notifyWatchers(ctx context.Context) {\n\tc.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "contrib/config/polaris/polaris_adapter_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package polaris implements gcfg.Adapter using polaris service.\npackage polaris\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\t// ContextKeyNamespace is the context key for namespace\n\tContextKeyNamespace gctx.StrKey = \"namespace\"\n\t// ContextKeyFileGroup is the context key for group\n\tContextKeyFileGroup gctx.StrKey = \"fileGroup\"\n)\n\n// PolarisAdapterCtx is the context adapter for polaris configuration\ntype PolarisAdapterCtx struct {\n\tCtx context.Context\n}\n\n// NewAdapterCtxWithCtx creates and returns a new PolarisAdapterCtx with the given context.\nfunc NewAdapterCtxWithCtx(ctx context.Context) *PolarisAdapterCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &PolarisAdapterCtx{Ctx: ctx}\n}\n\n// NewAdapterCtx creates and returns a new PolarisAdapterCtx.\n// If context is provided, it will be used; otherwise, a background context is created.\nfunc NewAdapterCtx(ctx ...context.Context) *PolarisAdapterCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterCtxWithCtx(context.Background())\n}\n\n// GetAdapterCtx creates a new PolarisAdapterCtx with the given context\nfunc GetAdapterCtx(ctx context.Context) *PolarisAdapterCtx {\n\treturn NewAdapterCtxWithCtx(ctx)\n}\n\n// WithOperation sets the operation in the context\nfunc (n *PolarisAdapterCtx) WithOperation(operation gcfg.OperationType) *PolarisAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, gcfg.ContextKeyOperation, operation)\n\treturn n\n}\n\n// WithNamespace sets the namespace in the context\nfunc (n *PolarisAdapterCtx) WithNamespace(namespace string) *PolarisAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, ContextKeyNamespace, namespace)\n\treturn n\n}\n\n// WithFileGroup sets the group in the context\nfunc (n *PolarisAdapterCtx) WithFileGroup(fileGroup string) *PolarisAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, ContextKeyFileGroup, fileGroup)\n\treturn n\n}\n\n// WithFileName sets the fileName in the context\nfunc (n *PolarisAdapterCtx) WithFileName(fileName string) *PolarisAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, gcfg.ContextKeyFileName, fileName)\n\treturn n\n}\n\n// WithContent sets the content in the context\nfunc (n *PolarisAdapterCtx) WithContent(content string) *PolarisAdapterCtx {\n\tn.Ctx = context.WithValue(n.Ctx, gcfg.ContextKeyContent, content)\n\treturn n\n}\n\n// GetNamespace retrieves the namespace from the context\nfunc (n *PolarisAdapterCtx) GetNamespace() string {\n\tif v := n.Ctx.Value(ContextKeyNamespace); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetFileGroup retrieves the group from the context\nfunc (n *PolarisAdapterCtx) GetFileGroup() string {\n\tif v := n.Ctx.Value(ContextKeyFileGroup); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetFileName retrieves the fileName from the context\nfunc (n *PolarisAdapterCtx) GetFileName() string {\n\tif v := n.Ctx.Value(gcfg.ContextKeyFileName); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetContent retrieves the content from the context\nfunc (n *PolarisAdapterCtx) GetContent() string {\n\tif v := n.Ctx.Value(gcfg.ContextKeyContent); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetOperation retrieves the operation from the context\nfunc (n *PolarisAdapterCtx) GetOperation() gcfg.OperationType {\n\tif v := n.Ctx.Value(gcfg.ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(gcfg.OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/drivers/README.MD",
    "content": "\n# Database drivers\n\nPowerful database drivers for package gdb.\n\n## Installation\n\nLet's take `mysql` for example.\n\n```shell\ngo get github.com/gogf/gf/contrib/drivers/mysql/v2@latest\n\n# Easy for copying:\ngo get github.com/gogf/gf/contrib/drivers/clickhouse/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/dm/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/gaussdb/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/mariadb/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/mssql/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/oceanbase/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/oracle/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/pgsql/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/sqlite/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/sqlitecgo/v2@latest\ngo get github.com/gogf/gf/contrib/drivers/tidb/v2@latest\n```\n\nChoose and import the driver to your project:\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n```\n\nCommonly imported at top of `main.go`:\n\n```go\npackage main\n\nimport (\n\t_ \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n\n\t// Other imported packages.\n)\n\nfunc main() {\n\t// Main logics.\n}\n```\n\n## Supported Drivers\n\n### MySQL\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n```\n\n### MariaDB\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/mariadb/v2\"\n```\n\n### TiDB\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/tidb/v2\"\n```\n\n### OceanBase\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/oceanbase/v2\"\n```\n\n### GaussDB\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/gaussdb/v2\"\n```\n\n### SQLite\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/sqlite/v2\"\n```\n\n#### cgo version\n\nWhen the target is a `32-bit` Windows system, the `cgo` version needs to be used.\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/sqlitecgo/v2\"\n```\n\n### PostgreSQL\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n```\n\n### SQL Server\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/mssql/v2\"\n```\n\nNote:\n\n- `InsertIgnore` returns error if there is no primary key or unique index submitted with record.\n- It supports server version >= `SQL Server2005`\n- It ONLY supports `datetime2` and `datetimeoffset` types for auto handling created_at/updated_at/deleted_at columns, \n  because datetime type does not support microseconds precision when column value is passed as string.\n\n### Oracle\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/oracle/v2\"\n```\n\nNote:\n\n- It does not support `LastInsertId`.\n- `InsertIgnore` returns error if there is no primary key or unique index submitted with record.\n\n### ClickHouse\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/clickhouse/v2\"\n```\n\nNote:\n\n- It does not support `InsertIgnore/InsertAndGetId` features.\n- It does not support `Save/Replace` features.\n- It does not support `Transaction` feature.\n- It does not support `RowsAffected` feature.\n\n### DM\n\n```go\nimport _ \"github.com/gogf/gf/contrib/drivers/dm/v2\"\n```\n\nNote:\n\n- `InsertIgnore` returns error if there is no primary key or unique index submitted with record.\n\n## Custom Drivers\n\nIt's quick and easy, please refer to current driver source.\nIt's quite appreciated if any PR for new drivers support into current repo.\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package clickhouse implements gdb.Driver, which supports operations for database ClickHouse.\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// Driver is the driver for clickhouse database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nvar (\n\terrUnsupportedInsertIgnore = errors.New(\"unsupported method:InsertIgnore\")\n\terrUnsupportedInsertGetId  = errors.New(\"unsupported method:InsertGetId\")\n\terrUnsupportedReplace      = errors.New(\"unsupported method:Replace\")\n\terrUnsupportedBegin        = errors.New(\"unsupported method:Begin\")\n\terrUnsupportedTransaction  = errors.New(\"unsupported method:Transaction\")\n)\n\nconst (\n\tupdateFilterPattern             = `(?i)UPDATE[\\s]+?(\\w+[\\.]?\\w+)[\\s]+?SET`\n\tdeleteFilterPattern             = `(?i)DELETE[\\s]+?FROM[\\s]+?(\\w+[\\.]?\\w+)`\n\tfilterTypePattern               = `(?i)^UPDATE|DELETE`\n\tneedParsedSqlInCtx  gctx.StrKey = \"NeedParsedSql\"\n\tdriverName                      = \"clickhouse\"\n)\n\nfunc init() {\n\tif err := gdb.Register(`clickhouse`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for clickhouse.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for clickhouse.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\nfunc (d *Driver) injectNeedParsedSql(ctx context.Context) context.Context {\n\tif ctx.Value(needParsedSqlInCtx) != nil {\n\t\treturn ctx\n\t}\n\treturn context.WithValue(ctx, needParsedSqlInCtx, true)\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"database/sql/driver\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// ConvertValueForField converts value to the type of the record field.\nfunc (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\tswitch itemValue := fieldValue.(type) {\n\tcase time.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn itemValue, nil\n\n\tcase uuid.UUID:\n\t\treturn itemValue, nil\n\n\tcase *time.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue == nil || itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn itemValue, nil\n\n\tcase gtime.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\t// for gtime type, needs to get time.Time\n\t\treturn itemValue.Time, nil\n\n\tcase *gtime.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue == nil || itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\t// for gtime type, needs to get time.Time\n\t\treturn itemValue.Time, nil\n\n\tcase decimal.Decimal:\n\t\treturn itemValue, nil\n\n\tcase *decimal.Decimal:\n\t\tif itemValue != nil {\n\t\t\treturn *itemValue, nil\n\t\t}\n\t\treturn nil, nil\n\n\tdefault:\n\t\t// if the other type implements valuer for the driver package\n\t\t// the converted result is used\n\t\t// otherwise the interface data is committed\n\t\tvaluer, ok := itemValue.(driver.Valuer)\n\t\tif !ok {\n\t\t\treturn itemValue, nil\n\t\t}\n\t\tconvertedValue, err := valuer.Value()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn convertedValue, nil\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_do_commit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoCommit commits current sql and arguments to underlying sql driver.\nfunc (d *Driver) DoCommit(ctx context.Context, in gdb.DoCommitInput) (out gdb.DoCommitOutput, err error) {\n\tctx = d.InjectIgnoreResult(ctx)\n\treturn d.Core.DoCommit(ctx, in)\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_do_delete.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoDelete does \"DELETE FROM ... \" statement for the table.\nfunc (d *Driver) DoDelete(ctx context.Context, link gdb.Link, table string, condition string, args ...any) (result sql.Result, err error) {\n\tctx = d.injectNeedParsedSql(ctx)\n\treturn d.Core.DoDelete(ctx, link, table, condition, args...)\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// DoFilter handles the sql before posts it to database.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, originSql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\tif len(args) == 0 {\n\t\treturn originSql, args, nil\n\t}\n\t// Convert placeholder char '?' to string \"$x\".\n\tvar index int\n\toriginSql, _ = gregex.ReplaceStringFunc(`\\?`, originSql, func(s string) string {\n\t\tindex++\n\t\treturn fmt.Sprintf(`$%d`, index)\n\t})\n\n\t// Only SQL generated through the framework is processed.\n\tif !d.getNeedParsedSqlFromCtx(ctx) {\n\t\treturn originSql, args, nil\n\t}\n\n\t// replace STD SQL to Clickhouse SQL grammar\n\tmodeRes, err := gregex.MatchString(filterTypePattern, strings.TrimSpace(originSql))\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tif len(modeRes) == 0 {\n\t\treturn originSql, args, nil\n\t}\n\n\t// Only delete/ UPDATE statements require filter\n\tswitch strings.ToUpper(modeRes[0]) {\n\tcase \"UPDATE\":\n\t\t// MySQL eg: UPDATE table_name SET field1=new-value1, field2=new-value2 [WHERE Clause]\n\t\t// Clickhouse eg: ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] WHERE filter_expr\n\t\tnewSql, err = gregex.ReplaceStringFuncMatch(\n\t\t\tupdateFilterPattern, originSql,\n\t\t\tfunc(s []string) string {\n\t\t\t\treturn fmt.Sprintf(\"ALTER TABLE %s UPDATE\", s[1])\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t\treturn newSql, args, nil\n\n\tcase \"DELETE\":\n\t\t// MySQL eg: DELETE FROM table_name [WHERE Clause]\n\t\t// Clickhouse eg: ALTER TABLE [db.]table [ON CLUSTER cluster] DELETE WHERE filter_expr\n\t\tnewSql, err = gregex.ReplaceStringFuncMatch(\n\t\t\tdeleteFilterPattern, originSql,\n\t\t\tfunc(s []string) string {\n\t\t\t\treturn fmt.Sprintf(\"ALTER TABLE %s DELETE\", s[1])\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\t\treturn newSql, args, nil\n\n\tdefault:\n\t\treturn originSql, args, nil\n\t}\n}\n\nfunc (d *Driver) getNeedParsedSqlFromCtx(ctx context.Context) bool {\n\treturn ctx.Value(needParsedSqlInCtx) != nil\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tvar keys, valueHolder []string\n\n\t// Handle the field names and placeholders.\n\tfor k := range list[0] {\n\t\tkeys = append(keys, k)\n\t\tvalueHolder = append(valueHolder, \"?\")\n\t}\n\t// Prepare the batch result pointer.\n\tvar (\n\t\tcharL, charR = d.Core.GetChars()\n\t\tkeysStr      = charL + strings.Join(keys, charR+\",\"+charL) + charR\n\t\tholderStr    = strings.Join(valueHolder, \",\")\n\t\ttx           gdb.TX\n\t\tstmt         *gdb.Stmt\n\t)\n\ttx, err = d.Core.Begin(ctx)\n\tif err != nil {\n\t\treturn\n\t}\n\t// It here uses defer to guarantee transaction be committed or roll-backed.\n\tdefer func() {\n\t\tif err == nil {\n\t\t\t_ = tx.Commit()\n\t\t} else {\n\t\t\t_ = tx.Rollback()\n\t\t}\n\t}()\n\tstmt, err = tx.Prepare(fmt.Sprintf(\n\t\t\"INSERT INTO %s(%s) VALUES (%s)\",\n\t\td.QuotePrefixTableName(table), keysStr,\n\t\tholderStr,\n\t))\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\t_ = stmt.Close()\n\t}()\n\n\tfor i := range len(list) {\n\t\t// Values that will be committed to underlying database driver.\n\t\tparams := make([]any, 0)\n\t\tfor _, k := range keys {\n\t\t\tparams = append(params, list[i][k])\n\t\t}\n\t\t// Prepare is allowed to execute only once in a transaction opened by clickhouse\n\t\tresult, err = stmt.ExecContext(ctx, params...)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_do_update.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoUpdate does \"UPDATE ... \" statement for the table.\nfunc (d *Driver) DoUpdate(ctx context.Context, link gdb.Link, table string, data any, condition string, args ...any) (result sql.Result, err error) {\n\tctx = d.injectNeedParsedSql(ctx)\n\treturn d.Core.DoUpdate(ctx, link, table, data, condition, args...)\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\n// InsertIgnore Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.\nfunc (d *Driver) InsertIgnore(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\treturn nil, errUnsupportedInsertIgnore\n}\n\n// InsertAndGetId Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.\nfunc (d *Driver) InsertAndGetId(ctx context.Context, table string, data any, batch ...int) (int64, error) {\n\treturn 0, errUnsupportedInsertGetId\n}\n\n// Replace Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.\nfunc (d *Driver) Replace(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\treturn nil, errUnsupportedReplace\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Open creates and returns an underlying sql.DB object for clickhouse.\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar source string\n\t// clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&max_execution_time=60\n\tif config.Pass != \"\" {\n\t\tsource = fmt.Sprintf(\n\t\t\t\"clickhouse://%s:%s@%s:%s/%s?debug=%t\",\n\t\t\tconfig.User, url.PathEscape(config.Pass),\n\t\t\tconfig.Host, config.Port, config.Name, config.Debug,\n\t\t)\n\t} else {\n\t\tsource = fmt.Sprintf(\n\t\t\t\"clickhouse://%s@%s:%s/%s?debug=%t\",\n\t\t\tconfig.User, config.Host, config.Port, config.Name, config.Debug,\n\t\t)\n\t}\n\tif config.Extra != \"\" {\n\t\tsource = fmt.Sprintf(\"%s&%s\", source, config.Extra)\n\t}\n\tif db, err = sql.Open(driverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, driverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_ping.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/ClickHouse/clickhouse-go/v2\"\n)\n\n// PingMaster pings the master node to check authentication or keeps the connection alive.\nfunc (d *Driver) PingMaster() error {\n\tconn, err := d.Master()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn d.ping(conn)\n}\n\n// PingSlave pings the slave node to check authentication or keeps the connection alive.\nfunc (d *Driver) PingSlave() error {\n\tconn, err := d.Slave()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn d.ping(conn)\n}\n\n// ping Returns the Clickhouse specific error.\nfunc (d *Driver) ping(conn *sql.DB) error {\n\terr := conn.Ping()\n\tif exception, ok := err.(*clickhouse.Exception); ok {\n\t\treturn fmt.Errorf(\"[%d]%s\", exception.Code, exception.Message)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nconst (\n\ttableFieldsColumns = `name,position,default_expression,comment,type,is_in_partition_key,is_in_sorting_key,is_in_primary_key,is_in_sampling_key`\n)\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\n// Also see DriverMysql.TableFields.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tgetColumnsSql = fmt.Sprintf(\n\t\t\t\"select %s from `system`.columns c where `table` = '%s'\",\n\t\t\ttableFieldsColumns, table,\n\t\t)\n\t)\n\tresult, err = d.DoSelect(ctx, link, getColumnsSql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor _, m := range result {\n\t\tvar (\n\t\t\tisNull    = false\n\t\t\tfieldType = m[\"type\"].String()\n\t\t)\n\t\t// in clickhouse , field type like is Nullable(int)\n\t\tfieldsResult, _ := gregex.MatchString(`^Nullable\\((.*?)\\)`, fieldType)\n\t\tif len(fieldsResult) == 2 {\n\t\t\tisNull = true\n\t\t\tfieldType = fieldsResult[1]\n\t\t}\n\t\tposition := m[\"position\"].Int()\n\t\tif result[0][\"position\"].Int() != 0 {\n\t\t\tposition -= 1\n\t\t}\n\t\tfields[m[\"name\"].String()] = &gdb.TableField{\n\t\t\tIndex:   position,\n\t\t\tName:    m[\"name\"].String(),\n\t\t\tDefault: m[\"default_expression\"].Val(),\n\t\t\tComment: m[\"comment\"].String(),\n\t\t\t// Key:     m[\"Key\"].String(),\n\t\t\tType: fieldType,\n\t\t\tNull: isNull,\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = \"select name from `system`.tables where database = '%s'\"\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, fmt.Sprintf(tablesSqlTmp, d.GetConfig().Name))\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\ttables = append(tables, m[\"name\"].String())\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_transaction.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Begin starts and returns the transaction object.\nfunc (d *Driver) Begin(ctx context.Context) (tx gdb.TX, err error) {\n\treturn nil, errUnsupportedBegin\n}\n\n// Transaction wraps the transaction logic using function `f`.\nfunc (d *Driver) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error {\n\treturn errUnsupportedTransaction\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_z_unit_db_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"select * from %s \", table))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          uint64(1),\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tanswer, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// normal map\n\t\t_, err = db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          uint64(2),\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t2\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Replace(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         uint64\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tdata := User{\n\t\t\tId:         uint64(1),\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetArray(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.GetArray(ctx, fmt.Sprintf(\"SELECT password FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tarrays := make([]string, 0)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarrays = append(arrays, fmt.Sprintf(`pass_%d`, i))\n\t\t}\n\t\tt.Assert(array, arrays)\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Update(ctx, table, \"password='123456'\", \"id=3\")\n\t\tt.AssertNE(err, nil)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"password\"].String(), \"123456\")\n\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//db.SetDebug(true)\n\t\tcount, err := db.Model(table).Ctx(ctx).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 10)\n\n\t\tresult, err := db.Delete(ctx, table, \"id>3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(result)\n\n\t\tcount, err = db.Model(table).Ctx(ctx).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 3)\n\t})\n}\n\nfunc Test_DB_Tables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"t_user1\", \"pop\", \"haha\"}\n\n\t\tfor _, v := range tables {\n\t\t\tcreateTable(v)\n\t\t}\n\n\t\tdefer dropTable(tables...)\n\n\t\tresult, err := db.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif tables[i] == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\t})\n}\n\nfunc Test_DB_TableFields(t *testing.T) {\n\ttable := createInitTable(\"user\")\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfield, err := db.TableFields(ctx, \"user\")\n\t\tgtest.AssertNil(err)\n\t\tgtest.AssertEQ(len(field), 5)\n\t\tgtest.AssertNQ(field, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTableSize = 10\n\tTableName = \"user\"\n)\n\nvar (\n\tdb  gdb.DB\n\tctx = context.TODO()\n)\n\nfunc init() {\n\tnode := gdb.ConfigNode{\n\t\tHost:  \"127.0.0.1\",\n\t\tPort:  \"9000\",\n\t\tUser:  \"default\",\n\t\tName:  \"default\",\n\t\tType:  \"clickhouse\",\n\t\tDebug: false,\n\t}\n\tvar err error\n\tdb, err = gdb.New(node)\n\tgtest.AssertNil(err)\n\tgtest.AssertNil(db.PingMaster())\n}\n\n// create table\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\n// create table and insert initial data\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc dropTable(tables ...string) {\n\tfor _, table := range tables {\n\t\tdropTableWithDb(db, table)\n\t}\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\t}\n\tdropTableWithDb(db, name)\n\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   id bigint unsigned NOT NULL,\n\t\t   passport varchar(45),\n\t\t   password char(32) NOT NULL,\n\t\t   nickname varchar(45) NOT NULL,\n\t\t   create_time datetime NOT NULL,\n\t\t   PRIMARY KEY (id)\n\t\t) ENGINE = MergeTree()\n\t\tORDER BY id ;`,\n\t\tname,\n\t))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\treturn\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          uint64(i),\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tif result != nil {\n\t\tn, e := result.RowsAffected()\n\t\tgtest.Assert(e, nil)\n\t\tgtest.Assert(n, TableSize)\n\t}\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"testing\"\n\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Issue2584(t *testing.T) {\n\ttype TDecimal struct {\n\t\tF1 *decimal.Decimal `json:\"f1\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tp1    = TDecimal{}\n\t\t\tdata1 = g.Map{\"f1\": gvar.New(1111.111)}\n\t\t\terr   = gconv.Scan(data1, &p1)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(p1.F1, 1111.111)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tp2    = TDecimal{}\n\t\t\tdata2 = g.Map{\"f1\": gvar.New(\"2222.222\")}\n\t\t\terr   = gconv.Scan(data2, &p2)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(p2.F1, 2222.222)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost:  \"127.0.0.1\",\n\t\t\tPort:  \"9000\",\n\t\t\tUser:  \"default\",\n\t\t\tName:  \"default\",\n\t\t\tType:  \"clickhouse\",\n\t\t\tDebug: false,\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Raw(fmt.Sprintf(\"select id from %s \", table)).Count()\n\t\tt.Assert(count, 10)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel := db.Model(table)\n\t\tresult, err := model.Data(g.Map{\n\t\t\t\"id\":       gdb.Raw(\"1+5\"),\n\t\t\t\"passport\": \"port_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).Insert()\n\t\tt.Assert(strings.Contains(err.Error(), \"converting gdb.Raw to UInt64 is unsupported\"), true)\n\n\t\tt.AssertNil(result)\n\t})\n}\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\t_, err := user.Data(g.Map{\n\t\t\t\"id\":          uint64(1),\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          uint64(2),\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         uint64      `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\t_, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value() // model value\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\t_, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\t_, err = db.Model(table).Where(\"id>?\", 1).Delete() // model delete\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         uint64\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One() // model one\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Where(\"id\", \"2\").Delete()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Where(\"passport='user_3'\").Update()\n\t\tt.AssertEQ(err.Error(), \"updating table with empty data\")\n\t})\n\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Model(table).Where(\"passport='user_44'\").One()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         uint64\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Sav(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          uint64(1),\n\t\t\t\"passport\":    \"t111\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T111\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          uint64(1),\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/clickhouse_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage clickhouse\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nconst (\n\tsqlVisitsDDL = `\n\tCREATE TABLE IF NOT EXISTS visits (\n\tid UInt64,\n\tduration Float64,\n\turl String,\n\tcreated DateTime\n\t) ENGINE = MergeTree()\n\tPRIMARY KEY id\n\tORDER BY id\n`\n\tdimSqlDDL = `\n\tCREATE TABLE IF NOT EXISTS dim (\n\t\"code\" String COMMENT '编码',\n\t\"translation\" String COMMENT '译文',\n\t\"superior\" UInt64 COMMENT '上级ID',\n\t\"row_number\" UInt16 COMMENT '行号',\n\t\"is_active\" UInt8 COMMENT '是否激活',\n\t\"is_preset\" UInt8 COMMENT '是否预置',\n\t\"category\" String COMMENT '类别',\n\t\"tree_path\" Array(String) COMMENT '树路径',\n\t\"id\" UInt64 COMMENT '代理主键ID',\n\t\"scd\" UInt64 COMMENT '缓慢变化维ID',\n\t\"version\" UInt64 COMMENT 'Merge版本ID',\n\t\"sign\" Int8 COMMENT '标识位',\n\t\"created_by\" UInt64 COMMENT '创建者ID',\n\t\"created_at\" DateTime64(3,'Asia/Shanghai') COMMENT '创建时间',\n\t\"updated_by\" UInt64 COMMENT '最后修改者ID',\n\t\"updated_at\" DateTime64(3,'Asia/Shanghai') COMMENT '最后修改时间',\n\t\"updated_tick\" UInt16 COMMENT '累计修改次数'\n\t) ENGINE = ReplacingMergeTree(\"version\")\n\tORDER BY (\"id\",\"scd\")\n\tCOMMENT '会计准则';\n`\n\tdimSqlDML = `\n\tinsert into dim (code, translation, superior, row_number, is_active, is_preset, category, tree_path, id, scd, version, sign, created_by, created_at, updated_by, updated_at, updated_tick)\n\tvalues  ('CN', '{\"zh_CN\":\"中国大陆会计准则\",\"en_US\":\"Chinese mainland accounting legislation\"}', 0, 1, 1, 1, 1, '[''CN'']', 607972403489804288, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0),\n\t\t\t('HK', '{\"zh_CN\":\"中国香港会计准则\",\"en_US\":\"Chinese Hong Kong accounting legislation\"}', 0, 2, 1, 1, 1, '[''HK'']', 607972558544834566, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0);\n`\n\tfactSqlDDL = `\n\tCREATE TABLE IF NOT EXISTS fact (\n\t\"adjustment_level\" UInt64 COMMENT '调整层ID',\n\t\"data_version\" UInt64 COMMENT '数据版本ID',\n\t\"accounting_legislation\" UInt64 COMMENT '会计准则ID',\n\t\"fiscal_year\" UInt16 COMMENT '会计年度',\n\t\"fiscal_period\" UInt8 COMMENT '会计期间',\n\t\"fiscal_year_period\" UInt32 COMMENT '会计年度期间',\n\t\"legal_entity\" UInt64 COMMENT '法人主体ID',\n\t\"cost_center\" UInt64 COMMENT '成本中心ID',\n\t\"legal_entity_partner\" UInt64 COMMENT '内部关联方ID',\n\t\"financial_posting\" UInt64 COMMENT '凭证头ID',\n\t\"line\" UInt16 COMMENT '行号',\n\t\"general_ledger_account\" UInt64 COMMENT '总账科目ID',\n\t\"debit\" Decimal64(9) COMMENT '借方金额',\n\t\"credit\" Decimal64(9) COMMENT '贷方金额',\n\t\"transaction_currency\" UInt64 COMMENT '交易币种ID',\n\t\"debit_tc\" Decimal64(9) COMMENT '借方金额（交易币种）',\n\t\"credit_tc\" Decimal64(9) COMMENT '贷方金额（交易币种）',\n\t\"posting_date\" Date32 COMMENT '过账日期',\n\t\"gc_year\" UInt16 COMMENT '公历年',\n\t\"gc_quarter\" UInt8 COMMENT '公历季',\n\t\"gc_month\" UInt8 COMMENT '公历月',\n\t\"gc_week\" UInt8 COMMENT '公历周',\n\t\"raw_info\" String COMMENT '源信息',\n\t\"summary\" String COMMENT '摘要',\n\t\"id\" UInt64 COMMENT '代理主键ID',\n\t\"version\" UInt64 COMMENT 'Merge版本ID',\n\t\"sign\" Int8 COMMENT '标识位'\n\t) ENGINE = ReplacingMergeTree(\"version\")\n\tORDER BY (\"adjustment_level\",\"data_version\",\"legal_entity\",\"fiscal_year\",\"fiscal_period\",\"financial_posting\",\"line\")\n\tPARTITION BY (\"adjustment_level\",\"data_version\",\"legal_entity\",\"fiscal_year\",\"fiscal_period\")\n\tCOMMENT '数据主表';\n`\n\tfactSqlDML = `\n\tinsert into fact (adjustment_level, data_version, accounting_legislation, fiscal_year, fiscal_period, fiscal_year_period, legal_entity, cost_center, legal_entity_partner, financial_posting, line, general_ledger_account, debit, credit, transaction_currency, debit_tc, credit_tc, posting_date, gc_year, gc_quarter, gc_month, gc_week, raw_info, summary, id, version, sign)\n\tvalues  (607970943242866688, 607973669943119880, 607972403489804288, 2022, 3, 202203, 607974511316307985, 0, 607976190010986520, 607996702456025136, 1, 607985607569838111, 8674.39, 0, 607974898261823505, 8674.39, 0, '2022-03-05', 2022, 1, 3, 11, '{}', '摘要', 607992882741121073, 0, 0),\n\t\t\t(607970943242866688, 607973669943119880, 607972403489804288, 2022, 4, 202204, 607974511316307985, 0, 607976190010986520, 607993586419503145, 1, 607985607569838111, 9999.88, 0, 607974898261823505, 9999.88, 0, '2022-04-10', 2022, 2, 4, 18, '{}', '摘要', 607996939140599857, 0, 0);\n`\n\texpmSqlDDL = `\n\tCREATE TABLE IF NOT EXISTS data_type (\n\t\t  Col1 UInt8 COMMENT '列1'\n\t\t, Col2 Nullable(String) COMMENT '列2'\n\t\t, Col3 FixedString(3) COMMENT '列3'\n\t\t, Col4 String COMMENT '列4'\n\t\t, Col5 Map(String, UInt8) COMMENT '列5'\n\t\t, Col6 Array(String) COMMENT '列6'\n\t\t, Col7 Tuple(String, UInt8, Array(Map(String, String))) COMMENT '列7'\n\t\t, Col8 DateTime COMMENT '列8'\n\t\t, Col9 UUID COMMENT '列9'\n\t\t, Col10 DateTime COMMENT '列10'\n\t\t, Col11 Decimal(9, 2) COMMENT '列11'\n\t\t, Col12 Decimal(9, 2) COMMENT '列12'\n\t) ENGINE = MergeTree()\n\tPRIMARY KEY Col4\n\tORDER BY Col4\n`\n)\n\nfunc clickhouseConfigDB() gdb.DB {\n\tconnect, err := gdb.New(gdb.ConfigNode{\n\t\tHost:  \"127.0.0.1\",\n\t\tPort:  \"9000\",\n\t\tUser:  \"default\",\n\t\tName:  \"default\",\n\t\tType:  \"clickhouse\",\n\t\tDebug: false,\n\t})\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(connect, nil)\n\treturn connect\n}\n\nfunc clickhouseLink() gdb.DB {\n\tconnect, err := gdb.New(gdb.ConfigNode{\n\t\tLink: \"clickhouse:default:@tcp(127.0.0.1:9000)/default?dial_timeout=200ms&max_execution_time=60\",\n\t})\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(connect, nil)\n\treturn connect\n}\n\nfunc createClickhouseTableVisits(connect gdb.DB) error {\n\t_, err := connect.Exec(context.Background(), sqlVisitsDDL)\n\treturn err\n}\n\nfunc createClickhouseTableDim(connect gdb.DB) error {\n\t_, err := connect.Exec(context.Background(), dimSqlDDL)\n\treturn err\n}\n\nfunc createClickhouseTableFact(connect gdb.DB) error {\n\t_, err := connect.Exec(context.Background(), factSqlDDL)\n\treturn err\n}\n\nfunc createClickhouseExampleTable(connect gdb.DB) error {\n\t_, err := connect.Exec(context.Background(), expmSqlDDL)\n\treturn err\n}\n\nfunc dropClickhouseTableVisits(conn gdb.DB) {\n\tsqlStr := \"DROP TABLE IF EXISTS `visits`\"\n\t_, _ = conn.Exec(context.Background(), sqlStr)\n}\n\nfunc dropClickhouseTableDim(conn gdb.DB) {\n\tsqlStr := \"DROP TABLE IF EXISTS `dim`\"\n\t_, _ = conn.Exec(context.Background(), sqlStr)\n}\n\nfunc dropClickhouseTableFact(conn gdb.DB) {\n\tsqlStr := \"DROP TABLE IF EXISTS `fact`\"\n\t_, _ = conn.Exec(context.Background(), sqlStr)\n}\n\nfunc dropClickhouseExampleTable(conn gdb.DB) {\n\tsqlStr := \"DROP TABLE IF EXISTS `data_type`\"\n\t_, _ = conn.Exec(context.Background(), sqlStr)\n}\n\nfunc TestDriverClickhouse_Create(t *testing.T) {\n\tgtest.AssertNil(createClickhouseTableVisits(clickhouseConfigDB()))\n}\n\nfunc TestDriverClickhouse_New(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNE(connect, nil)\n\tgtest.AssertNil(connect.PingMaster())\n\tgtest.AssertNil(connect.PingSlave())\n}\n\nfunc TestDriverClickhouse_OpenLink_Ping(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNE(connect, nil)\n\tgtest.AssertNil(connect.PingMaster())\n}\n\nfunc TestDriverClickhouse_Tables(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\ttables, err := connect.Tables(context.Background())\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(len(tables), 0)\n}\n\nfunc TestDriverClickhouse_TableFields_Use_Config(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseTableVisits(connect))\n\tdefer dropClickhouseTableVisits(connect)\n\tfield, err := connect.TableFields(context.Background(), \"visits\")\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(len(field), 4)\n\tgtest.AssertNQ(field, nil)\n}\n\nfunc TestDriverClickhouse_TableFields_Use_Link(t *testing.T) {\n\tconnect := clickhouseLink()\n\tgtest.AssertNil(createClickhouseTableVisits(connect))\n\tdefer dropClickhouseTableVisits(connect)\n\tfield, err := connect.TableFields(context.Background(), \"visits\")\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(len(field), 4)\n\tgtest.AssertNQ(field, nil)\n}\n\nfunc TestDriverClickhouse_Transaction(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tdefer dropClickhouseTableVisits(connect)\n\tgtest.AssertNE(connect.Transaction(context.Background(), func(ctx context.Context, tx gdb.TX) error {\n\t\treturn nil\n\t}), nil)\n}\n\nfunc TestDriverClickhouse_InsertIgnore(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\t_, err := connect.InsertIgnore(context.Background(), \"\", nil)\n\tgtest.AssertEQ(err, errUnsupportedInsertIgnore)\n}\n\nfunc TestDriverClickhouse_InsertAndGetId(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\t_, err := connect.InsertAndGetId(context.Background(), \"\", nil)\n\tgtest.AssertEQ(err, errUnsupportedInsertGetId)\n}\n\nfunc TestDriverClickhouse_InsertOne(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\t_, err := connect.Model(\"visits\").Data(g.Map{\n\t\t\"duration\": float64(grand.Intn(999)),\n\t\t\"url\":      gconv.String(grand.Intn(999)),\n\t\t\"created\":  time.Now(),\n\t}).Insert()\n\tgtest.AssertNil(err)\n}\n\nfunc TestDriverClickhouse_InsertOneAutoDateTimeWrite(t *testing.T) {\n\tconnect, err := gdb.New(gdb.ConfigNode{\n\t\tHost:      \"127.0.0.1\",\n\t\tPort:      \"9000\",\n\t\tUser:      \"default\",\n\t\tName:      \"default\",\n\t\tType:      \"clickhouse\",\n\t\tDebug:     false,\n\t\tCreatedAt: \"created\",\n\t})\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(connect, nil)\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\tbeforeInsertTime := time.Now()\n\t_, err = connect.Model(\"visits\").Data(g.Map{\n\t\t\"duration\": float64(grand.Intn(999)),\n\t\t\"url\":      gconv.String(grand.Intn(999)),\n\t}).Insert()\n\tgtest.AssertNil(err)\n\t// Query the inserted data to get the time field value\n\tdata, err := connect.Model(\"visits\").One()\n\tgtest.AssertNil(err)\n\t// Get the time value from the inserted data\n\tcreatedTime := data[\"created\"].Time()\n\t// Assert the time field value is equal to or after the beforeInsertTime\n\tgtest.AssertGE(createdTime.Unix(), beforeInsertTime.Unix())\n}\n\nfunc TestDriverClickhouse_InsertMany(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\ttx, err := connect.Begin(context.Background())\n\tgtest.AssertEQ(err, errUnsupportedBegin)\n\tgtest.AssertNil(tx)\n}\n\nfunc TestDriverClickhouse_Insert(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\ttype insertItem struct {\n\t\tId       uint64    `orm:\"id\"`\n\t\tDuration float64   `orm:\"duration\"`\n\t\tUrl      string    `orm:\"url\"`\n\t\tCreated  time.Time `orm:\"created\"`\n\t}\n\tvar (\n\t\tinsertUrl = \"https://goframe.org\"\n\t\ttotal     = 0\n\t\titem      = insertItem{\n\t\t\tDuration: 1,\n\t\t\tUrl:      insertUrl,\n\t\t\tCreated:  time.Now(),\n\t\t}\n\t)\n\t_, err := connect.Model(\"visits\").Data(item).Insert()\n\tgtest.AssertNil(err)\n\t_, err = connect.Model(\"visits\").Data(item).Save()\n\tgtest.AssertNil(err)\n\ttotal, err = connect.Model(\"visits\").Count()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(total, 2)\n\tvar list []*insertItem\n\tfor i := 0; i < 50; i++ {\n\t\tlist = append(list, &insertItem{\n\t\t\tDuration: float64(grand.Intn(999)),\n\t\t\tUrl:      insertUrl,\n\t\t\tCreated:  time.Now(),\n\t\t})\n\t}\n\t_, err = connect.Model(\"visits\").Data(list).Insert()\n\tgtest.AssertNil(err)\n\t_, err = connect.Model(\"visits\").Data(list).Save()\n\tgtest.AssertNil(err)\n\ttotal, err = connect.Model(\"visits\").Count()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(total, 102)\n}\n\nfunc TestDriverClickhouse_Insert_Use_Exec(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableFact(connect), nil)\n\tdefer dropClickhouseTableFact(connect)\n\t_, err := connect.Exec(context.Background(), factSqlDML)\n\tgtest.AssertNil(err)\n}\n\nfunc TestDriverClickhouse_Delete(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\t_, err := connect.Model(\"visits\").Where(\"created >\", \"2021-01-01 00:00:00\").Delete()\n\tgtest.AssertNil(err)\n\t_, err = connect.Model(\"visits\").\n\t\tWhere(\"created >\", \"2021-01-01 00:00:00\").\n\t\tWhere(\"duration > \", 0).\n\t\tWhere(\"url is not null\").\n\t\tDelete()\n\tgtest.AssertNil(err)\n}\n\nfunc TestDriverClickhouse_Update(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableVisits(connect), nil)\n\tdefer dropClickhouseTableVisits(connect)\n\t_, err := connect.Model(\"visits\").Where(\"created > \", \"2021-01-01 15:15:15\").Data(g.Map{\n\t\t\"created\": time.Now().Format(\"2006-01-02 15:04:05\"),\n\t}).Update()\n\tgtest.AssertNil(err)\n\t_, err = connect.Model(\"visits\").\n\t\tWhere(\"created > \", \"2021-01-01 15:15:15\").\n\t\tWhere(\"duration > \", 0).\n\t\tWhere(\"url is not null\").\n\t\tData(g.Map{\n\t\t\t\"created\": time.Now().Format(\"2006-01-02 15:04:05\"),\n\t\t}).Update()\n}\n\nfunc TestDriverClickhouse_Replace(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\t_, err := connect.Replace(context.Background(), \"\", nil)\n\tgtest.AssertEQ(err, errUnsupportedReplace)\n}\n\nfunc TestDriverClickhouse_DoFilter(t *testing.T) {\n\trawSQL := \"select * from visits where 1 = 1\"\n\tthis := Driver{}\n\treplaceSQL, _, err := this.DoFilter(context.Background(), nil, rawSQL, []any{1})\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(rawSQL, replaceSQL)\n\n\t// this SQL can't run ,clickhouse will report an error because there is no WHERE statement\n\trawSQL = \"update visit set url = '1'\"\n\treplaceSQL, _, err = this.DoFilter(context.Background(), nil, rawSQL, []any{1})\n\tgtest.AssertNil(err)\n\n\t// this SQL can't run ,clickhouse will report an error because there is no WHERE statement\n\trawSQL = \"delete from visit\"\n\treplaceSQL, _, err = this.DoFilter(context.Background(), nil, rawSQL, []any{1})\n\tgtest.AssertNil(err)\n\n\tctx := this.injectNeedParsedSql(context.Background())\n\trawSQL = \"UPDATE visit SET url = '1' WHERE url = '0'\"\n\treplaceSQL, _, err = this.DoFilter(ctx, nil, rawSQL, []any{1})\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(replaceSQL, \"ALTER TABLE visit UPDATE url = '1' WHERE url = '0'\")\n\n\trawSQL = \"DELETE FROM visit WHERE url = '0'\"\n\treplaceSQL, _, err = this.DoFilter(ctx, nil, rawSQL, []any{1})\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(replaceSQL, \"ALTER TABLE visit DELETE WHERE url = '0'\")\n}\n\nfunc TestDriverClickhouse_Select(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseTableVisits(connect))\n\tdefer dropClickhouseTableVisits(connect)\n\t_, err := connect.Model(\"visits\").Data(g.Map{\n\t\t\"url\":      \"goframe.org\",\n\t\t\"duration\": float64(1),\n\t}).Insert()\n\tgtest.AssertNil(err)\n\ttemp, err := connect.Model(\"visits\").Where(\"url\", \"goframe.org\").Where(\"duration >= \", 1).One()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(temp.IsEmpty(), false)\n\t_, err = connect.Model(\"visits\").Data(g.Map{\n\t\t\"url\":      \"goframe.org\",\n\t\t\"duration\": float64(2),\n\t}).Insert()\n\tgtest.AssertNil(err)\n\tdata, err := connect.Model(\"visits\").Where(\"url\", \"goframe.org\").Where(\"duration >= \", 1).All()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(len(data), 2)\n}\n\nfunc TestDriverClickhouse_Exec_OPTIMIZE(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseTableVisits(connect))\n\tdefer dropClickhouseTableVisits(connect)\n\tsqlStr := \"OPTIMIZE table visits\"\n\t_, err := connect.Exec(context.Background(), sqlStr)\n\tgtest.AssertNil(err)\n}\n\nfunc TestDriverClickhouse_ExecInsert(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertEQ(createClickhouseTableDim(connect), nil)\n\tdefer dropClickhouseTableDim(connect)\n\t_, err := connect.Exec(context.Background(), dimSqlDML)\n\tgtest.AssertNil(err)\n}\n\nfunc TestDriverClickhouse_NilTime(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseExampleTable(connect))\n\tdefer dropClickhouseExampleTable(connect)\n\ttype testNilTime struct {\n\t\tCol1  uint8\n\t\tCol2  string\n\t\tCol3  string\n\t\tCol4  string\n\t\tCol5  map[string]uint8\n\t\tCol6  []string\n\t\tCol7  []any\n\t\tCol8  *time.Time\n\t\tCol9  uuid.UUID\n\t\tCol10 *gtime.Time\n\t\tCol11 decimal.Decimal\n\t\tCol12 *decimal.Decimal\n\t}\n\tinsertData := []*testNilTime{}\n\tmoney := decimal.NewFromFloat(1.12)\n\tstrMoney, _ := decimal.NewFromString(\"99999.999\")\n\tfor i := 0; i < 10000; i++ {\n\t\tinsertData = append(insertData, &testNilTime{\n\t\t\tCol4: \"Inc.\",\n\t\t\tCol9: uuid.New(),\n\t\t\tCol7: []any{ // Tuple(String, UInt8, Array(Map(String, String)))\n\t\t\t\t\"String Value\", uint8(5), []map[string]string{\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t}},\n\t\t\tCol11: money,\n\t\t\tCol12: &strMoney,\n\t\t})\n\t}\n\t_, err := connect.Model(\"data_type\").Data(insertData).Insert()\n\tgtest.AssertNil(err)\n\tcount, err := connect.Model(\"data_type\").Where(\"Col4\", \"Inc.\").Count()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(count, 10000)\n\n\tdata, err := connect.Model(\"data_type\").Where(\"Col4\", \"Inc.\").One()\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(data, nil)\n\tg.Dump(data)\n\tgtest.AssertEQ(data[\"Col11\"].String(), \"1.12\")\n\tgtest.AssertEQ(data[\"Col12\"].String(), \"99999.99\")\n}\n\nfunc TestDriverClickhouse_BatchInsert(t *testing.T) {\n\t// example from\n\t// https://github.com/ClickHouse/clickhouse-go/blob/v2/examples/std/batch/main.go\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseExampleTable(connect))\n\tdefer dropClickhouseExampleTable(connect)\n\tinsertData := []g.Map{}\n\tfor i := 0; i < 10000; i++ {\n\t\tinsertData = append(insertData, g.Map{\n\t\t\t\"Col1\": uint8(42),\n\t\t\t\"Col2\": \"ClickHouse\",\n\t\t\t\"Col3\": \"Inc\",\n\t\t\t\"Col4\": guid.S(),\n\t\t\t\"Col5\": map[string]uint8{\"key\": 1},             // Map(String, UInt8)\n\t\t\t\"Col6\": []string{\"Q\", \"W\", \"E\", \"R\", \"T\", \"Y\"}, // Array(String)\n\t\t\t\"Col7\": []any{ // Tuple(String, UInt8, Array(Map(String, String)))\n\t\t\t\t\"String Value\", uint8(5), []map[string]string{\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t\t{\"key\": \"value\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"Col8\":  gtime.Now(),\n\t\t\t\"Col9\":  uuid.New(),\n\t\t\t\"Col10\": nil,\n\t\t})\n\t}\n\t_, err := connect.Model(\"data_type\").Data(insertData).Insert()\n\tgtest.AssertNil(err)\n\tcount, err := connect.Model(\"data_type\").Where(\"Col2\", \"ClickHouse\").Where(\"Col3\", \"Inc\").Count()\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(count, 10000)\n}\n\nfunc TestDriverClickhouse_Open(t *testing.T) {\n\t// link\n\t// DSM\n\t// clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&max_execution_time=60\n\tlink := \"clickhouse:default:@tcp(127.0.0.1:9000)/default?dial_timeout=200ms&max_execution_time=60\"\n\tdb, err := gdb.New(gdb.ConfigNode{\n\t\tLink: link,\n\t\tType: \"clickhouse\",\n\t})\n\tgtest.AssertNil(err)\n\tgtest.AssertNil(db.PingMaster())\n}\n\nfunc TestDriverClickhouse_TableFields(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseExampleTable(connect))\n\tdefer dropClickhouseExampleTable(connect)\n\tdataTypeTable, err := connect.TableFields(context.Background(), \"data_type\")\n\tgtest.AssertNil(err)\n\tgtest.AssertNE(dataTypeTable, nil)\n\n\tvar result = map[string][]any{\n\t\t\"Col1\":  {0, \"Col1\", \"UInt8\", false, \"\", \"\", \"\", \"列1\"},\n\t\t\"Col2\":  {1, \"Col2\", \"String\", true, \"\", \"\", \"\", \"列2\"},\n\t\t\"Col3\":  {2, \"Col3\", \"FixedString(3)\", false, \"\", \"\", \"\", \"列3\"},\n\t\t\"Col4\":  {3, \"Col4\", \"String\", false, \"\", \"\", \"\", \"列4\"},\n\t\t\"Col5\":  {4, \"Col5\", \"Map(String, UInt8)\", false, \"\", \"\", \"\", \"列5\"},\n\t\t\"Col6\":  {5, \"Col6\", \"Array(String)\", false, \"\", \"\", \"\", \"列6\"},\n\t\t\"Col7\":  {6, \"Col7\", \"Tuple(String, UInt8, Array(Map(String, String)))\", false, \"\", \"\", \"\", \"列7\"},\n\t\t\"Col8\":  {7, \"Col8\", \"DateTime\", false, \"\", \"\", \"\", \"列8\"},\n\t\t\"Col9\":  {8, \"Col9\", \"UUID\", false, \"\", \"\", \"\", \"列9\"},\n\t\t\"Col10\": {9, \"Col10\", \"DateTime\", false, \"\", \"\", \"\", \"列10\"},\n\t\t\"Col11\": {10, \"Col11\", \"Decimal(9, 2)\", false, \"\", \"\", \"\", \"列11\"},\n\t\t\"Col12\": {11, \"Col12\", \"Decimal(9, 2)\", false, \"\", \"\", \"\", \"列12\"},\n\t}\n\tfor k, v := range result {\n\t\t_, ok := dataTypeTable[k]\n\t\tgtest.AssertEQ(ok, true)\n\t\tgtest.AssertEQ(dataTypeTable[k].Index, v[0])\n\t\tgtest.AssertEQ(dataTypeTable[k].Name, v[1])\n\t\tgtest.AssertEQ(dataTypeTable[k].Type, v[2])\n\t\tgtest.AssertEQ(dataTypeTable[k].Null, v[3])\n\t\tgtest.AssertEQ(dataTypeTable[k].Key, v[4])\n\t\tgtest.AssertEQ(dataTypeTable[k].Default, v[5])\n\t\tgtest.AssertEQ(dataTypeTable[k].Comment, v[7])\n\t}\n}\n\nfunc TestDriverClickhouse_TableFields_HasField(t *testing.T) {\n\tconnect := clickhouseConfigDB()\n\tgtest.AssertNil(createClickhouseExampleTable(connect))\n\tdefer dropClickhouseExampleTable(connect)\n\t// 未修复前：panic: runtime error: index out of range [12] with length 12\n\tb, err := connect.GetCore().HasField(context.Background(), \"data_type\", \"Col1\")\n\tgtest.AssertNil(err)\n\tgtest.AssertEQ(b, true)\n}\n"
  },
  {
    "path": "contrib/drivers/clickhouse/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/clickhouse/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/ClickHouse/clickhouse-go/v2 v2.0.15\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/shopspring/decimal v1.3.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/paulmach/orb v0.7.1 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.14 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/ClickHouse/clickhouse-go/v2 => github.com/gogf/clickhouse-go/v2 v2.0.15-compatible\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/drivers/clickhouse/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=\ngithub.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/gogf/clickhouse-go/v2 v2.0.15-compatible h1:VYgibtmI/u+hUQmtJpC7zzg1YJsDCXS052R7vCqGpDc=\ngithub.com/gogf/clickhouse-go/v2 v2.0.15-compatible/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU=\ngithub.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=\ngithub.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=\ngithub.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=\ngithub.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=\ngithub.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/dm/dm.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package dm implements gdb.Driver, which supports operations for database DM.\npackage dm\n\nimport (\n\t_ \"gitee.com/chunanyong/dm\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// Driver is the driver for dm database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tquoteChar = `\"`\n)\n\nfunc init() {\n\tvar (\n\t\terr         error\n\t\tdriverObj   = New()\n\t\tdriverNames = g.SliceStr{\"dm\"}\n\t)\n\tfor _, driverName := range driverNames {\n\t\tif err = gdb.Register(driverName, driverObj); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for dm.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for dm.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// ConvertValueForField converts value to the type of the record field.\nfunc (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\tswitch itemValue := fieldValue.(type) {\n\t// dm does not support time.Time, it so here converts it to time string that it supports.\n\tcase time.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn gtime.New(itemValue).String(), nil\n\n\t// dm does not support time.Time, it so here converts it to time string that it supports.\n\tcase *time.Time:\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tif itemValue == nil || itemValue.IsZero() {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn gtime.New(itemValue).String(), nil\n\t}\n\n\treturn fieldValue, nil\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\t// There should be no need to capitalize, because it has been done from field processing before\n\tnewSql, _ = gregex.ReplaceString(`[\"]`, \"\", sql)\n\tnewSql = gstr.ReplaceI(gstr.ReplaceI(newSql, \"GROUP_CONCAT\", \"LISTAGG\"), \"SEPARATOR\", \",\")\n\n\t// TODO The current approach is too rough. We should deal with the GROUP_CONCAT function and the\n\t// parsing of the index field from within the select from match.\n\t// （GROUP_CONCAT DM  does not approve; index cannot be used as a query column name, and security characters need to be added, such as \"index\"）\n\tl, r := d.GetChars()\n\tif strings.Contains(newSql, \"INDEX\") || strings.Contains(newSql, \"index\") {\n\t\tif !(strings.Contains(newSql, \"_INDEX\") || strings.Contains(newSql, \"_index\")) {\n\t\t\tnewSql = gstr.ReplaceI(newSql, \"INDEX\", l+\"INDEX\"+r)\n\t\t}\n\t}\n\n\t// TODO i tried to do but it never work：\n\t// array, err := gregex.MatchAllString(`SELECT (.*INDEX.*) FROM .*`, newSql)\n\t// g.Dump(\"err:\", err)\n\t// g.Dump(\"array:\", array)\n\t// g.Dump(\"array:\", array[0][1])\n\n\t// newSql, err = gregex.ReplaceString(`SELECT (.*INDEX.*) FROM .*`, l+\"INDEX\"+r, newSql)\n\t// g.Dump(\"err:\", err)\n\t// g.Dump(\"newSql:\", newSql)\n\n\t// re, err := regexp.Compile(`.*SELECT (.*INDEX.*) FROM .*`)\n\t// newSql = re.ReplaceAllStringFunc(newSql, func(data string) string {\n\t// \tfmt.Println(\"data:\", data)\n\t// \treturn data\n\t// })\n\n\treturn d.Core.DoFilter(\n\t\tctx,\n\t\tlink,\n\t\tnewSql,\n\t\targs,\n\t)\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tswitch option.InsertOption {\n\tcase gdb.InsertOptionSave:\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionReplace:\n\t\t// dm does not support REPLACE INTO syntax, use SAVE instead.\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionIgnore:\n\t\t// dm does not support INSERT IGNORE syntax, use MERGE instead.\n\t\treturn d.doInsertIgnore(ctx, link, table, list, option)\n\n\tdefault:\n\t\t// DM database supports IDENTITY auto-increment columns natively.\n\t\t// The driver automatically returns LastInsertId through sql.Result.\n\t\t//\n\t\t// Note: DM IDENTITY columns cannot accept explicit ID values unless\n\t\t// IDENTITY_INSERT is enabled. When using tables with IDENTITY columns,\n\t\t// avoid providing explicit ID values in the data.\n\t\treturn d.Core.DoInsert(ctx, link, table, list, option)\n\t}\n}\n\n// doSave support upsert for dm\nfunc (d *Driver) doSave(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, true)\n}\n\n// doInsertIgnore implements INSERT IGNORE operation using MERGE statement for DM database.\n// It only inserts records when there's no conflict on primary/unique keys.\nfunc (d *Driver) doInsertIgnore(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, false)\n}\n\n// doMergeInsert implements MERGE-based insert operations for DM database.\n// When withUpdate is true, it performs upsert (insert or update).\n// When withUpdate is false, it performs insert ignore (insert only when no conflict).\nfunc (d *Driver) doMergeInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, withUpdate bool,\n) (result sql.Result, err error) {\n\t// If OnConflict is not specified, automatically get the primary key of the table\n\tconflictKeys := option.OnConflict\n\tif len(conflictKeys) == 0 {\n\t\tprimaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\terr,\n\t\t\t\t`failed to get primary keys for table`,\n\t\t\t)\n\t\t}\n\t\tfoundPrimaryKey := false\n\t\tfor _, primaryKey := range primaryKeys {\n\t\t\tfor dataKey := range list[0] {\n\t\t\t\tif strings.EqualFold(dataKey, primaryKey) {\n\t\t\t\t\tfoundPrimaryKey = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif foundPrimaryKey {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !foundPrimaryKey {\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeMissingParameter,\n\t\t\t\t`Replace/Save/InsertIgnore operation requires conflict detection: `+\n\t\t\t\t\t`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,\n\t\t\t\ttable,\n\t\t\t)\n\t\t}\n\t\t// TODO consider composite primary keys.\n\t\tconflictKeys = primaryKeys\n\t}\n\n\tvar (\n\t\tone            = list[0]\n\t\toneLen         = len(one)\n\t\tcharL, charR   = d.GetChars()\n\t\tconflictKeySet = gset.NewStrSet(false)\n\n\t\t// queryHolders:\tHandle data with Holder that need to be merged\n\t\t// queryValues:\t\tHandle data that need to be merged\n\t\t// insertKeys:\t\tHandle valid keys that need to be inserted\n\t\t// insertValues:\tHandle values that need to be inserted\n\t\t// updateValues:\tHandle values that need to be updated (only when withUpdate=true)\n\t\tqueryHolders = make([]string, oneLen)\n\t\tqueryValues  = make([]any, oneLen)\n\t\tinsertKeys   = make([]string, oneLen)\n\t\tinsertValues = make([]string, oneLen)\n\t\tupdateValues []string\n\t)\n\n\t// conflictKeys slice type conv to set type\n\tfor _, conflictKey := range conflictKeys {\n\t\tconflictKeySet.Add(gstr.ToUpper(conflictKey))\n\t}\n\n\tindex := 0\n\tfor key, value := range one {\n\t\tkeyWithChar := charL + key + charR\n\t\tqueryHolders[index] = fmt.Sprintf(\"? AS %s\", keyWithChar)\n\t\tqueryValues[index] = value\n\t\tinsertKeys[index] = keyWithChar\n\t\tinsertValues[index] = fmt.Sprintf(\"T2.%s\", keyWithChar)\n\n\t\t// Build updateValues only when withUpdate is true\n\t\t// Filter conflict keys and soft created fields from updateValues\n\t\tif withUpdate && !(conflictKeySet.Contains(key) || d.Core.IsSoftCreatedFieldName(key)) {\n\t\t\tupdateValues = append(\n\t\t\t\tupdateValues,\n\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, keyWithChar),\n\t\t\t)\n\t\t}\n\t\tindex++\n\t}\n\n\tvar (\n\t\tbatchResult = new(gdb.SqlResult)\n\t\tsqlStr      = parseSqlForMerge(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys)\n\t)\n\tr, err := d.DoExec(ctx, link, sqlStr, queryValues...)\n\tif err != nil {\n\t\treturn r, err\n\t}\n\tif n, err := r.RowsAffected(); err != nil {\n\t\treturn r, err\n\t} else {\n\t\tbatchResult.Result = r\n\t\tbatchResult.Affected += n\n\t}\n\treturn batchResult, nil\n}\n\n// parseSqlForMerge generates MERGE statement for DM database.\n// When updateValues is empty, it only inserts (INSERT IGNORE behavior).\n// When updateValues is provided, it performs upsert (INSERT or UPDATE).\n// Examples:\n// - INSERT IGNORE: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...)\n// - UPSERT: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...) WHEN MATCHED THEN UPDATE SET ...\nfunc parseSqlForMerge(table string,\n\tqueryHolders, insertKeys, insertValues, updateValues, duplicateKey []string,\n) (sqlStr string) {\n\tvar (\n\t\tqueryHolderStr  = strings.Join(queryHolders, \",\")\n\t\tinsertKeyStr    = strings.Join(insertKeys, \",\")\n\t\tinsertValueStr  = strings.Join(insertValues, \",\")\n\t\tduplicateKeyStr string\n\t)\n\n\t// Build ON condition\n\tfor index, keys := range duplicateKey {\n\t\tif index != 0 {\n\t\t\tduplicateKeyStr += \" AND \"\n\t\t}\n\t\tduplicateKeyStr += fmt.Sprintf(\"T1.%s = T2.%s\", keys, keys)\n\t}\n\n\t// Build SQL based on whether UPDATE is needed\n\tpattern := gstr.Trim(`MERGE INTO %s T1 USING (SELECT %s FROM DUAL) T2 ON (%s) WHEN NOT MATCHED THEN INSERT(%s) VALUES (%s)`)\n\tif len(updateValues) > 0 {\n\t\t// Upsert: INSERT or UPDATE\n\t\tpattern += gstr.Trim(`WHEN MATCHED THEN UPDATE SET %s`)\n\t\treturn fmt.Sprintf(\n\t\t\tpattern, table, queryHolderStr, duplicateKeyStr, insertKeyStr, insertValueStr,\n\t\t\tstrings.Join(updateValues, \",\"),\n\t\t)\n\t}\n\t// Insert Ignore: INSERT only\n\treturn fmt.Sprintf(pattern, table, queryHolderStr, duplicateKeyStr, insertKeyStr, insertValueStr)\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_do_query.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\n// TODO I originally wanted to only convert keywords in select\n// 但是我发现 DoQuery 中会对 sql 会对 \" \" 达梦的安全字符 进行 / 转义，最后还是导致达梦无法正常解析\n// However, I found that DoQuery() will perform / escape on sql with \" \" Dameng's safe characters, which ultimately caused Dameng to be unable to parse normally.\n// But processing in DoFilter() is OK\n// func (d *Driver) DoQuery(ctx context.Context, link gdb.Link, sql string, args ...any) (gdb.Result, error) {\n// \tl, r := d.GetChars()\n// \tnew := gstr.ReplaceI(sql, \"INDEX\", l+\"INDEX\"+r)\n// \tg.Dump(\"new:\", new)\n// \treturn d.Core.DoQuery(\n// \t\tctx,\n// \t\tlink,\n// \t\tnew,\n// \t\targs,\n// \t)\n// }\n"
  },
  {
    "path": "contrib/drivers/dm/dm_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Open creates and returns an underlying sql.DB object for pgsql.\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar (\n\t\tsource               string\n\t\tunderlyingDriverName = \"dm\"\n\t)\n\tif config.Name == \"\" {\n\t\treturn nil, fmt.Errorf(\n\t\t\t`dm.Open failed for driver \"%s\" without DB Name`, underlyingDriverName,\n\t\t)\n\t}\n\t// Data Source Name of DM8:\n\t// dm://userName:password@ip:port/dbname\n\t// dm://userName:password@DW/dbname?DW=(192.168.1.1:5236,192.168.1.2:5236)\n\tvar domain string\n\tif config.Port != \"\" {\n\t\tdomain = fmt.Sprintf(\"%s:%s\", config.Host, config.Port)\n\t} else {\n\t\tdomain = config.Host\n\t}\n\tsource = fmt.Sprintf(\n\t\t\"dm://%s:%s@%s/%s?charset=%s&schema=%s\",\n\t\tconfig.User, config.Pass, domain, config.Name, config.Charset, config.Name,\n\t)\n\t// Demo of timezone setting:\n\t// &loc=Asia/Shanghai\n\tif config.Timezone != \"\" {\n\t\tif strings.Contains(config.Timezone, \"/\") {\n\t\t\tconfig.Timezone = url.QueryEscape(config.Timezone)\n\t\t}\n\t\tsource = fmt.Sprintf(\"%s&loc%s\", source, config.Timezone)\n\t}\n\tif config.Extra != \"\" {\n\t\tsource = fmt.Sprintf(\"%s&%s\", source, config.Extra)\n\t}\n\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`dm.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// escapeSingleQuote escapes single quotes in the string to prevent SQL injection.\n// In SQL, single quotes are escaped by doubling them (two single quotes).\nfunc escapeSingleQuote(s string) string {\n\treturn strings.ReplaceAll(s, \"'\", \"''\")\n}\n\nconst (\n\ttableFieldsSqlTmp         = `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_LENGTH, c.DATA_DEFAULT, c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN ALL_COL_COMMENTS cc ON c.COLUMN_NAME = cc.COLUMN_NAME AND c.TABLE_NAME = cc.TABLE_NAME AND c.OWNER = cc.OWNER WHERE c.TABLE_NAME = '%s' AND c.OWNER = '%s'`\n\ttableFieldsPkSqlSchemaTmp = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P'`\n\ttableFieldsPkSqlDBATmp    = `SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM DBA_CONSTRAINTS CONS JOIN DBA_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.OWNER = '%s' AND CONS.CONSTRAINT_TYPE = 'P'`\n)\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\nfunc (d *Driver) TableFields(\n\tctx context.Context, table string, schema ...string,\n) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult   gdb.Result\n\t\tpkResult gdb.Result\n\t\tlink     gdb.Link\n\t\t// When no schema is specified, the configuration item is returned by default\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\t// When usedSchema is empty, return the default link\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\t// The link has been distinguished and no longer needs to judge the owner\n\tresult, err = d.DoSelect(\n\t\tctx, link,\n\t\tfmt.Sprintf(\n\t\t\ttableFieldsSqlTmp,\n\t\t\tescapeSingleQuote(strings.ToUpper(table)),\n\t\t\tescapeSingleQuote(strings.ToUpper(d.GetSchema())),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Query the primary key field\n\tpkResult, err = d.DoSelect(\n\t\tctx, link,\n\t\tfmt.Sprintf(tableFieldsPkSqlSchemaTmp, escapeSingleQuote(strings.ToUpper(table))),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif pkResult.IsEmpty() {\n\t\tpkResult, err = d.DoSelect(\n\t\t\tctx, link,\n\t\t\tfmt.Sprintf(tableFieldsPkSqlDBATmp, escapeSingleQuote(strings.ToUpper(table)), escapeSingleQuote(strings.ToUpper(d.GetSchema()))),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tpkFields := gmap.NewStrStrMap()\n\tfor _, pk := range pkResult {\n\t\tpkFields.Set(pk[\"PRIMARY_KEY_COLUMN\"].String(), \"PRI\")\n\t}\n\tfor i, m := range result {\n\t\t// m[NULLABLE] returns \"N\" \"Y\"\n\t\t// \"N\" means not null\n\t\t// \"Y\" means could be null\n\t\tvar nullable bool\n\t\tif m[\"NULLABLE\"].String() != \"N\" {\n\t\t\tnullable = true\n\t\t}\n\n\t\t// Build field type with length/precision\n\t\t// For NUMBER(p,s): use DATA_PRECISION and DATA_SCALE\n\t\t// For VARCHAR2/CHAR: use DATA_LENGTH\n\t\tvar (\n\t\t\tfieldType  string\n\t\t\tdataType   = m[\"DATA_TYPE\"].String()\n\t\t\tdataLength = m[\"DATA_LENGTH\"].Int()\n\t\t)\n\t\tif dataLength > 0 {\n\t\t\tfieldType = fmt.Sprintf(\"%s(%d)\", dataType, dataLength)\n\t\t} else {\n\t\t\tfieldType = dataType\n\t\t}\n\t\tfields[m[\"COLUMN_NAME\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"COLUMN_NAME\"].String(),\n\t\t\tType:    fieldType,\n\t\t\tNull:    nullable,\n\t\t\tDefault: m[\"DATA_DEFAULT\"].Val(),\n\t\t\tKey:     pkFields.Get(m[\"COLUMN_NAME\"].String()),\n\t\t\t// Extra:   m[\"Extra\"].String(),\n\t\t\tComment: m[\"COMMENTS\"].String(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = `SELECT * FROM ALL_TABLES`\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\t// When schema is empty, return the default link\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// The link has been distinguished and no longer needs to judge the owner\n\tresult, err = d.DoSelect(ctx, link, tablesSqlTmp)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tif v, ok := m[\"IOT_NAME\"]; ok {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_basic_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := dblink.PingMaster()\n\t\terr2 := dblink.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc TestTables(t *testing.T) {\n\ttables := createInitTables(2)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif strings.ToUpper(tables[i]) == strings.ToUpper(result[j]) {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\n\t\tresult, err = dblink.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif strings.ToUpper(tables[i]) == strings.ToUpper(result[j]) {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\t})\n}\n\n// The test scenario index of this test case (exact matching field) is a keyword in the Dameng database and cannot exist as a field name.\n// If the data structure previously migrated from mysql has an index (completely matching field), it will also be allowed.\n// However, when processing the index (completely matching field), the adapter will automatically add security character\n// In principle, such problems will not occur if you directly use Dameng database initialization instead of migrating the data structure from mysql.\n// If so, the adapter has also taken care of it.\nfunc TestTablesFalse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"A_tables\", \"A_tables2\"}\n\t\tfor _, v := range tables {\n\t\t\t_, err := createTableFalse(v)\n\t\t\tgtest.Assert(err, fmt.Errorf(\"createTableFalse\"))\n\t\t\t// createTable(v)\n\t\t}\n\t})\n}\n\nfunc TestTableFields(t *testing.T) {\n\ttables := \"A_tables\"\n\tcreateInitTable(tables)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar expect = map[string][]any{\n\t\t\t\"ID\":           {\"BIGINT(8)\", false},\n\t\t\t\"ACCOUNT_NAME\": {\"VARCHAR(128)\", false},\n\t\t\t\"PWD_RESET\":    {\"TINYINT(1)\", false},\n\t\t\t\"ATTR_INDEX\":   {\"INT(4)\", true},\n\t\t\t\"DELETED\":      {\"INT(4)\", false},\n\t\t\t\"CREATED_TIME\": {\"TIMESTAMP(8)\", false},\n\t\t}\n\n\t\tres, err := db.TableFields(ctx, tables)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.Assert(res[k].Type, v[0])\n\t\t\tgtest.Assert(res[k].Null, v[1])\n\t\t}\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.TableFields(ctx, \"t_user t_user2\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc TestTableFields_WithWrongPassword(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// dbErr is configured with wrong password, so it should return an error\n\t\t_, err := dbErr.TableFields(ctx, \"Fields\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\ttableName := \"A_tables\"\n\tcreateInitTable(tableName)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// createTable(tableName)\n\t\t_, err := db.Query(ctx, fmt.Sprintf(\"SELECT * from %s\", tableName))\n\t\tt.AssertNil(err)\n\n\t\tresTwo := make([]User, 0)\n\t\terr = db.Model(tableName).Scan(&resTwo)\n\t\tt.AssertNil(err)\n\n\t\tresThree := make([]User, 0)\n\t\tmodel := db.Model(tableName)\n\t\tmodel.Where(\"id\", g.Slice{1, 2, 3, 4})\n\t\t// model.Where(\"account_name like ?\", \"%\"+\"list\"+\"%\")\n\t\tmodel.Where(\"deleted\", 0).Order(\"pwd_reset desc\")\n\t\t_, err = model.Count()\n\t\tt.AssertNil(err)\n\t\terr = model.Page(2, 2).Scan(&resThree)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tcreateInitTable(\"A_tables\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ? from dual\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Exec(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeNow := time.Now()\n\t\t// normal map\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":           1000,\n\t\t\t\"ACCOUNT_NAME\": \"map1\",\n\t\t\t\"CREATED_TIME\": timeNow,\n\t\t\t\"UPDATED_TIME\": timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":           \"2000\",\n\t\t\t\"ACCOUNT_NAME\": \"map2\",\n\t\t\t\"CREATED_TIME\": timeNow,\n\t\t\t\"UPDATED_TIME\": timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":           3000,\n\t\t\t\"ACCOUNT_NAME\": \"map3\",\n\t\t\t\"CREATED_TIME\": timeNow,\n\t\t\t\"UPDATED_TIME\": timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tID:          4000,\n\t\t\tAccountName: \"struct_4\",\n\t\t\tCreatedTime: timeNow,\n\t\t\tUpdatedTime: timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tones, err := db.Model(table).Where(\"ID\", 4000).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(ones[0][\"ID\"].Int(), 4000)\n\t\tt.Assert(ones[0][\"ACCOUNT_NAME\"].String(), \"struct_4\")\n\t\t// TODO Question2\n\t\t// this is DM bug.\n\t\t// t.Assert(one[\"CREATED_TIME\"].GTime().String(), timeStr)\n\n\t\t// *struct\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tID:          5000,\n\t\t\tAccountName: \"struct_5\",\n\t\t\tCreatedTime: timeNow,\n\t\t\tUpdatedTime: timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"ID\", 5000).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 5000)\n\t\tt.Assert(one[\"ACCOUNT_NAME\"].String(), \"struct_5\")\n\n\t\t// batch with Insert\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"ID\":           6000,\n\t\t\t\t\"ACCOUNT_NAME\": \"t6000\",\n\t\t\t\t\"CREATED_TIME\": timeNow,\n\t\t\t\t\"UPDATED_TIME\": timeNow,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"ID\":           6001,\n\t\t\t\t\"ACCOUNT_NAME\": \"t6001\",\n\t\t\t\t\"CREATED_TIME\": timeNow,\n\t\t\t\t\"UPDATED_TIME\": timeNow,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"ID\", 6000).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 6000)\n\t\tt.Assert(one[\"ACCOUNT_NAME\"].String(), \"t6000\")\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"ID\":           400,\n\t\t\t\t\"ACCOUNT_NAME\": \"list_400\",\n\t\t\t\t\"CREATE_TIME\":  gtime.Now(),\n\t\t\t\t\"UPDATED_TIME\": gtime.Now(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"ID\":           401,\n\t\t\t\t\"ACCOUNT_NAME\": \"list_401\",\n\t\t\t\t\"CREATE_TIME\":  gtime.Now(),\n\t\t\t\t\"UPDATED_TIME\": gtime.Now(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"ID\":           500,\n\t\t\t\t\"ACCOUNT_NAME\": \"500_batch_500\",\n\t\t\t\t\"CREATE_TIME\":  gtime.Now(),\n\t\t\t\t\"UPDATED_TIME\": gtime.Now(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"ID\":           501,\n\t\t\t\t\"ACCOUNT_NAME\": \"501_batch_501\",\n\t\t\t\t\"CREATE_TIME\":  gtime.Now(),\n\t\t\t\t\"UPDATED_TIME\": gtime.Now(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":           600,\n\t\t\t\"ACCOUNT_NAME\": \"600_batch_600\",\n\t\t\t\"CREATE_TIME\":  gtime.Now(),\n\t\t\t\"UPDATED_TIME\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := &User{\n\t\t\tID:          700,\n\t\t\tAccountName: \"BatchInsert_Struct_700\",\n\t\t\tCreatedTime: time.Now(),\n\t\t\tUpdatedTime: time.Now(),\n\t\t}\n\t\tresult, err := db.Model(table).Insert(user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"pwd_reset=7\", \"id=7\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"ID\", 7).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 7)\n\t\tt.Assert(one[\"ACCOUNT_NAME\"].String(), \"name_7\")\n\t\tt.Assert(one[\"PWD_RESET\"].String(), \"7\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE account_name=?\", table), \"name_4\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"ACCOUNT_NAME\"].String(), \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE account_name=?\", table), \"name_2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 10)\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"name_2\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 4)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].ID, 5)\n\t\tt.Assert(users[1].ID, 6)\n\t\tt.Assert(users[2].ID, 7)\n\t\tt.Assert(users[0].AccountName, \"name_5\")\n\t\tt.Assert(users[1].AccountName, \"name_6\")\n\t\tt.Assert(users[2].AccountName, \"name_7\")\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id<?\", table), 4)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].ID, 1)\n\t\tt.Assert(users[1].ID, 2)\n\t\tt.Assert(users[2].ID, 3)\n\t\tt.Assert(users[0].AccountName, \"name_1\")\n\t\tt.Assert(users[1].AccountName, \"name_2\")\n\t\tt.Assert(users[2].AccountName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"id=32\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 33).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_feature_soft_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete1(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"CREATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"ID\"].Int(), 1)\n\t\tt.AssertGE(one5[\"DELETE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete2(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(0) DEFAULT NULL,\n  update_at TIMESTAMP(0) DEFAULT NULL,\n  delete_at TIMESTAMP(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"CREATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"ID\"].Int(), 1)\n\t\tt.AssertGE(one5[\"DELETE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Map(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         INT NOT NULL,\n  name       VARCHAR(45) DEFAULT NULL,\n  created_at TIMESTAMP(6) DEFAULT NULL,\n  updated_at TIMESTAMP(6) DEFAULT NULL,\n  deleted_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETED_AT\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"CREATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETED_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"UPDATED_AT\"].GTime().Timestamp(), oneInsert[\"UPDATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETED_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETED_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATED_AT\"].GTime().Timestamp(), oneInsert[\"UPDATED_AT\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"ID\"].Int(), 1)\n\t\tt.AssertGE(one5[\"DELETED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         INT NOT NULL,\n  name       VARCHAR(45) DEFAULT NULL,\n  created_at TIMESTAMP(6) DEFAULT NULL,\n  updated_at TIMESTAMP(6) DEFAULT NULL,\n  deleted_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId        int\n\t\tName      string\n\t\tCreatedAT *gtime.Time\n\t\tUpdatedAT *gtime.Time\n\t\tDeletedAT *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETED_AT\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"CREATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETED_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"UPDATED_AT\"].GTime().Timestamp(), oneInsert[\"UPDATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := User{\n\t\t\tName: \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).OmitEmpty().WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETED_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"UPDATED_AT\"].GTime().Timestamp(), gtime.Timestamp()-4)\n\n\t\t// Replace\n\t\tdataReplace := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETED_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATED_AT\"].GTime().Timestamp(), oneInsert[\"CREATED_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATED_AT\"].GTime().Timestamp(), oneInsert[\"UPDATED_AT\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"ID\"].Int(), 1)\n\t\tt.AssertGE(one5[\"DELETED_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftUpdateTime(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  num       INT DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NUM\"].Int(), 10)\n\n\t\t// Update.\n\t\tr, err = db.Model(table).Data(\"num=num+1\").Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_SoftUpdateTime_WithDO(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         INT NOT NULL,\n  num        INT DEFAULT NULL,\n  created_at TIMESTAMP(6) DEFAULT NULL,\n  updated_at TIMESTAMP(6) DEFAULT NULL,\n  deleted_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInserted, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInserted[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInserted[\"NUM\"].Int(), 10)\n\n\t\t// Update.\n\t\ttime.Sleep(2 * time.Second)\n\t\ttype User struct {\n\t\t\tg.Meta    `orm:\"do:true\"`\n\t\t\tId        any\n\t\t\tNum       any\n\t\t\tCreatedAt any\n\t\t\tUpdatedAt any\n\t\t\tDeletedAt any\n\t\t}\n\t\tr, err = db.Model(table).Data(User{\n\t\t\tNum: 100,\n\t\t}).Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdated, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdated[\"NUM\"].Int(), 100)\n\t\tt.Assert(oneUpdated[\"CREATED_AT\"].String(), oneInserted[\"CREATED_AT\"].String())\n\t\tt.AssertNE(oneUpdated[\"UPDATED_AT\"].String(), oneInserted[\"UPDATED_AT\"].String())\n\t})\n}\n\nfunc Test_SoftDelete(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"CREATE_AT\"].String(), \"\")\n\t\tt.AssertNE(one[\"UPDATE_AT\"].String(), \"\")\n\t\tt.Assert(one[\"DELETE_AT\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(10).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"CREATE_AT\"].String(), \"\")\n\t\tt.AssertNE(one[\"UPDATE_AT\"].String(), \"\")\n\t\tt.Assert(one[\"DELETE_AT\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", ids).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tall, err := db.Model(table).Unscoped().Where(\"id\", ids).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.AssertNE(all[0][\"CREATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"UPDATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"CREATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"UPDATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"CREATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"UPDATE_AT\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"DELETE_AT\"].String(), \"\")\n\t})\n}\n\nfunc Test_SoftDelete_Join(t *testing.T) {\n\ttable1 := \"time_test_table1\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table1)\n\n\ttable2 := \"time_test_table2\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id       INT NOT NULL,\n  name     VARCHAR(45) DEFAULT NULL,\n  createat TIMESTAMP(6) DEFAULT NULL,\n  updateat TIMESTAMP(6) DEFAULT NULL,\n  deleteat TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tdataInsert1 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table1).Data(dataInsert1).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tdataInsert2 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_2\",\n\t\t}\n\t\tr, err = db.Model(table2).Data(dataInsert2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"], \"name_1\")\n\n\t\t// Soft deleting.\n\t\tr, err = db.Model(table1).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\tone, err = db.Model(table2, \"t2\").LeftJoin(table1, \"t1\", \"t2.id=t1.id\").Fields(\"t2.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\t})\n}\n\nfunc Test_SoftDelete_WhereAndOr(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\t// Add datas.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", 1).WhereOr(\"id\", 3).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_CreateUpdateTime_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(6) DEFAULT NULL,\n  update_at TIMESTAMP(6) DEFAULT NULL,\n  delete_at TIMESTAMP(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\ttype Entity struct {\n\t\tId       uint64      `orm:\"id,primary\" json:\"id\"`\n\t\tName     string      `orm:\"name\"       json:\"name\"`\n\t\tCreateAt *gtime.Time `orm:\"create_at\"  json:\"create_at\"`\n\t\tUpdateAt *gtime.Time `orm:\"update_at\"  json:\"update_at\"`\n\t\tDeleteAt *gtime.Time `orm:\"delete_at\"  json:\"delete_at\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"CREATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_10\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1000\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"UPDATE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_100\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"ID\"].Int(), 1)\n\t\tt.AssertGE(one5[\"DELETE_AT\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_UnixTimestamp(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at INT DEFAULT NULL,\n  update_at INT DEFAULT NULL,\n  delete_at INT DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t\tt.Assert(len(one[\"CREATE_AT\"].String()), 10)\n\t\tt.Assert(len(one[\"UPDATE_AT\"].String()), 10)\n\t})\n\n\t// sleep some seconds to make update time greater than create time.\n\ttime.Sleep(2 * time.Second)\n\n\t// update\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// update: map\n\t\tdataInsert := g.Map{\n\t\t\t\"name\": \"name_11\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_11\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t\tt.Assert(len(one[\"CREATE_AT\"].String()), 10)\n\t\tt.Assert(len(one[\"UPDATE_AT\"].String()), 10)\n\n\t\tvar (\n\t\t\tlastCreateTime = one[\"CREATE_AT\"].Int64()\n\t\t\tlastUpdateTime = one[\"UPDATE_AT\"].Int64()\n\t\t)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// update: string\n\t\tr, err = db.Model(table).Data(\"name='name_111'\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_111\")\n\t\tt.Assert(one[\"CREATE_AT\"].Int64(), lastCreateTime)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), lastUpdateTime)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_111\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"DELETE_AT\"].Int64(), 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Bool_Deleted(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\t// do not use BIT(1) but use BIT in dm database as bool type.\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at INT DEFAULT NULL,\n  update_at INT DEFAULT NULL,\n  delete_at BIT DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t\tt.Assert(len(one[\"CREATE_AT\"].String()), 10)\n\t\tt.Assert(len(one[\"UPDATE_AT\"].String()), 10)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampMilli(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at BIGINT DEFAULT NULL,\n  update_at BIGINT DEFAULT NULL,\n  delete_at BIT DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampMilli,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"CREATE_AT\"].String()), 13)\n\t\tt.Assert(len(one[\"UPDATE_AT\"].String()), 13)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampNano(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at BIGINT DEFAULT NULL,\n  update_at BIGINT DEFAULT NULL,\n  delete_at BIT DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampNano,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"CREATE_AT\"].String()), 19)\n\t\tt.Assert(len(one[\"UPDATE_AT\"].String()), 19)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NAME\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"CREATE_AT\"].Int64(), 0)\n\t\tt.AssertGT(one[\"UPDATE_AT\"].Int64(), 0)\n\t\tt.Assert(one[\"DELETE_AT\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Specified(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        INT NOT NULL,\n  name      VARCHAR(45) DEFAULT NULL,\n  create_at TIMESTAMP(0) DEFAULT NULL,\n  update_at TIMESTAMP(0) DEFAULT NULL,\n  delete_at TIMESTAMP(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_1\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"ID\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"NAME\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"CREATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneInsert[\"UPDATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_10\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:15:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"ID\"].Int(), 1)\n\t\tt.Assert(oneSave[\"NAME\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneSave[\"CREATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneSave[\"UPDATE_AT\"].String(), \"2024-05-30 20:15:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\":      \"name_1000\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:30:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"ID\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"NAME\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"DELETE_AT\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"CREATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneUpdate[\"UPDATE_AT\"].String(), \"2024-05-30 20:30:00\")\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_100\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"ID\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"NAME\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"DELETE_AT\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"CREATE_AT\"].GTime().Timestamp(), oneInsert[\"CREATE_AT\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"UPDATE_AT\"].GTime().Timestamp(), oneInsert[\"UPDATE_AT\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Insert with delete_at\n\t\tdataInsertDelete := g.Map{\n\t\t\t\"id\":        2,\n\t\t\t\"name\":      \"name_2\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"delete_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataInsertDelete).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Delete Select\n\t\toneDelete, err := db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(oneDelete), 0)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"ID\"].Int(), 2)\n\t\tt.Assert(oneDeleteUnscoped[\"NAME\"].String(), \"name_2\")\n\t\tt.Assert(oneDeleteUnscoped[\"DELETE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"CREATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"UPDATE_AT\"].String(), \"2024-05-30 20:00:00\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_init_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tdb        gdb.DB\n\tdblink    gdb.DB\n\tdbErr     gdb.DB\n\tctx       context.Context\n\tTableSize = 10\n)\n\nconst (\n\tTestDBHost  = \"127.0.0.1\"\n\tTestDBPort  = \"5236\"\n\tTestDBUser  = \"SYSDBA\"\n\tTestDBPass  = \"SYSDBA001\"\n\tTestDBName  = \"SYSDBA\"\n\tTestDBType  = \"dm\"\n\tTestCharset = \"utf8\"\n)\n\ntype User struct {\n\tID          int64     `orm:\"id\"`\n\tAccountName string    `orm:\"account_name\"`\n\tPwdReset    int64     `orm:\"pwd_reset\"`\n\tAttrIndex   int64     `orm:\"attr_index\"`\n\tEnabled     int64     `orm:\"enabled\"`\n\tDeleted     int64     `orm:\"deleted\"`\n\tCreatedBy   string    `orm:\"created_by\"`\n\tCreatedTime time.Time `orm:\"created_time\"`\n\tUpdatedBy   string    `orm:\"updated_by\"`\n\tUpdatedTime time.Time `orm:\"updated_time\"`\n}\n\nfunc init() {\n\tnode := gdb.ConfigNode{\n\t\tHost:             TestDBHost,\n\t\tPort:             TestDBPort,\n\t\tUser:             TestDBUser,\n\t\tPass:             TestDBPass,\n\t\tName:             TestDBName,\n\t\tType:             TestDBType,\n\t\tRole:             \"master\",\n\t\tCharset:          TestCharset,\n\t\tWeight:           1,\n\t\tMaxIdleConnCount: 10,\n\t\tMaxOpenConnCount: 10,\n\t\t// CreatedAt:        \"created_time\",\n\t\t// UpdatedAt:        \"updated_time\",\n\t}\n\n\tnodeLink := gdb.ConfigNode{\n\t\tType: TestDBType,\n\t\tName: TestDBName,\n\t\tLink: fmt.Sprintf(\n\t\t\t\"dm:%s:%s@tcp(%s:%s)/%s?charset=%s\",\n\t\t\tTestDBUser, TestDBPass, TestDBHost, TestDBPort, TestDBName, TestCharset,\n\t\t),\n\t}\n\n\tnodeErr := gdb.ConfigNode{\n\t\tHost:    TestDBHost,\n\t\tPort:    TestDBPort,\n\t\tUser:    TestDBUser,\n\t\tPass:    \"1234\",\n\t\tName:    TestDBName,\n\t\tType:    TestDBType,\n\t\tRole:    \"master\",\n\t\tCharset: TestCharset,\n\t\tWeight:  1,\n\t}\n\n\tgdb.AddConfigNode(gdb.DefaultGroupName, node)\n\tif r, err := gdb.New(node); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\tgdb.AddConfigNode(\"dblink\", nodeLink)\n\tif r, err := gdb.New(nodeLink); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdblink = r\n\t}\n\n\tgdb.AddConfigNode(\"dbErr\", nodeErr)\n\tif r, err := gdb.New(nodeErr); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdbErr = r\n\t}\n\n\tctx = context.Background()\n\n\t// db.SetDebug(true)\n}\n\nfunc dropTable(table string) {\n\tcount, err := db.GetCount(\n\t\tctx,\n\t\t\"SELECT COUNT(*) FROM all_tables WHERE owner = ? And table_name= ?\", TestDBName, strings.ToUpper(table),\n\t)\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tif count == 0 {\n\t\treturn\n\t}\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE %s\", table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n}\n\nfunc createTable(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(\"random_%d\", gtime.Timestamp())\n\t}\n\n\tdropTable(name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE \"%s\"\n(\n\"ID\" BIGINT NOT NULL,\n\"ACCOUNT_NAME\" VARCHAR(128) DEFAULT '' NOT NULL COMMENT 'Account Name',\n\"PWD_RESET\" TINYINT DEFAULT 0 NOT NULL,\n\"ENABLED\" INT DEFAULT 1 NOT NULL,\n\"DELETED\" INT DEFAULT 0 NOT NULL,\n\"ATTR_INDEX\" INT DEFAULT 0 ,\n\"CREATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"CREATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\n\"UPDATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"UPDATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\nNOT CLUSTER PRIMARY KEY(\"ID\")) STORAGE(ON \"MAIN\", CLUSTERBTR) ;\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc createInitTable(table ...string) (name string) {\n\tname = createTable(table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":           i,\n\t\t\t\"account_name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t\"pwd_reset\":    0,\n\t\t\t\"attr_index\":   i,\n\t\t\t\"created_time\": gtime.Now(),\n\t\t})\n\t}\n\tresult, err := db.Schema(TestDBName).Insert(context.Background(), name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc createTableFalse(table ...string) (name string, err error) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(\"random_%d\", gtime.Timestamp())\n\t}\n\n\tdropTable(name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE \"%s\"\n(\n\"ID\" BIGINT NOT NULL,\n\"ACCOUNT_NAME\" VARCHAR(128) DEFAULT '' NOT NULL,\n\"PWD_RESET\" TINYINT DEFAULT 0 NOT NULL,\n\"ENABLED\" INT DEFAULT 1 NOT NULL,\n\"DELETED\" INT DEFAULT 0 NOT NULL,\n\"INDEX\" INT DEFAULT 0 ,\n\"ATTR_INDEX\" INT DEFAULT 0 ,\n\"CREATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"CREATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\n\"UPDATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"UPDATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\nNOT CLUSTER PRIMARY KEY(\"ID\")) STORAGE(ON \"MAIN\", CLUSTERBTR) ;\n\t`, name)); err != nil {\n\t\t// gtest.Fatal(err)\n\t\treturn name, fmt.Errorf(\"createTableFalse\")\n\t}\n\n\treturn name, nil\n}\n\nfunc createInitTables(len int) []string {\n\ttables := make([]string, 0, len)\n\tfor range len {\n\t\ttables = append(tables, createInitTable())\n\t}\n\treturn tables\n}\n\n// createTableWithIdentity creates a table with IDENTITY column for LastInsertId testing\nfunc createTableWithIdentity(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(\"random_%d\", gtime.Timestamp())\n\t}\n\n\tdropTable(name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE \"%s\"\n(\n\"ID\" BIGINT IDENTITY(1, 1) NOT NULL,\n\"ACCOUNT_NAME\" VARCHAR(128) DEFAULT '' NOT NULL COMMENT 'Account Name',\n\"PWD_RESET\" TINYINT DEFAULT 0 NOT NULL,\n\"ENABLED\" INT DEFAULT 1 NOT NULL,\n\"DELETED\" INT DEFAULT 0 NOT NULL,\n\"ATTR_INDEX\" INT DEFAULT 0 ,\n\"CREATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"CREATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\n\"UPDATED_BY\" VARCHAR(32) DEFAULT '' NOT NULL,\n\"UPDATED_TIME\" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,\nNOT CLUSTER PRIMARY KEY(\"ID\")) STORAGE(ON \"MAIN\", CLUSTERBTR) ;\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_issue_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Issue2594(t *testing.T) {\n\ttable := \"HANDLE_INFO\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issue`, `2594`, `sql.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\ttype HandleValueMysql struct {\n\t\tIndex int64  `orm:\"index\"`\n\t\tType  string `orm:\"type\"`\n\t\tData  []byte `orm:\"data\"`\n\t}\n\ttype HandleInfoMysql struct {\n\t\tId         int                `orm:\"id,primary\" json:\"id\"`\n\t\tSubPrefix  string             `orm:\"sub_prefix\"`\n\t\tPrefix     string             `orm:\"prefix\"`\n\t\tHandleName string             `orm:\"handle_name\"`\n\t\tCreateTime time.Time          `orm:\"create_time\"`\n\t\tUpdateTime time.Time          `orm:\"update_time\"`\n\t\tValue      []HandleValueMysql `orm:\"value\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar h1 = HandleInfoMysql{\n\t\t\tSubPrefix:  \"p_\",\n\t\t\tPrefix:     \"m_\",\n\t\t\tHandleName: \"name\",\n\t\t\tCreateTime: gtime.Now().FormatTo(\"Y-m-d H:i:s\").Time,\n\t\t\tUpdateTime: gtime.Now().FormatTo(\"Y-m-d H:i:s\").Time,\n\t\t\tValue: []HandleValueMysql{\n\t\t\t\t{\n\t\t\t\t\tIndex: 10,\n\t\t\t\t\tType:  \"t1\",\n\t\t\t\t\tData:  []byte(\"abc\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIndex: 20,\n\t\t\t\t\tType:  \"t2\",\n\t\t\t\t\tData:  []byte(\"def\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\t_, err := db.Model(table).OmitEmptyData().Insert(h1)\n\t\tt.AssertNil(err)\n\n\t\tvar h2 HandleInfoMysql\n\t\terr = db.Model(table).Scan(&h2)\n\t\tt.AssertNil(err)\n\n\t\th1.Id = 1\n\t\tt.Assert(h1, h2)\n\t})\n}\n\n// Test_MultilineSQLStatement tests that multi-line SQL statements are properly supported.\n// This test verifies that newlines and tabs in SQL queries are preserved,\n// which is essential for readability and proper SQL statement handling.\nfunc Test_MultilineSQLStatement(t *testing.T) {\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multi-line SELECT statement with newlines and indentation\n\t\tmultilineSql := `\n\t\tSELECT \n\t\t\tid,\n\t\t\taccount_name,\n\t\t\tattr_index\n\t\tFROM A_tables\n\t\tWHERE id = ?\n\t\tAND account_name = ?\n\t\t`\n\t\tresult, err := db.GetAll(ctx, multilineSql, 1, \"name_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[0][\"ACCOUNT_NAME\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multi-line SELECT with tabs\n\t\tmultilineSql := `SELECT\n\t\t\tid,\n\t\t\taccount_name,\n\t\t\tattr_index\n\t\tFROM A_tables\n\t\tWHERE id IN (?, ?)\n\t\tORDER BY id`\n\t\tresult, err := db.GetAll(ctx, multilineSql, 2, 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"].Int(), 2)\n\t\tt.Assert(result[1][\"ID\"].Int(), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test that newlines in values don't cause issues\n\t\tmultilineSql := `\n\t\tSELECT * \n\t\tFROM A_tables \n\t\tWHERE id = ?`\n\t\tresult, err := db.GetAll(ctx, multilineSql, 5)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 5)\n\t\tt.Assert(result[0][\"ACCOUNT_NAME\"].String(), \"name_5\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multi-line INSERT with newlines\n\t\tmultilineSql := `\n\t\tINSERT INTO A_tables\n\t\t(ID, ACCOUNT_NAME, ATTR_INDEX, CREATED_TIME, UPDATED_TIME)\n\t\tVALUES\n\t\t(?, ?, ?, ?, ?)`\n\t\t_, err := db.Exec(ctx, multilineSql, 1001, \"multiline_insert_test\", 100, gtime.Now(), gtime.Now())\n\t\tt.AssertNil(err)\n\n\t\t// Verify the insert worked\n\t\tresult, err := db.GetAll(ctx, \"SELECT * FROM A_tables WHERE ID = ?\", 1001)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ACCOUNT_NAME\"].String(), \"multiline_insert_test\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multi-line UPDATE with newlines\n\t\tmultilineSql := `\n\t\tUPDATE A_tables\n\t\tSET account_name = ?,\n\t\t\tattr_index = ?\n\t\tWHERE id = ?`\n\t\t_, err := db.Exec(ctx, multilineSql, \"updated_multiline\", 999, 1)\n\t\tt.AssertNil(err)\n\n\t\t// Verify the update worked\n\t\tresult, err := db.GetAll(ctx, \"SELECT * FROM A_tables WHERE ID = ?\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ACCOUNT_NAME\"].String(), \"updated_multiline\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_model_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTableWithIdentity()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId          int\n\t\t\tAccountName string\n\t\t\tAttrIndex   int\n\t\t}\n\t\tvar (\n\t\t\tuser   User\n\t\t\tcount  int\n\t\t\tresult sql.Result\n\t\t\terr    error\n\t\t)\n\n\t\t// First insert: let IDENTITY auto-generate ID - use Insert() instead of Save()\n\t\t// because Save() requires a primary key in the data for conflict detection\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"accountName\": \"ac1\",\n\t\t\t\"attrIndex\":   100,\n\t\t}).Insert()\n\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(user.Id, 0) // ID should be auto-generated\n\t\tt.Assert(user.AccountName, \"ac1\")\n\t\tt.Assert(user.AttrIndex, 100)\n\n\t\t// Second save: update the existing record using the generated ID\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          user.Id,\n\t\t\t\"accountName\": \"ac2\",\n\t\t\t\"attrIndex\":   200,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"ac2\")\n\t\tt.Assert(user.AttrIndex, 200)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          user.Id,\n\t\t\t\"accountName\": \"ac2\",\n\t\t\t\"attrIndex\":   2000,\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.AccountName, \"ac2\")\n\t\tt.Assert(user.AttrIndex, 2000)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Insert(t *testing.T) {\n\t// g.Model.insert not lost default not null column\n\ttable := \"A_tables\"\n\tcreateInitTable(table)\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 200\n\t\tdata := User{\n\t\t\tID:          int64(i),\n\t\t\tAccountName: fmt.Sprintf(`A%dtwo`, i),\n\t\t\tPwdReset:    0,\n\t\t\tAttrIndex:   99,\n\t\t\tCreatedTime: time.Now(),\n\t\t\tUpdatedTime: time.Now(),\n\t\t}\n\t\tresult, err := db.Model(table).Insert(&data)\n\t\tgtest.AssertNil(err)\n\t\tn, err := result.RowsAffected()\n\t\tgtest.AssertNil(err)\n\t\tgtest.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 201\n\t\tdata := User{\n\t\t\tID:          int64(i),\n\t\t\tAccountName: fmt.Sprintf(`A%dtwoONE`, i),\n\t\t\tPwdReset:    1,\n\t\t\tCreatedTime: time.Now(),\n\t\t\tAttrIndex:   98,\n\t\t\tUpdatedTime: time.Now(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(&data).Insert()\n\t\tgtest.AssertNil(err)\n\t\tn, err := result.RowsAffected()\n\t\tgtest.AssertNil(err)\n\t\tgtest.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":           1,\n\t\t\t\"account_name\": fmt.Sprintf(`name_%d`, 777),\n\t\t\t\"pwd_reset\":    0,\n\t\t\t\"attr_index\":   777,\n\t\t\t\"created_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ACCOUNT_NAME\"].String(), \"name_1\")\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t// \"id\":           1,\n\t\t\t\"account_name\": fmt.Sprintf(`name_%d`, 777),\n\t\t\t\"pwd_reset\":    0,\n\t\t\t\"attr_index\":   777,\n\t\t\t\"created_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_Model_InsertAndGetId(t *testing.T) {\n\ttable := createTableWithIdentity()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"account_name\": fmt.Sprintf(`name_%d`, 1),\n\t\t\t\"pwd_reset\":    0,\n\t\t\t\"attr_index\":   1,\n\t\t\t\"created_time\": gtime.Now(),\n\t\t}\n\t\tlastId, err := db.Model(table).Data(data).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(lastId, 0)\n\t})\n\n}\n"
  },
  {
    "path": "contrib/drivers/dm/dm_z_unit_pr_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage dm_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// PR #4157 WherePri\nfunc Test_WherePri_PR4157(t *testing.T) {\n\ttableName := \"A_tables\"\n\tcreateInitTable(tableName)\n\tdefer dropTable(tableName)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar resOne *User\n\t\terr := db.Model(tableName).WherePri(1).Scan(&resOne)\n\t\tt.AssertNil(err)\n\t\tt.AssertNQ(resOne, nil)\n\t\tt.AssertEQ(resOne.ID, int64(1))\n\t})\n}\n\n// PR #4157 get table field comments\nfunc Test_TableFields_Comment_PR4157(t *testing.T) {\n\ttableName := \"A_tables\"\n\tschema := \"SYSDBA\"\n\tcreateInitTable(tableName)\n\tdefer dropTable(tableName)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.Model().TableFields(tableName, schema)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(fields[\"ACCOUNT_NAME\"].Comment, \"Account Name\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/dm/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/dm/v2\n\ngo 1.23.0\n\nreplace github.com/gogf/gf/v2 => ../../../\n\nrequire (\n\tgitee.com/chunanyong/dm v1.8.12\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/snappy v0.0.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "contrib/drivers/dm/go.sum",
    "content": "gitee.com/chunanyong/dm v1.8.12 h1:WupbFZL0MRNIIiCPaLDHgFi5jkdkjzjPReuWPaInGwk=\ngitee.com/chunanyong/dm v1.8.12/go.mod h1:EPRJnuPFgbyOFgJ0TRYCTGzhq+ZT4wdyaj/GW/LLcNg=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/dm/testdata/issue/2594/sql.sql",
    "content": "CREATE TABLE HANDLE_INFO (\n    ID INT IDENTITY (1, 1) NOT NULL,\n    SUB_PREFIX VARCHAR(128),\n    PREFIX VARCHAR(256),\n    HANDLE_NAME VARCHAR(1024) NOT NULL,\n    CREATE_TIME TIMESTAMP,\n    UPDATE_TIME TIMESTAMP,\n    VALUE BLOB   ,\n    NOT CLUSTER PRIMARY KEY (ID)\n);"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gaussdb implements gdb.Driver, which supports operations for database GaussDB.\npackage gaussdb\n\nimport (\n\t_ \"gitee.com/opengauss/openGauss-connector-go-pq\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// Driver is the driver for GaussDB database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tinternalPrimaryKeyInCtx gctx.StrKey = \"primary_key\"\n\tdefaultSchema           string      = \"public\"\n\tquoteChar               string      = `\"`\n)\n\nfunc init() {\n\tif err := gdb.Register(`gaussdb`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for PostgreSql.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for postgresql.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\n\tpq \"gitee.com/opengauss/openGauss-connector-go-pq\"\n\t\"github.com/google/uuid\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ConvertValueForField converts value to database acceptable value.\nfunc (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\tif g.IsNil(fieldValue) {\n\t\treturn d.Core.ConvertValueForField(ctx, fieldType, fieldValue)\n\t}\n\n\tvar fieldValueKind = reflect.TypeOf(fieldValue).Kind()\n\n\tif fieldValueKind == reflect.Slice {\n\t\t// For pgsql, json or jsonb require '[]'\n\t\tif !gstr.Contains(fieldType, \"json\") {\n\t\t\tfieldValue = gstr.ReplaceByMap(gconv.String(fieldValue),\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"[\": \"{\",\n\t\t\t\t\t\"]\": \"}\",\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\treturn d.Core.ConvertValueForField(ctx, fieldType, fieldValue)\n}\n\n// CheckLocalTypeForField checks and returns corresponding local golang type for given db type.\n// The parameter `fieldType` is in lower case, like:\n// `int2`, `int4`, `int8`, `_int2`, `_int4`, `_int8`, `_float4`, `_float8`, etc.\n//\n// PostgreSQL type mapping:\n//\n//\t| PostgreSQL Type              | Local Go Type |\n//\t|------------------------------|---------------|\n//\t| int2, int4                   | int           |\n//\t| int8                         | int64         |\n//\t| uuid                         | uuid.UUID     |\n//\t| _int2, _int4                 | []int32       | // Note: pq package does not provide Int16Array; int32 is used for compatibility\n//\t| _int8                        | []int64       |\n//\t| _float4                      | []float32     |\n//\t| _float8                      | []float64     |\n//\t| _bool                        | []bool        |\n//\t| _varchar, _text              | []string      |\n//\t| _char, _bpchar               | []string      |\n//\t| _numeric, _decimal, _money   | []float64     |\n//\t| _bytea                       | [][]byte      |\n//\t| _uuid                        | []uuid.UUID   |\nfunc (d *Driver) CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue any) (gdb.LocalType, error) {\n\tvar typeName string\n\tmatch, _ := gregex.MatchString(`(.+?)\\((.+)\\)`, fieldType)\n\tif len(match) == 3 {\n\t\ttypeName = gstr.Trim(match[1])\n\t} else {\n\t\ttypeName = fieldType\n\t}\n\ttypeName = strings.ToLower(typeName)\n\tswitch typeName {\n\tcase \"int2\", \"int4\":\n\t\treturn gdb.LocalTypeInt, nil\n\n\tcase \"int8\":\n\t\treturn gdb.LocalTypeInt64, nil\n\n\tcase \"uuid\":\n\t\treturn gdb.LocalTypeUUID, nil\n\n\tcase \"_int2\", \"_int4\":\n\t\treturn gdb.LocalTypeInt32Slice, nil\n\n\tcase \"_int8\":\n\t\treturn gdb.LocalTypeInt64Slice, nil\n\n\tcase \"_float4\":\n\t\treturn gdb.LocalTypeFloat32Slice, nil\n\n\tcase \"_float8\":\n\t\treturn gdb.LocalTypeFloat64Slice, nil\n\n\tcase \"_bool\":\n\t\treturn gdb.LocalTypeBoolSlice, nil\n\n\tcase \"_varchar\", \"_text\", \"_char\", \"_bpchar\":\n\t\treturn gdb.LocalTypeStringSlice, nil\n\n\tcase \"_uuid\":\n\t\treturn gdb.LocalTypeUUIDSlice, nil\n\n\tcase \"_numeric\", \"_decimal\", \"_money\":\n\t\treturn gdb.LocalTypeFloat64Slice, nil\n\n\tcase \"_bytea\":\n\t\treturn gdb.LocalTypeBytesSlice, nil\n\n\tdefault:\n\t\treturn d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue)\n\t}\n}\n\n// ConvertValueForLocal converts value to local Golang type of value according field type name from database.\n// The parameter `fieldType` is in lower case, like:\n// `int2`, `int4`, `int8`, `_int2`, `_int4`, `_int8`, `uuid`, `_uuid`, etc.\n//\n// See: https://www.postgresql.org/docs/current/datatype.html\n//\n// PostgreSQL type mapping:\n//\n//\t| PostgreSQL Type | SQL Type                       | pq Type         | Go Type     |\n//\t|-----------------|--------------------------------|-----------------|-------------|\n//\t| int2            | int2, smallint                 | -               | int         |\n//\t| int4            | int4, integer                  | -               | int         |\n//\t| int8            | int8, bigint, bigserial        | -               | int64       |\n//\t| uuid            | uuid                           | -               | uuid.UUID   |\n//\t| _int2           | int2[], smallint[]             | pq.Int32Array   | []int32     |\n//\t| _int4           | int4[], integer[]              | pq.Int32Array   | []int32     |\n//\t| _int8           | int8[], bigint[]               | pq.Int64Array   | []int64     |\n//\t| _float4         | float4[], real[]               | pq.Float32Array | []float32   |\n//\t| _float8         | float8[], double precision[]   | pq.Float64Array | []float64   |\n//\t| _bool           | boolean[], bool[]              | pq.BoolArray    | []bool      |\n//\t| _varchar        | varchar[], character varying[] | pq.StringArray  | []string    |\n//\t| _text           | text[]                         | pq.StringArray  | []string    |\n//\t| _char, _bpchar  | char[], character[]            | pq.StringArray  | []string    |\n//\t| _numeric        | numeric[]                      | pq.Float64Array | []float64   |\n//\t| _decimal        | decimal[]                      | pq.Float64Array | []float64   |\n//\t| _money          | money[]                        | pq.Float64Array | []float64   |\n//\t| _bytea          | bytea[]                        | pq.ByteaArray   | [][]byte    |\n//\t| _uuid           | uuid[]                         | pq.StringArray  | []uuid.UUID |\n//\n// Note: PostgreSQL also supports these array types but they are not yet mapped:\n//   - _date (date[]), _timestamp (timestamp[]), _timestamptz (timestamptz[])\n//   - _jsonb (jsonb[]), _json (json[])\nfunc (d *Driver) ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\ttypeName, _ := gregex.ReplaceString(`\\(.+\\)`, \"\", fieldType)\n\ttypeName = strings.ToLower(typeName)\n\n\t// Basic types are mostly handled by Core layer, only handle array types here\n\tswitch typeName {\n\n\t// []int32\n\tcase \"_int2\", \"_int4\":\n\t\tvar result pq.Int32Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int32(result), nil\n\n\t// []int64\n\tcase \"_int8\":\n\t\tvar result pq.Int64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int64(result), nil\n\n\t// []float32\n\tcase \"_float4\":\n\t\tvar result pq.Float32Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float32(result), nil\n\n\t// []float64\n\tcase \"_float8\":\n\t\tvar result pq.Float64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float64(result), nil\n\n\t// []bool\n\tcase \"_bool\":\n\t\tvar result pq.BoolArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []bool(result), nil\n\n\t// []string\n\tcase \"_varchar\", \"_text\", \"_char\", \"_bpchar\":\n\t\tvar result pq.StringArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []string(result), nil\n\n\t// uuid.UUID\n\tcase \"uuid\":\n\t\tvar uuidStr string\n\t\tswitch v := fieldValue.(type) {\n\t\tcase []byte:\n\t\t\tuuidStr = string(v)\n\t\tcase string:\n\t\t\tuuidStr = v\n\t\tdefault:\n\t\t\tuuidStr = gconv.String(fieldValue)\n\t\t}\n\t\tresult, err := uuid.Parse(uuidStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn result, nil\n\n\t// []uuid.UUID\n\tcase \"_uuid\":\n\t\tvar strArray pq.StringArray\n\t\tif err := strArray.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult := make([]uuid.UUID, len(strArray))\n\t\tfor i, s := range strArray {\n\t\t\tparsed, err := uuid.Parse(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tresult[i] = parsed\n\t\t}\n\t\treturn result, nil\n\n\t// []float64\n\tcase \"_numeric\", \"_decimal\", \"_money\":\n\t\tvar result pq.Float64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float64(result), nil\n\n\t// [][]byte\n\tcase \"_bytea\":\n\t\tvar result pq.ByteaArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn [][]byte(result), nil\n\n\tdefault:\n\t\treturn d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_do_exec.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// DoExec commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\nfunc (d *Driver) DoExec(ctx context.Context, link gdb.Link, sql string, args ...any) (result sql.Result, err error) {\n\tvar (\n\t\tisUseCoreDoExec bool   = false // Check whether the default method needs to be used\n\t\tprimaryKey      string = \"\"\n\t\tpkField         gdb.TableField\n\t)\n\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = tx\n\t\t} else if link, err = d.MasterLink(); err != nil {\n\t\t\t// Or else it creates one from master node.\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it checks and retrieves transaction from context.\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\tlink = tx\n\t\t}\n\t}\n\n\t// Check if it is an insert operation with primary key.\n\tif value := ctx.Value(internalPrimaryKeyInCtx); value != nil {\n\t\tvar ok bool\n\t\tpkField, ok = value.(gdb.TableField)\n\t\tif !ok {\n\t\t\tisUseCoreDoExec = true\n\t\t}\n\t} else {\n\t\tisUseCoreDoExec = true\n\t}\n\n\t// check if it is an insert operation.\n\tif !isUseCoreDoExec && pkField.Name != \"\" && strings.Contains(sql, \"INSERT INTO\") {\n\t\tprimaryKey = pkField.Name\n\t\tsql += fmt.Sprintf(` RETURNING \"%s\"`, primaryKey)\n\t} else {\n\t\t// use default DoExec\n\t\treturn d.Core.DoExec(ctx, link, sql, args...)\n\t}\n\n\t// Only the insert operation with primary key can execute the following code\n\n\t// Sql filtering.\n\tsql, args = d.FormatSqlBeforeExecuting(sql, args)\n\tsql, args, err = d.DoFilter(ctx, link, sql, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Link execution.\n\tvar out gdb.DoCommitOutput\n\tout, err = d.DoCommit(ctx, gdb.DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          gdb.SqlTypeQueryContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\taffected := len(out.Records)\n\tif affected > 0 {\n\t\tif !strings.Contains(pkField.Type, \"int\") {\n\t\t\treturn Result{\n\t\t\t\taffected:     int64(affected),\n\t\t\t\tlastInsertId: 0,\n\t\t\t\tlastInsertIdError: gerror.NewCodef(\n\t\t\t\t\tgcode.CodeNotSupported,\n\t\t\t\t\t\"LastInsertId is not supported by primary key type: %s\", pkField.Type),\n\t\t\t}, nil\n\t\t}\n\n\t\tif out.Records[affected-1][primaryKey] != nil {\n\t\t\tlastInsertId := out.Records[affected-1][primaryKey].Int64()\n\t\t\treturn Result{\n\t\t\t\taffected:     int64(affected),\n\t\t\t\tlastInsertId: lastInsertId,\n\t\t\t}, nil\n\t\t}\n\t}\n\n\treturn Result{}, nil\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\tvar index int\n\t// Convert placeholder char '?' to string \"$x\".\n\tnewSql, err = gregex.ReplaceStringFunc(`\\?`, sql, func(s string) string {\n\t\tindex++\n\t\treturn fmt.Sprintf(`$%d`, index)\n\t})\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\t// Handle pgsql jsonb feature support, which contains place-holder char '?'.\n\t// Refer:\n\t// https://github.com/gogf/gf/issues/1537\n\t// https://www.postgresql.org/docs/12/functions-json.html\n\tnewSql, err = gregex.ReplaceStringFuncMatch(\n\t\t`(::jsonb([^\\w\\d]*)\\$\\d)`,\n\t\tnewSql,\n\t\tfunc(match []string) string {\n\t\t\treturn fmt.Sprintf(`::jsonb%s?`, match[2])\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tnewSql, err = gregex.ReplaceString(` LIMIT (\\d+),\\s*(\\d+)`, ` LIMIT $2 OFFSET $1`, newSql)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\t// Handle gaussdb INSERT IGNORE.\n\t// The IGNORE keyword is removed here, converting the statement to a regular INSERT.\n\t// The actual \"ignore\" behavior (i.e., skipping inserts that would violate constraints)\n\t// is implemented at the DoInsert level by checking for existence before inserting.\n\tif gstr.HasPrefix(newSql, gdb.InsertOperationIgnore) {\n\t\t// Remove the IGNORE operation prefix and keep as regular INSERT\n\t\tnewSql = \"INSERT\" + newSql[len(gdb.InsertOperationIgnore):]\n\t}\n\n\tnewArgs = args\n\n\treturn d.Core.DoFilter(ctx, link, newSql, newArgs)\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tswitch option.InsertOption {\n\tcase gdb.InsertOptionSave:\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionReplace:\n\t\t// Treat Replace as Save operation\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\t// GaussDB does not support InsertIgnore with ON CONFLICT, use MERGE instead\n\tcase gdb.InsertOptionIgnore:\n\t\treturn d.doInsertIgnore(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionDefault:\n\t\t// Get table fields to retrieve the primary key TableField object (not just the name)\n\t\t// because DoExec needs the `TableField.Type` to determine if LastInsertId is supported.\n\t\ttableFields, err := d.GetCore().GetDB().TableFields(ctx, table)\n\t\tif err == nil {\n\t\t\tfor _, field := range tableFields {\n\t\t\t\tif strings.EqualFold(field.Key, \"pri\") {\n\t\t\t\t\tpkField := *field\n\t\t\t\t\tctx = context.WithValue(ctx, internalPrimaryKeyInCtx, pkField)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t}\n\treturn d.Core.DoInsert(ctx, link, table, list, option)\n}\n\n// doSave implements upsert operation using MERGE statement for GaussDB.\nfunc (d *Driver) doSave(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, true)\n}\n\n// doInsertIgnore implements INSERT IGNORE operation using MERGE statement for GaussDB.\n// It only inserts records when there's no conflict on primary/unique keys.\nfunc (d *Driver) doInsertIgnore(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, false)\n}\n\n// doUpdateThenInsert handles upsert when conflict keys need to be updated.\n// GaussDB MERGE cannot update columns in ON clause, so we use UPDATE + INSERT instead.\nfunc (d *Driver) doUpdateThenInsert(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tcharL, charR := d.GetChars()\n\tvar (\n\t\tbatchResult   = new(gdb.SqlResult)\n\t\ttotalAffected int64\n\t)\n\n\tfor _, data := range list {\n\t\t// Build UPDATE statement\n\t\tvar (\n\t\t\tupdateFields []string\n\t\t\tupdateValues []any\n\t\t\twhereFields  []string\n\t\t\twhereValues  []any\n\t\t\tvalueIndex   = 1\n\t\t)\n\n\t\t// Process OnDuplicateMap to build UPDATE SET clause\n\t\tfor updateKey, updateValue := range option.OnDuplicateMap {\n\t\t\tkeyWithChar := charL + updateKey + charR\n\t\t\tswitch v := updateValue.(type) {\n\t\t\tcase gdb.Raw, *gdb.Raw:\n\t\t\t\trawStr := fmt.Sprintf(\"%v\", v)\n\t\t\t\trawStr = strings.ReplaceAll(rawStr, \"EXCLUDED.\", \"\")\n\t\t\t\trawStr = strings.ReplaceAll(rawStr, \"EXCLUDED \", \"\")\n\t\t\t\tupdateFields = append(updateFields, fmt.Sprintf(\"%s = %s\", keyWithChar, rawStr))\n\t\t\tcase gdb.Counter, *gdb.Counter:\n\t\t\t\tvar counter gdb.Counter\n\t\t\t\tif c, ok := v.(gdb.Counter); ok {\n\t\t\t\t\tcounter = c\n\t\t\t\t} else if c, ok := v.(*gdb.Counter); ok {\n\t\t\t\t\tcounter = *c\n\t\t\t\t}\n\t\t\t\toperator := \"+\"\n\t\t\t\tcolumnVal := counter.Value\n\t\t\t\tif columnVal < 0 {\n\t\t\t\t\toperator = \"-\"\n\t\t\t\t\tcolumnVal = -columnVal\n\t\t\t\t}\n\t\t\t\tfieldWithChar := charL + counter.Field + charR\n\t\t\t\t// For UPDATE statement, use the data value instead of referencing another column\n\t\t\t\tif dataValue, ok := data[counter.Field]; ok {\n\t\t\t\t\tupdateFields = append(updateFields, fmt.Sprintf(\"%s = $%d %s %v\", keyWithChar, valueIndex, operator, columnVal))\n\t\t\t\t\tupdateValues = append(updateValues, dataValue)\n\t\t\t\t\tvalueIndex++\n\t\t\t\t} else {\n\t\t\t\t\tupdateFields = append(updateFields, fmt.Sprintf(\"%s = %s %s %v\", keyWithChar, fieldWithChar, operator, columnVal))\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\t// Map value to another field name or use the value from data\n\t\t\t\tvalueStr := gconv.String(updateValue)\n\t\t\t\tif dataValue, ok := data[valueStr]; ok {\n\t\t\t\t\tupdateFields = append(updateFields, fmt.Sprintf(\"%s = $%d\", keyWithChar, valueIndex))\n\t\t\t\t\tupdateValues = append(updateValues, dataValue)\n\t\t\t\t\tvalueIndex++\n\t\t\t\t} else {\n\t\t\t\t\tupdateFields = append(updateFields, fmt.Sprintf(\"%s = $%d\", keyWithChar, valueIndex))\n\t\t\t\t\tupdateValues = append(updateValues, updateValue)\n\t\t\t\t\tvalueIndex++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Build WHERE clause using OnConflict keys\n\t\tfor _, conflictKey := range option.OnConflict {\n\t\t\tif dataValue, ok := data[conflictKey]; ok {\n\t\t\t\tkeyWithChar := charL + conflictKey + charR\n\t\t\t\twhereFields = append(whereFields, fmt.Sprintf(\"%s = $%d\", keyWithChar, valueIndex))\n\t\t\t\twhereValues = append(whereValues, dataValue)\n\t\t\t\tvalueIndex++\n\t\t\t}\n\t\t}\n\n\t\tif len(updateFields) > 0 && len(whereFields) > 0 {\n\t\t\tupdateSQL := fmt.Sprintf(\"UPDATE %s SET %s WHERE %s\",\n\t\t\t\ttable,\n\t\t\t\tstrings.Join(updateFields, \", \"),\n\t\t\t\tstrings.Join(whereFields, \" AND \"),\n\t\t\t)\n\t\t\tupdateResult, updateErr := d.DoExec(ctx, link, updateSQL, append(updateValues, whereValues...)...)\n\t\t\tif updateErr != nil {\n\t\t\t\treturn nil, updateErr\n\t\t\t}\n\n\t\t\taffected, _ := updateResult.RowsAffected()\n\t\t\tif affected > 0 {\n\t\t\t\t// UPDATE successful\n\t\t\t\ttotalAffected += affected\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// If UPDATE affected 0 rows, do INSERT\n\t\tvar (\n\t\t\tinsertKeys    []string\n\t\t\tinsertHolders []string\n\t\t\tinsertValues  []any\n\t\t\tinsertIndex   = 1\n\t\t)\n\t\tfor key, value := range data {\n\t\t\tkeyWithChar := charL + key + charR\n\t\t\tinsertKeys = append(insertKeys, keyWithChar)\n\t\t\tinsertHolders = append(insertHolders, fmt.Sprintf(\"$%d\", insertIndex))\n\t\t\tinsertValues = append(insertValues, value)\n\t\t\tinsertIndex++\n\t\t}\n\n\t\tinsertSQL := fmt.Sprintf(\"INSERT INTO %s (%s) VALUES (%s)\",\n\t\t\ttable,\n\t\t\tstrings.Join(insertKeys, \", \"),\n\t\t\tstrings.Join(insertHolders, \", \"),\n\t\t)\n\t\tinsertResult, insertErr := d.DoExec(ctx, link, insertSQL, insertValues...)\n\t\tif insertErr != nil {\n\t\t\t// Ignore duplicate key errors (race condition: another transaction inserted between our UPDATE and INSERT)\n\t\t\tif strings.Contains(insertErr.Error(), \"duplicate key\") ||\n\t\t\t\tstrings.Contains(insertErr.Error(), \"unique constraint\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn nil, insertErr\n\t\t}\n\n\t\taffected, _ := insertResult.RowsAffected()\n\t\ttotalAffected += affected\n\t}\n\n\tbatchResult.Result = &gdb.SqlResult{}\n\tbatchResult.Affected = totalAffected\n\treturn batchResult, nil\n}\n\n// doMergeInsert implements MERGE-based insert operations for GaussDB.\n// When withUpdate is true, it performs upsert (insert or update).\n// When withUpdate is false, it performs insert ignore (insert only when no conflict).\nfunc (d *Driver) doMergeInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, withUpdate bool,\n) (result sql.Result, err error) {\n\t// For batch operations (multiple records), process each record individually\n\tif len(list) > 1 {\n\t\tvar (\n\t\t\tbatchResult   = new(gdb.SqlResult)\n\t\t\ttotalAffected int64\n\t\t)\n\t\tfor _, record := range list {\n\t\t\tsingleResult, singleErr := d.doMergeInsert(ctx, link, table, gdb.List{record}, option, withUpdate)\n\t\t\tif singleErr != nil {\n\t\t\t\treturn nil, singleErr\n\t\t\t}\n\t\t\tif n, _ := singleResult.RowsAffected(); n > 0 {\n\t\t\t\ttotalAffected += n\n\t\t\t}\n\t\t}\n\t\tbatchResult.Result = &gdb.SqlResult{}\n\t\tbatchResult.Affected = totalAffected\n\t\treturn batchResult, nil\n\t}\n\n\t// Check if OnDuplicateMap contains conflict keys\n\t// GaussDB MERGE statement cannot update columns used in ON clause\n\t// If user wants to update conflict keys, we need to use a different approach\n\tif withUpdate && len(option.OnDuplicateMap) > 0 && len(option.OnConflict) > 0 {\n\t\tconflictKeySet := gset.NewStrSetFrom(option.OnConflict)\n\t\thasConflictKeyUpdate := false\n\t\tfor updateKey := range option.OnDuplicateMap {\n\t\t\tif conflictKeySet.Contains(strings.ToLower(updateKey)) ||\n\t\t\t\tconflictKeySet.Contains(strings.ToUpper(updateKey)) ||\n\t\t\t\tconflictKeySet.Contains(updateKey) {\n\t\t\t\thasConflictKeyUpdate = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif hasConflictKeyUpdate {\n\t\t\t// Use UPDATE + INSERT approach when conflict keys need to be updated\n\t\t\treturn d.doUpdateThenInsert(ctx, link, table, list, option)\n\t\t}\n\t}\n\n\t// If OnConflict is not specified, automatically get the primary key of the table\n\tconflictKeys := option.OnConflict\n\tif len(conflictKeys) == 0 {\n\t\tprimaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\terr,\n\t\t\t\t`failed to get primary keys for table`,\n\t\t\t)\n\t\t}\n\t\tfoundPrimaryKey := false\n\t\tfor _, primaryKey := range primaryKeys {\n\t\t\tfor dataKey := range list[0] {\n\t\t\t\tif strings.EqualFold(dataKey, primaryKey) {\n\t\t\t\t\tfoundPrimaryKey = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif foundPrimaryKey {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !foundPrimaryKey {\n\t\t\t// For InsertIgnore without primary key, try normal insert and ignore duplicate errors\n\t\t\t// For Save/Replace, primary key is required\n\t\t\tif !withUpdate {\n\t\t\t\tresult, err := d.Core.DoInsert(ctx, link, table, list, option)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// Ignore duplicate key errors for InsertIgnore\n\t\t\t\t\tif strings.Contains(err.Error(), \"duplicate key\") ||\n\t\t\t\t\t\tstrings.Contains(err.Error(), \"unique constraint\") {\n\t\t\t\t\t\treturn result, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn result, err\n\t\t\t\t}\n\t\t\t\treturn result, nil\n\t\t\t}\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeMissingParameter,\n\t\t\t\t`Replace/Save operation requires conflict detection: `+\n\t\t\t\t\t`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,\n\t\t\t\ttable,\n\t\t\t)\n\t\t}\n\t\t// TODO consider composite primary keys.\n\t\tconflictKeys = primaryKeys\n\t}\n\n\tvar (\n\t\tone            = list[0]\n\t\toneLen         = len(one)\n\t\tcharL, charR   = d.GetChars()\n\t\tconflictKeySet = gset.NewStrSet(false)\n\n\t\t// queryHolders:\tHandle data with Holder that need to be merged\n\t\t// queryValues:\t\tHandle data that need to be merged\n\t\t// insertKeys:\t\tHandle valid keys that need to be inserted\n\t\t// insertValues:\tHandle values that need to be inserted\n\t\t// updateValues:\tHandle values that need to be updated (only when withUpdate=true)\n\t\tqueryHolders = make([]string, oneLen)\n\t\tqueryValues  = make([]any, oneLen)\n\t\tinsertKeys   = make([]string, oneLen)\n\t\tinsertValues = make([]string, oneLen)\n\t\tupdateValues []string\n\t)\n\n\t// conflictKeys slice type conv to set type\n\tfor _, conflictKey := range conflictKeys {\n\t\tconflictKeySet.Add(strings.ToUpper(conflictKey))\n\t}\n\n\tindex := 0\n\tfor key, value := range one {\n\t\tkeyWithChar := charL + key + charR\n\t\tqueryHolders[index] = fmt.Sprintf(\"$%d AS %s\", index+1, keyWithChar)\n\t\tqueryValues[index] = value\n\t\tinsertKeys[index] = keyWithChar\n\t\tinsertValues[index] = fmt.Sprintf(\"T2.%s\", keyWithChar)\n\t\tindex++\n\t}\n\n\t// Build updateValues only when withUpdate is true\n\tif withUpdate {\n\t\t// Check if OnDuplicateStr or OnDuplicateMap is specified for custom update logic\n\t\tif option.OnDuplicateStr != \"\" {\n\t\t\t// Parse OnDuplicateStr (e.g., \"field1,field2\" or \"field1, field2\")\n\t\t\tfields := gstr.SplitAndTrim(option.OnDuplicateStr, \",\")\n\t\t\tfor _, field := range fields {\n\t\t\t\tfieldWithChar := charL + field + charR\n\t\t\t\tupdateValues = append(\n\t\t\t\t\tupdateValues,\n\t\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, fieldWithChar, fieldWithChar),\n\t\t\t\t)\n\t\t\t}\n\t\t} else if len(option.OnDuplicateMap) > 0 {\n\t\t\t// Use OnDuplicateMap for custom update mapping\n\t\t\tfor updateKey, updateValue := range option.OnDuplicateMap {\n\t\t\t\t// Skip conflict keys - they cannot be updated in MERGE\n\t\t\t\tif conflictKeySet.Contains(strings.ToUpper(updateKey)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tkeyWithChar := charL + updateKey + charR\n\t\t\t\tswitch v := updateValue.(type) {\n\t\t\t\tcase gdb.Raw, *gdb.Raw:\n\t\t\t\t\t// Raw SQL expression\n\t\t\t\t\t// Replace EXCLUDED (PostgreSQL ON CONFLICT syntax) with T2 (MERGE syntax)\n\t\t\t\t\trawStr := fmt.Sprintf(\"%v\", v)\n\t\t\t\t\trawStr = strings.ReplaceAll(rawStr, \"EXCLUDED.\", \"T2.\")\n\t\t\t\t\trawStr = strings.ReplaceAll(rawStr, \"EXCLUDED \", \"T2 \")\n\t\t\t\t\tupdateValues = append(\n\t\t\t\t\t\tupdateValues,\n\t\t\t\t\t\tfmt.Sprintf(`T1.%s = %s`, keyWithChar, rawStr),\n\t\t\t\t\t)\n\t\t\t\tcase gdb.Counter, *gdb.Counter:\n\t\t\t\t\t// Counter operation\n\t\t\t\t\tvar counter gdb.Counter\n\t\t\t\t\tif c, ok := v.(gdb.Counter); ok {\n\t\t\t\t\t\tcounter = c\n\t\t\t\t\t} else if c, ok := v.(*gdb.Counter); ok {\n\t\t\t\t\t\tcounter = *c\n\t\t\t\t\t}\n\t\t\t\t\toperator := \"+\"\n\t\t\t\t\tcolumnVal := counter.Value\n\t\t\t\t\tif columnVal < 0 {\n\t\t\t\t\t\toperator = \"-\"\n\t\t\t\t\t\tcolumnVal = -columnVal\n\t\t\t\t\t}\n\t\t\t\t\tfieldWithChar := charL + counter.Field + charR\n\t\t\t\t\tupdateValues = append(\n\t\t\t\t\t\tupdateValues,\n\t\t\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s %s %v`, keyWithChar, fieldWithChar, operator, columnVal),\n\t\t\t\t\t)\n\t\t\t\tdefault:\n\t\t\t\t\t// Map value to another field name\n\t\t\t\t\tvalueStr := gconv.String(updateValue)\n\t\t\t\t\tvalueWithChar := charL + valueStr + charR\n\t\t\t\t\tupdateValues = append(\n\t\t\t\t\t\tupdateValues,\n\t\t\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, valueWithChar),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Default: update all fields except conflict keys and soft created fields\n\t\t\tfor key := range one {\n\t\t\t\tif conflictKeySet.Contains(strings.ToUpper(key)) || d.Core.IsSoftCreatedFieldName(key) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tkeyWithChar := charL + key + charR\n\t\t\t\tupdateValues = append(\n\t\t\t\t\tupdateValues,\n\t\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, keyWithChar),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar (\n\t\tbatchResult = new(gdb.SqlResult)\n\t\tsqlStr      string\n\t)\n\n\t// For InsertIgnore (withUpdate=false), we need to check if record exists first\n\tif !withUpdate {\n\t\t// Build WHERE clause to check if record exists\n\t\tvar whereConditions []string\n\t\tvar checkValues []any\n\t\tcheckIndex := 1\n\t\tfor _, key := range conflictKeys {\n\t\t\tif value, ok := one[key]; ok {\n\t\t\t\tkeyWithChar := charL + key + charR\n\t\t\t\twhereConditions = append(whereConditions, fmt.Sprintf(\"%s = $%d\", keyWithChar, checkIndex))\n\t\t\t\tcheckValues = append(checkValues, value)\n\t\t\t\tcheckIndex++\n\t\t\t}\n\t\t}\n\t\twhereClause := strings.Join(whereConditions, \" AND \")\n\n\t\t// Check if record exists\n\t\tcheckSQL := fmt.Sprintf(\"SELECT 1 FROM %s WHERE %s LIMIT 1\", table, whereClause)\n\t\tcheckResult, checkErr := d.DoQuery(ctx, link, checkSQL, checkValues...)\n\t\tif checkErr != nil {\n\t\t\treturn nil, checkErr\n\t\t}\n\n\t\t// If record exists, return result with 0 affected rows\n\t\tif len(checkResult) > 0 {\n\t\t\tbatchResult.Result = &gdb.SqlResult{}\n\t\t\tbatchResult.Affected = 0\n\t\t\treturn batchResult, nil\n\t\t}\n\n\t\t// Record doesn't exist, proceed with insert\n\t\t// For InsertIgnore, we just do a simple INSERT (no MERGE needed since we checked it doesn't exist)\n\t\tvar insertSQL strings.Builder\n\t\tinsertSQL.WriteString(fmt.Sprintf(\"INSERT INTO %s (\", table))\n\t\tinsertSQL.WriteString(strings.Join(insertKeys, \",\"))\n\t\tinsertSQL.WriteString(\") VALUES (\")\n\t\tfor i := range insertKeys {\n\t\t\tif i > 0 {\n\t\t\t\tinsertSQL.WriteString(\",\")\n\t\t\t}\n\t\t\tinsertSQL.WriteString(fmt.Sprintf(\"$%d\", i+1))\n\t\t}\n\t\tinsertSQL.WriteString(\")\")\n\n\t\tr, err := d.DoExec(ctx, link, insertSQL.String(), queryValues...)\n\t\tif err != nil {\n\t\t\treturn r, err\n\t\t}\n\t\tif n, err := r.RowsAffected(); err != nil {\n\t\t\treturn r, err\n\t\t} else {\n\t\t\tbatchResult.Result = r\n\t\t\tbatchResult.Affected = n\n\t\t}\n\t\treturn batchResult, nil\n\t}\n\n\t// For Save/Replace (withUpdate=true), use MERGE\n\tsqlStr = parseSqlForMerge(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys, charL, charR)\n\tr, err := d.DoExec(ctx, link, sqlStr, queryValues...)\n\tif err != nil {\n\t\treturn r, err\n\t}\n\t// GaussDB's MERGE statement may not return correct RowsAffected\n\t// Workaround: If RowsAffected returns 0 despite a successful MERGE, we manually set it to 1.\n\tif n, err := r.RowsAffected(); err != nil {\n\t\treturn r, err\n\t} else {\n\t\tbatchResult.Result = r\n\t\t// If RowsAffected returns 0, manually set to 1 for MERGE operations\n\t\tif n == 0 {\n\t\t\tbatchResult.Affected = 1\n\t\t} else {\n\t\t\tbatchResult.Affected += n\n\t\t}\n\t}\n\treturn batchResult, nil\n}\n\n// parseSqlForMerge generates MERGE statement for GaussDB.\n// When updateValues is empty, it only inserts (INSERT IGNORE behavior).\n// When updateValues is provided, it performs upsert (INSERT or UPDATE).\n// Examples:\n// - INSERT IGNORE: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...)\n// - UPSERT: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...) WHEN MATCHED THEN UPDATE SET ...\nfunc parseSqlForMerge(table string,\n\tqueryHolders, insertKeys, insertValues, updateValues, duplicateKey []string, charL, charR string,\n) (sqlStr string) {\n\tvar (\n\t\tintoStr   = fmt.Sprintf(\"MERGE INTO %s AS T1\", table)\n\t\tusingStr  = fmt.Sprintf(\"USING (SELECT %s) AS T2\", strings.Join(queryHolders, \",\"))\n\t\tonStr     string\n\t\tinsertStr = fmt.Sprintf(\n\t\t\t\"WHEN NOT MATCHED THEN INSERT (%s) VALUES (%s)\",\n\t\t\tstrings.Join(insertKeys, \",\"),\n\t\t\tstrings.Join(insertValues, \",\"),\n\t\t)\n\t\tupdateStr string\n\t)\n\n\t// Build ON condition\n\tvar onConditions []string\n\tfor _, key := range duplicateKey {\n\t\tkeyWithChar := charL + key + charR\n\t\tonConditions = append(onConditions, fmt.Sprintf(\"T1.%s = T2.%s\", keyWithChar, keyWithChar))\n\t}\n\tonStr = \"ON (\" + strings.Join(onConditions, \" AND \") + \")\"\n\n\t// Build UPDATE clause only when updateValues is provided\n\tif len(updateValues) > 0 {\n\t\tupdateStr = fmt.Sprintf(\" WHEN MATCHED THEN UPDATE SET %s\", strings.Join(updateValues, \",\"))\n\t}\n\n\tsqlStr = fmt.Sprintf(\"%s %s %s %s%s\", intoStr, usingStr, onStr, insertStr, updateStr)\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Open creates and returns an underlying sql.DB object for GaussDB (openGauss).\n// https://gitee.com/opengauss/openGauss-connector-go-pq\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tsource, err := configNodeToSource(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tunderlyingDriverName := \"opengauss\"\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n\nfunc configNodeToSource(config *gdb.ConfigNode) (string, error) {\n\tvar source string\n\tsource = fmt.Sprintf(\n\t\t\"user=%s password='%s' host=%s sslmode=disable\",\n\t\tconfig.User, config.Pass, config.Host,\n\t)\n\tif config.Port != \"\" {\n\t\tsource = fmt.Sprintf(\"%s port=%s\", source, config.Port)\n\t}\n\tif config.Name != \"\" {\n\t\tsource = fmt.Sprintf(\"%s dbname=%s\", source, config.Name)\n\t}\n\tif config.Namespace != \"\" {\n\t\tsource = fmt.Sprintf(\"%s search_path=%s\", source, config.Namespace)\n\t}\n\tif config.Timezone != \"\" {\n\t\tsource = fmt.Sprintf(\"%s timezone=%s\", source, config.Timezone)\n\t}\n\tif config.Extra != \"\" {\n\t\textraMap, err := gstr.Parse(config.Extra)\n\t\tif err != nil {\n\t\t\treturn \"\", gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\terr,\n\t\t\t\t`invalid extra configuration: %s`, config.Extra,\n\t\t\t)\n\t\t}\n\t\tfor k, v := range extraMap {\n\t\t\tsource += fmt.Sprintf(` %s=%s`, k, v)\n\t\t}\n\t}\n\treturn source, nil\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_order.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\n// OrderRandomFunction returns the SQL function for random ordering.\nfunc (d *Driver) OrderRandomFunction() string {\n\treturn \"RANDOM()\"\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport \"database/sql\"\n\ntype Result struct {\n\tsql.Result\n\taffected          int64\n\tlastInsertId      int64\n\tlastInsertIdError error\n}\n\nfunc (pgr Result) RowsAffected() (int64, error) {\n\treturn pgr.affected, nil\n}\n\nfunc (pgr Result) LastInsertId() (int64, error) {\n\treturn pgr.lastInsertId, pgr.lastInsertIdError\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nvar (\n\ttableFieldsSqlTmp = `\nSELECT\n    a.attname                                                                            AS field,\n    t.typname                                                                            AS type,\n    a.attnotnull                                                                         AS null,\n    (CASE WHEN d.contype = 'p' THEN 'pri' WHEN d.contype = 'u' THEN 'uni' ELSE '' END)   AS key,\n    ic.column_default                                                                    AS default_value,\n    b.description                                                                        AS comment,\n    COALESCE(character_maximum_length, numeric_precision, -1)                            AS length,\n    numeric_scale                                                                        AS scale\nFROM pg_attribute a\n    LEFT JOIN pg_class c                 ON a.attrelid = c.oid\n    LEFT JOIN pg_constraint d            ON d.conrelid = c.oid AND a.attnum = d.conkey[1]\n    LEFT JOIN pg_description b           ON a.attrelid = b.objoid AND a.attnum = b.objsubid\n    LEFT JOIN pg_type t                  ON a.atttypid = t.oid\n    LEFT JOIN information_schema.columns ic ON ic.column_name = a.attname AND ic.table_name = c.relname\nWHERE c.oid = '%s'::regclass\n    AND a.attisdropped IS FALSE\n    AND a.attnum > 0\nORDER BY a.attnum`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\nfunc (d *Driver) TableFields(\n\tctx context.Context, table string, schema ...string,\n) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult       gdb.Result\n\t\tlink         gdb.Link\n\t\tstructureSql = fmt.Sprintf(tableFieldsSqlTmp, table)\n\t)\n\t// Schema parameter is not used for SlaveLink as it would attempt to switch database\n\t// In GaussDB/PostgreSQL, schema is handled via search_path or table qualification\n\tif link, err = d.SlaveLink(); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, structureSql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tvar (\n\t\tindex         = 0\n\t\tname          string\n\t\tok            bool\n\t\texistingField *gdb.TableField\n\t)\n\tfor _, m := range result {\n\t\tname = m[\"field\"].String()\n\t\t// Merge duplicated fields, especially for key constraints.\n\t\t// Priority: pri > uni > others\n\t\tif existingField, ok = fields[name]; ok {\n\t\t\tcurrentKey := m[\"key\"].String()\n\t\t\t// Merge key information with priority: pri > uni\n\t\t\tif currentKey == \"pri\" || (currentKey == \"uni\" && existingField.Key != \"pri\") {\n\t\t\t\texistingField.Key = currentKey\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tvar (\n\t\t\tfieldType  string\n\t\t\tdataType   = m[\"type\"].String()\n\t\t\tdataLength = m[\"length\"].Int()\n\t\t)\n\t\tif dataLength > 0 {\n\t\t\tfieldType = fmt.Sprintf(\"%s(%d)\", dataType, dataLength)\n\t\t} else {\n\t\t\tfieldType = dataType\n\t\t}\n\n\t\tfields[name] = &gdb.TableField{\n\t\t\tIndex:   index,\n\t\t\tName:    name,\n\t\t\tType:    fieldType,\n\t\t\tNull:    !m[\"null\"].Bool(),\n\t\t\tKey:     m[\"key\"].String(),\n\t\t\tDefault: m[\"default_value\"].Val(),\n\t\t\tComment: m[\"comment\"].String(),\n\t\t}\n\t\tindex++\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttablesSqlTmp = `\nSELECT\n\tc.relname\nFROM\n\tpg_class c\nINNER JOIN pg_namespace n ON\n\tc.relnamespace = n.oid\nWHERE\n\tn.nspname = '%s'\n\tAND c.relkind IN ('r', 'p')\n\t%s\nORDER BY\n\tc.relname\n`\n\n\tversionRegex = regexp.MustCompile(`PostgreSQL (\\d+\\.\\d+)`)\n)\n\nfunc init() {\n\tvar err error\n\ttablesSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tablesSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetConfig().Namespace, schema...)\n\t)\n\tif usedSchema == \"\" {\n\t\tusedSchema = defaultSchema\n\t}\n\t// DO NOT use `usedSchema` as parameter for function `SlaveLink`.\n\t// Schema is already handled in usedSchema variable above\n\tlink, err := d.SlaveLink()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tuseRelpartbound := \"\"\n\tif gstr.CompareVersion(d.version(ctx, link), \"10\") >= 0 {\n\t\tuseRelpartbound = \"AND c.relpartbound IS NULL\"\n\t}\n\n\tvar query = fmt.Sprintf(\n\t\ttablesSqlTmp,\n\t\tusedSchema,\n\t\tuseRelpartbound,\n\t)\n\n\tquery, _ = gregex.ReplaceString(`[\\n\\r\\s]+`, \" \", gstr.Trim(query))\n\tresult, err = d.DoSelect(ctx, link, query)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n\n// version checks and returns the database version.\nfunc (d *Driver) version(ctx context.Context, link gdb.Link) string {\n\tresult, err := d.DoSelect(ctx, link, \"SELECT version();\")\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif len(result) > 0 {\n\t\tif v, ok := result[0][\"version\"]; ok {\n\t\t\tmatches := versionRegex.FindStringSubmatch(v.String())\n\t\t\tif len(matches) >= 2 {\n\t\t\t\treturn matches[1]\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_db_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_DB_Query(t *testing.T) {\n\ttable := createTable(\"name\")\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, fmt.Sprintf(\"select * from %s \", table))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"select * from %s \", table))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tanswer, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t2\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\t// Insert initial record\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, \"t_user\", data)\n\t\tgtest.AssertNil(err)\n\n\t\t// Replace with new data\n\t\tdata2 := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d_new`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d_new`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d_new`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err = db.Replace(ctx, \"t_user\", data2)\n\t\tgtest.AssertNil(err)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM t_user WHERE id=?\"), i)\n\t\tgtest.AssertNil(err)\n\t\tgtest.Assert(one[\"passport\"].String(), fmt.Sprintf(`t%d_new`, i))\n\t\tgtest.Assert(one[\"password\"].String(), fmt.Sprintf(`p%d_new`, i))\n\t\tgtest.Assert(one[\"nickname\"].String(), fmt.Sprintf(`T%d_new`, i))\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetArray(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.GetArray(ctx, fmt.Sprintf(\"SELECT password FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tarrays := make([]string, 0)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarrays = append(arrays, fmt.Sprintf(`pass_%d`, i))\n\t\t}\n\t\tt.Assert(array, arrays)\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"987654321\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"id>3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 7)\n\t})\n}\n\nfunc Test_DB_Tables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"t_user1\", \"pop\", \"haha\"}\n\t\tfor _, v := range tables {\n\t\t\tcreateTable(v)\n\t\t}\n\t\tresult, err := db.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif tables[i] == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\t})\n}\n\nfunc Test_DB_TableFields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tvar expect = map[string][]any{\n\t\t\t// []string: Index Type Null Key Default Comment\n\t\t\t// id is bigserial so the default is a pgsql function\n\t\t\t\"id\":          {0, \"int8(64)\", false, \"pri\", fmt.Sprintf(\"nextval('%s_id_seq'::regclass)\", table), \"\"},\n\t\t\t\"passport\":    {1, \"varchar(45)\", false, \"\", nil, \"\"},\n\t\t\t\"password\":    {2, \"varchar(32)\", false, \"\", nil, \"\"},\n\t\t\t\"nickname\":    {3, \"varchar(45)\", false, \"\", nil, \"\"},\n\t\t\t\"create_time\": {4, \"timestamp\", false, \"\", nil, \"\"},\n\t\t}\n\n\t\tres, err := db.TableFields(ctx, table)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\n\t\t\tgtest.AssertEQ(res[k].Index, v[0])\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[1])\n\t\t\tgtest.AssertEQ(res[k].Null, v[2])\n\t\t\tgtest.AssertEQ(res[k].Key, v[3])\n\t\t\tgtest.AssertEQ(res[k].Default, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\t})\n}\n\nfunc Test_NoFields_Error(t *testing.T) {\n\tcreateSql := `CREATE TABLE IF NOT EXISTS %s (\nid bigint PRIMARY KEY,\nint_col INT);`\n\n\ttype Data struct {\n\t\tId     int64\n\t\tIntCol int64\n\t}\n\t// pgsql converts table names to lowercase\n\t// mark: [c.oid = '%s'::regclass] is not case-sensitive\n\ttableName := \"Error_table\"\n\t_, err := db.Exec(ctx, fmt.Sprintf(createSql, tableName))\n\tgtest.AssertNil(err)\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar data = Data{\n\t\t\tId:     2,\n\t\t\tIntCol: 2,\n\t\t}\n\t\t_, err = db.Model(tableName).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\n\t\t// Insert a piece of test data using lowercase\n\t\t_, err = db.Model(strings.ToLower(tableName)).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Model(tableName).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"int_col\": 9999,\n\t\t}).Update()\n\t\tt.AssertNE(err, nil)\n\n\t})\n\t// The inserted field does not exist in the table\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]any{\n\t\t\t\"id1\":        22,\n\t\t\t\"int_col_22\": 11111,\n\t\t}\n\t\t_, err = db.Model(tableName).Data(data).Insert()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, tableName))\n\n\t\tlowerTableName := strings.ToLower(tableName)\n\t\t_, err = db.Model(lowerTableName).Data(data).Insert()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, lowerTableName))\n\n\t\t_, err = db.Model(lowerTableName).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"int_col-2\": 9999,\n\t\t}).Update()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, lowerTableName))\n\t})\n\n}\n\nfunc Test_DB_TableFields_DuplicateConstraints(t *testing.T) {\n\t// Test for the fix of duplicate field results with multiple constraints\n\t// This test verifies that when a field has multiple constraints (e.g., both primary key and unique),\n\t// the TableFields method correctly merges the results with proper priority (pri > uni > others)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"test_multi_constraint\"\n\t\tcreateSql := fmt.Sprintf(`\n\t\t\tCREATE TABLE %s (\n\t\t\t\tid bigserial NOT NULL PRIMARY KEY,\n\t\t\t\temail varchar(100) NOT NULL UNIQUE,\n\t\t\t\tusername varchar(50) NOT NULL,\n\t\t\t\tstatus int NOT NULL DEFAULT 1\n\t\t\t)`, tableName)\n\n\t\t_, err := db.Exec(ctx, createSql)\n\t\tt.AssertNil(err)\n\t\tdefer dropTable(tableName)\n\n\t\t// Get table fields\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// Verify id field has primary key constraint\n\t\tt.AssertNE(fields[\"id\"], nil)\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\t\tt.Assert(fields[\"id\"].Name, \"id\")\n\t\tt.Assert(fields[\"id\"].Type, \"int8(64)\")\n\n\t\t// Verify email field has unique constraint\n\t\tt.AssertNE(fields[\"email\"], nil)\n\t\tt.Assert(fields[\"email\"].Key, \"uni\")\n\t\tt.Assert(fields[\"email\"].Name, \"email\")\n\t\tt.Assert(fields[\"email\"].Type, \"varchar(100)\")\n\n\t\t// Verify username field has no constraint\n\t\tt.AssertNE(fields[\"username\"], nil)\n\t\tt.Assert(fields[\"username\"].Key, \"\")\n\t\tt.Assert(fields[\"username\"].Name, \"username\")\n\n\t\t// Verify status field has no constraint and has default value\n\t\tt.AssertNE(fields[\"status\"], nil)\n\t\tt.Assert(fields[\"status\"].Key, \"\")\n\t\tt.Assert(fields[\"status\"].Name, \"status\")\n\t\tt.Assert(fields[\"status\"].Default, 1)\n\n\t\t// Verify field count is correct (no duplicates)\n\t\tt.Assert(len(fields), 4)\n\t})\n\n\t// Test table with composite constraints\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"test_composite_constraint\"\n\t\tcreateSql := fmt.Sprintf(`\n\t\t\tCREATE TABLE %s (\n\t\t\t\tuser_id bigint NOT NULL,\n\t\t\t\tproject_id bigint NOT NULL,\n\t\t\t\trole varchar(50) NOT NULL,\n\t\t\t\tPRIMARY KEY (user_id, project_id)\n\t\t\t)`, tableName)\n\n\t\t_, err := db.Exec(ctx, createSql)\n\t\tt.AssertNil(err)\n\t\tdefer dropTable(tableName)\n\n\t\t// Get table fields\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// In PostgreSQL, composite primary keys may appear in query results\n\t\t// The first field in the composite key should be marked as 'pri'\n\t\tt.AssertNE(fields[\"user_id\"], nil)\n\t\tt.Assert(fields[\"user_id\"].Name, \"user_id\")\n\n\t\tt.AssertNE(fields[\"project_id\"], nil)\n\t\tt.Assert(fields[\"project_id\"].Name, \"project_id\")\n\n\t\tt.AssertNE(fields[\"role\"], nil)\n\t\tt.Assert(fields[\"role\"].Name, \"role\")\n\t\tt.Assert(fields[\"role\"].Key, \"\")\n\n\t\t// Verify field count is correct (no duplicates)\n\t\tt.Assert(len(fields), 3)\n\t})\n}\n\nfunc Test_DB_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// Insert test record\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tanswer, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// Ignore Duplicate record\n\t\tresult, err := db.InsertIgnore(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1_duplicate\",\n\t\t\t\"password\":    \"duplicate_password\",\n\t\t\t\"nickname\":    \"Duplicate\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 0)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// Insert Correct Record\n\t\tresult, err = db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t2\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"name_2\")\n\n\t\t// Insert Multiple Records Using g.Map Array\n\t\tdata := g.List{\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"t4\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1_conflict\",\n\t\t\t\t\"password\":    \"conflict_password\",\n\t\t\t\t\"nickname\":    \"conflict_name\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2_conflict\",\n\t\t\t\t\"password\":    \"conflict_password\",\n\t\t\t\t\"nickname\":    \"conflict_name\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}\n\n\t\t// Insert Multiple Records with Ignore\n\t\tresult, err = db.InsertIgnore(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 4)\n\t\t// Should have four records in total (ID 1, 2, 3, 4)\n\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[1][\"passport\"], \"t2\")\n\t\tt.Assert(answer[2][\"passport\"], \"t3\")\n\t\tt.Assert(answer[3][\"passport\"], \"t4\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb, err := gdb.Instance()\n\t\tt.AssertNil(err)\n\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\n\t\tnewDb := db.Ctx(context.Background())\n\t\tt.AssertNE(newDb, nil)\n\t})\n}\n\nfunc Test_Ctx_Query(t *testing.T) {\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Query(ctx, \"select 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Query(ctx, \"select 2\")\n\t})\n}\n\nfunc Test_Ctx_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Model(table).Ctx(ctx).All()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Model(table).All()\n\t})\n}\n\nfunc Test_Ctx_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"tx_trace_123\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.2\")\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Ctx_Timeout(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10)\n\t\tdefer cancel()\n\n\t\t// Wait for the context to expire\n\t\ttime.Sleep(time.Millisecond * 50)\n\n\t\t// Query with expired context should return error\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Hook_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"test\"] = gvar.New(100 + record[\"id\"].Int())\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(\"id > ?\", 6).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 4)\n\t\tt.Assert(all[0][\"id\"].Int(), 7)\n\t\tt.Assert(all[0][\"test\"].Int(), 107)\n\t\tt.Assert(all[1][\"test\"].Int(), 108)\n\t\tt.Assert(all[2][\"test\"].Int(), 109)\n\t\tt.Assert(all[3][\"test\"].Int(), 110)\n\t})\n}\n\nfunc Test_Model_Hook_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\tfor i, item := range in.Data {\n\t\t\t\t\titem[\"passport\"] = fmt.Sprintf(`test_port_%d`, item[\"id\"])\n\t\t\t\t\titem[\"nickname\"] = fmt.Sprintf(`test_name_%d`, item[\"id\"])\n\t\t\t\t\titem[\"password\"] = fmt.Sprintf(`test_pass_%d`, item[\"id\"])\n\t\t\t\t\titem[\"create_time\"] = CreateTime\n\t\t\t\t\tin.Data[i] = item\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `test_port_1`)\n\t\tt.Assert(one[\"nickname\"], `test_name_1`)\n\t})\n}\n\nfunc Test_Model_Hook_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\t\tswitch value := in.Data.(type) {\n\t\t\t\tcase gdb.List:\n\t\t\t\t\tfor i, data := range value {\n\t\t\t\t\t\tdata[\"passport\"] = `port`\n\t\t\t\t\t\tdata[\"nickname\"] = `name`\n\t\t\t\t\t\tvalue[i] = data\n\t\t\t\t\t}\n\t\t\t\t\tin.Data = value\n\n\t\t\t\tcase gdb.Map:\n\t\t\t\t\tvalue[\"passport\"] = `port`\n\t\t\t\t\tvalue[\"nickname\"] = `name`\n\t\t\t\t\tin.Data = value\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Data(g.Map{\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `port`)\n\t\tt.Assert(one[\"nickname\"], `name`)\n\t})\n}\n\nfunc Test_Model_Hook_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\t\treturn db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": `deleted`,\n\t\t\t\t}).Where(in.Condition).Update()\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tfor _, item := range all {\n\t\t\tt.Assert(item[\"nickname\"].String(), `deleted`)\n\t\t}\n\t})\n}\n\nfunc Test_Model_Hook_Select_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Adding extra fields should not affect Count operations\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"extra\"] = gvar.New(\"extra_value\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tcount, err := m.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_Model_Hook_Chain(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Normal chain: two hooks both modify data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"hook1\"] = gvar.New(\"value1\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t}).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"hook2\"] = gvar.New(\"value2\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(\"id\", 1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\t// The last Hook should take effect (Hook replaces previous one)\n\t\tt.Assert(all[0][\"hook2\"].String(), \"value2\")\n\t})\n\n\t// Error chain: hook returns error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\treturn nil, gerror.New(\"hook error\")\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(\"id\", 1).All()\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"hook error\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_model_builder_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Model_Builder(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where And\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n\n\t// Where Or\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where with struct which has a field type of *gtime.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=? AND \"nickname\" IS NULL`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with struct which has a field type of *gjson.Json\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=? AND \"nickname\" IS NULL`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gtime.Time and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=?`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gjson.Json and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=?`)\n\t\tt.Assert(args, []any{1})\n\t})\n}\n\nfunc Test_Safe_Builder(t *testing.T) {\n\t// test whether m.Builder() is chain safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := db.Model().Builder()\n\t\tb.Where(\"id\", 1)\n\t\t_, args := b.Build()\n\t\tt.AssertNil(args)\n\n\t\tb = b.Where(\"id\", 1)\n\t\t_, args = b.Build()\n\t\tt.Assert(args, g.Slice{1})\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_model_do_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// createTableDO creates a table with nullable columns (no NOT NULL constraints)\n// suitable for DO (Data Object) partial insert tests.\nfunc createTableDO(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"do_test\", gtime.TimestampNano())\n\t}\n\tdropTable(name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial NOT NULL,\n\t\t\tpassport varchar(45) DEFAULT '',\n\t\t\tpassword varchar(32) DEFAULT '',\n\t\t\tnickname varchar(45) DEFAULT '',\n\t\t\tcreate_time timestamp DEFAULT NULL,\n\t\t\tPRIMARY KEY (id)\n\t\t);`, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc Test_Model_Insert_Data_DO(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_DO(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 2)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Update_Pointer_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype NN string\n\t\ttype Req struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t\tPassword *string\n\t\t\tNickname *NN\n\t\t}\n\t\ttype UserDo struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tvar (\n\t\t\tnickname = NN(\"nickname_111\")\n\t\t\treq      = Req{\n\t\t\t\tPassword: gconv.PtrString(\"12345678\"),\n\t\t\t\tNickname: &nickname,\n\t\t\t}\n\t\t\tdata = UserDo{\n\t\t\t\tPassport: req.Passport,\n\t\t\t\tPassword: req.Password,\n\t\t\t\tNickname: req.Nickname,\n\t\t\t}\n\t\t)\n\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`password`], `12345678`)\n\t\tt.Assert(one[`nickname`], `nickname_111`)\n\t})\n}\n\nfunc Test_Model_Where_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Insert_Data_ForDao(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_ForDao(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUserForDao{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUserForDao{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 2)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_FieldPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n\t// With omitempty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id,omitempty\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id,omitempty\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_model_join_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_LeftJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_RightJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_InnerJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_LeftJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_RightJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_InnerJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_FieldsPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"id\").\n\t\t\tFieldsPrefix(table2, \"nickname\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_model_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Embedded_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int    `json:\"id\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=100\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"john-test\")\n\t})\n}\n\nfunc Test_Model_Embedded_MapToStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Ids struct {\n\t\t\tId int `json:\"id\"`\n\t\t}\n\t\ttype Base struct {\n\t\t\tIds\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          100,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\n\t\tt.Assert(one.Struct(user), nil)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t\tt.Assert(user.Password, data[\"password\"])\n\t\tt.Assert(user.Nickname, data[\"nickname\"])\n\t\tt.Assert(user.CreateTime, data[\"create_time\"])\n\t})\n}\n\nfunc Test_Struct_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tuser := new(User)\n\t\terr = one.Struct(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Scan(user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Scan(&user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Structs_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\t// All\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]*User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Struct_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=100\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t\tt.AssertNE(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\t\tvar user *User\n\t\tt.Assert(one.Struct(&user), nil)\n\t\tt.Assert(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\nfunc Test_Structs_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []*User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n}\n\ntype MyTime struct {\n\tgtime.Time\n}\n\ntype MyTimeSt struct {\n\tCreateTime MyTime\n}\n\nfunc (st *MyTimeSt) UnmarshalValue(v any) error {\n\tm := gconv.Map(v)\n\tt, err := gtime.StrToTime(gconv.String(m[\"create_time\"]))\n\tif err != nil {\n\t\treturn err\n\t}\n\tst.CreateTime = MyTime{*t}\n\treturn nil\n}\n\nfunc Test_Model_Scan_CustomType_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyTimeSt)\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar stSlice []*MyTimeSt\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(&stSlice)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(stSlice), TableSize)\n\t\tt.Assert(stSlice[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\tt.Assert(stSlice[9].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_Model_Scan_CustomType_String(t *testing.T) {\n\ttype MyString string\n\n\ttype MyStringSt struct {\n\t\tPassport MyString\n\t}\n\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyStringSt)\n\t\terr := db.Model(table).Fields(\"Passport\").WherePri(1).Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.Passport, \"user_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar sts []MyStringSt\n\t\terr := db.Model(table).Fields(\"Passport\").Order(\"id asc\").Scan(&sts)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(sts), TableSize)\n\t\tt.Assert(sts[0].Passport, \"user_1\")\n\t})\n}\n\ntype User struct {\n\tId         int\n\tPassport   string\n\tPassword   string\n\tNickname   string\n\tCreateTime *gtime.Time\n}\n\nfunc (user *User) UnmarshalValue(value any) error {\n\tif record, ok := value.(gdb.Record); ok {\n\t\t*user = User{\n\t\t\tId:         record[\"id\"].Int(),\n\t\t\tPassport:   record[\"passport\"].String(),\n\t\t\tPassword:   \"\",\n\t\t\tNickname:   record[\"nickname\"].String(),\n\t\t\tCreateTime: record[\"create_time\"].GTime(),\n\t\t}\n\t\treturn nil\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value))\n}\n\nfunc Test_Model_Scan_UnmarshalValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Scan_Map(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Scan_AutoFilteringByStructAttributes(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_model_subquery_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_SubQuery_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).Group(\"id\").Having(\n\t\t\t\"id > ?\",\n\t\t\tdb.Model(table).Fields(\"MAX(id)\").Where(\"id\", g.Slice{1, 3}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery1 := db.Model(table).Where(\"id\", g.Slice{1, 3, 5})\n\t\tsubQuery2 := db.Model(table).Where(\"id\", g.Slice{5, 7, 9})\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).Fields(\"a.id\").Where(\"a.id=b.id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_scanlist_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Table_Relation_One(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL,\n  course varchar(45) NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `orm:\"uid\"`\n\t\tName string `orm:\"name\"`\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int    `orm:\"uid\"`\n\t\tAddress string `orm:\"address\"`\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId     int    `orm:\"id\"`\n\t\tUid    int    `orm:\"uid\"`\n\t\tScore  int    `orm:\"score\"`\n\t\tCourse string `orm:\"course\"`\n\t}\n\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tr, err := tx.Model(tableUser).Data(g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tuid, err := r.LastInsertId()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserDetail).Data(g.Map{\n\t\t\t\t\"uid\":     uid,\n\t\t\t\t\"address\": \"Beijing DongZhiMen #66\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserScores).Data(g.Slice{\n\t\t\t\tg.Map{\"uid\": uid, \"score\": 100, \"course\": \"math\"},\n\t\t\t\tg.Map{\"uid\": uid, \"score\": 99, \"course\": \"physics\"},\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\t// Data check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(tableUser).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"name\"].String(), \"john\")\n\n\t\tr, err = db.Model(tableUserDetail).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"address\"].String(), `Beijing DongZhiMen #66`)\n\n\t\tr, err = db.Model(tableUserScores).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 2)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[1][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"course\"].String(), `math`)\n\t\tt.Assert(r[1][\"course\"].String(), `physics`)\n\t})\n\t// Entity query.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user Entity\n\t\t// SELECT * FROM `user` WHERE `name`='john'\n\t\terr := db.Model(tableUser).Scan(&user.User, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid`=1\n\t\terr = db.Model(tableUserDetail).Scan(&user.UserDetail, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid`=1\n\t\terr = db.Model(tableUserScores).Scan(&user.UserScores, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.User, EntityUser{\n\t\t\tUid:  1,\n\t\t\tName: \"john\",\n\t\t})\n\t\tt.Assert(user.UserDetail, EntityUserDetail{\n\t\t\tUid:     1,\n\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t})\n\t\tt.Assert(user.UserScores, []EntityUserScores{\n\t\t\t{Id: 1, Uid: 1, Course: \"math\", Score: 100},\n\t\t\t{Id: 2, Uid: 1, Course: \"physics\", Score: 99},\n\t\t})\n\t})\n}\n\nfunc Test_Table_Relation_Many(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_ModelScanList(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_EmptyData(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Table_Relation_NoneEqualDataSize(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail and Scores are not inserted.\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct1(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\t*EntityUser\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\t*EntityUser\n\t\t*EntityUserDetail\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tscores []*EntityUserScores\n\t\t)\n\t\t// SELECT * FROM `user_scores`\n\t\terr = db.Model(tableUserScores).Scan(&scores)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUser).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUser\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Assertions.\n\t\tt.Assert(len(scores), 25)\n\t\tt.Assert(scores[0].Id, 1)\n\t\tt.Assert(scores[0].Uid, 1)\n\t\tt.Assert(scores[0].Name, \"name_1\")\n\t\tt.Assert(scores[0].Address, \"address_1\")\n\t\tt.Assert(scores[24].Id, 25)\n\t\tt.Assert(scores[24].Uid, 5)\n\t\tt.Assert(scores[24].Name, \"name_5\")\n\t\tt.Assert(scores[24].Address, \"address_5\")\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct2(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\t*EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_soft_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t// \"github.com/gogf/gf/v2/database/gdb\" // FIXME: Uncomment when boolean soft delete tests are enabled\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete1(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save (GaussDB uses OnConflict instead of REPLACE)\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreateAt/UpdateAt/DeleteAt with timestamp(0).\nfunc Test_SoftTime_CreateUpdateDelete2(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(0) DEFAULT NULL,\n  update_at timestamp(0) DEFAULT NULL,\n  delete_at timestamp(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Map(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  name       varchar(45) DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt with struct.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  name       varchar(45) DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId        int\n\t\tName      string\n\t\tCreatedAT *gtime.Time\n\t\tUpdatedAT *gtime.Time\n\t\tDeletedAT *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := User{\n\t\t\tName: \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).OmitEmpty().WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-4)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftUpdateTime(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  num       integer DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\tr, err = db.Model(table).Data(\"num=num+1\").Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_SoftUpdateTime_WithDO(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  num        integer DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInserted, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInserted[\"id\"].Int(), 1)\n\t\tt.Assert(oneInserted[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\ttime.Sleep(2 * time.Second)\n\t\ttype User struct {\n\t\t\tg.Meta    `orm:\"do:true\"`\n\t\t\tId        any\n\t\t\tNum       any\n\t\t\tCreatedAt any\n\t\t\tUpdatedAt any\n\t\t\tDeletedAt any\n\t\t}\n\t\tr, err = db.Model(table).Data(User{\n\t\t\tNum: 100,\n\t\t}).Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdated, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdated[\"num\"].Int(), 100)\n\t\tt.Assert(oneUpdated[\"created_at\"].String(), oneInserted[\"created_at\"].String())\n\t\tt.AssertNE(oneUpdated[\"updated_at\"].String(), oneInserted[\"updated_at\"].String())\n\t})\n}\n\nfunc Test_SoftDelete(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(10).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", ids).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tall, err := db.Model(table).Unscoped().Where(\"id\", ids).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.AssertNE(all[0][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"delete_at\"].String(), \"\")\n\t})\n}\n\nfunc Test_SoftDelete_Join(t *testing.T) {\n\ttable1 := \"time_test_table1_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table1)\n\n\ttable2 := \"time_test_table2_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  createat  timestamp(6) DEFAULT NULL,\n  updateat  timestamp(6) DEFAULT NULL,\n  deleteat  timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tdataInsert1 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table1).Data(dataInsert1).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tdataInsert2 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_2\",\n\t\t}\n\t\tr, err = db.Model(table2).Data(dataInsert2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"name_1\")\n\n\t\t// Soft deleting.\n\t\tr, err = db.Model(table1).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\tone, err = db.Model(table2, \"t2\").LeftJoin(table1, \"t1\", \"t2.id=t1.id\").Fields(\"t2.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\t})\n}\n\nfunc Test_SoftDelete_WhereAndOr(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\t// Add datas.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", 1).WhereOr(\"id\", 3).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_CreateUpdateTime_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\ttype Entity struct {\n\t\tId       uint64      `orm:\"id,primary\" json:\"id\"`\n\t\tName     string      `orm:\"name\"       json:\"name\"`\n\t\tCreateAt *gtime.Time `orm:\"create_at\"  json:\"create_at\"`\n\t\tUpdateAt *gtime.Time `orm:\"update_at\"  json:\"update_at\"`\n\t\tDeleteAt *gtime.Time `orm:\"delete_at\"  json:\"delete_at\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_10\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1000\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_UnixTimestamp(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at integer DEFAULT NULL,\n  update_at integer DEFAULT NULL,\n  delete_at integer DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// sleep some seconds to make update time greater than create time.\n\ttime.Sleep(2 * time.Second)\n\n\t// update\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// update: map\n\t\tdataInsert := g.Map{\n\t\t\t\"name\": \"name_11\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_11\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\n\t\tvar (\n\t\t\tlastCreateTime = one[\"create_at\"].Int64()\n\t\t\tlastUpdateTime = one[\"update_at\"].Int64()\n\t\t)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// update: string\n\t\tr, err = db.Model(table).Data(\"name='name_111'\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.Assert(one[\"create_at\"].Int64(), lastCreateTime)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), lastUpdateTime)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"delete_at\"].Int64(), 0)\n\t})\n}\n\n// FIXME: GaussDB boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but GaussDB boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports GaussDB boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Bool_Deleted(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at integer DEFAULT NULL,\n//   update_at integer DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \t//db.SetDebug(true)\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t\tt.Assert(len(one[\"create_at\"].String()), 10)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 10)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\n// FIXME: GaussDB boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but GaussDB boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports GaussDB boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampMilli(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at bigint DEFAULT NULL,\n//   update_at bigint DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \tvar softTimeOption = gdb.SoftTimeOption{\n// \t\tSoftTimeType: gdb.SoftTimeTypeTimestampMilli,\n// \t}\n//\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.Assert(len(one[\"create_at\"].String()), 13)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 13)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\n// FIXME: GaussDB boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but GaussDB boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports GaussDB boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampNano(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at bigint DEFAULT NULL,\n//   update_at bigint DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \tvar softTimeOption = gdb.SoftTimeOption{\n// \t\tSoftTimeType: gdb.SoftTimeTypeTimestampNano,\n// \t}\n//\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.Assert(len(one[\"create_at\"].String()), 19)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 19)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\nfunc Test_SoftTime_CreateUpdateDelete_Specified(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(0) DEFAULT NULL,\n  update_at timestamp(0) DEFAULT NULL,\n  delete_at timestamp(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_1\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneInsert[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_10\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:15:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneSave[\"update_at\"].String(), \"2024-05-30 20:15:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\":      \"name_1000\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:30:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneUpdate[\"update_at\"].String(), \"2024-05-30 20:30:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Insert with delete_at\n\t\tdataInsertDelete := g.Map{\n\t\t\t\"id\":        2,\n\t\t\t\"name\":      \"name_2\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"delete_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataInsertDelete).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Delete Select\n\t\toneDelete, err := db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(oneDelete), 0)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"id\"].Int(), 2)\n\t\tt.Assert(oneDeleteUnscoped[\"name\"].String(), \"name_2\")\n\t\tt.Assert(oneDeleteUnscoped[\"delete_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_union_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_feature_with_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Table_Relation_With_Scan(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_scan_user\"\n\t\ttableUserDetail = \"with_scan_user_detail\"\n\t\ttableUserScores = \"with_scan_user_score\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScore struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user_score\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user\"`\n\t\tId         int          `json:\"id\"`\n\t\tName       string       `json:\"name\"`\n\t\tUserDetail *UserDetail  `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScore `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\tuser := User{\n\t\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t\t}\n\t\t\tlastInsertId, err := db.Model(tableUser).Data(user).OmitEmpty().InsertAndGetId()\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\tuserDetail := UserDetail{\n\t\t\t\tUid:     int(lastInsertId),\n\t\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t\t}\n\t\t\t_, err = db.Model(tableUserDetail).Data(userDetail).OmitEmpty().Insert()\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\tuserScore := UserScore{\n\t\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\t\tScore: j,\n\t\t\t\t}\n\t\t\t\t_, err = db.Model(tableUserScores).Data(userScore).OmitEmpty().Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Scan pointer.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", 3).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\t// Scan struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserDetail).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserDetail).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 0)\n\t})\n\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.Assert(user.UserDetail, nil)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_rel_user\"\n\t\ttableUserDetail = \"with_rel_user_detail\"\n\t\ttableUserScores = \"with_rel_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 0)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 0)\n\t})\n\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.Assert(users[1].UserDetail, nil)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_user\"\n\t\ttableUserDetail = \"withall_user_detail\"\n\t\ttableUserScores = \"withall_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_list_user\"\n\t\ttableUserDetail = \"withall_list_user_detail\"\n\t\ttableUserScores = \"withall_list_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAllCondition_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_cond_user\"\n\t\ttableUserDetail = \"withall_cond_user_detail\"\n\t\ttableUserScores = \"withall_cond_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id, where:uid > 3\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id, where:score>1 and score<5, order:score desc\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_With_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_emsm_user\"\n\t\ttableUserDetail = \"withall_emsm_user_detail\"\n\t\ttableUserScores = \"withall_emsm_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_emsm_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_emsm_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_emsm_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Without_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_emns_user\"\n\t\ttableUserDetail = \"withall_emns_user_detail\"\n\t\ttableUserScores = \"withall_emns_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_emns_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_emns_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tId   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_emns_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tUserEmbedded\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_WithoutMeta(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_nometa_user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetailBase struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tUserDetailBase\n\t}\n\n\ttype UserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_nested_user\"\n\t\ttableUserDetail = \"withall_nested_user_detail\"\n\t\ttableUserScores = \"withall_nested_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_nested_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_nested_user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_nested_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends1(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int     `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     *TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     *TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends2(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int       `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     []*TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     []*TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.Assert(len(tableA.TableB), 2)\n\t\tt.Assert(tableA.TableB[0].Id, 10)\n\t\tt.Assert(tableA.TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA.TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA.TableB[1].TableC), 1)\n\t\tt.Assert(tableA.TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA.TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA.TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA.TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA.TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA.TableB[1].TableC[0].TableBId, 30)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\n\t\tt.Assert(len(tableA[0].TableB), 2)\n\t\tt.Assert(tableA[0].TableB[0].Id, 10)\n\t\tt.Assert(tableA[0].TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA[0].TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA[0].TableB[1].TableC), 1)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].TableBId, 30)\n\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].Id, 300)\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].TableBId, 20)\n\n\t\tt.Assert(tableA[1].TableB[1].Id, 40)\n\t\tt.Assert(tableA[1].TableB[1].TableAId, 2)\n\t\tt.Assert(tableA[1].TableB[1].TableC, nil)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends_Embedded(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\t*TableC    `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\t*TableB    `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Meta_NameMatchingRule(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_embed_user\"\n\t\ttableUserDetail = \"with_embed_user_detail\"\n\t\ttableUserScores = \"with_embed_user_scores\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nuser_id integer NOT NULL,\nscore integer NOT NULL\n);\n `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user_detail\"`\n\t\tUserID     int    `json:\"user_id\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user_scores\"`\n\t\tID         int `json:\"id\"`\n\t\tUserID     int `json:\"user_id\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user\"`\n\t\tUserEmbedded\n\t\tUserDetail UserDetail    `orm:\"with:user_id=id\"`\n\t\tUserScores []*UserScores `orm:\"with:user_id=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t\t\"score\":   j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.ID, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.UserID, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].UserID, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].UserID, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Unscoped(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_unscoped_user\"\n\t\ttableUserDetail = \"with_unscoped_user_detail\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL,\ndeleted_at timestamp default NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user_detail\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Order(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_order_user\"\n\t\ttableUserDetail = \"with_order_user_detail\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL,\ndeleted_at timestamp default NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user_detail\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, order:user_id asc,address desc, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_field_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_TableFields tests the TableFields method for retrieving table field information\nfunc Test_TableFields(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields) > 0, true)\n\n\t\t// Test primary key field\n\t\tt.Assert(fields[\"id\"].Name, \"id\")\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\n\t\t// Test integer types\n\t\tt.Assert(fields[\"col_int2\"].Name, \"col_int2\")\n\t\tt.Assert(fields[\"col_int4\"].Name, \"col_int4\")\n\t\tt.Assert(fields[\"col_int8\"].Name, \"col_int8\")\n\n\t\t// Test float types\n\t\tt.Assert(fields[\"col_float4\"].Name, \"col_float4\")\n\t\tt.Assert(fields[\"col_float8\"].Name, \"col_float8\")\n\t\tt.Assert(fields[\"col_numeric\"].Name, \"col_numeric\")\n\n\t\t// Test character types\n\t\tt.Assert(fields[\"col_char\"].Name, \"col_char\")\n\t\tt.Assert(fields[\"col_varchar\"].Name, \"col_varchar\")\n\t\tt.Assert(fields[\"col_text\"].Name, \"col_text\")\n\n\t\t// Test boolean type\n\t\tt.Assert(fields[\"col_bool\"].Name, \"col_bool\")\n\n\t\t// Test date/time types\n\t\tt.Assert(fields[\"col_date\"].Name, \"col_date\")\n\t\tt.Assert(fields[\"col_timestamp\"].Name, \"col_timestamp\")\n\n\t\t// Test JSON types\n\t\tt.Assert(fields[\"col_json\"].Name, \"col_json\")\n\t\tt.Assert(fields[\"col_jsonb\"].Name, \"col_jsonb\")\n\n\t\t// Test array types\n\t\tt.Assert(fields[\"col_int2_arr\"].Name, \"col_int2_arr\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Name, \"col_int4_arr\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Name, \"col_varchar_arr\")\n\t})\n}\n\n// Test_TableFields_Types tests field type information\nfunc Test_TableFields_Types(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// Test integer type names\n\t\tt.Assert(fields[\"col_int2\"].Type, \"int2(16)\")\n\t\tt.Assert(fields[\"col_int4\"].Type, \"int4(32)\")\n\t\tt.Assert(fields[\"col_int8\"].Type, \"int8(64)\")\n\n\t\t// Test float type names\n\t\tt.Assert(fields[\"col_float4\"].Type, \"float4(24)\")\n\t\tt.Assert(fields[\"col_float8\"].Type, \"float8(53)\")\n\t\tt.Assert(fields[\"col_numeric\"].Type, \"numeric(10)\")\n\n\t\t// Test character type names\n\t\tt.Assert(fields[\"col_char\"].Type, \"bpchar(10)\")\n\t\tt.Assert(fields[\"col_varchar\"].Type, \"varchar(100)\")\n\t\tt.Assert(fields[\"col_text\"].Type, \"text\")\n\n\t\t// Test boolean type name\n\t\tt.Assert(fields[\"col_bool\"].Type, \"bool\")\n\n\t\t// Test date/time type names\n\t\t// Note: GaussDB internally represents date as timestamp in pg_type\n\t\tt.Assert(fields[\"col_date\"].Type, \"timestamp\")\n\t\tt.Assert(fields[\"col_timestamp\"].Type, \"timestamp\")\n\t\tt.Assert(fields[\"col_timestamptz\"].Type, \"timestamptz\")\n\n\t\t// Test JSON type names\n\t\tt.Assert(fields[\"col_json\"].Type, \"json\")\n\t\tt.Assert(fields[\"col_jsonb\"].Type, \"jsonb\")\n\n\t\t// Test array type names (PostgreSQL uses _ prefix for array types)\n\t\tt.Assert(fields[\"col_int2_arr\"].Type, \"_int2\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Type, \"_int4\")\n\t\tt.Assert(fields[\"col_int8_arr\"].Type, \"_int8\")\n\t\tt.Assert(fields[\"col_float4_arr\"].Type, \"_float4\")\n\t\tt.Assert(fields[\"col_float8_arr\"].Type, \"_float8\")\n\t\tt.Assert(fields[\"col_numeric_arr\"].Type, \"_numeric\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Type, \"_varchar\")\n\t\tt.Assert(fields[\"col_text_arr\"].Type, \"_text\")\n\t\tt.Assert(fields[\"col_bool_arr\"].Type, \"_bool\")\n\t})\n}\n\n// Test_TableFields_Nullable tests field nullable information\nfunc Test_TableFields_Nullable(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// NOT NULL fields should have Null = false\n\t\tt.Assert(fields[\"col_int2\"].Null, false)\n\t\tt.Assert(fields[\"col_int4\"].Null, false)\n\t\tt.Assert(fields[\"col_numeric\"].Null, false)\n\t\tt.Assert(fields[\"col_varchar\"].Null, false)\n\t\tt.Assert(fields[\"col_bool\"].Null, false)\n\t\tt.Assert(fields[\"col_varchar_arr\"].Null, false)\n\n\t\t// Nullable fields should have Null = true\n\t\tt.Assert(fields[\"col_int8\"].Null, true)\n\t\tt.Assert(fields[\"col_text\"].Null, true)\n\t\tt.Assert(fields[\"col_json\"].Null, true)\n\t})\n}\n\n// Test_TableFields_Comments tests field comment information\nfunc Test_TableFields_Comments(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// Test fields with comments\n\t\tt.Assert(fields[\"id\"].Comment, \"Primary key ID\")\n\t\tt.Assert(fields[\"col_int2\"].Comment, \"int2 type (smallint)\")\n\t\tt.Assert(fields[\"col_int4\"].Comment, \"int4 type (integer)\")\n\t\tt.Assert(fields[\"col_int8\"].Comment, \"int8 type (bigint)\")\n\t\tt.Assert(fields[\"col_numeric\"].Comment, \"numeric type with precision\")\n\t\tt.Assert(fields[\"col_varchar\"].Comment, \"varchar type\")\n\t\tt.Assert(fields[\"col_bool\"].Comment, \"boolean type\")\n\t\tt.Assert(fields[\"col_timestamp\"].Comment, \"timestamp type\")\n\t\tt.Assert(fields[\"col_json\"].Comment, \"json type\")\n\t\tt.Assert(fields[\"col_jsonb\"].Comment, \"jsonb type\")\n\n\t\t// Test array field comments\n\t\tt.Assert(fields[\"col_int2_arr\"].Comment, \"int2 array type (_int2)\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Comment, \"int4 array type (_int4)\")\n\t\tt.Assert(fields[\"col_int8_arr\"].Comment, \"int8 array type (_int8)\")\n\t\tt.Assert(fields[\"col_numeric_arr\"].Comment, \"numeric array type (_numeric)\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Comment, \"varchar array type (_varchar)\")\n\t\tt.Assert(fields[\"col_text_arr\"].Comment, \"text array type (_text)\")\n\t})\n}\n\n// Test_Field_Type_Conversion tests type conversion for various PostgreSQL types\nfunc Test_Field_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test integer type conversions\n\t\tt.Assert(one[\"col_int2\"].Int(), 1)\n\t\tt.Assert(one[\"col_int4\"].Int(), 10)\n\t\tt.Assert(one[\"col_int8\"].Int64(), int64(100))\n\n\t\t// Test float type conversions\n\t\tt.Assert(one[\"col_float4\"].Float32() > 0, true)\n\t\tt.Assert(one[\"col_float8\"].Float64() > 0, true)\n\n\t\t// Test string type conversions\n\t\tt.AssertNE(one[\"col_varchar\"].String(), \"\")\n\t\tt.AssertNE(one[\"col_text\"].String(), \"\")\n\n\t\t// Test boolean type conversion\n\t\tt.Assert(one[\"col_bool\"].Bool(), false) // i=1, 1%2==0 is false\n\t})\n}\n\n// Test_Field_Array_Type_Conversion tests array type conversion\nfunc Test_Field_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test integer array type conversions\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 1)\n\t\tt.Assert(int2Arr[1], 2)\n\t\tt.Assert(int2Arr[2], 1)\n\n\t\tint4Arr := one[\"col_int4_arr\"].Ints()\n\t\tt.Assert(len(int4Arr), 3)\n\t\tt.Assert(int4Arr[0], 10)\n\t\tt.Assert(int4Arr[1], 20)\n\t\tt.Assert(int4Arr[2], 1)\n\n\t\tint8Arr := one[\"col_int8_arr\"].Int64s()\n\t\tt.Assert(len(int8Arr), 3)\n\t\tt.Assert(int8Arr[0], int64(100))\n\t\tt.Assert(int8Arr[1], int64(200))\n\t\tt.Assert(int8Arr[2], int64(1))\n\n\t\t// Test string array type conversions\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"a\")\n\t\tt.Assert(varcharArr[1], \"b\")\n\t\tt.Assert(varcharArr[2], \"c1\")\n\n\t\ttextArr := one[\"col_text_arr\"].Strings()\n\t\tt.Assert(len(textArr), 3)\n\t\tt.Assert(textArr[0], \"x\")\n\t\tt.Assert(textArr[1], \"y\")\n\t\tt.Assert(textArr[2], \"z1\")\n\n\t\t// Test boolean array type conversions\n\t\t// col_bool_arr is '{true, false, %t}' where %t = i%2==0, for i=1 it's false\n\t\tboolArr := one[\"col_bool_arr\"].Bools()\n\t\tt.Assert(len(boolArr), 3)\n\t\tt.Assert(boolArr[0], true)  // literal true\n\t\tt.Assert(boolArr[1], false) // literal false\n\t\tt.Assert(boolArr[2], false) // i=1, 1%2==0 is false\n\t})\n}\n\n// Test_Field_Array_Insert tests inserting array data\nfunc Test_Field_Array_Insert(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_int2_arr\":    []int{1, 2, 3},\n\t\t\t\"col_int4_arr\":    []int{10, 20, 30},\n\t\t\t\"col_varchar_arr\": []string{\"a\", \"b\", \"c\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(one[\"col_int2\"].Int(), 1)\n\t\tt.Assert(one[\"col_varchar\"].String(), \"test\")\n\t\tt.Assert(one[\"col_bool\"].Bool(), true)\n\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 1)\n\t\tt.Assert(int2Arr[1], 2)\n\t\tt.Assert(int2Arr[2], 3)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"a\")\n\t\tt.Assert(varcharArr[1], \"b\")\n\t\tt.Assert(varcharArr[2], \"c\")\n\t})\n}\n\n// Test_Field_Array_Update tests updating array data\nfunc Test_Field_Array_Update(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Update array values\n\t\t_, err := db.Model(table).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"col_int2_arr\":    []int{100, 200, 300},\n\t\t\t\"col_varchar_arr\": []string{\"x\", \"y\", \"z\"},\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 100)\n\t\tt.Assert(int2Arr[1], 200)\n\t\tt.Assert(int2Arr[2], 300)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"x\")\n\t\tt.Assert(varcharArr[1], \"y\")\n\t\tt.Assert(varcharArr[2], \"z\")\n\t})\n}\n\n// Test_Field_JSON_Type tests JSON/JSONB type handling\nfunc Test_Field_JSON_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with JSON values\n\t\ttestData := g.Map{\n\t\t\t\"name\":  \"test\",\n\t\t\t\"value\": 123,\n\t\t\t\"items\": []string{\"a\", \"b\", \"c\"},\n\t\t}\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":    1,\n\t\t\t\"col_int4\":    10,\n\t\t\t\"col_numeric\": 99.99,\n\t\t\t\"col_varchar\": \"test\",\n\t\t\t\"col_bool\":    true,\n\t\t\t\"col_json\":    testData,\n\t\t\t\"col_jsonb\":   testData,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test JSON field\n\t\tjsonMap := one[\"col_json\"].Map()\n\t\tt.Assert(jsonMap[\"name\"], \"test\")\n\t\tt.Assert(jsonMap[\"value\"], 123)\n\n\t\t// Test JSONB field\n\t\tjsonbMap := one[\"col_jsonb\"].Map()\n\t\tt.Assert(jsonbMap[\"name\"], \"test\")\n\t\tt.Assert(jsonbMap[\"value\"], 123)\n\t})\n}\n\n// Test_Field_Scan_To_Struct tests scanning results to struct\nfunc Test_Field_Scan_To_Struct(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\ttype TestRecord struct {\n\t\tId         int64    `json:\"id\"`\n\t\tColInt2    int16    `json:\"col_int2\"`\n\t\tColInt4    int32    `json:\"col_int4\"`\n\t\tColInt8    int64    `json:\"col_int8\"`\n\t\tColVarchar string   `json:\"col_varchar\"`\n\t\tColBool    bool     `json:\"col_bool\"`\n\t\tColInt2Arr []int    `json:\"col_int2_arr\"`\n\t\tColInt4Arr []int    `json:\"col_int4_arr\"`\n\t\tColInt8Arr []int64  `json:\"col_int8_arr\"`\n\t\tColTextArr []string `json:\"col_text_arr\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar record TestRecord\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(&record)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(record.Id, int64(1))\n\t\tt.Assert(record.ColInt2, int16(1))\n\t\tt.Assert(record.ColInt4, int32(10))\n\t\tt.Assert(record.ColInt8, int64(100))\n\t\tt.AssertNE(record.ColVarchar, \"\")\n\t\tt.Assert(record.ColBool, false)\n\n\t\t// Test array fields scanned to struct\n\t\tt.Assert(len(record.ColInt2Arr), 3)\n\t\tt.Assert(record.ColInt2Arr[0], 1)\n\t\tt.Assert(record.ColInt2Arr[1], 2)\n\t\tt.Assert(record.ColInt2Arr[2], 1)\n\n\t\tt.Assert(len(record.ColTextArr), 3)\n\t\tt.Assert(record.ColTextArr[0], \"x\")\n\t\tt.Assert(record.ColTextArr[1], \"y\")\n\t\tt.Assert(record.ColTextArr[2], \"z1\")\n\t})\n}\n\n// Test_Field_Scan_To_Struct_Slice tests scanning multiple results to struct slice\nfunc Test_Field_Scan_To_Struct_Slice(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\ttype TestRecord struct {\n\t\tId         int64    `json:\"id\"`\n\t\tColInt2    int16    `json:\"col_int2\"`\n\t\tColVarchar string   `json:\"col_varchar\"`\n\t\tColInt2Arr []int    `json:\"col_int2_arr\"`\n\t\tColTextArr []string `json:\"col_text_arr\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar records []TestRecord\n\t\terr := db.Model(table).OrderAsc(\"id\").Limit(5).Scan(&records)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(records), 5)\n\n\t\t// Verify first record\n\t\tt.Assert(records[0].Id, int64(1))\n\t\tt.Assert(records[0].ColInt2, int16(1))\n\t\tt.Assert(len(records[0].ColInt2Arr), 3)\n\n\t\t// Verify last record\n\t\tt.Assert(records[4].Id, int64(5))\n\t\tt.Assert(records[4].ColInt2, int16(5))\n\t})\n}\n\n// Test_Field_Empty_Array tests handling empty arrays\nfunc Test_Field_Empty_Array(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with empty array values (using default)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":    1,\n\t\t\t\"col_int4\":    10,\n\t\t\t\"col_numeric\": 99.99,\n\t\t\t\"col_varchar\": \"test\",\n\t\t\t\"col_bool\":    true,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify empty arrays\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Default empty arrays\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 0)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 0)\n\t})\n}\n\n// Test_Field_Null_Values tests handling NULL values\nfunc Test_Field_Null_Values(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert minimal required fields, leaving nullable fields as NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL handling\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Nullable fields should return appropriate zero values\n\t\tt.Assert(one[\"col_text\"].IsNil() || one[\"col_text\"].IsEmpty(), true)\n\t\tt.Assert(one[\"col_int8_arr\"].IsNil() || one[\"col_int8_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_Float_Array_Type_Conversion tests float array type conversion (_float4, _float8)\nfunc Test_Field_Float_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test float4 array type conversions\n\t\tfloat4Arr := one[\"col_float4_arr\"].Float32s()\n\t\tt.Assert(len(float4Arr), 3)\n\t\tt.Assert(float4Arr[0] > 0, true)\n\t\tt.Assert(float4Arr[1] > 0, true)\n\n\t\t// Test float8 array type conversions\n\t\tfloat8Arr := one[\"col_float8_arr\"].Float64s()\n\t\tt.Assert(len(float8Arr), 3)\n\t\tt.Assert(float8Arr[0] > 0, true)\n\t\tt.Assert(float8Arr[1] > 0, true)\n\t})\n}\n\n// Test_Field_Numeric_Array_Type_Conversion tests numeric/decimal array type conversion\nfunc Test_Field_Numeric_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test numeric array type conversions\n\t\tnumericArr := one[\"col_numeric_arr\"].Float64s()\n\t\tt.Assert(len(numericArr), 3)\n\t\tt.Assert(numericArr[0] > 0, true)\n\t\tt.Assert(numericArr[1] > 0, true)\n\n\t\t// Test decimal array type conversions\n\t\tdecimalArr := one[\"col_decimal_arr\"].Float64s()\n\t\tif !one[\"col_decimal_arr\"].IsNil() {\n\t\t\tt.Assert(len(decimalArr) > 0, true)\n\t\t}\n\t})\n}\n\n// Test_Field_Bool_Array_Type_Conversion tests bool array type conversion more thoroughly\nfunc Test_Field_Bool_Array_Type_Conversion(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with specific bool array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":     1,\n\t\t\t\"col_int4\":     10,\n\t\t\t\"col_numeric\":  99.99,\n\t\t\t\"col_varchar\":  \"test\",\n\t\t\t\"col_bool\":     true,\n\t\t\t\"col_bool_arr\": []bool{true, false, true},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bool array\n\t\tboolArr := one[\"col_bool_arr\"].Bools()\n\t\tt.Assert(len(boolArr), 3)\n\t\tt.Assert(boolArr[0], true)\n\t\tt.Assert(boolArr[1], false)\n\t\tt.Assert(boolArr[2], true)\n\t})\n}\n\n// Test_Field_Char_Array_Type tests char array type (_char)\nfunc Test_Field_Char_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with char array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_char_arr\":    []string{\"a\", \"b\", \"c\"},\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test char array\n\t\tcharArr := one[\"col_char_arr\"].Strings()\n\t\tt.Assert(len(charArr), 3)\n\t})\n}\n\n// Test_Field_Bytea_Type tests bytea (binary) type conversion\nfunc Test_Field_Bytea_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with binary data\n\t\tbinaryData := []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f} // \"Hello\" in hex\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_bytea\":       binaryData,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea field\n\t\tresult := one[\"col_bytea\"].Bytes()\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0], 0x48) // 'H'\n\t})\n}\n\n// Test_Field_Bytea_Array_Type tests bytea array type (_bytea)\nfunc Test_Field_Bytea_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with bytea array values using raw SQL\n\t\t// PostgreSQL bytea array literal format: ARRAY[E'\\\\x010203', E'\\\\x040506']::bytea[]\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\t\tINSERT INTO %s (col_int2, col_int4, col_numeric, col_varchar, col_bool, col_varchar_arr, col_bytea_arr)\n\t\t\tVALUES (1, 10, 99.99, 'test', true, '{}', ARRAY[E'\\\\x010203', E'\\\\x040506']::bytea[])\n\t\t`, table))\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify bytea array\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea array field - should be converted to [][]byte\n\t\tbyteaArrVal := one[\"col_bytea_arr\"]\n\t\tt.Assert(byteaArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\tbyteaArr := byteaArrVal.Interfaces()\n\t\tt.Assert(len(byteaArr), 2)\n\t})\n}\n\n// Test_Field_Date_Array_Type tests date array type (_date)\nfunc Test_Field_Date_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _date array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL date array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// date array should be nil or empty\n\t\tt.Assert(one[\"col_date_arr\"].IsNil() || one[\"col_date_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_Timestamp_Array_Type tests timestamp array type (_timestamp)\nfunc Test_Field_Timestamp_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _timestamp array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL timestamp array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// timestamp array should be nil or empty\n\t\tt.Assert(one[\"col_timestamp_arr\"].IsNil() || one[\"col_timestamp_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_JSONB_Array_Type tests JSONB array type (_jsonb)\nfunc Test_Field_JSONB_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _jsonb array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL jsonb array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// jsonb array should be nil or empty\n\t\tt.Assert(one[\"col_jsonb_arr\"].IsNil() || one[\"col_jsonb_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_UUID_Array_Type tests UUID array type (_uuid)\nfunc Test_Field_UUID_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with UUID array values using raw SQL\n\t\t// PostgreSQL uuid array literal format: ARRAY['uuid1', 'uuid2']::uuid[]\n\t\tuuid1 := \"550e8400-e29b-41d4-a716-446655440000\"\n\t\tuuid2 := \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\"\n\t\tuuid3 := \"6ba7b811-9dad-11d1-80b4-00c04fd430c8\"\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\t\tINSERT INTO %s (col_int2, col_int4, col_numeric, col_varchar, col_bool, col_varchar_arr, col_uuid_arr)\n\t\t\tVALUES (1, 10, 99.99, 'test', true, '{}', ARRAY['%s', '%s', '%s']::uuid[])\n\t\t`, table, uuid1, uuid2, uuid3))\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify UUID array\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test UUID array field - should be converted to []uuid.UUID\n\t\tuuidArrVal := one[\"col_uuid_arr\"]\n\t\tt.Assert(uuidArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data as []uuid.UUID\n\t\tuuidArr := uuidArrVal.Interfaces()\n\t\tt.Assert(len(uuidArr), 3)\n\n\t\t// Verify each element is uuid.UUID type\n\t\tu1, ok := uuidArr[0].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u1.String(), uuid1)\n\n\t\tu2, ok := uuidArr[1].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u2.String(), uuid2)\n\n\t\tu3, ok := uuidArr[2].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u3.String(), uuid3)\n\t})\n}\n\n// Test_Field_UUID_Type tests UUID type\nfunc Test_Field_UUID_Type(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify UUID field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test UUID field - should be converted to uuid.UUID\n\t\tuuidVal := one[\"col_uuid\"]\n\t\tt.Assert(uuidVal.IsNil(), false)\n\n\t\t// Verify the value is uuid.UUID type\n\t\tuuidObj, ok := uuidVal.Val().(uuid.UUID)\n\t\tt.Assert(ok, true)\n\n\t\t// Verify the UUID format\n\t\tuuidStr := uuidObj.String()\n\t\tt.Assert(len(uuidStr) > 0, true)\n\t\t// UUID should contain the pattern from insert: 550e8400-e29b-41d4-a716-44665544000X\n\t\tt.Assert(uuidStr, \"550e8400-e29b-41d4-a716-446655440001\")\n\n\t\t// Also verify we can still get string representation via .String()\n\t\tt.Assert(uuidVal.String(), \"550e8400-e29b-41d4-a716-446655440001\")\n\t})\n}\n\n// Test_Field_Bytea_Array_Type_Scan tests bytea array type and scanning\nfunc Test_Field_Bytea_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify bytea array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea array field\n\t\tbyteaArrVal := one[\"col_bytea_arr\"]\n\t\t// bytea array should not be nil since we inserted data\n\t\tt.Assert(byteaArrVal.IsNil(), false)\n\t})\n}\n\n// Test_Field_Date_Array_Type_Scan tests date array type and scanning\nfunc Test_Field_Date_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify date array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test date array field\n\t\tdateArrVal := one[\"col_date_arr\"]\n\t\tt.Assert(dateArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\tdateArr := dateArrVal.Strings()\n\t\tt.Assert(len(dateArr) > 0, true)\n\t})\n}\n\n// Test_Field_Timestamp_Array_Type_Scan tests timestamp array type and scanning\nfunc Test_Field_Timestamp_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify timestamp array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test timestamp array field\n\t\ttimestampArrVal := one[\"col_timestamp_arr\"]\n\t\tt.Assert(timestampArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\ttimestampArr := timestampArrVal.Strings()\n\t\tt.Assert(len(timestampArr) > 0, true)\n\t})\n}\n\n// Test_Field_JSONB_Array_Type_Scan tests JSONB array type and scanning\nfunc Test_Field_JSONB_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify JSONB array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test JSONB array field\n\t\tjsonbArrVal := one[\"col_jsonb_arr\"]\n\t\tt.Assert(jsonbArrVal.IsNil(), false)\n\t})\n}\n\n// Test_Field_UUID_Query tests querying by UUID field\nfunc Test_Field_UUID_Query(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test 1: Query by UUID string\n\t\tuuidStr := \"550e8400-e29b-41d4-a716-446655440001\"\n\t\tone, err := db.Model(table).Where(\"col_uuid\", uuidStr).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\n\t\t// Verify the returned UUID is correct\n\t\tuuidObj, ok := one[\"col_uuid\"].Val().(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(uuidObj.String(), uuidStr)\n\n\t\t// Test 2: Query by uuid.UUID type directly\n\t\tuuidVal, err := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440002\")\n\t\tt.AssertNil(err)\n\t\tone, err = db.Model(table).Where(\"col_uuid\", uuidVal).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 2)\n\n\t\t// Test 3: Query by UUID string using g.Map\n\t\tone, err = db.Model(table).Where(g.Map{\n\t\t\t\"col_uuid\": \"550e8400-e29b-41d4-a716-446655440003\",\n\t\t}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\n\t\t// Test 4: Query by uuid.UUID type using g.Map\n\t\tuuidVal, err = uuid.Parse(\"550e8400-e29b-41d4-a716-446655440004\")\n\t\tt.AssertNil(err)\n\t\tone, err = db.Model(table).Where(g.Map{\n\t\t\t\"col_uuid\": uuidVal,\n\t\t}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 4)\n\n\t\t// Test 5: Query non-existent UUID\n\t\tone, err = db.Model(table).Where(\"col_uuid\", \"00000000-0000-0000-0000-000000000000\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\t// Test 6: Query multiple records by UUID IN clause with strings\n\t\tall, err := db.Model(table).WhereIn(\"col_uuid\", g.Slice{\n\t\t\t\"550e8400-e29b-41d4-a716-446655440001\",\n\t\t\t\"550e8400-e29b-41d4-a716-446655440002\",\n\t\t}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 2)\n\n\t\t// Test 7: Query multiple records by UUID IN clause with uuid.UUID types\n\t\tuuid1, _ := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440003\")\n\t\tuuid2, _ := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440004\")\n\t\tall, err = db.Model(table).WhereIn(\"col_uuid\", g.Slice{uuid1, uuid2}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 4)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_filter_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/gaussdb/v2\"\n)\n\n// Test_DoFilter_LimitOffset tests LIMIT OFFSET conversion\nfunc Test_DoFilter_LimitOffset(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test MySQL style LIMIT x,y to PostgreSQL style LIMIT y OFFSET x\n\t\tsql := \"SELECT * FROM users LIMIT 10, 20\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 20 OFFSET 10\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with different numbers\n\t\tsql := \"SELECT * FROM users LIMIT 0, 100\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 100 OFFSET 0\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test no conversion needed\n\t\tsql := \"SELECT * FROM users LIMIT 50\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 50\")\n\t})\n}\n\n// Test_DoFilter_InsertIgnore tests INSERT IGNORE conversion\nfunc Test_DoFilter_InsertIgnore(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test INSERT IGNORE conversion\n\t\t// Note: GaussDB (PostgreSQL 9.2) does not support ON CONFLICT syntax (added in PG 9.5)\n\t\t// GaussDB handles InsertIgnore at DoInsert level using MERGE statement\n\t\tsql := \"INSERT IGNORE INTO users (name) VALUES ($1)\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\t// GaussDB removes IGNORE keyword but doesn't add ON CONFLICT (not supported)\n\t\tt.Assert(newSql, \"INSERT INTO users (name) VALUES ($1)\")\n\t})\n}\n\n// Test_DoFilter_PlaceholderConversion tests placeholder conversion\nfunc Test_DoFilter_PlaceholderConversion(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test ? placeholder conversion to $n\n\t\tsql := \"SELECT * FROM users WHERE id = ? AND name = ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE id = $1 AND name = $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multiple placeholders\n\t\tsql := \"INSERT INTO users (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"INSERT INTO users (a, b, c, d, e) VALUES ($1, $2, $3, $4, $5)\")\n\t})\n}\n\n// Test_DoFilter_JsonbOperator tests JSONB operator handling\nfunc Test_DoFilter_JsonbOperator(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ?| operator\n\t\t// The jsonb ? is first converted to $1, then restored to ?\n\t\t// So the next placeholder becomes $2\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb ?| ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\t// After placeholder conversion, the ? in jsonb should be preserved\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb ?| $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ?& operator\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb &? ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb &? $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ? operator\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb ? ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb ? $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test combination of jsonb and regular placeholders\n\t\tsql := \"SELECT * FROM users WHERE id = ? AND (data)::jsonb ?| ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE id = $1 AND (data)::jsonb ?| $3\")\n\t})\n}\n\n// Test_DoFilter_ComplexQuery tests complex queries with multiple features\nfunc Test_DoFilter_ComplexQuery(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test complex query with LIMIT and placeholders\n\t\tsql := \"SELECT * FROM users WHERE status = ? AND age > ? LIMIT 5, 10\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE status = $1 AND age > $2 LIMIT 10 OFFSET 5\")\n\t})\n}\n\n// Test_Tables tests the Tables method\nfunc Test_Tables_Method(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables, err := db.Tables(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tables) >= 0, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with specific schema - use the test schema\n\t\ttables, err := db.Tables(ctx, \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tables) >= 0, true)\n\t})\n}\n\n// Test_OrderRandomFunction tests the OrderRandomFunction method\nfunc Test_OrderRandomFunction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test ORDER BY RANDOM()\n\t\tall, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t})\n}\n\n// Test_GetChars tests the GetChars method\nfunc Test_GetChars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tleft, right := driver.GetChars()\n\t\tt.Assert(left, `\"`)\n\t\tt.Assert(right, `\"`)\n\t})\n}\n\n// Test_New tests the New method\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.New()\n\t\tt.AssertNE(driver, nil)\n\t})\n}\n\n// Test_DoExec_NonIntPrimaryKey tests DoExec with non-integer primary key\nfunc Test_DoExec_NonIntPrimaryKey(t *testing.T) {\n\t// Create a table with UUID primary key\n\ttableName := \"t_uuid_pk_test\"\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE IF NOT EXISTS `+tableName+` (\n\t\t\tid uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n\t\t\tname varchar(100)\n\t\t)\n\t`)\n\tif err != nil {\n\t\t// If gen_random_uuid is not available, skip this test\n\t\tt.Log(\"Skipping UUID test:\", err)\n\t\treturn\n\t}\n\tdefer db.Exec(ctx, \"DROP TABLE IF EXISTS \"+tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with UUID primary key\n\t\tresult, err := db.Model(tableName).Data(g.Map{\n\t\t\t\"name\": \"test_user\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// LastInsertId should return error for non-integer primary key\n\t\t_, err = result.LastInsertId()\n\t\t// For UUID, LastInsertId is not supported\n\t\tt.AssertNE(err, nil)\n\n\t\t// RowsAffected should still work\n\t\taffected, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(affected, int64(1))\n\t})\n}\n\n// Test_TableFields_WithSchema tests TableFields with specific schema\nfunc Test_TableFields_WithSchema(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with schema parameter\n\t\tfields, err := db.TableFields(ctx, table, \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields) > 0, true)\n\t})\n}\n\n// Test_TableFields_UniqueKey tests TableFields with unique key constraint\nfunc Test_TableFields_UniqueKey(t *testing.T) {\n\ttableName := \"t_unique_test\"\n\n\t// Create table with unique constraint\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE IF NOT EXISTS `+tableName+` (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\temail varchar(100) UNIQUE NOT NULL,\n\t\t\tname varchar(100)\n\t\t)\n\t`)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer db.Exec(ctx, \"DROP TABLE IF EXISTS \"+tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// Check primary key\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\n\t\t// Check unique key\n\t\tt.Assert(fields[\"email\"].Key, \"uni\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t_ \"github.com/gogf/gf/contrib/drivers/gaussdb/v2\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTableSize   = 10\n\tTablePrefix = \"t_\"\n\tSchemaName  = \"test\"\n\tCreateTime  = \"2018-10-24 10:00:00\"\n)\n\nvar (\n\tdb         gdb.DB\n\tconfigNode gdb.ConfigNode\n\tctx        = context.TODO()\n)\n\nfunc init() {\n\tconfigNode = gdb.ConfigNode{\n\t\tLink:      `gaussdb:gaussdb:UTpass@1234@tcp(127.0.0.1:9950)/postgres`,\n\t\tNamespace: SchemaName, // Set the schema namespace\n\t}\n\n\t// gaussdb only permit to connect to the designation database.\n\t// so you need to create the gaussdb database before you use orm\n\tgdb.AddConfigNode(gdb.DefaultGroupName, configNode)\n\tif r, err := gdb.New(configNode); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\t// Create schema if not exists\n\tschemaTemplate := \"CREATE SCHEMA IF NOT EXISTS %s\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, SchemaName)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"test\", gtime.TimestampNano())\n\t}\n\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial  NOT NULL,\n\t\t   \tpassport varchar(45) NOT NULL,\n\t\t   \tpassword varchar(32) NOT NULL,\n\t\t   \tnickname varchar(45) NOT NULL,\n\t\t   \tcreate_time timestamp NOT NULL,\n\t\t    favorite_movie varchar[],\n\t\t    favorite_music text[],\n\t\t\tnumeric_values numeric[],\n\t\t\tdecimal_values decimal[],\n\t\t   \tPRIMARY KEY (id)\n\t\t) ;`, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS %s\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\n// createAllTypesTable creates a table with all common PostgreSQL types for testing\nfunc createAllTypesTable(table ...string) string {\n\treturn createAllTypesTableWithDb(db, table...)\n}\n\nfunc createAllTypesTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"all_types\", gtime.TimestampNano())\n\t}\n\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\t-- Basic integer types\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tcol_int2 int2 NOT NULL DEFAULT 0,\n\t\t\tcol_int4 int4 NOT NULL DEFAULT 0,\n\t\t\tcol_int8 int8 DEFAULT 0,\n\t\t\tcol_smallint smallint,\n\t\t\tcol_integer integer,\n\t\t\tcol_bigint bigint,\n\n\t\t\t-- Float types\n\t\t\tcol_float4 float4 DEFAULT 0.0,\n\t\t\tcol_float8 float8 DEFAULT 0.0,\n\t\t\tcol_real real,\n\t\t\tcol_double double precision,\n\t\t\tcol_numeric numeric(10,2) NOT NULL DEFAULT 0.00,\n\t\t\tcol_decimal decimal(10,2),\n\n\t\t\t-- Character types\n\t\t\tcol_char char(10) DEFAULT '',\n\t\t\tcol_varchar varchar(100) NOT NULL DEFAULT '',\n\t\t\tcol_text text,\n\n\t\t\t-- Boolean type\n\t\t\tcol_bool boolean NOT NULL DEFAULT false,\n\n\t\t\t-- Date/Time types\n\t\t\tcol_date date DEFAULT CURRENT_DATE,\n\t\t\tcol_time time,\n\t\t\tcol_timetz timetz,\n\t\t\tcol_timestamp timestamp DEFAULT CURRENT_TIMESTAMP,\n\t\t\tcol_timestamptz timestamptz,\n\t\t\tcol_interval interval,\n\n\t\t\t-- Binary type\n\t\t\tcol_bytea bytea,\n\n\t\t\t-- JSON types\n\t\t\tcol_json json DEFAULT '{}',\n\t\t\tcol_jsonb jsonb DEFAULT '{}',\n\n\t\t\t-- UUID type\n\t\t\tcol_uuid uuid,\n\n\t\t\t-- Network types\n\t\t\tcol_inet inet,\n\t\t\tcol_cidr cidr,\n\t\t\tcol_macaddr macaddr,\n\n\t\t\t-- Array types - integers\n\t\t\tcol_int2_arr int2[] DEFAULT '{}',\n\t\t\tcol_int4_arr int4[] DEFAULT '{}',\n\t\t\tcol_int8_arr int8[],\n\n\t\t\t-- Array types - floats\n\t\t\tcol_float4_arr float4[],\n\t\t\tcol_float8_arr float8[],\n\t\t\tcol_numeric_arr numeric[] DEFAULT '{}',\n\t\t\tcol_decimal_arr decimal[],\n\n\t\t\t-- Array types - characters\n\t\t\tcol_varchar_arr varchar[] NOT NULL DEFAULT '{}',\n\t\t\tcol_text_arr text[],\n\t\t\tcol_char_arr char(10)[],\n\n\t\t\t-- Array types - boolean\n\t\t\tcol_bool_arr boolean[],\n\n\t\t\t-- Array types - bytea\n\t\t\tcol_bytea_arr bytea[],\n\n\t\t\t-- Array types - date/time\n\t\t\tcol_date_arr date[],\n\t\t\tcol_timestamp_arr timestamp[],\n\n\t\t\t-- Array types - JSON\n\t\t\tcol_jsonb_arr jsonb[],\n\n\t\t\t-- Array types - UUID\n\t\t\tcol_uuid_arr uuid[]\n\t\t);\n\n\t\t-- Add comments for columns\n\t\tCOMMENT ON TABLE %s IS 'Test table with all PostgreSQL types';\n\t\tCOMMENT ON COLUMN %s.id IS 'Primary key ID';\n\t\tCOMMENT ON COLUMN %s.col_int2 IS 'int2 type (smallint)';\n\t\tCOMMENT ON COLUMN %s.col_int4 IS 'int4 type (integer)';\n\t\tCOMMENT ON COLUMN %s.col_int8 IS 'int8 type (bigint)';\n\t\tCOMMENT ON COLUMN %s.col_numeric IS 'numeric type with precision';\n\t\tCOMMENT ON COLUMN %s.col_varchar IS 'varchar type';\n\t\tCOMMENT ON COLUMN %s.col_bool IS 'boolean type';\n\t\tCOMMENT ON COLUMN %s.col_timestamp IS 'timestamp type';\n\t\tCOMMENT ON COLUMN %s.col_json IS 'json type';\n\t\tCOMMENT ON COLUMN %s.col_jsonb IS 'jsonb type';\n\t\tCOMMENT ON COLUMN %s.col_int2_arr IS 'int2 array type (_int2)';\n\t\tCOMMENT ON COLUMN %s.col_int4_arr IS 'int4 array type (_int4)';\n\t\tCOMMENT ON COLUMN %s.col_int8_arr IS 'int8 array type (_int8)';\n\t\tCOMMENT ON COLUMN %s.col_numeric_arr IS 'numeric array type (_numeric)';\n\t\tCOMMENT ON COLUMN %s.col_varchar_arr IS 'varchar array type (_varchar)';\n\t\tCOMMENT ON COLUMN %s.col_text_arr IS 'text array type (_text)';\n\t\t`, name,\n\t\tname, name, name, name, name, name, name, name, name, name, name, name, name, name, name, name, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\n// createInitAllTypesTable creates and initializes a table with all common PostgreSQL types\nfunc createInitAllTypesTable(table ...string) string {\n\treturn createInitAllTypesTableWithDb(db, table...)\n}\n\nfunc createInitAllTypesTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createAllTypesTableWithDb(db, table...)\n\n\t// Insert test data\n\tfor i := 1; i <= TableSize; i++ {\n\t\tvar sql strings.Builder\n\n\t\t// Write INSERT statement header\n\t\tsql.WriteString(fmt.Sprintf(`INSERT INTO %s (\n\t\t\tcol_int2, col_int4, col_int8, col_smallint, col_integer, col_bigint,\n\t\t\tcol_float4, col_float8, col_real, col_double, col_numeric, col_decimal,\n\t\t\tcol_char, col_varchar, col_text, col_bool,\n\t\t\tcol_date, col_time, col_timestamp,\n\t\t\tcol_json, col_jsonb,\n\t\t\tcol_bytea,\n\t\t\tcol_uuid,\n\t\t\tcol_int2_arr, col_int4_arr, col_int8_arr,\n\t\t\tcol_float4_arr, col_float8_arr, col_numeric_arr, col_decimal_arr,\n\t\t\tcol_varchar_arr, col_text_arr, col_bool_arr, col_bytea_arr, col_date_arr, col_timestamp_arr, col_jsonb_arr, col_uuid_arr\n\t\t) VALUES (`, name))\n\n\t\t// Integer types: col_int2, col_int4, col_int8, col_smallint, col_integer, col_bigint\n\t\tsql.WriteString(fmt.Sprintf(\"%d, %d, %d, %d, %d, %d, \",\n\t\t\ti, i*10, i*100, i, i*10, i*100))\n\n\t\t// Float types: col_float4, col_float8, col_real, col_double, col_numeric, col_decimal\n\t\tsql.WriteString(fmt.Sprintf(\"%d.5, %d.5, %d.5, %d.5, %d.99, %d.99, \",\n\t\t\ti, i, i, i, i, i))\n\n\t\t// Character types: col_char, col_varchar, col_text, col_bool\n\t\tsql.WriteString(fmt.Sprintf(\"'char_%d', 'varchar_%d', 'text_%d', %t, \",\n\t\t\ti, i, i, i%2 == 0))\n\n\t\t// Date/Time types: col_date, col_time, col_timestamp\n\t\t// Calculate day as integer in range 1-28; 28 is used because it is the maximum day value safe for all months to avoid date validity issues.\n\t\t// %02d in fmt.Sprintf ensures two-digit zero-padded format\n\t\tdayOfMonth := (i-1)%28 + 1\n\t\tsql.WriteString(fmt.Sprintf(\"'2024-01-%02d', '10:00:%02d', '2024-01-%02d 10:00:00', \",\n\t\t\tdayOfMonth, (i-1)%60, dayOfMonth))\n\n\t\t// JSON types: col_json, col_jsonb\n\t\tsql.WriteString(fmt.Sprintf(`'{\"key\": \"value%d\"}', '{\"key\": \"value%d\"}', `, i, i))\n\n\t\t// Bytea type: col_bytea\n\t\tsql.WriteString(`E'\\\\xDEADBEEF', `)\n\n\t\t// UUID type: col_uuid (use %x for hex representation, padded to ensure valid UUID)\n\t\tsql.WriteString(fmt.Sprintf(\"'550e8400-e29b-41d4-a716-4466554400%02x', \", i))\n\n\t\t// Integer array types: col_int2_arr, col_int4_arr, col_int8_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{1, 2, %d}', '{10, 20, %d}', '{100, 200, %d}', \",\n\t\t\ti, i, i))\n\n\t\t// Float array types: col_float4_arr, col_float8_arr, col_numeric_arr, col_decimal_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{1.1, 2.2, %d.3}', '{1.1, 2.2, %d.3}', '{1.11, 2.22, %d.33}', '{1.11, 2.22, %d.33}', \",\n\t\t\ti, i, i, i))\n\n\t\t// Character array types: col_varchar_arr, col_text_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"a\", \"b\", \"c%d\"}', '{\"x\", \"y\", \"z%d\"}', `, i, i))\n\n\t\t// Boolean array type: col_bool_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{true, false, %t}', \", i%2 == 0))\n\n\t\t// Bytea array type: col_bytea_arr (use ARRAY syntax for bytea)\n\t\tsql.WriteString(`ARRAY[E'\\\\xDEADBEEF', E'\\\\xCAFEBABE']::bytea[], `)\n\n\t\t// Date array type: col_date_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"2024-01-%02d\", \"2024-01-%02d\"}', `, dayOfMonth, (dayOfMonth%28)+1))\n\n\t\t// Timestamp array type: col_timestamp_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"2024-01-%02d 10:00:00\", \"2024-01-%02d 11:00:00\"}', `, dayOfMonth, dayOfMonth))\n\n\t\t// JSONB array type: col_jsonb_arr (store as text array first, then cast to jsonb array)\n\t\tsql.WriteString(`ARRAY['{\"key\": \"value1\"}', '{\"key\": \"value2\"}']::jsonb[], `)\n\n\t\t// UUID array type: col_uuid_arr\n\t\tsql.WriteString(fmt.Sprintf(\"ARRAY['550e8400-e29b-41d4-a716-4466554400%02x'::uuid, '6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid]\", i))\n\n\t\t// Close VALUES\n\t\tsql.WriteString(\")\")\n\n\t\tif _, err := db.Exec(ctx, sql.String()); err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value() // model value\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete() // model delete\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One() // model one\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", \"2\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser   User\n\t\t\tcount  int\n\t\t\tresult sql.Result\n\t\t\terr    error\n\t\t)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"pw1\")\n\t\tt.Assert(user.NickName, \"n1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw2\",\n\t\t\t\"nickname\":    \"n2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"pw2\")\n\t\tt.Assert(user.NickName, \"n2\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial record\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"pass1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Replace with new data\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"].String(), \"t11\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\n\t\t// Replace with new ID (insert new record)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t22\",\n\t\t\t\"password\":    \"pass22\",\n\t\t\t\"nickname\":    \"T22\",\n\t\t\t\"create_time\": \"2018-10-24 11:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify new record was inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_Model_OnConflict(t *testing.T) {\n\tvar (\n\t\ttable      = fmt.Sprintf(`%s_%d`, TablePrefix+\"test\", gtime.TimestampNano())\n\t\tuniqueName = fmt.Sprintf(`%s_%d`, TablePrefix+\"test_unique\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial  NOT NULL,\n\t\t   \tpassport varchar(45) NOT NULL,\n\t\t   \tpassword varchar(32) NOT NULL,\n\t\t   \tnickname varchar(45) NOT NULL,\n\t\t   \tcreate_time timestamp NOT NULL,\n\t\t   \tPRIMARY KEY (id),\n\t\t\tCONSTRAINT %s UNIQUE (\"passport\", \"password\")\n\t\t) ;`, table, uniqueName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"passport,password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"passport\", \"password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(g.Slice{\"passport\", \"password\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n}\n\nfunc Test_Model_OnDuplicate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(\"passport,password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(\"passport\", \"password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Slice{\"passport\", \"password\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"passport\": \"nickname\",\n\t\t\t\"password\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"nickname\"])\n\t\tt.Assert(one[\"password\"], data[\"nickname\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map+raw.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"id\":          \"1\",\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"passport\": gdb.Raw(\"CONCAT(EXCLUDED.passport, '1')\"),\n\t\t\t\"password\": gdb.Raw(\"CONCAT(EXCLUDED.password, '2')\"),\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"]+\"1\")\n\t\tt.Assert(one[\"password\"], data[\"password\"]+\"2\")\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_Model_OnDuplicateWithCounter(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"id\": gdb.Counter{Field: \"id\", Value: 999999},\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(one)\n\t})\n}\n\nfunc Test_Model_OnDuplicateEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(\"nickname,create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(\"nickname\", \"create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(g.Slice{\"nickname\", \"create_time\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(g.Map{\n\t\t\t\"nickname\":    \"nickname\",\n\t\t\t\"create_time\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_OrderRandom(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_ConvertSliceString(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId            int\n\t\t\tPassport      string\n\t\t\tPassword      string\n\t\t\tNickName      string\n\t\t\tCreateTime    *gtime.Time\n\t\t\tFavoriteMovie []string\n\t\t\tFavoriteMusic []string\n\t\t}\n\n\t\tvar (\n\t\t\tuser  User\n\t\t\tuser2 User\n\t\t\terr   error\n\t\t)\n\n\t\t// slice string not null\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":             1,\n\t\t\t\"passport\":       \"p1\",\n\t\t\t\"password\":       \"pw1\",\n\t\t\t\"nickname\":       \"n1\",\n\t\t\t\"create_time\":    CreateTime,\n\t\t\t\"favorite_movie\": g.Slice{\"Iron-Man\", \"Spider-Man\"},\n\t\t\t\"favorite_music\": g.Slice{\"Hey jude\", \"Let it be\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Where(\"id\", 1).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(user.FavoriteMusic), 2)\n\t\tt.Assert(user.FavoriteMusic[0], \"Hey jude\")\n\t\tt.Assert(user.FavoriteMusic[1], \"Let it be\")\n\t\tt.Assert(len(user.FavoriteMovie), 2)\n\t\tt.Assert(user.FavoriteMovie[0], \"Iron-Man\")\n\t\tt.Assert(user.FavoriteMovie[1], \"Spider-Man\")\n\n\t\t// slice string null\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Where(\"id\", 2).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.FavoriteMusic, nil)\n\t\tt.Assert(len(user2.FavoriteMovie), 0)\n\t})\n}\n\nfunc Test_ConvertSliceFloat64(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype Args struct {\n\t\tNumericValues []float64 `orm:\"numeric_values\"`\n\t\tDecimalValues []float64 `orm:\"decimal_values\"`\n\t}\n\ttype User struct {\n\t\tId         int         `orm:\"id\"`\n\t\tPassport   string      `orm:\"passport\"`\n\t\tPassword   string      `json:\"password\"`\n\t\tNickName   string      `json:\"nickname\"`\n\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\tArgs\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\targs Args\n\t}{\n\t\t{\n\t\t\tname: \"nil\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: nil,\n\t\t\t\tDecimalValues: nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"not nil\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: []float64{1.1, 2.2, 3.3},\n\t\t\t\tDecimalValues: []float64{1.1, 2.2, 3.3},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"not empty\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: []float64{},\n\t\t\t\tDecimalValues: []float64{},\n\t\t\t},\n\t\t},\n\t}\n\tnow := gtime.New(CreateTime)\n\tfor i, tt := range tests {\n\t\tgtest.C(t, func(t *gtest.T) {\n\t\t\tuser := User{\n\t\t\t\tId:         i + 1,\n\t\t\t\tPassport:   fmt.Sprintf(\"test_%d\", i+1),\n\t\t\t\tPassword:   fmt.Sprintf(\"pass_%d\", i+1),\n\t\t\t\tNickName:   fmt.Sprintf(\"name_%d\", i+1),\n\t\t\t\tCreateTime: now,\n\t\t\t\tArgs:       tt.args,\n\t\t\t}\n\n\t\t\t_, err := db.Model(table).OmitNilData().Insert(user)\n\t\t\tt.AssertNil(err)\n\t\t\tvar got Args\n\t\t\terr = db.Model(table).Where(\"id\", user.Id).Limit(1).Scan(&got)\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(tt.args, got)\n\t\t})\n\t}\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNE(err, nil)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 0)\n\n\t\tvalue, err := db.Model(table).Fields(\"passport\").WherePri(1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t1\")\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\t// pgsql support ignore without primary key\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_model_where_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":         \"%name%\",\n\t\t\t\"id between ? and ?\":      g.Slice{1, 3},\n\t\t\t\"id > 0\":                  nil,\n\t\t\t\"create_time IS NOT NULL\": nil,\n\t\t\t\"id\":                      g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    \"1970-01-01\",\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":         \"%name%\",\n\t\t\t\"id between ? and ?\":      g.Slice{1, 3},\n\t\t\t\"id > 0\":                  nil,\n\t\t\t\"create_time IS NOT NULL\": nil,\n\t\t\t\"id\":                      g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    \"1970-01-01\",\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL(t *testing.T) {\n\t// Create a custom table with nullable nickname column for this test\n\ttable := fmt.Sprintf(`%s_%d`, TablePrefix+\"nullable\", gtime.TimestampNano())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial NOT NULL,\n\t\t   \tpassport varchar(45),\n\t\t   \tpassword varchar(32),\n\t\t   \tnickname varchar(45),\n\t\t   \tcreate_time timestamp,\n\t\t   \tPRIMARY KEY (id)\n\t\t) ;`, table,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\t// Insert test data\n\tfor i := 1; i <= TableSize; i++ {\n\t\tif _, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t}); err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WhereExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          bigserial NOT NULL,\n    uid         int NOT NULL DEFAULT 0,\n    PRIMARY KEY (id)\n);`, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\"))\n\n\t\tr, err := db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereNotExists\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\n\t\t// Test WhereExists with empty result\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table).\n\t\t\tWhereExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereNotExists with all results\n\t\tr, err = db.Model(table).\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test combination of Where and WhereExists\n\t\tr, err = db.Model(table+\" as \\\"user\\\"\").\n\t\t\tWhere(\"id>?\", 3).\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereExists with complex subquery\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\")).\n\t\t\tWhere(\"id > ?\", 0)\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Fields\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tFields(\"id,passport\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[0][\"passport\"].String(), \"user_1\")\n\n\t\t// Test WhereExists with Group\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Having\n\t\tr, err = db.Model(table+\" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tHaving(\"id > ?\", 1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_WhereNotExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          bigserial NOT NULL,\n    uid         int NOT NULL DEFAULT 0,\n    PRIMARY KEY (id)\n);`, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereNotExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\"))\n\n\t\tr, err := db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\t\tt.Assert(r[1][\"id\"].Int(), 4)\n\n\t\t// Test WhereNotExists with empty subquery\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test WhereNotExists with complex condition\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\")).\n\t\t\tWhere(\"id > ?\", 1)\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 9)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_open_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/gaussdb/v2\"\n)\n\n// Test_Open tests the Open method with various configurations\nfunc Test_Open_WithNamespace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:      \"postgres\",\n\t\t\tPass:      \"12345678\",\n\t\t\tHost:      \"127.0.0.1\",\n\t\t\tPort:      \"5432\",\n\t\t\tName:      \"test\",\n\t\t\tNamespace: \"public\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithTimezone tests Open with timezone configuration\nfunc Test_Open_WithTimezone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:     \"postgres\",\n\t\t\tPass:     \"12345678\",\n\t\t\tHost:     \"127.0.0.1\",\n\t\t\tPort:     \"5432\",\n\t\t\tName:     \"test\",\n\t\t\tTimezone: \"Asia/Shanghai\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithExtra tests Open with extra configuration\nfunc Test_Open_WithExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:  \"postgres\",\n\t\t\tPass:  \"12345678\",\n\t\t\tHost:  \"127.0.0.1\",\n\t\t\tPort:  \"5432\",\n\t\t\tName:  \"test\",\n\t\t\tExtra: \"connect_timeout=10\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithInvalidExtra tests Open with invalid extra configuration\nfunc Test_Open_WithInvalidExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"5432\",\n\t\t\tName: \"test\",\n\t\t\t// Invalid extra format with invalid URL encoding that will cause parse error\n\t\t\tExtra: \"%Q=%Q&b\",\n\t\t}\n\t\t_, err := driver.Open(config)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Open_WithFullConfig tests Open with all configuration options\nfunc Test_Open_WithFullConfig(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:      \"postgres\",\n\t\t\tPass:      \"12345678\",\n\t\t\tHost:      \"127.0.0.1\",\n\t\t\tPort:      \"5432\",\n\t\t\tName:      \"test\",\n\t\t\tNamespace: \"public\",\n\t\t\tTimezone:  \"UTC\",\n\t\t\tExtra:     \"connect_timeout=10\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithoutPort tests Open without port\nfunc Test_Open_WithoutPort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tName: \"test\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithoutName tests Open without database name\nfunc Test_Open_WithoutName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"5432\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_InvalidHost tests Open with invalid host\nfunc Test_Open_InvalidHost(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := gaussdb.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"invalid_host_that_does_not_exist\",\n\t\t\tPort: \"5432\",\n\t\t\tName: \"test\",\n\t\t}\n\t\t// Note: sql.Open doesn't actually connect, so no error here\n\t\t// The error would occur when actually using the connection\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_raw_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Raw_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"passport\":    \"port_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(\n\t\t\tg.List{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"passport\":    \"port_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t\tg.Map{\n\t\t\t\t\t\"passport\":    \"port_4\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t},\n\t\t).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_Raw_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\": gdb.Raw(\"id\"),\n\t\t}).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+100\"),\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tn, err := user.Where(\"id\", 101).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(1))\n\t})\n}\n\nfunc Test_Raw_Where(t *testing.T) {\n\ttable1 := createTable(\"test_raw_where_table1\")\n\ttable2 := createTable(\"test_raw_where_table2\")\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\t// https://github.com/gogf/gf/issues/3922\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" AS A WHERE NOT EXISTS (SELECT B.id FROM \"test_raw_where_table2\" AS B WHERE \"B\".\"id\"=A.id) LIMIT 1`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(\"B.id\", gdb.Raw(\"A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" AS A WHERE NOT EXISTS (SELECT B.id FROM \"test_raw_where_table2\" AS B WHERE B.id=A.id) LIMIT 1`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(gdb.Raw(\"B.id=A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\t// https://github.com/gogf/gf/issues/3915\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" WHERE \"passport\" < \"nickname\"`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\tm := db.Model(table1).Ctx(ctx).WhereLT(\"passport\", gdb.Raw(`\"nickname\"`))\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/gaussdb/v2\"\n)\n\nfunc Test_LastInsertId(t *testing.T) {\n\t// err not nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"notexist\").Insert(g.List{\n\t\t\t{\"name\": \"user1\"},\n\t\t\t{\"name\": \"user2\"},\n\t\t\t{\"name\": \"user3\"},\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := createTable()\n\t\tdefer dropTable(tableName)\n\t\tres, err := db.Model(tableName).Insert(g.List{\n\t\t\t{\"passport\": \"user1\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t{\"passport\": \"user2\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t{\"passport\": \"user3\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tlastInsertId, err := res.LastInsertId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(lastInsertId, int64(3))\n\t\trowsAffected, err := res.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(rowsAffected, int64(3))\n\t})\n}\n\nfunc Test_TxLastInsertId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := createTable()\n\t\tdefer dropTable(tableName)\n\t\terr := db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// user\n\t\t\tres, err := tx.Model(tableName).Insert(g.List{\n\t\t\t\t{\"passport\": \"user1\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user2\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user3\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tlastInsertId, err := res.LastInsertId()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(lastInsertId, int64(3))\n\t\t\trowsAffected, err := res.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(rowsAffected, int64(3))\n\n\t\t\tres1, err := tx.Model(tableName).Insert(g.List{\n\t\t\t\t{\"passport\": \"user4\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user5\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tlastInsertId1, err := res1.LastInsertId()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(lastInsertId1, int64(5))\n\t\t\trowsAffected1, err := res1.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(rowsAffected1, int64(2))\n\t\t\treturn nil\n\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Driver_DoFilter(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = gaussdb.Driver{}\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar data = g.Map{\n\t\t\t`select * from user where (role)::jsonb ?| 'admin'`: `select * from user where (role)::jsonb ?| 'admin'`,\n\t\t\t`select * from user where (role)::jsonb ?| '?'`:     `select * from user where (role)::jsonb ?| '$2'`,\n\t\t\t`select * from user where (role)::jsonb &? '?'`:     `select * from user where (role)::jsonb &? '$2'`,\n\t\t\t`select * from user where (role)::jsonb ? '?'`:      `select * from user where (role)::jsonb ? '$2'`,\n\t\t\t`select * from user where '?'`:                      `select * from user where '$1'`,\n\t\t}\n\t\tfor k, v := range data {\n\t\t\tnewSql, _, err := driver.DoFilter(ctx, nil, k, nil)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(newSql, v)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_transaction_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_TX_Query(t *testing.T) {\n\t// Test successful queries\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int+$2::int\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int+$2::int\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test error query - in GaussDB, once a statement fails,\n\t// the transaction is aborted and must be rolled back\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Exec(t *testing.T) {\n\t// Test successful exec operations\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int+$2::int\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int+$2::int\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test error exec - in GaussDB, once a statement fails,\n\t// the transaction is aborted and must be rolled back\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tst, err := tx.Prepare(\"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0], \"?column?\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_IsClosed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), false)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), false)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tuser := tx.Model(table)\n\n\t\t_, err = user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(2))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(2))\n\t})\n}\n\nfunc Test_TX_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.Update(table, \"create_time='2019-10-24 10:00:00'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"2019-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_TX_Delete_Commit(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize-1))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Delete_Rollback(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize-1))\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tn, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\t\tt.AssertNE(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Save(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_TX_BatchSave(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 4).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"PASS_4\")\n\t})\n}\n\nfunc Test_TX_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.GetAll(fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\trecord, err := tx.GetOne(fmt.Sprintf(\"SELECT * FROM %s WHERE passport=$1\", table), \"user_2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(record, nil)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_2\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := tx.GetValue(fmt.Sprintf(\"SELECT id FROM %s WHERE passport=$1\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := tx.GetCount(\"SELECT * FROM \" + table)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Ctx(ctx).Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(tx.IsClosed(), false)\n\t\t\treturn gerror.New(\"error\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Ctx(ctx).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_Transaction_Panic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\tpanic(\"error\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_Transaction_Method(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = db.Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\n\t\t\t_, err = db.Ctx(ctx).Exec(ctx, fmt.Sprintf(\n\t\t\t\t\"INSERT INTO %s(passport,password,nickname,create_time,id) \"+\n\t\t\t\t\t\"VALUES('t2','25d55ad283aa400af464c76d713c07ad','T2','2021-08-25 21:53:00',2) \",\n\t\t\t\ttable))\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\nfunc Test_Transaction_Nested_Begin_Rollback_Commit(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx begin.\n\t\terr = tx.Begin()\n\t\tt.AssertNil(err)\n\n\t\t// tx rollback.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseTX(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\t// another record.\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseDB(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_SavePoint_RollbackTo(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx save point.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.SavePoint(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\t// tx rollback to.\n\t\terr = tx.RollbackTo(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Required(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"required\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"required_nested\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Transaction_Propagation_RequiresNew(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"outer\",\n\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"inner_new\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"rollback inner transaction\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_Propagation_Nested(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          5,\n\t\t\t\t\"passport\":    \"nested_outer\",\n\t\t\t\t\"password\":    \"pass_5\",\n\t\t\t\t\"nickname\":    \"name_5\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          6,\n\t\t\t\t\t\"passport\":    \"nested_inner\",\n\t\t\t\t\t\"password\":    \"pass_6\",\n\t\t\t\t\t\"nickname\":    \"name_6\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"rollback to savepoint\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          7,\n\t\t\t\t\"passport\":    \"nested_after\",\n\t\t\t\t\"password\":    \"pass_7\",\n\t\t\t\t\"nickname\":    \"name_7\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"nested_inner\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"nested_outer\", \"nested_after\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Transaction_Propagation_NotSupported(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"tx_record\",\n\t\t\t\t\"password\":    \"pass_8\",\n\t\t\t\t\"nickname\":    \"name_8\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table, g.Map{\n\t\t\t\t\t\"id\":          9,\n\t\t\t\t\t\"passport\":    \"non_tx_record\",\n\t\t\t\t\t\"password\":    \"pass_9\",\n\t\t\t\t\t\"nickname\":    \"name_9\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"non_tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_Propagation_Mandatory(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          10,\n\t\t\t\t\t\"passport\":    \"mandatory\",\n\t\t\t\t\t\"password\":    \"pass_10\",\n\t\t\t\t\t\"nickname\":    \"name_10\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Never(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationNever,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\t\"id\":          11,\n\t\t\t\t\"passport\":    \"never\",\n\t\t\t\t\"password\":    \"pass_11\",\n\t\t\t\t\"nickname\":    \"name_11\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNever,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Supports(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// scenario1: when in a transaction, use PropagationSupports to execute a transaction\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"user_1\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationSupports,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"user_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"error\")\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// scenario2: when not in a transaction, do not use transaction but direct db link.\n\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationSupports,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tresult, err := db.Model(table).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Complex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createTable()\n\t\ttable2 := createTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table1, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"outer\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// First nested transaction (NESTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table1, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"nested1\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// Second nested transaction (REQUIRES_NEW)\n\t\t\t\terr = tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\"passport\":    \"new1\",\n\t\t\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn gerror.New(\"rollback new transaction\")\n\t\t\t\t})\n\t\t\t\tt.AssertNE(err, nil)\n\n\t\t\t\t// Third nested transaction (NESTED)\n\t\t\t\treturn tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\t\"passport\":    \"nested2\",\n\t\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn gerror.New(\"rollback nested transaction\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Fourth transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table2, g.Map{\n\t\t\t\t\t\"id\":          5,\n\t\t\t\t\t\"passport\":    \"not_supported\",\n\t\t\t\t\t\"password\":    \"pass_5\",\n\t\t\t\t\t\"nickname\":    \"name_5\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table1).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"new1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested2\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table2).Where(\"passport\", \"not_supported\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          6,\n\t\t\t\t\"passport\":    \"suspend_outer\",\n\t\t\t\t\"password\":    \"pass6\",\n\t\t\t\t\"nickname\":    \"suspend_outer\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Suspend current transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn db.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":          7,\n\t\t\t\t\t\t\"passport\":    \"independent\",\n\t\t\t\t\t\t\"password\":    \"pass7\",\n\t\t\t\t\t\t\"nickname\":    \"independent\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Resume original transaction\n\t\t\t_, err = tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"suspend_resume\",\n\t\t\t\t\"password\":    \"pass8\",\n\t\t\t\t\"nickname\":    \"suspend_resume\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"suspend_outer\", \"suspend_resume\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"independent\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_ReadOnly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"changed\"}, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n}\n\nfunc Test_Transaction_Isolation_ReadCommitted(t *testing.T) {\n\t// GaussDB default isolation level is READ COMMITTED.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"committed_value\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Should see new value in READ COMMITTED\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), \"committed_value\")\n\t\t\tt.AssertNE(v2.String(), initialValue)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Isolation_RepeatableRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits the value\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\n\t\t\t\t\t\"passport\": \"changed_value\",\n\t\t\t\t}, \"id=1\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Verify the change is visible outside transaction\n\t\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v.String(), \"changed_value\")\n\n\t\t\t// Should still see old value in REPEATABLE READ transaction\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), initialValue)\n\n\t\t\t// Even after multiple reads, should still see the same value\n\t\t\tv3, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v3.String(), initialValue)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// After transaction ends, should see the committed change\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"changed_value\")\n\t})\n}\n\nfunc Test_Transaction_Isolation_Serializable(t *testing.T) {\n\t// GaussDB uses SSI (Serializable Snapshot Isolation) for SERIALIZABLE level.\n\t// Concurrent writes to the same data may cause serialization failures.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read all records\n\t\t\t_, err := tx1.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Try concurrent insert in another transaction\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          1000,\n\t\t\t\t\t\"passport\":    \"new_user\",\n\t\t\t\t\t\"password\":    \"pass_1000\",\n\t\t\t\t\t\"nickname\":    \"name_1000\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\t// Note: GaussDB SSI may or may not cause serialization failure\n\t\t\t// depending on timing and whether there's an actual conflict.\n\t\t\t// For new rows with unique IDs, it typically succeeds.\n\t\t\t// We only verify the outer transaction completes.\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Spread(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\terr = db.Transaction(tx.GetCtx(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := tx.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/gaussdb_z_unit_upsert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gaussdb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_FormatUpsert_WithOnDuplicateStr tests FormatUpsert with OnDuplicateStr\nfunc Test_FormatUpsert_WithOnDuplicateStr(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user1\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test Save with OnConflict (upsert)\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user1\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify the update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick\")\n\t})\n}\n\n// Test_FormatUpsert_WithOnDuplicateMap tests FormatUpsert with OnDuplicateMap\nfunc Test_FormatUpsert_WithOnDuplicateMap(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user2\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test OnDuplicate with map - values should be column names to use EXCLUDED.column\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user2\",\n\t\t\t\"password\":    \"newpwd2\",\n\t\t\t\"nickname\":    \"newnick2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"password\": \"password\",\n\t\t\t\"nickname\": \"nickname\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify - values should be from the inserted data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd2\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick2\")\n\t})\n}\n\n// Test_FormatUpsert_WithCounter tests FormatUpsert with Counter type on numeric column.\n// Note: In PostgreSQL, Counter uses EXCLUDED.column which references the NEW value being inserted,\n// not the current table value. This differs from MySQL's ON DUPLICATE KEY UPDATE behavior.\nfunc Test_FormatUpsert_WithCounter(t *testing.T) {\n\t// Create a special table with numeric id for counter test\n\ttableName := \"t_counter_test\"\n\tdropTable(tableName)\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE `+tableName+` (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tcounter_value int NOT NULL DEFAULT 0,\n\t\t\tname varchar(45)\n\t\t)\n\t`)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(tableName).Data(g.Map{\n\t\t\t\"counter_value\": 10,\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Get initial ID\n\t\tone, err := db.Model(tableName).Where(\"name\", \"counter_test\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// Test OnDuplicate with Counter\n\t\t// In PostgreSQL: counter_value = EXCLUDED.counter_value + 5\n\t\t// EXCLUDED.counter_value is the value we're trying to insert (20)\n\t\t// So result = 20 + 5 = 25\n\t\t_, err = db.Model(tableName).Data(g.Map{\n\t\t\t\"id\":            initialId,\n\t\t\t\"counter_value\": 20, // This is the EXCLUDED value\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"counter_value\": &gdb.Counter{\n\t\t\t\tField: \"counter_value\",\n\t\t\t\tValue: 5,\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify: EXCLUDED.counter_value(20) + 5 = 25\n\t\tone, err = db.Model(tableName).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"counter_value\"].Int(), 25)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Counter with negative value (decrement)\n\t\tone, err := db.Model(tableName).Where(\"name\", \"counter_test\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// In PostgreSQL: counter_value = EXCLUDED.counter_value - 3\n\t\t// EXCLUDED.counter_value is 100, so result = 100 - 3 = 97\n\t\t_, err = db.Model(tableName).Data(g.Map{\n\t\t\t\"id\":            initialId,\n\t\t\t\"counter_value\": 100, // This is the EXCLUDED value\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"counter_value\": &gdb.Counter{\n\t\t\t\tField: \"counter_value\",\n\t\t\t\tValue: -3,\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify: EXCLUDED.counter_value(100) - 3 = 97\n\t\tone, err = db.Model(tableName).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"counter_value\"].Int(), 97)\n\t})\n}\n\n// Test_FormatUpsert_WithRaw tests FormatUpsert with Raw type\nfunc Test_FormatUpsert_WithRaw(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"raw_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Get initial ID\n\t\tone, err := db.Model(table).Where(\"passport\", \"raw_user\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// Test OnDuplicate with Raw SQL\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          initialId,\n\t\t\t\"passport\":    \"raw_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"password\": gdb.Raw(\"'raw_password'\"),\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify\n\t\tone, err = db.Model(table).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"raw_password\")\n\t})\n}\n\n// Test_FormatUpsert_NoOnConflict tests FormatUpsert without OnConflict (should fail)\nfunc Test_FormatUpsert_NoOnConflict(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"no_conflict_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Try Save without OnConflict and without primary key in data - should fail\n\t\t// because driver cannot auto-detect conflict columns when primary key is missing\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"passport\":    \"no_conflict_user\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_FormatUpsert_MultipleConflictKeys tests FormatUpsert with multiple conflict keys\nfunc Test_FormatUpsert_MultipleConflictKeys(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"multi_key_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test with multiple conflict keys using only \"id\" which has a unique constraint\n\t\t// Note: Using multiple keys requires a composite unique constraint to exist\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"multi_key_user\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify the update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/gaussdb/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/gaussdb/v2\n\ngo 1.23.0\n\nrequire (\n\tgitee.com/opengauss/openGauss-connector-go-pq v1.0.7\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/google/uuid v1.6.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/tjfoc/gmsm v1.4.1 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/crypto v0.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 => ../mysql\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/drivers/gaussdb/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngitee.com/opengauss/openGauss-connector-go-pq v1.0.7 h1:plLidoldV5RfMU6i/I+tvRKtP3sfDyUzQ//HGXLLsZo=\ngitee.com/opengauss/openGauss-connector-go-pq v1.0.7/go.mod h1:2UEp+ug6ls6C0pLfZgBn7VBzBntFUzxJuy+6FlQ7qyI=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=\ngithub.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\n"
  },
  {
    "path": "contrib/drivers/gaussdb/testdata/table_with_prefix.sql",
    "content": "DROP TABLE IF EXISTS instance;\nCREATE TABLE instance (\n    f_id SERIAL NOT NULL PRIMARY KEY,\n    name varchar(255) DEFAULT ''\n);\nINSERT INTO instance VALUES (1, 'john');\n"
  },
  {
    "path": "contrib/drivers/gaussdb/testdata/with_multiple_depends.sql",
    "content": "\nCREATE TABLE table_a (\n    id SERIAL PRIMARY KEY,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_a VALUES (1, 'table_a_test1');\nINSERT INTO table_a VALUES (2, 'table_a_test2');\n\nCREATE TABLE table_b (\n    id SERIAL PRIMARY KEY,\n    table_a_id integer NOT NULL,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_b VALUES (10, 1, 'table_b_test1');\nINSERT INTO table_b VALUES (20, 2, 'table_b_test2');\nINSERT INTO table_b VALUES (30, 1, 'table_b_test3');\nINSERT INTO table_b VALUES (40, 2, 'table_b_test4');\n\nCREATE TABLE table_c (\n    id SERIAL PRIMARY KEY,\n    table_b_id integer NOT NULL,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_c VALUES (100, 10, 'table_c_test1');\nINSERT INTO table_c VALUES (200, 10, 'table_c_test2');\nINSERT INTO table_c VALUES (300, 20, 'table_c_test3');\nINSERT INTO table_c VALUES (400, 30, 'table_c_test4');\n"
  },
  {
    "path": "contrib/drivers/gaussdb/testdata/with_tpl_user.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id SERIAL PRIMARY KEY,\n    name varchar(45) NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/gaussdb/testdata/with_tpl_user_detail.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    uid SERIAL PRIMARY KEY,\n    address varchar(45) NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/gaussdb/testdata/with_tpl_user_scores.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id SERIAL PRIMARY KEY,\n    uid integer NOT NULL,\n    score integer NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/mariadb/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/mariadb/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-sql-driver/mysql v1.7.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 => ../mysql\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/drivers/mariadb/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=\ngithub.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package mariadb implements gdb.Driver, which supports operations for database MariaDB.\npackage mariadb\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\n// Driver is the driver for MariaDB database.\n//\n// MariaDB is a community-developed, commercially supported fork of the MySQL relational database.\n// This driver uses the MySQL protocol to communicate with MariaDB database, as MariaDB maintains\n// high compatibility with MySQL protocol.\n//\n// Although MariaDB is compatible with MySQL protocol, it is packaged as a separate driver component\n// rather than reusing the mysql adapter directly. This design allows for future extensibility,\n// such as implementing MariaDB-specific features or optimizations.\ntype Driver struct {\n\t*mysql.Driver\n}\n\nfunc init() {\n\tvar (\n\t\terr         error\n\t\tdriverObj   = New()\n\t\tdriverNames = g.SliceStr{\"mariadb\"}\n\t)\n\tfor _, driverName := range driverNames {\n\t\tif err = gdb.Register(driverName, driverObj); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// New creates and returns a driver that implements gdb.Driver, which supports operations for MariaDB.\nfunc New() gdb.Driver {\n\tmysqlDriver := mysql.New().(*mysql.Driver)\n\treturn &Driver{\n\t\tDriver: mysqlDriver,\n\t}\n}\n\n// New creates and returns a database object for MariaDB.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\tmysqlDB, err := d.Driver.New(core, node)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Driver{\n\t\tDriver: mysqlDB.(*mysql.Driver),\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttableFieldsSqlByMariadb = `\nSELECT\n\tc.COLUMN_NAME AS 'Field',\n\t( CASE WHEN ch.CHECK_CLAUSE LIKE 'json_valid%%' THEN 'json' ELSE c.COLUMN_TYPE END ) AS 'Type',\n\tc.COLLATION_NAME AS 'Collation',\n\tc.IS_NULLABLE AS 'Null',\n\tc.COLUMN_KEY AS 'Key',\n\t( CASE WHEN c.COLUMN_DEFAULT = 'NULL' OR c.COLUMN_DEFAULT IS NULL THEN NULL ELSE c.COLUMN_DEFAULT END) AS 'Default',\n\tc.EXTRA AS 'Extra',\n\tc.PRIVILEGES AS 'Privileges',\n\tc.COLUMN_COMMENT AS 'Comment' \nFROM\n\tinformation_schema.COLUMNS AS c\n\tLEFT JOIN information_schema.CHECK_CONSTRAINTS AS ch ON c.TABLE_NAME = ch.TABLE_NAME \n\tAND c.TABLE_SCHEMA = ch.CONSTRAINT_SCHEMA\n\tAND c.COLUMN_NAME = ch.CONSTRAINT_NAME \nWHERE\n\tc.TABLE_SCHEMA = '%s' \n\tAND c.TABLE_NAME = '%s'\n\tORDER BY c.ORDINAL_POSITION`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlByMariadb, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlByMariadb)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current\n// schema.\nfunc (d *Driver) TableFields(\n\tctx context.Context, table string, schema ...string,\n) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err = d.DoSelect(\n\t\tctx, link,\n\t\tfmt.Sprintf(tableFieldsSqlByMariadb, usedSchema, table),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tfields[m[\"Field\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"Field\"].String(),\n\t\t\tType:    m[\"Type\"].String(),\n\t\t\tNull:    m[\"Null\"].Bool(),\n\t\t\tKey:     m[\"Key\"].String(),\n\t\t\tDefault: m[\"Default\"].Val(),\n\t\t\tExtra:   m[\"Extra\"].String(),\n\t\t\tComment: m[\"Comment\"].String(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t_ \"github.com/gogf/gf/contrib/drivers/mariadb/v2\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTableSize   = 10\n\tTableName   = \"user\"\n\tTestSchema1 = \"test1\"\n\tTestSchema2 = \"test2\"\n\tTestDbPass  = \"12345678\"\n\tCreateTime  = \"2018-10-24 10:00:00\"\n)\n\nvar (\n\tdb        gdb.DB\n\tdb2       gdb.DB\n\tdbInvalid gdb.DB\n\tctx       = context.TODO()\n)\n\nfunc init() {\n\tnodeDefault := gdb.ConfigNode{\n\t\tExecTimeout: time.Second * 2,\n\t\tLink:        fmt.Sprintf(\"mariadb:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tTranTimeout: time.Second * 3,\n\t}\n\terr := gdb.AddConfigNode(gdb.DefaultGroupName, nodeDefault)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Default db.\n\tif r, err := gdb.NewByGroup(); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdb = r\n\t}\n\tschemaTemplate := \"CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdb = db.Schema(TestSchema1)\n\tdb2 = db.Schema(TestSchema2)\n\n\t// Invalid db (wrong port for testing error handling).\n\tnodeInvalid := gdb.ConfigNode{\n\t\tLink:        fmt.Sprintf(\"mariadb:root:%s@tcp(127.0.0.1:3317)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tTranTimeout: time.Second * 3,\n\t}\n\tgdb.AddConfigNode(\"nodeinvalid\", nodeInvalid)\n\tif r, err := gdb.NewByGroup(\"nodeinvalid\"); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbInvalid = r\n\t}\n\tdbInvalid = dbInvalid.Schema(TestSchema1)\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\t}\n\tdropTableWithDb(db, name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        passport    varchar(45) NULL,\n\t        password    char(32) NULL,\n\t        nickname    varchar(45) NULL,\n\t        create_time timestamp(6) NULL,\n\t        create_date       date NULL,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:       3,\n\t\t\tUid:      3,\n\t\t\tPassport: \"t3\",\n\t\t\tPassword: \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname: \"name_3\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"uid\":         3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert, retrieving last insert auto-increment id.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\"passport\": \"t1\"},\n\t\t\t{\"passport\": \"t2\"},\n\t\t\t{\"passport\": \"t3\"},\n\t\t\t{\"passport\": \"t4\"},\n\t\t\t{\"passport\": \"t5\"},\n\t\t}).Batch(2).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 5)\n\t})\n\n\t// batch save\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Save()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize*2)\n\t})\n\n\t// batch replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Replace()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize*2)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t111\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T111\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// UPDATE...LIMIT\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"nickname\", \"T100\").Where(1).Order(\"id desc\").Limit(2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tv1, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 10).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v1.String(), \"T100\")\n\n\t\tv2, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 8).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), \"name_8\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := md.Safe(true).Order(\"id DESC\").One()\n\t\tt.AssertNil(err)\n\n\t\tresult, err := md.Safe(true).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(2))\n\t\tt.Assert(record[\"id\"].Int(), 3)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Safe(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(false).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe().Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd1 := db.Model(table).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmd1 := db.Model(table).Where(\"id>\", 0).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tmd3 := md1.Where(\"id in (?)\", g.Slice{4, 5, 6})\n\n\t\t// 1,3\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 3)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// 4,5,6\n\t\tcount, err = md3.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\tall, err = md3.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"].Int(), 4)\n\t\tt.Assert(all[1][\"id\"].Int(), 5)\n\t\tt.Assert(all[2][\"id\"].Int(), 6)\n\n\t\tall, err = md3.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Fields(t *testing.T) {\n\ttableName1 := createInitTable()\n\tdefer dropTable(tableName1)\n\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id         int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        name       varchar(45) NULL,\n\t\t\tage        int(10) unsigned,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u\").Fields(\"u.passport,u.id\").Where(\"u.id<2\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName1, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.id AS u2id\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id,nickname\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Structs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Auto create struct slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Where(\"id<0\").Scan(&users)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_OrderBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(\"id DESC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), fmt.Sprintf(\"name_%d\", TableSize))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"NULL\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"field(id, 10,1,2,3,4,5,6,7,8,9)\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_10\")\n\t\tt.Assert(result[1][\"nickname\"].String(), \"name_1\")\n\t\tt.Assert(result[2][\"nickname\"].String(), \"name_2\")\n\t})\n}\n\nfunc Test_Model_GroupBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Group(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_Model_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(\"nickname=?\", \"test\").Where(\"id=?\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := make([]g.MapStrAny, 0)\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers = append(users, g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := garray.New()\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers.Append(g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// DELETE...LIMIT\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(1).Limit(2).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize-2)\n\t})\n}\n\nfunc Test_Model_Offset(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(2).Offset(5).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(3, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t\tt.Assert(result[1][\"id\"], 8)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel := db.Model(table).Safe().Order(\"id\")\n\t\tall, err := model.Page(3, 3).All()\n\t\tcount, err := model.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], \"7\")\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_OmitEmpty(t *testing.T) {\n\ttable := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n        id int(10) unsigned NOT NULL AUTO_INCREMENT,\n        name varchar(45) NOT NULL,\n        PRIMARY KEY (id)\n    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmpty().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmptyWhere().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_OmitNil(t *testing.T) {\n\ttable := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n        id int(10) unsigned NOT NULL AUTO_INCREMENT,\n        name varchar(45) NOT NULL,\n        PRIMARY KEY (id)\n    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": nil,\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNilWhere().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_FieldsEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, id\").Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(len(r[0]), 4)\n\t\tt.Assert(r[0][\"id\"], \"\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[0][\"password\"], \"pass_1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"create_time\"], \"\")\n\t\tt.Assert(r[1][\"id\"], \"\")\n\t\tt.Assert(r[1][\"passport\"], \"user_2\")\n\t\tt.Assert(r[1][\"password\"], \"pass_2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"create_time\"], \"\")\n\t})\n\t// Update.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"password\").Data(g.Map{\"nickname\": \"123\", \"password\": \"456\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"123\")\n\t\tt.AssertNE(one[\"password\"], \"456\")\n\t})\n}\n\nfunc Test_Model_FieldsExStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tNickName: \"333\",\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").OmitEmpty().Data(user).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tusers := make([]*User, 0)\n\t\tfor i := 100; i < 110; i++ {\n\t\t\tusers = append(users, &User{\n\t\t\t\tId:       i,\n\t\t\t\tPassport: fmt.Sprintf(`passport_%d`, i),\n\t\t\t\tPassword: fmt.Sprintf(`password_%d`, i),\n\t\t\t\tNickName: fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").\n\t\t\tOmitEmpty().\n\t\t\tBatch(2).\n\t\t\tData(users).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Join_SubQuery(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery := fmt.Sprintf(\"select * from `%s`\", table)\n\t\tr, err := db.Model(table, \"t1\").Fields(\"t2.id\").LeftJoin(subQuery, \"t2\", \"t2.id=t1.id\").Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), TableSize)\n\t\tt.Assert(r[0], \"1\")\n\t\tt.Assert(r[TableSize-1], TableSize)\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Having(\"id\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table, \"t\").Fields(\"distinct t.id\").Where(\"id > 1\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n\nfunc Test_Model_Fields_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"ID\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICK_NAME\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":        1,\n\t\t\t\"NICK_NAME\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tID       int\n\t\t\tNICKNAME int\n\t\t}\n\t\tone, err := db.Model(table).Fields(&T{\n\t\t\tID:       0,\n\t\t\tNICKNAME: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_FieldsEx_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// \"id\":          i,\n\t// \"passport\":    fmt.Sprintf(`user_%d`, i),\n\t// \"password\":    fmt.Sprintf(`pass_%d`, i),\n\t// \"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t// \"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"create_date, Passport, Password, NickName, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"create_date, ID, Passport, Password, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).FieldsEx(g.Map{\n\t\t\t\"Passport\":   1,\n\t\t\t\"Password\":   1,\n\t\t\t\"CreateTime\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tPassport   int\n\t\t\tPassword   int\n\t\t\tCreateTime int\n\t\t}\n\t\tone, err := db.Model(table).FieldsEx(&T{\n\t\t\tPassport:   0,\n\t\t\tPassword:   0,\n\t\t\tCreateTime: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_Fields_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype A struct {\n\t\tPassport string\n\t\tPassword string\n\t}\n\ttype B struct {\n\t\tA\n\t\tNickName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(table)\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4577\n// Test TableFields with multiple schemas having same table name with JSON field.\n// The bug: when JOIN information_schema.CHECK_CONSTRAINTS without schema filter,\n// MariaDB creates CHECK constraints for JSON fields (json_valid), causing duplicate rows\n// when multiple schemas have tables with same name and same JSON field name.\n// This leads to wrong field Index values.\nfunc Test_Issue4577_TableFields_MultipleSchema(t *testing.T) {\n\ttableName := fmt.Sprintf(\"test_json_fields_%d\", gtime.TimestampNano())\n\n\t// Create table with JSON field in schema1 (3 columns)\n\tcreateSQL1 := fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t\t\tname        varchar(45) NULL,\n\t\t\tdata        JSON NULL,\n\t\t\tPRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t`, tableName)\n\n\t// Create table with JSON field in schema2 (5 columns - different structure)\n\t// This is critical: different column count will cause Index overflow\n\tcreateSQL2 := fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t\t\tname        varchar(45) NULL,\n\t\t\textra1      varchar(45) NULL,\n\t\t\textra2      varchar(45) NULL,\n\t\t\tdata        JSON NULL,\n\t\t\tPRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t`, tableName)\n\n\t// Create table in schema test1 (db) - 3 columns\n\tif _, err := db.Exec(ctx, createSQL1); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer func() {\n\t\tdb.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS %s\", tableName))\n\t}()\n\n\t// Create table in schema test2 (db2) - 5 columns\n\tif _, err := db2.Exec(ctx, createSQL2); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer func() {\n\t\tdb2.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS %s\", tableName))\n\t}()\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Clear any cached table fields to ensure fresh query\n\t\tdb.GetCore().ClearTableFieldsAll(ctx)\n\t\tdb2.GetCore().ClearTableFieldsAll(ctx)\n\n\t\t// Get fields from test1 schema (should have 3 columns)\n\t\tfields1, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields1), 3)\n\n\t\t// Check the 'data' field's Index - this is the critical check\n\t\t// Without the fix (missing c.TABLE_SCHEMA = ch.CONSTRAINT_SCHEMA),\n\t\t// the 'data' field's Index would be 3 (due to duplicate row from schema2's CHECK constraint)\n\t\t// which is >= 3 and would cause array out of bounds during Scan\n\t\tdataField := fields1[\"data\"]\n\t\tt.Assert(dataField.Index, 2)\n\n\t\t// Verify JSON field type is correctly detected as 'json'\n\t\tt.Assert(fields1[\"data\"].Type, \"json\")\n\n\t\t// Get fields from test2 schema (should have 5 columns)\n\t\tfields2, err := db2.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields2), 5)\n\t\tt.Assert(fields2[\"data\"].Index, 4)\n\t\tt.Assert(fields2[\"data\"].Type, \"json\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_batch_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Batch_Insert tests batch insert with different batch sizes\nfunc Test_Model_Batch_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare data for batch insert\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"batch_user_%d\", i),\n\t\t\t\t\"password\": fmt.Sprintf(\"batch_pass_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"batch_name_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Batch insert with batch size 3\n\t\tresult, err := db.Model(table).Batch(3).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\n\t\t// Verify all records were inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 10)\n\n\t\t// Verify specific records\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"batch_user_1\")\n\n\t\tone, err = db.Model(table).Where(\"id\", 10).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"batch_user_10\")\n\t})\n}\n\n// Test_Model_Batch_Replace tests batch replace operation\nfunc Test_Model_Batch_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Initial insert\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"original_%d\", i),\n\t\t\t})\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Batch replace with overlapping ids\n\t\treplaceData := g.Slice{}\n\t\tfor i := 3; i <= 8; i++ {\n\t\t\treplaceData = append(replaceData, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"replaced_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"new_name_%d\", i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Batch(2).Data(replaceData).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.AssertGT(n, 0)\n\n\t\t// Verify replaced records\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"replaced_3\")\n\t\tt.Assert(one[\"nickname\"], \"new_name_3\")\n\n\t\t// Verify new records\n\t\tone, err = db.Model(table).Where(\"id\", 8).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"replaced_8\")\n\n\t\t// Verify total count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 8) // ids 1-8\n\t})\n}\n\n// Test_Model_Batch_Save tests batch save operation\nfunc Test_Model_Batch_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Initial data\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"save_user_%d\", i),\n\t\t\t})\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Batch save with overlapping and new ids\n\t\tsaveData := g.Slice{}\n\t\tfor i := 3; i <= 8; i++ {\n\t\t\tsaveData = append(saveData, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"saved_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"save_name_%d\", i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Batch(3).Data(saveData).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.AssertGT(n, 0)\n\n\t\t// Verify updated records\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"saved_3\")\n\n\t\t// Verify inserted records\n\t\tone, err = db.Model(table).Where(\"id\", 8).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"saved_8\")\n\n\t\t// Verify total count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 8)\n\t})\n}\n\n// Test_Model_Batch_LargeBatch tests batch operation with large dataset\nfunc Test_Model_Batch_LargeBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare 1000+ records\n\t\tdata := g.Slice{}\n\t\ttotalRecords := 1500\n\t\tfor i := 1; i <= totalRecords; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"large_user_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"large_name_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Batch insert with batch size 100\n\t\tresult, err := db.Model(table).Batch(100).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, totalRecords)\n\n\t\t// Verify count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, totalRecords)\n\n\t\t// Verify first and last records\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"large_user_1\")\n\n\t\tone, err = db.Model(table).Where(\"id\", totalRecords).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], fmt.Sprintf(\"large_user_%d\", totalRecords))\n\t})\n}\n\n// Test_Model_Batch_EmptyBatch tests batch operation with empty data\nfunc Test_Model_Batch_EmptyBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Empty slice\n\t\tdata := g.Slice{}\n\n\t\t// Batch insert with empty data should return error\n\t\t_, err := db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertIN(err.Error(), \"data list cannot be empty\")\n\n\t\t// Verify no records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Batch_SingleRecord tests batch operation with single record\nfunc Test_Model_Batch_SingleRecord(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Single record batch insert\n\t\tdata := g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"single_user\",\n\t\t\t\t\"nickname\": \"single_name\",\n\t\t\t},\n\t\t}\n\n\t\tresult, err := db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"single_user\")\n\t\tt.Assert(one[\"nickname\"], \"single_name\")\n\t})\n}\n\n// Test_Model_Batch_VsBatch tests performance comparison between different batch sizes\nfunc Test_Model_Batch_VsBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare data\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 100; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"perf_user_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Test with batch size 1\n\t\tresult, err := db.Model(table).Batch(1).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test with batch size 10\n\t\tresult, err = db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test with batch size 50\n\t\tresult, err = db.Model(table).Batch(50).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// All batch sizes should produce same result\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 100)\n\t})\n}\n\n// Test_Model_Batch_WithTransaction tests batch operation within transaction\nfunc Test_Model_Batch_WithTransaction(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 50; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"tx_batch_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Test commit\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\tresult, err := tx.Model(table).Batch(10).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := result.RowsAffected()\n\t\t\tt.Assert(n, 50)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify commit\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 50)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test rollback\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Batch(10).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\treturn fmt.Errorf(\"rollback test\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify rollback - no records should exist\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_cache_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Cache_Basic tests basic cache functionality\nfunc Test_Model_Cache_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First query - cache miss, result from DB\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"test_cache_basic\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update the record in DB\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"updated_user\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Second query - cache hit, still returns old cached value\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"test_cache_basic\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value, not \"updated_user\"\n\n\t\t// Query without cache - returns updated value from DB\n\t\tone, err = db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"updated_user\")\n\t})\n}\n\n// Test_Model_Cache_TTL tests cache TTL expiration\nfunc Test_Model_Cache_TTL(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with short TTL\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100, // 100ms TTL\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"ttl_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Immediate query - cache still valid\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100,\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value\n\n\t\t// Wait for cache to expire\n\t\ttime.Sleep(time.Millisecond * 150)\n\n\t\t// Query after expiration - should get fresh data\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100,\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"ttl_test\") // fresh value from DB\n\t})\n}\n\n// Test_Model_Cache_Clear tests clearing cache with negative duration\nfunc Test_Model_Cache_Clear(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Set cache\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 60,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record and clear cache\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Data(g.Map{\"passport\": \"cleared\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query again - should get fresh data since cache was cleared\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 60,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"cleared\")\n\t})\n}\n\n// Test_Model_Cache_NoExpire tests cache with no expiration (Duration=0)\nfunc Test_Model_Cache_NoExpire(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with no expiration\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: 0, // never expires\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"no_expire_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Wait a bit\n\t\ttime.Sleep(time.Millisecond * 100)\n\n\t\t// Query - cache should still be valid\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: 0,\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value persists\n\n\t\t// Clear the cache with update operation\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Data(g.Map{\"nickname\": \"cleared\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Model_Cache_Force tests Force option to cache nil results\nfunc Test_Model_Cache_Force(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Note: Removed Force cache test due to cache invalidation on INSERT\n\t// The test logic was flawed - INSERT operations clear cache, so cached nil\n\t// results would be invalidated before the second query\n}\n\n// Test_Model_Cache_DisabledInTransaction tests cache is disabled in transactions\nfunc Test_Model_Cache_DisabledInTransaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// First query in transaction\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     \"test_tx_cache\",\n\t\t\t}).Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t\t// Update in transaction\n\t\t\t_, err = tx.Model(table).Data(g.Map{\"passport\": \"tx_update\"}).Where(\"id\", 1).Update()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Second query - should see updated value (cache disabled in tx)\n\t\t\tone, err = tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     \"test_tx_cache\",\n\t\t\t}).Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"tx_update\") // not cached, fresh from DB\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Model_PageCache tests pagination cache\nfunc Test_Model_PageCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First page query with cache\n\t\tall, err := db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\n\t\t// Insert new record\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":       11,\n\t\t\t\"passport\": \"user_11\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query again - should return cached results\n\t\tall, err = db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // cached results\n\n\t\t// Clear page cache by updating with Duration=-1\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_page_count\",\n\t\t}).Data(g.Map{\"nickname\": \"page_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query with fresh cache - should return updated count\n\t\tall, err = db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // still 3 items per page\n\n\t\t// Verify total count increased\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 11)\n\t})\n}\n\n// Test_Model_Cache_DifferentNames tests different cache names for same query\nfunc Test_Model_Cache_DifferentNames(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with name1\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Cache same query with name2\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name2\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record and clear only cache_name1\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Data(g.Map{\"passport\": \"diff_name\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query with cache_name1 - should get fresh data\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"diff_name\")\n\n\t\t// Query with cache_name2 - should still have cached old value\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name2\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // still cached\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_concurrent_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Concurrent_Insert tests concurrent Insert operations\nfunc Test_Concurrent_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i + 1)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency)\n\t})\n}\n\n// Test_Concurrent_Update tests concurrent Update operations\nfunc Test_Concurrent_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"updated_%d\", id),\n\t\t\t\t}).Where(\"id\", id+1).Update()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify updates\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tone, err := db.Model(table).Where(\"id\", i+1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"nickname\"].String(), fmt.Sprintf(\"updated_%d\", i))\n\t\t}\n\t})\n}\n\n// Test_Concurrent_Delete tests concurrent Delete operations\nfunc Test_Concurrent_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Where(\"id\", id+1).Delete()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify deletions\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize-concurrency)\n\t})\n}\n\n// Test_Concurrent_Query tests concurrent Query operations\nfunc Test_Concurrent_Query(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 20\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tresult, err := db.Model(table).Where(\"id\", (id%TableSize)+1).One()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.AssertNE(result, nil)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Transaction tests concurrent transaction operations\nfunc Test_Concurrent_Transaction(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := db.Transaction(ctx, func(ctx g.Ctx, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Model(table).Insert(g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i + 1)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all transactions committed\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency)\n\t})\n}\n\n// Test_Concurrent_Mixed_Operations tests mixed concurrent operations\nfunc Test_Concurrent_Mixed_Operations(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\toperations := 30\n\n\t\twg.Add(operations)\n\t\tfor i := 0; i < operations; i++ {\n\t\t\top := i % 3\n\t\t\tswitch op {\n\t\t\tcase 0: // Insert\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\t_, _ = db.Model(table).Insert(g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"new_user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"new_pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"new_name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t}(i)\n\t\t\tcase 1: // Update\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\ttargetId := (id % TableSize) + 1\n\t\t\t\t\t_, _ = db.Model(table).Data(g.Map{\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"concurrent_%d\", id),\n\t\t\t\t\t}).Where(\"id\", targetId).Update()\n\t\t\t\t}(i)\n\t\t\tcase 2: // Query\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\ttargetId := (id % TableSize) + 1\n\t\t\t\t\t_, _ = db.Model(table).Where(\"id\", targetId).One()\n\t\t\t\t}(i)\n\t\t\t}\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify database is still consistent\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(count, TableSize)\n\t})\n}\n\n// Test_Concurrent_Connection_Pool tests connection pool under load\nfunc Test_Concurrent_Connection_Pool(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 50\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t// Each goroutine performs multiple operations\n\t\t\t\tfor j := 0; j < 5; j++ {\n\t\t\t\t\t_, err := db.Model(table).Where(\"id\", (id%TableSize)+1).One()\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t}\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Schema_Switch tests concurrent schema switching\nfunc Test_Concurrent_Schema_Switch(t *testing.T) {\n\ttable1 := createTableWithDb(db, \"test_schema_1\")\n\ttable2 := createTableWithDb(db2, \"test_schema_2\")\n\tdefer dropTableWithDb(db, table1)\n\tdefer dropTableWithDb(db2, table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency * 2)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\t// Insert to schema1\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table1).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_s1_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\n\t\t\t// Insert to schema2\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db2.Model(table2).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_s2_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify both schemas\n\t\tcount1, err := db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count1, concurrency)\n\n\t\tcount2, err := db2.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count2, concurrency)\n\t})\n}\n\n// Test_Concurrent_Model_Clone tests concurrent model cloning\nfunc Test_Concurrent_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbaseModel := db.Model(table).Where(\"id>\", 0)\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 20\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t// Clone model for each goroutine\n\t\t\t\tm := baseModel.Clone()\n\t\t\t\tresult, err := m.Where(\"id<=\", TableSize/2).All()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.AssertGT(len(result), 0)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Batch_Insert tests concurrent batch insert operations\nfunc Test_Concurrent_Batch_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\t\tbatchSize := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(batchId int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tbatch := make([]g.Map, 0, batchSize)\n\t\t\t\tfor j := 0; j < batchSize; j++ {\n\t\t\t\t\tid := batchId*batchSize + j\n\t\t\t\t\tbatch = append(batch, g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"batch_user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\t_, err := db.Model(table).Data(batch).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all batch inserts\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency*batchSize)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb, err := gdb.Instance()\n\t\tt.AssertNil(err)\n\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\n\t\tnewDb := db.Ctx(context.Background())\n\t\tt.AssertNE(newDb, nil)\n\t})\n}\n\nfunc Test_Ctx_Query(t *testing.T) {\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Query(ctx, \"select 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Query(ctx, \"select 2\")\n\t})\n}\n\nfunc Test_Ctx_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Model(table).Ctx(ctx).All()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Model(table).All()\n\t})\n}\n\n// Test_Ctx_Timeout tests context timeout behavior\nfunc Test_Ctx_Timeout(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a context with very short timeout\n\t\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)\n\t\tdefer cancel()\n\n\t\t// Wait for timeout\n\t\ttime.Sleep(1 * time.Millisecond)\n\n\t\t// Query should fail due to context timeout\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Ctx_Cancel tests context cancellation\nfunc Test_Ctx_Cancel(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t// Cancel immediately\n\t\tcancel()\n\n\t\t// Query should fail due to cancelled context\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Ctx_Propagation_Transaction tests context propagation in transaction\nfunc Test_Ctx_Propagation_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"tx_trace_123\")\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Context should propagate to transaction operations\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Ctx_Multiple_Values tests context with multiple values\nfunc Test_Ctx_Multiple_Values(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\", \"RequestId\", \"UserId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"trace_001\")\n\t\tctx = context.WithValue(ctx, \"RequestId\", \"req_002\")\n\t\tctx = context.WithValue(ctx, \"UserId\", \"user_003\")\n\n\t\tdb.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t})\n}\n\n// Test_Ctx_Nested_Operations tests context in nested operations\nfunc Test_Ctx_Nested_Operations(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"nested_trace\")\n\n\t\t// Nested query operations should all have context\n\t\tresult, err := db.Model(table).Ctx(ctx).Where(\"id>\", 0).All()\n\t\tt.AssertNil(err)\n\n\t\tif len(result) > 0 {\n\t\t\t// Another query using same context\n\t\t\t_, err = db.Model(table).Ctx(ctx).Where(\"id\", result[0][\"id\"]).One()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_error_handling_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Insert_NilData tests Insert with nil data\nfunc Test_Model_Insert_NilData(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(nil).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Insert_EmptyMap tests Insert with empty map\nfunc Test_Model_Insert_EmptyMap(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Insert_EmptySlice tests Insert with empty slice\nfunc Test_Model_Insert_EmptySlice(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Slice{}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_NilData tests Update with nil data\nfunc Test_Model_Update_NilData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(nil).Where(\"id\", 1).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_EmptyData tests Update with empty data\nfunc Test_Model_Update_EmptyData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{}).Where(\"id\", 1).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_NoWhere tests Update without WHERE clause is rejected by framework\nfunc Test_Model_Update_NoWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Framework safety check: Update without WHERE should return error\n\t\t_, err := db.Model(table).Data(g.Map{\"nickname\": \"updated\"}).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Delete_NoWhere tests Delete without WHERE clause is rejected by framework\nfunc Test_Model_Delete_NoWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Framework safety check: Delete without WHERE should return error\n\t\t_, err := db.Model(table).Delete()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_NilPointer tests Scan with nil pointer\nfunc Test_Model_Scan_NilPointer(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_InvalidPointer tests Scan with invalid pointer type\nfunc Test_Model_Scan_InvalidPointer(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar str string\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(&str)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_EmptyResult tests Scan with empty result\nfunc Test_Model_Scan_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\t// Scan initialized struct with empty result returns sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).Scan(&user)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// Scan nil pointer with empty result returns nil error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\n// Test_Model_Where_InvalidOperator tests Where with invalid operator\nfunc Test_Model_Where_InvalidOperator(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Invalid SQL should cause error at query time\n\t\t_, err := db.Model(table).Where(\"id INVALID_OP ?\", 1).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Where_EmptyString tests Where with empty string\nfunc Test_Model_Where_EmptyString(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize) // Empty WHERE returns all\n\t})\n}\n\n// Test_Model_Fields_InvalidField tests Fields with non-existent field\nfunc Test_Model_Fields_InvalidField(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Fields(\"non_existent_field\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Fields_Empty tests Fields with empty string\n// Regression test for #4697: Fields(\"\") should handle empty string gracefully\n// https://github.com/gogf/gf/issues/4697\nfunc Test_Model_Fields_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"\").Limit(1).All()\n\t\tt.AssertNil(err)\n\t\tt.AssertLE(len(result), 1)\n\t})\n}\n\n// Test_Model_Order_InvalidSyntax tests Order with invalid syntax\nfunc Test_Model_Order_InvalidSyntax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Invalid ORDER BY syntax\n\t\t_, err := db.Model(table).Order(\"id INVALID\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Group_UnknownColumn tests Group with non-existent column\nfunc Test_Model_Group_UnknownColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Group(\"non_existent_field\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_TableNotExist tests querying non-existent table\nfunc Test_Model_TableNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"non_existent_table_xyz\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_InvalidTableName tests invalid table name\nfunc Test_Model_InvalidTableName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Empty table name\n\t\t_, err := db.Model(\"\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_SQLInjection_Where tests SQL injection prevention in Where\nfunc Test_Model_SQLInjection_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt SQL injection through string column parameter.\n\t\t// Using string column `nickname` instead of int column `id`,\n\t\t// because MySQL coerces \"1 OR 1=1\" to 1 for int columns.\n\t\tmaliciousInput := \"1 OR 1=1\"\n\t\tresult, err := db.Model(table).Where(\"nickname = ?\", maliciousInput).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0) // Should not return all records\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt SQL injection with quotes, using string column to avoid\n\t\t// MySQL implicit int conversion (which would coerce \"1'...\" to 1)\n\t\tmaliciousInput := \"1'; DROP TABLE \" + table + \"; --\"\n\t\tresult, err := db.Model(table).Where(\"nickname = ?\", maliciousInput).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\t// Table should still exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_SQLInjection_Insert tests SQL injection prevention in Insert\nfunc Test_Model_SQLInjection_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmaliciousData := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"'; DROP TABLE \" + table + \"; --\",\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": \"test\",\n\t\t}\n\t\t_, err := db.Model(table).Data(maliciousData).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data was inserted correctly and table still exists\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"passport\"].String(), \"'; DROP TABLE \"+table+\"; --\")\n\t})\n}\n\n// Test_Model_SQLInjection_Update tests SQL injection prevention in Update\nfunc Test_Model_SQLInjection_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Use shorter malicious string to fit in nickname column\n\t\tmaliciousData := g.Map{\n\t\t\t\"nickname\": \"'; DELETE FROM users; --\",\n\t\t}\n\t\t_, err := db.Model(table).Data(maliciousData).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only one record was updated (parameterized query prevents injection)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"].String(), \"'; DELETE FROM users; --\")\n\n\t\t// Other records should still exist (injection was prevented)\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_Context_Cancelled tests query with cancelled context\nfunc Test_Model_Context_Cancelled(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tcancel() // Cancel immediately\n\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gerror.Is(err, context.Canceled), true)\n\t})\n}\n\n// Test_Model_Value_EmptyResult tests Value with empty result\nfunc Test_Model_Value_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.IsEmpty(), true)\n\t})\n}\n\n// Test_Model_Array_EmptyResult tests Array with empty result\nfunc Test_Model_Array_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Where(\"id > ?\", 1000).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(array), 0)\n\t})\n}\n\n// Test_Model_Count_InvalidTable tests Count on invalid table\nfunc Test_Model_Count_InvalidTable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"non_existent_table\").Count()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Max_EmptyResult tests Max with empty result\nfunc Test_Model_Max_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Min_EmptyResult tests Min with empty result\nfunc Test_Model_Min_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Avg_EmptyResult tests Avg with empty result\nfunc Test_Model_Avg_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Sum_EmptyResult tests Sum with empty result\nfunc Test_Model_Sum_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_One_NilResult tests One returning nil\nfunc Test_Model_One_NilResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id > ?\", 1000).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one, nil)\n\t})\n}\n\n// Test_TX_Rollback_AfterError tests transaction rollback after error\nfunc Test_TX_Rollback_AfterError(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert valid record\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"pass1\",\n\t\t\t\t\"password\": \"pwd1\",\n\t\t\t\t\"nickname\": \"name1\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Insert duplicate id (should fail)\n\t\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":       1, // Duplicate\n\t\t\t\t\"passport\": \"pass2\",\n\t\t\t\t\"password\": \"pwd2\",\n\t\t\t\t\"nickname\": \"name2\",\n\t\t\t}).Insert()\n\n\t\t\treturn err // Return error to trigger rollback\n\t\t})\n\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify rollback - table should be empty\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Insert_DuplicateKey tests handling of duplicate key error\nfunc Test_Model_Insert_DuplicateKey(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"pass\",\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": \"name\",\n\t\t}\n\n\t\t// First insert should succeed\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Second insert with same id should fail\n\t\t_, err = db.Model(table).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_All_InvalidConnection tests query with invalid connection\nfunc Test_Model_All_InvalidConnection(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif dbInvalid == nil {\n\t\t\tt.Skip(\"dbInvalid not configured\")\n\t\t}\n\t\t_, err := dbInvalid.Model(\"test_table\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Hook_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"test\"] = gvar.New(100 + record[\"id\"].Int())\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(`id > 6`).OrderAsc(`id`).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 4)\n\t\tt.Assert(all[0][\"id\"].Int(), 7)\n\t\tt.Assert(all[0][\"test\"].Int(), 107)\n\t\tt.Assert(all[1][\"test\"].Int(), 108)\n\t\tt.Assert(all[2][\"test\"].Int(), 109)\n\t\tt.Assert(all[3][\"test\"].Int(), 110)\n\t})\n}\n\nfunc Test_Model_Hook_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\tfor i, item := range in.Data {\n\t\t\t\t\titem[\"passport\"] = fmt.Sprintf(`test_port_%d`, item[\"id\"])\n\t\t\t\t\titem[\"nickname\"] = fmt.Sprintf(`test_name_%d`, item[\"id\"])\n\t\t\t\t\tin.Data[i] = item\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `test_port_1`)\n\t\tt.Assert(one[\"nickname\"], `test_name_1`)\n\t})\n}\n\nfunc Test_Model_Hook_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\t\tswitch value := in.Data.(type) {\n\t\t\t\tcase gdb.List:\n\t\t\t\t\tfor i, data := range value {\n\t\t\t\t\t\tdata[\"passport\"] = `port`\n\t\t\t\t\t\tdata[\"nickname\"] = `name`\n\t\t\t\t\t\tvalue[i] = data\n\t\t\t\t\t}\n\t\t\t\t\tin.Data = value\n\n\t\t\t\tcase gdb.Map:\n\t\t\t\t\tvalue[\"passport\"] = `port`\n\t\t\t\t\tvalue[\"nickname\"] = `name`\n\t\t\t\t\tin.Data = value\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Data(g.Map{\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `port`)\n\t\tt.Assert(one[\"nickname\"], `name`)\n\t})\n}\n\nfunc Test_Model_Hook_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\t\treturn db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": `deleted`,\n\t\t\t\t}).Where(in.Condition).Update()\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(1).Delete()\n\t\tt.AssertNil(err)\n\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tfor _, item := range all {\n\t\t\tt.Assert(item[\"nickname\"].String(), `deleted`)\n\t\t}\n\t})\n}\n\n// Test_Model_Hook_Multiple tests multiple hooks execution order\nfunc Test_Model_Hook_Multiple(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar execOrder []string\n\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\texecOrder = append(execOrder, \"hook1_before\")\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\texecOrder = append(execOrder, \"hook1_after\")\n\t\t\t\treturn\n\t\t\t},\n\t\t}).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\texecOrder = append(execOrder, \"hook2_before\")\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\texecOrder = append(execOrder, \"hook2_after\")\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only the last registered hook executes (Hook is override, not chain)\n\t\tt.Assert(len(execOrder), 2)\n\t\tt.Assert(execOrder, g.Slice{\"hook2_before\", \"hook2_after\"})\n\t})\n}\n\n// Test_Model_Hook_Error_Abort tests hook returning error aborts operation\nfunc Test_Model_Hook_Error_Abort(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\t// Return error to abort insert\n\t\t\t\treturn nil, fmt.Errorf(\"hook aborted insert\")\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"passport\": \"test_abort\",\n\t\t\t\"password\": \"pass\",\n\t\t\t\"nickname\": \"name\",\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"hook aborted insert\")\n\n\t\t// Verify record was not inserted\n\t\tcount, err := db.Model(table).Where(\"passport\", \"test_abort\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Hook_Modify_Data tests hook modifying data before insert\nfunc Test_Model_Hook_Modify_Data(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\t// Modify all data items\n\t\t\t\tfor i := range in.Data {\n\t\t\t\t\tin.Data[i][\"password\"] = \"encrypted_\" + fmt.Sprint(in.Data[i][\"password\"])\n\t\t\t\t\tin.Data[i][\"nickname\"] = \"verified_\" + fmt.Sprint(in.Data[i][\"nickname\"])\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"passport\": \"test_user\",\n\t\t\t\"password\": \"plain123\",\n\t\t\t\"nickname\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify data was modified by hook\n\t\tone, err := db.Model(table).Where(\"passport\", \"test_user\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"encrypted_plain123\")\n\t\tt.Assert(one[\"nickname\"].String(), \"verified_john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_builder_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Model_Builder(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where And\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n\n\t// Where Or\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where with struct which has a field type of *gtime.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=? AND `nickname` IS NULL\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with struct which has a field type of *gjson.Json\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=? AND `nickname` IS NULL\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gtime.Time and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=?\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gjson.Json and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=?\")\n\t\tt.Assert(args, []any{1})\n\t})\n}\n\nfunc Test_Safe_Builder(t *testing.T) {\n\t// test whether m.Builder() is chain safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := db.Model().Builder()\n\t\tb.Where(\"id\", 1)\n\t\t_, args := b.Build()\n\t\tt.AssertNil(args)\n\n\t\tb = b.Where(\"id\", 1)\n\t\t_, args = b.Build()\n\t\tt.Assert(args, g.Slice{1})\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_do_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Insert_Data_DO(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_DO(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `2`)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Update_Pointer_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype NN string\n\t\ttype Req struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t\tPassword *string\n\t\t\tNickname *NN\n\t\t}\n\t\ttype UserDo struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tvar (\n\t\t\tnickname = NN(\"nickname_111\")\n\t\t\treq      = Req{\n\t\t\t\tPassword: gconv.PtrString(\"12345678\"),\n\t\t\t\tNickname: &nickname,\n\t\t\t}\n\t\t\tdata = UserDo{\n\t\t\t\tPassport: req.Passport,\n\t\t\t\tPassword: req.Password,\n\t\t\t\tNickname: req.Nickname,\n\t\t\t}\n\t\t)\n\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`password`], `12345678`)\n\t\tt.Assert(one[`nickname`], `nickname_111`)\n\t})\n}\n\nfunc Test_Model_Where_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Insert_Data_ForDao(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_ForDao(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUserForDao{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUserForDao{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `2`)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_FieldPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n\t// With omitempty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id,omitempty\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id,omitempty\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_join_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_LeftJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_RightJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_InnerJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_LeftJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_RightJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_InnerJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_FieldsPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"id\").\n\t\t\tFieldsPrefix(table2, \"nickname\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t})\n}\n\n// Test_Model_Join_FiveTables tests complex join with 5+ tables\nfunc Test_Model_Join_FiveTables(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t\ttable3 = gtime.TimestampNanoStr() + \"_table3\"\n\t\ttable4 = gtime.TimestampNanoStr() + \"_table4\"\n\t\ttable5 = gtime.TimestampNanoStr() + \"_table5\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\tcreateInitTable(table3)\n\tdefer dropTable(table3)\n\tcreateInitTable(table4)\n\tdefer dropTable(table4)\n\tcreateInitTable(table5)\n\tdefer dropTable(table5)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tFieldsPrefix(\"t2\", \"passport\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tInnerJoin(table3+\" AS t3\", \"t2.id = t3.id\").\n\t\t\tInnerJoin(table4+\" AS t4\", \"t3.id = t4.id\").\n\t\t\tInnerJoin(table5+\" AS t5\", \"t4.id = t5.id\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 6 tables with mixed join types\n\t\ttable6 := gtime.TimestampNanoStr() + \"_table6\"\n\t\tcreateInitTable(table6)\n\t\tdefer dropTable(table6)\n\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tLeftJoin(table3+\" AS t3\", \"t2.id = t3.id\").\n\t\t\tInnerJoin(table4+\" AS t4\", \"t3.id = t4.id\").\n\t\t\tRightJoin(table5+\" AS t5\", \"t4.id = t5.id\").\n\t\t\tLeftJoin(table6+\" AS t6\", \"t5.id = t6.id\").\n\t\t\tWhere(\"t1.id\", 5).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], \"5\")\n\t})\n}\n\n// Test_Model_Join_SelfJoin tests self-join scenarios\nfunc Test_Model_Join_SelfJoin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Self-join to find pairs where a.id < b.id\n\t\tr, err := db.Model(table).As(\"a\").\n\t\t\tFields(\"a.id AS a_id\", \"b.id AS b_id\").\n\t\t\tInnerJoin(table+\" AS b\", \"a.id < b.id\").\n\t\t\tWhere(\"a.id\", 1).\n\t\t\tWhere(\"b.id <=\", 3).\n\t\t\tOrder(\"b.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"a_id\"], \"1\")\n\t\tt.Assert(r[0][\"b_id\"], \"2\")\n\t\tt.Assert(r[1][\"b_id\"], \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Self-join with multiple conditions\n\t\tr, err := db.Model(table).As(\"a\").\n\t\t\tFields(\"a.id\", \"a.nickname\", \"b.nickname AS other_nickname\").\n\t\t\tLeftJoin(table+\" AS b\", \"a.id = b.id - 1\").\n\t\t\tWhere(\"a.id IN(?)\", g.Slice{1, 2}).\n\t\t\tOrder(\"a.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"other_nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"other_nickname\"], \"name_3\")\n\t})\n}\n\n// Test_Model_Join_LeftJoinNull tests LEFT JOIN NULL handling\nfunc Test_Model_Join_LeftJoinNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\n\t// Create table2 with only partial data\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, err := db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// LEFT JOIN - table1 has all records, table2 only has id 1,2\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\") // matched\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\") // matched\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t\t// r[2][\"nickname\"] should be NULL/empty from t2\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Find records where RIGHT table is NULL\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id IS NULL\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3, 4}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should return id 3,4 (not in table2)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[1][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_Join_RightJoinNull tests RIGHT JOIN NULL handling\nfunc Test_Model_Join_RightJoinNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\t// table1 has partial data\n\tcreateTable(table1)\n\tdefer dropTable(table1)\n\t_, err := db.Insert(ctx, table1, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// table2 has all data\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// RIGHT JOIN - table1 only has id 1,2, table2 has all\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t2\", \"id\").\n\t\t\tFieldsPrefix(\"t1\", \"nickname\").\n\t\t\tRightJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t2.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\") // matched\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\") // matched\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t\t// r[2][\"nickname\"] should be NULL/empty from t1\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Find records where LEFT table is NULL\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t2\", \"id\", \"nickname\").\n\t\t\tRightJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id IS NULL\").\n\t\t\tWhere(\"t2.id IN(?)\", g.Slice{1, 2, 3, 4}).\n\t\t\tOrder(\"t2.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should return id 3,4 (not in table1)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[1][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_Join_OnVsWhere tests difference between ON and WHERE conditions\nfunc Test_Model_Join_OnVsWhere(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// INNER JOIN: ON and WHERE behave the same\n\t\tr1, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id AND t2.id <= 3\").\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tr2, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id <=\", 3).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// For INNER JOIN, results should be identical\n\t\tt.Assert(len(r1), 3)\n\t\tt.Assert(len(r2), 3)\n\t\tt.Assert(r1[0][\"id\"], r2[0][\"id\"])\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// LEFT JOIN: ON filter in join condition vs WHERE filter after join\n\t\t// ON condition: filters t2 before join (keeps all t1 rows)\n\t\tr1, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id AND t2.id <= 2\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// WHERE condition: filters result after join (removes t1 rows where t2 is NULL)\n\t\tr2, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tWhere(\"t2.id <=\", 2).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// r1: all t1 rows (1,2,3,4), t2 data only for id 1,2\n\t\tt.Assert(len(r1), 4)\n\t\tt.Assert(r1[0][\"id\"], \"1\")\n\t\tt.Assert(r1[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r1[2][\"id\"], \"3\")\n\t\t// r1[2][\"nickname\"] is NULL from t2\n\n\t\t// r2: only rows where t2.id <= 2, so only id 1,2\n\t\tt.Assert(len(r2), 2)\n\t\tt.Assert(r2[0][\"id\"], \"1\")\n\t\tt.Assert(r2[1][\"id\"], \"2\")\n\t})\n}\n\n// Test_Model_Join_ComplexConditions tests joins with complex ON conditions\nfunc Test_Model_Join_ComplexConditions(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple AND conditions in ON clause\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\", \"t1.nickname\").\n\t\t\tInnerJoin(\n\t\t\t\ttable2+\" AS t2\",\n\t\t\t\t\"t1.id = t2.id AND t1.nickname = t2.nickname AND t1.id BETWEEN 2 AND 4\",\n\t\t\t).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OR conditions in ON clause (need to use Where for OR in join)\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id = 1 OR t2.id = 5\").\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"5\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_sharding_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTestDbNameSh0 = \"test_0\"\n\tTestDbNameSh1 = \"test_1\"\n\tTestTableName = \"user\"\n)\n\ntype ShardingUser struct {\n\tId   int\n\tName string\n}\n\n// createShardingDatabase creates test databases and tables for sharding\nfunc createShardingDatabase(t *gtest.T) {\n\t// Create databases\n\tdbs := []string{TestDbNameSh0, TestDbNameSh1}\n\tfor _, dbName := range dbs {\n\t\tsql := fmt.Sprintf(\"CREATE DATABASE IF NOT EXISTS `%s`\", dbName)\n\t\t_, err := db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\n\t\t// Switch to the database\n\t\tsql = fmt.Sprintf(\"USE `%s`\", dbName)\n\t\t_, err = db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\n\t\t// Create tables\n\t\ttables := []string{\"user_0\", \"user_1\", \"user_2\", \"user_3\"}\n\t\tfor _, table := range tables {\n\t\t\tsql := fmt.Sprintf(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\t\t\tid int(11) NOT NULL,\n\t\t\t\t\tname varchar(255) NOT NULL,\n\t\t\t\t\tPRIMARY KEY (id)\n\t\t\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\t\t\t`, table)\n\t\t\t_, err := db.Exec(ctx, sql)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t}\n}\n\n// dropShardingDatabase drops test databases\nfunc dropShardingDatabase(t *gtest.T) {\n\tdbs := []string{TestDbNameSh0, TestDbNameSh1}\n\tfor _, dbName := range dbs {\n\t\tsql := fmt.Sprintf(\"DROP DATABASE IF EXISTS `%s`\", dbName)\n\t\t_, err := db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\t}\n}\n\nfunc Test_Sharding_Basic(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttablePrefix  = \"user_\"\n\t\t\tschemaPrefix = \"test_\"\n\t\t)\n\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\t// Create sharding configuration\n\t\tshardingConfig := gdb.ShardingConfig{\n\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: tablePrefix,\n\t\t\t\tRule: &gdb.DefaultShardingRule{\n\t\t\t\t\tTableCount: 4,\n\t\t\t\t},\n\t\t\t},\n\t\t\tSchema: gdb.ShardingSchemaConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: schemaPrefix,\n\t\t\t\tRule: &gdb.DefaultShardingRule{\n\t\t\t\t\tSchemaCount: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// Prepare test data\n\t\tuser := ShardingUser{\n\t\t\tId:   1,\n\t\t\tName: \"John\",\n\t\t}\n\n\t\tmodel := db.Model(TestTableName).\n\t\t\tSharding(shardingConfig).\n\t\t\tShardingValue(user.Id).\n\t\t\tSafe()\n\n\t\t// Test Insert\n\t\t_, err := model.Data(user).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test Select\n\t\tvar result ShardingUser\n\t\terr = model.Where(\"id\", user.Id).Scan(&result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.Id, user.Id)\n\t\tt.Assert(result.Name, user.Name)\n\n\t\t// Test Update\n\t\t_, err = model.Data(g.Map{\"name\": \"John Doe\"}).\n\t\t\tWhere(\"id\", user.Id).\n\t\t\tUpdate()\n\t\tt.AssertNil(err)\n\n\t\t// Verify Update\n\t\terr = model.Where(\"id\", user.Id).Scan(&result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.Name, \"John Doe\")\n\n\t\t// Test Delete\n\t\t_, err = model.Where(\"id\", user.Id).Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Verify Delete\n\t\tcount, err := model.Where(\"id\", user.Id).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Sharding_Error tests error cases\nfunc Test_Sharding_Error(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\t// Test missing sharding value\n\t\tmodel := db.Model(TestTableName).\n\t\t\tSharding(gdb.ShardingConfig{\n\t\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\t\tEnable: true,\n\t\t\t\t\tPrefix: \"user_\",\n\t\t\t\t\tRule:   &gdb.DefaultShardingRule{TableCount: 4},\n\t\t\t\t},\n\t\t\t}).Safe()\n\n\t\t_, err := model.Insert(g.Map{\"id\": 1, \"name\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"sharding value is required when sharding feature enabled\")\n\n\t\t// Test missing sharding rule\n\t\tmodel = db.Model(TestTableName).\n\t\t\tSharding(gdb.ShardingConfig{\n\t\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\t\tEnable: true,\n\t\t\t\t\tPrefix: \"user_\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tShardingValue(1)\n\n\t\t_, err = model.Insert(g.Map{\"id\": 1, \"name\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"sharding rule is required when sharding feature enabled\")\n\t})\n}\n\n// Test_Sharding_Complex tests complex sharding scenarios\nfunc Test_Sharding_Complex(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\tshardingConfig := gdb.ShardingConfig{\n\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: \"user_\",\n\t\t\t\tRule:   &gdb.DefaultShardingRule{TableCount: 4},\n\t\t\t},\n\t\t\tSchema: gdb.ShardingSchemaConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: \"test_\",\n\t\t\t\tRule:   &gdb.DefaultShardingRule{SchemaCount: 2},\n\t\t\t},\n\t\t}\n\n\t\tusers := []ShardingUser{\n\t\t\t{Id: 1, Name: \"User1\"},\n\t\t\t{Id: 2, Name: \"User2\"},\n\t\t\t{Id: 3, Name: \"User3\"},\n\t\t}\n\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\t_, err := model.Data(user).Insert()\n\t\t\tt.AssertNil(err)\n\t\t}\n\n\t\t// Test batch query\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\tvar result ShardingUser\n\t\t\terr := model.Where(\"id\", user.Id).Scan(&result)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result.Id, user.Id)\n\t\t\tt.Assert(result.Name, user.Name)\n\t\t}\n\n\t\t// Clean up\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\t_, err := model.Where(\"id\", user.Id).Delete()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n\nfunc Test_Model_Sharding_Table_Using_Hook(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateTable(table1)\n\tdefer dropTable(table1)\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\n\tshardingModel := db.Model(table1).Hook(gdb.HookHandler{\n\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, 1),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, 1),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, 1),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Data(g.Map{\n\t\t\t\"passport\": fmt.Sprintf(`user_%d`, 2),\n\t\t\t\"password\": fmt.Sprintf(`pass_%d`, 2),\n\t\t\t\"nickname\": fmt.Sprintf(`name_%d`, 2),\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar (\n\t\t\tcount int\n\t\t\twhere = g.Map{\"passport\": fmt.Sprintf(`user_%d`, 2)}\n\t\t)\n\t\tcount, err = shardingModel.Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table1).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Delete()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_Model_Sharding_Schema_Using_Hook(t *testing.T) {\n\tvar (\n\t\ttable = gtime.TimestampNanoStr() + \"_table\"\n\t)\n\tcreateTableWithDb(db, table)\n\tdefer dropTableWithDb(db, table)\n\tcreateTableWithDb(db2, table)\n\tdefer dropTableWithDb(db2, table)\n\n\tshardingModel := db.Model(table).Hook(gdb.HookHandler{\n\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, 1),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, 1),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, 1),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Data(g.Map{\n\t\t\t\"passport\": fmt.Sprintf(`user_%d`, 2),\n\t\t\t\"password\": fmt.Sprintf(`pass_%d`, 2),\n\t\t\t\"nickname\": fmt.Sprintf(`name_%d`, 2),\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar (\n\t\t\tcount int\n\t\t\twhere = g.Map{\"passport\": fmt.Sprintf(`user_%d`, 2)}\n\t\t)\n\t\tcount, err = shardingModel.Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Delete()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Embedded_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int    `json:\"id\"`\n\t\t\tUid        int    `json:\"uid\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tUid:        100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=100\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"john-test\")\n\t})\n}\n\nfunc Test_Model_Embedded_MapToStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Ids struct {\n\t\t\tId  int `json:\"id\"`\n\t\t\tUid int `json:\"uid\"`\n\t\t}\n\t\ttype Base struct {\n\t\t\tIds\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          100,\n\t\t\t\"uid\":         101,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\n\t\tt.Assert(one.Struct(user), nil)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t\tt.Assert(user.Password, data[\"password\"])\n\t\tt.Assert(user.Nickname, data[\"nickname\"])\n\t\tt.Assert(user.CreateTime, data[\"create_time\"])\n\t})\n}\n\nfunc Test_Struct_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tuser := new(User)\n\t\terr = one.Struct(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Scan(user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Scan(&user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Structs_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\t// All\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]*User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Struct_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=100\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t\tt.AssertNE(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\t\tvar user *User\n\t\tt.Assert(one.Struct(&user), nil)\n\t\tt.Assert(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\nfunc Test_Structs_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []*User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n}\n\ntype MyTime struct {\n\tgtime.Time\n}\n\ntype MyTimeSt struct {\n\tCreateTime MyTime\n}\n\nfunc (st *MyTimeSt) UnmarshalValue(v any) error {\n\tm := gconv.Map(v)\n\tt, err := gtime.StrToTime(gconv.String(m[\"create_time\"]))\n\tif err != nil {\n\t\treturn err\n\t}\n\tst.CreateTime = MyTime{*t}\n\treturn nil\n}\n\nfunc Test_Model_Scan_CustomType_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyTimeSt)\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar stSlice []*MyTimeSt\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(&stSlice)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(stSlice), TableSize)\n\t\tt.Assert(stSlice[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\tt.Assert(stSlice[9].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_Model_Scan_CustomType_String(t *testing.T) {\n\ttype MyString string\n\n\ttype MyStringSt struct {\n\t\tPassport MyString\n\t}\n\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyStringSt)\n\t\terr := db.Model(table).Fields(\"Passport\").WherePri(1).Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.Passport, \"user_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar sts []MyStringSt\n\t\terr := db.Model(table).Fields(\"Passport\").Order(\"id asc\").Scan(&sts)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(sts), TableSize)\n\t\tt.Assert(sts[0].Passport, \"user_1\")\n\t})\n}\n\ntype User struct {\n\tId         int\n\tPassport   string\n\tPassword   string\n\tNickname   string\n\tCreateTime *gtime.Time\n}\n\nfunc (user *User) UnmarshalValue(value any) error {\n\tif record, ok := value.(gdb.Record); ok {\n\t\t*user = User{\n\t\t\tId:         record[\"id\"].Int(),\n\t\t\tPassport:   record[\"passport\"].String(),\n\t\t\tPassword:   \"\",\n\t\t\tNickname:   record[\"nickname\"].String(),\n\t\t\tCreateTime: record[\"create_time\"].GTime(),\n\t\t}\n\t\treturn nil\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value))\n}\n\nfunc Test_Model_Scan_UnmarshalValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Scan_Map(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Scan_AutoFilteringByStructAttributes(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_model_subquery_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_SubQuery_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).Having(\n\t\t\t\"id > ?\",\n\t\t\tdb.Model(table).Fields(\"MAX(id)\").Where(\"id\", g.Slice{1, 3}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery1 := db.Model(table).Where(\"id\", g.Slice{1, 3, 5})\n\t\tsubQuery2 := db.Model(table).Where(\"id\", g.Slice{5, 7, 9})\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).Fields(\"a.id\").Where(\"a.id=b.id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\n// Test_Model_SubQuery_Correlated tests scalar subquery and correlated subquery with EXISTS\nfunc Test_Model_SubQuery_Correlated(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Scalar subquery: find users whose id is greater than average id\n\t\tsubQuery := db.Model(table + \" AS inner_table\").Fields(\"AVG(id)\")\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id > (?)\",\n\t\t\tsubQuery,\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\t// Average of 1-10 is 5.5, so expect ids 6-10\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[4][\"id\"], 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Correlated subquery with EXISTS: find users with id matching their own id\n\t\tr, err := db.Model(table+\" AS outer_table\").\n\t\t\tWhere(\n\t\t\t\tfmt.Sprintf(\"EXISTS (SELECT 1 FROM %s AS inner_table WHERE inner_table.id = outer_table.id AND inner_table.id <= ?)\", table),\n\t\t\t\t3,\n\t\t\t).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[2][\"id\"], 3)\n\t})\n}\n\n// Test_Model_SubQuery_From tests subquery in FROM clause\nfunc Test_Model_SubQuery_From(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery in FROM clause\n\t\tsubQuery := db.Model(table).Where(\"id <=\", 5)\n\t\tr, err := db.Model(\"(?) AS sub\", subQuery).\n\t\t\tFields(\"sub.id\", \"sub.nickname\").\n\t\t\tWhere(\"sub.id >\", 2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple subqueries in FROM clause with JOIN\n\t\tsubQuery1 := db.Model(table).Fields(\"id\", \"nickname\").Where(\"id <=\", 3)\n\t\tsubQuery2 := db.Model(table).Fields(\"id\", \"passport\").Where(\"id >=\", 3)\n\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).\n\t\t\tFields(\"a.id\", \"a.nickname\", \"b.passport\").\n\t\t\tWhere(\"a.id = b.id\").\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[0][\"passport\"], \"user_3\")\n\t})\n}\n\n// Test_Model_SubQuery_Select tests subquery in SELECT clause\nfunc Test_Model_SubQuery_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery in SELECT clause for scalar value\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id\", \"nickname\", fmt.Sprintf(\"(SELECT MAX(id) FROM %s) AS max_id\", table)).\n\t\t\tWhere(\"id\", 1).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 1)\n\t\tt.Assert(r[\"nickname\"], \"name_1\")\n\t\tt.Assert(r[\"max_id\"], 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple subqueries in SELECT clause\n\t\tr, err := db.Model(table).\n\t\t\tFields(\n\t\t\t\t\"id\",\n\t\t\t\tfmt.Sprintf(\"(SELECT MAX(id) FROM %s) AS max_id\", table),\n\t\t\t\tfmt.Sprintf(\"(SELECT MIN(id) FROM %s) AS min_id\", table),\n\t\t\t).\n\t\t\tWhere(\"id\", 5).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 5)\n\t\tt.Assert(r[\"max_id\"], 10)\n\t\tt.Assert(r[\"min_id\"], 1)\n\t})\n}\n\n// Test_Model_SubQuery_Nested tests multi-level nested subqueries (3+ levels)\nfunc Test_Model_SubQuery_Nested(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 3-level nested subquery\n\t\t// Level 3: innermost - get ids <= 8\n\t\tlevel3 := db.Model(table).Fields(\"id\").Where(\"id <=\", 8)\n\n\t\t// Level 2: middle - filter from level 3 where id >= 3\n\t\tlevel2 := db.Model(\"(?) AS l3\", level3).Fields(\"l3.id\").Where(\"l3.id >=\", 3)\n\n\t\t// Level 1: outermost - filter from level 2 where id <= 6\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN (?)\", level2).\n\t\t\tWhere(\"id <=\", 6).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[3][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 4-level nested subquery with aggregates\n\t\t// Level 4: get all ids\n\t\tlevel4 := db.Model(table).Fields(\"id\")\n\n\t\t// Level 3: get ids > 5 from level 4\n\t\tlevel3 := db.Model(\"(?) AS l4\", level4).Fields(\"l4.id\").Where(\"l4.id >\", 5)\n\n\t\t// Level 2: get MIN(id) from level 3\n\t\tlevel2 := db.Model(\"(?) AS l3\", level3).Fields(\"MIN(l3.id)\")\n\n\t\t// Level 1: find records >= the minimum from level 2\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id >= (?)\", level2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// MIN(id) from level 3 should be 6, so expect ids 6-10\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[4][\"id\"], 10)\n\t})\n}\n\n// Test_Model_SubQuery_WhereIn tests subquery with WHERE IN\nfunc Test_Model_SubQuery_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Simple WHERE IN with subquery\n\t\tsubQuery := db.Model(table).Fields(\"id\").Where(\"id IN(?)\", g.Slice{2, 4, 6})\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN(?)\", subQuery).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 2)\n\t\tt.Assert(r[1][\"id\"], 4)\n\t\tt.Assert(r[2][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple WHERE IN subqueries combined\n\t\tsubQuery1 := db.Model(table).Fields(\"id\").Where(\"id <=\", 5)\n\t\tsubQuery2 := db.Model(table).Fields(\"id\").Where(\"id >=\", 3)\n\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN(?)\", subQuery1).\n\t\t\tWhere(\"id IN(?)\", subQuery2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\n// Test_Model_SubQuery_Complex tests complex subquery combinations\nfunc Test_Model_SubQuery_Complex(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Combine subquery in WHERE, FROM, and SELECT\n\t\twhereSubQuery := db.Model(table).Fields(\"AVG(id)\")\n\t\tfromSubQuery := db.Model(table).Where(\"id <=\", 7)\n\n\t\tr, err := db.Model(\"(?) AS sub\", fromSubQuery).\n\t\t\tFields(\"sub.id\", \"sub.nickname\").\n\t\t\tWhere(\"sub.id > (?)\", whereSubQuery).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// AVG(1-10) = 5.5, filter sub.id > 5.5 from ids 1-7\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[1][\"id\"], 7)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery with GROUP BY and HAVING\n\t\tsubQuery := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >=\", 3)\n\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id % 3 IN(?)\", db.Model(\"(?) AS sub\", subQuery).Fields(\"sub.mod_group\")).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// id % 3: 0(3,6,9), 1(1,4,7,10), 2(2,5,8)\n\t\t// Groups with count >= 3: 0(3 items), 1(4 items), 2(3 items) - all qualify\n\t\tt.Assert(len(r), 10)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_omit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_OmitEmpty_Comprehensive tests OmitEmpty filtering for both data and where parameters\nfunc Test_Model_OmitEmpty_Comprehensive(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmpty with empty string in Data\n\t\tresult, err := db.Model(table).OmitEmpty().Data(g.Map{\n\t\t\t\"nickname\": \"\",         // empty string should be omitted\n\t\t\t\"passport\": \"new_user\", // non-empty should be kept\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\") // original value preserved\n\t\tt.Assert(one[\"passport\"], \"new_user\")\n\n\t\t// Test OmitEmpty with empty slice in Where\n\t\tall, err := db.Model(table).OmitEmpty().Where(g.Map{\n\t\t\t\"id\":       []int{}, // empty slice should be omitted\n\t\t\t\"passport\": \"new_user\",\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\n\t\t// Without OmitEmpty, empty slice causes WHERE 0=1\n\t\tall, err = db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0) // no results due to WHERE 0=1\n\t})\n}\n\n// Test_Model_OmitEmptyWhere_Extended tests OmitEmpty filtering only for where parameters\nfunc Test_Model_OmitEmptyWhere_Extended(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitEmptyWhere only affects Where, not Data\n\t\tresult, err := db.Model(table).OmitEmptyWhere().Data(g.Map{\n\t\t\t\"nickname\": \"\", // empty string in Data should NOT be omitted (only Where is affected)\n\t\t}).Where(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"\", // empty string in Where should be omitted\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was updated to empty (Data is not affected by OmitEmptyWhere)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"\")\n\n\t\t// Test with empty slice in Where\n\t\tall, err := db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id\": []int{}, // should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // returns results because empty condition was omitted\n\n\t\t// Test with zero value in Where (zero is considered empty)\n\t\tall, err = db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id\": 0, // zero should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\n// Test_Model_OmitEmptyData tests OmitEmpty filtering only for data parameters\nfunc Test_Model_OmitEmptyData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitEmptyData only affects Data, not Where\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"nickname\": \"\",          // empty string in Data should be omitted\n\t\t\t\"passport\": \"test_user\", // non-empty should be kept\n\t\t}).Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted), passport was updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"test_user\")\n\n\t\t// Test Insert with OmitEmptyData\n\t\tresult, err = db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       100,\n\t\t\t\"passport\": \"user_100\",\n\t\t\t\"nickname\": \"\", // should be omitted\n\t\t\t\"password\": \"pass_100\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname is NULL (was omitted from INSERT)\n\t\tone, err = db.Model(table).Where(\"id\", 100).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_100\")\n\t\tt.Assert(one[\"nickname\"].IsNil(), true)\n\t})\n}\n\n// Test_Model_OmitNil_Comprehensive tests OmitNil filtering for both data and where parameters\nfunc Test_Model_OmitNil_Comprehensive(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitNil with nil value in Data\n\t\tresult, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"nickname\": nil,        // nil should be omitted\n\t\t\t\"passport\": \"nil_test\", // non-nil should be kept\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"nil_test\")\n\n\t\t// Test OmitNil with nil in Where\n\t\tall, err := db.Model(table).OmitNil().Where(g.Map{\n\t\t\t\"passport\": nil, // nil should be omitted\n\t\t}).Order(\"id\").Limit(5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // returns results because nil condition was omitted\n\n\t\t// Without OmitNil, WHERE passport=NULL (which won't match anything)\n\t\tall, err = db.Model(table).Where(g.Map{\n\t\t\t\"passport\": nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0) // NULL comparison doesn't match\n\t})\n}\n\n// Test_Model_OmitNilWhere tests OmitNil filtering only for where parameters\nfunc Test_Model_OmitNilWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitNilWhere only affects Where, not Data\n\t\tresult, err := db.Model(table).OmitNilWhere().Data(g.Map{\n\t\t\t\"nickname\": nil, // nil in Data should NOT be omitted (only Where is affected)\n\t\t}).Where(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": nil, // nil in Where should be omitted\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was set to NULL (Data is not affected by OmitNilWhere)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"].IsNil(), true)\n\n\t\t// Test with nil in Where\n\t\tall, err := db.Model(table).OmitNilWhere().Where(g.Map{\n\t\t\t\"passport\": nil, // should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // returns results\n\t})\n}\n\n// Test_Model_OmitNilData tests OmitNil filtering only for data parameters\nfunc Test_Model_OmitNilData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitNilData only affects Data, not Where\n\t\tresult, err := db.Model(table).OmitNilData().Data(g.Map{\n\t\t\t\"nickname\": nil,            // nil in Data should be omitted\n\t\t\t\"passport\": \"omitnil_test\", // non-nil should be kept\n\t\t}).Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted), passport was updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"omitnil_test\")\n\n\t\t// Test Insert with OmitNilData\n\t\tresult, err = db.Model(table).OmitNilData().Data(g.Map{\n\t\t\t\"id\":       101,\n\t\t\t\"passport\": \"user_101\",\n\t\t\t\"nickname\": nil, // should be omitted\n\t\t\t\"password\": \"pass_101\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify insert\n\t\tone, err = db.Model(table).Where(\"id\", 101).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_101\")\n\t})\n}\n\n// Test_Model_OmitEmpty_WithStruct tests OmitEmpty with struct data\nfunc Test_Model_OmitEmpty_WithStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tNickname string\n\t\tPassword string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyData with struct\n\t\tuser := User{\n\t\t\tPassport: \"struct_user\",\n\t\t\tNickname: \"\", // empty, should be omitted\n\t\t\tPassword: \"struct_pass\",\n\t\t}\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(user).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"struct_user\")\n\t})\n}\n\n// Test_Model_OmitNil_WithPointerStruct tests OmitNil with pointer struct data\nfunc Test_Model_OmitNil_WithPointerStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport *string\n\t\tNickname *string\n\t\tPassword string\n\t}\n\n\t// Note: Removed OmitNilData with pointer struct test due to framework limitations\n\t// Struct field nil pointer handling needs further investigation\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitNilData with Map (working as expected)\n\t\tsqlArray2, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\t_, err := db.Ctx(ctx).Model(table).OmitNilData().Data(g.Map{\n\t\t\t\t\"passport\": \"map_user\",\n\t\t\t\t\"nickname\": nil,\n\t\t\t\t\"password\": \"map_pass\",\n\t\t\t}).Where(\"id\", 2).Update()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Logf(\"Map SQL: %v\", sqlArray2)\n\n\t\tone2, err := db.Model(table).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Logf(\"Map result - nickname: %v, passport: %v\", one2[\"nickname\"], one2[\"passport\"])\n\t\tt.Assert(one2[\"nickname\"], \"name_2\") // should be preserved\n\t\tt.Assert(one2[\"passport\"], \"map_user\")\n\t})\n}\n\n// Test_Model_OmitEmpty_ZeroValues tests OmitEmpty with various zero values\nfunc Test_Model_OmitEmpty_ZeroValues(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyData with various zero values\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       0,           // zero int, should be omitted\n\t\t\t\"passport\": \"zero_test\", // non-empty\n\t\t\t\"nickname\": \"\",          // empty string, should be omitted\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the insert (id should be auto-generated since 0 was omitted)\n\t\tone, err := db.Model(table).Where(\"passport\", \"zero_test\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"zero_test\")\n\t\tt.AssertNE(one[\"id\"], 0) // auto-generated id\n\t})\n}\n\n// Test_Model_OmitEmpty_ComplexWhere tests OmitEmpty with complex where conditions\nfunc Test_Model_OmitEmpty_ComplexWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyWhere with multiple conditions\n\t\tall, err := db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id >\":     0,   // zero, should be omitted\n\t\t\t\"passport\": \"\",  // empty string, should be omitted\n\t\t\t\"nickname\": \"?\", // placeholder, should NOT be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\t// Should execute query with only the nickname condition\n\n\t\t// Test with all empty conditions\n\t\tall, err = db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"passport\": \"\",\n\t\t\t\"nickname\": \"\",\n\t\t}).Order(\"id\").Limit(5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // all conditions omitted, returns all (limited to 5)\n\t})\n}\n\n// Test_Model_Omit_ChainedMethods tests Omit methods with other chained methods\nfunc Test_Model_Omit_ChainedMethods(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmpty with Fields and Order\n\t\tresult, err := db.Model(table).\n\t\t\tOmitEmptyData().\n\t\t\tFields(\"passport\", \"nickname\").\n\t\t\tData(g.Map{\n\t\t\t\t\"passport\": \"chain_test\",\n\t\t\t\t\"nickname\": \"\",\n\t\t\t}).\n\t\t\tWhere(\"id\", 1).\n\t\t\tUpdate()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"chain_test\")\n\t\tt.Assert(one[\"nickname\"], \"name_1\") // not updated due to OmitEmptyData\n\n\t\t// Test OmitNilWhere with multiple Where clauses\n\t\tall, err := db.Model(table).\n\t\t\tOmitNilWhere().\n\t\t\tWhere(\"id>?\", 5).\n\t\t\tWhere(g.Map{\n\t\t\t\t\"passport\": nil, // should be omitted\n\t\t\t}).\n\t\t\tOrder(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // id 6-10\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_pagination_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Test_Model_AllAndCount_Basic tests basic AllAndCount functionality\nfunc Test_Model_AllAndCount_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_AllAndCount_WithWhere tests AllAndCount with WHERE conditions\nfunc Test_Model_AllAndCount_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id > ?\", 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(count, 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, 3)\n\t})\n}\n\n// Test_Model_AllAndCount_WithPage tests AllAndCount with pagination\nfunc Test_Model_AllAndCount_WithPage(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(1, 3).Order(\"id\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, TableSize) // Count should be total, not page size\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(2, 3).Order(\"id\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(result[0][\"id\"], 4)\n\t})\n}\n\n// Test_Model_AllAndCount_WithFields tests AllAndCount with specific fields\n// Related: https://github.com/gogf/gf/issues/4698\nfunc Test_Model_AllAndCount_WithFields(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result[0]), 2) // Only 2 fields\n\t})\n\n\t// Regression test for #4698: AllAndCount(true) with multiple fields should work correctly\n\t// https://github.com/gogf/gf/issues/4698\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result[0]), 2)\n\t})\n}\n\n// Test_Model_AllAndCount_Empty tests AllAndCount with no results\nfunc Test_Model_AllAndCount_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id > ?\", 1000).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\tt.Assert(count, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id < ?\", 0).AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_AllAndCount_WithCache tests AllAndCount with cache\nfunc Test_Model_AllAndCount_WithCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult1, count1, err := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result1), 5)\n\t\tt.Assert(count1, TableSize)\n\n\t\t// Second call should use cache\n\t\tresult2, count2, err := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result2), 5)\n\t\tt.Assert(count2, count1)\n\t})\n}\n\n// Test_Model_AllAndCount_Distinct tests AllAndCount with DISTINCT\nfunc Test_Model_AllAndCount_Distinct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// Insert duplicate nicknames\n\tfor i := 1; i <= 10; i++ {\n\t\tnickname := \"name_\" + gconv.String((i-1)/2) // Creates duplicates\n\t\tdb.Model(table).Data(g.Map{\n\t\t\t\"id\":       i,\n\t\t\t\"passport\": \"pass_\" + gconv.String(i),\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": nickname,\n\t\t}).Insert()\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"DISTINCT nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 5) // 10 records / 2 = 5 distinct nicknames\n\t\tt.Assert(len(result), 5)\n\t})\n}\n\n// Test_Model_ScanAndCount_Basic tests basic ScanAndCount functionality\nfunc Test_Model_ScanAndCount_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithWhere tests ScanAndCount with WHERE conditions\nfunc Test_Model_ScanAndCount_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id <= ?\", 5).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 5)\n\t\tt.Assert(count, 5)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithPage tests ScanAndCount with pagination\nfunc Test_Model_ScanAndCount_WithPage(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Page(2, 3).Order(\"id\").ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(count, TableSize) // Total count, not page count\n\t\tt.Assert(users[0].Id, 4)\n\t\tt.Assert(users[2].Id, 6)\n\t})\n}\n\n// Test_Model_ScanAndCount_Single tests ScanAndCount for single record\nfunc Test_Model_ScanAndCount_Single(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id\", 1).ScanAndCount(&user, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test_Model_ScanAndCount_Empty tests ScanAndCount with no results\nfunc Test_Model_ScanAndCount_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithFields tests ScanAndCount with specific fields\nfunc Test_Model_ScanAndCount_WithFields(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Fields(\"id, nickname\").ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(users[0].Id > 0, true)\n\t\tt.AssertNE(users[0].Nickname, \"\")\n\t})\n}\n\n// Test_Model_ScanAndCount_WithCache tests ScanAndCount with cache\nfunc Test_Model_ScanAndCount_WithCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users1 []User\n\t\tvar count1 int\n\t\terr := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).ScanAndCount(&users1, &count1, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users1), 5)\n\t\tt.Assert(count1, TableSize)\n\n\t\t// Second call should use cache\n\t\tvar users2 []User\n\t\tvar count2 int\n\t\terr = db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).ScanAndCount(&users2, &count2, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users2), 5)\n\t\tt.Assert(count2, count1)\n\t})\n}\n\n// Test_Model_Chunk_Basic tests basic Chunk functionality\nfunc Test_Model_Chunk_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttotal  int\n\t\t\tchunks int\n\t\t)\n\t\tdb.Model(table).Order(\"id\").Chunk(3, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\ttotal += len(result)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 4) // 10 records / 3 = 4 chunks (3+3+3+1)\n\t\tt.Assert(total, TableSize)\n\t})\n}\n\n// Test_Model_Chunk_StopEarly tests Chunk with early stop\nfunc Test_Model_Chunk_StopEarly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar chunks int\n\t\tdb.Model(table).Order(\"id\").Chunk(3, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\treturn chunks < 2 // Stop after 2nd chunk\n\t\t})\n\t\tt.Assert(chunks, 2)\n\t})\n}\n\n// Test_Model_Chunk_WithWhere tests Chunk with WHERE conditions\nfunc Test_Model_Chunk_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttotal  int\n\t\t\tchunks int\n\t\t)\n\t\tdb.Model(table).Where(\"id <= ?\", 5).Order(\"id\").Chunk(2, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\ttotal += len(result)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 3) // 5 records / 2 = 3 chunks (2+2+1)\n\t\tt.Assert(total, 5)\n\t})\n}\n\n// Test_Model_Chunk_ErrorHandling tests Chunk error handling\nfunc Test_Model_Chunk_ErrorHandling(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar errorReceived bool\n\t\tdb.Model(\"non_existent_table\").Chunk(10, func(result gdb.Result, err error) bool {\n\t\t\tif err != nil {\n\t\t\t\terrorReceived = true\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(errorReceived, true)\n\t})\n}\n\n// Test_Model_Chunk_Empty tests Chunk with no results\nfunc Test_Model_Chunk_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar chunks int\n\t\tdb.Model(table).Where(\"id > ?\", 1000).Chunk(10, func(result gdb.Result, err error) bool {\n\t\t\tchunks++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 0) // No chunks for empty result\n\t})\n}\n\n// Test_Model_Page_Boundary tests Page with boundary values\n// Related: https://github.com/gogf/gf/issues/4699\nfunc Test_Model_Page_Boundary(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Page 0 should be treated as page 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(0, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n\n\t// Negative page should be treated as page 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(-1, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n\n\t// Size 0: framework treats limit=0 as \"no limit\", returns all records\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(1, 0).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Negative size: normalized to 0, same as Page(1, 0)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(1, -1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Very large page number (beyond available data)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(100, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test_Model_Limit_Boundary tests Limit with boundary values\n// Related: https://github.com/gogf/gf/issues/4699\nfunc Test_Model_Limit_Boundary(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Limit 0: framework treats limit=0 as \"no limit\", returns all records\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(0).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Negative limit: normalized to 0, same as Limit(0)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(-1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Limit larger than available data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(1000).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Limit(offset, size): offset=5 skips 5 rows, size=100 takes up to 100\n\t// With 10 rows total, skipping 5 returns remaining 5 rows\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(5, 100).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize-5)\n\t})\n\n\t// Offset beyond data: returns empty result\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(100, 5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test_Model_Page_Limit_Combination tests Page and Limit used together\nfunc Test_Model_Page_Limit_Combination(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Page should override Limit\n\t\tresult, err := db.Model(table).Limit(5).Page(1, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_raw_type_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Raw_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+2\"),\n\t\t\t\"passport\":    \"port_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_Raw_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(\n\t\t\tg.List{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"id\":          gdb.Raw(\"id+2\"),\n\t\t\t\t\t\"passport\":    \"port_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t\tg.Map{\n\t\t\t\t\t\"id\":          gdb.Raw(\"id+4\"),\n\t\t\t\t\t\"passport\":    \"port_4\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t},\n\t\t).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 4)\n\t})\n}\n\nfunc Test_Raw_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+100\"),\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tn, err := user.Where(\"id\", 101).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_Where(t *testing.T) {\n\ttable1 := createTable(\"Test_Raw_Where_Table1\")\n\ttable2 := createTable(\"Test_Raw_Where_Table2\")\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\t// https://github.com/gogf/gf/issues/3922\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` AS A WHERE NOT EXISTS (SELECT B.id FROM `Test_Raw_Where_Table2` AS B WHERE `B`.`id`=A.id) LIMIT 1\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(\"B.id\", gdb.Raw(\"A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` AS A WHERE NOT EXISTS (SELECT B.id FROM `Test_Raw_Where_Table2` AS B WHERE B.id=A.id) LIMIT 1\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(gdb.Raw(\"B.id=A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\t// https://github.com/gogf/gf/issues/3915\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` WHERE `passport` < `nickname`\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\tm := db.Model(table1).Ctx(ctx).WhereLT(\"passport\", gdb.Raw(\"`nickname`\"))\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n}\n\n// Test_DataType_JSON_Insert tests JSON data insertion\nfunc Test_DataType_JSON_Insert(t *testing.T) {\n\ttable := \"test_json_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert simple JSON object\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"John\",\"age\":30}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"John\", \"age\": float64(30)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_JSON_Extract tests JSON_EXTRACT function\nfunc Test_DataType_JSON_Extract(t *testing.T) {\n\ttable := \"test_json_extract_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Alice\",\"age\":25,\"city\":\"Beijing\"}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract name using JSON_EXTRACT\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$.name') as name\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), `\"Alice\"`)\n\n\t\t// Extract age\n\t\tone, err = db.Model(table).Fields(\"JSON_EXTRACT(data, '$.age') as age\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"age\"].Int(), 25)\n\t})\n}\n\n// Test_DataType_JSON_Set tests JSON_SET function\nfunc Test_DataType_JSON_Set(t *testing.T) {\n\ttable := \"test_json_set_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Bob\"}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update using JSON_SET\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\"UPDATE %s SET data = JSON_SET(data, '$.age', 30) WHERE id = 1\", table))\n\t\tt.AssertNil(err)\n\n\t\t// Verify updated data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"Bob\", \"age\": float64(30)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_JSON_Array tests JSON array operations\nfunc Test_DataType_JSON_Array(t *testing.T) {\n\ttable := \"test_json_array_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert JSON array\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `[\"apple\",\"banana\",\"cherry\"]`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract array element\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$[0]') as first\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"first\"].String(), `\"apple\"`)\n\t})\n}\n\n// Test_DataType_JSON_Null tests JSON NULL handling\nfunc Test_DataType_JSON_Null(t *testing.T) {\n\ttable := \"test_json_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL value\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"data\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_JSON_Complex tests complex nested JSON\nfunc Test_DataType_JSON_Complex(t *testing.T) {\n\ttable := \"test_json_complex_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert complex nested JSON\n\t\tcomplexJSON := `{\n\t\t\t\"user\": {\n\t\t\t\t\"name\": \"Charlie\",\n\t\t\t\t\"contacts\": {\n\t\t\t\t\t\"email\": \"charlie@example.com\",\n\t\t\t\t\t\"phone\": \"1234567890\"\n\t\t\t\t},\n\t\t\t\t\"tags\": [\"developer\", \"gopher\"]\n\t\t\t}\n\t\t}`\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": complexJSON,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract nested field\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$.user.contacts.email') as email\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"email\"].String(), `\"charlie@example.com\"`)\n\t})\n}\n\n// Test_DataType_JSON_Query tests JSON query with WHERE clause\nfunc Test_DataType_JSON_Query(t *testing.T) {\n\ttable := \"test_json_query_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert multiple JSON records\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\tg.Map{\"data\": `{\"name\":\"David\",\"age\":20}`},\n\t\t\tg.Map{\"data\": `{\"name\":\"Eve\",\"age\":30}`},\n\t\t\tg.Map{\"data\": `{\"name\":\"Frank\",\"age\":25}`},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query by JSON field value\n\t\tcount, err := db.Model(table).Where(\"JSON_EXTRACT(data, '$.age') > ?\", 25).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test_DataType_JSON_Update tests updating JSON data\nfunc Test_DataType_JSON_Update(t *testing.T) {\n\ttable := \"test_json_update_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Grace\",\"age\":28}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update entire JSON\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Grace\",\"age\":29}`,\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"Grace\", \"age\": float64(29)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Binary_Small tests small binary data\nfunc Test_DataType_Binary_Small(t *testing.T) {\n\ttable := \"test_binary_small_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert small binary data\n\t\tbinaryData := []byte{0x00, 0x01, 0x02, 0x03, 0xFF}\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": binaryData,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(bytes.Equal(one[\"data\"].Bytes(), binaryData), true)\n\t})\n}\n\n// Test_DataType_Binary_Large tests large binary data (1MB+)\nfunc Test_DataType_Binary_Large(t *testing.T) {\n\ttable := \"test_binary_large_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data MEDIUMBLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create 1MB binary data\n\t\tsize := 1024 * 1024 // 1MB\n\t\tlargeBinary := make([]byte, size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tlargeBinary[i] = byte(i % 256)\n\t\t}\n\n\t\t// Insert large binary data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": largeBinary,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one[\"data\"].Bytes()), size)\n\t\tt.Assert(bytes.Equal(one[\"data\"].Bytes(), largeBinary), true)\n\t})\n}\n\n// Test_DataType_Binary_Integrity tests binary data integrity with checksum\nfunc Test_DataType_Binary_Integrity(t *testing.T) {\n\ttable := \"test_binary_integrity_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB, checksum VARCHAR(64))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create random binary data\n\t\tbinaryData := []byte(\"Hello, World! This is a binary test data with special chars: \\x00\\xFF\\xAB\")\n\n\t\t// Calculate SHA256 checksum\n\t\thash := sha256.Sum256(binaryData)\n\t\tchecksum := hex.EncodeToString(hash[:])\n\n\t\t// Insert with checksum\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\":     binaryData,\n\t\t\t\"checksum\": checksum,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify integrity\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tretrievedHash := sha256.Sum256(one[\"data\"].Bytes())\n\t\tretrievedChecksum := hex.EncodeToString(retrievedHash[:])\n\t\tt.Assert(retrievedChecksum, checksum)\n\t})\n}\n\n// Test_DataType_Binary_Empty tests empty and NULL binary\nfunc Test_DataType_Binary_Empty(t *testing.T) {\n\ttable := \"test_binary_empty_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert empty binary\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": []byte{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert NULL\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"data\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify empty\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one[\"data\"].Bytes()), 0)\n\n\t\t// Verify NULL\n\t\tone, err = db.Model(table).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"data\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Decimal_HighPrecision tests high precision decimal (65,30)\nfunc Test_DataType_Decimal_HighPrecision(t *testing.T) {\n\ttable := \"test_decimal_precision_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, amount DECIMAL(65,30))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert high precision decimal\n\t\tvalue := \"12345678901234567890123456789012345.123456789012345678901234567890\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"amount\": value,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify precision\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"amount\"].String(), value)\n\t})\n}\n\n// Test_DataType_Decimal_Calculation tests decimal arithmetic\nfunc Test_DataType_Decimal_Calculation(t *testing.T) {\n\ttable := \"test_decimal_calc_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, price DECIMAL(10,2), quantity DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"price\":    \"19.99\",\n\t\t\t\"quantity\": \"3.5\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Calculate total using SQL\n\t\tone, err := db.Model(table).Fields(\"price * quantity as total\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"total\"].String(), \"69.9650\")\n\t})\n}\n\n// Test_DataType_Decimal_Boundary tests decimal boundary values\nfunc Test_DataType_Decimal_Boundary(t *testing.T) {\n\ttable := \"test_decimal_boundary_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, value DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test max value (10 digits, 2 decimals: 99999999.99)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"99999999.99\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test min value\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"-99999999.99\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test zero\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"0.00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"value\"].String(), \"99999999.99\")\n\t\tt.Assert(all[1][\"value\"].String(), \"-99999999.99\")\n\t\tt.Assert(all[2][\"value\"].String(), \"0.00\")\n\t})\n}\n\n// Test_DataType_Decimal_Null tests NULL decimal values\nfunc Test_DataType_Decimal_Null(t *testing.T) {\n\ttable := \"test_decimal_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, value DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"value\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"value\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Datetime_Timezone tests datetime with timezone handling\nfunc Test_DataType_Datetime_Timezone(t *testing.T) {\n\ttable := \"test_datetime_tz_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert datetime\n\t\tdt := \"2024-01-15 12:30:45\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"created_at\": dt,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify datetime\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"created_at\"].String(), dt)\n\t})\n}\n\n// Test_DataType_Datetime_Precision tests datetime with microsecond precision\nfunc Test_DataType_Datetime_Precision(t *testing.T) {\n\ttable := \"test_datetime_precision_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME(6))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert datetime with microseconds\n\t\tdt := \"2024-01-15 12:30:45.123456\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"created_at\": dt,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify precision (compare up to seconds, MySQL may format microseconds differently)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := \"2024-01-15 12:30:45\"\n\t\tactual := one[\"created_at\"].String()[:19] // Extract first 19 chars (YYYY-MM-DD HH:MM:SS)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Datetime_Boundary tests datetime boundary values\nfunc Test_DataType_Datetime_Boundary(t *testing.T) {\n\ttable := \"test_datetime_boundary_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test min datetime (MySQL supports 1000-01-01 00:00:00)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": \"1000-01-01 00:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test max datetime\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"dt\": \"9999-12-31 23:59:59\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify boundaries\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"dt\"].String(), \"1000-01-01 00:00:00\")\n\t\tt.Assert(all[1][\"dt\"].String(), \"9999-12-31 23:59:59\")\n\t})\n}\n\n// Test_DataType_Datetime_Null tests NULL datetime\nfunc Test_DataType_Datetime_Null(t *testing.T) {\n\ttable := \"test_datetime_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"dt\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Datetime_Update tests datetime updates\nfunc Test_DataType_Datetime_Update(t *testing.T) {\n\ttable := \"test_datetime_update_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial datetime\n\t\tdt1 := \"2024-01-01 10:00:00\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": dt1,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update datetime\n\t\tdt2 := \"2024-12-31 23:59:59\"\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"dt\": dt2,\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"dt\"].String(), dt2)\n\t})\n}\n\n// Test_DataType_Enum_Valid tests valid ENUM values\nfunc Test_DataType_Enum_Valid(t *testing.T) {\n\ttable := \"test_enum_valid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, status ENUM('pending','approved','rejected'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert all valid values\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\tg.Map{\"status\": \"pending\"},\n\t\t\tg.Map{\"status\": \"approved\"},\n\t\t\tg.Map{\"status\": \"rejected\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"status\"].String(), \"pending\")\n\t\tt.Assert(all[1][\"status\"].String(), \"approved\")\n\t\tt.Assert(all[2][\"status\"].String(), \"rejected\")\n\t})\n}\n\n// Test_DataType_Enum_Invalid tests invalid ENUM values (should fail or truncate)\nfunc Test_DataType_Enum_Invalid(t *testing.T) {\n\ttable := \"test_enum_invalid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, status ENUM('pending','approved','rejected'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt to insert invalid value (should fail in strict mode)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"status\": \"invalid_status\",\n\t\t}).Insert()\n\t\t// In strict SQL mode, this should produce an error\n\t\t// In non-strict mode, it might insert empty string\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_DataType_Set_Valid tests valid SET values\nfunc Test_DataType_Set_Valid(t *testing.T) {\n\ttable := \"test_set_valid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, permissions SET('read','write','execute'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert single value\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert multiple values\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read,write\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert all values\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read,write,execute\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"permissions\"].String(), \"read\")\n\t\tt.Assert(all[1][\"permissions\"].String(), \"read,write\")\n\t\tt.Assert(all[2][\"permissions\"].String(), \"read,write,execute\")\n\t})\n}\n\n// Test_DataType_Set_Empty tests empty SET values\nfunc Test_DataType_Set_Empty(t *testing.T) {\n\ttable := \"test_set_empty_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, permissions SET('read','write','execute'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert empty SET\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify empty\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"permissions\"].String(), \"\")\n\t})\n}\n\n// Test_DataType_Geometry_Point tests POINT geometry type\nfunc Test_DataType_Geometry_Point(t *testing.T) {\n\ttable := \"test_geo_point_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, location POINT)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert POINT using ST_GeomFromText\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"INSERT INTO %s (location) VALUES (ST_GeomFromText('POINT(116.4074 39.9042)'))\", table))\n\t\tt.AssertNil(err)\n\n\t\t// Query POINT using ST_AsText\n\t\tone, err := db.Model(table).Fields(\"ST_AsText(location) as location_text\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"location_text\"].String(), \"POINT(116.4074 39.9042)\")\n\t})\n}\n\n// Test_DataType_Geometry_Polygon tests POLYGON geometry type\nfunc Test_DataType_Geometry_Polygon(t *testing.T) {\n\ttable := \"test_geo_polygon_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, area POLYGON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert POLYGON (rectangle)\n\t\tpolygon := \"POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))\"\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"INSERT INTO %s (area) VALUES (ST_GeomFromText('%s'))\", table, polygon))\n\t\tt.AssertNil(err)\n\n\t\t// Query POLYGON (normalize spaces for comparison)\n\t\tone, err := db.Model(table).Fields(\"ST_AsText(area) as area_text\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := \"POLYGON((0 0,10 0,10 10,0 10,0 0))\"\n\t\tactual := strings.ReplaceAll(one[\"area_text\"].String(), \", \", \",\") // Remove spaces after commas\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Geometry_Null tests NULL geometry values\nfunc Test_DataType_Geometry_Null(t *testing.T) {\n\ttable := \"test_geo_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, location POINT)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"location\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"location\"].IsNil(), true)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_scanlist_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Table_Relation_One(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  course varchar(45) NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `orm:\"uid\"`\n\t\tName string `orm:\"name\"`\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int    `orm:\"uid\"`\n\t\tAddress string `orm:\"address\"`\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId     int    `orm:\"id\"`\n\t\tUid    int    `orm:\"uid\"`\n\t\tScore  int    `orm:\"score\"`\n\t\tCourse string `orm:\"course\"`\n\t}\n\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tr, err := tx.Model(tableUser).Save(EntityUser{\n\t\t\t\tName: \"john\",\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tuid, err := r.LastInsertId()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserDetail).Save(EntityUserDetail{\n\t\t\t\tUid:     int(uid),\n\t\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserScores).Save(g.Slice{\n\t\t\t\tEntityUserScores{Uid: int(uid), Score: 100, Course: \"math\"},\n\t\t\t\tEntityUserScores{Uid: int(uid), Score: 99, Course: \"physics\"},\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\t// Data check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(tableUser).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"name\"].String(), \"john\")\n\n\t\tr, err = db.Model(tableUserDetail).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"address\"].String(), `Beijing DongZhiMen #66`)\n\n\t\tr, err = db.Model(tableUserScores).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 2)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[1][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"course\"].String(), `math`)\n\t\tt.Assert(r[1][\"course\"].String(), `physics`)\n\t})\n\t// Entity query.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user Entity\n\t\t// SELECT * FROM `user` WHERE `name`='john'\n\t\terr := db.Model(tableUser).Scan(&user.User, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid`=1\n\t\terr = db.Model(tableUserDetail).Scan(&user.UserDetail, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid`=1\n\t\terr = db.Model(tableUserScores).Scan(&user.UserScores, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.User, EntityUser{\n\t\t\tUid:  1,\n\t\t\tName: \"john\",\n\t\t})\n\t\tt.Assert(user.UserDetail, EntityUserDetail{\n\t\t\tUid:     1,\n\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t})\n\t\tt.Assert(user.UserScores, []EntityUserScores{\n\t\t\t{Id: 1, Uid: 1, Course: \"math\", Score: 100},\n\t\t\t{Id: 2, Uid: 1, Course: \"physics\", Score: 99},\n\t\t})\n\t})\n}\n\nfunc Test_Table_Relation_Many(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_ModelScanList(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t//db.SetDebug(true)\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_RelationKeyCaseInsensitive(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UId:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_TheSameRelationNames(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_EmptyData(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t})\n\treturn\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:UId\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UId:Uid\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID:Uid\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 0)\n\t})\n}\n\nfunc Test_Table_Relation_NoneEqualDataSize(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t// _, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t//\t\"uid\":     i,\n\t\t\t//\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t// })\n\t\t\t// t.AssertNil(err)\n\t\t\t// Scores.\n\t\t\t// for j := 1; j <= 5; j++ {\n\t\t\t//\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t//\t\t\"uid\":   i,\n\t\t\t//\t\t\"score\": j,\n\t\t\t//\t})\n\t\t\t//\tt.AssertNil(err)\n\t\t\t// }\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, EntityUserDetail{})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, EntityUserDetail{})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct1(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\t*EntityUser\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\t*EntityUser\n\t\t*EntityUserDetail\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tscores []*EntityUserScores\n\t\t)\n\t\t// SELECT * FROM `user_scores`\n\t\terr = db.Model(tableUserScores).Scan(&scores)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUser).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUser\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Assertions.\n\t\tt.Assert(len(scores), 25)\n\t\tt.Assert(scores[0].Id, 1)\n\t\tt.Assert(scores[0].Uid, 1)\n\t\tt.Assert(scores[0].Name, \"name_1\")\n\t\tt.Assert(scores[0].Address, \"address_1\")\n\t\tt.Assert(scores[24].Id, 25)\n\t\tt.Assert(scores[24].Uid, 5)\n\t\tt.Assert(scores[24].Name, \"name_5\")\n\t\tt.Assert(scores[24].Address, \"address_5\")\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct2(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\t*EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tEntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tEntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_soft_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete1(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete2(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(0) DEFAULT NULL,\n  update_at datetime(0) DEFAULT NULL,\n  delete_at datetime(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Map(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId        int\n\t\tName      string\n\t\tCreatedAT *gtime.Time\n\t\tUpdatedAT *gtime.Time\n\t\tDeletedAT *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := User{\n\t\t\tName: \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).OmitEmpty().WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-4)\n\n\t\t// Replace\n\t\tdataReplace := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftUpdateTime(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  num       int(11) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\tr, err = db.Model(table).Data(\"num=num+1\").Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_SoftUpdateTime_WithDO(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  num       int(11) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInserted, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInserted[\"id\"].Int(), 1)\n\t\tt.Assert(oneInserted[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\ttime.Sleep(2 * time.Second)\n\t\ttype User struct {\n\t\t\tg.Meta    `orm:\"do:true\"`\n\t\t\tId        any\n\t\t\tNum       any\n\t\t\tCreatedAt any\n\t\t\tUpdatedAt any\n\t\t\tDeletedAt any\n\t\t}\n\t\tr, err = db.Model(table).Data(User{\n\t\t\tNum: 100,\n\t\t}).Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdated, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdated[\"num\"].Int(), 100)\n\t\tt.Assert(oneUpdated[\"created_at\"].String(), oneInserted[\"created_at\"].String())\n\t\tt.AssertNE(oneUpdated[\"updated_at\"].String(), oneInserted[\"updated_at\"].String())\n\t})\n}\n\nfunc Test_SoftDelete(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(10).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", ids).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tall, err := db.Model(table).Unscoped().Where(\"id\", ids).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.AssertNE(all[0][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"delete_at\"].String(), \"\")\n\t})\n}\n\nfunc Test_SoftDelete_Join(t *testing.T) {\n\ttable1 := \"time_test_table1\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table1)\n\n\ttable2 := \"time_test_table2\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  createat datetime(6) DEFAULT NULL,\n  updateat datetime(6) DEFAULT NULL,\n  deleteat datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tdataInsert1 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table1).Data(dataInsert1).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tdataInsert2 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_2\",\n\t\t}\n\t\tr, err = db.Model(table2).Data(dataInsert2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"name_1\")\n\n\t\t// Soft deleting.\n\t\tr, err = db.Model(table1).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\tone, err = db.Model(table2, \"t2\").LeftJoin(table1, \"t1\", \"t2.id=t1.id\").Fields(\"t2.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\t})\n}\n\nfunc Test_SoftDelete_WhereAndOr(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\t// Add datas.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", 1).WhereOr(\"id\", 3).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_CreateUpdateTime_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\ttype Entity struct {\n\t\tId       uint64      `orm:\"id,primary\" json:\"id\"`\n\t\tName     string      `orm:\"name\"       json:\"name\"`\n\t\tCreateAt *gtime.Time `orm:\"create_at\"  json:\"create_at\"`\n\t\tUpdateAt *gtime.Time `orm:\"update_at\"  json:\"update_at\"`\n\t\tDeleteAt *gtime.Time `orm:\"delete_at\"  json:\"delete_at\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_10\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1000\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_100\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_UnixTimestamp(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at int(11) DEFAULT NULL,\n  update_at int(11) DEFAULT NULL,\n  delete_at int(11) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// sleep some seconds to make update time greater than create time.\n\ttime.Sleep(2 * time.Second)\n\n\t// update\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// update: map\n\t\tdataInsert := g.Map{\n\t\t\t\"name\": \"name_11\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_11\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\n\t\tvar (\n\t\t\tlastCreateTime = one[\"create_at\"].Int64()\n\t\t\tlastUpdateTime = one[\"update_at\"].Int64()\n\t\t)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// update: string\n\t\tr, err = db.Model(table).Data(\"name='name_111'\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.Assert(one[\"create_at\"].Int64(), lastCreateTime)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), lastUpdateTime)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"delete_at\"].Int64(), 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Bool_Deleted(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at int(11) DEFAULT NULL,\n  update_at int(11) DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t//db.SetDebug(true)\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampMilli(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at bigint(19) unsigned DEFAULT NULL,\n  update_at bigint(19) unsigned DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampMilli,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"create_at\"].String()), 13)\n\t\tt.Assert(len(one[\"update_at\"].String()), 13)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampNano(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at bigint(19) unsigned DEFAULT NULL,\n  update_at bigint(19) unsigned DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampNano,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"create_at\"].String()), 19)\n\t\tt.Assert(len(one[\"update_at\"].String()), 19)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Specified(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(0) DEFAULT NULL,\n  update_at datetime(0) DEFAULT NULL,\n  delete_at datetime(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_1\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneInsert[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_10\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:15:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneSave[\"update_at\"].String(), \"2024-05-30 20:15:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\":      \"name_1000\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:30:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneUpdate[\"update_at\"].String(), \"2024-05-30 20:30:00\")\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_100\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneReplace[\"create_at\"].String(), \"2024-05-30 21:00:00\")\n\t\tt.Assert(oneReplace[\"update_at\"].String(), \"2024-05-30 21:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Insert with delete_at\n\t\tdataInsertDelete := g.Map{\n\t\t\t\"id\":        2,\n\t\t\t\"name\":      \"name_2\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"delete_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataInsertDelete).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Delete Select\n\t\toneDelete, err := db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(oneDelete), 0)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"id\"].Int(), 2)\n\t\tt.Assert(oneDeleteUnscoped[\"name\"].String(), \"name_2\")\n\t\tt.Assert(oneDeleteUnscoped[\"delete_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_union_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_feature_with_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\n/*\nmysql> show tables;\n+----------------+\n| Tables_in_test |\n+----------------+\n| user           |\n| user_detail    |\n| user_score     |\n+----------------+\n3 rows in set (0.01 sec)\n\nmysql> select * from `user`;\n+----+--------+\n| id | name   |\n+----+--------+\n|  1 | name_1 |\n|  2 | name_2 |\n|  3 | name_3 |\n|  4 | name_4 |\n|  5 | name_5 |\n+----+--------+\n5 rows in set (0.01 sec)\n\nmysql> select * from `user_detail`;\n+-----+-----------+\n| uid | address   |\n+-----+-----------+\n|   1 | address_1 |\n|   2 | address_2 |\n|   3 | address_3 |\n|   4 | address_4 |\n|   5 | address_5 |\n+-----+-----------+\n5 rows in set (0.00 sec)\n\nmysql> select * from `user_score`;\n+----+-----+-------+\n| id | uid | score |\n+----+-----+-------+\n|  1 |   1 |     1 |\n|  2 |   1 |     2 |\n|  3 |   1 |     3 |\n|  4 |   1 |     4 |\n|  5 |   1 |     5 |\n|  6 |   2 |     1 |\n|  7 |   2 |     2 |\n|  8 |   2 |     3 |\n|  9 |   2 |     4 |\n| 10 |   2 |     5 |\n| 11 |   3 |     1 |\n| 12 |   3 |     2 |\n| 13 |   3 |     3 |\n| 14 |   3 |     4 |\n| 15 |   3 |     5 |\n| 16 |   4 |     1 |\n| 17 |   4 |     2 |\n| 18 |   4 |     3 |\n| 19 |   4 |     4 |\n| 20 |   4 |     5 |\n| 21 |   5 |     1 |\n| 22 |   5 |     2 |\n| 23 |   5 |     3 |\n| 24 |   5 |     4 |\n| 25 |   5 |     5 |\n+----+-----+-------+\n25 rows in set (0.00 sec)\n*/\n\nfunc Test_Table_Relation_With_Scan(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_score\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScore struct {\n\t\tgmeta.Meta `orm:\"table:user_score\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int          `json:\"id\"`\n\t\tName       string       `json:\"name\"`\n\t\tUserDetail *UserDetail  `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScore `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\tuser := User{\n\t\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t\t}\n\t\t\tlastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\tuserDetail := UserDetail{\n\t\t\t\tUid:     int(lastInsertId),\n\t\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t\t}\n\t\t\t_, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert()\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\tuserScore := UserScore{\n\t\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\t\tScore: j,\n\t\t\t\t}\n\t\t\t\t_, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\tuser := User{\n\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t}\n\t\tlastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\tuserDetail := UserDetail{\n\t\t\tUid:     int(lastInsertId),\n\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t}\n\t\t_, err = db.Model(userDetail).Data(userDetail).Insert()\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\tuserScore := UserScore{\n\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\tScore: j,\n\t\t\t}\n\t\t\t_, err = db.Model(userScore).Data(userScore).Insert()\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", 3).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserDetail).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.With(User{}).\n\t\t\tWith(UserDetail{}).\n\t\t\tWith(UserScore{}).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserDetail).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 0)\n\t})\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.Assert(user.UserDetail, nil)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 0)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 0)\n\t})\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.Assert(users[1].UserDetail, nil)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAllCondition_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id, where:uid > 3\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id, where:score>1 and score<5, order:score desc\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 3)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 4)\n\t\tt.Assert(users[0].UserScores[2].Uid, 3)\n\t\tt.Assert(users[0].UserScores[2].Score, 2)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_With_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Without_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tId   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tUserEmbedded\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_WithoutMeta(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetailBase struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tUserDetailBase\n\t}\n\n\ttype UserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag_MoreDeep(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail1 struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail2 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail1 *UserDetail1  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail3 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail2 *UserDetail2  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail3 *UserDetail3  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_AttributeStructAlsoHasWithTag_MoreDeep(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail1 struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail2 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail1 *UserDetail1  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail3 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail2 *UserDetail2  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail3 *UserDetail3  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).With(UserDetail{}, UserDetail2{}, UserDetail3{}, UserScores{}).Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1, nil)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).With(UserDetail{}, UserDetail2{}, UserDetail3{}, UserScores{}).Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1, nil)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends1(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int     `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     *TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     *TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends2(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int       `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     []*TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     []*TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.Assert(len(tableA.TableB), 2)\n\t\tt.Assert(tableA.TableB[0].Id, 10)\n\t\tt.Assert(tableA.TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA.TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA.TableB[1].TableC), 1)\n\t\tt.Assert(tableA.TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA.TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA.TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA.TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA.TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA.TableB[1].TableC[0].TableBId, 30)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\n\t\tt.Assert(len(tableA[0].TableB), 2)\n\t\tt.Assert(tableA[0].TableB[0].Id, 10)\n\t\tt.Assert(tableA[0].TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA[0].TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA[0].TableB[1].TableC), 1)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].TableBId, 30)\n\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].Id, 300)\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].TableBId, 20)\n\n\t\tt.Assert(tableA[1].TableB[1].Id, 40)\n\t\tt.Assert(tableA[1].TableB[1].TableAId, 2)\n\t\tt.Assert(tableA[1].TableB[1].TableC, nil)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends_Embedded(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\t*TableC    `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\t*TableB    `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Meta_NameMatchingRule(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user100\"\n\t\ttableUserDetail = \"user_detail100\"\n\t\ttableUserScores = \"user_scores100\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nuser_id int(10) unsigned NOT NULL,\nscore int(10) unsigned NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail100\"`\n\t\tUserID     int    `json:\"user_id\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores100\"`\n\t\tID         int `json:\"id\"`\n\t\tUserID     int `json:\"user_id\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user100\"`\n\t\tUserEmbedded\n\t\tUserDetail UserDetail    `orm:\"with:user_id=id\"`\n\t\tUserScores []*UserScores `orm:\"with:user_id=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t\t\"score\":   j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\tvar user *User\n\t//\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t//\tt.AssertNil(err)\n\t//\tt.Assert(user.ID, 3)\n\t//\tt.AssertNE(user.UserDetail, nil)\n\t//\tt.Assert(user.UserDetail.UserID, 3)\n\t//\tt.Assert(user.UserDetail.Address, `address_3`)\n\t//\tt.Assert(len(user.UserScores), 5)\n\t//\tt.Assert(user.UserScores[0].UserID, 3)\n\t//\tt.Assert(user.UserScores[0].Score, 1)\n\t//\tt.Assert(user.UserScores[4].UserID, 3)\n\t//\tt.Assert(user.UserScores[4].Score, 5)\n\t// })\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.ID, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.UserID, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].UserID, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].UserID, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Unscoped(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user101\"\n\t\ttableUserDetail = \"user_detail101\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\ndeleted_at datetime default NULL ,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail101\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Order(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user101\"\n\t\ttableUserDetail = \"user_detail101\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\ndeleted_at datetime default NULL ,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail101\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, order:user_id asc,address desc, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_model_where_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Option_Where(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 0, \"passport\": \"\"}).Where(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 1, \"passport\": \"\"}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err := db.Model(table).Where(\"id\", 1).Fields(\"nickname\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"1\")\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_1(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_2(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// complicated one.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n\nfunc Test_Model_WhereExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid         int(10) unsigned NOT NULL DEFAULT '0',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\"))\n\n\t\tr, err := db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereNotExists\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\n\t\t// Test WhereExists with empty result\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table).\n\t\t\tWhereExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereNotExists with all results\n\t\tr, err = db.Model(table).\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test combination of Where and WhereExists\n\t\tr, err = db.Model(table+\" as user\").\n\t\t\tWhere(\"id>?\", 3).\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereExists with complex subquery\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\")).\n\t\t\tWhere(\"id > ?\", 0)\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Fields\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tFields(\"id,passport\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[0][\"passport\"].String(), \"user_1\")\n\n\t\t// Test WhereExists with Group\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Having\n\t\tr, err = db.Model(table+\" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tHaving(\"id > ?\", 1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_WhereNotExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid         int(10) unsigned NOT NULL DEFAULT '0',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereNotExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\"))\n\n\t\tr, err := db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)           // Should be 8 because records with id 1 and 2 exist in table2\n\t\tt.Assert(r[0][\"id\"].Int(), 3) // First record should be id 3\n\t\tt.Assert(r[1][\"id\"].Int(), 4) // Second record should be id 4\n\n\t\t// Test WhereNotExists with empty subquery\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\") // This condition will return no results\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10) // Should return all records when subquery is empty\n\n\t\t// Test WhereNotExists with complex condition\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\")).\n\t\t\tWhere(\"id > ?\", 1)\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 9)           // Should only exclude the record with id 2\n\t\tt.Assert(r[0][\"id\"].Int(), 1) // Should include id 1\n\t})\n}\n\n// Test_Model_WherePrefixIn tests WherePrefix with IN clause\nfunc Test_Model_WherePrefixIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixIn(\"t1\", \"id\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixNotIn tests WherePrefix with NOT IN clause\nfunc Test_Model_WherePrefixNotIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotIn(\"t1\", \"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"8\")\n\t\tt.Assert(r[2][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixBetween tests WherePrefix with BETWEEN clause\nfunc Test_Model_WherePrefixBetween(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixBetween(\"t1\", \"id\", 3, 6).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[3][\"id\"], \"6\")\n\t})\n}\n\n// Test_Model_WherePrefixNotBetween tests WherePrefix with NOT BETWEEN clause\nfunc Test_Model_WherePrefixNotBetween(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotBetween(\"t1\", \"id\", 3, 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// NOT BETWEEN 3 AND 7 returns: 1, 2, 8, 9, 10 (5 records)\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t\tt.Assert(r[4][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixLT tests WherePrefix with < operator\nfunc Test_Model_WherePrefixLT(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixLT(\"t1\", \"id\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixLTE tests WherePrefix with <= operator\nfunc Test_Model_WherePrefixLTE(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixLTE(\"t1\", \"id\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[3][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_WherePrefixGT tests WherePrefix with > operator\nfunc Test_Model_WherePrefixGT(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixGT(\"t1\", \"id\", 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"8\")\n\t\tt.Assert(r[2][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixGTE tests WherePrefix with >= operator\nfunc Test_Model_WherePrefixGTE(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixGTE(\"t1\", \"id\", 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"7\")\n\t\tt.Assert(r[3][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixNotLike tests WherePrefix with NOT LIKE operator\nfunc Test_Model_WherePrefixNotLike(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotLike(\"t1\", \"nickname\", \"name_1%\").\n\t\t\tWhere(\"t1.id <\", 5).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should exclude name_1 and name_10 (but id 10 filtered by WHERE anyway)\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[2][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_WherePrefixNull tests WherePrefix with IS NULL\nfunc Test_Model_WherePrefixNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\t// table2 has partial data, will cause NULLs in LEFT JOIN\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, _ = db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNull(\"t2\", \"nickname\").\n\t\t\tWhere(\"t1.id <=\", 3).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// t2 only has id=1, so id 2,3 should have NULL in t2.nickname\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixNotNull tests WherePrefix with IS NOT NULL\nfunc Test_Model_WherePrefixNotNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\t// table2 has partial data\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, _ = db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotNull(\"t2\", \"nickname\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// t2 has id 1,2, so only these should have NOT NULL in t2.nickname\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\n// Test_Model_WhereOrPrefixIn tests WhereOrPrefix with IN clause\nfunc Test_Model_WhereOrPrefixIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhereOrPrefixIn(\"t1\", \"id\", g.Slice{1, 2}).\n\t\t\tWhereOrPrefixIn(\"t2\", \"id\", g.Slice{8, 9}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\n// Test_Model_WhereOrPrefixNotIn tests WhereOrPrefix with NOT IN clause\nfunc Test_Model_WhereOrPrefixNotIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhereOrPrefixNotIn(\"t1\", \"id\", g.Slice{1}).\n\t\t\tWhereOrPrefixNotIn(\"t2\", \"id\", g.Slice{2, 3, 4, 5, 6, 7, 8, 9, 10}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 10) // All records match one OR condition\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t})\n}\n\n// Test_Model_Having_Aggregate tests HAVING clause with aggregate functions\nfunc Test_Model_Having_Aggregate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with COUNT\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >= ?\", 3).\n\t\t\tOrder(\"mod_group asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// mod 0: 3,6,9 (3 items)\n\t\t// mod 1: 1,4,7,10 (4 items)\n\t\t// mod 2: 2,5,8 (3 items)\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"mod_group\"], \"0\")\n\t\tt.Assert(r[0][\"cnt\"], \"3\")\n\t\tt.Assert(r[1][\"cnt\"], \"4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with SUM\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 2 AS parity\", \"SUM(id) AS total\").\n\t\t\tGroup(\"parity\").\n\t\t\tHaving(\"SUM(id) > ?\", 25).\n\t\t\tOrder(\"parity asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// even (2,4,6,8,10): sum=30\n\t\t// odd (1,3,5,7,9): sum=25\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"parity\"], \"0\")\n\t\tt.Assert(r[0][\"total\"], \"30\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with AVG\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id DIV 5 AS group_key\", \"AVG(id) AS avg_id\").\n\t\t\tGroup(\"group_key\").\n\t\t\tHaving(\"AVG(id) >= ?\", 5).\n\t\t\tOrder(\"group_key asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// group 0 (id 1-4): avg=2.5\n\t\t// group 1 (id 5-9): avg=7\n\t\t// group 2 (id 10): avg=10\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"group_key\"], \"1\")\n\t})\n}\n\n// Test_Model_Having_MultipleConditions tests HAVING with multiple conditions\nfunc Test_Model_Having_MultipleConditions(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple HAVING conditions\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\", \"SUM(id) AS total\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >= ?\", 3).\n\t\t\tHaving(\"SUM(id) < ?\", 30).\n\t\t\tOrder(\"mod_group asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// mod 0: cnt=3, sum=18 (3+6+9) ✓\n\t\t// mod 1: cnt=4, sum=22 (1+4+7+10) ✓\n\t\t// mod 2: cnt=3, sum=15 (2+5+8) ✓\n\t\tt.Assert(len(r), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with complex expression\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id DIV 3 AS group_key\", \"MAX(id) - MIN(id) AS range_val\").\n\t\t\tGroup(\"group_key\").\n\t\t\tHaving(\"MAX(id) - MIN(id) >= ?\", 2).\n\t\t\tOrder(\"group_key asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// group 0 (1,2): range=1\n\t\t// group 1 (3,4,5): range=2 ✓\n\t\t// group 2 (6,7,8): range=2 ✓\n\t\t// group 3 (9,10): range=1\n\t\tt.Assert(len(r), 2)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/mariadb_z_unit_transaction_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mariadb_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_TX_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tst, err := tx.Prepare(\"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(array[0], \"100\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tuser := tx.Model(table)\n\n\t\t_, err = user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\t})\n}\n\nfunc Test_TX_BatchReplace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Replace(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"PASS_2\")\n\t})\n}\n\nfunc Test_TX_BatchSave(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Save(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 4).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"PASS_4\")\n\t})\n}\n\nfunc Test_TX_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Replace(table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_TX_Save(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Save(table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_TX_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.Update(table, \"create_time='2019-10-24 10:00:00'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"2019-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_TX_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.GetAll(fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(result), 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\trecord, err := tx.GetOne(fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_2\")\n\t\tt.AssertNil(err)\n\n\t\tt.AssertNE(record, nil)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_2\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := tx.GetValue(fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.Int(), 3)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := tx.GetCount(\"SELECT * FROM \" + table)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(TableSize))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Delete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Delete(table, 1)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Delete(table, 1)\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(0))\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tn, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\t\tt.AssertNE(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Ctx(ctx).Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\tt.Assert(tx.IsClosed(), false)\n\t\t\treturn gerror.New(\"error\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Ctx(ctx).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_Transaction_Panic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tpanic(\"error\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_Transaction_Nested_Begin_Rollback_Commit(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx begin.\n\t\terr = tx.Begin()\n\t\tt.AssertNil(err)\n\n\t\t// tx rollback.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"user_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).Insert()\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       2,\n\t\t\t\"passport\": \"user_2\",\n\t\t\t\"password\": \"pass_2\",\n\t\t\t\"nickname\": \"name_2\",\n\t\t}).Insert()\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseTX(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\t// another record.\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseDB(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_SavePoint_RollbackTo(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx save point.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"user_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).Insert()\n\t\terr = tx.SavePoint(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       2,\n\t\t\t\"passport\": \"user_2\",\n\t\t\t\"password\": \"pass_2\",\n\t\t\t\"nickname\": \"name_2\",\n\t\t}).Insert()\n\t\t// tx rollback to.\n\t\terr = tx.RollbackTo(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Transaction_Method(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = db.Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\n\t\t\t_, err = db.Ctx(ctx).Exec(ctx, fmt.Sprintf(\n\t\t\t\t\"insert into %s(`passport`,`password`,`nickname`,`create_time`,`id`) \"+\n\t\t\t\t\t\"VALUES('t2','25d55ad283aa400af464c76d713c07ad','T2','2021-08-25 21:53:00',2) \",\n\t\t\t\ttable))\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\nfunc Test_Transaction_Propagation(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationRequired\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert initial record\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"required\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Nested transaction with PropagationRequired\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should use the same transaction\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       2,\n\t\t\t\t\t\"passport\": \"required_nested\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify both records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationRequiresNew\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       3,\n\t\t\t\t\"passport\": \"outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Inner transaction with PropagationRequiresNew\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// This is a new transaction\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       4,\n\t\t\t\t\t\"passport\": \"inner_new\",\n\t\t\t\t})\n\t\t\t\t// Simulate error to test independent rollback\n\t\t\t\treturn gerror.New(\"rollback inner transaction\")\n\t\t\t})\n\t\t\t// Inner transaction error should not affect outer transaction\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify only outer transaction record exists\n\t\tcount, err := db.Model(table).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNested\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       5,\n\t\t\t\t\"passport\": \"nested_outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Nested transaction\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       6,\n\t\t\t\t\t\"passport\": \"nested_inner\",\n\t\t\t\t})\n\t\t\t\t// Simulate error to test savepoint rollback\n\t\t\t\treturn gerror.New(\"rollback to savepoint\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Insert another record after nested transaction rollback\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       7,\n\t\t\t\t\"passport\": \"nested_after\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify outer transaction records exist, but nested transaction record doesn't\n\t\tcount, err := db.Model(table).Where(\"passport\", \"nested_inner\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"nested_outer\", \"nested_after\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNotSupported\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       8,\n\t\t\t\t\"passport\": \"tx_record\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Non-transactional operation\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should execute without transaction\n\t\t\t\t_, err = db.Insert(ctx, table, g.Map{\n\t\t\t\t\t\"id\":       9,\n\t\t\t\t\t\"passport\": \"non_tx_record\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify transactional record is rolled back but non-transactional record exists\n\t\tcount, err := db.Model(table).Where(\"passport\", \"tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"non_tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationMandatory\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn nil\n\t\t})\n\t\t// Should fail because no transaction exists\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test within an existing transaction\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should succeed because transaction exists\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       10,\n\t\t\t\t\t\"passport\": \"mandatory\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNever\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationNever,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\t\"id\":       11,\n\t\t\t\t\"passport\": \"never\",\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test within an existing transaction\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNever,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t\t// Should fail because transaction exists\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Transaction_Propagation_PropagationSupports(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// scenario1: when in a transaction, use PropagationSupports to execute a transaction\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// insert in outer tx.\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\": 1,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationSupports,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\": 2,\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"error\")\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// scenario2: when not in a transaction, do not use transaction but direct db link.\n\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationSupports,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\": 3,\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// 查询结果\n\t\tresult, err := db.Model(table).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Complex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createTable()\n\t\ttable2 := createTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\t// Test nested transactions with different propagation behaviors\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx1.Insert(table1, g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// First nested transaction (NESTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table1, g.Map{\n\t\t\t\t\t\"id\":       2,\n\t\t\t\t\t\"passport\": \"nested1\",\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// Second nested transaction (REQUIRES_NEW)\n\t\t\t\terr = tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":       3,\n\t\t\t\t\t\t\"passport\": \"new1\",\n\t\t\t\t\t})\n\t\t\t\t\t// This will be rolled back independently\n\t\t\t\t\treturn gerror.New(\"rollback new transaction\")\n\t\t\t\t})\n\t\t\t\tt.AssertNE(err, nil)\n\n\t\t\t\t// Third nested transaction (NESTED)\n\t\t\t\treturn tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":       4,\n\t\t\t\t\t\t\"passport\": \"nested2\",\n\t\t\t\t\t})\n\t\t\t\t\t// This will rollback to the savepoint\n\t\t\t\t\treturn gerror.New(\"rollback nested transaction\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Fourth transaction (NOT_SUPPORTED)\n\t\t\t// Note that, it locks table if it continues using table1.\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table2, g.Map{\n\t\t\t\t\t\"id\":       5,\n\t\t\t\t\t\"passport\": \"not_supported\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify final state\n\t\t// 1. \"outer\" should exist (committed)\n\t\tcount, err := db.Model(table1).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\n\t\t// 2. \"nested1\" should not exist (rolled back due to error)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 3. \"new1\" should not exist (rolled back independently)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"new1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 4. \"nested2\" should not exist (rolled back to savepoint)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested2\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 5. \"not_supported\" should exist (non-transactional)\n\t\tcount, err = db.Model(table2).Where(\"passport\", \"not_supported\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test transaction suspension and resume\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          6,\n\t\t\t\t\"passport\":    \"suspend_outer\",\n\t\t\t\t\"password\":    \"pass6\",\n\t\t\t\t\"nickname\":    \"suspend_outer\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Suspend current transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Start a new independent transaction\n\t\t\t\treturn db.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":          7,\n\t\t\t\t\t\t\"passport\":    \"independent\",\n\t\t\t\t\t\t\"password\":    \"pass7\",\n\t\t\t\t\t\t\"nickname\":    \"independent\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Resume original transaction\n\t\t\t_, err = tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"suspend_resume\",\n\t\t\t\t\"password\":    \"pass8\",\n\t\t\t\t\"nickname\":    \"suspend_resume\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Simulate error to rollback outer transaction\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify final state\n\t\t// 1. \"suspend_outer\" and \"suspend_resume\" should not exist (rolled back)\n\t\tcount, err := db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"suspend_outer\", \"suspend_resume\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 2. \"independent\" should exist (committed independently)\n\t\tcount, err = db.Model(table).Where(\"passport\", \"independent\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_ReadOnly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test read-only transaction\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Try to modify data in read-only transaction\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"changed\"}, \"id=1\")\n\t\t\t// Should return error\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify data was not modified\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n}\n\nfunc Test_Transaction_Isolation(t *testing.T) {\n\t// Test READ UNCOMMITTED\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tIsolation: sql.LevelReadUncommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Update value in first transaction\n\t\t\t_, err := tx1.Update(table, g.Map{\"passport\": \"dirty_read\"}, \"id=1\")\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Start another transaction to verify dirty read\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tIsolation: sql.LevelReadUncommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should see uncommitted change in READ UNCOMMITTED\n\t\t\t\tv, err := tx2.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.Assert(v.String(), \"dirty_read\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Rollback the first transaction\n\t\t\treturn gerror.New(\"rollback first transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify the value is rolled back\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n\n\t// Test REPEATABLE READ (default)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\t// Start a transaction with REPEATABLE READ isolation\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits the value\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\n\t\t\t\t\t\"passport\": \"changed_value\",\n\t\t\t\t}, \"id=1\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Verify the change is visible outside transaction\n\t\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v.String(), \"changed_value\")\n\n\t\t\t// Should still see old value in REPEATABLE READ transaction\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), initialValue)\n\n\t\t\t// Even after multiple reads, should still see the same value\n\t\t\tv3, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v3.String(), initialValue)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// After transaction ends, should see the committed change\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"changed_value\")\n\t})\n\n\t// Test SERIALIZABLE\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read all records\n\t\t\t_, err := tx1.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Try concurrent insert in another transaction\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       1000,\n\t\t\t\t\t\"passport\": \"new_user\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test READ COMMITTED\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"committed_value\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Should see new value in READ COMMITTED\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), \"committed_value\")\n\t\t\tt.AssertNE(v2.String(), initialValue)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Spread(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\terr = db.Transaction(tx.GetCtx(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := tx.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0)\n\t})\n}\n\n// ========== Deep Transaction Enhancement Tests ==========\n\n// Test_Transaction_Isolation_ReadCommitted_NonRepeatableRead tests READ COMMITTED isolation level\n// allows non-repeatable reads - same query can return different results within the same transaction\nfunc Test_Transaction_Isolation_ReadCommitted_NonRepeatableRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tfirstRead := v1.String()\n\t\t\tt.Assert(firstRead, \"user_1\")\n\n\t\t\t// External transaction commits a change\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"user_1_modified\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Second read - should see the committed change (non-repeatable read)\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tsecondRead := v2.String()\n\t\t\tt.Assert(secondRead, \"user_1_modified\")\n\t\t\tt.AssertNE(firstRead, secondRead)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Isolation_Serializable_PhantomRead tests SERIALIZABLE isolation level\n// prevents phantom reads - range queries see consistent snapshot\nfunc Test_Transaction_Isolation_Serializable_PhantomRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First count\n\t\t\tcount1, err := tx1.Model(table).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count1, int64(TableSize))\n\n\t\t\t// Try to insert in another transaction.\n\t\t\t// InnoDB's SERIALIZABLE uses gap locks; whether this insert conflicts\n\t\t\t// depends on table state and index structure, so we do not assert on err.\n\t\t\t_ = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       100,\n\t\t\t\t\t\"passport\": \"phantom_user\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\n\t\t\t// Second count - should remain the same\n\t\t\tcount2, err := tx1.Model(table).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count2, count1)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Isolation_RepeatableRead_ConsistentSnapshot tests REPEATABLE READ isolation\n// maintains consistent snapshot throughout transaction\nfunc Test_Transaction_Isolation_RepeatableRead_ConsistentSnapshot(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read multiple records\n\t\t\trecords1, err := tx1.Model(table).Where(\"id IN(?,?)\", 1, 2).All()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(records1), 2)\n\n\t\t\t// External transaction modifies both records\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"nickname\": \"modified\"}, \"id IN(?,?)\", 1, 2)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Re-read - should see original values\n\t\t\trecords2, err := tx1.Model(table).Where(\"id IN(?,?)\", 1, 2).All()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(records2), 2)\n\t\t\tfor i := 0; i < 2; i++ {\n\t\t\t\tt.Assert(records1[i][\"nickname\"], records2[i][\"nickname\"])\n\t\t\t\tt.AssertNE(records2[i][\"nickname\"].String(), \"modified\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Deadlock_TwoTables tests deadlock detection with two tables\nfunc Test_Transaction_Deadlock_TwoTables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable()\n\t\ttable2 := createInitTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tvar wg sync.WaitGroup\n\t\terrs := make([]error, 2)\n\t\t// Use channels to synchronize lock acquisition order.\n\t\ttx1Locked := make(chan struct{})\n\t\ttx2Locked := make(chan struct{})\n\n\t\t// Transaction 1: lock table1 then table2\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[0] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t_, err := tx.Update(table1, g.Map{\"passport\": \"tx1_lock\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx1Locked)\n\t\t\t\t<-tx2Locked\n\t\t\t\t_, err = tx.Update(table2, g.Map{\"passport\": \"tx1_lock\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Transaction 2: lock table2 then table1\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[1] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t<-tx1Locked\n\t\t\t\t_, err := tx.Update(table2, g.Map{\"passport\": \"tx2_lock\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx2Locked)\n\t\t\t\t_, err = tx.Update(table1, g.Map{\"passport\": \"tx2_lock\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Wait for both transactions to complete\n\t\twg.Wait()\n\n\t\t// At least one transaction should fail due to deadlock\n\t\tt.Assert(errs[0] != nil || errs[1] != nil, true)\n\t})\n}\n\n// Test_Transaction_Deadlock_SameTable tests deadlock detection on same table\nfunc Test_Transaction_Deadlock_SameTable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg sync.WaitGroup\n\t\terrs := make([]error, 2)\n\t\t// Use channels to synchronize lock acquisition order.\n\t\ttx1Locked := make(chan struct{})\n\t\ttx2Locked := make(chan struct{})\n\n\t\t// Transaction 1: lock id=1 then id=2\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[0] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t_, err := tx.Update(table, g.Map{\"nickname\": \"tx1\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx1Locked)\n\t\t\t\t<-tx2Locked\n\t\t\t\t_, err = tx.Update(table, g.Map{\"nickname\": \"tx1\"}, \"id=2\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Transaction 2: lock id=2 then id=1\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[1] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t<-tx1Locked\n\t\t\t\t_, err := tx.Update(table, g.Map{\"nickname\": \"tx2\"}, \"id=2\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx2Locked)\n\t\t\t\t_, err = tx.Update(table, g.Map{\"nickname\": \"tx2\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Wait for both transactions to complete\n\t\twg.Wait()\n\n\t\t// At least one transaction should fail due to deadlock\n\t\tt.Assert(errs[0] != nil || errs[1] != nil, true)\n\t})\n}\n\n// Test_Transaction_Deadlock_Retry tests automatic retry on deadlock\nfunc Test_Transaction_Deadlock_Retry(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmaxRetries := 3\n\t\tvar retryCount int\n\n\t\texecuteWithRetry := func(fn func(context.Context, gdb.TX) error) error {\n\t\t\tfor i := 0; i < maxRetries; i++ {\n\t\t\t\terr := db.Transaction(ctx, fn)\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t// Check if error message contains deadlock-related keywords.\n\t\t\t\terrMsg := err.Error()\n\t\t\t\tif gstr.ContainsI(errMsg, \"deadlock\") || gstr.ContainsI(errMsg, \"lock wait timeout\") {\n\t\t\t\t\tretryCount++\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn gerror.New(\"max retries exceeded\")\n\t\t}\n\n\t\t// A simple non-conflicting update should succeed on first attempt.\n\t\terr := executeWithRetry(func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"retry_test\"}, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(retryCount, 0)\n\t})\n}\n\n// Test_Transaction_Nested_7Levels tests 7-level deep nested transactions\nfunc Test_Transaction_Nested_7Levels(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(7))\n\t})\n}\n\n// Test_Transaction_Nested_7Levels_PartialRollback tests partial rollback in deep nesting\nfunc Test_Transaction_Nested_7Levels_PartialRollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\t\t// Fail at deepest level\n\t\t\t\t\t\t\t\t\treturn gerror.New(\"rollback from level 7\")\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify all records are rolled back\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\n// Test_Transaction_Nested_10Levels tests maximum depth of 10 levels\nfunc Test_Transaction_Nested_10Levels(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\treturn tx7.Transaction(ctx, func(ctx context.Context, tx8 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t_, err := tx8.Insert(table, g.Map{\"id\": 8, \"passport\": \"level8\"})\n\t\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\t\treturn tx8.Transaction(ctx, func(ctx context.Context, tx9 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t\t_, err := tx9.Insert(table, g.Map{\"id\": 9, \"passport\": \"level9\"})\n\t\t\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\t\t\treturn tx9.Transaction(ctx, func(ctx context.Context, tx10 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t\t\t_, err := tx10.Insert(table, g.Map{\"id\": 10, \"passport\": \"level10\"})\n\t\t\t\t\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(10))\n\t})\n}\n\n// Test_Transaction_Nested_SavePoint_Multiple tests multiple savepoints in nested transactions\nfunc Test_Transaction_Nested_SavePoint_Multiple(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create first savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"sp1\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp1\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create second savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 2, \"passport\": \"sp2\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp2\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create third savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 3, \"passport\": \"sp3\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp3\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert without savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 4, \"passport\": \"no_sp\"})\n\t\tt.AssertNil(err)\n\n\t\t// Rollback to sp2\n\t\terr = tx.RollbackTo(\"sp2\")\n\t\tt.AssertNil(err)\n\n\t\t// Commit transaction\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only records up to sp2 exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tv1, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v1.String(), \"sp1\")\n\n\t\tv2, err := db.Model(table).Where(\"id=2\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), \"sp2\")\n\t})\n}\n\n// Test_Transaction_Nested_SavePoint_RollbackToNonExistent tests rollback to non-existent savepoint\nfunc Test_Transaction_Nested_SavePoint_RollbackToNonExistent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\t// Try to rollback to non-existent savepoint\n\t\terr = tx.RollbackTo(\"non_existent\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Concurrent_Insert tests concurrent inserts in separate transactions\nfunc Test_Transaction_Concurrent_Insert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg = sync.WaitGroup{}\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(index int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":       index + 1,\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", index+1),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(concurrency))\n\t})\n}\n\n// Test_Transaction_Concurrent_Update tests concurrent updates to same record\nfunc Test_Transaction_Concurrent_Update(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg = sync.WaitGroup{}\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(index int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_ = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Update(table, g.Map{\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"concurrent_%d\", index),\n\t\t\t\t\t}, \"id=1\")\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t}(i)\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Verify record was updated (one of the concurrent values should win)\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"nickname\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(v.String(), \"name_1\")\n\t})\n}\n\n// Test_Transaction_Mixed_Propagation_Nested tests mixed propagation modes in nested transactions\nfunc Test_Transaction_Mixed_Propagation_Nested(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"outer\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// REQUIRES_NEW - should create independent transaction\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"independent\"})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// NESTED - should create savepoint\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 3, \"passport\": \"nested\"})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn gerror.New(\"rollback nested\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// REQUIRED - should use existing transaction\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 4, \"passport\": \"required\"})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify results: outer, independent, and required should exist; nested should not\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\texists, err := db.Model(table).Where(\"passport\", \"nested\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exists, int64(0))\n\t})\n}\n\n// Test_Transaction_Rollback_After_Commit tests that rollback after commit fails\nfunc Test_Transaction_Rollback_After_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Try to rollback after commit\n\t\terr = tx.Rollback()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Commit_After_Rollback tests that commit after rollback fails\nfunc Test_Transaction_Commit_After_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// Try to commit after rollback\n\t\terr = tx.Commit()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Operation_After_Commit tests that operations after commit fail\nfunc Test_Transaction_Operation_After_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Try to insert after commit\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Operation_After_Rollback tests that operations after rollback fail\nfunc Test_Transaction_Operation_After_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// Try to insert after rollback\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Context_Timeout tests transaction with context timeout\nfunc Test_Transaction_Context_Timeout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Create context with timeout\n\t\tctx, cancel := context.WithTimeout(context.Background(), 100*gtime.MS)\n\t\tdefer cancel()\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Wait for context timeout instead of using fixed sleep.\n\t\t\t<-ctx.Done()\n\t\t\treturn ctx.Err()\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Context_Cancel tests transaction with context cancellation\nfunc Test_Transaction_Context_Cancel(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tcancel()\n\t\t}()\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Wait for context cancellation instead of using fixed sleep.\n\t\t\t<-ctx.Done()\n\t\t\treturn ctx.Err()\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Empty_NoOperations tests empty transaction with no operations\nfunc Test_Transaction_Empty_NoOperations(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// No operations\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Large_Batch_Insert tests transaction with large batch insert\nfunc Test_Transaction_Large_Batch_Insert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\tbatchSize := 1000\n\t\t\tdata := make(g.List, batchSize)\n\t\t\tfor i := 0; i < batchSize; i++ {\n\t\t\t\tdata[i] = g.Map{\n\t\t\t\t\t\"id\":       i + 1,\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", i+1),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_, err := tx.Insert(table, data)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1000))\n\t})\n}\n\n// Test_Transaction_Large_Batch_Update tests transaction with large batch update\nfunc Test_Transaction_Large_Batch_Update(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// First insert records\n\t\tbatchSize := 500\n\t\tdata := make(g.List, batchSize)\n\t\tfor i := 0; i < batchSize; i++ {\n\t\t\tdata[i] = g.Map{\n\t\t\t\t\"id\":       i + 1,\n\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", i+1),\n\t\t\t}\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\t// Update all records in transaction (WHERE required for safety)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Where(\"id > ?\", 0).Update(g.Map{\"nickname\": \"updated\"})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records updated\n\t\tcount, err := db.Model(table).Where(\"nickname\", \"updated\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(batchSize))\n\t})\n}\n\n// Test_Transaction_ReadOnly_WithUpdate tests that updates fail in read-only transactions\nfunc Test_Transaction_ReadOnly_WithUpdate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Read operations should work\n\t\t\t_, err := tx.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Write operations should fail\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       100,\n\t\t\t\t\"passport\": \"new_user\",\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_ReadOnly_WithDelete tests that deletes fail in read-only transactions\nfunc Test_Transaction_ReadOnly_WithDelete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Delete(table, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify record still exists\n\t\tcount, err := db.Model(table).Where(\"id=1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/fix_gdb_join.sql",
    "content": "\n\nDROP TABLE IF EXISTS `common_resource`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `common_resource` (\n    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) NOT NULL,\n    `resource_id` varchar(64) NOT NULL,\n    `src_instance_id` varchar(64) DEFAULT NULL,\n    `region` varchar(36) DEFAULT NULL,\n    `zone` varchar(36) DEFAULT NULL,\n    `database_kind` varchar(20) NOT NULL,\n    `source_type` varchar(64) NOT NULL,\n    `ip` varchar(64) DEFAULT NULL,\n    `port` int(10) DEFAULT NULL,\n    `vpc_id` varchar(20) DEFAULT NULL,\n    `subnet_id` varchar(20) DEFAULT NULL,\n    `proxy_ip` varchar(64) DEFAULT NULL,\n    `proxy_port` int(10) DEFAULT NULL,\n    `proxy_id` bigint(20) DEFAULT NULL,\n    `proxy_snat_ip` varchar(64) DEFAULT NULL,\n    `lease_at` timestamp NULL DEFAULT NULL,\n    `uin` varchar(32) NOT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `unique_resource` (`app_id`,`src_instance_id`,`vpc_id`,`subnet_id`,`ip`,`port`),\n    KEY `resource_id` (`resource_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COMMENT='资源公共信息表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `common_resource`\n--\n\nLOCK TABLES `common_resource` WRITE;\n/*!40000 ALTER TABLE `common_resource` DISABLE KEYS */;\nINSERT INTO `common_resource` VALUES (1,1,'2','2','2','3','1','1','1',1,'1','1','1',1,1,'1',NULL,''),(3,2,'3','3','3','3','3','3','3',3,'3','3','3',3,3,'3',NULL,''),(18,1303697168,'dmc-rgnh9qre','vdb-6b6m3u1u','ap-guangzhou','','vdb','cloud','10.0.1.16',80,'vpc-m3dchft7','subnet-9as3a3z2','9.27.72.189',11131,228476,'169.254.128.5, ','2023-11-08 08:13:04',''),(20,1303697168,'dmc-4grzi4jg','tdsqlshard-313spncx','ap-guangzhou','','tdsql','cloud','10.255.0.27',3306,'vpc-407k0e8x','subnet-qhkkk3bo','30.86.239.200',24087,0,'',NULL,'');\n/*!40000 ALTER TABLE `common_resource` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `managed_resource`\n--\n\nDROP TABLE IF EXISTS `managed_resource`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `managed_resource` (\n     `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n     `instance_id` varchar(64) NOT NULL,\n     `resource_id` varchar(64) NOT NULL,\n     `resource_name` varchar(64) DEFAULT NULL,\n     `status` varchar(36) NOT NULL DEFAULT 'valid',\n     `status_message` varchar(64) DEFAULT NULL,\n     `user` varchar(64) NOT NULL,\n     `password` varchar(1024) NOT NULL,\n     `pay_mode` tinyint(1) DEFAULT '0',\n     `safe_publication` bit(1) DEFAULT b'0',\n     `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n     `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n     `expired_at` timestamp NULL DEFAULT NULL,\n     `deleted` tinyint(1) NOT NULL DEFAULT '0',\n     `resource_mark_id` int(11) DEFAULT NULL,\n     `comments` varchar(64) DEFAULT NULL,\n     `rule_template_id` varchar(64) NOT NULL,\n     PRIMARY KEY (`id`),\n     UNIQUE KEY `resource_id` (`resource_id`),\n     KEY `instance_id` (`instance_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='管控实例表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `managed_resource`\n--\n\nLOCK TABLES `managed_resource` WRITE;\n/*!40000 ALTER TABLE `managed_resource` DISABLE KEYS */;\nINSERT INTO `managed_resource` VALUES (1,'2','3','1','1','1','1','1',1,_binary '\u0001','2023-11-06 12:14:21','2023-11-06 12:14:21',NULL,1,1,'1',''),(2,'3','2','1','1','1','1','1',1,_binary '\\0','2023-11-06 12:15:07','2023-11-06 12:15:07',NULL,1,2,'1',''),(5,'dmcins-jxy0x75m','dmc-rgnh9qre','erichmao-vdb-test','invalid','The Ip field is required','root','2e39af3dd1d447e2b1437b40c62c35995fa22b370c7455ff7815dace3a6e8891ccadcfc893fe1342a4102d742bd7a3e603cd0ac1fcdc072d7c0b5be5836ec87306981b629f9b59aedf0316e9504ab172fa1c95756d5b260114e4feaa0b19223fb61cb268cc4818307ed193dbab830cf556b91cde182686eb70f70ea77f69eff66230dec2ce92bd3352cad31abf47597a5cc6a0d638381dc3bae7aa1b142730790a6d4cefdef1bd460061c966ad5008c2b5fc971b7f4d7dddffa5b1456c45e2917763dd8fffb1fa7fc4783feca95dafc9a9f4edf21b0579f76b0a3154f087e3b9a7fc49af8ff92b12e7b03caa865e72e777dd9d35a11910df0d55ead90e47d5f8',1,_binary '\u0001','2023-11-08 08:13:20','2023-11-09 05:31:07',NULL,0,11,NULL,'12345'),(6,'dmcins-erxms6ya','dmc-4grzi4jg','erichmao-vdb-test','invalid','The Ip field is required','leotaowang','641d846cf75bc7944202251d97dca8335f7f149dd4fd911ca5b87c71ef1dc5d0a66c4e5021ef7ad53136cda2fb2567d34e3dd1a7666e3f64ebf532eb2a55d84952aac86b4211f563f7b9da7dd0f88ec288d6680d3513cea0c1b7ad7babb474717f77ebbc9d63bb458adaf982887da9e63df957ffda572c1c3ed187471b99fdc640b45fed76a6d50dc1090eee79b4d94d056c4d43416133481f55bd040759398680104a84d801e6475dcfe919a00859908296747430b728a00c8d54256ae220235a138e0bbf08fe8b6fc8589971436b55bff966154721a91adbdc9c2b6f50ef5849ed77e5b028116abac51584b8d401cd3a88d18df127006358ed33fc3fa6f480',1,_binary '\u0001','2023-11-08 22:15:17','2023-11-09 05:31:07',NULL,0,11,NULL,'12345');\n/*!40000 ALTER TABLE `managed_resource` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `rules_template`\n--\n\nDROP TABLE IF EXISTS `rules_template`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `rules_template` (\n    `id` bigint(20) NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) DEFAULT NULL,\n    `name` varchar(255) NOT NULL,\n    `database_kind` varchar(64) DEFAULT NULL,\n    `is_default` tinyint(1) NOT NULL DEFAULT '0',\n    `win_rules` varchar(2048) DEFAULT NULL,\n    `inception_rules` varchar(2048) DEFAULT NULL,\n    `auto_exec_rules` varchar(2048) DEFAULT NULL,\n    `order_check_step` varchar(2048) DEFAULT NULL,\n    `template_id` varchar(64) NOT NULL DEFAULT '',\n    `version` int(11) NOT NULL DEFAULT '1',\n    `deleted` tinyint(1) NOT NULL DEFAULT '0',\n    `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n    `is_system` tinyint(1) NOT NULL DEFAULT '0',\n    `uin` varchar(64) DEFAULT NULL,\n    `subAccountUin` varchar(64) DEFAULT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `uniq_template_id` (`template_id`),\n    UNIQUE KEY `uniq_name` (`name`,`app_id`,`deleted`,`uin`) USING BTREE\n) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `rules_template`\n--\n\nLOCK TABLES `rules_template` WRITE;\n/*!40000 ALTER TABLE `rules_template` DISABLE KEYS */;\n/*!40000 ALTER TABLE `rules_template` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `resource_mark`\n--\n\nDROP TABLE IF EXISTS `resource_mark`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `resource_mark` (\n    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) NOT NULL,\n    `mark_name` varchar(64) NOT NULL,\n    `color` varchar(11) NOT NULL,\n    `creator` varchar(32) NOT NULL,\n    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `app_id_name` (`app_id`,`mark_name`)\n) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='标签信息表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `resource_mark`\n--\n\nLOCK TABLES `resource_mark` WRITE;\n/*!40000 ALTER TABLE `resource_mark` DISABLE KEYS */;\nINSERT INTO `resource_mark` VALUES (10,1,'test','red','1','2023-11-06 02:45:46','2023-11-06 02:45:46');\n/*!40000 ALTER TABLE `resource_mark` ENABLE KEYS */;\nUNLOCK TABLES;\n\n"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/fix_gdb_join_expect.sql",
    "content": "SELECT `managed_resource`.`resource_id`,`managed_resource`.`user`,`managed_resource`.`status`,`managed_resource`.`status_message`,`managed_resource`.`safe_publication`,`managed_resource`.`rule_template_id`,`managed_resource`.`created_at`,`managed_resource`.`comments`,`managed_resource`.`expired_at`,`managed_resource`.`resource_mark_id`,`managed_resource`.`instance_id`,`managed_resource`.`resource_name`,`managed_resource`.`pay_mode`,`resource_mark`.`mark_name`,`resource_mark`.`color`,`rules_template`.`name`,`common_resource`.`src_instance_id`,`common_resource`.`database_kind`,`common_resource`.`source_type`,`common_resource`.`ip`,`common_resource`.`port` FROM `managed_resource` LEFT JOIN `common_resource` ON (`managed_resource`.`resource_id`=`common_resource`.`resource_id`) LEFT JOIN `resource_mark` ON (`managed_resource`.`resource_mark_id` = `resource_mark`.`id`) LEFT JOIN `rules_template` ON (`managed_resource`.`rule_template_id` = `rules_template`.`template_id`) ORDER BY `src_instance_id` ASC"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/table_with_prefix.sql",
    "content": "CREATE TABLE `instance`  (\n    `f_id` int(11) NOT NULL AUTO_INCREMENT,\n    `name` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`f_id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `instance` VALUES (1, 'john');"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/with_multiple_depends.sql",
    "content": "\nCREATE TABLE `table_a`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_a` VALUES (1, 'table_a_test1');\nINSERT INTO `table_a` VALUES (2, 'table_a_test2');\n\nCREATE TABLE `table_b`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_a_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_b` VALUES (10, 1, 'table_b_test1');\nINSERT INTO `table_b` VALUES (20, 2, 'table_b_test2');\nINSERT INTO `table_b` VALUES (30, 1, 'table_b_test3');\nINSERT INTO `table_b` VALUES (40, 2, 'table_b_test4');\n\nCREATE TABLE `table_c`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_b_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_c` VALUES (100, 10, 'table_c_test1');\nINSERT INTO `table_c` VALUES (200, 10, 'table_c_test2');\nINSERT INTO `table_c` VALUES (300, 20, 'table_c_test3');\nINSERT INTO `table_c` VALUES (400, 30, 'table_c_test4');"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/with_tpl_user.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id int(10) unsigned NOT NULL AUTO_INCREMENT,\n    name varchar(45) NOT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/with_tpl_user_detail.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n    address varchar(45) NOT NULL,\n    PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mariadb/testdata/with_tpl_user_scores.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid int(10) unsigned NOT NULL,\n    score int(10) unsigned NOT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mssql/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/mssql/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/microsoft/go-mssqldb v1.7.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect\n\tgithub.com/golang-sql/sqlexp v0.1.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/crypto v0.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/mssql/go.sum",
    "content": "github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=\ngithub.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=\ngithub.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=\ngithub.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=\ngithub.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/microsoft/go-mssqldb v1.7.1 h1:KU/g8aWeM3Hx7IMOFpiwYiUkU+9zeISb4+tx3ScVfsM=\ngithub.com/microsoft/go-mssqldb v1.7.1/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package mssql implements gdb.Driver, which supports operations for MSSQL.\npackage mssql\n\nimport (\n\t_ \"github.com/microsoft/go-mssqldb\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Driver is the driver for SQL server database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\trowNumberAliasForSelect = `ROW_NUMBER__`\n\tquoteChar               = `\"`\n)\n\nfunc init() {\n\tif err := gdb.Register(`mssql`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for Mssql.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for SQL server.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_do_commit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoCommit commits current sql and arguments to underlying sql driver.\nfunc (d *Driver) DoCommit(ctx context.Context, in gdb.DoCommitInput) (out gdb.DoCommitOutput, err error) {\n\tout, err = d.Core.DoCommit(ctx, in)\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(out.Records) > 0 {\n\t\t// remove auto added field.\n\t\tfor i, record := range out.Records {\n\t\t\tdelete(record, rowNumberAliasForSelect)\n\t\t\tout.Records[i] = record\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_do_exec.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\t// INSERT statement prefixes\n\tinsertPrefixDefault = \"INSERT INTO\"\n\tinsertPrefixIgnore  = \"INSERT IGNORE INTO\"\n\n\t// Database field attributes\n\tfieldExtraIdentity = \"IDENTITY\"\n\tfieldKeyPrimary    = \"PRI\"\n\n\t// SQL keywords and syntax markers\n\toutputKeyword      = \"OUTPUT\"\n\tinsertValuesMarker = \") VALUES\" // find the position of the string \"VALUES\" in the INSERT SQL statement to embed output code for retrieving the last inserted ID\n\n\t// Object and field references\n\tinsertedObjectName = \"INSERTED\"\n\n\t// Result field names and aliases\n\taffectCountExpression  = \" 1 as AffectCount\"\n\tlastInsertIdFieldAlias = \"ID\"\n)\n\n// DoExec commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\nfunc (d *Driver) DoExec(ctx context.Context, link gdb.Link, sqlStr string, args ...interface{}) (result sql.Result, err error) {\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = &txLinkMssql{tx.GetSqlTX()}\n\t\t} else if link, err = d.MasterLink(); err != nil {\n\t\t\t// Or else it creates one from master node.\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it checks and retrieves transaction from context.\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\tlink = &txLinkMssql{tx.GetSqlTX()}\n\t\t}\n\t}\n\n\t// SQL filtering.\n\tsqlStr, args = d.FormatSqlBeforeExecuting(sqlStr, args)\n\tsqlStr, args, err = d.DoFilter(ctx, link, sqlStr, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !strings.HasPrefix(sqlStr, insertPrefixDefault) && !strings.HasPrefix(sqlStr, insertPrefixIgnore) {\n\t\treturn d.Core.DoExec(ctx, link, sqlStr, args)\n\t}\n\t// Find the first position of VALUES marker in the INSERT statement.\n\tpos := strings.Index(sqlStr, insertValuesMarker)\n\n\ttable := d.GetTableNameFromSql(sqlStr)\n\toutPutSql := d.GetInsertOutputSql(ctx, table)\n\t// rebuild sql add output\n\tvar (\n\t\tsqlValueBefore = sqlStr[:pos+1]\n\t\tsqlValueAfter  = sqlStr[pos+1:]\n\t)\n\n\tsqlStr = fmt.Sprintf(\"%s%s%s\", sqlValueBefore, outPutSql, sqlValueAfter)\n\n\t// fmt.Println(\"sql str:\", sqlStr)\n\t// Link execution.\n\tvar out gdb.DoCommitOutput\n\tout, err = d.DoCommit(ctx, gdb.DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sqlStr,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          gdb.SqlTypeQueryContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\treturn &Result{lastInsertId: 0, rowsAffected: 0, err: err}, err\n\t}\n\tstdSqlResult := out.Records\n\tif len(stdSqlResult) == 0 {\n\t\terr = gerror.WrapCode(\n\t\t\tgcode.CodeDbOperationError,\n\t\t\tgerror.New(\"affected count is zero\"),\n\t\t\t`sql.Result.RowsAffected failed`,\n\t\t)\n\t\treturn &Result{lastInsertId: 0, rowsAffected: 0, err: err}, err\n\t}\n\t// For batch insert, OUTPUT clause returns one row per inserted row.\n\t// So the rowsAffected should be the count of returned records.\n\trowsAffected := int64(len(stdSqlResult))\n\t// get last_insert_id from the first returned row\n\tlastInsertId := stdSqlResult[0].GMap().GetVar(lastInsertIdFieldAlias).Int64()\n\n\treturn &Result{lastInsertId: lastInsertId, rowsAffected: rowsAffected}, err\n}\n\n// GetTableNameFromSql get table name from sql statement\n// It handles table string like:\n// \"user\"\n// \"user u\"\n// \"DbLog.dbo.user\",\n// \"user as u\".\nfunc (d *Driver) GetTableNameFromSql(sqlStr string) (table string) {\n\t// INSERT INTO \"ip_to_id\"(\"ip\") OUTPUT  1 as AffectCount,INSERTED.id as ID VALUES(?)\n\tvar (\n\t\tleftChars, rightChars = d.GetChars()\n\t\ttrimStr               = leftChars + rightChars + \"[] \"\n\t\tpattern               = \"INTO(.+?)\\\\(\"\n\t\tregCompile            = regexp.MustCompile(pattern)\n\t\ttableInfo             = regCompile.FindStringSubmatch(sqlStr)\n\t)\n\t// get the first one. after the first it may be content of the value, it's not table name.\n\ttable = tableInfo[1]\n\ttable = strings.Trim(table, \" \")\n\tif strings.Contains(table, \".\") {\n\t\ttmpAry := strings.Split(table, \".\")\n\t\t// the last one is table name\n\t\ttable = tmpAry[len(tmpAry)-1]\n\t} else if strings.Contains(table, \"as\") || strings.Contains(table, \" \") {\n\t\ttmpAry := strings.Split(table, \"as\")\n\t\tif len(tmpAry) < 2 {\n\t\t\ttmpAry = strings.Split(table, \" \")\n\t\t}\n\t\t// get the first one\n\t\ttable = tmpAry[0]\n\t}\n\ttable = strings.Trim(table, trimStr)\n\treturn table\n}\n\n// txLink is used to implement interface Link for TX.\ntype txLinkMssql struct {\n\t*sql.Tx\n}\n\n// IsTransaction returns if current Link is a transaction.\nfunc (l *txLinkMssql) IsTransaction() bool {\n\treturn true\n}\n\n// IsOnMaster checks and returns whether current link is operated on master node.\n// Note that, transaction operation is always operated on master node.\nfunc (l *txLinkMssql) IsOnMaster() bool {\n\treturn true\n}\n\n// GetInsertOutputSql  gen get last_insert_id code\nfunc (d *Driver) GetInsertOutputSql(ctx context.Context, table string) string {\n\tfds, errFd := d.GetDB().TableFields(ctx, table)\n\tif errFd != nil {\n\t\treturn \"\"\n\t}\n\textraSqlAry := make([]string, 0)\n\textraSqlAry = append(extraSqlAry, fmt.Sprintf(\" %s %s\", outputKeyword, affectCountExpression))\n\tincrNo := 0\n\tif len(fds) > 0 {\n\t\tfor _, fd := range fds {\n\t\t\t// has primary key and is auto-increment\n\t\t\tif fd.Extra == fieldExtraIdentity && fd.Key == fieldKeyPrimary && !fd.Null {\n\t\t\t\tincrNoStr := \"\"\n\t\t\t\tif incrNo == 0 { // fixed first field named id, convenient to get\n\t\t\t\t\tincrNoStr = fmt.Sprintf(\" as %s\", lastInsertIdFieldAlias)\n\t\t\t\t}\n\n\t\t\t\textraSqlAry = append(extraSqlAry, fmt.Sprintf(\"%s.%s%s\", insertedObjectName, fd.Name, incrNoStr))\n\t\t\t\tincrNo++\n\t\t\t}\n\t\t\t// fmt.Printf(\"null:%t name:%s key:%s k:%s \\n\", fd.Null, fd.Name, fd.Key, k)\n\t\t}\n\t}\n\treturn strings.Join(extraSqlAry, \",\")\n\t// sql example:INSERT INTO \"ip_to_id\"(\"ip\") OUTPUT  1 as AffectCount,INSERTED.id as ID VALUES(?)\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\tselectWithOrderSqlTmp = `\nSELECT * FROM (\n    SELECT ROW_NUMBER() OVER (ORDER BY %s) as ROW_NUMBER__, %s \n    FROM (%s) as InnerQuery\n) as TMP_ \nWHERE TMP_.ROW_NUMBER__ > %d AND TMP_.ROW_NUMBER__ <= %d`\n\tselectWithoutOrderSqlTmp = `\nSELECT * FROM (\n    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ROW_NUMBER__, %s \n    FROM (%s) as InnerQuery\n) as TMP_ \nWHERE TMP_.ROW_NUMBER__ > %d AND TMP_.ROW_NUMBER__ <= %d`\n)\n\nfunc init() {\n\tvar err error\n\tselectWithOrderSqlTmp, err = gdb.FormatMultiLineSqlToSingle(selectWithOrderSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tselectWithoutOrderSqlTmp, err = gdb.FormatMultiLineSqlToSingle(selectWithoutOrderSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\tvar index int\n\t// Convert placeholder char '?' to string \"@px\".\n\tnewSql, err = gregex.ReplaceStringFunc(\"\\\\?\", sql, func(s string) string {\n\t\tindex++\n\t\treturn fmt.Sprintf(\"@p%d\", index)\n\t})\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tnewSql, err = gregex.ReplaceString(\"\\\"\", \"\", newSql)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tnewSql, err = d.parseSql(newSql)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tnewArgs = args\n\treturn d.Core.DoFilter(ctx, link, newSql, newArgs)\n}\n\n// parseSql does some replacement of the sql before commits it to underlying driver,\n// for support of microsoft sql server.\nfunc (d *Driver) parseSql(toBeCommittedSql string) (string, error) {\n\tvar (\n\t\terr       error\n\t\toperation = gstr.StrTillEx(toBeCommittedSql, \" \")\n\t\tkeyword   = strings.ToUpper(gstr.Trim(operation))\n\t)\n\tswitch keyword {\n\tcase \"SELECT\":\n\t\ttoBeCommittedSql, err = d.handleSelectSqlReplacement(toBeCommittedSql)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\treturn toBeCommittedSql, nil\n}\n\nfunc (d *Driver) handleSelectSqlReplacement(toBeCommittedSql string) (newSql string, err error) {\n\t// SELECT * FROM USER WHERE ID=1 LIMIT 1\n\tmatch, err := gregex.MatchString(`^SELECT(.+?)LIMIT\\s+1$`, toBeCommittedSql)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(match) > 1 {\n\t\treturn fmt.Sprintf(`SELECT TOP 1 %s`, strings.TrimSpace(match[1])), nil\n\t}\n\n\t// SELECT * FROM USER WHERE AGE>18 ORDER BY ID DESC LIMIT 100, 200\n\tpattern := `(?i)SELECT(.+?)(ORDER BY.+?)?\\s*LIMIT\\s*(\\d+)(?:\\s*,\\s*(\\d+))?`\n\tif !gregex.IsMatchString(pattern, toBeCommittedSql) {\n\t\treturn toBeCommittedSql, nil\n\t}\n\n\tallMatch, err := gregex.MatchString(pattern, toBeCommittedSql)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Extract SELECT part\n\tselectStr := strings.TrimSpace(allMatch[1])\n\n\t// Extract ORDER BY part\n\torderStr := \"\"\n\tif len(allMatch[2]) > 0 {\n\t\torderStr = strings.TrimSpace(allMatch[2])\n\t\t// Remove \"ORDER BY\" prefix as it will be used in OVER clause\n\t\torderStr = strings.TrimPrefix(orderStr, \"ORDER BY\")\n\t\torderStr = strings.TrimSpace(orderStr)\n\t}\n\n\t// Calculate LIMIT and OFFSET values\n\tfirst, _ := strconv.Atoi(allMatch[3]) // LIMIT first parameter\n\tlimit := 0\n\tif len(allMatch) > 4 && allMatch[4] != \"\" {\n\t\tlimit, _ = strconv.Atoi(allMatch[4]) // LIMIT second parameter\n\t} else {\n\t\tlimit = first\n\t\tfirst = 0\n\t}\n\n\t// Build the final query\n\tif orderStr != \"\" {\n\t\t// Have ORDER BY clause\n\t\tnewSql = fmt.Sprintf(\n\t\t\tselectWithOrderSqlTmp,\n\t\t\torderStr,                            // ORDER BY clause for ROW_NUMBER\n\t\t\t\"*\",                                 // Select all columns\n\t\t\tfmt.Sprintf(\"SELECT %s\", selectStr), // Original SELECT\n\t\t\tfirst,                               // OFFSET\n\t\t\tfirst+limit,                         // OFFSET + LIMIT\n\t\t)\n\t} else {\n\t\t// Without ORDER BY clause\n\t\tnewSql = fmt.Sprintf(\n\t\t\tselectWithoutOrderSqlTmp,\n\t\t\t\"*\",                                 // Select all columns\n\t\t\tfmt.Sprintf(\"SELECT %s\", selectStr), // Original SELECT\n\t\t\tfirst,                               // OFFSET\n\t\t\tfirst+limit,                         // OFFSET + LIMIT\n\t\t)\n\t}\n\treturn newSql, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_do_filter_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestDriver_DoFilter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\td := &Driver{}\n\n\t\t// Test SELECT with LIMIT\n\t\tsql := \"SELECT * FROM users WHERE id = ? LIMIT 10\"\n\t\targs := []any{1}\n\t\tnewSql, newArgs, err := d.DoFilter(context.Background(), nil, sql, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newArgs, args)\n\t\t// DoFilter should transform the SQL for MSSQL compatibility\n\t\tt.AssertNE(newSql, \"\")\n\n\t\t// Test INSERT statement (should remain unchanged except for placeholder)\n\t\tsql = \"INSERT INTO users (name) VALUES (?)\"\n\t\targs = []any{\"test\"}\n\t\tnewSql, newArgs, err = d.DoFilter(context.Background(), nil, sql, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newArgs, args)\n\t\tt.AssertNE(newSql, \"\")\n\n\t\t// Test UPDATE statement\n\t\tsql = \"UPDATE users SET name = ? WHERE id = ?\"\n\t\targs = []any{\"test\", 1}\n\t\tnewSql, newArgs, err = d.DoFilter(context.Background(), nil, sql, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newArgs, args)\n\t\tt.AssertNE(newSql, \"\")\n\n\t\t// Test DELETE statement\n\t\tsql = \"DELETE FROM users WHERE id = ?\"\n\t\targs = []any{1}\n\t\tnewSql, newArgs, err = d.DoFilter(context.Background(), nil, sql, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newArgs, args)\n\t\tt.AssertNE(newSql, \"\")\n\t})\n}\n\nfunc TestDriver_handleSelectSqlReplacement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\td := &Driver{}\n\n\t\t// LIMIT 1\n\t\tinputSql := \"SELECT * FROM User WHERE ID = 1 LIMIT 1\"\n\t\texpectedSql := \"SELECT TOP 1 * FROM User WHERE ID = 1\"\n\t\tresultSql, err := d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// LIMIT query with offset and number of rows\n\t\tinputSql = \"SELECT * FROM User ORDER BY ID DESC LIMIT 100, 200\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) as ROW_NUMBER__, * FROM (SELECT * FROM User) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 100 AND TMP_.ROW_NUMBER__ <= 300\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// Simple query with no LIMIT\n\t\tinputSql = \"SELECT * FROM User WHERE age > 18\"\n\t\texpectedSql = \"SELECT * FROM User WHERE age > 18\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// without LIMIT\n\t\tinputSql = \"SELECT * FROM User ORDER BY ID DESC\"\n\t\texpectedSql = \"SELECT * FROM User ORDER BY ID DESC\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// LIMIT query with only rows\n\t\tinputSql = \"SELECT * FROM User LIMIT 50\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ROW_NUMBER__, * FROM (SELECT * FROM User) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 0 AND TMP_.ROW_NUMBER__ <= 50\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// LIMIT query without ORDER BY\n\t\tinputSql = \"SELECT * FROM User LIMIT 30\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ROW_NUMBER__, * FROM (SELECT * FROM User) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 0 AND TMP_.ROW_NUMBER__ <= 30\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// Complex query with ORDER BY and LIMIT\n\t\tinputSql = \"SELECT name, age FROM User WHERE age > 18 ORDER BY age ASC LIMIT 10, 5\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY age ASC) as ROW_NUMBER__, * FROM (SELECT name, age FROM User WHERE age > 18) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 10 AND TMP_.ROW_NUMBER__ <= 15\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// Complex conditional queries have limits\n\t\tinputSql = \"SELECT * FROM User WHERE age > 18 AND status = 'active' LIMIT 100, 50\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ROW_NUMBER__, * FROM (SELECT * FROM User WHERE age > 18 AND status = 'active') as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 100 AND TMP_.ROW_NUMBER__ <= 150\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// A LIMIT query that contains subquery\n\t\tinputSql = \"SELECT * FROM (SELECT * FROM User WHERE age > 18) AS subquery LIMIT 10\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ROW_NUMBER__, * FROM (SELECT * FROM (SELECT * FROM User WHERE age > 18) AS subquery) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 0 AND TMP_.ROW_NUMBER__ <= 10\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t\t// Queries with complex ORDER BY and LIMIT\n\t\tinputSql = \"SELECT name, age FROM User WHERE age > 18 ORDER BY age DESC, name ASC LIMIT 20, 10\"\n\t\texpectedSql = \"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY age DESC, name ASC) as ROW_NUMBER__, * FROM (SELECT name, age FROM User WHERE age > 18) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 20 AND TMP_.ROW_NUMBER__ <= 30\"\n\t\tresultSql, err = d.handleSelectSqlReplacement(inputSql)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultSql, expectedSql)\n\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tswitch option.InsertOption {\n\tcase gdb.InsertOptionSave:\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionReplace:\n\t\t// MSSQL does not support REPLACE INTO syntax, use SAVE instead.\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionIgnore:\n\t\t// MSSQL does not support INSERT IGNORE syntax, use MERGE instead.\n\t\treturn d.doInsertIgnore(ctx, link, table, list, option)\n\n\tdefault:\n\t\treturn d.Core.DoInsert(ctx, link, table, list, option)\n\t}\n}\n\n// doSave support upsert for MSSQL\nfunc (d *Driver) doSave(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, true)\n}\n\n// doInsertIgnore implements INSERT IGNORE operation using MERGE statement for MSSQL database.\n// It only inserts records when there's no conflict on primary/unique keys.\nfunc (d *Driver) doInsertIgnore(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, false)\n}\n\n// doMergeInsert implements MERGE-based insert operations for MSSQL database.\n// When withUpdate is true, it performs upsert (insert or update).\n// When withUpdate is false, it performs insert ignore (insert only when no conflict).\nfunc (d *Driver) doMergeInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, withUpdate bool,\n) (result sql.Result, err error) {\n\t// If OnConflict is not specified, automatically get the primary key of the table\n\tconflictKeys := option.OnConflict\n\tif len(conflictKeys) == 0 {\n\t\tprimaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\terr,\n\t\t\t\t`failed to get primary keys for table`,\n\t\t\t)\n\t\t}\n\t\tfoundPrimaryKey := false\n\t\tfor _, primaryKey := range primaryKeys {\n\t\t\tfor dataKey := range list[0] {\n\t\t\t\tif strings.EqualFold(dataKey, primaryKey) {\n\t\t\t\t\tfoundPrimaryKey = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif foundPrimaryKey {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !foundPrimaryKey {\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeMissingParameter,\n\t\t\t\t`Replace/Save/InsertIgnore operation requires conflict detection: `+\n\t\t\t\t\t`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,\n\t\t\t\ttable,\n\t\t\t)\n\t\t}\n\t\t// TODO consider composite primary keys.\n\t\tconflictKeys = primaryKeys\n\t}\n\n\tvar (\n\t\tone            = list[0]\n\t\toneLen         = len(one)\n\t\tcharL, charR   = d.GetChars()\n\t\tconflictKeySet = gset.NewStrSet(false)\n\n\t\t// queryHolders:\tHandle data with Holder that need to be merged\n\t\t// queryValues:\t\tHandle data that need to be merged\n\t\t// insertKeys:\t\tHandle valid keys that need to be inserted\n\t\t// insertValues:\tHandle values that need to be inserted\n\t\t// updateValues:\tHandle values that need to be updated (only when withUpdate=true)\n\t\tqueryHolders = make([]string, oneLen)\n\t\tqueryValues  = make([]any, oneLen)\n\t\tinsertKeys   = make([]string, oneLen)\n\t\tinsertValues = make([]string, oneLen)\n\t\tupdateValues []string\n\t)\n\n\t// conflictKeys slice type conv to set type\n\tfor _, conflictKey := range conflictKeys {\n\t\tconflictKeySet.Add(gstr.ToUpper(conflictKey))\n\t}\n\n\tindex := 0\n\tfor key, value := range one {\n\t\tqueryHolders[index] = \"?\"\n\t\tqueryValues[index] = value\n\t\tinsertKeys[index] = charL + key + charR\n\t\tinsertValues[index] = \"T2.\" + charL + key + charR\n\n\t\t// Build updateValues only when withUpdate is true\n\t\t// Filter conflict keys and soft created fields from updateValues\n\t\tif withUpdate && !(conflictKeySet.Contains(key) || d.Core.IsSoftCreatedFieldName(key)) {\n\t\t\tupdateValues = append(\n\t\t\t\tupdateValues,\n\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, charL+key+charR, charL+key+charR),\n\t\t\t)\n\t\t}\n\t\tindex++\n\t}\n\n\tvar (\n\t\tbatchResult = new(gdb.SqlResult)\n\t\tsqlStr      = parseSqlForMerge(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys)\n\t)\n\tr, err := d.DoExec(ctx, link, sqlStr, queryValues...)\n\tif err != nil {\n\t\treturn r, err\n\t}\n\tif n, err := r.RowsAffected(); err != nil {\n\t\treturn r, err\n\t} else {\n\t\tbatchResult.Result = r\n\t\tbatchResult.Affected += n\n\t}\n\treturn batchResult, nil\n}\n\n// parseSqlForMerge generates MERGE statement for MSSQL database.\n// When updateValues is empty, it only inserts (INSERT IGNORE behavior).\n// When updateValues is provided, it performs upsert (INSERT or UPDATE).\n// Examples:\n// - INSERT IGNORE: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...)\n// - UPSERT: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...) WHEN MATCHED THEN UPDATE SET ...\nfunc parseSqlForMerge(table string,\n\tqueryHolders, insertKeys, insertValues, updateValues, duplicateKey []string,\n) (sqlStr string) {\n\tvar (\n\t\tqueryHolderStr  = strings.Join(queryHolders, \",\")\n\t\tinsertKeyStr    = strings.Join(insertKeys, \",\")\n\t\tinsertValueStr  = strings.Join(insertValues, \",\")\n\t\tduplicateKeyStr string\n\t)\n\n\t// Build ON condition\n\tfor index, keys := range duplicateKey {\n\t\tif index != 0 {\n\t\t\tduplicateKeyStr += \" AND \"\n\t\t}\n\t\tduplicateKeyStr += fmt.Sprintf(\"T1.%s = T2.%s\", keys, keys)\n\t}\n\n\t// Build SQL based on whether UPDATE is needed\n\tpattern := gstr.Trim(\n\t\t`MERGE INTO %s T1 USING (VALUES(%s)) T2 (%s) ON (%s) WHEN NOT MATCHED THEN INSERT(%s) VALUES (%s)`,\n\t)\n\tif len(updateValues) > 0 {\n\t\t// Upsert: INSERT or UPDATE\n\t\tpattern += gstr.Trim(` WHEN MATCHED THEN UPDATE SET %s`)\n\t\treturn fmt.Sprintf(\n\t\t\tpattern+\";\",\n\t\t\ttable,\n\t\t\tqueryHolderStr,\n\t\t\tinsertKeyStr,\n\t\t\tduplicateKeyStr,\n\t\t\tinsertKeyStr,\n\t\t\tinsertValueStr,\n\t\t\tstrings.Join(updateValues, \",\"),\n\t\t)\n\t}\n\t// Insert Ignore: INSERT only\n\treturn fmt.Sprintf(pattern+\";\", table, queryHolderStr, insertKeyStr, duplicateKeyStr, insertKeyStr, insertValueStr)\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Open creates and returns an underlying sql.DB object for mssql.\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tsource, err := configNodeToSource(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tunderlyingDriverName := \"sqlserver\"\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n\nfunc configNodeToSource(config *gdb.ConfigNode) (string, error) {\n\tvar source string\n\tsource = fmt.Sprintf(\n\t\t\"user id=%s;password=%s;server=%s;encrypt=disable\",\n\t\tconfig.User, config.Pass, config.Host,\n\t)\n\tif config.Name != \"\" {\n\t\tsource = fmt.Sprintf(\"%s;database=%s\", source, config.Name)\n\t}\n\tif config.Port != \"\" {\n\t\tsource = fmt.Sprintf(\"%s;port=%s\", source, config.Port)\n\t}\n\tif config.Extra != \"\" {\n\t\textraMap, err := gstr.Parse(config.Extra)\n\t\tif err != nil {\n\t\t\treturn \"\", gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\terr,\n\t\t\t\t`invalid extra configuration: %s`, config.Extra,\n\t\t\t)\n\t\t}\n\t\tfor k, v := range extraMap {\n\t\t\tsource += fmt.Sprintf(`;%s=%s`, k, v)\n\t\t}\n\t}\n\treturn source, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\n// Result instance of sql.Result\ntype Result struct {\n\tlastInsertId int64\n\trowsAffected int64\n\terr          error\n}\n\nfunc (r *Result) LastInsertId() (int64, error) {\n\treturn r.lastInsertId, r.err\n}\n\nfunc (r *Result) RowsAffected() (int64, error) {\n\treturn r.rowsAffected, r.err\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttableFieldsSqlTmp = `\nSELECT \n\tc.name AS Field,\n\tCASE \n\t\tWHEN t.name IN ('datetime', 'datetime2', 'smalldatetime', 'date', 'time', 'text', 'ntext', 'image', 'xml') THEN t.name\n\t\tWHEN t.name IN ('decimal', 'numeric') THEN t.name + '(' + CAST(c.precision AS varchar(20)) + ',' + CAST(c.scale AS varchar(20)) + ')'\n\t\tWHEN t.name IN ('char', 'varchar', 'binary', 'varbinary') THEN t.name + '(' + CASE WHEN c.max_length = -1 THEN 'max' ELSE CAST(c.max_length AS varchar(20)) END + ')'\n\t\tWHEN t.name IN ('nchar', 'nvarchar') THEN t.name + '(' + CASE WHEN c.max_length = -1 THEN 'max' ELSE CAST(c.max_length/2 AS varchar(20)) END + ')'\n\t\tELSE t.name\n\tEND AS Type,\n\tCASE WHEN c.is_nullable = 1 THEN 'YES' ELSE 'NO' END AS [Null],\n\tCASE WHEN pk.column_id IS NOT NULL THEN 'PRI' ELSE '' END AS [Key],\n\tCASE WHEN c.is_identity = 1 THEN 'IDENTITY' ELSE '' END AS Extra,\n\tISNULL(dc.definition, '') AS [Default],\n\tISNULL(CAST(ep.value AS nvarchar(max)), '') AS [Comment]\nFROM sys.columns c\nINNER JOIN sys.objects o ON c.object_id = o.object_id AND o.type = 'U' AND o.is_ms_shipped = 0\nINNER JOIN sys.types t ON c.user_type_id = t.user_type_id\nLEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id\nLEFT JOIN sys.extended_properties ep ON c.object_id = ep.major_id AND c.column_id = ep.minor_id AND ep.name = 'MS_Description'\nLEFT JOIN (\n\tSELECT ic.object_id, ic.column_id\n\tFROM sys.index_columns ic\n\tINNER JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id\n\tWHERE i.is_primary_key = 1\n) pk ON c.object_id = pk.object_id AND c.column_id = pk.column_id\nWHERE o.name = '%s'\nORDER BY c.column_id\n`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\n//\n// Also see DriverMysql.TableFields.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tstructureSql := fmt.Sprintf(tableFieldsSqlTmp, table)\n\tresult, err = d.DoSelect(ctx, link, structureSql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tfields[m[\"Field\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"Field\"].String(),\n\t\t\tType:    m[\"Type\"].String(),\n\t\t\tNull:    m[\"Null\"].Bool(),\n\t\t\tKey:     m[\"Key\"].String(),\n\t\t\tDefault: m[\"Default\"].Val(),\n\t\t\tExtra:   m[\"Extra\"].String(),\n\t\t\tComment: m[\"Comment\"].String(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = `SELECT name FROM sys.objects WHERE type='U' AND is_ms_shipped = 0 ORDER BY name`\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err = d.DoSelect(ctx, link, tablesSqlTmp)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_z_unit_basic_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mssql/v2\"\n)\n\nfunc TestTables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"t_user1\", \"pop\", \"haha\"}\n\n\t\tfor _, v := range tables {\n\t\t\tcreateTable(v)\n\t\t}\n\n\t\tresult, err := db.Tables(context.Background())\n\t\tgtest.AssertNil(err)\n\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif tables[i] == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\n\t\tresult, err = db.Tables(context.Background(), TestSchema)\n\t\tgtest.AssertNil(err)\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif tables[i] == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\n\t\tfor _, v := range tables {\n\t\t\tdropTable(v)\n\t\t}\n\t})\n}\n\nfunc TestTableFields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\t\tvar expect = map[string][]any{\n\t\t\t\"ID\":          {\"numeric(10,0)\", false, \"PRI\", \"\", \"\", \"\"},\n\t\t\t\"PASSPORT\":    {\"varchar(45)\", true, \"\", \"\", \"\", \"\"},\n\t\t\t\"PASSWORD\":    {\"varchar(32)\", true, \"\", \"\", \"\", \"\"},\n\t\t\t\"NICKNAME\":    {\"varchar(45)\", true, \"\", \"\", \"\", \"\"},\n\t\t\t\"CREATE_TIME\": {\"datetime\", true, \"\", \"\", \"\", \"\"},\n\t\t}\n\n\t\tres, err := db.TableFields(context.Background(), \"t_user\")\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[0])\n\t\t\tgtest.AssertEQ(res[k].Null, v[1])\n\t\t\tgtest.AssertEQ(res[k].Key, v[2])\n\t\t\tgtest.AssertEQ(res[k].Default, v[3])\n\t\t\tgtest.AssertEQ(res[k].Extra, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\n\t\tres, err = db.TableFields(context.Background(), \"t_user\", TestSchema)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[0])\n\t\t\tgtest.AssertEQ(res[k].Null, v[1])\n\t\t\tgtest.AssertEQ(res[k].Key, v[2])\n\t\t\tgtest.AssertEQ(res[k].Default, v[3])\n\t\t\tgtest.AssertEQ(res[k].Extra, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.TableFields(context.Background(), \"t_user t_user2\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDoInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Insert(context.Background(), \"t_user\", data)\n\t\tgtest.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t// \"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t// Save without OnConflict should fail (missing conflict columns)\n\t\t_, err := db.Save(context.Background(), \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\n\t\t// Replace should fail because primary key 'id' is not in the data\n\t\t_, err = db.Replace(context.Background(), \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDoInsertGetId(t *testing.T) {\n\t// create test table\n\tcreateInsertAndGetIdTableForTest()\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"ip_to_id\"\n\t\tdata := map[string]interface{}{\n\t\t\t\"ip\": \"192.168.179.1\",\n\t\t}\n\t\tid, err := db.InsertAndGetId(gctx.New(), table, data)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(id, 0)\n\t\t// fmt.Println(\"id:\", id)\n\n\t\t// multiple insert test\n\t\tdataAry := []map[string]interface{}{{\"ip\": \"192.168.5.9\"}, {\"ip\": \"192.168.5.10\"}}\n\t\tid1, err1 := db.InsertAndGetId(gctx.New(), table, dataAry)\n\t\tt.AssertNil(err1)\n\t\tt.AssertGT(id1, 0)\n\t})\n}\n\nfunc TestGetTableFromSql(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tokTable := \"ip_to_id\"\n\t\tsqlStr := \"INSERT INTO \\\"ip_to_id\\\"(\\\"ip\\\") VALUES(?)\"\n\t\tdbWrapper, ok := db.GetCore().GetDB().(*gdb.DriverWrapperDB)\n\t\tt.Assert(ok, true)\n\t\tdbMssql, ok := dbWrapper.DB.(*mssql.Driver)\n\t\tt.Assert(ok, true)\n\t\ttable := dbMssql.GetTableNameFromSql(sqlStr)\n\t\t// fmt.Println(\"default table:\", table)\n\t\tt.Assert(table, okTable)\n\n\t\tsqlStr = \"INSERT INTO \\\"MyLogDb\\\".\\\"dbo\\\".\\\"ip_to_id\\\"(\\\"ip\\\") VALUES(?)\"\n\t\ttable = dbMssql.GetTableNameFromSql(sqlStr)\n\t\t// fmt.Println(\"MyLogDb.dbo.ip_to_id table:\", table)\n\t\tt.Assert(table, okTable)\n\n\t\tsqlStr = \"INSERT INTO \\\"ip_to_id\\\" as \\\"tt\\\" (\\\"ip\\\") VALUES(?)\"\n\t\ttable = dbMssql.GetTableNameFromSql(sqlStr)\n\t\t// fmt.Println(\"ip_to_id as tt table:\", table)\n\t\tt.Assert(table, okTable)\n\n\t\tsqlStr = \"INSERT INTO \\\"ip_to_id\\\" \\\"tt\\\" (\\\"ip\\\") VALUES(?)\"\n\t\ttable = dbMssql.GetTableNameFromSql(sqlStr)\n\t\t// fmt.Println(\"ip_to_id tt table:\", table)\n\t\tt.Assert(table, okTable)\n\t})\n}\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Exec(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\ttimeNow := gtime.New(\"2024-10-01 12:01:01\")\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tId:         3,\n\t\t\tPassport:   \"user_3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 3)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_3\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_3\")\n\t\tt.AssertNE(one[\"CREATE_TIME\"].GTime(), nil)\n\t\tt.AssertLT(timeNow.Sub(one[\"CREATE_TIME\"].GTime()), 3)\n\n\t\t// *struct\n\t\ttimeNow = gtime.Now()\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_4\",\n\t\t\tCreateTime: timeNow,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Where(\"id\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 4)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t4\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_4\")\n\n\t\t// batch with Insert\n\t\ttimeNow = gtime.Now()\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          200,\n\t\t\t\t\"passport\":    \"t200\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d71qw07ad\",\n\t\t\t\t\"nickname\":    \"T200\",\n\t\t\t\t\"create_time\": timeNow,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          300,\n\t\t\t\t\"passport\":    \"t300\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T300\",\n\t\t\t\t\"create_time\": timeNow,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"id\", 200).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 200)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t200\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d71qw07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T200\")\n\t})\n}\n\nfunc Test_DB_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"], data.Passport)\n\t\tt.Assert(one[\"CREATE_TIME\"], data.CreateTime)\n\t\tt.Assert(one[\"NICKNAME\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Update(ctx, table, data, \"id=1\")\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"], data.Passport)\n\t\tt.Assert(one[\"CREATE_TIME\"], data.CreateTime)\n\t\tt.Assert(one[\"NICKNAME\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttype User struct {\n\t\t\tId         int         `c:\"id\"`\n\t\t\tPassport   string      `c:\"passport\"`\n\t\t\tPassword   string      `c:\"password\"`\n\t\t\tNickName   string      `c:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `c:\"create_time\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"t1\",\n\t\t\tPassword:   \"p1\",\n\t\t\tNickName:   \"T1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\tresult, err := db.Insert(ctx, table, user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 3)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_3\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"987654321\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"NICKNAME\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"1=1\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_DB_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          200,\n\t\t\t\"passport\":    \"t200\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T200\",\n\t\t\t\"create_time\": time.Now(),\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select passport from %s where id=?\", table), 200)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t200\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := time.Now()\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          300,\n\t\t\t\"passport\":    \"t300\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T300\",\n\t\t\t\"create_time\": &t1,\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select passport from %s where id=?\", table), 300)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t300\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"1=1\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_DB_ToJson(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := make([]User, 0)\n\n\t\terr = result.Structs(users)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = result.Structs(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\t// ToJson\n\t\tresultJson, err := gjson.LoadContent([]byte(result.Json()))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(users[0].Id, resultJson.Get(\"0.ID\").Int())\n\t\tt.Assert(users[0].Passport, resultJson.Get(\"0.PASSPORT\").String())\n\t\tt.Assert(users[0].Password, resultJson.Get(\"0.PASSWORD\").String())\n\t\tt.Assert(users[0].NickName, resultJson.Get(\"0.NICKNAME\").String())\n\t\tt.Assert(users[0].CreateTime, resultJson.Get(\"0.CREATE_TIME\").String())\n\n\t\tresult = nil\n\t\tt.Assert(result.Structs(&users), sql.ErrNoRows)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := User{}\n\n\t\terr = result.Struct(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult = nil\n\t\terr = result.Struct(&users)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_ToXml(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tuser := User{}\n\t\terr = record.Struct(&user)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult, err := gxml.Decode([]byte(record.Xml(\"doc\")))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultXml := result[\"doc\"].(map[string]any)\n\t\tif v, ok := resultXml[\"ID\"]; ok {\n\t\t\tt.Assert(user.Id, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"PASSPORT\"]; ok {\n\t\t\tt.Assert(user.Passport, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"PASSWORD\"]; ok {\n\t\t\tt.Assert(user.Password, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"NICKNAME\"]; ok {\n\t\t\tt.Assert(user.NickName, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"CREATE_TIME\"]; ok {\n\t\t\tt.Assert(user.CreateTime, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\t})\n}\n\nfunc Test_DB_ToStringMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringMap := result.MapKeyStr(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultStringMap[id][\"ID\"])\n\t\tt.Assert(t_users[0].Passport, resultStringMap[id][\"PASSPORT\"])\n\t\tt.Assert(t_users[0].Password, resultStringMap[id][\"PASSWORD\"])\n\t\tt.Assert(t_users[0].NickName, resultStringMap[id][\"NICKNAME\"])\n\t\tt.Assert(t_users[0].CreateTime, resultStringMap[id][\"CREATE_TIME\"])\n\t})\n}\n\nfunc Test_DB_ToIntMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"ID\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"PASSPORT\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"PASSWORD\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"NICKNAME\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"CREATE_TIME\"])\n\t})\n}\n\nfunc Test_DB_ToUintMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintMap := result.MapKeyUint(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultUintMap[uint(id)][\"ID\"])\n\t\tt.Assert(t_users[0].Passport, resultUintMap[uint(id)][\"PASSPORT\"])\n\t\tt.Assert(t_users[0].Password, resultUintMap[uint(id)][\"PASSWORD\"])\n\t\tt.Assert(t_users[0].NickName, resultUintMap[uint(id)][\"NICKNAME\"])\n\t\tt.Assert(t_users[0].CreateTime, resultUintMap[uint(id)][\"CREATE_TIME\"])\n\t})\n}\n\nfunc Test_DB_ToStringRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tids := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringRecord := result.RecordKeyStr(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultStringRecord[ids][\"ID\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultStringRecord[ids][\"PASSPORT\"].String())\n\t\tt.Assert(t_users[0].Password, resultStringRecord[ids][\"PASSWORD\"].String())\n\t\tt.Assert(t_users[0].NickName, resultStringRecord[ids][\"NICKNAME\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultStringRecord[ids][\"CREATE_TIME\"].String())\n\t})\n}\n\nfunc Test_DB_ToIntRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntRecord := result.RecordKeyInt(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultIntRecord[id][\"ID\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultIntRecord[id][\"PASSPORT\"].String())\n\t\tt.Assert(t_users[0].Password, resultIntRecord[id][\"PASSWORD\"].String())\n\t\tt.Assert(t_users[0].NickName, resultIntRecord[id][\"NICKNAME\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultIntRecord[id][\"CREATE_TIME\"].String())\n\t})\n}\n\nfunc Test_DB_ToUintRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintRecord := result.RecordKeyUint(\"ID\")\n\t\tt.Assert(t_users[0].Id, resultUintRecord[uint(id)][\"ID\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultUintRecord[uint(id)][\"PASSPORT\"].String())\n\t\tt.Assert(t_users[0].Password, resultUintRecord[uint(id)][\"PASSWORD\"].String())\n\t\tt.Assert(t_users[0].NickName, resultUintRecord[uint(id)][\"NICKNAME\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultUintRecord[uint(id)][\"CREATE_TIME\"].String())\n\t})\n}\n\nfunc Test_Model_InnerJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 5).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 5)\n\n\t\tresult, err := db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 5)\n\n\t\tresult, err = db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ?\", 1).Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 4)\n\t})\n}\n\nfunc Test_Model_LeftJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table2).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t} else {\n\t\t\tt.Assert(n, 7)\n\t\t}\n\n\t\tresult, err := db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ? \", 2).All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 8)\n\t})\n}\n\nfunc Test_Model_RightJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 7)\n\n\t\tresult, err := db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > 2\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 1)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_z_unit_init_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tdb     gdb.DB\n\tdblink gdb.DB\n\tdbErr  gdb.DB\n\tctx    context.Context\n)\n\nconst (\n\tTableSize        = 10\n\tTableName        = \"t_user\"\n\tTestSchema       = \"test\"\n\tTableNamePrefix1 = \"gf_\"\n\tTestDbUser       = \"sa\"\n\tTestDbPass       = \"LoremIpsum86\"\n\tCreateTime       = \"2018-10-24 10:00:00\"\n)\n\nfunc init() {\n\t// First connect to master database to create test database\n\tnodemaster := gdb.ConfigNode{\n\t\tHost:             \"127.0.0.1\",\n\t\tPort:             \"1433\",\n\t\tUser:             TestDbUser,\n\t\tPass:             TestDbPass,\n\t\tName:             \"master\",\n\t\tType:             \"mssql\",\n\t\tRole:             \"master\",\n\t\tCharset:          \"utf8\",\n\t\tWeight:           1,\n\t\tMaxIdleConnCount: 10,\n\t\tMaxOpenConnCount: 10,\n\t}\n\n\ttempDb, err := gdb.New(nodemaster)\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// Create test database\n\tif _, err := tempDb.Exec(context.Background(), fmt.Sprintf(`\n\t\tIF NOT EXISTS (SELECT name FROM sys.databases WHERE name = '%s')\n\t\tCREATE DATABASE [%s]\n\t`, TestSchema, TestSchema)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tnode := gdb.ConfigNode{\n\t\tHost:             \"127.0.0.1\",\n\t\tPort:             \"1433\",\n\t\tUser:             TestDbUser,\n\t\tPass:             TestDbPass,\n\t\tName:             TestSchema,\n\t\tType:             \"mssql\",\n\t\tRole:             \"master\",\n\t\tCharset:          \"utf8\",\n\t\tWeight:           1,\n\t\tMaxIdleConnCount: 10,\n\t\tMaxOpenConnCount: 10,\n\t}\n\n\tnodeLink := gdb.ConfigNode{\n\t\tType: \"mssql\",\n\t\tName: \"master\",\n\t\tLink: fmt.Sprintf(\n\t\t\t\"mssql:%s:%s@tcp(%s:%s)/%s?encrypt=disable\",\n\t\t\tnode.User, node.Pass, node.Host, node.Port, node.Name,\n\t\t),\n\t}\n\n\tnodeErr := gdb.ConfigNode{\n\t\tType: \"mssql\",\n\t\tLink: fmt.Sprintf(\n\t\t\t\"mssql:%s:%s@tcp(%s:%s)/%s?encrypt=disable\",\n\t\t\tnode.User, \"node.Pass\", node.Host, node.Port, node.Name),\n\t}\n\n\tgdb.AddConfigNode(gdb.DefaultGroupName, node)\n\tif r, err := gdb.New(node); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\tgdb.AddConfigNode(\"dblink\", nodeLink)\n\tif r, err := gdb.New(nodeLink); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdblink = r\n\t}\n\n\tgdb.AddConfigNode(\"dbErr\", nodeErr)\n\tif r, err := gdb.New(nodeErr); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdbErr = r\n\t}\n\n\tctx = context.Background()\n}\n\nfunc createTable(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(\"user_%d\", gtime.Timestamp())\n\t}\n\n\tdropTable(name)\n\n\tif _, err := db.Exec(context.Background(), fmt.Sprintf(`\n\t\tIF NOT EXISTS (SELECT * FROM sys.objects WHERE name='%s' and type='U')\n\t\tCREATE TABLE [%s] (\n\t\tID numeric(10,0) NOT NULL,\n\t\tPASSPORT VARCHAR(45)  NULL,\n\t\tPASSWORD VARCHAR(32)  NULL,\n\t\tNICKNAME VARCHAR(45)  NULL,\n\t\tCREATE_TIME datetime NULL,\n\t\tCREATED_AT datetimeoffset NULL,\n\t\tUPDATED_AT datetimeoffset NULL,\n\t\tPRIMARY KEY (ID))\n\t`, name, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\treturn\n}\n\nfunc createInitTable(table ...string) (name string) {\n\tname = createTable(table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t})\n\t}\n\tresult, err := db.Insert(context.Background(), name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTable(table string) {\n\tif _, err := db.Exec(context.Background(), fmt.Sprintf(`\n\t\tIF EXISTS (SELECT * FROM sys.objects WHERE name='%s' and type='U')\n\t\tDROP TABLE [%s]\n\t`, table, table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n}\n\n// createInsertAndGetIdTableForTest tests InsertAndGetId functionality\nfunc createInsertAndGetIdTableForTest() (name string) {\n\n\tif _, err := db.Exec(context.Background(), `\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE name='ip_to_id' and type='U')\nbegin\n\tCREATE TABLE [ip_to_id](\n\t\t[id] [int] IDENTITY(1,1) NOT NULL,\n\t\t[ip] [varchar](128) NULL,\n\t CONSTRAINT [PK_ip_to_id] PRIMARY KEY CLUSTERED \n\t(\n\t\t[id] ASC\n\t)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n\t) ON [PRIMARY]\nend\n\t`); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tdb.Schema(db.GetConfig().Name)\n\tname = \"ip_to_id\"\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_z_unit_model_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(1, 2).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\t// fmt.Println(\"page:1--------\", result)\n\t\tgtest.Assert(len(result), 2)\n\t\tgtest.Assert(result[0][\"ID\"], 1)\n\t\tgtest.Assert(result[1][\"ID\"], 2)\n\n\t\tresult, err = db.Model(table).Page(2, 2).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\t// fmt.Println(\"page: 2--------\", result)\n\t\tgtest.Assert(len(result), 2)\n\t\tgtest.Assert(result[0][\"ID\"], 3)\n\t\tgtest.Assert(result[1][\"ID\"], 4)\n\n\t\tresult, err = db.Model(table).Page(3, 2).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\t// fmt.Println(\"page:3 --------\", result)\n\t\tgtest.Assert(len(result), 2)\n\t\tgtest.Assert(result[0][\"ID\"], 5)\n\n\t\tresult, err = db.Model(table).Page(2, 3).All()\n\t\tt.AssertNil(err)\n\t\tgtest.Assert(len(result), 3)\n\t})\n}\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:       3,\n\t\t\tPassport: \"t3\",\n\t\t\tPassword: \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname: \"name_3\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\t_, _ = result.RowsAffected()\n\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, 777),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, 777),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, 777),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_1\")\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, 777),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, 777),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, 777),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_Model_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"], data.Passport)\n\t\tt.Assert(one[\"CREATE_TIME\"], data.CreateTime)\n\t\tt.Assert(one[\"NICKNAME\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"], data.Passport)\n\t\tt.Assert(one[\"CREATE_TIME\"], data.CreateTime)\n\t\tt.Assert(one[\"NICKNAME\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Insert_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2020-10-10 20:09:18.334\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), data[\"passport\"])\n\t\tt.Assert(one[\"CREATE_TIME\"].String(), \"2020-10-10 20:09:18\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), data[\"nickname\"])\n\t})\n}\n\nfunc Test_Model_BatchInsertWithArrayStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tarray := garray.New()\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(\"t%d\", i),\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    fmt.Sprintf(\"name_%d\", i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\n\t\t_, err := user.Data(array).Insert()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t})\n\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := md.Safe(true).Order(\"id DESC\").One()\n\t\tt.AssertNil(err)\n\n\t\tresult, err := md.Safe(true).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(2))\n\t\tt.Assert(record[\"ID\"].Int(), 3)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Safe(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(false).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe().Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd1 := db.Model(table).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmd1 := db.Model(table).Where(\"id>\", 0).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tmd3 := md1.Where(\"id in (?)\", g.Slice{4, 5, 6})\n\n\t\t// 1,3\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"ID\"].Int(), 1)\n\t\tt.Assert(all[1][\"ID\"].Int(), 3)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// 4,5,6\n\t\tcount, err = md3.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\tall, err = md3.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"ID\"].Int(), 4)\n\t\tt.Assert(all[1][\"ID\"].Int(), 5)\n\t\tt.Assert(all[2][\"ID\"].Int(), 6)\n\n\t\tall, err = md3.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"NICKNAME\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(gconv.Ints(all.Array(\"ID\")), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"NICKNAME\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Struct_CustomType(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype MyInt int\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         MyInt\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n}\n\nfunc Test_Model_Structs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\t// Auto create struct slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Where(\"id<0\").Scan(&users)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\ttype Response struct {\n\t\t\tUsers []User `json:\"users\"`\n\t\t}\n\t\tvar res Response\n\t\terr := db.Model(table).Scan(&res.Users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(res.Users, nil)\n\t})\n}\n\nfunc Test_Model_OrderBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(\"id DESC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"NICKNAME\"].String(), fmt.Sprintf(\"name_%d\", TableSize))\n\t})\n}\n\nfunc Test_Model_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(\"nickname=?\", \"test\").Where(\"id=?\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := make([]g.MapStrAny, 0)\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers = append(users, g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := garray.New()\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers.Append(g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"ID\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"ID\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_1(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"ID\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_2(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// complicated one.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"ID\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"ID\"].Int(), 3)\n\t\tt.Assert(all[1][\"ID\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"ID\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"ID\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Offset(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(5, 2).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 6)\n\t\tt.Assert(result[1][\"ID\"], 7)\n\t})\n}\n\nfunc Test_Model_Option_Map(t *testing.T) {\n\t// Insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, passport\").Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"1\",\n\t\t\t\"password\": \"1\",\n\t\t\t\"nickname\": \"1\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"PASSWORD\"].String(), \"1\")\n\t\tt.AssertNE(one[\"NICKNAME\"].String(), \"1\")\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"PASSPORT\"].String(), \"0\")\n\t\tt.AssertNE(one[\"PASSWORD\"].String(), \"0\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"1\")\n\t})\n\n\t// Update\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tr, err := db.Model(table).Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmptyData().Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\n\t\tr, err = db.Model(table).OmitEmpty().Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmpty().Fields(\"nickname\", \"password\").Data(g.Map{\"nickname\": \"\", \"password\": \"123\", \"passport\": \"123\"}).Where(\"id\", 4).Update()\n\t\tt.AssertNil(err)\n\n\t\tr, err = db.Model(table).OmitEmpty().\n\t\t\tFields(\"password\").Data(g.Map{\n\t\t\t\"nickname\": \"\",\n\t\t\t\"passport\": \"123\",\n\t\t\t\"password\": \"456\",\n\t\t}).Where(\"id\", 5).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 5).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSWORD\"], \"456\")\n\t\tt.AssertNE(one[\"PASSPORT\"].String(), \"\")\n\t\tt.AssertNE(one[\"PASSPORT\"].String(), \"123\")\n\t})\n}\n\nfunc Test_Model_Option_Where(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 0, \"passport\": \"\"}).Where(\"1=1\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 1, \"passport\": \"\"}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err := db.Model(table).Where(\"id\", 1).Fields(\"nickname\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"1\")\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"ID\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_FieldsEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, created_at, updated_at, id\").Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(len(r[0]), 3)\n\t\tt.Assert(r[0][\"ID\"], \"\")\n\t\tt.Assert(r[0][\"PASSPORT\"], \"user_1\")\n\t\tt.Assert(r[0][\"PASSWORD\"], \"pass_1\")\n\t\tt.Assert(r[0][\"NICKNAME\"], \"name_1\")\n\t\tt.Assert(r[0][\"CREATE_TIME\"], \"\")\n\t\tt.Assert(r[1][\"ID\"], \"\")\n\t\tt.Assert(r[1][\"PASSPORT\"], \"user_2\")\n\t\tt.Assert(r[1][\"PASSWORD\"], \"pass_2\")\n\t\tt.Assert(r[1][\"NICKNAME\"], \"name_2\")\n\t\tt.Assert(r[1][\"CREATE_TIME\"], \"\")\n\t})\n\t// Update.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"password\").Data(g.Map{\"nickname\": \"123\", \"password\": \"456\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"NICKNAME\"], \"123\")\n\t\tt.AssertNE(one[\"PASSWORD\"], \"456\")\n\t})\n}\n\nfunc Test_Model_FieldsExStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tNickName: \"333\",\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").OmitEmpty().Data(user).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tusers := make([]*User, 0)\n\t\tfor i := 100; i < 110; i++ {\n\t\t\tusers = append(users, &User{\n\t\t\t\tId:       i,\n\t\t\t\tPassport: fmt.Sprintf(`passport_%d`, i),\n\t\t\t\tPassword: fmt.Sprintf(`password_%d`, i),\n\t\t\t\tNickName: fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").\n\t\t\tOmitEmpty().\n\t\t\tBatch(2).\n\t\t\tData(users).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_OmitEmpty_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tTime:     time.Time{},\n\t\t}\n\t\tr, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Result_Chunk(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tchunks := r.Chunk(3)\n\t\tt.Assert(len(chunks), 4)\n\t\tt.Assert(chunks[0][0][\"ID\"].Int(), 1)\n\t\tt.Assert(chunks[1][0][\"ID\"].Int(), 4)\n\t\tt.Assert(chunks[2][0][\"ID\"].Int(), 7)\n\t\tt.Assert(chunks[3][0][\"ID\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_DryRun(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.SetDryRun(true)\n\tdefer db.SetDryRun(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"], 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Data(\"passport\", \"port_1\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_Model_Join_SubQuery(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery := fmt.Sprintf(\"select * from %s\", table)\n\t\tr, err := db.Model(table, \"t1\").Fields(\"t2.id\").LeftJoin(subQuery, \"t2\", \"t2.id=t1.id\").Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), TableSize)\n\t\tt.Assert(r[0], \"1\")\n\t\tt.Assert(r[TableSize-1], TableSize)\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id, count(*)\").Where(\"id > 1\").Group(\"id\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n\nfunc Test_Model_Fields_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"ID\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICK_NAME\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":        1,\n\t\t\t\"NICK_NAME\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"ID\"], 2)\n\t\tt.Assert(one[\"NICKNAME\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tID       int\n\t\t\tNICKNAME int\n\t\t}\n\t\tone, err := db.Model(table).Fields(&T{\n\t\t\tID:       0,\n\t\t\tNICKNAME: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"ID\"], 2)\n\t\tt.Assert(one[\"NICKNAME\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_NullField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": nil,\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\n\t\tvar user *User\n\t\terr = one.Struct(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t})\n}\n\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(table)\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"ID\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 3)\n\t\tt.Assert(result[1][\"ID\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"ID\"], 6)\n\t\tt.Assert(result[1][\"ID\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[4][\"ID\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[4][\"ID\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 3)\n\t\tt.Assert(result[1][\"ID\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"ID\"], 5)\n\t\tt.Assert(result[4][\"ID\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"ID\"], 10)\n\t\tt.Assert(result[4][\"ID\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[2][\"ID\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[3][\"ID\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"ID\"], 7)\n\t})\n}\n\nfunc Test_Model_Min_Max_Avg_Sum(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 5.5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 55)\n\t})\n}\n\nfunc Test_Model_CountColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 3)\n\t})\n}\n\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"ID\"], 7)\n\t\tt.Assert(all[1][\"ID\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.\n\t\t// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)\n\t\t// WhereLT(\"id\", 8): id < 8 -> (1, 5, 7)\n\t\t// WhereIn(\"id\", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)\n\t\t// Result: 3 records match all conditions\n\t\tt.Assert(count, int64(3))\n\t})\n}\n\nfunc Test_Model_Handler(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Safe().Handler(\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Page(0, 3)\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Where(\"id\", g.Slice{1, 2, 3, 4, 5, 6})\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.OrderDesc(\"id\")\n\t\t\t},\n\t\t)\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"ID\"], 6)\n\t\tt.Assert(all[2][\"ID\"], 4)\n\t})\n}\n\nfunc Test_Model_FieldCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldCount(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMax(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMin(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldAvg(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldAvg(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_OmitEmptyWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Basic type where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Where(\"nickname\", \"\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Slice where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Struct Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Map Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       []int{},\n\t\t\t\"nickname\": []string{},\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId []int\n\t\t}\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\ttable1 := \"table1\"\n\ttable2 := \"table2\"\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"ID\"], \"1\")\n\t\tt.Assert(r[1][\"ID\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\ttable1 := \"table1\"\n\ttable2 := \"table2\"\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"ID\"], \"1\")\n\t\tt.Assert(r[1][\"ID\"], \"2\")\n\t\tt.Assert(r[2][\"ID\"], \"8\")\n\t\tt.Assert(r[3][\"ID\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\ttable1 := \"table1\"\n\ttable2 := \"table2\"\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"ID\"], \"3\")\n\t})\n}\n\nfunc Test_Model_AllAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, total, err := db.Model(table).Order(\"id\").Limit(0, 3).AllAndCount(false)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(total, TableSize)\n\t})\n}\n\nfunc Test_Model_ScanAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\n\t\tusers := make([]User, 0)\n\t\ttotal := 0\n\n\t\terr := db.Model(table).Order(\"id\").Limit(0, 3).ScanAndCount(&users, &total, false)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(total, TableSize)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId        int\n\t\t\tPassport  string\n\t\t\tPassword  string\n\t\t\tNickName  string\n\t\t\tCreatedAt *gtime.Time\n\t\t\tUpdatedAt *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser   User\n\t\t\tcount  int\n\t\t\tresult sql.Result\n\t\t\terr    error\n\t\t)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"p1\",\n\t\t\t\"password\": \"15d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\": \"n1\",\n\t\t}).OnConflict(\"id\").Save()\n\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"15d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(user.NickName, \"n1\")\n\n\t\t// Sleep 1 second to make sure the updated time is different.\n\t\ttime.Sleep(1 * time.Second)\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"p1\",\n\t\t\t\"password\": \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\": \"n2\",\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(user.NickName, \"n2\")\n\t\t// check created_at not equal to updated_at\n\t\tt.AssertNE(user.CreatedAt, user.UpdatedAt)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial record\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"pass1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Replace with new data (should update existing record using MERGE)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t11\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T11\")\n\n\t\t// Replace with non-existing record (should insert new record)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t222\",\n\t\t\t\"password\":    \"pass2\",\n\t\t\t\"nickname\":    \"T222\",\n\t\t\t\"create_time\": \"2018-10-24 11:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1) // MERGE reports: 1 for insert\n\n\t\t// Verify the new record was inserted\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t222\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T222\")\n\t})\n}\n\n// Test_Model_Insert_RowsAffected tests the RowsAffected result for INSERT operations.\n// This test ensures that the rowsAffected value is correctly returned from the database,\n// especially for batch INSERT statements.\nfunc Test_Model_Insert_RowsAffected(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// Test single insert - rowsAffected should be 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tn, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Test batch insert with 3 rows - rowsAffected should be 3\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"user_2\",\n\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"user_4\",\n\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tn, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 3)\n\t})\n\n\t// Test batch insert with 5 rows - rowsAffected should be 5\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\"id\": 5, \"passport\": \"user_5\", \"password\": \"pass_5\", \"nickname\": \"name_5\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"id\": 6, \"passport\": \"user_6\", \"password\": \"pass_6\", \"nickname\": \"name_6\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"id\": 7, \"passport\": \"user_7\", \"password\": \"pass_7\", \"nickname\": \"name_7\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"id\": 8, \"passport\": \"user_8\", \"password\": \"pass_8\", \"nickname\": \"name_8\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"id\": 9, \"passport\": \"user_9\", \"password\": \"pass_9\", \"nickname\": \"name_9\", \"create_time\": gtime.Now().String()},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tn, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 5)\n\t})\n\n\t// Verify total count in table\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 9)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mssql/mssql_z_unit_transaction_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mssql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_TX_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tst, err := tx.Prepare(\"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tvar value int\n\t\tif rows.Next() {\n\t\t\terr = rows.Scan(&value)\n\t\t\tt.AssertNil(err)\n\n\t\t}\n\t\tt.Assert(value, 100)\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tuser := tx.Model(table)\n\t\t_, err = user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\t})\n}\n\nfunc Test_TX_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.Update(table, \"create_time='2019-10-24 10:00:00'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"2019-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_TX_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.GetAll(fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(result), 1)\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\trecord, err := tx.GetOne(fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_2\")\n\t\tt.AssertNil(err)\n\n\t\tt.AssertNE(record, nil)\n\t\tt.Assert(record[\"NICKNAME\"].String(), \"name_2\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := tx.GetValue(fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.Int(), 3)\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := tx.GetCount(\"SELECT * FROM \" + table)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(TableSize))\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Delete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Delete(table, \"1=1\")\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\t_, err = tx.Delete(table, \"1=1\")\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(0))\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tn, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(TableSize))\n\t\tt.AssertNE(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Ctx(ctx).Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\tt.Assert(tx.IsClosed(), false)\n\t\t\treturn gerror.New(\"error\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Ctx(ctx).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_Transaction_Panic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\tpanic(\"error\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\n// TODO\n// MSSQL does not support nested transaction.\n// So the following test cases are not supported.\n// If the problem is solved in the future, the test cases will be enabled.\n\n// func Test_Transaction_Nested_Begin_Rollback_Commit(t *testing.T) {\n// \ttable := createTable()\n// \tdefer dropTable(table)\n//\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\ttx, err := db.Begin(ctx)\n// \t\tt.AssertNil(err)\n//\n// \t\t// tx begin.\n// \t\terr = tx.Begin()\n// \t\tt.AssertNil(err)\n//\n// \t\t// tx rollback.\n// \t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\"id\":       1,\n// \t\t\t\"passport\": \"user_1\",\n// \t\t\t\"password\": \"pass_1\",\n// \t\t\t\"nickname\": \"name_1\",\n// \t\t}).Insert()\n// \t\terr = tx.Rollback()\n// \t\tt.AssertNil(err)\n//\n// \t\t// tx commit.\n// \t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\"id\":       2,\n// \t\t\t\"passport\": \"user_2\",\n// \t\t\t\"password\": \"pass_2\",\n// \t\t\t\"nickname\": \"name_2\",\n// \t\t}).Insert()\n// \t\terr = tx.Commit()\n// \t\tt.AssertNil(err)\n//\n// \t\t// check data.\n// \t\tall, err := db.Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 1)\n// \t\tt.Assert(all[0][\"id\"], 2)\n// \t})\n// }\n//\n// func Test_Transaction_Nested_TX_Transaction_UseTX(t *testing.T) {\n// \ttable := createTable()\n// \tdefer dropTable(table)\n//\n// \tdb.SetDebug(true)\n// \tdefer db.SetDebug(false)\n//\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tvar (\n// \t\t\terr error\n// \t\t\tctx = context.TODO()\n// \t\t)\n// \t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t// commit\n// \t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\t\t\t\t\t\t\"id\":          1,\n// \t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n// \t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n// \t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n// \t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t\t\t\t\t}).Insert()\n// \t\t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t\t})\n// \t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t})\n// \t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\treturn err\n// \t\t\t\t\t})\n// \t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\treturn err\n// \t\t\t\t})\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNil(err)\n//\n// \t\t\t// rollback\n// \t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\t\t\"id\":          2,\n// \t\t\t\t\t\"passport\":    \"USER_2\",\n// \t\t\t\t\t\"password\":    \"PASS_2\",\n// \t\t\t\t\t\"nickname\":    \"NAME_2\",\n// \t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t}).Insert()\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\tpanic(\"error\")\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNE(err, nil)\n// \t\t\treturn nil\n// \t\t})\n// \t\tt.AssertNil(err)\n//\n// \t\tall, err := db.Ctx(ctx).Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 1)\n// \t\tt.Assert(all[0][\"id\"], 1)\n//\n// \t\t// another record.\n// \t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t// commit\n// \t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\t\t\t\t\t\t\"id\":          3,\n// \t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n// \t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n// \t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n// \t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t\t\t\t\t}).Insert()\n// \t\t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t\t})\n// \t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t})\n// \t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\treturn err\n// \t\t\t\t\t})\n// \t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\treturn err\n// \t\t\t\t})\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNil(err)\n//\n// \t\t\t// rollback\n// \t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\t\t\"id\":          4,\n// \t\t\t\t\t\"passport\":    \"USER_2\",\n// \t\t\t\t\t\"password\":    \"PASS_2\",\n// \t\t\t\t\t\"nickname\":    \"NAME_2\",\n// \t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t}).Insert()\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\tpanic(\"error\")\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNE(err, nil)\n// \t\t\treturn nil\n// \t\t})\n// \t\tt.AssertNil(err)\n//\n// \t\tall, err = db.Ctx(ctx).Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 2)\n// \t\tt.Assert(all[0][\"id\"], 1)\n// \t\tt.Assert(all[1][\"id\"], 3)\n// \t})\n// }\n//\n// func Test_Transaction_Nested_TX_Transaction_UseDB(t *testing.T) {\n// \ttable := createTable()\n// \tdefer dropTable(table)\n//\n// \t// db.SetDebug(true)\n// \t// defer db.SetDebug(false)\n//\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tvar (\n// \t\t\terr error\n// \t\t\tctx = context.TODO()\n// \t\t)\n// \t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t// commit\n// \t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n// \t\t\t\t\t\t\t\t\t\"id\":          1,\n// \t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n// \t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n// \t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n// \t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t\t\t\t\t}).Insert()\n// \t\t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t\t})\n// \t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t})\n// \t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\treturn err\n// \t\t\t\t\t})\n// \t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\treturn err\n// \t\t\t\t})\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNil(err)\n//\n// \t\t\t// rollback\n// \t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t_, err = tx.Model(table).Ctx(ctx).Data(g.Map{\n// \t\t\t\t\t\"id\":          2,\n// \t\t\t\t\t\"passport\":    \"USER_2\",\n// \t\t\t\t\t\"password\":    \"PASS_2\",\n// \t\t\t\t\t\"nickname\":    \"NAME_2\",\n// \t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t}).Insert()\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t// panic makes this transaction rollback.\n// \t\t\t\tpanic(\"error\")\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNE(err, nil)\n// \t\t\treturn nil\n// \t\t})\n// \t\tt.AssertNil(err)\n//\n// \t\tall, err := db.Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 1)\n// \t\tt.Assert(all[0][\"id\"], 1)\n//\n// \t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t// commit\n// \t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n// \t\t\t\t\t\t\t\t\t\"id\":          3,\n// \t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n// \t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n// \t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n// \t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t\t\t\t\t}).Insert()\n// \t\t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t\t})\n// \t\t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\t\treturn err\n// \t\t\t\t\t\t})\n// \t\t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\t\treturn err\n// \t\t\t\t\t})\n// \t\t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t\treturn err\n// \t\t\t\t})\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNil(err)\n//\n// \t\t\t// rollback\n// \t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n// \t\t\t\t_, err = tx.Model(table).Ctx(ctx).Data(g.Map{\n// \t\t\t\t\t\"id\":          4,\n// \t\t\t\t\t\"passport\":    \"USER_2\",\n// \t\t\t\t\t\"password\":    \"PASS_2\",\n// \t\t\t\t\t\"nickname\":    \"NAME_2\",\n// \t\t\t\t\t\"create_time\": gtime.Now().String(),\n// \t\t\t\t}).Insert()\n// \t\t\t\tt.AssertNil(err)\n//\n// \t\t\t\t// panic makes this transaction rollback.\n// \t\t\t\tpanic(\"error\")\n// \t\t\t\treturn err\n// \t\t\t})\n// \t\t\tt.AssertNE(err, nil)\n// \t\t\treturn nil\n// \t\t})\n// \t\tt.AssertNil(err)\n//\n// \t\tall, err = db.Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 2)\n// \t\tt.Assert(all[0][\"id\"], 1)\n// \t\tt.Assert(all[1][\"id\"], 3)\n// \t})\n// }\n//\n// func Test_Transaction_Nested_SavePoint_RollbackTo(t *testing.T) {\n// \ttable := createTable()\n// \tdefer dropTable(table)\n//\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\ttx, err := db.Begin(ctx)\n// \t\tt.AssertNil(err)\n//\n// \t\t// tx save point.\n// \t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\"id\":       1,\n// \t\t\t\"passport\": \"user_1\",\n// \t\t\t\"password\": \"pass_1\",\n// \t\t\t\"nickname\": \"name_1\",\n// \t\t}).Insert()\n// \t\terr = tx.SavePoint(\"MyPoint\")\n// \t\tt.AssertNil(err)\n//\n// \t\t_, err = tx.Model(table).Data(g.Map{\n// \t\t\t\"id\":       2,\n// \t\t\t\"passport\": \"user_2\",\n// \t\t\t\"password\": \"pass_2\",\n// \t\t\t\"nickname\": \"name_2\",\n// \t\t}).Insert()\n// \t\t// tx rollback to.\n// \t\terr = tx.RollbackTo(\"MyPoint\")\n// \t\tt.AssertNil(err)\n//\n// \t\t// tx commit.\n// \t\terr = tx.Commit()\n// \t\tt.AssertNil(err)\n//\n// \t\t// check data.\n// \t\tall, err := db.Model(table).All()\n// \t\tt.AssertNil(err)\n//\n// \t\tt.Assert(len(all), 1)\n// \t\tt.Assert(all[0][\"id\"], 1)\n// \t})\n// }\n\nfunc Test_Transaction_Method(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = db.Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\n\t\t\t_, err = db.Ctx(ctx).Exec(ctx, fmt.Sprintf(\n\t\t\t\t\"insert into %s(passport , password , nickname , create_time , id ) \"+\n\t\t\t\t\t\"VALUES('t2','25d55ad283aa400af464c76d713c07ad','T2','2021-08-25 21:53:00',2) \",\n\t\t\t\ttable))\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(0))\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/mysql/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/go-sql-driver/mysql v1.7.1\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/mysql/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=\ngithub.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package mysql implements gdb.Driver, which supports operations for database MySQL.\npackage mysql\n\nimport (\n\t_ \"github.com/go-sql-driver/mysql\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// Driver is the driver for mysql database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tquoteChar = \"`\"\n)\n\nfunc init() {\n\tvar (\n\t\terr         error\n\t\tdriverObj   = New()\n\t\tdriverNames = g.SliceStr{\"mysql\", \"mariadb\", \"tidb\"} // TODO remove mariadb and tidb in future versions.\n\t)\n\tfor _, driverName := range driverNames {\n\t\tif err = gdb.Register(driverName, driverObj); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for MySQL.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for mysql.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoFilter handles the sql before posts it to database.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\treturn d.Core.DoFilter(ctx, link, sql, args)\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Open creates and returns an underlying sql.DB object for mysql.\n// Note that it converts time.Time argument to local timezone in default.\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar (\n\t\tsource               = configNodeToSource(config)\n\t\tunderlyingDriverName = \"mysql\"\n\t)\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n\n// [username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]\nfunc configNodeToSource(config *gdb.ConfigNode) string {\n\tvar (\n\t\tsource  string\n\t\tportStr string\n\t)\n\tif config.Port != \"\" {\n\t\tportStr = \":\" + config.Port\n\t}\n\tsource = fmt.Sprintf(\n\t\t\"%s:%s@%s(%s%s)/%s?charset=%s\",\n\t\tconfig.User, config.Pass, config.Protocol, config.Host, portStr, config.Name, config.Charset,\n\t)\n\tif config.Timezone != \"\" {\n\t\tif strings.Contains(config.Timezone, \"/\") {\n\t\t\tconfig.Timezone = url.QueryEscape(config.Timezone)\n\t\t}\n\t\tsource = fmt.Sprintf(\"%s&loc=%s\", source, config.Timezone)\n\t}\n\tif config.Extra != \"\" {\n\t\tsource = fmt.Sprintf(\"%s&%s\", source, config.Extra)\n\t}\n\treturn source\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\t// tableFieldsSqlByMariadb is the query statement for retrieving table fields' information in MariaDB.\n\t// Deprecated: Use package `contrib/drivers/mariadb` instead.\n\t// TODO remove in next version.\n\ttableFieldsSqlByMariadb = `\nSELECT\n\tc.COLUMN_NAME AS 'Field',\n\t( CASE WHEN ch.CHECK_CLAUSE LIKE 'json_valid%%' THEN 'json' ELSE c.COLUMN_TYPE END ) AS 'Type',\n\tc.COLLATION_NAME AS 'Collation',\n\tc.IS_NULLABLE AS 'Null',\n\tc.COLUMN_KEY AS 'Key',\n\t( CASE WHEN c.COLUMN_DEFAULT = 'NULL' OR c.COLUMN_DEFAULT IS NULL THEN NULL ELSE c.COLUMN_DEFAULT END) AS 'Default',\n\tc.EXTRA AS 'Extra',\n\tc.PRIVILEGES AS 'Privileges',\n\tc.COLUMN_COMMENT AS 'Comment' \nFROM\n\tinformation_schema.COLUMNS AS c\n\tLEFT JOIN information_schema.CHECK_CONSTRAINTS AS ch ON c.TABLE_NAME = ch.TABLE_NAME \n    AND c.TABLE_SCHEMA = ch.CONSTRAINT_SCHEMA\n\tAND c.COLUMN_NAME = ch.CONSTRAINT_NAME \nWHERE\n\tc.TABLE_SCHEMA = '%s' \n\tAND c.TABLE_NAME = '%s'\n\tORDER BY c.ORDINAL_POSITION`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlByMariadb, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlByMariadb)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current\n// schema.\n//\n// The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection\n// as its link to proceed necessary sql query.\n//\n// Note that it returns a map containing the field name and its corresponding fields.\n// As a map is unsorted, the TableField struct has a \"Index\" field marks its sequence in\n// the fields.\n//\n// It's using cache feature to enhance the performance, which is never expired util the\n// process restarts.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult         gdb.Result\n\t\tlink           gdb.Link\n\t\tusedSchema     = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t\ttableFieldsSql string\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tdbType := d.GetConfig().Type\n\tswitch dbType {\n\t// Deprecated: Use package `contrib/drivers/mariadb` instead.\n\t// TODO remove in next version.\n\tcase \"mariadb\":\n\t\ttableFieldsSql = fmt.Sprintf(tableFieldsSqlByMariadb, usedSchema, table)\n\tdefault:\n\t\ttableFieldsSql = fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.QuoteWord(table))\n\t}\n\n\tresult, err = d.DoSelect(\n\t\tctx, link,\n\t\ttableFieldsSql,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tfields[m[\"Field\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"Field\"].String(),\n\t\t\tType:    m[\"Type\"].String(),\n\t\t\tNull:    m[\"Null\"].Bool(),\n\t\t\tKey:     m[\"Key\"].String(),\n\t\t\tDefault: m[\"Default\"].Val(),\n\t\t\tExtra:   m[\"Extra\"].String(),\n\t\t\tComment: m[\"Comment\"].String(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, `SHOW TABLES`)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Instance(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gdb.Instance(\"none\")\n\t\tt.AssertNE(err, nil)\n\n\t\tdb, err := gdb.Instance()\n\t\tt.AssertNil(err)\n\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Func_FormatSqlWithArgs(t *testing.T) {\n\t// mysql\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s string\n\t\ts = gdb.FormatSqlWithArgs(\"select * from table where id>=? and sex=?\", []any{100, 1})\n\t\tt.Assert(s, \"select * from table where id>=100 and sex=1\")\n\t})\n\t// mssql\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s string\n\t\ts = gdb.FormatSqlWithArgs(\"select * from table where id>=@p1 and sex=@p2\", []any{100, 1})\n\t\tt.Assert(s, \"select * from table where id>=100 and sex=1\")\n\t})\n\t// pgsql\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s string\n\t\ts = gdb.FormatSqlWithArgs(\"select * from table where id>=$1 and sex=$2\", []any{100, 1})\n\t\tt.Assert(s, \"select * from table where id>=100 and sex=1\")\n\t})\n\t// oracle\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s string\n\t\ts = gdb.FormatSqlWithArgs(\"select * from table where id>=:v1 and sex=:v2\", []any{100, 1})\n\t\tt.Assert(s, \"select * from table where id>=100 and sex=1\")\n\t})\n}\n\nfunc Test_Func_ToSQL(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\tvalue, err := db.Ctx(ctx).Model(TableName).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\t\tt.Assert(value, nil)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(sql, \"SELECT `nickname` FROM `user` WHERE `id`=1 LIMIT 1\")\n\t})\n}\n\nfunc Test_Func_CatchSQL(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tvalue, err := db.Ctx(ctx).Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\t\tt.Assert(value, \"name_1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertGE(len(array), 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_core_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nfunc Benchmark_BatchInsert(b *testing.B) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\ttype User struct {\n\t\tId         int         `c:\"id\"`\n\t\tPassport   string      `c:\"passport\"`\n\t\tPassword   string      `c:\"password\"`\n\t\tNickName   string      `c:\"nickname\"`\n\t\tCreateTime *gtime.Time `c:\"create_time\"`\n\t}\n\tvar users []*User\n\tfor i := 0; i < 10000; i++ {\n\t\tusers = append(users, &User{\n\t\t\tPassport:   grand.S(10),\n\t\t\tPassword:   grand.S(10),\n\t\t\tNickName:   grand.S(10),\n\t\t\tCreateTime: gtime.Now(),\n\t\t})\n\t}\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tresult, err := db.Insert(ctx, table, users)\n\t\tif err != nil {\n\t\t\tb.Fatalf(\"insert error: %v\", err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tb.Logf(\"insert %d rows\", n)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_core_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: TestDbUser,\n\t\t\tPass: TestDbPass,\n\t\t\tType: \"mysql\",\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Exec(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst, err := db.Prepare(ctx, \"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0], \"100\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\"create_date\": gtime.Date(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\"create_date\": gtime.Date(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime string      `json:\"create_time\"`\n\t\t\tCreateDate *gtime.Time `json:\"create_date\"`\n\t\t}\n\t\tgTime := gtime.New(\"2024-10-01 12:01:01\")\n\t\ttimeStr, dateStr := gTime.String(), \"2024-10-01 00:00:00\"\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tId:         3,\n\t\t\tPassport:   \"user_3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: timeStr,\n\t\t\tCreateDate: gTime,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t\tt.Assert(one[\"create_date\"].GTime().String(), dateStr)\n\n\t\t// *struct\n\t\tgTime = gtime.New(\"2024-10-01 12:01:01\")\n\t\ttimeStr, dateStr = gTime.String(), \"2024-10-01 00:00:00\"\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_4\",\n\t\t\tCreateTime: timeStr,\n\t\t\tCreateDate: gTime,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Where(\"id\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 4)\n\t\tt.Assert(one[\"passport\"].String(), \"t4\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_4\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t\tt.Assert(one[\"create_date\"].GTime().String(), dateStr)\n\n\t\t// batch with Insert\n\t\tgTime = gtime.New(\"2024-10-01 12:01:01\")\n\t\ttimeStr, dateStr = gTime.String(), \"2024-10-01 00:00:00\"\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          200,\n\t\t\t\t\"passport\":    \"t200\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d71qw07ad\",\n\t\t\t\t\"nickname\":    \"T200\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t\t\"create_date\": gTime,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          300,\n\t\t\t\t\"passport\":    \"t300\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T300\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t\t\"create_date\": gTime,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"id\", 200).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 200)\n\t\tt.Assert(one[\"passport\"].String(), \"t200\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d71qw07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T200\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t\tt.Assert(one[\"create_date\"].GTime().String(), dateStr)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_DB_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_DB_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_Insert_NilGjson(t *testing.T) {\n\tvar tableName = \"nil\" + gtime.TimestampNanoStr()\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t\tjson_empty_string json DEFAULT NULL,\n\t\tjson_nil json DEFAULT NULL,\n\t\tjson_null json DEFAULT NULL,\n\t\tPRIMARY KEY (id)\n\t) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t`, tableName))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Json struct {\n\t\t\tId              int\n\t\t\tJsonEmptyString *gjson.Json\n\t\t\tJsonNil         *gjson.Json\n\t\t\tJsonNull        *gjson.Json\n\t\t}\n\n\t\tdata := Json{\n\t\t\tId:              1,\n\t\t\tJsonEmptyString: gjson.New(\"\"),\n\t\t\tJsonNil:         gjson.New(nil),\n\t\t\tJsonNull:        gjson.New(struct{}{}),\n\t\t}\n\n\t\t_, err = db.Insert(ctx, tableName, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", tableName), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.AssertEQ(len(one), 4)\n\n\t\tt.Assert(one[\"json_empty_string\"], nil)\n\t\tt.Assert(one[\"json_nil\"], nil)\n\t\tt.Assert(one[\"json_null\"], \"null\")\n\t})\n}\n\nfunc Test_DB_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Update(ctx, table, data, \"id=1\")\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\n// This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0.\n// func Test_DB_Insert_KeyFieldNameMapping_Error(t *testing.T) {\n//\ttable := createTable()\n//\tdefer dropTable(table)\n//\n//\tgtest.C(t, func(t *gtest.T) {\n//\t\ttype User struct {\n//\t\t\tId             int\n//\t\t\tPassport       string\n//\t\t\tPassword       string\n//\t\t\tNickname       string\n//\t\t\tCreateTime     string\n//\t\t\tNoneExistField string\n//\t\t}\n//\t\tdata := User{\n//\t\t\tId:         1,\n//\t\t\tPassport:   \"user_1\",\n//\t\t\tPassword:   \"pass_1\",\n//\t\t\tNickname:   \"name_1\",\n//\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n//\t\t}\n//\t\t_, err := db.Insert(ctx, table, data)\n//\t\tt.AssertNE(err, nil)\n//\t})\n// }\n\nfunc Test_DB_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.InsertIgnore(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tn, _ = r.LastInsertId()\n\t\tt.Assert(n, 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Batch insert with different fields\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ac\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttype User struct {\n\t\t\tId         int         `c:\"id\"`\n\t\t\tPassport   string      `c:\"passport\"`\n\t\t\tPassword   string      `c:\"password\"`\n\t\t\tNickName   string      `c:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `c:\"create_time\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"t1\",\n\t\t\tPassword:   \"p1\",\n\t\t\tNickName:   \"T1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\tresult, err := db.Insert(ctx, table, user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\t_, err := db.Save(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t1\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\t_, err := db.Replace(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t1\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"987654321\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_DB_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          200,\n\t\t\t\"passport\":    \"t200\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T200\",\n\t\t\t\"create_time\": time.Now(),\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 200)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t200\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := time.Now()\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          300,\n\t\t\t\"passport\":    \"t300\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T300\",\n\t\t\t\"create_time\": &t1,\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 300)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t300\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_DB_ToJson(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := make([]User, 0)\n\n\t\terr = result.Structs(users)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = result.Structs(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\t// ToJson\n\t\tresultJson, err := gjson.LoadContent([]byte(result.Json()))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(users[0].Id, resultJson.Get(\"0.id\").Int())\n\t\tt.Assert(users[0].Passport, resultJson.Get(\"0.passport\").String())\n\t\tt.Assert(users[0].Password, resultJson.Get(\"0.password\").String())\n\t\tt.Assert(users[0].NickName, resultJson.Get(\"0.nickname\").String())\n\t\tt.Assert(users[0].CreateTime, resultJson.Get(\"0.create_time\").String())\n\n\t\tresult = nil\n\t\tt.Assert(result.Structs(&users), sql.ErrNoRows)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := User{}\n\n\t\terr = result.Struct(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult = nil\n\t\terr = result.Struct(&users)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_ToXml(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tuser := User{}\n\t\terr = record.Struct(&user)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult, err := gxml.Decode([]byte(record.Xml(\"doc\")))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultXml := result[\"doc\"].(map[string]any)\n\t\tif v, ok := resultXml[\"id\"]; ok {\n\t\t\tt.Assert(user.Id, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"passport\"]; ok {\n\t\t\tt.Assert(user.Passport, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"password\"]; ok {\n\t\t\tt.Assert(user.Password, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"nickname\"]; ok {\n\t\t\tt.Assert(user.NickName, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"create_time\"]; ok {\n\t\t\tt.Assert(user.CreateTime, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\t})\n}\n\nfunc Test_DB_ToStringMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringMap := result.MapKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultStringMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultStringMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultStringMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultStringMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToIntMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToUintMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintMap := result.MapKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintMap[uint(id)][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultUintMap[uint(id)][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultUintMap[uint(id)][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultUintMap[uint(id)][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultUintMap[uint(id)][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToStringRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tids := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringRecord := result.RecordKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringRecord[ids][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultStringRecord[ids][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultStringRecord[ids][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultStringRecord[ids][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultStringRecord[ids][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToIntRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntRecord := result.RecordKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntRecord[id][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultIntRecord[id][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultIntRecord[id][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultIntRecord[id][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultIntRecord[id][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToUintRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintRecord := result.RecordKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintRecord[uint(id)][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultUintRecord[uint(id)][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultUintRecord[uint(id)][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultUintRecord[uint(id)][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultUintRecord[uint(id)][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_TableField(t *testing.T) {\n\tname := \"field_test\"\n\tdropTable(name)\n\tdefer dropTable(name)\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\tfield_tinyint  tinyint(8) NULL ,\n\t\tfield_int  int(8) NULL ,\n\t\tfield_integer  integer(8) NULL ,\n\t\tfield_bigint  bigint(8) NULL ,\n\t\tfield_bit  bit(3) NULL ,\n\t\tfield_real  real(8,0) NULL ,\n\t\tfield_double  double(12,2) NULL ,\n\t\tfield_varchar  varchar(10) NULL ,\n\t\tfield_varbinary  varbinary(255) NULL \n\t) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t`, name))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tdata := gdb.Map{\n\t\t\"field_tinyint\":   1,\n\t\t\"field_int\":       2,\n\t\t\"field_integer\":   3,\n\t\t\"field_bigint\":    4,\n\t\t\"field_bit\":       6,\n\t\t\"field_real\":      123,\n\t\t\"field_double\":    123.25,\n\t\t\"field_varchar\":   \"abc\",\n\t\t\"field_varbinary\": \"aaa\",\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tres, err := db.Model(name).Data(data).Insert()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t} else {\n\t\t\tt.Assert(n, 1)\n\t\t}\n\n\t\tresult, err := db.Model(name).Fields(\"*\").Where(\"field_int = ?\", 2).All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(result[0], data)\n\t})\n\n}\n\nfunc Test_DB_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\tname := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\ttable := TableNamePrefix1 + name\n\tcreateTableWithDb(db, table)\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Insert(ctx, name, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Replace(ctx, name, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:01\").String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Save(ctx, name, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:02\").String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Update(ctx, name, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:03\").String(),\n\t\t}, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Delete(ctx, name, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := db.Insert(ctx, name, array.Slice())\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InnerJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 5).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 5)\n\n\t\tresult, err := db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 5)\n\n\t\tresult, err = db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ?\", 1).Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 4)\n\t})\n}\n\nfunc Test_Model_LeftJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table2).Where(\"id > ?\", 3).Delete()\n\t\tt.AssertNil(err)\n\n\t\tn, err := res.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 7)\n\n\t\tresult, err := db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ? \", 2).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t})\n}\n\nfunc Test_Model_RightJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 7)\n\n\t\tresult, err := db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > 2\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 1)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// update counter test.\nfunc Test_DB_UpdateCounter(t *testing.T) {\n\ttableName := \"gf_update_counter_test_\" + gtime.TimestampNanoStr()\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid int(10) unsigned NOT NULL,\n\t\tviews  int(8) unsigned DEFAULT '0'  NOT NULL ,\n\t\tupdated_time int(10) unsigned DEFAULT '0' NOT NULL\n\t) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t`, tableName))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tinsertData := g.Map{\n\t\t\t\"id\":           1,\n\t\t\t\"views\":        0,\n\t\t\t\"updated_time\": 0,\n\t\t}\n\t\t_, err = db.Insert(ctx, tableName, insertData)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"id\",\n\t\t\tValue: 1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\": gdbCounter,\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"views\",\n\t\t\tValue: -1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\":        gdbCounter,\n\t\t\t\"updated_time\": gtime.Now().Unix(),\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 1)\n\t})\n}\n\nfunc Test_DB_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Second)\n\t\tdefer cancel()\n\t\t_, err := db.Query(ctx, \"SELECT SLEEP(10)\")\n\t\tt.Assert(gstr.Contains(err.Error(), \"deadline\"), true)\n\t})\n}\n\nfunc Test_DB_Ctx_Logger(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer db.SetDebug(db.GetDebug())\n\t\tdb.SetDebug(true)\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"123456789\")\n\t\t_, err := db.Query(ctx, \"SELECT 1\")\n\t\tt.AssertNil(err)\n\t})\n}\n\n// All types testing.\nfunc Test_Types(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS types (\n        id int(10) unsigned NOT NULL AUTO_INCREMENT,\n        %s blob NOT NULL,\n        %s binary(8) NOT NULL,\n        %s date NOT NULL,\n        %s time NOT NULL,\n        %s timestamp(6) NOT NULL,\n        %s decimal(5,2) NOT NULL,\n        %s double NOT NULL,\n        %s bit(2) NOT NULL,\n        %s tinyint(1) NOT NULL,\n        %s bool NOT NULL,\n        PRIMARY KEY (id)\n    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `,\n\t\t\t\"`blob`\",\n\t\t\t\"`binary`\",\n\t\t\t\"`date`\",\n\t\t\t\"`time`\",\n\t\t\t\"`timestamp`\",\n\t\t\t\"`decimal`\",\n\t\t\t\"`double`\",\n\t\t\t\"`bit`\",\n\t\t\t\"`tinyint`\",\n\t\t\t\"`bool`\")); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tdefer dropTable(\"types\")\n\t\tdata := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"blob\":      \"i love gf\",\n\t\t\t\"binary\":    []byte(\"abcdefgh\"),\n\t\t\t\"date\":      \"1880-10-24\",\n\t\t\t\"time\":      \"10:00:01\",\n\t\t\t\"timestamp\": \"2022-02-14 12:00:01.123456\",\n\t\t\t\"decimal\":   -123.456,\n\t\t\t\"double\":    -123.456,\n\t\t\t\"bit\":       2,\n\t\t\t\"tinyint\":   true,\n\t\t\t\"bool\":      false,\n\t\t}\n\t\tr, err := db.Model(\"types\").Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(\"types\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"blob\"].String(), data[\"blob\"])\n\t\tt.Assert(one[\"binary\"].String(), data[\"binary\"])\n\t\tt.Assert(one[\"date\"].String(), data[\"date\"])\n\t\tt.Assert(one[\"time\"].String(), `10:00:01`)\n\t\tt.Assert(one[\"timestamp\"].GTime().Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(one[\"decimal\"].String(), -123.46)\n\t\tt.Assert(one[\"double\"].String(), data[\"double\"])\n\t\tt.Assert(one[\"bit\"].Int(), data[\"bit\"])\n\t\tt.Assert(one[\"tinyint\"].Bool(), data[\"tinyint\"])\n\n\t\ttype T struct {\n\t\t\tId        int\n\t\t\tBlob      []byte\n\t\t\tBinary    []byte\n\t\t\tDate      *gtime.Time\n\t\t\tTime      *gtime.Time\n\t\t\tTimestamp *gtime.Time\n\t\t\tDecimal   float64\n\t\t\tDouble    float64\n\t\t\tBit       int8\n\t\t\tTinyInt   bool\n\t\t}\n\t\tvar obj *T\n\t\terr = db.Model(\"types\").Scan(&obj)\n\t\tt.AssertNil(err)\n\t\tt.Assert(obj.Id, 1)\n\t\tt.Assert(obj.Blob, data[\"blob\"])\n\t\tt.Assert(obj.Binary, data[\"binary\"])\n\t\tt.Assert(obj.Date.Format(\"Y-m-d\"), data[\"date\"])\n\t\tt.Assert(obj.Time.String(), `10:00:01`)\n\t\tt.Assert(obj.Timestamp.Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(obj.Decimal, -123.46)\n\t\tt.Assert(obj.Double, data[\"double\"])\n\t\tt.Assert(obj.Bit, data[\"bit\"])\n\t\tt.Assert(obj.TinyInt, data[\"tinyint\"])\n\t})\n}\n\nfunc Test_Core_ClearTableFields(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields), 6)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.GetCore().ClearTableFields(ctx, table)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Core_ClearTableFieldsAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.GetCore().ClearTableFieldsAll(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Core_ClearCache(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.GetCore().ClearCache(ctx, \"\")\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Core_ClearCacheAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.GetCore().ClearCacheAll(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_batch_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Batch_Insert tests batch insert with different batch sizes\nfunc Test_Model_Batch_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare data for batch insert\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"batch_user_%d\", i),\n\t\t\t\t\"password\": fmt.Sprintf(\"batch_pass_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"batch_name_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Batch insert with batch size 3\n\t\tresult, err := db.Model(table).Batch(3).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\n\t\t// Verify all records were inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 10)\n\n\t\t// Verify specific records\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"batch_user_1\")\n\n\t\tone, err = db.Model(table).Where(\"id\", 10).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"batch_user_10\")\n\t})\n}\n\n// Test_Model_Batch_Replace tests batch replace operation\nfunc Test_Model_Batch_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Initial insert\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"original_%d\", i),\n\t\t\t})\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Batch replace with overlapping ids\n\t\treplaceData := g.Slice{}\n\t\tfor i := 3; i <= 8; i++ {\n\t\t\treplaceData = append(replaceData, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"replaced_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"new_name_%d\", i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Batch(2).Data(replaceData).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.AssertGT(n, 0)\n\n\t\t// Verify replaced records\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"replaced_3\")\n\t\tt.Assert(one[\"nickname\"], \"new_name_3\")\n\n\t\t// Verify new records\n\t\tone, err = db.Model(table).Where(\"id\", 8).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"replaced_8\")\n\n\t\t// Verify total count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 8) // ids 1-8\n\t})\n}\n\n// Test_Model_Batch_Save tests batch save operation\nfunc Test_Model_Batch_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Initial data\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"save_user_%d\", i),\n\t\t\t})\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Batch save with overlapping and new ids\n\t\tsaveData := g.Slice{}\n\t\tfor i := 3; i <= 8; i++ {\n\t\t\tsaveData = append(saveData, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"saved_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"save_name_%d\", i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Batch(3).Data(saveData).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.AssertGT(n, 0)\n\n\t\t// Verify updated records\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"saved_3\")\n\n\t\t// Verify inserted records\n\t\tone, err = db.Model(table).Where(\"id\", 8).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"saved_8\")\n\n\t\t// Verify total count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 8)\n\t})\n}\n\n// Test_Model_Batch_LargeBatch tests batch operation with large dataset\nfunc Test_Model_Batch_LargeBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare 1000+ records\n\t\tdata := g.Slice{}\n\t\ttotalRecords := 1500\n\t\tfor i := 1; i <= totalRecords; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"large_user_%d\", i),\n\t\t\t\t\"nickname\": fmt.Sprintf(\"large_name_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Batch insert with batch size 100\n\t\tresult, err := db.Model(table).Batch(100).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, totalRecords)\n\n\t\t// Verify count\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, totalRecords)\n\n\t\t// Verify first and last records\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"large_user_1\")\n\n\t\tone, err = db.Model(table).Where(\"id\", totalRecords).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], fmt.Sprintf(\"large_user_%d\", totalRecords))\n\t})\n}\n\n// Test_Model_Batch_EmptyBatch tests batch operation with empty data\nfunc Test_Model_Batch_EmptyBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Empty slice\n\t\tdata := g.Slice{}\n\n\t\t// Batch insert with empty data should return error\n\t\t_, err := db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertIN(err.Error(), \"data list cannot be empty\")\n\n\t\t// Verify no records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Batch_SingleRecord tests batch operation with single record\nfunc Test_Model_Batch_SingleRecord(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Single record batch insert\n\t\tdata := g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"single_user\",\n\t\t\t\t\"nickname\": \"single_name\",\n\t\t\t},\n\t\t}\n\n\t\tresult, err := db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"single_user\")\n\t\tt.Assert(one[\"nickname\"], \"single_name\")\n\t})\n}\n\n// Test_Model_Batch_VsBatch tests performance comparison between different batch sizes\nfunc Test_Model_Batch_VsBatch(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prepare data\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 100; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"perf_user_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Test with batch size 1\n\t\tresult, err := db.Model(table).Batch(1).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test with batch size 10\n\t\tresult, err = db.Model(table).Batch(10).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test with batch size 50\n\t\tresult, err = db.Model(table).Batch(50).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 100)\n\n\t\t// All batch sizes should produce same result\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 100)\n\t})\n}\n\n// Test_Model_Batch_WithTransaction tests batch operation within transaction\nfunc Test_Model_Batch_WithTransaction(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 50; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(\"tx_batch_%d\", i),\n\t\t\t})\n\t\t}\n\n\t\t// Test commit\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\tresult, err := tx.Model(table).Batch(10).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := result.RowsAffected()\n\t\t\tt.Assert(n, 50)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify commit\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 50)\n\n\t\t// Clean up\n\t\t_, err = db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Test rollback\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Batch(10).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\treturn fmt.Errorf(\"rollback test\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify rollback - no records should exist\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_cache_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Cache_Basic tests basic cache functionality\nfunc Test_Model_Cache_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First query - cache miss, result from DB\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"test_cache_basic\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update the record in DB\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"updated_user\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Second query - cache hit, still returns old cached value\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"test_cache_basic\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value, not \"updated_user\"\n\n\t\t// Query without cache - returns updated value from DB\n\t\tone, err = db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"updated_user\")\n\t})\n}\n\n// Test_Model_Cache_TTL tests cache TTL expiration\nfunc Test_Model_Cache_TTL(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with short TTL\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100, // 100ms TTL\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"ttl_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Immediate query - cache still valid\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100,\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value\n\n\t\t// Wait for cache to expire\n\t\ttime.Sleep(time.Millisecond * 150)\n\n\t\t// Query after expiration - should get fresh data\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Millisecond * 100,\n\t\t\tName:     \"test_cache_ttl\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"ttl_test\") // fresh value from DB\n\t})\n}\n\n// Test_Model_Cache_Clear tests clearing cache with negative duration\nfunc Test_Model_Cache_Clear(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Set cache\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 60,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record and clear cache\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Data(g.Map{\"passport\": \"cleared\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query again - should get fresh data since cache was cleared\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 60,\n\t\t\tName:     \"test_cache_clear\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"cleared\")\n\t})\n}\n\n// Test_Model_Cache_NoExpire tests cache with no expiration (Duration=0)\nfunc Test_Model_Cache_NoExpire(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with no expiration\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: 0, // never expires\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record\n\t\t_, err = db.Model(table).Data(g.Map{\"passport\": \"no_expire_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Wait a bit\n\t\ttime.Sleep(time.Millisecond * 100)\n\n\t\t// Query - cache should still be valid\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: 0,\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // cached value persists\n\n\t\t// Clear the cache with update operation\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_cache_no_expire\",\n\t\t}).Data(g.Map{\"nickname\": \"cleared\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Model_Cache_Force tests Force option to cache nil results\nfunc Test_Model_Cache_Force(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Note: Removed Force cache test due to cache invalidation on INSERT\n\t// The test logic was flawed - INSERT operations clear cache, so cached nil\n\t// results would be invalidated before the second query\n}\n\n// Test_Model_Cache_DisabledInTransaction tests cache is disabled in transactions\nfunc Test_Model_Cache_DisabledInTransaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// First query in transaction\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     \"test_tx_cache\",\n\t\t\t}).Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t\t// Update in transaction\n\t\t\t_, err = tx.Model(table).Data(g.Map{\"passport\": \"tx_update\"}).Where(\"id\", 1).Update()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Second query - should see updated value (cache disabled in tx)\n\t\t\tone, err = tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     \"test_tx_cache\",\n\t\t\t}).Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"tx_update\") // not cached, fresh from DB\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Model_PageCache tests pagination cache\nfunc Test_Model_PageCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First page query with cache\n\t\tall, err := db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\n\t\t// Insert new record\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":       11,\n\t\t\t\"passport\": \"user_11\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query again - should return cached results\n\t\tall, err = db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // cached results\n\n\t\t// Clear page cache by updating with Duration=-1\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test_page_count\",\n\t\t}).Data(g.Map{\"nickname\": \"page_test\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query with fresh cache - should return updated count\n\t\tall, err = db.Model(table).PageCache(\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_count\"},\n\t\t\tgdb.CacheOption{Duration: time.Second * 10, Name: \"test_page_data\"},\n\t\t).Page(1, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // still 3 items per page\n\n\t\t// Verify total count increased\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 11)\n\t})\n}\n\n// Test_Model_Cache_DifferentNames tests different cache names for same query\nfunc Test_Model_Cache_DifferentNames(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Cache with name1\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Cache same query with name2\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name2\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Update record and clear only cache_name1\n\t\t_, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Data(g.Map{\"passport\": \"diff_name\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query with cache_name1 - should get fresh data\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name1\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"diff_name\")\n\n\t\t// Query with cache_name2 - should still have cached old value\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tName:     \"cache_name2\",\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\") // still cached\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_concurrent_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Concurrent_Insert tests concurrent Insert operations\nfunc Test_Concurrent_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i + 1)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency)\n\t})\n}\n\n// Test_Concurrent_Update tests concurrent Update operations\nfunc Test_Concurrent_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"updated_%d\", id),\n\t\t\t\t}).Where(\"id\", id+1).Update()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify updates\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tone, err := db.Model(table).Where(\"id\", i+1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"nickname\"].String(), fmt.Sprintf(\"updated_%d\", i))\n\t\t}\n\t})\n}\n\n// Test_Concurrent_Delete tests concurrent Delete operations\nfunc Test_Concurrent_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table).Where(\"id\", id+1).Delete()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify deletions\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize-concurrency)\n\t})\n}\n\n// Test_Concurrent_Query tests concurrent Query operations\nfunc Test_Concurrent_Query(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 20\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tresult, err := db.Model(table).Where(\"id\", (id%TableSize)+1).One()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.AssertNE(result, nil)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Transaction tests concurrent transaction operations\nfunc Test_Concurrent_Transaction(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := db.Transaction(ctx, func(ctx g.Ctx, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Model(table).Insert(g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i + 1)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all transactions committed\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency)\n\t})\n}\n\n// Test_Concurrent_Mixed_Operations tests mixed concurrent operations\nfunc Test_Concurrent_Mixed_Operations(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\toperations := 30\n\n\t\twg.Add(operations)\n\t\tfor i := 0; i < operations; i++ {\n\t\t\top := i % 3\n\t\t\tswitch op {\n\t\t\tcase 0: // Insert\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\t_, _ = db.Model(table).Insert(g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"new_user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"new_pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"new_name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t}(i)\n\t\t\tcase 1: // Update\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\ttargetId := (id % TableSize) + 1\n\t\t\t\t\t_, _ = db.Model(table).Data(g.Map{\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"concurrent_%d\", id),\n\t\t\t\t\t}).Where(\"id\", targetId).Update()\n\t\t\t\t}(i)\n\t\t\tcase 2: // Query\n\t\t\t\tgo func(id int) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\ttargetId := (id % TableSize) + 1\n\t\t\t\t\t_, _ = db.Model(table).Where(\"id\", targetId).One()\n\t\t\t\t}(i)\n\t\t\t}\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify database is still consistent\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(count, TableSize)\n\t})\n}\n\n// Test_Concurrent_Connection_Pool tests connection pool under load\nfunc Test_Concurrent_Connection_Pool(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 50\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t// Each goroutine performs multiple operations\n\t\t\t\tfor j := 0; j < 5; j++ {\n\t\t\t\t\t_, err := db.Model(table).Where(\"id\", (id%TableSize)+1).One()\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t}\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Schema_Switch tests concurrent schema switching\nfunc Test_Concurrent_Schema_Switch(t *testing.T) {\n\ttable1 := createTableWithDb(db, \"test_schema_1\")\n\ttable2 := createTableWithDb(db2, \"test_schema_2\")\n\tdefer dropTableWithDb(db, table1)\n\tdefer dropTableWithDb(db2, table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency * 2)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\t// Insert to schema1\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db.Model(table1).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_s1_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\n\t\t\t// Insert to schema2\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := db2.Model(table2).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_s2_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify both schemas\n\t\tcount1, err := db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count1, concurrency)\n\n\t\tcount2, err := db2.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count2, concurrency)\n\t})\n}\n\n// Test_Concurrent_Model_Clone tests concurrent model cloning\nfunc Test_Concurrent_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbaseModel := db.Model(table).Where(\"id>\", 0)\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 20\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t// Clone model for each goroutine\n\t\t\t\tm := baseModel.Clone()\n\t\t\t\tresult, err := m.Where(\"id<=\", TableSize/2).All()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.AssertGT(len(result), 0)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t})\n}\n\n// Test_Concurrent_Batch_Insert tests concurrent batch insert operations\nfunc Test_Concurrent_Batch_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 5\n\t\tbatchSize := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(batchId int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tbatch := make([]g.Map, 0, batchSize)\n\t\t\t\tfor j := 0; j < batchSize; j++ {\n\t\t\t\t\tid := batchId*batchSize + j\n\t\t\t\t\tbatch = append(batch, g.Map{\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"batch_user_%d\", id),\n\t\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\t_, err := db.Model(table).Data(batch).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify all batch inserts\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency*batchSize)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb, err := gdb.Instance()\n\t\tt.AssertNil(err)\n\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\n\t\tnewDb := db.Ctx(context.Background())\n\t\tt.AssertNE(newDb, nil)\n\t})\n}\n\nfunc Test_Ctx_Query(t *testing.T) {\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Query(ctx, \"select 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Query(ctx, \"select 2\")\n\t})\n}\n\nfunc Test_Ctx_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Model(table).Ctx(ctx).All()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Model(table).All()\n\t})\n}\n\n// Test_Ctx_Timeout tests context timeout behavior\nfunc Test_Ctx_Timeout(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a context with very short timeout\n\t\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)\n\t\tdefer cancel()\n\n\t\t// Wait for timeout\n\t\ttime.Sleep(1 * time.Millisecond)\n\n\t\t// Query should fail due to context timeout\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Ctx_Cancel tests context cancellation\nfunc Test_Ctx_Cancel(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t// Cancel immediately\n\t\tcancel()\n\n\t\t// Query should fail due to cancelled context\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Ctx_Propagation_Transaction tests context propagation in transaction\nfunc Test_Ctx_Propagation_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"tx_trace_123\")\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Context should propagate to transaction operations\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Ctx_Multiple_Values tests context with multiple values\nfunc Test_Ctx_Multiple_Values(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\", \"RequestId\", \"UserId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"trace_001\")\n\t\tctx = context.WithValue(ctx, \"RequestId\", \"req_002\")\n\t\tctx = context.WithValue(ctx, \"UserId\", \"user_003\")\n\n\t\tdb.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t})\n}\n\n// Test_Ctx_Nested_Operations tests context in nested operations\nfunc Test_Ctx_Nested_Operations(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"TraceId\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"nested_trace\")\n\n\t\t// Nested query operations should all have context\n\t\tresult, err := db.Model(table).Ctx(ctx).Where(\"id>\", 0).All()\n\t\tt.AssertNil(err)\n\n\t\tif len(result) > 0 {\n\t\t\t// Another query using same context\n\t\t\t_, err = db.Model(table).Ctx(ctx).Where(\"id\", result[0][\"id\"]).One()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_duplicate_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc createDuplicateTable(table ...string) string {\n\tvar name string\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`duplicate_table_%d`, gtime.TimestampNano())\n\t}\n\tdropTable(name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t\t\temail       varchar(100) NOT NULL,\n\t\t\tusername    varchar(45) NULL,\n\t\t\tscore       int(10) unsigned DEFAULT 0,\n\t\t\tlogin_count int(10) unsigned DEFAULT 0,\n\t\t\tPRIMARY KEY (id),\n\t\t\tUNIQUE KEY uk_email (email)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc Test_OnDuplicateKeyUpdate_Basic(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First insert\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 100)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1\")\n\t\tt.Assert(one[\"score\"], 100)\n\n\t\t// Duplicate insert - should update\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1_updated\", 200)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1_updated\")\n\t\tt.Assert(one[\"score\"], 200)\n\n\t\t// Verify only one record exists\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_Increment(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First insert\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 1)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"login_count\"], 1)\n\n\t\t// Duplicate - increment login_count\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 1)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"login_count\"], 2)\n\n\t\t// Third time\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 1)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"login_count\"], 3)\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_MultipleColumns(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First insert\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score, login_count) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score), login_count = login_count + 1\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 100, 1)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1\")\n\t\tt.Assert(one[\"score\"], 100)\n\t\tt.Assert(one[\"login_count\"], 1)\n\n\t\t// Duplicate - update multiple columns\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score, login_count) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score), login_count = login_count + 1\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1_v2\", 200, 1)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1_v2\")\n\t\tt.Assert(one[\"score\"], 200)\n\t\tt.Assert(one[\"login_count\"], 2)\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_Batch(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert multiple records\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 100,\n\t\t\t\"user2@example.com\", \"user2\", 200,\n\t\t\t\"user3@example.com\", \"user3\", 300)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 3)\n\n\t\t// Update with duplicate - should update specific records\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1_updated\", 150,\n\t\t\t\"user2@example.com\", \"user2_updated\", 250)\n\t\tt.AssertNil(err)\n\n\t\t// Still 3 records\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 3)\n\n\t\t// Verify updates\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1_updated\")\n\t\tt.Assert(one[\"score\"], 150)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user2@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user2_updated\")\n\t\tt.Assert(one[\"score\"], 250)\n\n\t\t// user3 unchanged\n\t\tone, err = db.Model(table).Where(\"email\", \"user3@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user3\")\n\t\tt.Assert(one[\"score\"], 300)\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_ConditionalUpdate(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First insert\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 100)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"score\"], 100)\n\n\t\t// Try to update with lower score - should not update\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 50)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"score\"], 100) // Still 100\n\n\t\t// Update with higher score - should update\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 150)\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"score\"], 150) // Updated to 150\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_WithTransaction(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Transaction with ON DUPLICATE KEY UPDATE\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// First insert\n\t\t\t_, err := tx.Exec(fmt.Sprintf(\n\t\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\t\ttable,\n\t\t\t), \"user1@example.com\", \"user1\", 100)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Duplicate in same transaction\n\t\t\t_, err = tx.Exec(fmt.Sprintf(\n\t\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\t\ttable,\n\t\t\t), \"user1@example.com\", \"user1_updated\", 200)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify final state\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1_updated\")\n\t\tt.Assert(one[\"score\"], 200)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_OnDuplicateKeyUpdate_MixedInsertUpdate(t *testing.T) {\n\ttable := createDuplicateTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// First batch insert\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1\", 100,\n\t\t\t\"user2@example.com\", \"user2\", 200)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 2)\n\n\t\t// Mixed batch: one duplicate, one new\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)\",\n\t\t\ttable,\n\t\t), \"user1@example.com\", \"user1_updated\", 150,\n\t\t\t\"user3@example.com\", \"user3\", 300)\n\t\tt.AssertNil(err)\n\n\t\t// Should have 3 records now\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 3)\n\n\t\t// Verify user1 was updated\n\t\tone, err := db.Model(table).Where(\"email\", \"user1@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user1_updated\")\n\t\tt.Assert(one[\"score\"], 150)\n\n\t\t// Verify user3 was inserted\n\t\tone, err = db.Model(table).Where(\"email\", \"user3@example.com\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"username\"], \"user3\")\n\t\tt.Assert(one[\"score\"], 300)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_error_handling_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Insert_NilData tests Insert with nil data\nfunc Test_Model_Insert_NilData(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(nil).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Insert_EmptyMap tests Insert with empty map\nfunc Test_Model_Insert_EmptyMap(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Insert_EmptySlice tests Insert with empty slice\nfunc Test_Model_Insert_EmptySlice(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Slice{}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_NilData tests Update with nil data\nfunc Test_Model_Update_NilData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(nil).Where(\"id\", 1).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_EmptyData tests Update with empty data\nfunc Test_Model_Update_EmptyData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{}).Where(\"id\", 1).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Update_NoWhere tests Update without WHERE clause is rejected by framework\nfunc Test_Model_Update_NoWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Framework safety check: Update without WHERE should return error\n\t\t_, err := db.Model(table).Data(g.Map{\"nickname\": \"updated\"}).Update()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Delete_NoWhere tests Delete without WHERE clause is rejected by framework\nfunc Test_Model_Delete_NoWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Framework safety check: Delete without WHERE should return error\n\t\t_, err := db.Model(table).Delete()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_NilPointer tests Scan with nil pointer\nfunc Test_Model_Scan_NilPointer(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_InvalidPointer tests Scan with invalid pointer type\nfunc Test_Model_Scan_InvalidPointer(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar str string\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(&str)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Scan_EmptyResult tests Scan with empty result\nfunc Test_Model_Scan_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\t// Scan initialized struct with empty result returns sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).Scan(&user)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// Scan nil pointer with empty result returns nil error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\n// Test_Model_Where_InvalidOperator tests Where with invalid operator\nfunc Test_Model_Where_InvalidOperator(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Invalid SQL should cause error at query time\n\t\t_, err := db.Model(table).Where(\"id INVALID_OP ?\", 1).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Where_EmptyString tests Where with empty string\nfunc Test_Model_Where_EmptyString(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize) // Empty WHERE returns all\n\t})\n}\n\n// Test_Model_Fields_InvalidField tests Fields with non-existent field\nfunc Test_Model_Fields_InvalidField(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Fields(\"non_existent_field\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Fields_Empty tests Fields with empty string\n// Regression test for #4697: Fields(\"\") should handle empty string gracefully\n// https://github.com/gogf/gf/issues/4697\nfunc Test_Model_Fields_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"\").Limit(1).All()\n\t\tt.AssertNil(err)\n\t\tt.AssertLE(len(result), 1)\n\t})\n}\n\n// Test_Model_Order_InvalidSyntax tests Order with invalid syntax\nfunc Test_Model_Order_InvalidSyntax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Invalid ORDER BY syntax\n\t\t_, err := db.Model(table).Order(\"id INVALID\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Group_UnknownColumn tests Group with non-existent column\nfunc Test_Model_Group_UnknownColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Group(\"non_existent_field\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_TableNotExist tests querying non-existent table\nfunc Test_Model_TableNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"non_existent_table_xyz\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_InvalidTableName tests invalid table name\nfunc Test_Model_InvalidTableName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Empty table name\n\t\t_, err := db.Model(\"\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_SQLInjection_Where tests SQL injection prevention in Where\nfunc Test_Model_SQLInjection_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt SQL injection through string column parameter.\n\t\t// Using string column `nickname` instead of int column `id`,\n\t\t// because MySQL coerces \"1 OR 1=1\" to 1 for int columns.\n\t\tmaliciousInput := \"1 OR 1=1\"\n\t\tresult, err := db.Model(table).Where(\"nickname = ?\", maliciousInput).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0) // Should not return all records\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt SQL injection with quotes, using string column to avoid\n\t\t// MySQL implicit int conversion (which would coerce \"1'...\" to 1)\n\t\tmaliciousInput := \"1'; DROP TABLE \" + table + \"; --\"\n\t\tresult, err := db.Model(table).Where(\"nickname = ?\", maliciousInput).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\t// Table should still exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_SQLInjection_Insert tests SQL injection prevention in Insert\nfunc Test_Model_SQLInjection_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmaliciousData := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"'; DROP TABLE \" + table + \"; --\",\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": \"test\",\n\t\t}\n\t\t_, err := db.Model(table).Data(maliciousData).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data was inserted correctly and table still exists\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"passport\"].String(), \"'; DROP TABLE \"+table+\"; --\")\n\t})\n}\n\n// Test_Model_SQLInjection_Update tests SQL injection prevention in Update\nfunc Test_Model_SQLInjection_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Use shorter malicious string to fit in nickname column\n\t\tmaliciousData := g.Map{\n\t\t\t\"nickname\": \"'; DELETE FROM users; --\",\n\t\t}\n\t\t_, err := db.Model(table).Data(maliciousData).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only one record was updated (parameterized query prevents injection)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"].String(), \"'; DELETE FROM users; --\")\n\n\t\t// Other records should still exist (injection was prevented)\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_Context_Cancelled tests query with cancelled context\nfunc Test_Model_Context_Cancelled(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tcancel() // Cancel immediately\n\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gerror.Is(err, context.Canceled), true)\n\t})\n}\n\n// Test_Model_Value_EmptyResult tests Value with empty result\nfunc Test_Model_Value_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.IsEmpty(), true)\n\t})\n}\n\n// Test_Model_Array_EmptyResult tests Array with empty result\nfunc Test_Model_Array_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Where(\"id > ?\", 1000).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(array), 0)\n\t})\n}\n\n// Test_Model_Count_InvalidTable tests Count on invalid table\nfunc Test_Model_Count_InvalidTable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"non_existent_table\").Count()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_Max_EmptyResult tests Max with empty result\nfunc Test_Model_Max_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Min_EmptyResult tests Min with empty result\nfunc Test_Model_Min_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Avg_EmptyResult tests Avg with empty result\nfunc Test_Model_Avg_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_Sum_EmptyResult tests Sum with empty result\nfunc Test_Model_Sum_EmptyResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id > ?\", 1000).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 0) // Returns 0 for empty result\n\t})\n}\n\n// Test_Model_One_NilResult tests One returning nil\nfunc Test_Model_One_NilResult(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id > ?\", 1000).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one, nil)\n\t})\n}\n\n// Test_TX_Rollback_AfterError tests transaction rollback after error\nfunc Test_TX_Rollback_AfterError(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert valid record\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"pass1\",\n\t\t\t\t\"password\": \"pwd1\",\n\t\t\t\t\"nickname\": \"name1\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Insert duplicate id (should fail)\n\t\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":       1, // Duplicate\n\t\t\t\t\"passport\": \"pass2\",\n\t\t\t\t\"password\": \"pwd2\",\n\t\t\t\t\"nickname\": \"name2\",\n\t\t\t}).Insert()\n\n\t\t\treturn err // Return error to trigger rollback\n\t\t})\n\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify rollback - table should be empty\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Insert_DuplicateKey tests handling of duplicate key error\nfunc Test_Model_Insert_DuplicateKey(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"pass\",\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": \"name\",\n\t\t}\n\n\t\t// First insert should succeed\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Second insert with same id should fail\n\t\t_, err = db.Model(table).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Model_All_InvalidConnection tests query with invalid connection\nfunc Test_Model_All_InvalidConnection(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif dbInvalid == nil {\n\t\t\tt.Skip(\"dbInvalid not configured\")\n\t\t}\n\t\t_, err := dbInvalid.Model(\"test_table\").All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Hook_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"test\"] = gvar.New(100 + record[\"id\"].Int())\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(`id > 6`).OrderAsc(`id`).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 4)\n\t\tt.Assert(all[0][\"id\"].Int(), 7)\n\t\tt.Assert(all[0][\"test\"].Int(), 107)\n\t\tt.Assert(all[1][\"test\"].Int(), 108)\n\t\tt.Assert(all[2][\"test\"].Int(), 109)\n\t\tt.Assert(all[3][\"test\"].Int(), 110)\n\t})\n}\n\nfunc Test_Model_Hook_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\tfor i, item := range in.Data {\n\t\t\t\t\titem[\"passport\"] = fmt.Sprintf(`test_port_%d`, item[\"id\"])\n\t\t\t\t\titem[\"nickname\"] = fmt.Sprintf(`test_name_%d`, item[\"id\"])\n\t\t\t\t\tin.Data[i] = item\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `test_port_1`)\n\t\tt.Assert(one[\"nickname\"], `test_name_1`)\n\t})\n}\n\nfunc Test_Model_Hook_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\t\tswitch value := in.Data.(type) {\n\t\t\t\tcase gdb.List:\n\t\t\t\t\tfor i, data := range value {\n\t\t\t\t\t\tdata[\"passport\"] = `port`\n\t\t\t\t\t\tdata[\"nickname\"] = `name`\n\t\t\t\t\t\tvalue[i] = data\n\t\t\t\t\t}\n\t\t\t\t\tin.Data = value\n\n\t\t\t\tcase gdb.Map:\n\t\t\t\t\tvalue[\"passport\"] = `port`\n\t\t\t\t\tvalue[\"nickname\"] = `name`\n\t\t\t\t\tin.Data = value\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Data(g.Map{\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `port`)\n\t\tt.Assert(one[\"nickname\"], `name`)\n\t})\n}\n\nfunc Test_Model_Hook_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\t\treturn db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": `deleted`,\n\t\t\t\t}).Where(in.Condition).Update()\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(1).Delete()\n\t\tt.AssertNil(err)\n\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tfor _, item := range all {\n\t\t\tt.Assert(item[\"nickname\"].String(), `deleted`)\n\t\t}\n\t})\n}\n\n// Test_Model_Hook_Multiple tests multiple hooks execution order\nfunc Test_Model_Hook_Multiple(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar execOrder []string\n\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\texecOrder = append(execOrder, \"hook1_before\")\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\texecOrder = append(execOrder, \"hook1_after\")\n\t\t\t\treturn\n\t\t\t},\n\t\t}).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\texecOrder = append(execOrder, \"hook2_before\")\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\texecOrder = append(execOrder, \"hook2_after\")\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only the last registered hook executes (Hook is override, not chain)\n\t\tt.Assert(len(execOrder), 2)\n\t\tt.Assert(execOrder, g.Slice{\"hook2_before\", \"hook2_after\"})\n\t})\n}\n\n// Test_Model_Hook_Error_Abort tests hook returning error aborts operation\nfunc Test_Model_Hook_Error_Abort(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\t// Return error to abort insert\n\t\t\t\treturn nil, fmt.Errorf(\"hook aborted insert\")\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"passport\": \"test_abort\",\n\t\t\t\"password\": \"pass\",\n\t\t\t\"nickname\": \"name\",\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"hook aborted insert\")\n\n\t\t// Verify record was not inserted\n\t\tcount, err := db.Model(table).Where(\"passport\", \"test_abort\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_Hook_Modify_Data tests hook modifying data before insert\nfunc Test_Model_Hook_Modify_Data(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\t// Modify all data items\n\t\t\t\tfor i := range in.Data {\n\t\t\t\t\tin.Data[i][\"password\"] = \"encrypted_\" + fmt.Sprint(in.Data[i][\"password\"])\n\t\t\t\t\tin.Data[i][\"nickname\"] = \"verified_\" + fmt.Sprint(in.Data[i][\"nickname\"])\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"passport\": \"test_user\",\n\t\t\t\"password\": \"plain123\",\n\t\t\t\"nickname\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify data was modified by hook\n\t\tone, err := db.Model(table).Where(\"passport\", \"test_user\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"encrypted_plain123\")\n\t\tt.Assert(one[\"nickname\"].String(), \"verified_john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc createJSONTable(table ...string) string {\n\tvar name string\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`json_table_%d`, gtime.TimestampNano())\n\t}\n\tdropTable(name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t\t\tname        varchar(45) NULL,\n\t\t\tconfig      json NULL,\n\t\t\tmetadata    json NULL,\n\t\t\tPRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc Test_JSON_Insert_Map(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"name\": \"user1\",\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\"lang\":  \"zh-CN\",\n\t\t\t},\n\t\t\t\"metadata\": g.Map{\n\t\t\t\t\"tags\":  g.Slice{\"admin\", \"developer\"},\n\t\t\t\t\"level\": 5,\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"user1\")\n\t\tt.AssertNE(one[\"config\"], nil)\n\t\tt.AssertNE(one[\"metadata\"], nil)\n\t})\n}\n\nfunc Test_JSON_Insert_String(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"name\":     \"user2\",\n\t\t\t\"config\":   `{\"theme\":\"light\",\"lang\":\"en-US\"}`,\n\t\t\t\"metadata\": `{\"tags\":[\"user\"],\"level\":1}`,\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"user2\")\n\t\tt.AssertNE(one[\"config\"], nil)\n\t\tt.AssertNE(one[\"metadata\"], nil)\n\t})\n}\n\nfunc Test_JSON_Insert_Null(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"name\":     \"user3\",\n\t\t\t\"config\":   nil,\n\t\t\t\"metadata\": nil,\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"user3\")\n\t\tt.Assert(one[\"config\"], nil)\n\t\tt.Assert(one[\"metadata\"], nil)\n\t})\n}\n\nfunc Test_JSON_Update(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"name\": \"user1\",\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"theme\": \"dark\",\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update JSON column\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"theme\": \"light\",\n\t\t\t\t\"lang\":  \"en-US\",\n\t\t\t},\n\t\t}).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"config\"], nil)\n\t})\n}\n\nfunc Test_JSON_Extract_Where(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\tdata := g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user1\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\t\"lang\":  \"zh-CN\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user2\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"light\",\n\t\t\t\t\t\"lang\":  \"en-US\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user3\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\t\"lang\":  \"en-US\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query by JSON field using JSON_EXTRACT\n\t\tall, err := db.Model(table).Where(\"JSON_EXTRACT(config, '$.theme') = ?\", \"dark\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = db.Model(table).Where(\"JSON_EXTRACT(config, '$.lang') = ?\", \"en-US\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n}\n\nfunc Test_JSON_Extract_Select(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"name\": \"user1\",\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\"lang\":  \"zh-CN\",\n\t\t\t},\n\t\t\t\"metadata\": g.Map{\n\t\t\t\t\"level\": 5,\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Select with JSON_EXTRACT\n\t\tone, err := db.Model(table).Fields(\"name, JSON_EXTRACT(config, '$.theme') as theme, JSON_EXTRACT(metadata, '$.level') as level\").WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"user1\")\n\t\tt.AssertNE(one[\"theme\"], nil)\n\t\tt.AssertNE(one[\"level\"], nil)\n\t})\n}\n\nfunc Test_JSON_Array_Query(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data with JSON array\n\t\tdata := g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user1\",\n\t\t\t\t\"metadata\": g.Map{\n\t\t\t\t\t\"tags\": g.Slice{\"admin\", \"developer\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user2\",\n\t\t\t\t\"metadata\": g.Map{\n\t\t\t\t\t\"tags\": g.Slice{\"user\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user3\",\n\t\t\t\t\"metadata\": g.Map{\n\t\t\t\t\t\"tags\": g.Slice{\"admin\", \"user\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query by JSON array contains\n\t\tall, err := db.Model(table).Where(\"JSON_CONTAINS(metadata, ?, '$.tags')\", `\"admin\"`).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n}\n\nfunc Test_JSON_Batch_Insert(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user1\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\": \"user2\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"light\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"name\":   \"user3\",\n\t\t\t\t\"config\": nil,\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_JSON_Scan_To_Struct(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\ttype Config struct {\n\t\tTheme string `json:\"theme\"`\n\t\tLang  string `json:\"lang\"`\n\t}\n\ttype User struct {\n\t\tId     int\n\t\tName   string\n\t\tConfig *Config\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"name\": \"user1\",\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\"lang\":  \"zh-CN\",\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Scan to struct\n\t\tvar user User\n\t\terr = db.Model(table).WherePri(1).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Name, \"user1\")\n\t\tt.AssertNE(user.Config, nil)\n\t\tif user.Config != nil {\n\t\t\tt.Assert(user.Config.Theme, \"dark\")\n\t\t\tt.Assert(user.Config.Lang, \"zh-CN\")\n\t\t}\n\t})\n}\n\nfunc Test_JSON_Complex_Structure(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert complex nested JSON\n\t\tdata := g.Map{\n\t\t\t\"name\": \"user1\",\n\t\t\t\"config\": g.Map{\n\t\t\t\t\"ui\": g.Map{\n\t\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t\t\"fontSize\": g.Map{\n\t\t\t\t\t\t\"base\": 14,\n\t\t\t\t\t\t\"code\": 12,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"editor\": g.Map{\n\t\t\t\t\t\"tabSize\":  4,\n\t\t\t\t\t\"wordWrap\": true,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\t// Query nested JSON path\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(config, '$.ui.theme') as theme, JSON_EXTRACT(config, '$.ui.fontSize.base') as base_font\").WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"theme\"], nil)\n\t\tt.AssertNE(one[\"base_font\"], nil)\n\t})\n}\n\nfunc Test_JSON_Transaction(t *testing.T) {\n\ttable := createJSONTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in transaction\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"name\": \"user1\",\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"dark\",\n\t\t\t\t},\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Update in transaction\n\t\t\t_, err = tx.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"config\": g.Map{\n\t\t\t\t\t\"theme\": \"light\",\n\t\t\t\t},\n\t\t\t}).WherePri(1).Update()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"user1\")\n\t\tt.AssertNE(one[\"config\"], nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_lock_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_Lock tests the Lock method with custom lock clause\nfunc Test_Model_Lock(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test basic Lock with FOR UPDATE\n\t\tone, err := db.Model(table).Lock(\"FOR UPDATE\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\n\t\t// Test Lock with legacy LOCK IN SHARE MODE (MySQL 5.7+ compatible)\n\t\tone, err = db.Model(table).Lock(\"LOCK IN SHARE MODE\").Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 3)\n\n\t\t// Test Lock with predefined constants\n\t\tone, err = db.Model(table).Lock(gdb.LockForUpdate).Where(\"id\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 4)\n\t})\n}\n\n// Test_Model_LockUpdate tests the LockUpdate convenience method\nfunc Test_Model_LockUpdate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test LockUpdate is equivalent to Lock(\"FOR UPDATE\")\n\t\tone, err := db.Model(table).LockUpdate().Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Test LockUpdate with All()\n\t\tall, err := db.Model(table).LockUpdate().Where(\"id<?\", 4).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[2][\"id\"], 3)\n\n\t\t// Test LockUpdate with Count()\n\t\tcount, err := db.Model(table).LockUpdate().Where(\"id>?\", 5).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 5)\n\t})\n}\n\n// Test_Model_LockUpdateSkipLocked tests the LockUpdateSkipLocked convenience method\n// Note: SKIP LOCKED requires MySQL 8.0+, skipped for compatibility\n// func Test_Model_LockUpdateSkipLocked(t *testing.T) {\n// \ttable := createInitTable()\n// \tdefer dropTable(table)\n//\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\t// Test LockUpdateSkipLocked basic usage\n// \t\tone, err := db.Model(table).LockUpdateSkipLocked().Where(\"id\", 1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"id\"], 1)\n//\n// \t\t// Test LockUpdateSkipLocked with All()\n// \t\tall, err := db.Model(table).LockUpdateSkipLocked().Where(\"id>?\", 7).Order(\"id\").All()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(all), 3)\n// \t})\n// }\n\n// Test_Model_LockShared tests the LockShared convenience method\nfunc Test_Model_LockShared(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test LockShared is equivalent to Lock(\"LOCK IN SHARE MODE\")\n\t\tone, err := db.Model(table).LockShared().Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\n\t\t// Test LockShared with All()\n\t\tall, err := db.Model(table).LockShared().Where(\"id<=?\", 5).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[4][\"id\"], 5)\n\t})\n}\n\n// Test_Model_Lock_WithTransaction tests Lock methods within transaction\nfunc Test_Model_Lock_WithTransaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Lock row for update in transaction\n\t\t\tone, err := tx.Model(table).LockUpdate().Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"id\"], 1)\n\n\t\t\t// Update the locked row\n\t\t\t_, err = tx.Model(table).Data(g.Map{\"nickname\": \"updated_name\"}).Where(\"id\", 1).Update()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Verify update\n\t\t\tupdated, err := tx.Model(table).Where(\"id\", 1).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(updated[\"nickname\"], \"updated_name\")\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify transaction committed successfully\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"updated_name\")\n\t})\n}\n\n// Test_Model_Lock_ReleaseAfterCommit tests lock is released after transaction commit\nfunc Test_Model_Lock_ReleaseAfterCommit(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Start transaction and lock a row\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tone, err := tx.Model(table).LockUpdate().Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\n\t\t// Update within transaction\n\t\t_, err = tx.Model(table).Data(g.Map{\"nickname\": \"tx_update\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Commit transaction - this should release the lock\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Another query should succeed without blocking\n\t\tone, err = db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"tx_update\")\n\t})\n}\n\n// Test_Model_Lock_ReleaseAfterRollback tests lock is released after transaction rollback\nfunc Test_Model_Lock_ReleaseAfterRollback(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Start transaction and lock a row\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tone, err := tx.Model(table).LockUpdate().Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\n\t\t// Update within transaction\n\t\t_, err = tx.Model(table).Data(g.Map{\"nickname\": \"rollback_update\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Rollback transaction - this should release the lock and discard changes\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// Verify original value is preserved\n\t\tone, err = db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\n// Test_Model_Lock_ChainedMethods tests Lock with other chained methods\nfunc Test_Model_Lock_ChainedMethods(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Lock with Fields\n\t\tone, err := db.Model(table).Fields(\"id,passport\").LockUpdate().Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 1)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\t// Lock with Order and Limit\n\t\tall, err := db.Model(table).LockShared().Where(\"id>?\", 5).Order(\"id desc\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], 10)\n\t\tt.Assert(all[2][\"id\"], 8)\n\n\t\t// Lock with Group and Having\n\t\tall, err = db.Model(table).Fields(\"LEFT(passport,4) as prefix, COUNT(*) as cnt\").\n\t\t\tLockUpdate().\n\t\t\tGroup(\"prefix\").\n\t\t\tHaving(\"cnt>?\", 0).\n\t\t\tOrder(\"prefix\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"prefix\"], \"user\")\n\t\tt.Assert(all[0][\"cnt\"], 10)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_master_slave_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Master_Slave(t *testing.T) {\n\tvar err error\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `master` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `slave` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t})\n\tdefer func() {\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `master`\")\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `slave`\")\n\t}()\n\tvar (\n\t\tconfigKey   = guid.S()\n\t\tconfigGroup = gdb.ConfigGroup{\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"master\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"master\",\n\t\t\t\tDebug:  true,\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"slave\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"slave\",\n\t\t\t\tDebug:  true,\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t}\n\t)\n\tgdb.SetConfigGroup(configKey, configGroup)\n\tmasterSlaveDB := g.DB(configKey)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"table_\" + guid.S()\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\n\t\t// Data insert to master.\n\t\tarray := garray.New(true)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t\t})\n\t\t}\n\t\t_, err = masterSlaveDB.Model(table).Data(array).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvar count int\n\t\t// Auto slave.\n\t\tcount, err = masterSlaveDB.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// slave.\n\t\tcount, err = masterSlaveDB.Model(table).Slave().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// master.\n\t\tcount, err = masterSlaveDB.Model(table).Master().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\n// Test_Master_Slave_Concurrent_ReadWrite tests concurrent read/write routing\nfunc Test_Master_Slave_Concurrent_ReadWrite(t *testing.T) {\n\tvar err error\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `master` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `slave` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t})\n\tdefer func() {\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `master`\")\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `slave`\")\n\t}()\n\n\tvar (\n\t\tconfigKey   = guid.S()\n\t\tconfigGroup = gdb.ConfigGroup{\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"master\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"master\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"slave\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"slave\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t}\n\t)\n\tgdb.SetConfigGroup(configKey, configGroup)\n\tmasterSlaveDB := g.DB(configKey)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"table_\" + guid.S()\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\n\t\tvar wg sync.WaitGroup\n\t\tconcurrency := 10\n\n\t\t// Concurrent writes to master\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(id int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_, err := masterSlaveDB.Model(table).Insert(g.Map{\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"concurrent_%d\", id),\n\t\t\t\t\t\"password\": fmt.Sprintf(\"pass_%d\", id),\n\t\t\t\t\t\"nickname\": fmt.Sprintf(\"name_%d\", id),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\n\t\t// Verify writes went to master\n\t\tcount, err := masterSlaveDB.Model(table).Master().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, concurrency)\n\t})\n}\n\n// Test_Master_Slave_Transaction_Routing tests transaction routing to master\nfunc Test_Master_Slave_Transaction_Routing(t *testing.T) {\n\tvar err error\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `master` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `slave` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t})\n\tdefer func() {\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `master`\")\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `slave`\")\n\t}()\n\n\tvar (\n\t\tconfigKey   = guid.S()\n\t\tconfigGroup = gdb.ConfigGroup{\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"master\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"master\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"slave\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"slave\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t}\n\t)\n\tgdb.SetConfigGroup(configKey, configGroup)\n\tmasterSlaveDB := g.DB(configKey)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"table_\" + guid.S()\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\n\t\t// Transaction should route to master\n\t\terr := masterSlaveDB.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Insert(g.Map{\n\t\t\t\t\"passport\": \"tx_user\",\n\t\t\t\t\"password\": \"tx_pass\",\n\t\t\t\t\"nickname\": \"tx_name\",\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Read within transaction should also use master\n\t\t\tcount, err := tx.Model(table).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, 1)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify data is in master\n\t\tcount, err := masterSlaveDB.Model(table).Master().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test_Master_Slave_Explicit_Selection tests explicit master/slave selection\nfunc Test_Master_Slave_Explicit_Selection(t *testing.T) {\n\tvar err error\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `master` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t\t_, err = db.Exec(ctx, \"CREATE DATABASE IF NOT EXISTS `slave` CHARACTER SET UTF8\")\n\t\tt.AssertNil(err)\n\t})\n\tdefer func() {\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `master`\")\n\t\t_, _ = db.Exec(ctx, \"DROP DATABASE `slave`\")\n\t}()\n\n\tvar (\n\t\tconfigKey   = guid.S()\n\t\tconfigGroup = gdb.ConfigGroup{\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"master\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"master\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t\tgdb.ConfigNode{\n\t\t\t\tHost:   \"127.0.0.1\",\n\t\t\t\tPort:   \"3306\",\n\t\t\t\tUser:   \"root\",\n\t\t\t\tPass:   \"12345678\",\n\t\t\t\tName:   \"slave\",\n\t\t\t\tType:   \"mysql\",\n\t\t\t\tRole:   \"slave\",\n\t\t\t\tWeight: 100,\n\t\t\t},\n\t\t}\n\t)\n\tgdb.SetConfigGroup(configKey, configGroup)\n\tmasterSlaveDB := g.DB(configKey)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"table_\" + guid.S()\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tcreateTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"master\"), table)\n\t\tdefer dropTableWithDb(masterSlaveDB.Schema(\"slave\"), table)\n\n\t\t// Insert to master\n\t\t_, err := masterSlaveDB.Model(table).Master().Insert(g.Map{\n\t\t\t\"passport\": \"explicit_test\",\n\t\t\t\"password\": \"pass\",\n\t\t\t\"nickname\": \"name\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Explicitly read from slave (should be empty)\n\t\tcount, err := masterSlaveDB.Model(table).Slave().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\t// Explicitly read from master (should have data)\n\t\tcount, err = masterSlaveDB.Model(table).Master().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_metadata_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_TableFields_Basic tests basic TableFields functionality\nfunc Test_TableFields_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(fields), 0)\n\n\t\t// Verify common fields exist\n\t\t_, ok := fields[\"id\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = fields[\"passport\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = fields[\"password\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = fields[\"nickname\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = fields[\"create_time\"]\n\t\tt.Assert(ok, true)\n\t})\n}\n\n// Test_TableFields_Schema tests TableFields with explicit schema\nfunc Test_TableFields_Schema(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table, TestSchema1)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(fields), 0)\n\n\t\t// Verify field properties\n\t\tidField, ok := fields[\"id\"]\n\t\tt.Assert(ok, true)\n\t\tt.Assert(idField.Name, \"id\")\n\t\tt.AssertGT(idField.Index, -1)\n\t})\n}\n\n// Test_HasField_Positive tests HasField for existing field\nfunc Test_HasField_Positive(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\thas, err := db.GetCore().HasField(ctx, table, \"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(has, true)\n\n\t\thas, err = db.GetCore().HasField(ctx, table, \"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(has, true)\n\t})\n}\n\n// Test_HasField_Negative tests HasField for non-existent field\nfunc Test_HasField_Negative(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\thas, err := db.GetCore().HasField(ctx, table, \"non_exist_field\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(has, false)\n\t})\n}\n\n// Test_HasField_Schema tests HasField with explicit schema\nfunc Test_HasField_Schema(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\thas, err := db.GetCore().HasField(ctx, table, \"id\", TestSchema1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(has, true)\n\t})\n}\n\n// Test_QuoteWord_Basic tests basic QuoteWord functionality\nfunc Test_QuoteWord_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tquoted := db.GetCore().QuoteWord(\"user\")\n\t\tt.Assert(quoted, \"`user`\")\n\n\t\tquoted = db.GetCore().QuoteWord(\"user_table\")\n\t\tt.Assert(quoted, \"`user_table`\")\n\t})\n}\n\n// Test_QuoteWord_AlreadyQuoted tests QuoteWord with already quoted words\nfunc Test_QuoteWord_AlreadyQuoted(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// If already quoted, should not double quote\n\t\tquoted := db.GetCore().QuoteWord(\"`user`\")\n\t\tt.Assert(quoted, \"`user`\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_builder_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Model_Builder(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where And\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n\n\t// Where Or\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where with struct which has a field type of *gtime.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=? AND `nickname` IS NULL\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with struct which has a field type of *gjson.Json\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=? AND `nickname` IS NULL\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gtime.Time and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=?\")\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gjson.Json and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, \"`id`=?\")\n\t\tt.Assert(args, []any{1})\n\t})\n}\n\nfunc Test_Safe_Builder(t *testing.T) {\n\t// test whether m.Builder() is chain safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := db.Model().Builder()\n\t\tb.Where(\"id\", 1)\n\t\t_, args := b.Build()\n\t\tt.AssertNil(args)\n\n\t\tb = b.Where(\"id\", 1)\n\t\t_, args = b.Build()\n\t\tt.Assert(args, g.Slice{1})\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_do_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Insert_Data_DO(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_DO(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `2`)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Update_Pointer_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype NN string\n\t\ttype Req struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t\tPassword *string\n\t\t\tNickname *NN\n\t\t}\n\t\ttype UserDo struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tvar (\n\t\t\tnickname = NN(\"nickname_111\")\n\t\t\treq      = Req{\n\t\t\t\tPassword: gconv.PtrString(\"12345678\"),\n\t\t\t\tNickname: &nickname,\n\t\t\t}\n\t\t\tdata = UserDo{\n\t\t\t\tPassport: req.Passport,\n\t\t\t\tPassword: req.Password,\n\t\t\t\tNickname: req.Nickname,\n\t\t\t}\n\t\t)\n\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`password`], `12345678`)\n\t\tt.Assert(one[`nickname`], `nickname_111`)\n\t})\n}\n\nfunc Test_Model_Where_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Insert_Data_ForDao(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_ForDao(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUserForDao{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUserForDao{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `2`)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_FieldPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n\t// With omitempty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id,omitempty\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id,omitempty\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_join_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_LeftJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_RightJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_InnerJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_LeftJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_RightJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_InnerJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_FieldsPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"id\").\n\t\t\tFieldsPrefix(table2, \"nickname\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t})\n}\n\n// Test_Model_Join_FiveTables tests complex join with 5+ tables\nfunc Test_Model_Join_FiveTables(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t\ttable3 = gtime.TimestampNanoStr() + \"_table3\"\n\t\ttable4 = gtime.TimestampNanoStr() + \"_table4\"\n\t\ttable5 = gtime.TimestampNanoStr() + \"_table5\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\tcreateInitTable(table3)\n\tdefer dropTable(table3)\n\tcreateInitTable(table4)\n\tdefer dropTable(table4)\n\tcreateInitTable(table5)\n\tdefer dropTable(table5)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tFieldsPrefix(\"t2\", \"passport\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tInnerJoin(table3+\" AS t3\", \"t2.id = t3.id\").\n\t\t\tInnerJoin(table4+\" AS t4\", \"t3.id = t4.id\").\n\t\t\tInnerJoin(table5+\" AS t5\", \"t4.id = t5.id\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 6 tables with mixed join types\n\t\ttable6 := gtime.TimestampNanoStr() + \"_table6\"\n\t\tcreateInitTable(table6)\n\t\tdefer dropTable(table6)\n\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tLeftJoin(table3+\" AS t3\", \"t2.id = t3.id\").\n\t\t\tInnerJoin(table4+\" AS t4\", \"t3.id = t4.id\").\n\t\t\tRightJoin(table5+\" AS t5\", \"t4.id = t5.id\").\n\t\t\tLeftJoin(table6+\" AS t6\", \"t5.id = t6.id\").\n\t\t\tWhere(\"t1.id\", 5).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], \"5\")\n\t})\n}\n\n// Test_Model_Join_SelfJoin tests self-join scenarios\nfunc Test_Model_Join_SelfJoin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Self-join to find pairs where a.id < b.id\n\t\tr, err := db.Model(table).As(\"a\").\n\t\t\tFields(\"a.id AS a_id\", \"b.id AS b_id\").\n\t\t\tInnerJoin(table+\" AS b\", \"a.id < b.id\").\n\t\t\tWhere(\"a.id\", 1).\n\t\t\tWhere(\"b.id <=\", 3).\n\t\t\tOrder(\"b.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"a_id\"], \"1\")\n\t\tt.Assert(r[0][\"b_id\"], \"2\")\n\t\tt.Assert(r[1][\"b_id\"], \"3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Self-join with multiple conditions\n\t\tr, err := db.Model(table).As(\"a\").\n\t\t\tFields(\"a.id\", \"a.nickname\", \"b.nickname AS other_nickname\").\n\t\t\tLeftJoin(table+\" AS b\", \"a.id = b.id - 1\").\n\t\t\tWhere(\"a.id IN(?)\", g.Slice{1, 2}).\n\t\t\tOrder(\"a.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"other_nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"other_nickname\"], \"name_3\")\n\t})\n}\n\n// Test_Model_Join_LeftJoinNull tests LEFT JOIN NULL handling\nfunc Test_Model_Join_LeftJoinNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\n\t// Create table2 with only partial data\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, err := db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// LEFT JOIN - table1 has all records, table2 only has id 1,2\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\") // matched\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\") // matched\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t\t// r[2][\"nickname\"] should be NULL/empty from t2\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Find records where RIGHT table is NULL\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id IS NULL\").\n\t\t\tWhere(\"t1.id IN(?)\", g.Slice{1, 2, 3, 4}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should return id 3,4 (not in table2)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[1][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_Join_RightJoinNull tests RIGHT JOIN NULL handling\nfunc Test_Model_Join_RightJoinNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\t// table1 has partial data\n\tcreateTable(table1)\n\tdefer dropTable(table1)\n\t_, err := db.Insert(ctx, table1, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// table2 has all data\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// RIGHT JOIN - table1 only has id 1,2, table2 has all\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t2\", \"id\").\n\t\t\tFieldsPrefix(\"t1\", \"nickname\").\n\t\t\tRightJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id IN(?)\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t2.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\") // matched\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\") // matched\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t\t// r[2][\"nickname\"] should be NULL/empty from t1\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Find records where LEFT table is NULL\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t2\", \"id\", \"nickname\").\n\t\t\tRightJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id IS NULL\").\n\t\t\tWhere(\"t2.id IN(?)\", g.Slice{1, 2, 3, 4}).\n\t\t\tOrder(\"t2.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should return id 3,4 (not in table1)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[1][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_Join_OnVsWhere tests difference between ON and WHERE conditions\nfunc Test_Model_Join_OnVsWhere(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// INNER JOIN: ON and WHERE behave the same\n\t\tr1, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id AND t2.id <= 3\").\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tr2, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id <=\", 3).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// For INNER JOIN, results should be identical\n\t\tt.Assert(len(r1), 3)\n\t\tt.Assert(len(r2), 3)\n\t\tt.Assert(r1[0][\"id\"], r2[0][\"id\"])\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// LEFT JOIN: ON filter in join condition vs WHERE filter after join\n\t\t// ON condition: filters t2 before join (keeps all t1 rows)\n\t\tr1, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id AND t2.id <= 2\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// WHERE condition: filters result after join (removes t1 rows where t2 is NULL)\n\t\tr2, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tFieldsPrefix(\"t2\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tWhere(\"t2.id <=\", 2).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// r1: all t1 rows (1,2,3,4), t2 data only for id 1,2\n\t\tt.Assert(len(r1), 4)\n\t\tt.Assert(r1[0][\"id\"], \"1\")\n\t\tt.Assert(r1[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r1[2][\"id\"], \"3\")\n\t\t// r1[2][\"nickname\"] is NULL from t2\n\n\t\t// r2: only rows where t2.id <= 2, so only id 1,2\n\t\tt.Assert(len(r2), 2)\n\t\tt.Assert(r2[0][\"id\"], \"1\")\n\t\tt.Assert(r2[1][\"id\"], \"2\")\n\t})\n}\n\n// Test_Model_Join_ComplexConditions tests joins with complex ON conditions\nfunc Test_Model_Join_ComplexConditions(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple AND conditions in ON clause\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\", \"t1.nickname\").\n\t\t\tInnerJoin(\n\t\t\t\ttable2+\" AS t2\",\n\t\t\t\t\"t1.id = t2.id AND t1.nickname = t2.nickname AND t1.id BETWEEN 2 AND 4\",\n\t\t\t).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OR conditions in ON clause (need to use Where for OR in join)\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFields(\"t1.id\").\n\t\t\tInnerJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhere(\"t2.id = 1 OR t2.id = 5\").\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"5\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_sharding_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTestDbNameSh0 = \"test_0\"\n\tTestDbNameSh1 = \"test_1\"\n\tTestTableName = \"user\"\n)\n\ntype ShardingUser struct {\n\tId   int\n\tName string\n}\n\n// createShardingDatabase creates test databases and tables for sharding\nfunc createShardingDatabase(t *gtest.T) {\n\t// Create databases\n\tdbs := []string{TestDbNameSh0, TestDbNameSh1}\n\tfor _, dbName := range dbs {\n\t\tsql := fmt.Sprintf(\"CREATE DATABASE IF NOT EXISTS `%s`\", dbName)\n\t\t_, err := db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\n\t\t// Switch to the database\n\t\tsql = fmt.Sprintf(\"USE `%s`\", dbName)\n\t\t_, err = db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\n\t\t// Create tables\n\t\ttables := []string{\"user_0\", \"user_1\", \"user_2\", \"user_3\"}\n\t\tfor _, table := range tables {\n\t\t\tsql := fmt.Sprintf(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\t\t\tid int(11) NOT NULL,\n\t\t\t\t\tname varchar(255) NOT NULL,\n\t\t\t\t\tPRIMARY KEY (id)\n\t\t\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\t\t\t`, table)\n\t\t\t_, err := db.Exec(ctx, sql)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t}\n}\n\n// dropShardingDatabase drops test databases\nfunc dropShardingDatabase(t *gtest.T) {\n\tdbs := []string{TestDbNameSh0, TestDbNameSh1}\n\tfor _, dbName := range dbs {\n\t\tsql := fmt.Sprintf(\"DROP DATABASE IF EXISTS `%s`\", dbName)\n\t\t_, err := db.Exec(ctx, sql)\n\t\tt.AssertNil(err)\n\t}\n}\n\nfunc Test_Sharding_Basic(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttablePrefix  = \"user_\"\n\t\t\tschemaPrefix = \"test_\"\n\t\t)\n\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\t// Create sharding configuration\n\t\tshardingConfig := gdb.ShardingConfig{\n\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: tablePrefix,\n\t\t\t\tRule: &gdb.DefaultShardingRule{\n\t\t\t\t\tTableCount: 4,\n\t\t\t\t},\n\t\t\t},\n\t\t\tSchema: gdb.ShardingSchemaConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: schemaPrefix,\n\t\t\t\tRule: &gdb.DefaultShardingRule{\n\t\t\t\t\tSchemaCount: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// Prepare test data\n\t\tuser := ShardingUser{\n\t\t\tId:   1,\n\t\t\tName: \"John\",\n\t\t}\n\n\t\tmodel := db.Model(TestTableName).\n\t\t\tSharding(shardingConfig).\n\t\t\tShardingValue(user.Id).\n\t\t\tSafe()\n\n\t\t// Test Insert\n\t\t_, err := model.Data(user).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test Select\n\t\tvar result ShardingUser\n\t\terr = model.Where(\"id\", user.Id).Scan(&result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.Id, user.Id)\n\t\tt.Assert(result.Name, user.Name)\n\n\t\t// Test Update\n\t\t_, err = model.Data(g.Map{\"name\": \"John Doe\"}).\n\t\t\tWhere(\"id\", user.Id).\n\t\t\tUpdate()\n\t\tt.AssertNil(err)\n\n\t\t// Verify Update\n\t\terr = model.Where(\"id\", user.Id).Scan(&result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.Name, \"John Doe\")\n\n\t\t// Test Delete\n\t\t_, err = model.Where(\"id\", user.Id).Delete()\n\t\tt.AssertNil(err)\n\n\t\t// Verify Delete\n\t\tcount, err := model.Where(\"id\", user.Id).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Sharding_Error tests error cases\nfunc Test_Sharding_Error(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\t// Test missing sharding value\n\t\tmodel := db.Model(TestTableName).\n\t\t\tSharding(gdb.ShardingConfig{\n\t\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\t\tEnable: true,\n\t\t\t\t\tPrefix: \"user_\",\n\t\t\t\t\tRule:   &gdb.DefaultShardingRule{TableCount: 4},\n\t\t\t\t},\n\t\t\t}).Safe()\n\n\t\t_, err := model.Insert(g.Map{\"id\": 1, \"name\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"sharding value is required when sharding feature enabled\")\n\n\t\t// Test missing sharding rule\n\t\tmodel = db.Model(TestTableName).\n\t\t\tSharding(gdb.ShardingConfig{\n\t\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\t\tEnable: true,\n\t\t\t\t\tPrefix: \"user_\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tShardingValue(1)\n\n\t\t_, err = model.Insert(g.Map{\"id\": 1, \"name\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"sharding rule is required when sharding feature enabled\")\n\t})\n}\n\n// Test_Sharding_Complex tests complex sharding scenarios\nfunc Test_Sharding_Complex(t *testing.T) {\n\treturn\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create test databases and tables\n\t\tcreateShardingDatabase(t)\n\t\tdefer dropShardingDatabase(t)\n\n\t\tshardingConfig := gdb.ShardingConfig{\n\t\t\tTable: gdb.ShardingTableConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: \"user_\",\n\t\t\t\tRule:   &gdb.DefaultShardingRule{TableCount: 4},\n\t\t\t},\n\t\t\tSchema: gdb.ShardingSchemaConfig{\n\t\t\t\tEnable: true,\n\t\t\t\tPrefix: \"test_\",\n\t\t\t\tRule:   &gdb.DefaultShardingRule{SchemaCount: 2},\n\t\t\t},\n\t\t}\n\n\t\tusers := []ShardingUser{\n\t\t\t{Id: 1, Name: \"User1\"},\n\t\t\t{Id: 2, Name: \"User2\"},\n\t\t\t{Id: 3, Name: \"User3\"},\n\t\t}\n\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\t_, err := model.Data(user).Insert()\n\t\t\tt.AssertNil(err)\n\t\t}\n\n\t\t// Test batch query\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\tvar result ShardingUser\n\t\t\terr := model.Where(\"id\", user.Id).Scan(&result)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result.Id, user.Id)\n\t\t\tt.Assert(result.Name, user.Name)\n\t\t}\n\n\t\t// Clean up\n\t\tfor _, user := range users {\n\t\t\tmodel := db.Model(TestTableName).\n\t\t\t\tSharding(shardingConfig).\n\t\t\t\tShardingValue(user.Id).\n\t\t\t\tSafe()\n\n\t\t\t_, err := model.Where(\"id\", user.Id).Delete()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n\nfunc Test_Model_Sharding_Table_Using_Hook(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateTable(table1)\n\tdefer dropTable(table1)\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\n\tshardingModel := db.Model(table1).Hook(gdb.HookHandler{\n\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\tin.Table = table2\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, 1),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, 1),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, 1),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Data(g.Map{\n\t\t\t\"passport\": fmt.Sprintf(`user_%d`, 2),\n\t\t\t\"password\": fmt.Sprintf(`pass_%d`, 2),\n\t\t\t\"nickname\": fmt.Sprintf(`name_%d`, 2),\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar (\n\t\t\tcount int\n\t\t\twhere = g.Map{\"passport\": fmt.Sprintf(`user_%d`, 2)}\n\t\t)\n\t\tcount, err = shardingModel.Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table1).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Delete()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_Model_Sharding_Schema_Using_Hook(t *testing.T) {\n\tvar (\n\t\ttable = gtime.TimestampNanoStr() + \"_table\"\n\t)\n\tcreateTableWithDb(db, table)\n\tdefer dropTableWithDb(db, table)\n\tcreateTableWithDb(db2, table)\n\tdefer dropTableWithDb(db2, table)\n\n\tshardingModel := db.Model(table).Hook(gdb.HookHandler{\n\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\tin.Table = table\n\t\t\tin.Schema = db2.GetSchema()\n\t\t\treturn in.Next(ctx)\n\t\t},\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, 1),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, 1),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, 1),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Data(g.Map{\n\t\t\t\"passport\": fmt.Sprintf(`user_%d`, 2),\n\t\t\t\"password\": fmt.Sprintf(`pass_%d`, 2),\n\t\t\t\"nickname\": fmt.Sprintf(`name_%d`, 2),\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar (\n\t\t\tcount int\n\t\t\twhere = g.Map{\"passport\": fmt.Sprintf(`user_%d`, 2)}\n\t\t)\n\t\tcount, err = shardingModel.Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\tcount, err = db.Model(table).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Where(where).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := shardingModel.Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Delete()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tvar count int\n\t\tcount, err = shardingModel.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tcount, err = db2.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Embedded_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int    `json:\"id\"`\n\t\t\tUid        int    `json:\"uid\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tUid:        100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=100\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"john-test\")\n\t})\n}\n\nfunc Test_Model_Embedded_MapToStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Ids struct {\n\t\t\tId  int `json:\"id\"`\n\t\t\tUid int `json:\"uid\"`\n\t\t}\n\t\ttype Base struct {\n\t\t\tIds\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          100,\n\t\t\t\"uid\":         101,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\n\t\tt.Assert(one.Struct(user), nil)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t\tt.Assert(user.Password, data[\"password\"])\n\t\tt.Assert(user.Nickname, data[\"nickname\"])\n\t\tt.Assert(user.CreateTime, data[\"create_time\"])\n\t})\n}\n\nfunc Test_Struct_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tuser := new(User)\n\t\terr = one.Struct(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Scan(user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Scan(&user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Structs_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\t// All\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]*User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Struct_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=100\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t\tt.AssertNE(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\t\tvar user *User\n\t\tt.Assert(one.Struct(&user), nil)\n\t\tt.Assert(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\nfunc Test_Structs_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []*User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n}\n\ntype MyTime struct {\n\tgtime.Time\n}\n\ntype MyTimeSt struct {\n\tCreateTime MyTime\n}\n\nfunc (st *MyTimeSt) UnmarshalValue(v any) error {\n\tm := gconv.Map(v)\n\tt, err := gtime.StrToTime(gconv.String(m[\"create_time\"]))\n\tif err != nil {\n\t\treturn err\n\t}\n\tst.CreateTime = MyTime{*t}\n\treturn nil\n}\n\nfunc Test_Model_Scan_CustomType_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyTimeSt)\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar stSlice []*MyTimeSt\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(&stSlice)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(stSlice), TableSize)\n\t\tt.Assert(stSlice[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\tt.Assert(stSlice[9].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_Model_Scan_CustomType_String(t *testing.T) {\n\ttype MyString string\n\n\ttype MyStringSt struct {\n\t\tPassport MyString\n\t}\n\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyStringSt)\n\t\terr := db.Model(table).Fields(\"Passport\").WherePri(1).Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.Passport, \"user_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar sts []MyStringSt\n\t\terr := db.Model(table).Fields(\"Passport\").Order(\"id asc\").Scan(&sts)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(sts), TableSize)\n\t\tt.Assert(sts[0].Passport, \"user_1\")\n\t})\n}\n\ntype User struct {\n\tId         int\n\tPassport   string\n\tPassword   string\n\tNickname   string\n\tCreateTime *gtime.Time\n}\n\nfunc (user *User) UnmarshalValue(value any) error {\n\tif record, ok := value.(gdb.Record); ok {\n\t\t*user = User{\n\t\t\tId:         record[\"id\"].Int(),\n\t\t\tPassport:   record[\"passport\"].String(),\n\t\t\tPassword:   \"\",\n\t\t\tNickname:   record[\"nickname\"].String(),\n\t\t\tCreateTime: record[\"create_time\"].GTime(),\n\t\t}\n\t\treturn nil\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value))\n}\n\nfunc Test_Model_Scan_UnmarshalValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Scan_Map(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Scan_AutoFilteringByStructAttributes(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_model_subquery_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_SubQuery_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).Having(\n\t\t\t\"id > ?\",\n\t\t\tdb.Model(table).Fields(\"MAX(id)\").Where(\"id\", g.Slice{1, 3}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery1 := db.Model(table).Where(\"id\", g.Slice{1, 3, 5})\n\t\tsubQuery2 := db.Model(table).Where(\"id\", g.Slice{5, 7, 9})\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).Fields(\"a.id\").Where(\"a.id=b.id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\n// Test_Model_SubQuery_Correlated tests scalar subquery and correlated subquery with EXISTS\nfunc Test_Model_SubQuery_Correlated(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Scalar subquery: find users whose id is greater than average id\n\t\tsubQuery := db.Model(table + \" AS inner_table\").Fields(\"AVG(id)\")\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id > (?)\",\n\t\t\tsubQuery,\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\t// Average of 1-10 is 5.5, so expect ids 6-10\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[4][\"id\"], 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Correlated subquery with EXISTS: find users with id matching their own id\n\t\tr, err := db.Model(table+\" AS outer_table\").\n\t\t\tWhere(\n\t\t\t\tfmt.Sprintf(\"EXISTS (SELECT 1 FROM %s AS inner_table WHERE inner_table.id = outer_table.id AND inner_table.id <= ?)\", table),\n\t\t\t\t3,\n\t\t\t).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[2][\"id\"], 3)\n\t})\n}\n\n// Test_Model_SubQuery_From tests subquery in FROM clause\nfunc Test_Model_SubQuery_From(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery in FROM clause\n\t\tsubQuery := db.Model(table).Where(\"id <=\", 5)\n\t\tr, err := db.Model(\"(?) AS sub\", subQuery).\n\t\t\tFields(\"sub.id\", \"sub.nickname\").\n\t\t\tWhere(\"sub.id >\", 2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple subqueries in FROM clause with JOIN\n\t\tsubQuery1 := db.Model(table).Fields(\"id\", \"nickname\").Where(\"id <=\", 3)\n\t\tsubQuery2 := db.Model(table).Fields(\"id\", \"passport\").Where(\"id >=\", 3)\n\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).\n\t\t\tFields(\"a.id\", \"a.nickname\", \"b.passport\").\n\t\t\tWhere(\"a.id = b.id\").\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[0][\"nickname\"], \"name_3\")\n\t\tt.Assert(r[0][\"passport\"], \"user_3\")\n\t})\n}\n\n// Test_Model_SubQuery_Select tests subquery in SELECT clause\nfunc Test_Model_SubQuery_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery in SELECT clause for scalar value\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id\", \"nickname\", fmt.Sprintf(\"(SELECT MAX(id) FROM %s) AS max_id\", table)).\n\t\t\tWhere(\"id\", 1).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 1)\n\t\tt.Assert(r[\"nickname\"], \"name_1\")\n\t\tt.Assert(r[\"max_id\"], 10)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple subqueries in SELECT clause\n\t\tr, err := db.Model(table).\n\t\t\tFields(\n\t\t\t\t\"id\",\n\t\t\t\tfmt.Sprintf(\"(SELECT MAX(id) FROM %s) AS max_id\", table),\n\t\t\t\tfmt.Sprintf(\"(SELECT MIN(id) FROM %s) AS min_id\", table),\n\t\t\t).\n\t\t\tWhere(\"id\", 5).\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 5)\n\t\tt.Assert(r[\"max_id\"], 10)\n\t\tt.Assert(r[\"min_id\"], 1)\n\t})\n}\n\n// Test_Model_SubQuery_Nested tests multi-level nested subqueries (3+ levels)\nfunc Test_Model_SubQuery_Nested(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 3-level nested subquery\n\t\t// Level 3: innermost - get ids <= 8\n\t\tlevel3 := db.Model(table).Fields(\"id\").Where(\"id <=\", 8)\n\n\t\t// Level 2: middle - filter from level 3 where id >= 3\n\t\tlevel2 := db.Model(\"(?) AS l3\", level3).Fields(\"l3.id\").Where(\"l3.id >=\", 3)\n\n\t\t// Level 1: outermost - filter from level 2 where id <= 6\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN (?)\", level2).\n\t\t\tWhere(\"id <=\", 6).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[3][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 4-level nested subquery with aggregates\n\t\t// Level 4: get all ids\n\t\tlevel4 := db.Model(table).Fields(\"id\")\n\n\t\t// Level 3: get ids > 5 from level 4\n\t\tlevel3 := db.Model(\"(?) AS l4\", level4).Fields(\"l4.id\").Where(\"l4.id >\", 5)\n\n\t\t// Level 2: get MIN(id) from level 3\n\t\tlevel2 := db.Model(\"(?) AS l3\", level3).Fields(\"MIN(l3.id)\")\n\n\t\t// Level 1: find records >= the minimum from level 2\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id >= (?)\", level2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// MIN(id) from level 3 should be 6, so expect ids 6-10\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[4][\"id\"], 10)\n\t})\n}\n\n// Test_Model_SubQuery_WhereIn tests subquery with WHERE IN\nfunc Test_Model_SubQuery_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Simple WHERE IN with subquery\n\t\tsubQuery := db.Model(table).Fields(\"id\").Where(\"id IN(?)\", g.Slice{2, 4, 6})\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN(?)\", subQuery).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 2)\n\t\tt.Assert(r[1][\"id\"], 4)\n\t\tt.Assert(r[2][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple WHERE IN subqueries combined\n\t\tsubQuery1 := db.Model(table).Fields(\"id\").Where(\"id <=\", 5)\n\t\tsubQuery2 := db.Model(table).Fields(\"id\").Where(\"id >=\", 3)\n\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id IN(?)\", subQuery1).\n\t\t\tWhere(\"id IN(?)\", subQuery2).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\n// Test_Model_SubQuery_Complex tests complex subquery combinations\nfunc Test_Model_SubQuery_Complex(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Combine subquery in WHERE, FROM, and SELECT\n\t\twhereSubQuery := db.Model(table).Fields(\"AVG(id)\")\n\t\tfromSubQuery := db.Model(table).Where(\"id <=\", 7)\n\n\t\tr, err := db.Model(\"(?) AS sub\", fromSubQuery).\n\t\t\tFields(\"sub.id\", \"sub.nickname\").\n\t\t\tWhere(\"sub.id > (?)\", whereSubQuery).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// AVG(1-10) = 5.5, filter sub.id > 5.5 from ids 1-7\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 6)\n\t\tt.Assert(r[1][\"id\"], 7)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Subquery with GROUP BY and HAVING\n\t\tsubQuery := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >=\", 3)\n\n\t\tr, err := db.Model(table).\n\t\t\tWhere(\"id % 3 IN(?)\", db.Model(\"(?) AS sub\", subQuery).Fields(\"sub.mod_group\")).\n\t\t\tOrderAsc(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// id % 3: 0(3,6,9), 1(1,4,7,10), 2(2,5,8)\n\t\t// Groups with count >= 3: 0(3 items), 1(4 items), 2(3 items) - all qualify\n\t\tt.Assert(len(r), 10)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_omit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Model_OmitEmpty_Comprehensive tests OmitEmpty filtering for both data and where parameters\nfunc Test_Model_OmitEmpty_Comprehensive(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmpty with empty string in Data\n\t\tresult, err := db.Model(table).OmitEmpty().Data(g.Map{\n\t\t\t\"nickname\": \"\",         // empty string should be omitted\n\t\t\t\"passport\": \"new_user\", // non-empty should be kept\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\") // original value preserved\n\t\tt.Assert(one[\"passport\"], \"new_user\")\n\n\t\t// Test OmitEmpty with empty slice in Where\n\t\tall, err := db.Model(table).OmitEmpty().Where(g.Map{\n\t\t\t\"id\":       []int{}, // empty slice should be omitted\n\t\t\t\"passport\": \"new_user\",\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\n\t\t// Without OmitEmpty, empty slice causes WHERE 0=1\n\t\tall, err = db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0) // no results due to WHERE 0=1\n\t})\n}\n\n// Test_Model_OmitEmptyWhere_Extended tests OmitEmpty filtering only for where parameters\nfunc Test_Model_OmitEmptyWhere_Extended(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitEmptyWhere only affects Where, not Data\n\t\tresult, err := db.Model(table).OmitEmptyWhere().Data(g.Map{\n\t\t\t\"nickname\": \"\", // empty string in Data should NOT be omitted (only Where is affected)\n\t\t}).Where(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"\", // empty string in Where should be omitted\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was updated to empty (Data is not affected by OmitEmptyWhere)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"\")\n\n\t\t// Test with empty slice in Where\n\t\tall, err := db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id\": []int{}, // should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // returns results because empty condition was omitted\n\n\t\t// Test with zero value in Where (zero is considered empty)\n\t\tall, err = db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id\": 0, // zero should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\n// Test_Model_OmitEmptyData tests OmitEmpty filtering only for data parameters\nfunc Test_Model_OmitEmptyData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitEmptyData only affects Data, not Where\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"nickname\": \"\",          // empty string in Data should be omitted\n\t\t\t\"passport\": \"test_user\", // non-empty should be kept\n\t\t}).Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted), passport was updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"test_user\")\n\n\t\t// Test Insert with OmitEmptyData\n\t\tresult, err = db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       100,\n\t\t\t\"passport\": \"user_100\",\n\t\t\t\"nickname\": \"\", // should be omitted\n\t\t\t\"password\": \"pass_100\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname is NULL (was omitted from INSERT)\n\t\tone, err = db.Model(table).Where(\"id\", 100).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_100\")\n\t\tt.Assert(one[\"nickname\"].IsNil(), true)\n\t})\n}\n\n// Test_Model_OmitNil_Comprehensive tests OmitNil filtering for both data and where parameters\nfunc Test_Model_OmitNil_Comprehensive(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitNil with nil value in Data\n\t\tresult, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"nickname\": nil,        // nil should be omitted\n\t\t\t\"passport\": \"nil_test\", // non-nil should be kept\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"nil_test\")\n\n\t\t// Test OmitNil with nil in Where\n\t\tall, err := db.Model(table).OmitNil().Where(g.Map{\n\t\t\t\"passport\": nil, // nil should be omitted\n\t\t}).Order(\"id\").Limit(5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // returns results because nil condition was omitted\n\n\t\t// Without OmitNil, WHERE passport=NULL (which won't match anything)\n\t\tall, err = db.Model(table).Where(g.Map{\n\t\t\t\"passport\": nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0) // NULL comparison doesn't match\n\t})\n}\n\n// Test_Model_OmitNilWhere tests OmitNil filtering only for where parameters\nfunc Test_Model_OmitNilWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitNilWhere only affects Where, not Data\n\t\tresult, err := db.Model(table).OmitNilWhere().Data(g.Map{\n\t\t\t\"nickname\": nil, // nil in Data should NOT be omitted (only Where is affected)\n\t\t}).Where(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": nil, // nil in Where should be omitted\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was set to NULL (Data is not affected by OmitNilWhere)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"].IsNil(), true)\n\n\t\t// Test with nil in Where\n\t\tall, err := db.Model(table).OmitNilWhere().Where(g.Map{\n\t\t\t\"passport\": nil, // should be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3) // returns results\n\t})\n}\n\n// Test_Model_OmitNilData tests OmitNil filtering only for data parameters\nfunc Test_Model_OmitNilData(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// OmitNilData only affects Data, not Where\n\t\tresult, err := db.Model(table).OmitNilData().Data(g.Map{\n\t\t\t\"nickname\": nil,            // nil in Data should be omitted\n\t\t\t\"passport\": \"omitnil_test\", // non-nil should be kept\n\t\t}).Where(g.Map{\n\t\t\t\"id\": 1,\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated (omitted), passport was updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"omitnil_test\")\n\n\t\t// Test Insert with OmitNilData\n\t\tresult, err = db.Model(table).OmitNilData().Data(g.Map{\n\t\t\t\"id\":       101,\n\t\t\t\"passport\": \"user_101\",\n\t\t\t\"nickname\": nil, // should be omitted\n\t\t\t\"password\": \"pass_101\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify insert\n\t\tone, err = db.Model(table).Where(\"id\", 101).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_101\")\n\t})\n}\n\n// Test_Model_OmitEmpty_WithStruct tests OmitEmpty with struct data\nfunc Test_Model_OmitEmpty_WithStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tNickname string\n\t\tPassword string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyData with struct\n\t\tuser := User{\n\t\t\tPassport: \"struct_user\",\n\t\t\tNickname: \"\", // empty, should be omitted\n\t\t\tPassword: \"struct_pass\",\n\t\t}\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(user).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify nickname was not updated\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t\tt.Assert(one[\"passport\"], \"struct_user\")\n\t})\n}\n\n// Test_Model_OmitNil_WithPointerStruct tests OmitNil with pointer struct data\nfunc Test_Model_OmitNil_WithPointerStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport *string\n\t\tNickname *string\n\t\tPassword string\n\t}\n\n\t// Note: Removed OmitNilData with pointer struct test due to framework limitations\n\t// Struct field nil pointer handling needs further investigation\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitNilData with Map (working as expected)\n\t\tsqlArray2, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\t_, err := db.Ctx(ctx).Model(table).OmitNilData().Data(g.Map{\n\t\t\t\t\"passport\": \"map_user\",\n\t\t\t\t\"nickname\": nil,\n\t\t\t\t\"password\": \"map_pass\",\n\t\t\t}).Where(\"id\", 2).Update()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Logf(\"Map SQL: %v\", sqlArray2)\n\n\t\tone2, err := db.Model(table).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Logf(\"Map result - nickname: %v, passport: %v\", one2[\"nickname\"], one2[\"passport\"])\n\t\tt.Assert(one2[\"nickname\"], \"name_2\") // should be preserved\n\t\tt.Assert(one2[\"passport\"], \"map_user\")\n\t})\n}\n\n// Test_Model_OmitEmpty_ZeroValues tests OmitEmpty with various zero values\nfunc Test_Model_OmitEmpty_ZeroValues(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyData with various zero values\n\t\tresult, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       0,           // zero int, should be omitted\n\t\t\t\"passport\": \"zero_test\", // non-empty\n\t\t\t\"nickname\": \"\",          // empty string, should be omitted\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the insert (id should be auto-generated since 0 was omitted)\n\t\tone, err := db.Model(table).Where(\"passport\", \"zero_test\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"zero_test\")\n\t\tt.AssertNE(one[\"id\"], 0) // auto-generated id\n\t})\n}\n\n// Test_Model_OmitEmpty_ComplexWhere tests OmitEmpty with complex where conditions\nfunc Test_Model_OmitEmpty_ComplexWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmptyWhere with multiple conditions\n\t\tall, err := db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"id >\":     0,   // zero, should be omitted\n\t\t\t\"passport\": \"\",  // empty string, should be omitted\n\t\t\t\"nickname\": \"?\", // placeholder, should NOT be omitted\n\t\t}).Order(\"id\").Limit(3).All()\n\t\tt.AssertNil(err)\n\t\t// Should execute query with only the nickname condition\n\n\t\t// Test with all empty conditions\n\t\tall, err = db.Model(table).OmitEmptyWhere().Where(g.Map{\n\t\t\t\"passport\": \"\",\n\t\t\t\"nickname\": \"\",\n\t\t}).Order(\"id\").Limit(5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // all conditions omitted, returns all (limited to 5)\n\t})\n}\n\n// Test_Model_Omit_ChainedMethods tests Omit methods with other chained methods\nfunc Test_Model_Omit_ChainedMethods(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test OmitEmpty with Fields and Order\n\t\tresult, err := db.Model(table).\n\t\t\tOmitEmptyData().\n\t\t\tFields(\"passport\", \"nickname\").\n\t\t\tData(g.Map{\n\t\t\t\t\"passport\": \"chain_test\",\n\t\t\t\t\"nickname\": \"\",\n\t\t\t}).\n\t\t\tWhere(\"id\", 1).\n\t\t\tUpdate()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"chain_test\")\n\t\tt.Assert(one[\"nickname\"], \"name_1\") // not updated due to OmitEmptyData\n\n\t\t// Test OmitNilWhere with multiple Where clauses\n\t\tall, err := db.Model(table).\n\t\t\tOmitNilWhere().\n\t\t\tWhere(\"id>?\", 5).\n\t\t\tWhere(g.Map{\n\t\t\t\t\"passport\": nil, // should be omitted\n\t\t\t}).\n\t\t\tOrder(\"id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5) // id 6-10\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_pagination_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Test_Model_AllAndCount_Basic tests basic AllAndCount functionality\nfunc Test_Model_AllAndCount_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_AllAndCount_WithWhere tests AllAndCount with WHERE conditions\nfunc Test_Model_AllAndCount_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id > ?\", 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(count, 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, 3)\n\t})\n}\n\n// Test_Model_AllAndCount_WithPage tests AllAndCount with pagination\nfunc Test_Model_AllAndCount_WithPage(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(1, 3).Order(\"id\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, TableSize) // Count should be total, not page size\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(2, 3).Order(\"id\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(result[0][\"id\"], 4)\n\t})\n}\n\n// Test_Model_AllAndCount_WithFields tests AllAndCount with specific fields\n// Related: https://github.com/gogf/gf/issues/4698\nfunc Test_Model_AllAndCount_WithFields(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result[0]), 2) // Only 2 fields\n\t})\n\n\t// Regression test for #4698: AllAndCount(true) with multiple fields should work correctly\n\t// https://github.com/gogf/gf/issues/4698\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result[0]), 2)\n\t})\n}\n\n// Test_Model_AllAndCount_Empty tests AllAndCount with no results\nfunc Test_Model_AllAndCount_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id > ?\", 1000).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\tt.Assert(count, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id < ?\", 0).AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_AllAndCount_WithCache tests AllAndCount with cache\nfunc Test_Model_AllAndCount_WithCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult1, count1, err := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result1), 5)\n\t\tt.Assert(count1, TableSize)\n\n\t\t// Second call should use cache\n\t\tresult2, count2, err := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result2), 5)\n\t\tt.Assert(count2, count1)\n\t})\n}\n\n// Test_Model_AllAndCount_Distinct tests AllAndCount with DISTINCT\nfunc Test_Model_AllAndCount_Distinct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// Insert duplicate nicknames\n\tfor i := 1; i <= 10; i++ {\n\t\tnickname := \"name_\" + gconv.String((i-1)/2) // Creates duplicates\n\t\tdb.Model(table).Data(g.Map{\n\t\t\t\"id\":       i,\n\t\t\t\"passport\": \"pass_\" + gconv.String(i),\n\t\t\t\"password\": \"pwd\",\n\t\t\t\"nickname\": nickname,\n\t\t}).Insert()\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"DISTINCT nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 5) // 10 records / 2 = 5 distinct nicknames\n\t\tt.Assert(len(result), 5)\n\t})\n}\n\n// Test_Model_ScanAndCount_Basic tests basic ScanAndCount functionality\nfunc Test_Model_ScanAndCount_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithWhere tests ScanAndCount with WHERE conditions\nfunc Test_Model_ScanAndCount_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id <= ?\", 5).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 5)\n\t\tt.Assert(count, 5)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithPage tests ScanAndCount with pagination\nfunc Test_Model_ScanAndCount_WithPage(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Page(2, 3).Order(\"id\").ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(count, TableSize) // Total count, not page count\n\t\tt.Assert(users[0].Id, 4)\n\t\tt.Assert(users[2].Id, 6)\n\t})\n}\n\n// Test_Model_ScanAndCount_Single tests ScanAndCount for single record\nfunc Test_Model_ScanAndCount_Single(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id\", 1).ScanAndCount(&user, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test_Model_ScanAndCount_Empty tests ScanAndCount with no results\nfunc Test_Model_ScanAndCount_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id > ?\", 1000).ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\tt.Assert(count, 0)\n\t})\n}\n\n// Test_Model_ScanAndCount_WithFields tests ScanAndCount with specific fields\nfunc Test_Model_ScanAndCount_WithFields(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Fields(\"id, nickname\").ScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(users[0].Id > 0, true)\n\t\tt.AssertNE(users[0].Nickname, \"\")\n\t})\n}\n\n// Test_Model_ScanAndCount_WithCache tests ScanAndCount with cache\nfunc Test_Model_ScanAndCount_WithCache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users1 []User\n\t\tvar count1 int\n\t\terr := db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).ScanAndCount(&users1, &count1, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users1), 5)\n\t\tt.Assert(count1, TableSize)\n\n\t\t// Second call should use cache\n\t\tvar users2 []User\n\t\tvar count2 int\n\t\terr = db.Model(table).PageCache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}, gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Page(1, 5).ScanAndCount(&users2, &count2, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users2), 5)\n\t\tt.Assert(count2, count1)\n\t})\n}\n\n// Test_Model_Chunk_Basic tests basic Chunk functionality\nfunc Test_Model_Chunk_Basic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttotal  int\n\t\t\tchunks int\n\t\t)\n\t\tdb.Model(table).Order(\"id\").Chunk(3, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\ttotal += len(result)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 4) // 10 records / 3 = 4 chunks (3+3+3+1)\n\t\tt.Assert(total, TableSize)\n\t})\n}\n\n// Test_Model_Chunk_StopEarly tests Chunk with early stop\nfunc Test_Model_Chunk_StopEarly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar chunks int\n\t\tdb.Model(table).Order(\"id\").Chunk(3, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\treturn chunks < 2 // Stop after 2nd chunk\n\t\t})\n\t\tt.Assert(chunks, 2)\n\t})\n}\n\n// Test_Model_Chunk_WithWhere tests Chunk with WHERE conditions\nfunc Test_Model_Chunk_WithWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttotal  int\n\t\t\tchunks int\n\t\t)\n\t\tdb.Model(table).Where(\"id <= ?\", 5).Order(\"id\").Chunk(2, func(result gdb.Result, err error) bool {\n\t\t\tt.AssertNil(err)\n\t\t\tchunks++\n\t\t\ttotal += len(result)\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 3) // 5 records / 2 = 3 chunks (2+2+1)\n\t\tt.Assert(total, 5)\n\t})\n}\n\n// Test_Model_Chunk_ErrorHandling tests Chunk error handling\nfunc Test_Model_Chunk_ErrorHandling(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar errorReceived bool\n\t\tdb.Model(\"non_existent_table\").Chunk(10, func(result gdb.Result, err error) bool {\n\t\t\tif err != nil {\n\t\t\t\terrorReceived = true\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(errorReceived, true)\n\t})\n}\n\n// Test_Model_Chunk_Empty tests Chunk with no results\nfunc Test_Model_Chunk_Empty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar chunks int\n\t\tdb.Model(table).Where(\"id > ?\", 1000).Chunk(10, func(result gdb.Result, err error) bool {\n\t\t\tchunks++\n\t\t\treturn true\n\t\t})\n\t\tt.Assert(chunks, 0) // No chunks for empty result\n\t})\n}\n\n// Test_Model_Page_Boundary tests Page with boundary values\n// Related: https://github.com/gogf/gf/issues/4699\nfunc Test_Model_Page_Boundary(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Page 0 should be treated as page 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(0, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n\n\t// Negative page should be treated as page 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(-1, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n\n\t// Size 0: framework treats limit=0 as \"no limit\", returns all records\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(1, 0).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Negative size: normalized to 0, same as Page(1, 0)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(1, -1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Very large page number (beyond available data)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(100, 3).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test_Model_Limit_Boundary tests Limit with boundary values\n// Related: https://github.com/gogf/gf/issues/4699\nfunc Test_Model_Limit_Boundary(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Limit 0: framework treats limit=0 as \"no limit\", returns all records\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(0).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Negative limit: normalized to 0, same as Limit(0)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(-1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Limit larger than available data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(1000).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Limit(offset, size): offset=5 skips 5 rows, size=100 takes up to 100\n\t// With 10 rows total, skipping 5 returns remaining 5 rows\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(5, 100).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize-5)\n\t})\n\n\t// Offset beyond data: returns empty result\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(100, 5).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// Test_Model_Page_Limit_Combination tests Page and Limit used together\nfunc Test_Model_Page_Limit_Combination(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Page should override Limit\n\t\tresult, err := db.Model(table).Limit(5).Page(1, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_partition_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc createRangePartitionTable(table ...string) string {\n\tvar name string\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`partition_range_%d`, gtime.TimestampNano())\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid int(11) NOT NULL,\n\t\t\tsales_date date DEFAULT NULL,\n\t\t\tamount decimal(10,2) DEFAULT NULL,\n\t\t\tregion varchar(50) DEFAULT NULL\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\n\t\tPARTITION BY RANGE (YEAR(sales_date))\n\t\t(PARTITION p2020 VALUES LESS THAN (2021) ENGINE = InnoDB,\n\t\t PARTITION p2021 VALUES LESS THAN (2022) ENGINE = InnoDB,\n\t\t PARTITION p2022 VALUES LESS THAN (2023) ENGINE = InnoDB,\n\t\t PARTITION p2023 VALUES LESS THAN (2024) ENGINE = InnoDB,\n\t\t PARTITION p_future VALUES LESS THAN MAXVALUE ENGINE = InnoDB);\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc createHashPartitionTable(table ...string) string {\n\tvar name string\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`partition_hash_%d`, gtime.TimestampNano())\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid int(11) NOT NULL,\n\t\t\tuser_id int(11) NOT NULL,\n\t\t\tusername varchar(50) DEFAULT NULL,\n\t\t\temail varchar(100) DEFAULT NULL\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\n\t\tPARTITION BY HASH (user_id)\n\t\tPARTITIONS 4;\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc createListPartitionTable(table ...string) string {\n\tvar name string\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`partition_list_%d`, gtime.TimestampNano())\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid int(11) NOT NULL,\n\t\t\tregion_code int(11) NOT NULL,\n\t\t\tcity varchar(50) DEFAULT NULL,\n\t\t\tpopulation int(11) DEFAULT NULL\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\n\t\tPARTITION BY LIST (region_code)\n\t\t(PARTITION p_north VALUES IN (1,2,3) ENGINE = InnoDB,\n\t\t PARTITION p_south VALUES IN (4,5,6) ENGINE = InnoDB,\n\t\t PARTITION p_east VALUES IN (7,8,9) ENGINE = InnoDB,\n\t\t PARTITION p_west VALUES IN (10,11,12) ENGINE = InnoDB);\n\t`, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc dropPartitionTable(table string) {\n\tif _, err := db3.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\nfunc Test_Partition_Range_Insert_And_Query(t *testing.T) {\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data across different partitions\n\t\tdata := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"sales_date\": \"2020-06-15\", \"amount\": 1000.50, \"region\": \"North\"},\n\t\t\tg.Map{\"id\": 2, \"sales_date\": \"2021-03-20\", \"amount\": 2000.75, \"region\": \"South\"},\n\t\t\tg.Map{\"id\": 3, \"sales_date\": \"2022-09-10\", \"amount\": 3000.00, \"region\": \"East\"},\n\t\t\tg.Map{\"id\": 4, \"sales_date\": \"2023-12-01\", \"amount\": 4000.25, \"region\": \"West\"},\n\t\t\tg.Map{\"id\": 5, \"sales_date\": \"2024-01-15\", \"amount\": 5000.00, \"region\": \"North\"},\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query all data\n\t\tall, err := db3.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5)\n\n\t\t// Query specific year (should hit specific partition)\n\t\tresult, err := db3.Model(table).Where(\"YEAR(sales_date) = ?\", 2022).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t})\n}\n\nfunc Test_Partition_Range_PartitionQuery(t *testing.T) {\n\t// Known limitation: Model.Partition() sets m.partition field but it's not used in SQL generation\n\t// See: database/gdb/gdb_model_select.go lines 735,755 - m.tables is used without PARTITION clause\n\t// TODO: Add PARTITION clause support to GoFrame query builder\n\tt.Skip(\"Partition clause in SELECT queries not yet supported in GoFrame query builder\")\n\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data\n\t\tdata := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"sales_date\": \"2020-06-15\", \"amount\": 1000.50},\n\t\t\tg.Map{\"id\": 2, \"sales_date\": \"2021-03-20\", \"amount\": 2000.75},\n\t\t\tg.Map{\"id\": 3, \"sales_date\": \"2022-09-10\", \"amount\": 3000.00},\n\t\t\tg.Map{\"id\": 4, \"sales_date\": \"2023-12-01\", \"amount\": 4000.25},\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query specific partition\n\t\tresult, err := db3.Model(table).Partition(\"p2022\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\n\t\t// Query multiple partitions\n\t\tresult, err = db3.Model(table).Partition(\"p2021\", \"p2022\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t})\n}\n\nfunc Test_Partition_Hash_Insert_And_Distribution(t *testing.T) {\n\ttable := createHashPartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data that will be distributed across hash partitions\n\t\tdata := g.Slice{}\n\t\tfor i := 1; i <= 20; i++ {\n\t\t\tdata = append(data, g.Map{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"user_id\":  i * 10,\n\t\t\t\t\"username\": fmt.Sprintf(\"user_%d\", i),\n\t\t\t\t\"email\":    fmt.Sprintf(\"user%d@example.com\", i),\n\t\t\t})\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query all data\n\t\tall, err := db3.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 20)\n\n\t\t// Query specific user_id (will hit specific partition based on hash)\n\t\tresult, err := db3.Model(table).Where(\"user_id\", 100).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"username\"], \"user_10\")\n\t})\n}\n\nfunc Test_Partition_List_Insert_And_Query(t *testing.T) {\n\t// Known limitation: Model.Partition() sets m.partition field but it's not used in SQL generation\n\t// See: database/gdb/gdb_model_select.go lines 735,755 - m.tables is used without PARTITION clause\n\t// TODO: Add PARTITION clause support to GoFrame query builder\n\tt.Skip(\"Partition clause in SELECT queries not yet supported in GoFrame query builder\")\n\n\ttable := createListPartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data for different regions\n\t\tdata := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"region_code\": 1, \"city\": \"Beijing\", \"population\": 2154},\n\t\t\tg.Map{\"id\": 2, \"region_code\": 2, \"city\": \"Harbin\", \"population\": 1063},\n\t\t\tg.Map{\"id\": 3, \"region_code\": 5, \"city\": \"Guangzhou\", \"population\": 1868},\n\t\t\tg.Map{\"id\": 4, \"region_code\": 7, \"city\": \"Shanghai\", \"population\": 2428},\n\t\t\tg.Map{\"id\": 5, \"region_code\": 10, \"city\": \"Chengdu\", \"population\": 2093},\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query all\n\t\tall, err := db3.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 5)\n\n\t\t// Query specific partition (north region)\n\t\tresult, err := db3.Model(table).Partition(\"p_north\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\n\t\t// Query specific partition (south region)\n\t\tresult, err = db3.Model(table).Partition(\"p_south\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"city\"], \"Guangzhou\")\n\t})\n}\n\nfunc Test_Partition_Range_Update(t *testing.T) {\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data\n\t\t_, err := db3.Model(table).Data(g.Map{\n\t\t\t\"id\":         1,\n\t\t\t\"sales_date\": \"2022-06-15\",\n\t\t\t\"amount\":     1000.00,\n\t\t\t\"region\":     \"North\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update data within same partition\n\t\tresult, err := db3.Model(table).Data(g.Map{\n\t\t\t\"amount\": 1500.00,\n\t\t\t\"region\": \"South\",\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify update\n\t\tone, err := db3.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"amount\"], \"1500.00\")\n\t\tt.Assert(one[\"region\"], \"South\")\n\t})\n}\n\nfunc Test_Partition_Range_Delete(t *testing.T) {\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data\n\t\tdata := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"sales_date\": \"2020-06-15\", \"amount\": 1000.50},\n\t\t\tg.Map{\"id\": 2, \"sales_date\": \"2021-03-20\", \"amount\": 2000.75},\n\t\t\tg.Map{\"id\": 3, \"sales_date\": \"2022-09-10\", \"amount\": 3000.00},\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Delete from specific partition\n\t\tresult, err := db3.Model(table).Where(\"YEAR(sales_date) = ?\", 2021).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify deletion\n\t\tall, err := db3.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// Verify remaining data\n\t\tresult2, err := db3.Model(table).Where(\"YEAR(sales_date) = ?\", 2021).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result2), 0)\n\t})\n}\n\nfunc Test_Partition_Transaction(t *testing.T) {\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Transaction with partitioned table\n\t\terr := db3.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert across multiple partitions\n\t\t\tdata := g.Slice{\n\t\t\t\tg.Map{\"id\": 1, \"sales_date\": \"2020-06-15\", \"amount\": 1000.50},\n\t\t\t\tg.Map{\"id\": 2, \"sales_date\": \"2021-03-20\", \"amount\": 2000.75},\n\t\t\t\tg.Map{\"id\": 3, \"sales_date\": \"2022-09-10\", \"amount\": 3000.00},\n\t\t\t}\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Data(data).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// Update in transaction\n\t\t\t_, err = tx.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"amount\": 1500.00,\n\t\t\t}).Where(\"id\", 1).Update()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify transaction committed\n\t\tall, err := db3.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\n\t\tone, err := db3.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"amount\"], \"1500.00\")\n\t})\n}\n\nfunc Test_Partition_Range_Count_And_Sum(t *testing.T) {\n\ttable := createRangePartitionTable()\n\tdefer dropPartitionTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert data\n\t\tdata := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"sales_date\": \"2020-06-15\", \"amount\": 1000.00},\n\t\t\tg.Map{\"id\": 2, \"sales_date\": \"2020-09-20\", \"amount\": 1500.00},\n\t\t\tg.Map{\"id\": 3, \"sales_date\": \"2021-03-20\", \"amount\": 2000.00},\n\t\t\tg.Map{\"id\": 4, \"sales_date\": \"2022-09-10\", \"amount\": 3000.00},\n\t\t}\n\t\t_, err := db3.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Count by year (specific partition)\n\t\tcount, err := db3.Model(table).Where(\"YEAR(sales_date) = ?\", 2020).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 2)\n\n\t\t// Sum across partitions\n\t\tvalue, err := db3.Model(table).Fields(\"SUM(amount) as total\").Value()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(value.Float64(), 7000.0) // 1000+1500+2000+3000 = 7500\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_raw_type_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Raw_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+2\"),\n\t\t\t\"passport\":    \"port_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_Raw_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(\n\t\t\tg.List{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"id\":          gdb.Raw(\"id+2\"),\n\t\t\t\t\t\"passport\":    \"port_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t\tg.Map{\n\t\t\t\t\t\"id\":          gdb.Raw(\"id+4\"),\n\t\t\t\t\t\"passport\":    \"port_4\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t},\n\t\t).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 4)\n\t})\n}\n\nfunc Test_Raw_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+100\"),\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tn, err := user.Where(\"id\", 101).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_Where(t *testing.T) {\n\ttable1 := createTable(\"Test_Raw_Where_Table1\")\n\ttable2 := createTable(\"Test_Raw_Where_Table2\")\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\t// https://github.com/gogf/gf/issues/3922\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` AS A WHERE NOT EXISTS (SELECT B.id FROM `Test_Raw_Where_Table2` AS B WHERE `B`.`id`=A.id) LIMIT 1\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(\"B.id\", gdb.Raw(\"A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` AS A WHERE NOT EXISTS (SELECT B.id FROM `Test_Raw_Where_Table2` AS B WHERE B.id=A.id) LIMIT 1\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(gdb.Raw(\"B.id=A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\t// https://github.com/gogf/gf/issues/3915\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := \"SELECT * FROM `Test_Raw_Where_Table1` WHERE `passport` < `nickname`\"\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\tm := db.Model(table1).Ctx(ctx).WhereLT(\"passport\", gdb.Raw(\"`nickname`\"))\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n}\n\n// Test_DataType_JSON_Insert tests JSON data insertion\nfunc Test_DataType_JSON_Insert(t *testing.T) {\n\ttable := \"test_json_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert simple JSON object\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"John\",\"age\":30}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"John\", \"age\": float64(30)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_JSON_Extract tests JSON_EXTRACT function\nfunc Test_DataType_JSON_Extract(t *testing.T) {\n\ttable := \"test_json_extract_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Alice\",\"age\":25,\"city\":\"Beijing\"}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract name using JSON_EXTRACT\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$.name') as name\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), `\"Alice\"`)\n\n\t\t// Extract age\n\t\tone, err = db.Model(table).Fields(\"JSON_EXTRACT(data, '$.age') as age\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"age\"].Int(), 25)\n\t})\n}\n\n// Test_DataType_JSON_Set tests JSON_SET function\nfunc Test_DataType_JSON_Set(t *testing.T) {\n\ttable := \"test_json_set_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Bob\"}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update using JSON_SET\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\"UPDATE %s SET data = JSON_SET(data, '$.age', 30) WHERE id = 1\", table))\n\t\tt.AssertNil(err)\n\n\t\t// Verify updated data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"Bob\", \"age\": float64(30)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_JSON_Array tests JSON array operations\nfunc Test_DataType_JSON_Array(t *testing.T) {\n\ttable := \"test_json_array_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert JSON array\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `[\"apple\",\"banana\",\"cherry\"]`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract array element\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$[0]') as first\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"first\"].String(), `\"apple\"`)\n\t})\n}\n\n// Test_DataType_JSON_Null tests JSON NULL handling\nfunc Test_DataType_JSON_Null(t *testing.T) {\n\ttable := \"test_json_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL value\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"data\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_JSON_Complex tests complex nested JSON\nfunc Test_DataType_JSON_Complex(t *testing.T) {\n\ttable := \"test_json_complex_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert complex nested JSON\n\t\tcomplexJSON := `{\n\t\t\t\"user\": {\n\t\t\t\t\"name\": \"Charlie\",\n\t\t\t\t\"contacts\": {\n\t\t\t\t\t\"email\": \"charlie@example.com\",\n\t\t\t\t\t\"phone\": \"1234567890\"\n\t\t\t\t},\n\t\t\t\t\"tags\": [\"developer\", \"gopher\"]\n\t\t\t}\n\t\t}`\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": complexJSON,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Extract nested field\n\t\tone, err := db.Model(table).Fields(\"JSON_EXTRACT(data, '$.user.contacts.email') as email\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"email\"].String(), `\"charlie@example.com\"`)\n\t})\n}\n\n// Test_DataType_JSON_Query tests JSON query with WHERE clause\nfunc Test_DataType_JSON_Query(t *testing.T) {\n\ttable := \"test_json_query_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert multiple JSON records\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\tg.Map{\"data\": `{\"name\":\"David\",\"age\":20}`},\n\t\t\tg.Map{\"data\": `{\"name\":\"Eve\",\"age\":30}`},\n\t\t\tg.Map{\"data\": `{\"name\":\"Frank\",\"age\":25}`},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query by JSON field value\n\t\tcount, err := db.Model(table).Where(\"JSON_EXTRACT(data, '$.age') > ?\", 25).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// Test_DataType_JSON_Update tests updating JSON data\nfunc Test_DataType_JSON_Update(t *testing.T) {\n\ttable := \"test_json_update_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data JSON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Grace\",\"age\":28}`,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update entire JSON\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"data\": `{\"name\":\"Grace\",\"age\":29}`,\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := map[string]interface{}{\"name\": \"Grace\", \"age\": float64(29)}\n\t\tvar actual map[string]interface{}\n\t\terr = json.Unmarshal([]byte(one[\"data\"].String()), &actual)\n\t\tt.AssertNil(err)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Binary_Small tests small binary data\nfunc Test_DataType_Binary_Small(t *testing.T) {\n\ttable := \"test_binary_small_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert small binary data\n\t\tbinaryData := []byte{0x00, 0x01, 0x02, 0x03, 0xFF}\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": binaryData,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(bytes.Equal(one[\"data\"].Bytes(), binaryData), true)\n\t})\n}\n\n// Test_DataType_Binary_Large tests large binary data (1MB+)\nfunc Test_DataType_Binary_Large(t *testing.T) {\n\ttable := \"test_binary_large_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data MEDIUMBLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create 1MB binary data\n\t\tsize := 1024 * 1024 // 1MB\n\t\tlargeBinary := make([]byte, size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tlargeBinary[i] = byte(i % 256)\n\t\t}\n\n\t\t// Insert large binary data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": largeBinary,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one[\"data\"].Bytes()), size)\n\t\tt.Assert(bytes.Equal(one[\"data\"].Bytes(), largeBinary), true)\n\t})\n}\n\n// Test_DataType_Binary_Integrity tests binary data integrity with checksum\nfunc Test_DataType_Binary_Integrity(t *testing.T) {\n\ttable := \"test_binary_integrity_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB, checksum VARCHAR(64))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create random binary data\n\t\tbinaryData := []byte(\"Hello, World! This is a binary test data with special chars: \\x00\\xFF\\xAB\")\n\n\t\t// Calculate SHA256 checksum\n\t\thash := sha256.Sum256(binaryData)\n\t\tchecksum := hex.EncodeToString(hash[:])\n\n\t\t// Insert with checksum\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\":     binaryData,\n\t\t\t\"checksum\": checksum,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify integrity\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tretrievedHash := sha256.Sum256(one[\"data\"].Bytes())\n\t\tretrievedChecksum := hex.EncodeToString(retrievedHash[:])\n\t\tt.Assert(retrievedChecksum, checksum)\n\t})\n}\n\n// Test_DataType_Binary_Empty tests empty and NULL binary\nfunc Test_DataType_Binary_Empty(t *testing.T) {\n\ttable := \"test_binary_empty_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, data BLOB)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert empty binary\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"data\": []byte{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert NULL\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"data\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify empty\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one[\"data\"].Bytes()), 0)\n\n\t\t// Verify NULL\n\t\tone, err = db.Model(table).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"data\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Decimal_HighPrecision tests high precision decimal (65,30)\nfunc Test_DataType_Decimal_HighPrecision(t *testing.T) {\n\ttable := \"test_decimal_precision_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, amount DECIMAL(65,30))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert high precision decimal\n\t\tvalue := \"12345678901234567890123456789012345.123456789012345678901234567890\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"amount\": value,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify precision\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"amount\"].String(), value)\n\t})\n}\n\n// Test_DataType_Decimal_Calculation tests decimal arithmetic\nfunc Test_DataType_Decimal_Calculation(t *testing.T) {\n\ttable := \"test_decimal_calc_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, price DECIMAL(10,2), quantity DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert test data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"price\":    \"19.99\",\n\t\t\t\"quantity\": \"3.5\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Calculate total using SQL\n\t\tone, err := db.Model(table).Fields(\"price * quantity as total\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"total\"].String(), \"69.9650\")\n\t})\n}\n\n// Test_DataType_Decimal_Boundary tests decimal boundary values\nfunc Test_DataType_Decimal_Boundary(t *testing.T) {\n\ttable := \"test_decimal_boundary_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, value DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test max value (10 digits, 2 decimals: 99999999.99)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"99999999.99\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test min value\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"-99999999.99\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test zero\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"value\": \"0.00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"value\"].String(), \"99999999.99\")\n\t\tt.Assert(all[1][\"value\"].String(), \"-99999999.99\")\n\t\tt.Assert(all[2][\"value\"].String(), \"0.00\")\n\t})\n}\n\n// Test_DataType_Decimal_Null tests NULL decimal values\nfunc Test_DataType_Decimal_Null(t *testing.T) {\n\ttable := \"test_decimal_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, value DECIMAL(10,2))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"value\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"value\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Datetime_Timezone tests datetime with timezone handling\nfunc Test_DataType_Datetime_Timezone(t *testing.T) {\n\ttable := \"test_datetime_tz_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert datetime\n\t\tdt := \"2024-01-15 12:30:45\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"created_at\": dt,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify datetime\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"created_at\"].String(), dt)\n\t})\n}\n\n// Test_DataType_Datetime_Precision tests datetime with microsecond precision\nfunc Test_DataType_Datetime_Precision(t *testing.T) {\n\ttable := \"test_datetime_precision_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME(6))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert datetime with microseconds\n\t\tdt := \"2024-01-15 12:30:45.123456\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"created_at\": dt,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify precision (compare up to seconds, MySQL may format microseconds differently)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := \"2024-01-15 12:30:45\"\n\t\tactual := one[\"created_at\"].String()[:19] // Extract first 19 chars (YYYY-MM-DD HH:MM:SS)\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Datetime_Boundary tests datetime boundary values\nfunc Test_DataType_Datetime_Boundary(t *testing.T) {\n\ttable := \"test_datetime_boundary_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test min datetime (MySQL supports 1000-01-01 00:00:00)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": \"1000-01-01 00:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test max datetime\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"dt\": \"9999-12-31 23:59:59\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify boundaries\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"dt\"].String(), \"1000-01-01 00:00:00\")\n\t\tt.Assert(all[1][\"dt\"].String(), \"9999-12-31 23:59:59\")\n\t})\n}\n\n// Test_DataType_Datetime_Null tests NULL datetime\nfunc Test_DataType_Datetime_Null(t *testing.T) {\n\ttable := \"test_datetime_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"dt\"].IsNil(), true)\n\t})\n}\n\n// Test_DataType_Datetime_Update tests datetime updates\nfunc Test_DataType_Datetime_Update(t *testing.T) {\n\ttable := \"test_datetime_update_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, dt DATETIME)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial datetime\n\t\tdt1 := \"2024-01-01 10:00:00\"\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"dt\": dt1,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Update datetime\n\t\tdt2 := \"2024-12-31 23:59:59\"\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"dt\": dt2,\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Verify update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"dt\"].String(), dt2)\n\t})\n}\n\n// Test_DataType_Enum_Valid tests valid ENUM values\nfunc Test_DataType_Enum_Valid(t *testing.T) {\n\ttable := \"test_enum_valid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, status ENUM('pending','approved','rejected'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert all valid values\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\tg.Map{\"status\": \"pending\"},\n\t\t\tg.Map{\"status\": \"approved\"},\n\t\t\tg.Map{\"status\": \"rejected\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"status\"].String(), \"pending\")\n\t\tt.Assert(all[1][\"status\"].String(), \"approved\")\n\t\tt.Assert(all[2][\"status\"].String(), \"rejected\")\n\t})\n}\n\n// Test_DataType_Enum_Invalid tests invalid ENUM values (should fail or truncate)\nfunc Test_DataType_Enum_Invalid(t *testing.T) {\n\ttable := \"test_enum_invalid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, status ENUM('pending','approved','rejected'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Attempt to insert invalid value (should fail in strict mode)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"status\": \"invalid_status\",\n\t\t}).Insert()\n\t\t// In strict SQL mode, this should produce an error\n\t\t// In non-strict mode, it might insert empty string\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_DataType_Set_Valid tests valid SET values\nfunc Test_DataType_Set_Valid(t *testing.T) {\n\ttable := \"test_set_valid_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, permissions SET('read','write','execute'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert single value\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert multiple values\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read,write\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Insert all values\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"read,write,execute\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify all values\n\t\tall, err := db.Model(table).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"permissions\"].String(), \"read\")\n\t\tt.Assert(all[1][\"permissions\"].String(), \"read,write\")\n\t\tt.Assert(all[2][\"permissions\"].String(), \"read,write,execute\")\n\t})\n}\n\n// Test_DataType_Set_Empty tests empty SET values\nfunc Test_DataType_Set_Empty(t *testing.T) {\n\ttable := \"test_set_empty_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, permissions SET('read','write','execute'))\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert empty SET\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"permissions\": \"\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify empty\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"permissions\"].String(), \"\")\n\t})\n}\n\n// Test_DataType_Geometry_Point tests POINT geometry type\nfunc Test_DataType_Geometry_Point(t *testing.T) {\n\ttable := \"test_geo_point_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, location POINT)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert POINT using ST_GeomFromText\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"INSERT INTO %s (location) VALUES (ST_GeomFromText('POINT(116.4074 39.9042)'))\", table))\n\t\tt.AssertNil(err)\n\n\t\t// Query POINT using ST_AsText\n\t\tone, err := db.Model(table).Fields(\"ST_AsText(location) as location_text\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"location_text\"].String(), \"POINT(116.4074 39.9042)\")\n\t})\n}\n\n// Test_DataType_Geometry_Polygon tests POLYGON geometry type\nfunc Test_DataType_Geometry_Polygon(t *testing.T) {\n\ttable := \"test_geo_polygon_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, area POLYGON)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert POLYGON (rectangle)\n\t\tpolygon := \"POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))\"\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"INSERT INTO %s (area) VALUES (ST_GeomFromText('%s'))\", table, polygon))\n\t\tt.AssertNil(err)\n\n\t\t// Query POLYGON (normalize spaces for comparison)\n\t\tone, err := db.Model(table).Fields(\"ST_AsText(area) as area_text\").Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\texpected := \"POLYGON((0 0,10 0,10 10,0 10,0 0))\"\n\t\tactual := strings.ReplaceAll(one[\"area_text\"].String(), \", \", \",\") // Remove spaces after commas\n\t\tt.Assert(actual, expected)\n\t})\n}\n\n// Test_DataType_Geometry_Null tests NULL geometry values\nfunc Test_DataType_Geometry_Null(t *testing.T) {\n\ttable := \"test_geo_null_\" + gtime.TimestampMicroStr()\n\t_, err := db.Exec(ctx, \"CREATE TABLE \"+table+\" (id INT PRIMARY KEY AUTO_INCREMENT, location POINT)\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"location\": nil,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Verify NULL\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"location\"].IsNil(), true)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_scanlist_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Table_Relation_One(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  course varchar(45) NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `orm:\"uid\"`\n\t\tName string `orm:\"name\"`\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int    `orm:\"uid\"`\n\t\tAddress string `orm:\"address\"`\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId     int    `orm:\"id\"`\n\t\tUid    int    `orm:\"uid\"`\n\t\tScore  int    `orm:\"score\"`\n\t\tCourse string `orm:\"course\"`\n\t}\n\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tr, err := tx.Model(tableUser).Save(EntityUser{\n\t\t\t\tName: \"john\",\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tuid, err := r.LastInsertId()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserDetail).Save(EntityUserDetail{\n\t\t\t\tUid:     int(uid),\n\t\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserScores).Save(g.Slice{\n\t\t\t\tEntityUserScores{Uid: int(uid), Score: 100, Course: \"math\"},\n\t\t\t\tEntityUserScores{Uid: int(uid), Score: 99, Course: \"physics\"},\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\t// Data check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(tableUser).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"name\"].String(), \"john\")\n\n\t\tr, err = db.Model(tableUserDetail).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"address\"].String(), `Beijing DongZhiMen #66`)\n\n\t\tr, err = db.Model(tableUserScores).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 2)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[1][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"course\"].String(), `math`)\n\t\tt.Assert(r[1][\"course\"].String(), `physics`)\n\t})\n\t// Entity query.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user Entity\n\t\t// SELECT * FROM `user` WHERE `name`='john'\n\t\terr := db.Model(tableUser).Scan(&user.User, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid`=1\n\t\terr = db.Model(tableUserDetail).Scan(&user.UserDetail, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid`=1\n\t\terr = db.Model(tableUserScores).Scan(&user.UserScores, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.User, EntityUser{\n\t\t\tUid:  1,\n\t\t\tName: \"john\",\n\t\t})\n\t\tt.Assert(user.UserDetail, EntityUserDetail{\n\t\t\tUid:     1,\n\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t})\n\t\tt.Assert(user.UserScores, []EntityUserScores{\n\t\t\t{Id: 1, Uid: 1, Course: \"math\", Score: 100},\n\t\t\t{Id: 2, Uid: 1, Course: \"physics\", Score: 99},\n\t\t})\n\t})\n}\n\nfunc Test_Table_Relation_Many(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_ModelScanList(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t//db.SetDebug(true)\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_RelationKeyCaseInsensitive(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UId:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_TheSameRelationNames(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_EmptyData(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t})\n\treturn\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid:UID\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:UId\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UId:Uid\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID:Uid\")\n\t\tt.AssertNil(err)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 0)\n\t})\n}\n\nfunc Test_Table_Relation_NoneEqualDataSize(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t// _, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t//\t\"uid\":     i,\n\t\t\t//\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t// })\n\t\t\t// t.AssertNil(err)\n\t\t\t// Scores.\n\t\t\t// for j := 1; j <= 5; j++ {\n\t\t\t//\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t//\t\t\"uid\":   i,\n\t\t\t//\t\t\"score\": j,\n\t\t\t//\t})\n\t\t\t//\tt.AssertNil(err)\n\t\t\t// }\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"UId\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, EntityUserDetail{})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, EntityUserDetail{})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct1(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\t*EntityUser\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\t*EntityUser\n\t\t*EntityUserDetail\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tscores []*EntityUserScores\n\t\t)\n\t\t// SELECT * FROM `user_scores`\n\t\terr = db.Model(tableUserScores).Scan(&scores)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUser).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUser\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Assertions.\n\t\tt.Assert(len(scores), 25)\n\t\tt.Assert(scores[0].Id, 1)\n\t\tt.Assert(scores[0].Uid, 1)\n\t\tt.Assert(scores[0].Name, \"name_1\")\n\t\tt.Assert(scores[0].Address, \"address_1\")\n\t\tt.Assert(scores[24].Id, 25)\n\t\tt.Assert(scores[24].Uid, 5)\n\t\tt.Assert(scores[24].Name, \"name_5\")\n\t\tt.Assert(scores[24].Address, \"address_5\")\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct2(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\t*EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with struct elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tEntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and struct attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EntityUser struct {\n\t\t\tUid  int    `json:\"uid\"`\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\ttype EntityUserDetail struct {\n\t\t\tUid     int    `json:\"uid\"`\n\t\t\tAddress string `json:\"address\"`\n\t\t}\n\t\ttype EntityUserScores struct {\n\t\t\tId    int `json:\"id\"`\n\t\t\tUid   int `json:\"uid\"`\n\t\t\tScore int `json:\"score\"`\n\t\t}\n\t\ttype Entity struct {\n\t\t\tEntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\t\tvar users []*Entity\n\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_soft_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete1(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete2(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(0) DEFAULT NULL,\n  update_at datetime(0) DEFAULT NULL,\n  delete_at datetime(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Map(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId        int\n\t\tName      string\n\t\tCreatedAT *gtime.Time\n\t\tUpdatedAT *gtime.Time\n\t\tDeletedAT *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := User{\n\t\t\tName: \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).OmitEmpty().WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-4)\n\n\t\t// Replace\n\t\tdataReplace := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_100\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftUpdateTime(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  num       int(11) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\tr, err = db.Model(table).Data(\"num=num+1\").Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_SoftUpdateTime_WithDO(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  num       int(11) DEFAULT NULL,\n  created_at datetime(6) DEFAULT NULL,\n  updated_at datetime(6) DEFAULT NULL,\n  deleted_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInserted, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInserted[\"id\"].Int(), 1)\n\t\tt.Assert(oneInserted[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\ttime.Sleep(2 * time.Second)\n\t\ttype User struct {\n\t\t\tg.Meta    `orm:\"do:true\"`\n\t\t\tId        any\n\t\t\tNum       any\n\t\t\tCreatedAt any\n\t\t\tUpdatedAt any\n\t\t\tDeletedAt any\n\t\t}\n\t\tr, err = db.Model(table).Data(User{\n\t\t\tNum: 100,\n\t\t}).Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdated, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdated[\"num\"].Int(), 100)\n\t\tt.Assert(oneUpdated[\"created_at\"].String(), oneInserted[\"created_at\"].String())\n\t\tt.AssertNE(oneUpdated[\"updated_at\"].String(), oneInserted[\"updated_at\"].String())\n\t})\n}\n\nfunc Test_SoftDelete(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(10).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", ids).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tall, err := db.Model(table).Unscoped().Where(\"id\", ids).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.AssertNE(all[0][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"delete_at\"].String(), \"\")\n\t})\n}\n\nfunc Test_SoftDelete_Join(t *testing.T) {\n\ttable1 := \"time_test_table1\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table1)\n\n\ttable2 := \"time_test_table2\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  createat datetime(6) DEFAULT NULL,\n  updateat datetime(6) DEFAULT NULL,\n  deleteat datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tdataInsert1 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table1).Data(dataInsert1).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tdataInsert2 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_2\",\n\t\t}\n\t\tr, err = db.Model(table2).Data(dataInsert2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"name_1\")\n\n\t\t// Soft deleting.\n\t\tr, err = db.Model(table1).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\tone, err = db.Model(table2, \"t2\").LeftJoin(table1, \"t1\", \"t2.id=t1.id\").Fields(\"t2.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\t})\n}\n\nfunc Test_SoftDelete_WhereAndOr(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\t// Add datas.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", 1).WhereOr(\"id\", 3).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_CreateUpdateTime_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(6) DEFAULT NULL,\n  update_at datetime(6) DEFAULT NULL,\n  delete_at datetime(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\ttype Entity struct {\n\t\tId       uint64      `orm:\"id,primary\" json:\"id\"`\n\t\tName     string      `orm:\"name\"       json:\"name\"`\n\t\tCreateAt *gtime.Time `orm:\"create_at\"  json:\"create_at\"`\n\t\tUpdateAt *gtime.Time `orm:\"update_at\"  json:\"update_at\"`\n\t\tDeleteAt *gtime.Time `orm:\"delete_at\"  json:\"delete_at\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_10\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1000\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// Replace\n\t\tdataReplace := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_100\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).OmitEmpty().Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneReplace[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneReplace[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_UnixTimestamp(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at int(11) DEFAULT NULL,\n  update_at int(11) DEFAULT NULL,\n  delete_at int(11) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// sleep some seconds to make update time greater than create time.\n\ttime.Sleep(2 * time.Second)\n\n\t// update\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// update: map\n\t\tdataInsert := g.Map{\n\t\t\t\"name\": \"name_11\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_11\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\n\t\tvar (\n\t\t\tlastCreateTime = one[\"create_at\"].Int64()\n\t\t\tlastUpdateTime = one[\"update_at\"].Int64()\n\t\t)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// update: string\n\t\tr, err = db.Model(table).Data(\"name='name_111'\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.Assert(one[\"create_at\"].Int64(), lastCreateTime)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), lastUpdateTime)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"delete_at\"].Int64(), 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Bool_Deleted(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at int(11) DEFAULT NULL,\n  update_at int(11) DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t//db.SetDebug(true)\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampMilli(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at bigint(19) unsigned DEFAULT NULL,\n  update_at bigint(19) unsigned DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampMilli,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"create_at\"].String()), 13)\n\t\tt.Assert(len(one[\"update_at\"].String()), 13)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampNano(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at bigint(19) unsigned DEFAULT NULL,\n  update_at bigint(19) unsigned DEFAULT NULL,\n  delete_at bit(1) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tvar softTimeOption = gdb.SoftTimeOption{\n\t\tSoftTimeType: gdb.SoftTimeTypeTimestampNano,\n\t}\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.Assert(len(one[\"create_at\"].String()), 19)\n\t\tt.Assert(len(one[\"update_at\"].String()), 19)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 1)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_Specified(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        int(11) NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at datetime(0) DEFAULT NULL,\n  update_at datetime(0) DEFAULT NULL,\n  delete_at datetime(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_1\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneInsert[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_10\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:15:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneSave[\"update_at\"].String(), \"2024-05-30 20:15:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\":      \"name_1000\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:30:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneUpdate[\"update_at\"].String(), \"2024-05-30 20:30:00\")\n\n\t\t// Replace\n\t\tdataReplace := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_100\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 21:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataReplace).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\toneReplace, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneReplace[\"id\"].Int(), 1)\n\t\tt.Assert(oneReplace[\"name\"].String(), \"name_100\")\n\t\tt.Assert(oneReplace[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneReplace[\"create_at\"].String(), \"2024-05-30 21:00:00\")\n\t\tt.Assert(oneReplace[\"update_at\"].String(), \"2024-05-30 21:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Insert with delete_at\n\t\tdataInsertDelete := g.Map{\n\t\t\t\"id\":        2,\n\t\t\t\"name\":      \"name_2\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"delete_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataInsertDelete).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Delete Select\n\t\toneDelete, err := db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(oneDelete), 0)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"id\"].Int(), 2)\n\t\tt.Assert(oneDeleteUnscoped[\"name\"].String(), \"name_2\")\n\t\tt.Assert(oneDeleteUnscoped[\"delete_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_union_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_feature_with_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\n/*\nmysql> show tables;\n+----------------+\n| Tables_in_test |\n+----------------+\n| user           |\n| user_detail    |\n| user_score     |\n+----------------+\n3 rows in set (0.01 sec)\n\nmysql> select * from `user`;\n+----+--------+\n| id | name   |\n+----+--------+\n|  1 | name_1 |\n|  2 | name_2 |\n|  3 | name_3 |\n|  4 | name_4 |\n|  5 | name_5 |\n+----+--------+\n5 rows in set (0.01 sec)\n\nmysql> select * from `user_detail`;\n+-----+-----------+\n| uid | address   |\n+-----+-----------+\n|   1 | address_1 |\n|   2 | address_2 |\n|   3 | address_3 |\n|   4 | address_4 |\n|   5 | address_5 |\n+-----+-----------+\n5 rows in set (0.00 sec)\n\nmysql> select * from `user_score`;\n+----+-----+-------+\n| id | uid | score |\n+----+-----+-------+\n|  1 |   1 |     1 |\n|  2 |   1 |     2 |\n|  3 |   1 |     3 |\n|  4 |   1 |     4 |\n|  5 |   1 |     5 |\n|  6 |   2 |     1 |\n|  7 |   2 |     2 |\n|  8 |   2 |     3 |\n|  9 |   2 |     4 |\n| 10 |   2 |     5 |\n| 11 |   3 |     1 |\n| 12 |   3 |     2 |\n| 13 |   3 |     3 |\n| 14 |   3 |     4 |\n| 15 |   3 |     5 |\n| 16 |   4 |     1 |\n| 17 |   4 |     2 |\n| 18 |   4 |     3 |\n| 19 |   4 |     4 |\n| 20 |   4 |     5 |\n| 21 |   5 |     1 |\n| 22 |   5 |     2 |\n| 23 |   5 |     3 |\n| 24 |   5 |     4 |\n| 25 |   5 |     5 |\n+----+-----+-------+\n25 rows in set (0.00 sec)\n*/\n\nfunc Test_Table_Relation_With_Scan(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_score\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScore struct {\n\t\tgmeta.Meta `orm:\"table:user_score\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int          `json:\"id\"`\n\t\tName       string       `json:\"name\"`\n\t\tUserDetail *UserDetail  `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScore `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\tuser := User{\n\t\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t\t}\n\t\t\tlastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\tuserDetail := UserDetail{\n\t\t\t\tUid:     int(lastInsertId),\n\t\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t\t}\n\t\t\t_, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert()\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\tuserScore := UserScore{\n\t\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\t\tScore: j,\n\t\t\t\t}\n\t\t\t\t_, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\tuser := User{\n\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t}\n\t\tlastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\tuserDetail := UserDetail{\n\t\t\tUid:     int(lastInsertId),\n\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t}\n\t\t_, err = db.Model(userDetail).Data(userDetail).Insert()\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\tuserScore := UserScore{\n\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\tScore: j,\n\t\t\t}\n\t\t\t_, err = db.Model(userScore).Data(userScore).Insert()\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", 3).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserDetail).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.With(User{}).\n\t\t\tWith(UserDetail{}).\n\t\t\tWith(UserScore{}).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserDetail).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 0)\n\t})\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.With(user).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.Assert(user.UserDetail, nil)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 0)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 0)\n\t})\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.With(User{}).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.Assert(users[1].UserDetail, nil)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAllCondition_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id, where:uid > 3\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id, where:score>1 and score<5, order:score desc\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 3)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 4)\n\t\tt.Assert(users[0].UserScores[2].Uid, 3)\n\t\tt.Assert(users[0].UserScores[2].Score, 2)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_With_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Without_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tId   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tUserEmbedded\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_WithoutMeta(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetailBase struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tUserDetailBase\n\t}\n\n\ttype UserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag_MoreDeep(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail1 struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail2 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail1 *UserDetail1  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail3 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail2 *UserDetail2  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail3 *UserDetail3  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_AttributeStructAlsoHasWithTag_MoreDeep(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail1 struct {\n\t\tgmeta.Meta `orm:\"table:user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail2 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail1 *UserDetail1  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail3 struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail2 *UserDetail2  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta  `orm:\"table:user_detail\"`\n\t\tUid         int           `json:\"uid\"`\n\t\tAddress     string        `json:\"address\"`\n\t\tUserDetail3 *UserDetail3  `orm:\"with:uid\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).With(UserDetail{}, UserDetail2{}, UserDetail3{}, UserScores{}).Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 3)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1, nil)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).With(UserDetail{}, UserDetail2{}, UserDetail3{}, UserScores{}).Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.Uid, 4)\n\t\tt.Assert(user.UserDetail.UserDetail3.UserDetail2.UserDetail1, nil)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends1(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int     `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     *TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     *TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends2(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int       `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     []*TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     []*TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.Assert(len(tableA.TableB), 2)\n\t\tt.Assert(tableA.TableB[0].Id, 10)\n\t\tt.Assert(tableA.TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA.TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA.TableB[1].TableC), 1)\n\t\tt.Assert(tableA.TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA.TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA.TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA.TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA.TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA.TableB[1].TableC[0].TableBId, 30)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\n\t\tt.Assert(len(tableA[0].TableB), 2)\n\t\tt.Assert(tableA[0].TableB[0].Id, 10)\n\t\tt.Assert(tableA[0].TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA[0].TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA[0].TableB[1].TableC), 1)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].TableBId, 30)\n\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].Id, 300)\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].TableBId, 20)\n\n\t\tt.Assert(tableA[1].TableB[1].Id, 40)\n\t\tt.Assert(tableA[1].TableB[1].TableAId, 2)\n\t\tt.Assert(tableA[1].TableB[1].TableC, nil)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends_Embedded(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\t*TableC    `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\t*TableB    `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\t// g.Dump(tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Meta_NameMatchingRule(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user100\"\n\t\ttableUserDetail = \"user_detail100\"\n\t\ttableUserScores = \"user_scores100\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nuser_id int(10) unsigned NOT NULL,\nscore int(10) unsigned NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail100\"`\n\t\tUserID     int    `json:\"user_id\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:user_scores100\"`\n\t\tID         int `json:\"id\"`\n\t\tUserID     int `json:\"user_id\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user100\"`\n\t\tUserEmbedded\n\t\tUserDetail UserDetail    `orm:\"with:user_id=id\"`\n\t\tUserScores []*UserScores `orm:\"with:user_id=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t\t\"score\":   j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\tvar user *User\n\t//\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t//\tt.AssertNil(err)\n\t//\tt.Assert(user.ID, 3)\n\t//\tt.AssertNE(user.UserDetail, nil)\n\t//\tt.Assert(user.UserDetail.UserID, 3)\n\t//\tt.Assert(user.UserDetail.Address, `address_3`)\n\t//\tt.Assert(len(user.UserScores), 5)\n\t//\tt.Assert(user.UserScores[0].UserID, 3)\n\t//\tt.Assert(user.UserScores[0].Score, 1)\n\t//\tt.Assert(user.UserScores[4].UserID, 3)\n\t//\tt.Assert(user.UserScores[4].Score, 5)\n\t// })\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.ID, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.UserID, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].UserID, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].UserID, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Unscoped(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user101\"\n\t\ttableUserDetail = \"user_detail101\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\ndeleted_at datetime default NULL ,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail101\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Order(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user101\"\n\t\ttableUserDetail = \"user_detail101\"\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nid int(10) unsigned NOT NULL AUTO_INCREMENT,\nname varchar(45) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE IF NOT EXISTS %s (\nuser_id int(10) unsigned NOT NULL,\naddress varchar(45) NOT NULL,\ndeleted_at datetime default NULL ,\nPRIMARY KEY (user_id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:user_detail101\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:user101\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, order:user_id asc,address desc, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTableSize        = 10\n\tTableName        = \"user\"\n\tTestSchema1      = \"test1\"\n\tTestSchema2      = \"test2\"\n\tTestPartitionDB  = \"test3\"\n\tTableNamePrefix1 = \"gf_\"\n\tTestDbUser       = \"root\"\n\tTestDbPass       = \"12345678\"\n\tCreateTime       = \"2018-10-24 10:00:00\"\n)\n\nvar (\n\tdb        gdb.DB\n\tdb2       gdb.DB\n\tdb3       gdb.DB\n\tdbPrefix  gdb.DB\n\tdbInvalid gdb.DB\n\tctx       = context.TODO()\n)\n\nfunc init() {\n\tnodeDefault := gdb.ConfigNode{\n\t\tExecTimeout: time.Second * 2,\n\t\tLink:        fmt.Sprintf(\"mysql:root:%s@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tTranTimeout: time.Second * 3,\n\t}\n\tpartitionDefault := gdb.ConfigNode{\n\t\tLink:        fmt.Sprintf(\"mysql:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tDebug:       true,\n\t\tTranTimeout: time.Second * 3,\n\t}\n\tnodePrefix := gdb.ConfigNode{\n\t\tLink:        fmt.Sprintf(\"mysql:root:%s@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tTranTimeout: time.Second * 3,\n\t}\n\tnodePrefix.Prefix = TableNamePrefix1\n\n\tnodeInvalid := gdb.ConfigNode{\n\t\tLink:        fmt.Sprintf(\"mysql:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true\", TestDbPass),\n\t\tTranTimeout: time.Second * 3,\n\t}\n\tgdb.AddConfigNode(\"test\", nodeDefault)\n\tgdb.AddConfigNode(\"prefix\", nodePrefix)\n\tgdb.AddConfigNode(\"nodeinvalid\", nodeInvalid)\n\tgdb.AddConfigNode(\"partition\", partitionDefault)\n\tgdb.AddConfigNode(gdb.DefaultGroupName, nodeDefault)\n\n\t// Default db.\n\tif r, err := gdb.NewByGroup(); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdb = r\n\t}\n\tschemaTemplate := \"CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8\"\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestPartitionDB)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdb = db.Schema(TestSchema1)\n\tdb2 = db.Schema(TestSchema2)\n\tdb3 = db.Schema(TestPartitionDB)\n\t// Prefix db.\n\tif r, err := gdb.NewByGroup(\"prefix\"); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbPrefix = r\n\t}\n\tif _, err := dbPrefix.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tif _, err := dbPrefix.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdbPrefix = dbPrefix.Schema(TestSchema1)\n\n\t// Invalid db.\n\tif r, err := gdb.NewByGroup(\"nodeinvalid\"); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbInvalid = r\n\t}\n\tdbInvalid = dbInvalid.Schema(TestSchema1)\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\t}\n\tdropTableWithDb(db, name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        passport    varchar(45) NULL,\n\t        password    char(32) NULL,\n\t        nickname    varchar(45) NULL,\n\t        create_time timestamp(6) NULL,\n\t        create_date       date NULL,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn name\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\nfunc Test_PartitionTable(t *testing.T) {\n\tdropShopDBTable()\n\tcreateShopDBTable()\n\tinsertShopDBData()\n\n\t// defer dropShopDBTable()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata, err := db3.Ctx(ctx).Model(\"dbx_order\").Partition(\"p3\", \"p4\").All()\n\t\tt.AssertNil(err)\n\t\tdataLen := len(data)\n\t\tt.Assert(dataLen, 5)\n\t\tdata, err = db3.Ctx(ctx).Model(\"dbx_order\").Partition(\"p3\").All()\n\t\tt.AssertNil(err)\n\t\tdataLen = len(data)\n\t\tt.Assert(dataLen, 5)\n\t})\n}\nfunc createShopDBTable() {\n\tsql := `CREATE TABLE dbx_order (\n  id int(11) NOT NULL,\n  sales_date date DEFAULT NULL,\n  amount decimal(10,2) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\nPARTITION BY RANGE (YEAR(sales_date))\n(PARTITION p1 VALUES LESS THAN (2020) ENGINE = InnoDB,\n PARTITION p2 VALUES LESS THAN (2021) ENGINE = InnoDB,\n PARTITION p3 VALUES LESS THAN (2022) ENGINE = InnoDB,\n PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = InnoDB);`\n\t_, err := db3.Exec(ctx, sql)\n\tif err != nil {\n\t\tgtest.Fatal(err.Error())\n\t}\n}\nfunc insertShopDBData() {\n\tdata := g.Slice{}\n\tyear := 2020\n\tfor i := 1; i <= 5; i++ {\n\t\tyear++\n\t\tdata = append(data, g.Map{\n\t\t\t\"id\":         i,\n\t\t\t\"sales_date\": fmt.Sprintf(\"%d-09-21\", year),\n\t\t\t\"amount\":     fmt.Sprintf(\"1%d.21\", i),\n\t\t})\n\t}\n\t_, err := db3.Model(\"dbx_order\").Ctx(ctx).Data(data).Insert()\n\tif err != nil {\n\t\tgtest.Error(err)\n\t}\n}\nfunc dropShopDBTable() {\n\tif _, err := db3.Exec(ctx, \"DROP TABLE IF EXISTS `dbx_order`\"); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_configNodeToSource(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfigNode := &gdb.ConfigNode{\n\t\t\tHost:     \"/tmp/mysql.sock\",\n\t\t\tPort:     \"\",\n\t\t\tUser:     \"username\",\n\t\t\tPass:     \"password\",\n\t\t\tName:     \"dbname\",\n\t\t\tType:     \"mysql\",\n\t\t\tProtocol: \"unix\",\n\t\t}\n\t\tsource := configNodeToSource(configNode)\n\t\tt.Assert(source, \"username:password@unix(/tmp/mysql.sock)/dbname?charset=\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// https://github.com/gogf/gf/issues/1380\nfunc Test_Issue1380(t *testing.T) {\n\ttype GiftImage struct {\n\t\tUid    string `json:\"uid\"`\n\t\tUrl    string `json:\"url\"`\n\t\tStatus string `json:\"status\"`\n\t\tName   string `json:\"name\"`\n\t}\n\n\ttype GiftComment struct {\n\t\tName     string `json:\"name\"`\n\t\tField    string `json:\"field\"`\n\t\tRequired bool   `json:\"required\"`\n\t}\n\n\ttype Prop struct {\n\t\tName   string   `json:\"name\"`\n\t\tValues []string `json:\"values\"`\n\t}\n\n\ttype Sku struct {\n\t\tGiftId      int64  `json:\"gift_id\"`\n\t\tName        string `json:\"name\"`\n\t\tScorePrice  int    `json:\"score_price\"`\n\t\tMarketPrice int    `json:\"market_price\"`\n\t\tCostPrice   int    `json:\"cost_price\"`\n\t\tStock       int    `json:\"stock\"`\n\t}\n\n\ttype Covers struct {\n\t\tList []GiftImage `json:\"list\"`\n\t}\n\n\ttype GiftEntity struct {\n\t\tId                   int64         `json:\"id\"`\n\t\tStoreId              int64         `json:\"store_id\"`\n\t\tGiftType             int           `json:\"gift_type\"`\n\t\tGiftName             string        `json:\"gift_name\"`\n\t\tDescription          string        `json:\"description\"`\n\t\tCovers               Covers        `json:\"covers\"`\n\t\tCover                string        `json:\"cover\"`\n\t\tGiftCategoryId       []int64       `json:\"gift_category_id\"`\n\t\tHasProps             bool          `json:\"has_props\"`\n\t\tOutSn                string        `json:\"out_sn\"`\n\t\tIsLimitSell          bool          `json:\"is_limit_sell\"`\n\t\tLimitSellType        int           `json:\"limit_sell_type\"`\n\t\tLimitSellCycle       string        `json:\"limit_sell_cycle\"`\n\t\tLimitSellCycleCount  int           `json:\"limit_sell_cycle_count\"`\n\t\tLimitSellCustom      bool          `json:\"limit_sell_custom\"`   // 只允许特定会员兑换\n\t\tLimitCustomerTags    []int64       `json:\"limit_customer_tags\"` // 允许兑换的成员\n\t\tScorePrice           int           `json:\"score_price\"`\n\t\tMarketPrice          float64       `json:\"market_price\"`\n\t\tCostPrice            int           `json:\"cost_price\"`\n\t\tStock                int           `json:\"stock\"`\n\t\tProps                []Prop        `json:\"props\"`\n\t\tSkus                 []Sku         `json:\"skus\"`\n\t\tExpressType          []string      `json:\"express_type\"`\n\t\tComments             []GiftComment `json:\"comments\"`\n\t\tContent              string        `json:\"content\"`\n\t\tAtLeastRechargeCount int           `json:\"at_least_recharge_count\"`\n\t\tStatus               int           `json:\"status\"`\n\t}\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\n\ttable := \"jfy_gift\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1380.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tentity = new(GiftEntity)\n\t\t\terr    = db.Model(table).Where(\"id\", 17).Scan(entity)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(entity.Skus), 2)\n\n\t\tt.Assert(entity.Skus[0].Name, \"red\")\n\t\tt.Assert(entity.Skus[0].Stock, 10)\n\t\tt.Assert(entity.Skus[0].GiftId, 1)\n\t\tt.Assert(entity.Skus[0].CostPrice, 80)\n\t\tt.Assert(entity.Skus[0].ScorePrice, 188)\n\t\tt.Assert(entity.Skus[0].MarketPrice, 388)\n\n\t\tt.Assert(entity.Skus[1].Name, \"blue\")\n\t\tt.Assert(entity.Skus[1].Stock, 100)\n\t\tt.Assert(entity.Skus[1].GiftId, 2)\n\t\tt.Assert(entity.Skus[1].CostPrice, 81)\n\t\tt.Assert(entity.Skus[1].ScorePrice, 200)\n\t\tt.Assert(entity.Skus[1].MarketPrice, 288)\n\n\t\tt.Assert(entity.Id, 17)\n\t\tt.Assert(entity.StoreId, 100004)\n\t\tt.Assert(entity.GiftType, 1)\n\t\tt.Assert(entity.GiftName, \"GIFT\")\n\t\tt.Assert(entity.Description, \"支持个性定制的父亲节老师长辈的专属礼物\")\n\t\tt.Assert(len(entity.Covers.List), 3)\n\t\tt.Assert(entity.OutSn, \"259402\")\n\t\tt.Assert(entity.LimitCustomerTags, \"[]\")\n\t\tt.Assert(entity.ScorePrice, 10)\n\t\tt.Assert(len(entity.Props), 1)\n\t\tt.Assert(len(entity.Comments), 2)\n\t\tt.Assert(entity.Status, 99)\n\t\tt.Assert(entity.Content, `<p>礼品详情</p>`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1934\nfunc Test_Issue1934(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\" id \", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1570\nfunc Test_Issue1570(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampMicroStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampMicroStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampMicroStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  name varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n  address varchar(45) NOT NULL,\n  PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id int(10) unsigned NOT NULL AUTO_INCREMENT,\n  uid int(10) unsigned NOT NULL,\n  score int(10) unsigned NOT NULL,\n  PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tFields(\"uid\").\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"\"})\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1401\nfunc Test_Issue1401(t *testing.T) {\n\tvar (\n\t\ttable1 = \"parcels\"\n\t\ttable2 = \"parcel_items\"\n\t)\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1401.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype NItem struct {\n\t\t\tId       int `json:\"id\"`\n\t\t\tParcelId int `json:\"parcel_id\"`\n\t\t}\n\n\t\ttype ParcelItem struct {\n\t\t\tgmeta.Meta `orm:\"table:parcel_items\"`\n\t\t\tNItem\n\t\t}\n\n\t\ttype ParcelRsp struct {\n\t\t\tgmeta.Meta `orm:\"table:parcels\"`\n\t\t\tId         int           `json:\"id\"`\n\t\t\tItems      []*ParcelItem `json:\"items\" orm:\"with:parcel_id=Id\"`\n\t\t}\n\n\t\tparcelDetail := &ParcelRsp{}\n\t\terr := db.Model(table1).With(parcelDetail.Items).Where(\"id\", 3).Scan(&parcelDetail)\n\t\tt.AssertNil(err)\n\t\tt.Assert(parcelDetail.Id, 3)\n\t\tt.Assert(len(parcelDetail.Items), 1)\n\t\tt.Assert(parcelDetail.Items[0].Id, 2)\n\t\tt.Assert(parcelDetail.Items[0].ParcelId, 3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1412\nfunc Test_Issue1412(t *testing.T) {\n\tvar (\n\t\ttable1 = \"parcels\"\n\t\ttable2 = \"items\"\n\t)\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1412.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Items struct {\n\t\t\tgmeta.Meta `orm:\"table:items\"`\n\t\t\tId         int    `json:\"id\"`\n\t\t\tName       string `json:\"name\"`\n\t\t}\n\n\t\ttype ParcelRsp struct {\n\t\t\tgmeta.Meta `orm:\"table:parcels\"`\n\t\t\tId         int   `json:\"id\"`\n\t\t\tItemId     int   `json:\"item_id\"`\n\t\t\tItems      Items `json:\"items\" orm:\"with:Id=ItemId\"`\n\t\t}\n\n\t\tentity := &ParcelRsp{}\n\t\terr := db.Model(\"parcels\").With(Items{}).Where(\"id=3\").Scan(&entity)\n\t\tt.AssertNil(err)\n\t\tt.Assert(entity.Id, 3)\n\t\tt.Assert(entity.ItemId, 0)\n\t\tt.Assert(entity.Items.Id, 0)\n\t\tt.Assert(entity.Items.Name, \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Items struct {\n\t\t\tgmeta.Meta `orm:\"table:items\"`\n\t\t\tId         int    `json:\"id\"`\n\t\t\tName       string `json:\"name\"`\n\t\t}\n\n\t\ttype ParcelRsp struct {\n\t\t\tgmeta.Meta `orm:\"table:parcels\"`\n\t\t\tId         int   `json:\"id\"`\n\t\t\tItemId     int   `json:\"item_id\"`\n\t\t\tItems      Items `json:\"items\" orm:\"with:Id=ItemId\"`\n\t\t}\n\n\t\tentity := &ParcelRsp{}\n\t\terr := db.Model(\"parcels\").With(Items{}).Where(\"id=30000\").Scan(&entity)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(entity.Id, 0)\n\t\tt.Assert(entity.ItemId, 0)\n\t\tt.Assert(entity.Items.Id, 0)\n\t\tt.Assert(entity.Items.Name, \"\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1002\nfunc Test_Issue1002(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tresult, err := db.Model(table).Data(g.Map{\n\t\t\"id\":          1,\n\t\t\"passport\":    \"port_1\",\n\t\t\"password\":    \"pass_1\",\n\t\t\"nickname\":    \"name_2\",\n\t\t\"create_time\": \"2020-10-27 19:03:33\",\n\t}).Insert()\n\tgtest.AssertNil(err)\n\tn, _ := result.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// where + string.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + string arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", \"2020-10-27 19:03:32\", \"2020-10-27 19:03:34\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + gtime.Time arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", gtime.New(\"2020-10-27 19:03:32\"), gtime.New(\"2020-10-27 19:03:34\")).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + time.Time arguments, UTC.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:32\")\n\t\tt2, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:34\")\n\t\t{\n\t\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", t1, t2).Value()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v.Int(), 1)\n\t\t}\n\t})\n\t// where + time.Time arguments, +8.\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\t// Change current timezone to +8 zone.\n\t//\tlocation, err := time.LoadLocation(\"Asia/Shanghai\")\n\t//\tt.AssertNil(err)\n\t//\tt1, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", \"2020-10-27 19:03:32\", location)\n\t//\tt2, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", \"2020-10-27 19:03:34\", location)\n\t//\t{\n\t//\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", t1, t2).Value()\n\t//\t\tt.AssertNil(err)\n\t//\t\tt.Assert(v.Int(), 1)\n\t//\t}\n\t//\t{\n\t//\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", t1, t2).FindValue()\n\t//\t\tt.AssertNil(err)\n\t//\t\tt.Assert(v.Int(), 1)\n\t//\t}\n\t//\t{\n\t//\t\tv, err := db.Model(table).Where(\"create_time>? and create_time<?\", t1, t2).FindValue(\"id\")\n\t//\t\tt.AssertNil(err)\n\t//\t\tt.Assert(v.Int(), 1)\n\t//\t}\n\t// })\n}\n\n// https://github.com/gogf/gf/issues/1700\nfunc Test_Issue1700(t *testing.T) {\n\ttable := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id         int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        user_id    int(10) unsigned NOT NULL,\n\t        UserId    int(10) unsigned NOT NULL,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId     int `orm:\"id\"`\n\t\t\tUserid int `orm:\"user_id\"`\n\t\t\tUserId int `orm:\"UserId\"`\n\t\t}\n\t\t_, err := db.Model(table).Data(User{\n\t\t\tId:     1,\n\t\t\tUserid: 2,\n\t\t\tUserId: 3,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one, g.Map{\n\t\t\t\"id\":      1,\n\t\t\t\"user_id\": 2,\n\t\t\t\"UserId\":  3,\n\t\t})\n\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tvar user *User\n\t\t\terr = db.Model(table).Scan(&user)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(user.Id, 1)\n\t\t\tt.Assert(user.Userid, 2)\n\t\t\tt.Assert(user.UserId, 3)\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1701\nfunc Test_Issue1701(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(gdb.Raw(\"if(id=1,100,null)\")).WherePri(1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), 100)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1733\nfunc Test_Issue1733(t *testing.T) {\n\ttable := \"user_\" + guid.S()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id int(8) unsigned zerofill NOT NULL AUTO_INCREMENT,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\t\"id\": i,\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\t\t}\n\n\t\tall, err := db.Model(table).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 10)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.Assert(all[i][\"id\"].Int(), i+1)\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2012\nfunc Test_Issue2012(t *testing.T) {\n\ttable := \"time_only_\" + guid.S()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s(\n\t\t\tid int(8) unsigned zerofill NOT NULL AUTO_INCREMENT,\n\t\t\ttime_only time,\n\t\t\tPRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype TimeOnly struct {\n\t\tId       int         `json:\"id\"`\n\t\tTimeOnly *gtime.Time `json:\"timeOnly\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeOnly := gtime.New(\"15:04:05\")\n\t\tm := db.Model(table)\n\n\t\t_, err := m.Insert(TimeOnly{\n\t\t\tTimeOnly: gtime.New(timeOnly),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t_, err = m.Insert(g.Map{\n\t\t\t\"time_only\": timeOnly,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t_, err = m.Insert(\"time_only\", timeOnly)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2105\nfunc Test_Issue2105(t *testing.T) {\n\ttable := \"issue2105\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2105.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\ttype JsonItem struct {\n\t\tName  string `json:\"name,omitempty\"`\n\t\tValue string `json:\"value,omitempty\"`\n\t}\n\ttype Test struct {\n\t\tId   string      `json:\"id,omitempty\"`\n\t\tJson []*JsonItem `json:\"json,omitempty\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar list []*Test\n\t\terr := db.Model(table).Scan(&list)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(list), 2)\n\t\tt.Assert(len(list[0].Json), 0)\n\t\tt.Assert(len(list[1].Json), 3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2231\nfunc Test_Issue2231(t *testing.T) {\n\tvar (\n\t\tpattern = `(\\w+):([\\w\\-]*):(.*?)@(\\w+?)\\((.+?)\\)/{0,1}([^\\?]*)\\?{0,1}(.*)`\n\t\tlink    = `mysql:root:12345678@tcp(127.0.0.1:3306)/a正bc式?loc=Local&parseTime=true`\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmatch, err := gregex.MatchString(pattern, link)\n\t\tt.AssertNil(err)\n\t\tt.Assert(match[1], \"mysql\")\n\t\tt.Assert(match[2], \"root\")\n\t\tt.Assert(match[3], \"12345678\")\n\t\tt.Assert(match[4], \"tcp\")\n\t\tt.Assert(match[5], \"127.0.0.1:3306\")\n\t\tt.Assert(match[6], \"a正bc式\")\n\t\tt.Assert(match[7], \"loc=Local&parseTime=true\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2339\nfunc Test_Issue2339(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel1 := db.Model(table, \"u1\").Where(\"id between ? and ?\", 1, 9)\n\t\tmodel2 := db.Model(\"? as u2\", model1)\n\t\tmodel3 := db.Model(\"? as u3\", model2)\n\t\tall2, err := model2.WhereGT(\"id\", 6).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all2), 3)\n\t\tt.Assert(all2[0][\"id\"], 7)\n\n\t\tall3, err := model3.WhereGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all3), 2)\n\t\tt.Assert(all3[0][\"id\"], 8)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2356\nfunc Test_Issue2356(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"demo_\" + guid.S()\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`INSERT INTO %s (id) VALUES (18446744073709551615);`, table)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\n\t\tone, err := db.Model(table).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(one[\"id\"].Val(), uint64(18446744073709551615))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2338\nfunc Test_Issue2338(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := \"demo_\" + guid.S()\n\t\ttable2 := \"demo_\" + guid.S()\n\t\tif _, err := db.Schema(TestSchema1).Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n    id        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    nickname  varchar(45) DEFAULT NULL COMMENT 'User Nickname',\n    create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',\n    update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table1,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tif _, err := db.Schema(TestSchema2).Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n    id        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    nickname  varchar(45) DEFAULT NULL COMMENT 'User Nickname',\n    create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',\n    update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table2,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTableWithDb(db.Schema(TestSchema1), table1)\n\t\tdefer dropTableWithDb(db.Schema(TestSchema2), table2)\n\n\t\tvar err error\n\t\t_, err = db.Schema(TestSchema1).Model(table1).Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Schema(TestSchema2).Model(table2).Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_2\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\ttableName1 := fmt.Sprintf(`%s.%s`, TestSchema1, table1)\n\t\ttableName2 := fmt.Sprintf(`%s.%s`, TestSchema2, table2)\n\t\tall, err := db.Model(tableName1).As(`a`).\n\t\t\tLeftJoin(tableName2+\" b\", `a.id=b.id`).\n\t\t\tFields(`a.id`, `b.nickname`).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"nickname\"], \"name_2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := \"demo_\" + guid.S()\n\t\ttable2 := \"demo_\" + guid.S()\n\t\tif _, err := db.Schema(TestSchema1).Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n    id        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    nickname  varchar(45) DEFAULT NULL COMMENT 'User Nickname',\n    create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',\n    update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',\n    deleted_at datetime(6) DEFAULT NULL COMMENT 'Deleted Time',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table1,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tif _, err := db.Schema(TestSchema2).Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n    id        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    nickname  varchar(45) DEFAULT NULL COMMENT 'User Nickname',\n    create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',\n    update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',\n    deleted_at datetime(6) DEFAULT NULL COMMENT 'Deleted Time',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table2,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTableWithDb(db.Schema(TestSchema1), table1)\n\t\tdefer dropTableWithDb(db.Schema(TestSchema2), table2)\n\n\t\tvar err error\n\t\t_, err = db.Schema(TestSchema1).Model(table1).Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Schema(TestSchema2).Model(table2).Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_2\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\ttableName1 := fmt.Sprintf(`%s.%s`, TestSchema1, table1)\n\t\ttableName2 := fmt.Sprintf(`%s.%s`, TestSchema2, table2)\n\t\tall, err := db.Model(tableName1).As(`a`).\n\t\t\tLeftJoin(tableName2+\" b\", `a.id=b.id`).\n\t\t\tFields(`a.id`, `b.nickname`).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"nickname\"], \"name_2\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2427\nfunc Test_Issue2427(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"demo_\" + guid.S()\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n    id        int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',\n    passport  varchar(45) NOT NULL COMMENT 'User Passport',\n    password  varchar(45) NOT NULL COMMENT 'User Password',\n    nickname  varchar(45) NOT NULL COMMENT 'User Nickname',\n    create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',\n    update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, table,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table)\n\n\t\t_, err1 := db.Model(table).Delete()\n\t\tt.Assert(err1, `there should be WHERE condition statement for DELETE operation`)\n\n\t\t_, err2 := db.Model(table).Where(g.Map{}).Delete()\n\t\tt.Assert(err2, `there should be WHERE condition statement for DELETE operation`)\n\n\t\t_, err3 := db.Model(table).Where(1).Delete()\n\t\tt.AssertNil(err3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2561\nfunc Test_Issue2561(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       2,\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       3,\n\t\t\t\tPassword: \"pass_3\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\t// m, _ := result.LastInsertId() // TODO: The order of LastInsertId cannot be guaranteed\n\t\t// t.Assert(m, 3)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `1`)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], ``)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `2`)\n\t\tt.Assert(one[`passport`], ``)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\n\t\tone, err = db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], `3`)\n\t\tt.Assert(one[`passport`], ``)\n\t\tt.Assert(one[`password`], `pass_3`)\n\t\tt.Assert(one[`nickname`], ``)\n\t\tt.Assert(one[`create_time`], ``)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2439\nfunc Test_Issue2439(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2439.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"a\")\n\t\tdefer dropTable(\"b\")\n\t\tdefer dropTable(\"c\")\n\n\t\torm := db.Model(\"a\")\n\t\torm = orm.InnerJoin(\n\t\t\t\"c\", \"a.id=c.id\",\n\t\t)\n\t\torm = orm.InnerJoinOnField(\"b\", \"id\")\n\t\twhereFormat := fmt.Sprintf(\n\t\t\t\"(`%s`.`%s` LIKE ?) \",\n\t\t\t\"b\", \"name\",\n\t\t)\n\t\torm = orm.WhereOrf(\n\t\t\twhereFormat,\n\t\t\t\"%a%\",\n\t\t)\n\t\tr, err := orm.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 2)\n\t\tt.Assert(r[0][\"name\"], \"a\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2782\nfunc Test_Issue2787(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(\"user\")\n\n\t\tcondWhere, _ := m.Builder().\n\t\t\tWhere(\"id\", \"\").\n\t\t\tWhere(m.Builder().\n\t\t\t\tWhere(\"nickname\", \"foo\").\n\t\t\t\tWhereOr(\"password\", \"abc123\")).\n\t\t\tWhere(\"passport\", \"pp\").\n\t\t\tBuild()\n\t\tt.Assert(condWhere, \"(`id`=?) AND (((`nickname`=?) OR (`password`=?))) AND (`passport`=?)\")\n\n\t\tcondWhere, _ = m.OmitEmpty().Builder().\n\t\t\tWhere(\"id\", \"\").\n\t\t\tWhere(m.Builder().\n\t\t\t\tWhere(\"nickname\", \"foo\").\n\t\t\t\tWhereOr(\"password\", \"abc123\")).\n\t\t\tWhere(\"passport\", \"pp\").\n\t\t\tBuild()\n\t\tt.Assert(condWhere, \"((`nickname`=?) OR (`password`=?)) AND (`passport`=?)\")\n\n\t\tcondWhere, _ = m.OmitEmpty().Builder().\n\t\t\tWhere(m.Builder().\n\t\t\t\tWhere(\"nickname\", \"foo\").\n\t\t\t\tWhereOr(\"password\", \"abc123\")).\n\t\t\tWhere(\"id\", \"\").\n\t\t\tWhere(\"passport\", \"pp\").\n\t\t\tBuild()\n\t\tt.Assert(condWhere, \"((`nickname`=?) OR (`password`=?)) AND (`passport`=?)\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2907\nfunc Test_Issue2907(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\torm = db.Model(table)\n\t\t\terr error\n\t\t)\n\n\t\torm = orm.WherePrefixNotIn(\n\t\t\ttable,\n\t\t\t\"id\",\n\t\t\t[]int{\n\t\t\t\t1,\n\t\t\t\t2,\n\t\t\t},\n\t\t)\n\t\tall, err := orm.OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize-2)\n\t\tt.Assert(all[0][\"id\"], 3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3086\nfunc Test_Issue3086(t *testing.T) {\n\ttable := \"issue3086_user\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3086.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t},\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Batch(10).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       3,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       4,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Batch(10).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 2)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3204\nfunc Test_Issue3204(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// where\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any `orm:\"id,omitempty\"`\n\t\t\tPassport   any `orm:\"passport,omitempty\"`\n\t\t\tPassword   any `orm:\"password,omitempty\"`\n\t\t\tNickname   any `orm:\"nickname,omitempty\"`\n\t\t\tCreateTime any `orm:\"create_time,omitempty\"`\n\t\t}\n\t\twhere := User{\n\t\t\tId:       2,\n\t\t\tPassport: \"\",\n\t\t}\n\t\tall, err := db.Model(table).Where(where).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n\t// data\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any `orm:\"id,omitempty\"`\n\t\t\tPassport   any `orm:\"passport,omitempty\"`\n\t\t\tPassword   any `orm:\"password,omitempty\"`\n\t\t\tNickname   any `orm:\"nickname,omitempty\"`\n\t\t\tCreateTime any `orm:\"create_time,omitempty\"`\n\t\t}\n\t\tvar (\n\t\t\terr      error\n\t\t\tsqlArray []string\n\t\t\tinsertId int64\n\t\t\tdata     = User{\n\t\t\t\tId:       20,\n\t\t\t\tPassport: \"passport_20\",\n\t\t\t\tPassword: \"\",\n\t\t\t}\n\t\t)\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tinsertId, err = db.Ctx(ctx).Model(table).Data(data).InsertAndGetId()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(insertId, 20)\n\t\tt.Assert(\n\t\t\tgstr.Contains(sqlArray[len(sqlArray)-1], \"(`id`,`passport`) VALUES(20,'passport_20')\"),\n\t\t\ttrue,\n\t\t)\n\t})\n\t// update data\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any `orm:\"id,omitempty\"`\n\t\t\tPassport   any `orm:\"passport,omitempty\"`\n\t\t\tPassword   any `orm:\"password,omitempty\"`\n\t\t\tNickname   any `orm:\"nickname,omitempty\"`\n\t\t\tCreateTime any `orm:\"create_time,omitempty\"`\n\t\t}\n\t\tvar (\n\t\t\terr      error\n\t\t\tsqlArray []string\n\t\t\tdata     = User{\n\t\t\t\tPassport: \"passport_1\",\n\t\t\t\tPassword: \"\",\n\t\t\t\tNickname: \"\",\n\t\t\t}\n\t\t)\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\t_, err = db.Ctx(ctx).Model(table).Data(data).WherePri(1).Update()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tgstr.Contains(sqlArray[len(sqlArray)-1], \"SET `passport`='passport_1' WHERE `id`=1\"),\n\t\t\ttrue,\n\t\t)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3218\nfunc Test_Issue3218(t *testing.T) {\n\ttable := \"issue3218_sys_config\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3218.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype SysConfigInfo struct {\n\t\t\tName  string            `json:\"name\"`\n\t\t\tValue map[string]string `json:\"value\"`\n\t\t}\n\t\tvar configData *SysConfigInfo\n\t\terr := db.Model(table).Scan(&configData)\n\t\tt.AssertNil(err)\n\t\tt.Assert(configData, &SysConfigInfo{\n\t\t\tName: \"site\",\n\t\t\tValue: map[string]string{\n\t\t\t\t\"fixed_page\": \"\",\n\t\t\t\t\"site_name\":  \"22\",\n\t\t\t\t\"version\":    \"22\",\n\t\t\t\t\"banned_ip\":  \"22\",\n\t\t\t\t\"filings\":    \"2222\",\n\t\t\t},\n\t\t})\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2552\nfunc Test_Issue2552_ClearTableFieldsAll(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tshowTableKey := `SHOW FULL COLUMNS FROM`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.Background()\n\t\tsqlArray, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\t_, err := db.Model(table).Ctx(ctx).Insert(g.Map{\n\t\t\t\t\"passport\":    guid.S(),\n\t\t\t\t\"password\":    guid.S(),\n\t\t\t\t\"nickname\":    guid.S(),\n\t\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), true)\n\n\t\tctx = context.Background()\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tone, err := db.Model(table).Ctx(ctx).One()\n\t\t\tt.Assert(len(one), 6)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), false)\n\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\"alter table %s drop column `nickname`\", table))\n\t\tt.AssertNil(err)\n\n\t\terr = db.GetCore().ClearTableFieldsAll(ctx)\n\t\tt.AssertNil(err)\n\n\t\tctx = context.Background()\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tone, err := db.Model(table).Ctx(ctx).One()\n\t\t\tt.Assert(len(one), 5)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2552\nfunc Test_Issue2552_ClearTableFields(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tshowTableKey := `SHOW FULL COLUMNS FROM`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.Background()\n\t\tsqlArray, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\t_, err := db.Model(table).Ctx(ctx).Insert(g.Map{\n\t\t\t\t\"passport\":    guid.S(),\n\t\t\t\t\"password\":    guid.S(),\n\t\t\t\t\"nickname\":    guid.S(),\n\t\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), true)\n\n\t\tctx = context.Background()\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tone, err := db.Model(table).Ctx(ctx).One()\n\t\t\tt.Assert(len(one), 6)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), false)\n\n\t\t_, err = db.Exec(ctx, fmt.Sprintf(\"alter table %s drop column `nickname`\", table))\n\t\tt.AssertNil(err)\n\n\t\terr = db.GetCore().ClearTableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\tctx = context.Background()\n\t\tsqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tone, err := db.Model(table).Ctx(ctx).One()\n\t\t\tt.Assert(len(one), 5)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(gstr.Join(sqlArray, \"|\"), showTableKey), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2643\nfunc Test_Issue2643(t *testing.T) {\n\ttable := \"issue2643\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2643.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\texpectKey1 = \"SELECT s.name,replace(concat_ws(',',lpad(s.id, 6, '0'),s.name),',','') `code` FROM `issue2643` AS s\"\n\t\t\texpectKey2 = \"SELECT CASE WHEN dept='物资部' THEN '物资部' ELSE '其他' END dept,sum(s.value) FROM `issue2643` AS s GROUP BY CASE WHEN dept='物资部' THEN '物资部' ELSE '其他' END\"\n\t\t)\n\t\tsqlArray, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tdb.Ctx(ctx).Model(table).As(\"s\").Fields(\n\t\t\t\t\"s.name\",\n\t\t\t\t\"replace(concat_ws(',',lpad(s.id, 6, '0'),s.name),',','') `code`\",\n\t\t\t).All()\n\t\t\tdb.Ctx(ctx).Model(table).As(\"s\").Fields(\n\t\t\t\t\"CASE WHEN dept='物资部' THEN '物资部' ELSE '其他' END dept\",\n\t\t\t\t\"sum(s.value)\",\n\t\t\t).Group(\"CASE WHEN dept='物资部' THEN '物资部' ELSE '其他' END\").All()\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t\tsqlContent := gstr.Join(sqlArray, \"\\n\")\n\t\tt.Assert(gstr.Contains(sqlContent, expectKey1), true)\n\t\tt.Assert(gstr.Contains(sqlContent, expectKey2), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3238\nfunc Test_Issue3238(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t_, err := db.Ctx(ctx).Model(table).Hook(gdb.HookHandler{\n\t\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tvar wg sync.WaitGroup\n\t\t\t\t\tfor _, record := range result {\n\t\t\t\t\t\twg.Add(1)\n\t\t\t\t\t\tgo func(record gdb.Record) {\n\t\t\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\t\t\tid, _ := db.Ctx(ctx).Model(table).WherePri(1).Value(`id`)\n\t\t\t\t\t\t\tnickname, _ := db.Ctx(ctx).Model(table).WherePri(1).Value(`nickname`)\n\t\t\t\t\t\t\tt.Assert(id.Int(), 1)\n\t\t\t\t\t\t\tt.Assert(nickname.String(), \"name_1\")\n\t\t\t\t\t\t}(record)\n\t\t\t\t\t}\n\t\t\t\t\twg.Wait()\n\t\t\t\t\treturn\n\t\t\t\t},\n\t\t\t},\n\t\t\t).All()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3649\nfunc Test_Issue3649(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsql, err := gdb.CatchSQL(context.Background(), func(ctx context.Context) (err error) {\n\t\t\tuser := db.Model(table).Ctx(ctx)\n\t\t\t_, err = user.Where(\"create_time = ?\", gdb.Raw(\"now()\")).WhereLT(\"create_time\", gdb.Raw(\"now()\")).Count()\n\t\t\treturn\n\t\t})\n\t\tt.AssertNil(err)\n\t\tsqlStr := fmt.Sprintf(\"SELECT COUNT(1) FROM `%s` WHERE (create_time = now()) AND (`create_time` < now())\", table)\n\t\tt.Assert(sql[0], sqlStr)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3754\nfunc Test_Issue3754(t *testing.T) {\n\ttable := \"issue3754\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3754.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfieldsEx := []string{\"delete_at\", \"create_at\", \"update_at\"}\n\t\t// Insert.\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).FieldsEx(fieldsEx).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"create_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"update_at\"].String(), \"\")\n\n\t\t// Update.\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).FieldsEx(fieldsEx).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"update_at\"].String(), \"\")\n\n\t\t// FieldsEx does not affect Delete operation.\n\t\tr, err = db.Model(table).FieldsEx(fieldsEx).WherePri(1).Delete()\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"id\"].Int(), 1)\n\t\tt.Assert(oneDeleteUnscoped[\"name\"].String(), \"name_1000\")\n\t\tt.AssertNE(oneDeleteUnscoped[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneDeleteUnscoped[\"create_at\"].String(), \"\")\n\t\tt.Assert(oneDeleteUnscoped[\"update_at\"].String(), \"\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3626\nfunc Test_Issue3626(t *testing.T) {\n\ttable := \"issue3626\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3626.sql`), \";\")\n\tdefer dropTable(table)\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\t// Insert.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t})\n\n\tvar (\n\t\tcacheKey  = guid.S()\n\t\tcacheFunc = func(duration time.Duration) gdb.HookHandler {\n\t\t\treturn gdb.HookHandler{\n\t\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\t\tget, err := db.GetCache().Get(ctx, cacheKey)\n\t\t\t\t\tif err == nil && !get.IsEmpty() {\n\t\t\t\t\t\terr = get.Scan(&result)\n\t\t\t\t\t\tif err == nil {\n\t\t\t\t\t\t\treturn result, nil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif result == nil || result.Len() < 1 {\n\t\t\t\t\t\tresult = make(gdb.Result, 0)\n\t\t\t\t\t}\n\t\t\t\t\t_ = db.GetCache().Set(ctx, cacheKey, result, duration)\n\t\t\t\t\treturn\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer db.GetCache().Clear(ctx)\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t\tcount, err = db.Model(table).Hook(cacheFunc(time.Hour)).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t\tcount, err = db.Model(table).Hook(cacheFunc(time.Hour)).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3932\nfunc Test_Issue3932(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Order(\"id\", \"desc\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Order(\"id desc\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Order(\"id desc, nickname asc\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Order(\"id desc\", \"nickname asc\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Order(\"id desc\").Order(\"nickname asc\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 10)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3968\nfunc Test_Issue3968(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar hook = gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif result != nil {\n\t\t\t\t\tfor i := range result {\n\t\t\t\t\t\tresult[i][\"location\"] = gvar.New(\"ny\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t}\n\t\tvar (\n\t\t\tcount  int\n\t\t\tresult gdb.Result\n\t\t)\n\t\terr := db.Model(table).Hook(hook).ScanAndCount(&result, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 10)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3915\nfunc Test_Issue3915(t *testing.T) {\n\ttable := \"issue3915\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3915.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//db.SetDebug(true)\n\t\tall, err := db.Model(table).Where(\"a < b\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\tall, err = db.Model(table).Where(gdb.Raw(\"a < b\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\tall, err = db.Model(table).WhereLT(\"a\", gdb.Raw(\"`b`\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t//db.SetDebug(true)\n\t\tall, err := db.Model(table).Where(\"a > b\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\n\t\tall, err = db.Model(table).Where(gdb.Raw(\"a > b\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\n\t\tall, err = db.Model(table).WhereGT(\"a\", gdb.Raw(\"`b`\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n}\n\ntype RoleBase struct {\n\tgmeta.Meta  `orm:\"table:sys_role\"`\n\tName        string      `json:\"name\"           description:\"角色名称\"     `\n\tCode        string      `json:\"code\"           description:\"角色 code\"    `\n\tDescription string      `json:\"description\"    description:\"描述信息\"     `\n\tWeight      int         `json:\"weight\"         description:\"排序\"         `\n\tStatusId    int         `json:\"statusId\"       description:\"发布状态\"     `\n\tCreatedAt   *gtime.Time `json:\"createdAt\"      description:\"\"             `\n\tUpdatedAt   *gtime.Time `json:\"updatedAt\"      description:\"\"             `\n}\n\ntype Role struct {\n\tgmeta.Meta `orm:\"table:sys_role\"`\n\tRoleBase\n\tId     uint    `json:\"id\"          description:\"\"`\n\tStatus *Status `json:\"status\"       description:\"发布状态\"     orm:\"with:id=status_id\"        `\n}\n\ntype StatusBase struct {\n\tgmeta.Meta `orm:\"table:sys_status\"`\n\tEn         string `json:\"en\"        description:\"英文名称\"    `\n\tCn         string `json:\"cn\"        description:\"中文名称\"    `\n\tWeight     int    `json:\"weight\"    description:\"排序权重\"    `\n}\n\ntype Status struct {\n\tgmeta.Meta `orm:\"table:sys_status\"`\n\tStatusBase\n\tId uint `json:\"id\"          description:\"\"`\n}\n\n// https://github.com/gogf/gf/issues/2119\nfunc Test_Issue2119(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\n\t\t\t\"sys_role\",\n\t\t\t\"sys_status\",\n\t\t}\n\n\t\tdefer dropTable(tables[0])\n\t\tdefer dropTable(tables[1])\n\t\t_ = tables\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2119.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\t_, err := db.Exec(ctx, v)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\troles := make([]*Role, 0)\n\t\terr := db.Ctx(context.Background()).Model(&Role{}).WithAll().Scan(&roles)\n\t\tt.AssertNil(err)\n\t\texpectStatus := []*Status{\n\t\t\t{\n\t\t\t\tStatusBase: StatusBase{\n\t\t\t\t\tEn:     \"undecided\",\n\t\t\t\t\tCn:     \"未决定\",\n\t\t\t\t\tWeight: 800,\n\t\t\t\t},\n\t\t\t\tId: 2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tStatusBase: StatusBase{\n\t\t\t\t\tEn:     \"on line\",\n\t\t\t\t\tCn:     \"上线\",\n\t\t\t\t\tWeight: 900,\n\t\t\t\t},\n\t\t\t\tId: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tStatusBase: StatusBase{\n\t\t\t\t\tEn:     \"on line\",\n\t\t\t\t\tCn:     \"上线\",\n\t\t\t\t\tWeight: 900,\n\t\t\t\t},\n\t\t\t\tId: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tStatusBase: StatusBase{\n\t\t\t\t\tEn:     \"on line\",\n\t\t\t\t\tCn:     \"上线\",\n\t\t\t\t\tWeight: 900,\n\t\t\t\t},\n\t\t\t\tId: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tStatusBase: StatusBase{\n\t\t\t\t\tEn:     \"on line\",\n\t\t\t\t\tCn:     \"上线\",\n\t\t\t\t\tWeight: 900,\n\t\t\t\t},\n\t\t\t\tId: 1,\n\t\t\t},\n\t\t}\n\n\t\tfor i := 0; i < len(roles); i++ {\n\t\t\tt.Assert(roles[i].Status, expectStatus[i])\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4034\nfunc Test_Issue4034(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := \"issue4034\"\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4034.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\t_, err := db.Exec(ctx, v)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table)\n\n\t\terr := issue4034SaveDeviceAndToken(ctx, table)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc issue4034SaveDeviceAndToken(ctx context.Context, table string) error {\n\treturn db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\tif err := issue4034SaveAppDevice(ctx, table, tx); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc issue4034SaveAppDevice(ctx context.Context, table string, tx gdb.TX) error {\n\t_, err := db.Model(table).Safe().Ctx(ctx).TX(tx).Data(g.Map{\n\t\t\"passport\": \"111\",\n\t\t\"password\": \"222\",\n\t\t\"nickname\": \"333\",\n\t}).Save()\n\treturn err\n}\n\n// https://github.com/gogf/gf/issues/4086\nfunc Test_Issue4086(t *testing.T) {\n\ttable := \"issue4086\"\n\tdefer dropTable(table)\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4086.sql`), \";\")\n\tfor _, v := range array {\n\t\t_, err := db.Exec(ctx, v)\n\t\tgtest.AssertNil(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64   `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds []int64 `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       []int64 `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: []int64{584, 585},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: []int64{},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64     `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds []int64   `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       []float32 `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: []int64{584, 585},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: []int64{},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64    `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds []int64  `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       []string `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: []int64{584, 585},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: []int64{},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64   `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds []int64 `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       []any   `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: []int64{584, 585},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: []int64{},\n\t\t\t\tPhotos:       nil,\n\t\t\t},\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64   `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds []int64 `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       string  `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: []int64{584, 585},\n\t\t\t\tPhotos:       \"null\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: []int64{},\n\t\t\t\tPhotos:       \"\",\n\t\t\t},\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ProxyParam struct {\n\t\t\tProxyId      int64           `json:\"proxyId\" orm:\"proxy_id\"`\n\t\t\tRecommendIds string          `json:\"recommendIds\" orm:\"recommend_ids\"`\n\t\t\tPhotos       json.RawMessage `json:\"photos\" orm:\"photos\"`\n\t\t}\n\n\t\tvar proxyParamList []*ProxyParam\n\t\terr := db.Model(table).Ctx(ctx).Scan(&proxyParamList)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proxyParamList), 2)\n\t\tt.Assert(proxyParamList, []*ProxyParam{\n\t\t\t{\n\t\t\t\tProxyId:      1,\n\t\t\t\tRecommendIds: \"[584, 585]\",\n\t\t\t\tPhotos:       json.RawMessage(\"null\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tProxyId:      2,\n\t\t\t\tRecommendIds: \"[]\",\n\t\t\t\tPhotos:       json.RawMessage(\"null\"),\n\t\t\t},\n\t\t})\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4500\n// Raw() Count ignores Where condition\nfunc Test_Issue4500(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Test 1: Raw SQL with WHERE + external Where condition + Count\n\t// This tests that formatCondition correctly uses AND when Raw SQL already has WHERE\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw SQL: id IN (1,5,7,8,9,10) = 6 records\n\t\t// Where: id < 8 filters to {1,5,7} = 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 2: Raw SQL without WHERE + external Where condition + Count\n\t// This tests that formatCondition correctly adds WHERE\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s\", table)).\n\t\t\tWhereLT(\"id\", 5).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw SQL: all 10 records\n\t\t// Where: id < 5 = {1,2,3,4} = 4 records\n\t\tt.Assert(count, 4)\n\t})\n\n\t// Test 3: Raw + Where + ScanAndCount\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t}\n\t\tvar users []User\n\t\tvar total int\n\t\terr := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tScanAndCount(&users, &total, false)\n\t\tt.AssertNil(err)\n\t\t// Both scan result and count should respect Where condition\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(total, 3)\n\t})\n\n\t// Test 4: Raw + multiple Where conditions + Count\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id > ?\", table), 0).\n\t\t\tWhereLT(\"id\", 5).\n\t\t\tWhereGTE(\"id\", 2).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw: id > 0 (all 10 records)\n\t\t// Where: id < 5 AND id >= 2 = {2, 3, 4} = 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 5: Raw SQL with no external Where + Count (baseline test)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 2, 3}).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Should count 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 6: Verify All() still works correctly with Raw + Where\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4697\nfunc Test_Issue4697(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Fields(\"\") should be treated as Fields() and select all fields\n\t\tresult, err := db.Model(table).Fields(\"\").Limit(1).All()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\t// Should have all fields (id, passport, password, nickname, create_time, create_date)\n\t\tt.Assert(len(result[0]), 6)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Fields(\"\", \"id\") should ignore empty string and only select \"id\"\n\t\tresult, err := db.Model(table).Fields(\"\", \"id\").Limit(1).All()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(len(result[0]), 1)\n\t\tt.AssertNE(result[0][\"id\"], nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Fields(\"id\", \"\", \"nickname\") should ignore empty string\n\t\tresult, err := db.Model(table).Fields(\"id\", \"\", \"nickname\").Limit(1).All()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(len(result[0]), 2)\n\t\tt.AssertNE(result[0][\"id\"], nil)\n\t\tt.AssertNE(result[0][\"nickname\"], nil)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4698\nfunc Test_Issue4698(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Test 1: AllAndCount with multiple fields should generate valid COUNT SQL\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.AssertNE(result[0][\"id\"], nil)\n\t\tt.AssertNE(result[0][\"nickname\"], nil)\n\t\tt.Assert(result[0][\"passport\"], nil)\n\t})\n\n\t// Test 2: AllAndCount(false) with multiple fields\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\n\t// Test 3: ScanAndCount with multiple fields\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tvar users []User\n\t\tvar total int\n\t\terr := db.Model(table).Fields(\"id, nickname\").ScanAndCount(&users, &total, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(total, TableSize)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.AssertGT(users[0].Id, 0)\n\t\tt.AssertNE(users[0].Nickname, \"\")\n\t})\n\n\t// Test 4: AllAndCount with single field and useFieldForCount=true\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(len(result[0]), 1)\n\t})\n\n\t// Test 5: AllAndCount with Where condition\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").Where(\"id<?\", 5).AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 4)\n\t\tt.Assert(len(result), 4)\n\t})\n\n\t// Test 6: Distinct + AllAndCount(false) should use COUNT(1), not COUNT(DISTINCT 1)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"nickname\").Distinct().AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\t// COUNT(1) should return total rows, not distinct count\n\t\tt.Assert(count, TableSize)\n\t\tt.AssertGT(len(result), 0)\n\t})\n\n\t// Test 7: Distinct + AllAndCount(true) with single field should use COUNT(DISTINCT nickname)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, count, err := db.Model(table).Fields(\"nickname\").Distinct().AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\t// COUNT(DISTINCT nickname) should return distinct count\n\t\tt.Assert(count, TableSize)\n\t})\n\n\t// Test 8: Distinct + multiple fields + AllAndCount(true) should fallback to COUNT(1)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"id, nickname\").Distinct().AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:       3,\n\t\t\tUid:      3,\n\t\t\tPassport: \"t3\",\n\t\t\tPassword: \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname: \"name_3\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_Model_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Insert_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2020-10-10 20:09:18.334\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], \"2020-10-10 20:09:18\")\n\t\tt.Assert(one[\"nickname\"], data[\"nickname\"])\n\t})\n}\n\nfunc Test_Model_BatchInsertWithArrayStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tarray := garray.New()\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"uid\":         i,\n\t\t\t\t\"passport\":    fmt.Sprintf(\"t%d\", i),\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    fmt.Sprintf(\"name_%d\", i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := user.Data(array).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"uid\":         3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert, retrieving last insert auto-increment id.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\"passport\": \"t1\"},\n\t\t\t{\"passport\": \"t2\"},\n\t\t\t{\"passport\": \"t3\"},\n\t\t\t{\"passport\": \"t4\"},\n\t\t\t{\"passport\": \"t5\"},\n\t\t}).Batch(2).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 5)\n\t})\n\n\t// batch save\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Save()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize*2)\n\t})\n\n\t// batch replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Replace()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize*2)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t111\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T111\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// UPDATE...LIMIT\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"nickname\", \"T100\").Where(1).Order(\"id desc\").Limit(2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tv1, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 10).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v1.String(), \"T100\")\n\n\t\tv2, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 8).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), \"name_8\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_UpdateAndGetAffected(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn, err := db.Model(table).Data(\"nickname\", \"T100\").\n\t\t\tWhere(1).Order(\"id desc\").Limit(2).\n\t\t\tUpdateAndGetAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := md.Safe(true).Order(\"id DESC\").One()\n\t\tt.AssertNil(err)\n\n\t\tresult, err := md.Safe(true).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(2))\n\t\tt.Assert(record[\"id\"].Int(), 3)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Safe(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(false).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe().Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd1 := db.Model(table).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmd1 := db.Model(table).Where(\"id>\", 0).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tmd3 := md1.Where(\"id in (?)\", g.Slice{4, 5, 6})\n\n\t\t// 1,3\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 3)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// 4,5,6\n\t\tcount, err = md3.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\tall, err = md3.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"].Int(), 4)\n\t\tt.Assert(all[1][\"id\"].Int(), 5)\n\t\tt.Assert(all[2][\"id\"].Int(), 6)\n\n\t\tall, err = md3.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Fields(t *testing.T) {\n\ttableName1 := createInitTable()\n\tdefer dropTable(tableName1)\n\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id         int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        name       varchar(45) NULL,\n\t\t\tage        int(10) unsigned,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u\").Fields(\"u.passport,u.id\").Where(\"u.id<2\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName1, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.id AS u2id\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id,nickname\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Value_WithCache(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.MapStrAny{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, 1),\n\t\t\t\"password\": fmt.Sprintf(`password_%d`, 1),\n\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, 1),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Value(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 1)\n\t})\n}\n\nfunc Test_Model_Count_WithCache(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.MapStrAny{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, 1),\n\t\t\t\"password\": fmt.Sprintf(`password_%d`, 1),\n\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, 1),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_Count_All_WithCache(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.MapStrAny{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, 1),\n\t\t\t\"password\": fmt.Sprintf(`password_%d`, 1),\n\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, 1),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.MapStrAny{\n\t\t\t\"id\":       2,\n\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, 2),\n\t\t\t\"password\": fmt.Sprintf(`password_%d`, 2),\n\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, 2),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_CountColumn_WithCache(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.MapStrAny{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, 1),\n\t\t\t\"password\": fmt.Sprintf(`password_%d`, 1),\n\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, 1),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 1).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second * 10,\n\t\t\tForce:    false,\n\t\t}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Struct_CustomType(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype MyInt int\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         MyInt\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_Model_Structs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Auto create struct slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Where(\"id<0\").Scan(&users)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_StructsWithOrmTag(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tdbInvalid.SetDebug(true)\n\tdefer dbInvalid.SetDebug(false)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tUid      int `orm:\"id\"`\n\t\t\tPassport string\n\t\t\tPassword string     `orm:\"password\"`\n\t\t\tName     string     `orm:\"nick_name\"`\n\t\t\tTime     gtime.Time `orm:\"create_time\"`\n\t\t}\n\t\tvar (\n\t\t\tusers  []User\n\t\t\tbuffer = bytes.NewBuffer(nil)\n\t\t)\n\t\tdbInvalid.GetLogger().(*glog.Logger).SetWriter(buffer)\n\t\tdefer dbInvalid.GetLogger().(*glog.Logger).SetWriter(os.Stdout)\n\t\tdbInvalid.Model(table).Order(\"id asc\").Scan(&users)\n\t\t// fmt.Println(buffer.String())\n\t\tt.Assert(\n\t\t\tgstr.Contains(\n\t\t\t\tbuffer.String(),\n\t\t\t\t\"SELECT `id`,`Passport`,`password`,`nick_name`,`create_time` FROM `user\",\n\t\t\t),\n\t\t\ttrue,\n\t\t)\n\t})\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t}\n\t\ttype B struct {\n\t\t\tA\n\t\t\tNickName string\n\t\t}\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\ttype Response struct {\n\t\t\tUsers []User `json:\"users\"`\n\t\t}\n\t\tvar res Response\n\t\terr := db.Model(table).Scan(&res.Users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(res.Users, nil)\n\t})\n}\n\nfunc Test_Model_OrderBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(\"id DESC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), fmt.Sprintf(\"name_%d\", TableSize))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"NULL\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"field(id, 10,1,2,3,4,5,6,7,8,9)\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_10\")\n\t\tt.Assert(result[1][\"nickname\"].String(), \"name_1\")\n\t\tt.Assert(result[2][\"nickname\"].String(), \"name_2\")\n\t})\n}\n\nfunc Test_Model_GroupBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Group(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_Model_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(\"nickname=?\", \"test\").Where(\"id=?\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := make([]g.MapStrAny, 0)\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers = append(users, g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := garray.New()\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers.Append(g.MapStrAny{\n\t\t\t\t\"id\":       i,\n\t\t\t\t\"passport\": fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\": fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\": fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// DELETE...LIMIT\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(1).Limit(2).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize-2)\n\t})\n}\n\nfunc Test_Model_Offset(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(2).Offset(5).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(3, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t\tt.Assert(result[1][\"id\"], 8)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel := db.Model(table).Safe().Order(\"id\")\n\t\tall, err := model.Page(3, 3).All()\n\t\tcount, err := model.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], \"7\")\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Option_Map(t *testing.T) {\n\t// Insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, passport\").Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"1\",\n\t\t\t\"password\": \"1\",\n\t\t\t\"nickname\": \"1\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"password\"].String(), \"1\")\n\t\tt.AssertNE(one[\"nickname\"].String(), \"1\")\n\t\tt.Assert(one[\"passport\"].String(), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\t})\n\n\t// Replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\t})\n\n\t// Save\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, passport\").Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"1\",\n\t\t\t\"password\": \"1\",\n\t\t\t\"nickname\": \"1\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"password\"].String(), \"1\")\n\t\tt.AssertNE(one[\"nickname\"].String(), \"1\")\n\t\tt.Assert(one[\"passport\"].String(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tone, err = db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"].String(), \"0\")\n\t\tt.Assert(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\t})\n\n\t// Update\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tr, err := db.Model(table).Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmptyData().Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 2).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmpty().Fields(\"nickname\").Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 4).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().\n\t\t\tFields(\"password\").Data(g.Map{\n\t\t\t\"nickname\": \"\",\n\t\t\t\"passport\": \"123\",\n\t\t\t\"password\": \"456\",\n\t\t}).Where(\"id\", 5).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 5).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"], \"456\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"123\")\n\t})\n}\n\nfunc Test_Model_Option_List(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, password\").Data(g.List{\n\t\t\tg.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"1\",\n\t\t\t\t\"password\": \"1\",\n\t\t\t\t\"nickname\": \"1\",\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":       2,\n\t\t\t\t\"passport\": \"2\",\n\t\t\t\t\"password\": \"2\",\n\t\t\t\t\"nickname\": \"2\",\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t\tlist, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(list), 2)\n\t\tt.Assert(list[0][\"id\"].String(), \"1\")\n\t\tt.Assert(list[0][\"nickname\"].String(), \"\")\n\t\tt.Assert(list[0][\"passport\"].String(), \"\")\n\t\tt.Assert(list[0][\"password\"].String(), \"1\")\n\n\t\tt.Assert(list[1][\"id\"].String(), \"2\")\n\t\tt.Assert(list[1][\"nickname\"].String(), \"\")\n\t\tt.Assert(list[1][\"passport\"].String(), \"\")\n\t\tt.Assert(list[1][\"password\"].String(), \"2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Fields(\"id, password\").Data(g.List{\n\t\t\tg.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"1\",\n\t\t\t\t\"password\": 0,\n\t\t\t\t\"nickname\": \"1\",\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":       2,\n\t\t\t\t\"passport\": \"2\",\n\t\t\t\t\"password\": \"2\",\n\t\t\t\t\"nickname\": \"2\",\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t\tlist, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(list), 2)\n\t\tt.Assert(list[0][\"id\"].String(), \"1\")\n\t\tt.Assert(list[0][\"nickname\"].String(), \"\")\n\t\tt.Assert(list[0][\"passport\"].String(), \"\")\n\t\tt.Assert(list[0][\"password\"].String(), \"0\")\n\n\t\tt.Assert(list[1][\"id\"].String(), \"2\")\n\t\tt.Assert(list[1][\"nickname\"].String(), \"\")\n\t\tt.Assert(list[1][\"passport\"].String(), \"\")\n\t\tt.Assert(list[1][\"password\"].String(), \"2\")\n\t})\n}\n\nfunc Test_Model_OmitEmpty(t *testing.T) {\n\ttable := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n        id int(10) unsigned NOT NULL AUTO_INCREMENT,\n        name varchar(45) NOT NULL,\n        PRIMARY KEY (id)\n    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmpty().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitEmptyWhere().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_OmitNil(t *testing.T) {\n\ttable := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n        id int(10) unsigned NOT NULL AUTO_INCREMENT,\n        name varchar(45) NOT NULL,\n        PRIMARY KEY (id)\n    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": nil,\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNil().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).OmitNilWhere().Data(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_FieldsEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, id\").Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(len(r[0]), 4)\n\t\tt.Assert(r[0][\"id\"], \"\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[0][\"password\"], \"pass_1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"create_time\"], \"\")\n\t\tt.Assert(r[1][\"id\"], \"\")\n\t\tt.Assert(r[1][\"passport\"], \"user_2\")\n\t\tt.Assert(r[1][\"password\"], \"pass_2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"create_time\"], \"\")\n\t})\n\t// Update.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"password\").Data(g.Map{\"nickname\": \"123\", \"password\": \"456\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"123\")\n\t\tt.AssertNE(one[\"password\"], \"456\")\n\t})\n}\n\nfunc Test_Model_FieldsEx_WithReservedWords(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttable      = \"fieldsex_test_table\"\n\t\t\tsqlTpcPath = gtest.DataPath(\"reservedwords_table_tpl.sql\")\n\t\t\tsqlContent = gfile.GetContents(sqlTpcPath)\n\t\t)\n\t\tt.AssertNE(sqlContent, \"\")\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(sqlContent, table)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).FieldsEx(\"content\").One()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\ttable := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\tcreateInitTableWithDb(db, TableNamePrefix1+table)\n\tdefer dropTable(TableNamePrefix1 + table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table+\" as u\").Where(\"u.id in (?)\", g.Slice{1, 2}).Order(\"u.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias to struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickName string\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table+\" u\").Where(\"u.id in (?)\", g.Slice{1, 5}).Order(\"u.id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 5)\n\t})\n\t// Select with alias and join statement.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table+\" as u1\").LeftJoin(table+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).As(\"u1\").LeftJoin(table+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_Schema1(t *testing.T) {\n\t// db.SetDebug(true)\n\n\tdb = db.Schema(TestSchema1)\n\ttable := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr())\n\tcreateInitTableWithDb(db, table)\n\tdb = db.Schema(TestSchema2)\n\tcreateInitTableWithDb(db, table)\n\tdefer func() {\n\t\tdb = db.Schema(TestSchema1)\n\t\tdropTableWithDb(db, table)\n\t\tdb = db.Schema(TestSchema2)\n\t\tdropTableWithDb(db, table)\n\t\tdb = db.Schema(TestSchema1)\n\t}()\n\t// Method.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb = db.Schema(TestSchema1)\n\t\tr, err := db.Model(table).Update(g.Map{\"nickname\": \"name_100\"}, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err := db.Model(table).Value(\"nickname\", \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_100\")\n\n\t\tdb = db.Schema(TestSchema2)\n\t\tv, err = db.Model(table).Value(\"nickname\", \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_1\")\n\t})\n\t// Model.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Schema(TestSchema1).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_2\")\n\n\t\tr, err := db.Model(table).Schema(TestSchema1).Update(g.Map{\"nickname\": \"name_200\"}, \"id=2\")\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err = db.Model(table).Schema(TestSchema1).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_200\")\n\n\t\tv, err = db.Model(table).Schema(TestSchema2).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_2\")\n\n\t\tv, err = db.Model(table).Schema(TestSchema1).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_200\")\n\t})\n\t// Model.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 1000\n\t\t_, err := db.Model(table).Schema(TestSchema1).Insert(g.Map{\n\t\t\t\"id\":               i,\n\t\t\t\"passport\":         fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":         fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":         fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\":      gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\t\t\t\"none-exist-field\": 1,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tv, err := db.Model(table).Schema(TestSchema1).Value(\"nickname\", \"id=?\", i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_1000\")\n\n\t\tv, err = db.Model(table).Schema(TestSchema2).Value(\"nickname\", \"id=?\", i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"\")\n\t})\n}\n\nfunc Test_Model_Schema2(t *testing.T) {\n\t// db.SetDebug(true)\n\n\tdb = db.Schema(TestSchema1)\n\ttable := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr())\n\tcreateInitTableWithDb(db, table)\n\tdb = db.Schema(TestSchema2)\n\tcreateInitTableWithDb(db, table)\n\tdefer func() {\n\t\tdb = db.Schema(TestSchema1)\n\t\tdropTableWithDb(db, table)\n\t\tdb = db.Schema(TestSchema2)\n\t\tdropTableWithDb(db, table)\n\n\t\tdb = db.Schema(TestSchema1)\n\t}()\n\t// Schema.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Schema(TestSchema1).Model(table).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_2\")\n\n\t\tr, err := db.Schema(TestSchema1).Model(table).Update(g.Map{\"nickname\": \"name_200\"}, \"id=2\")\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err = db.Schema(TestSchema1).Model(table).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_200\")\n\n\t\tv, err = db.Schema(TestSchema2).Model(table).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_2\")\n\n\t\tv, err = db.Schema(TestSchema1).Model(table).Value(\"nickname\", \"id=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_200\")\n\t})\n\t// Schema.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti := 1000\n\t\t_, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{\n\t\t\t\"id\":               i,\n\t\t\t\"passport\":         fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":         fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":         fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\":      gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\t\t\t\"none-exist-field\": 1,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tv, err := db.Schema(TestSchema1).Model(table).Value(\"nickname\", \"id=?\", i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"name_1000\")\n\n\t\tv, err = db.Schema(TestSchema2).Model(table).Value(\"nickname\", \"id=?\", i)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"\")\n\t})\n}\n\nfunc Test_Model_FieldsExStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tNickName: \"333\",\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").OmitEmpty().Data(user).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string `orm:\"password\" json:\"password\"`\n\t\t\tNickName string `orm:\"nickname\" json:\"nick__name\"`\n\t\t}\n\t\tusers := make([]*User, 0)\n\t\tfor i := 100; i < 110; i++ {\n\t\t\tusers = append(users, &User{\n\t\t\t\tId:       i,\n\t\t\t\tPassport: fmt.Sprintf(`passport_%d`, i),\n\t\t\t\tPassword: fmt.Sprintf(`password_%d`, i),\n\t\t\t\tNickName: fmt.Sprintf(`nickname_%d`, i),\n\t\t\t})\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, password\").\n\t\t\tOmitEmpty().\n\t\t\tBatch(2).\n\t\t\tData(users).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_OmitEmpty_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tTime:     time.Time{},\n\t\t}\n\t\tr, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Result_Chunk(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tchunks := r.Chunk(3)\n\t\tt.Assert(len(chunks), 4)\n\t\tt.Assert(chunks[0][0][\"id\"].Int(), 1)\n\t\tt.Assert(chunks[1][0][\"id\"].Int(), 4)\n\t\tt.Assert(chunks[2][0][\"id\"].Int(), 7)\n\t\tt.Assert(chunks[3][0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_DryRun(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.SetDryRun(true)\n\tdefer db.SetDryRun(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Data(\"passport\", \"port_1\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_Model_Join_SubQuery(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery := fmt.Sprintf(\"select * from `%s`\", table)\n\t\tr, err := db.Model(table, \"t1\").Fields(\"t2.id\").LeftJoin(subQuery, \"t2\", \"t2.id=t1.id\").Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), TableSize)\n\t\tt.Assert(r[0], \"1\")\n\t\tt.Assert(r[TableSize-1], TableSize)\n\t})\n}\n\nfunc Test_Model_Cache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_100\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\ttime.Sleep(time.Second * 2)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_100\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_200\").Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_200\")\n\t})\n\t// transaction.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 3\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_300\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test3\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(3).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_300\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 4\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_400\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Cache feature disabled.\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test4\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(4).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_400\")\n\t\t\t// Update the cache.\n\t\t\tr, err := tx.Model(table).Data(\"passport\", \"user_4000\").\n\t\t\t\tCache(gdb.CacheOption{\n\t\t\t\t\tDuration: -1,\n\t\t\t\t\tName:     \"test4\",\n\t\t\t\t\tForce:    false,\n\t\t\t\t}).WherePri(4).Update()\n\t\t\tt.AssertNil(err)\n\t\t\tn, err := r.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(n, 1)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Read from db.\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4000\")\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Having(\"id\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table, \"t\").Fields(\"distinct t.id\").Where(\"id > 1\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n\nfunc Test_Model_Fields_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"ID\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICK_NAME\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":        1,\n\t\t\t\"NICK_NAME\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tID       int\n\t\t\tNICKNAME int\n\t\t}\n\t\tone, err := db.Model(table).Fields(&T{\n\t\t\tID:       0,\n\t\t\tNICKNAME: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_FieldsEx_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// \"id\":          i,\n\t// \"passport\":    fmt.Sprintf(`user_%d`, i),\n\t// \"password\":    fmt.Sprintf(`pass_%d`, i),\n\t// \"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t// \"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:00\").String(),\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"create_date, Passport, Password, NickName, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"create_date, ID, Passport, Password, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).FieldsEx(g.Map{\n\t\t\t\"Passport\":   1,\n\t\t\t\"Password\":   1,\n\t\t\t\"CreateTime\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tPassport   int\n\t\t\tPassword   int\n\t\t\tCreateTime int\n\t\t}\n\t\tone, err := db.Model(table).FieldsEx(&T{\n\t\t\tPassport:   0,\n\t\t\tPassword:   0,\n\t\t\tCreateTime: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_Fields_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype A struct {\n\t\tPassport string\n\t\tPassword string\n\t}\n\ttype B struct {\n\t\tA\n\t\tNickName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_NullField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": nil,\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\n\t\tvar user *User\n\t\terr = one.Struct(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t})\n}\n\nfunc Test_Model_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(table)\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc createTableForTimeZoneTest() string {\n\ttableName := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t    CREATE TABLE %s (\n\t        id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n\t        passport    varchar(45) NULL,\n\t        password    char(32) NULL,\n\t        nickname    varchar(45) NULL,\n\t        created_at timestamp(6) NULL,\n \t\t\tupdated_at timestamp(6) NULL,\n\t\t\tdeleted_at timestamp(6) NULL,\n\t        PRIMARY KEY (id)\n\t    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\t    `, tableName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn tableName\n}\n\n// https://github.com/gogf/gf/issues/1012\nfunc Test_TimeZoneInsert(t *testing.T) {\n\ttableName := createTableForTimeZoneTest()\n\tdefer dropTable(tableName)\n\n\ttokyoLoc, err := time.LoadLocation(\"Asia/Tokyo\")\n\tgtest.AssertNil(err)\n\n\tCreateTime := \"2020-11-22 12:23:45\"\n\tUpdateTime := \"2020-11-22 13:23:46\"\n\tDeleteTime := \"2020-11-22 14:23:47\"\n\ttype User struct {\n\t\tId        int         `json:\"id\"`\n\t\tCreatedAt *gtime.Time `json:\"created_at\"`\n\t\tUpdatedAt gtime.Time  `json:\"updated_at\"`\n\t\tDeletedAt time.Time   `json:\"deleted_at\"`\n\t}\n\tt1, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", CreateTime, tokyoLoc)\n\tt2, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", UpdateTime, tokyoLoc)\n\tt3, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", DeleteTime, tokyoLoc)\n\tu := &User{\n\t\tId:        1,\n\t\tCreatedAt: gtime.New(t1.UTC()),\n\t\tUpdatedAt: *gtime.New(t2.UTC()),\n\t\tDeletedAt: t3.UTC(),\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err = db.Model(tableName).Unscoped().Insert(u)\n\t\tt.AssertNil(err)\n\t\tuserEntity := &User{}\n\t\terr = db.Model(tableName).Where(\"id\", 1).Unscoped().Scan(&userEntity)\n\t\tt.AssertNil(err)\n\t\tt.Assert(userEntity.CreatedAt.String(), \"2020-11-22 11:23:45\")\n\t\tt.Assert(userEntity.UpdatedAt.String(), \"2020-11-22 12:23:46\")\n\t\tt.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), \"2020-11-22 13:23:47\")\n\t})\n}\n\nfunc Test_Model_Fields_Map_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":         1,\n\t\t\t\"PASSPORT\":   1,\n\t\t\t\"NONE_EXIST\": 1,\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[\"id\"], 1)\n\t\tt.Assert(result[\"passport\"], \"user_1\")\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\ta := A{}\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// *struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// **struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(&a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n}\n\nfunc Test_Model_Min_Max_Avg_Sum(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 5.5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 55)\n\t})\n}\n\nfunc Test_Model_CountColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 3)\n\t})\n}\n\nfunc Test_Model_InsertAndGetId(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"user_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\": \"user_2\",\n\t\t\t\"password\": \"pass_2\",\n\t\t\t\"nickname\": \"name_2\",\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 2)\n\t})\n}\n\nfunc Test_Model_Increment_Decrement(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 1).Increment(\"id\", 100)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 101).Decrement(\"id\", 10)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 91).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_OnDuplicate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicate(\"passport,password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicate(\"passport\", \"password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicate(g.Slice{\"passport\", \"password\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicate(g.Map{\n\t\t\t\"passport\": \"nickname\",\n\t\t\t\"password\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"nickname\"])\n\t\tt.Assert(one[\"password\"], data[\"nickname\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map+raw.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"id\":          \"1\",\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicate(g.Map{\n\t\t\t\"passport\": gdb.Raw(\"CONCAT(VALUES(`passport`), '1')\"),\n\t\t\t\"password\": gdb.Raw(\"CONCAT(VALUES(`password`), '2')\"),\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"]+\"1\")\n\t\tt.Assert(one[\"password\"], data[\"password\"]+\"2\")\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_Model_OnDuplicateWithCounter(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"id\": gdb.Counter{Field: \"id\", Value: 999999},\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(one)\n\t})\n}\n\nfunc Test_Model_OnDuplicateEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicateEx(\"nickname,create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicateEx(\"nickname\", \"create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicateEx(g.Slice{\"nickname\", \"create_time\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnDuplicateEx(g.Map{\n\t\t\t\"nickname\":    \"nickname\",\n\t\t\t\"create_time\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 7)\n\t\tt.Assert(all[1][\"id\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw SQL selects {1,5,7,8,9,10}, Where filters to id < 8 AND id IN {1,2,3,4,5,6,7}\n\t\t// Result: {1,5,7} = 3 records\n\t\tt.Assert(count, int64(3))\n\t})\n}\n\nfunc Test_Model_Handler(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Safe().Handler(\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Page(0, 3)\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Where(\"id\", g.Slice{1, 2, 3, 4, 5, 6})\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.OrderDesc(\"id\")\n\t\t\t},\n\t\t)\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], 6)\n\t\tt.Assert(all[2][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_FieldCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldCount(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMax(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMin(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldAvg(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldAvg(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_OmitEmptyWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Basic type where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Where(\"nickname\", \"\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Slice where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Struct Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Map Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       []int{},\n\t\t\t\"nickname\": []string{},\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId []int\n\t\t}\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1387\nfunc Test_Model_GTime_DefaultValue(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t\tNickname: \"name_1\",\n\t\t}\n\t\t// Insert\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Select\n\t\tvar (\n\t\t\tuser *User\n\t\t)\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, data.Passport)\n\t\tt.Assert(user.Password, data.Password)\n\t\tt.Assert(user.CreateTime, data.CreateTime)\n\t\tt.Assert(user.Nickname, data.Nickname)\n\n\t\t// Insert\n\t\tuser.Id = 2\n\t\t_, err = db.Model(table).Data(user).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Using filter does not affect the outside value inside function.\nfunc Test_Model_Insert_Filter(t *testing.T) {\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tt.Assert(data[\"uid\"], 1)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.List{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"uid\":         1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}\n\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tt.Assert(data[0][\"uid\"], 1)\n\t\tt.Assert(data[1][\"uid\"], 2)\n\t})\n}\n\nfunc Test_Model_Embedded_Filter(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int\n\t\t\tUid        int\n\t\t\tCreateTime string\n\t\t\tNoneExist  string\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tUid:        100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tvar user *User\n\t\terr = db.Model(table).Fields(user).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"john-test\")\n\t\tt.Assert(user.Id, 100)\n\t})\n}\n\n// This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0.\n// func Test_Model_Insert_KeyFieldNameMapping_Error(t *testing.T) {\n//\ttable := createTable()\n//\tdefer dropTable(table)\n//\n//\tgtest.C(t, func(t *gtest.T) {\n//\t\ttype User struct {\n//\t\t\tId             int\n//\t\t\tPassport       string\n//\t\t\tPassword       string\n//\t\t\tNickname       string\n//\t\t\tCreateTime     string\n//\t\t\tNoneExistField string\n//\t\t}\n//\t\tdata := User{\n//\t\t\tId:         1,\n//\t\t\tPassport:   \"user_1\",\n//\t\t\tPassword:   \"pass_1\",\n//\t\t\tNickname:   \"name_1\",\n//\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n//\t\t}\n//\t\t_, err := db.Model(table).Data(data).Insert()\n//\t\tt.AssertNE(err, nil)\n//\t})\n// }\n\nfunc Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\ttable1 := \"user\"\n\t\ttable2 := \"score\"\n\t\ttable3 := \"info\"\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t   id int(11) NOT NULL AUTO_INCREMENT,\n\t\t   name varchar(500) NOT NULL DEFAULT '',\n\t\t PRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;\n\t    `, table1,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table1)\n\t\t_, err = db.Model(table1).Insert(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid int(11) NOT NULL AUTO_INCREMENT,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t    number varchar(500) NOT NULL DEFAULT '',\n\t\t PRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;\n\t    `, table2,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\t\t_, err = db.Model(table2).Insert(g.Map{\n\t\t\t\"id\":      1,\n\t\t\t\"user_id\": 1,\n\t\t\t\"number\":  \"n\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid int(11) NOT NULL AUTO_INCREMENT,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t    description varchar(500) NOT NULL DEFAULT '',\n\t\t PRIMARY KEY (id)\n\t\t) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;\n\t    `, table3,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table3)\n\t\t_, err = db.Model(table3).Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"user_id\":     1,\n\t\t\t\"description\": \"brief\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(\"user\").\n\t\t\tWhere(\"user.id\", 1).\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tOrder(\"user.id asc\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\n\t\tone, err = db.Model(\"user\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne *S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_StructAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  *S1\n\t\t\tMany []*S2\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  S1\n\t\t\tMany []S2\n\t\t}\n\t\tvar (\n\t\t\ts   []S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\nfunc TestResult_Structs1(t *testing.T) {\n\ttype A struct {\n\t\tId int `orm:\"id\"`\n\t}\n\ttype B struct {\n\t\t*A\n\t\tName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gdb.Result{\n\t\t\tgdb.Record{\"id\": gvar.New(nil), \"name\": gvar.New(\"john\")},\n\t\t\tgdb.Record{\"id\": gvar.New(1), \"name\": gvar.New(\"smith\")},\n\t\t}\n\t\tarray := make([]*B, 2)\n\t\terr := r.Structs(&array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0].Id, 0)\n\t\tt.Assert(array[1].Id, 1)\n\t\tt.Assert(array[0].Name, \"john\")\n\t\tt.Assert(array[1].Name, \"smith\")\n\t})\n}\n\nfunc Test_Builder_OmitEmptyWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 1).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 0).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuilder := db.Model(table).OmitEmptyWhere().Builder()\n\t\tcount, err := db.Model(table).Where(\n\t\t\tbuilder.Where(\"id\", 0),\n\t\t).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Scan_Nil_Result_Error(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype S struct {\n\t\tId    int\n\t\tName  string\n\t\tAge   int\n\t\tScore int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s *S\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(&s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s *S\n\t\terr := db.Model(table).Where(\"id\", 100).Scan(&s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s S\n\t\terr := db.Model(table).Where(\"id\", 100).Scan(&s)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ss []*S\n\t\terr := db.Model(table).Scan(&ss)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(ss), TableSize)\n\t})\n\t// If the result is empty, it returns error.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ss = make([]*S, 10)\n\t\terr := db.Model(table).WhereGT(\"id\", 100).Scan(&ss)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n}\n\nfunc Test_Model_FixGdbJoin(t *testing.T) {\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_join.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(`common_resource`)\n\tdefer dropTable(`managed_resource`)\n\tdefer dropTable(`rules_template`)\n\tdefer dropTable(`resource_mark`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tsqlSlice, err := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\torm := db.Model(`managed_resource`).Ctx(ctx).\n\t\t\t\tLeftJoinOnField(`common_resource`, `resource_id`).\n\t\t\t\tLeftJoinOnFields(`resource_mark`, `resource_mark_id`, `=`, `id`).\n\t\t\t\tLeftJoinOnFields(`rules_template`, `rule_template_id`, `=`, `template_id`).\n\t\t\t\tFieldsPrefix(\n\t\t\t\t\t`managed_resource`,\n\t\t\t\t\t\"resource_id\", \"user\", \"status\", \"status_message\", \"safe_publication\", \"rule_template_id\",\n\t\t\t\t\t\"created_at\", \"comments\", \"expired_at\", \"resource_mark_id\", \"instance_id\", \"resource_name\",\n\t\t\t\t\t\"pay_mode\").\n\t\t\t\tFieldsPrefix(`resource_mark`, \"mark_name\", \"color\").\n\t\t\t\tFieldsPrefix(`rules_template`, \"name\").\n\t\t\t\tFieldsPrefix(`common_resource`, `src_instance_id`, \"database_kind\", \"source_type\", \"ip\", \"port\")\n\t\t\tall, err := orm.OrderAsc(\"src_instance_id\").All()\n\t\t\tt.Assert(err, nil)\n\t\t\tt.Assert(len(all), 4)\n\t\t\tt.Assert(all[0][\"pay_mode\"], 1)\n\t\t\tt.Assert(all[0][\"src_instance_id\"], 2)\n\t\t\tt.Assert(all[3][\"instance_id\"], \"dmcins-jxy0x75m\")\n\t\t\tt.Assert(all[3][\"src_instance_id\"], \"vdb-6b6m3u1u\")\n\t\t\tt.Assert(all[3][\"resource_mark_id\"], \"11\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gtest.DataContent(`fix_gdb_join_expect.sql`), sqlSlice[len(sqlSlice)-1])\n\t})\n}\n\nfunc Test_Model_Year_Date_Time_DateTime_Timestamp(t *testing.T) {\n\ttable := \"date_time_example\"\n\tarray := gstr.SplitAndTrim(gtest.DataContent(`date_time_example.sql`), \";\")\n\tfor _, v := range array {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// insert.\n\t\tvar now = gtime.Now()\n\t\t_, err := db.Model(\"date_time_example\").Insert(g.Map{\n\t\t\t\"year\":      now,\n\t\t\t\"date\":      now,\n\t\t\t\"time\":      now,\n\t\t\t\"datetime\":  now,\n\t\t\t\"timestamp\": now,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// select.\n\t\tone, err := db.Model(\"date_time_example\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"year\"].String(), now.Format(\"Y\"))\n\t\tt.Assert(one[\"date\"].String(), now.Format(\"Y-m-d\"))\n\t\tt.Assert(one[\"time\"].String(), now.Format(\"H:i:s\"))\n\t\tt.AssertLT(one[\"datetime\"].GTime().Sub(now).Seconds(), 5)\n\t\tt.AssertLT(one[\"timestamp\"].GTime().Sub(now).Seconds(), 5)\n\t})\n}\n\nfunc Test_OrderBy_Statement_Generated(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_order_by.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(`employee`)\n\t\tsqlArray, _ := gdb.CatchSQL(ctx, func(ctx context.Context) error {\n\t\t\tg.DB(\"default\").Ctx(ctx).Model(\"employee\").Order(\"name asc\", \"age desc\").All()\n\t\t\treturn nil\n\t\t})\n\t\trawSql := strings.ReplaceAll(sqlArray[len(sqlArray)-1], \" \", \"\")\n\t\texpectSql := strings.ReplaceAll(\"SELECT * FROM `employee` ORDER BY `name` asc, `age` desc\", \" \", \"\")\n\t\tt.Assert(rawSql, expectSql)\n\t})\n}\n\nfunc Test_Fields_Raw(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tone, err := db.Model(table).Fields(gdb.Raw(\"1\")).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"1\"], 1)\n\n\t\tone, err = db.Model(table).Fields(gdb.Raw(\"2\")).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"2\"], 2)\n\n\t\tone, err = db.Model(table).Fields(gdb.Raw(\"2\")).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"2\"], 2)\n\n\t\tone, err = db.Model(table).Fields(gdb.Raw(\"2\")).Where(\"id\", 10000000000).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_model_where_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Option_Where(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 0, \"passport\": \"\"}).Where(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 1, \"passport\": \"\"}).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tv, err := db.Model(table).Where(\"id\", 1).Fields(\"nickname\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"1\")\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_1(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_2(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// complicated one.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n\nfunc Test_Model_WhereExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid         int(10) unsigned NOT NULL DEFAULT '0',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\"))\n\n\t\tr, err := db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereNotExists\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\n\t\t// Test WhereExists with empty result\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table).\n\t\t\tWhereExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereNotExists with all results\n\t\tr, err = db.Model(table).\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test combination of Where and WhereExists\n\t\tr, err = db.Model(table+\" as user\").\n\t\t\tWhere(\"id>?\", 3).\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereExists with complex subquery\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\")).\n\t\t\tWhere(\"id > ?\", 0)\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Fields\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tFields(\"id,passport\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[0][\"passport\"].String(), \"user_1\")\n\n\t\t// Test WhereExists with Group\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Having\n\t\tr, err = db.Model(table+\" as user\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tHaving(\"id > ?\", 1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_WhereNotExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid         int(10) unsigned NOT NULL DEFAULT '0',\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n    `, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereNotExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\"))\n\n\t\tr, err := db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)           // Should be 8 because records with id 1 and 2 exist in table2\n\t\tt.Assert(r[0][\"id\"].Int(), 3) // First record should be id 3\n\t\tt.Assert(r[1][\"id\"].Int(), 4) // Second record should be id 4\n\n\t\t// Test WhereNotExists with empty subquery\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\") // This condition will return no results\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10) // Should return all records when subquery is empty\n\n\t\t// Test WhereNotExists with complex condition\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"user.id\")).\n\t\t\tWhere(\"id > ?\", 1)\n\t\tr, err = db.Model(table + \" as user\").\n\t\t\tWhereNotExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 9)           // Should only exclude the record with id 2\n\t\tt.Assert(r[0][\"id\"].Int(), 1) // Should include id 1\n\t})\n}\n\n// Test_Model_WherePrefixIn tests WherePrefix with IN clause\nfunc Test_Model_WherePrefixIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixIn(\"t1\", \"id\", g.Slice{1, 2, 3}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixNotIn tests WherePrefix with NOT IN clause\nfunc Test_Model_WherePrefixNotIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotIn(\"t1\", \"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"8\")\n\t\tt.Assert(r[2][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixBetween tests WherePrefix with BETWEEN clause\nfunc Test_Model_WherePrefixBetween(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixBetween(\"t1\", \"id\", 3, 6).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t\tt.Assert(r[3][\"id\"], \"6\")\n\t})\n}\n\n// Test_Model_WherePrefixNotBetween tests WherePrefix with NOT BETWEEN clause\nfunc Test_Model_WherePrefixNotBetween(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotBetween(\"t1\", \"id\", 3, 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// NOT BETWEEN 3 AND 7 returns: 1, 2, 8, 9, 10 (5 records)\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t\tt.Assert(r[4][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixLT tests WherePrefix with < operator\nfunc Test_Model_WherePrefixLT(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixLT(\"t1\", \"id\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[2][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixLTE tests WherePrefix with <= operator\nfunc Test_Model_WherePrefixLTE(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixLTE(\"t1\", \"id\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[3][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_WherePrefixGT tests WherePrefix with > operator\nfunc Test_Model_WherePrefixGT(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixGT(\"t1\", \"id\", 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"8\")\n\t\tt.Assert(r[2][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixGTE tests WherePrefix with >= operator\nfunc Test_Model_WherePrefixGTE(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixGTE(\"t1\", \"id\", 7).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"7\")\n\t\tt.Assert(r[3][\"id\"], \"10\")\n\t})\n}\n\n// Test_Model_WherePrefixNotLike tests WherePrefix with NOT LIKE operator\nfunc Test_Model_WherePrefixNotLike(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"nickname\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotLike(\"t1\", \"nickname\", \"name_1%\").\n\t\t\tWhere(\"t1.id <\", 5).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// Should exclude name_1 and name_10 (but id 10 filtered by WHERE anyway)\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[2][\"id\"], \"4\")\n\t})\n}\n\n// Test_Model_WherePrefixNull tests WherePrefix with IS NULL\nfunc Test_Model_WherePrefixNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\t// table2 has partial data, will cause NULLs in LEFT JOIN\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, _ = db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNull(\"t2\", \"nickname\").\n\t\t\tWhere(\"t1.id <=\", 3).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// t2 only has id=1, so id 2,3 should have NULL in t2.nickname\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"2\")\n\t\tt.Assert(r[1][\"id\"], \"3\")\n\t})\n}\n\n// Test_Model_WherePrefixNotNull tests WherePrefix with IS NOT NULL\nfunc Test_Model_WherePrefixNotNull(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\t// table2 has partial data\n\tcreateTable(table2)\n\tdefer dropTable(table2)\n\t_, _ = db.Insert(ctx, table2, g.List{\n\t\t{\"id\": 1, \"passport\": \"user_1\", \"nickname\": \"name_1\"},\n\t\t{\"id\": 2, \"passport\": \"user_2\", \"nickname\": \"name_2\"},\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWherePrefixNotNull(\"t2\", \"nickname\").\n\t\t\tWhere(\"t1.id <=\", 4).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// t2 has id 1,2, so only these should have NOT NULL in t2.nickname\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\n// Test_Model_WhereOrPrefixIn tests WhereOrPrefix with IN clause\nfunc Test_Model_WhereOrPrefixIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhereOrPrefixIn(\"t1\", \"id\", g.Slice{1, 2}).\n\t\t\tWhereOrPrefixIn(\"t2\", \"id\", g.Slice{8, 9}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\n// Test_Model_WhereOrPrefixNotIn tests WhereOrPrefix with NOT IN clause\nfunc Test_Model_WhereOrPrefixNotIn(t *testing.T) {\n\tvar (\n\t\ttable1 = gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).As(\"t1\").\n\t\t\tFieldsPrefix(\"t1\", \"id\").\n\t\t\tLeftJoin(table2+\" AS t2\", \"t1.id = t2.id\").\n\t\t\tWhereOrPrefixNotIn(\"t1\", \"id\", g.Slice{1}).\n\t\t\tWhereOrPrefixNotIn(\"t2\", \"id\", g.Slice{2, 3, 4, 5, 6, 7, 8, 9, 10}).\n\t\t\tOrder(\"t1.id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 10) // All records match one OR condition\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t})\n}\n\n// Test_Model_Having_Aggregate tests HAVING clause with aggregate functions\nfunc Test_Model_Having_Aggregate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with COUNT\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >= ?\", 3).\n\t\t\tOrder(\"mod_group asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// mod 0: 3,6,9 (3 items)\n\t\t// mod 1: 1,4,7,10 (4 items)\n\t\t// mod 2: 2,5,8 (3 items)\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"mod_group\"], \"0\")\n\t\tt.Assert(r[0][\"cnt\"], \"3\")\n\t\tt.Assert(r[1][\"cnt\"], \"4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with SUM\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 2 AS parity\", \"SUM(id) AS total\").\n\t\t\tGroup(\"parity\").\n\t\t\tHaving(\"SUM(id) > ?\", 25).\n\t\t\tOrder(\"parity asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// even (2,4,6,8,10): sum=30\n\t\t// odd (1,3,5,7,9): sum=25\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"parity\"], \"0\")\n\t\tt.Assert(r[0][\"total\"], \"30\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with AVG\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id DIV 5 AS group_key\", \"AVG(id) AS avg_id\").\n\t\t\tGroup(\"group_key\").\n\t\t\tHaving(\"AVG(id) >= ?\", 5).\n\t\t\tOrder(\"group_key asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// group 0 (id 1-4): avg=2.5\n\t\t// group 1 (id 5-9): avg=7\n\t\t// group 2 (id 10): avg=10\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"group_key\"], \"1\")\n\t})\n}\n\n// Test_Model_Having_MultipleConditions tests HAVING with multiple conditions\nfunc Test_Model_Having_MultipleConditions(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple HAVING conditions\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id % 3 AS mod_group\", \"COUNT(*) AS cnt\", \"SUM(id) AS total\").\n\t\t\tGroup(\"mod_group\").\n\t\t\tHaving(\"COUNT(*) >= ?\", 3).\n\t\t\tHaving(\"SUM(id) < ?\", 30).\n\t\t\tOrder(\"mod_group asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// mod 0: cnt=3, sum=18 (3+6+9) ✓\n\t\t// mod 1: cnt=4, sum=22 (1+4+7+10) ✓\n\t\t// mod 2: cnt=3, sum=15 (2+5+8) ✓\n\t\tt.Assert(len(r), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// HAVING with complex expression\n\t\tr, err := db.Model(table).\n\t\t\tFields(\"id DIV 3 AS group_key\", \"MAX(id) - MIN(id) AS range_val\").\n\t\t\tGroup(\"group_key\").\n\t\t\tHaving(\"MAX(id) - MIN(id) >= ?\", 2).\n\t\t\tOrder(\"group_key asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\n\t\t// group 0 (1,2): range=1\n\t\t// group 1 (3,4,5): range=2 ✓\n\t\t// group 2 (6,7,8): range=2 ✓\n\t\t// group 3 (9,10): range=1\n\t\tt.Assert(len(r), 2)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/mysql_z_unit_transaction_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mysql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_TX_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tst, err := tx.Prepare(\"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(array[0], \"100\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tuser := tx.Model(table)\n\n\t\t_, err = user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(2))\n\t})\n}\n\nfunc Test_TX_BatchReplace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Replace(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"PASS_2\")\n\t})\n}\n\nfunc Test_TX_BatchSave(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Save(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 4).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"PASS_4\")\n\t})\n}\n\nfunc Test_TX_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Replace(table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_TX_Save(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Save(table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_TX_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.Update(table, \"create_time='2019-10-24 10:00:00'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.String(), \"2019-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_TX_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.GetAll(fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(result), 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\trecord, err := tx.GetOne(fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_2\")\n\t\tt.AssertNil(err)\n\n\t\tt.AssertNE(record, nil)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_2\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := tx.GetValue(fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.Int(), 3)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := tx.GetCount(\"SELECT * FROM \" + table)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(TableSize))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=?\", table), 1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_TX_Delete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Delete(table, 1)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Delete(table, 1)\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(0))\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tn, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\t\tt.AssertNE(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Ctx(ctx).Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\tt.Assert(tx.IsClosed(), false)\n\t\t\treturn gerror.New(\"error\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Ctx(ctx).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_Transaction_Panic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Replace(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tpanic(\"error\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_Transaction_Nested_Begin_Rollback_Commit(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx begin.\n\t\terr = tx.Begin()\n\t\tt.AssertNil(err)\n\n\t\t// tx rollback.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"user_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).Insert()\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       2,\n\t\t\t\"passport\": \"user_2\",\n\t\t\t\"password\": \"pass_2\",\n\t\t\t\"nickname\": \"name_2\",\n\t\t}).Insert()\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseTX(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\t// another record.\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseDB(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_SavePoint_RollbackTo(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx save point.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": \"user_1\",\n\t\t\t\"password\": \"pass_1\",\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).Insert()\n\t\terr = tx.SavePoint(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":       2,\n\t\t\t\"passport\": \"user_2\",\n\t\t\t\"password\": \"pass_2\",\n\t\t\t\"nickname\": \"name_2\",\n\t\t}).Insert()\n\t\t// tx rollback to.\n\t\terr = tx.RollbackTo(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Transaction_Method(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = db.Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\n\t\t\t_, err = db.Ctx(ctx).Exec(ctx, fmt.Sprintf(\n\t\t\t\t\"insert into %s(`passport`,`password`,`nickname`,`create_time`,`id`) \"+\n\t\t\t\t\t\"VALUES('t2','25d55ad283aa400af464c76d713c07ad','T2','2021-08-25 21:53:00',2) \",\n\t\t\t\ttable))\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\nfunc Test_Transaction_Propagation(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationRequired\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert initial record\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"required\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Nested transaction with PropagationRequired\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should use the same transaction\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       2,\n\t\t\t\t\t\"passport\": \"required_nested\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify both records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationRequiresNew\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       3,\n\t\t\t\t\"passport\": \"outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Inner transaction with PropagationRequiresNew\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// This is a new transaction\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       4,\n\t\t\t\t\t\"passport\": \"inner_new\",\n\t\t\t\t})\n\t\t\t\t// Simulate error to test independent rollback\n\t\t\t\treturn gerror.New(\"rollback inner transaction\")\n\t\t\t})\n\t\t\t// Inner transaction error should not affect outer transaction\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify only outer transaction record exists\n\t\tcount, err := db.Model(table).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNested\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       5,\n\t\t\t\t\"passport\": \"nested_outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Nested transaction\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       6,\n\t\t\t\t\t\"passport\": \"nested_inner\",\n\t\t\t\t})\n\t\t\t\t// Simulate error to test savepoint rollback\n\t\t\t\treturn gerror.New(\"rollback to savepoint\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Insert another record after nested transaction rollback\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       7,\n\t\t\t\t\"passport\": \"nested_after\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify outer transaction records exist, but nested transaction record doesn't\n\t\tcount, err := db.Model(table).Where(\"passport\", \"nested_inner\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"nested_outer\", \"nested_after\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNotSupported\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Insert in transaction\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       8,\n\t\t\t\t\"passport\": \"tx_record\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Non-transactional operation\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should execute without transaction\n\t\t\t\t_, err = db.Insert(ctx, table, g.Map{\n\t\t\t\t\t\"id\":       9,\n\t\t\t\t\t\"passport\": \"non_tx_record\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify transactional record is rolled back but non-transactional record exists\n\t\tcount, err := db.Model(table).Where(\"passport\", \"tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"non_tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationMandatory\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn nil\n\t\t})\n\t\t// Should fail because no transaction exists\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test within an existing transaction\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should succeed because transaction exists\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       10,\n\t\t\t\t\t\"passport\": \"mandatory\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test PropagationNever\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationNever,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\t\"id\":       11,\n\t\t\t\t\"passport\": \"never\",\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test within an existing transaction\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNever,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t\t// Should fail because transaction exists\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Transaction_Propagation_PropagationSupports(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// scenario1: when in a transaction, use PropagationSupports to execute a transaction\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// insert in outer tx.\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\": 1,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationSupports,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\": 2,\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"error\")\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// scenario2: when not in a transaction, do not use transaction but direct db link.\n\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationSupports,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\": 3,\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// 查询结果\n\t\tresult, err := db.Model(table).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Complex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createTable()\n\t\ttable2 := createTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\t// Test nested transactions with different propagation behaviors\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx1.Insert(table1, g.Map{\n\t\t\t\t\"id\":       1,\n\t\t\t\t\"passport\": \"outer\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// First nested transaction (NESTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table1, g.Map{\n\t\t\t\t\t\"id\":       2,\n\t\t\t\t\t\"passport\": \"nested1\",\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// Second nested transaction (REQUIRES_NEW)\n\t\t\t\terr = tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":       3,\n\t\t\t\t\t\t\"passport\": \"new1\",\n\t\t\t\t\t})\n\t\t\t\t\t// This will be rolled back independently\n\t\t\t\t\treturn gerror.New(\"rollback new transaction\")\n\t\t\t\t})\n\t\t\t\tt.AssertNE(err, nil)\n\n\t\t\t\t// Third nested transaction (NESTED)\n\t\t\t\treturn tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":       4,\n\t\t\t\t\t\t\"passport\": \"nested2\",\n\t\t\t\t\t})\n\t\t\t\t\t// This will rollback to the savepoint\n\t\t\t\t\treturn gerror.New(\"rollback nested transaction\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Fourth transaction (NOT_SUPPORTED)\n\t\t\t// Note that, it locks table if it continues using table1.\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table2, g.Map{\n\t\t\t\t\t\"id\":       5,\n\t\t\t\t\t\"passport\": \"not_supported\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify final state\n\t\t// 1. \"outer\" should exist (committed)\n\t\tcount, err := db.Model(table1).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\n\t\t// 2. \"nested1\" should not exist (rolled back due to error)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 3. \"new1\" should not exist (rolled back independently)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"new1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 4. \"nested2\" should not exist (rolled back to savepoint)\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested2\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 5. \"not_supported\" should exist (non-transactional)\n\t\tcount, err = db.Model(table2).Where(\"passport\", \"not_supported\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Test transaction suspension and resume\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Insert in outer transaction\n\t\t\t_, err := tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          6,\n\t\t\t\t\"passport\":    \"suspend_outer\",\n\t\t\t\t\"password\":    \"pass6\",\n\t\t\t\t\"nickname\":    \"suspend_outer\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Suspend current transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Start a new independent transaction\n\t\t\t\treturn db.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":          7,\n\t\t\t\t\t\t\"passport\":    \"independent\",\n\t\t\t\t\t\t\"password\":    \"pass7\",\n\t\t\t\t\t\t\"nickname\":    \"independent\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Resume original transaction\n\t\t\t_, err = tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"suspend_resume\",\n\t\t\t\t\"password\":    \"pass8\",\n\t\t\t\t\"nickname\":    \"suspend_resume\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Simulate error to rollback outer transaction\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify final state\n\t\t// 1. \"suspend_outer\" and \"suspend_resume\" should not exist (rolled back)\n\t\tcount, err := db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"suspend_outer\", \"suspend_resume\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\t// 2. \"independent\" should exist (committed independently)\n\t\tcount, err = db.Model(table).Where(\"passport\", \"independent\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_ReadOnly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test read-only transaction\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Try to modify data in read-only transaction\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"changed\"}, \"id=1\")\n\t\t\t// Should return error\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify data was not modified\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n}\n\nfunc Test_Transaction_Isolation(t *testing.T) {\n\t// Test READ UNCOMMITTED\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tIsolation: sql.LevelReadUncommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Update value in first transaction\n\t\t\t_, err := tx1.Update(table, g.Map{\"passport\": \"dirty_read\"}, \"id=1\")\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Start another transaction to verify dirty read\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tIsolation: sql.LevelReadUncommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t// Should see uncommitted change in READ UNCOMMITTED\n\t\t\t\tv, err := tx2.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tt.Assert(v.String(), \"dirty_read\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Rollback the first transaction\n\t\t\treturn gerror.New(\"rollback first transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify the value is rolled back\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n\n\t// Test REPEATABLE READ (default)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\t// Start a transaction with REPEATABLE READ isolation\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits the value\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\n\t\t\t\t\t\"passport\": \"changed_value\",\n\t\t\t\t}, \"id=1\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Verify the change is visible outside transaction\n\t\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v.String(), \"changed_value\")\n\n\t\t\t// Should still see old value in REPEATABLE READ transaction\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), initialValue)\n\n\t\t\t// Even after multiple reads, should still see the same value\n\t\t\tv3, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v3.String(), initialValue)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// After transaction ends, should see the committed change\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"changed_value\")\n\t})\n\n\t// Test SERIALIZABLE\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read all records\n\t\t\t_, err := tx1.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Try concurrent insert in another transaction\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       1000,\n\t\t\t\t\t\"passport\": \"new_user\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test READ COMMITTED\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"committed_value\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Should see new value in READ COMMITTED\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), \"committed_value\")\n\t\t\tt.AssertNE(v2.String(), initialValue)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Spread(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\terr = db.Transaction(tx.GetCtx(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := tx.Model(table).All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0)\n\t})\n}\n\n// ========== Deep Transaction Enhancement Tests ==========\n\n// Test_Transaction_Isolation_ReadCommitted_NonRepeatableRead tests READ COMMITTED isolation level\n// allows non-repeatable reads - same query can return different results within the same transaction\nfunc Test_Transaction_Isolation_ReadCommitted_NonRepeatableRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tfirstRead := v1.String()\n\t\t\tt.Assert(firstRead, \"user_1\")\n\n\t\t\t// External transaction commits a change\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"user_1_modified\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Second read - should see the committed change (non-repeatable read)\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tsecondRead := v2.String()\n\t\t\tt.Assert(secondRead, \"user_1_modified\")\n\t\t\tt.AssertNE(firstRead, secondRead)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Isolation_Serializable_PhantomRead tests SERIALIZABLE isolation level\n// prevents phantom reads - range queries see consistent snapshot\nfunc Test_Transaction_Isolation_Serializable_PhantomRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First count\n\t\t\tcount1, err := tx1.Model(table).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count1, int64(TableSize))\n\n\t\t\t// Try to insert in another transaction.\n\t\t\t// InnoDB's SERIALIZABLE uses gap locks; whether this insert conflicts\n\t\t\t// depends on table state and index structure, so we do not assert on err.\n\t\t\t_ = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":       100,\n\t\t\t\t\t\"passport\": \"phantom_user\",\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\n\t\t\t// Second count - should remain the same\n\t\t\tcount2, err := tx1.Model(table).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count2, count1)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Isolation_RepeatableRead_ConsistentSnapshot tests REPEATABLE READ isolation\n// maintains consistent snapshot throughout transaction\nfunc Test_Transaction_Isolation_RepeatableRead_ConsistentSnapshot(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read multiple records\n\t\t\trecords1, err := tx1.Model(table).Where(\"id IN(?,?)\", 1, 2).All()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(records1), 2)\n\n\t\t\t// External transaction modifies both records\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"nickname\": \"modified\"}, \"id IN(?,?)\", 1, 2)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Re-read - should see original values\n\t\t\trecords2, err := tx1.Model(table).Where(\"id IN(?,?)\", 1, 2).All()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(records2), 2)\n\t\t\tfor i := 0; i < 2; i++ {\n\t\t\t\tt.Assert(records1[i][\"nickname\"], records2[i][\"nickname\"])\n\t\t\t\tt.AssertNE(records2[i][\"nickname\"].String(), \"modified\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Deadlock_TwoTables tests deadlock detection with two tables\nfunc Test_Transaction_Deadlock_TwoTables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable()\n\t\ttable2 := createInitTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tvar wg sync.WaitGroup\n\t\terrs := make([]error, 2)\n\t\t// Use channels to synchronize lock acquisition order.\n\t\ttx1Locked := make(chan struct{})\n\t\ttx2Locked := make(chan struct{})\n\n\t\t// Transaction 1: lock table1 then table2\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[0] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t_, err := tx.Update(table1, g.Map{\"passport\": \"tx1_lock\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx1Locked)\n\t\t\t\t<-tx2Locked\n\t\t\t\t_, err = tx.Update(table2, g.Map{\"passport\": \"tx1_lock\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Transaction 2: lock table2 then table1\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[1] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t<-tx1Locked\n\t\t\t\t_, err := tx.Update(table2, g.Map{\"passport\": \"tx2_lock\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx2Locked)\n\t\t\t\t_, err = tx.Update(table1, g.Map{\"passport\": \"tx2_lock\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Wait for both transactions to complete\n\t\twg.Wait()\n\n\t\t// At least one transaction should fail due to deadlock\n\t\tt.Assert(errs[0] != nil || errs[1] != nil, true)\n\t})\n}\n\n// Test_Transaction_Deadlock_SameTable tests deadlock detection on same table\nfunc Test_Transaction_Deadlock_SameTable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg sync.WaitGroup\n\t\terrs := make([]error, 2)\n\t\t// Use channels to synchronize lock acquisition order.\n\t\ttx1Locked := make(chan struct{})\n\t\ttx2Locked := make(chan struct{})\n\n\t\t// Transaction 1: lock id=1 then id=2\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[0] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t_, err := tx.Update(table, g.Map{\"nickname\": \"tx1\"}, \"id=1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx1Locked)\n\t\t\t\t<-tx2Locked\n\t\t\t\t_, err = tx.Update(table, g.Map{\"nickname\": \"tx1\"}, \"id=2\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Transaction 2: lock id=2 then id=1\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\terrs[1] = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t<-tx1Locked\n\t\t\t\t_, err := tx.Update(table, g.Map{\"nickname\": \"tx2\"}, \"id=2\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclose(tx2Locked)\n\t\t\t\t_, err = tx.Update(table, g.Map{\"nickname\": \"tx2\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\n\t\t// Wait for both transactions to complete\n\t\twg.Wait()\n\n\t\t// At least one transaction should fail due to deadlock\n\t\tt.Assert(errs[0] != nil || errs[1] != nil, true)\n\t})\n}\n\n// Test_Transaction_Deadlock_Retry tests automatic retry on deadlock\nfunc Test_Transaction_Deadlock_Retry(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmaxRetries := 3\n\t\tvar retryCount int\n\n\t\texecuteWithRetry := func(fn func(context.Context, gdb.TX) error) error {\n\t\t\tfor i := 0; i < maxRetries; i++ {\n\t\t\t\terr := db.Transaction(ctx, fn)\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t// Check if error message contains deadlock-related keywords.\n\t\t\t\terrMsg := err.Error()\n\t\t\t\tif gstr.ContainsI(errMsg, \"deadlock\") || gstr.ContainsI(errMsg, \"lock wait timeout\") {\n\t\t\t\t\tretryCount++\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn gerror.New(\"max retries exceeded\")\n\t\t}\n\n\t\t// A simple non-conflicting update should succeed on first attempt.\n\t\terr := executeWithRetry(func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"retry_test\"}, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(retryCount, 0)\n\t})\n}\n\n// Test_Transaction_Nested_7Levels tests 7-level deep nested transactions\nfunc Test_Transaction_Nested_7Levels(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(7))\n\t})\n}\n\n// Test_Transaction_Nested_7Levels_PartialRollback tests partial rollback in deep nesting\nfunc Test_Transaction_Nested_7Levels_PartialRollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\t\t// Fail at deepest level\n\t\t\t\t\t\t\t\t\treturn gerror.New(\"rollback from level 7\")\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify all records are rolled back\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\n// Test_Transaction_Nested_10Levels tests maximum depth of 10 levels\nfunc Test_Transaction_Nested_10Levels(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"level1\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn tx1.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"level2\"})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\treturn tx2.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\"id\": 3, \"passport\": \"level3\"})\n\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\treturn tx3.Transaction(ctx, func(ctx context.Context, tx4 gdb.TX) error {\n\t\t\t\t\t\t_, err := tx4.Insert(table, g.Map{\"id\": 4, \"passport\": \"level4\"})\n\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\treturn tx4.Transaction(ctx, func(ctx context.Context, tx5 gdb.TX) error {\n\t\t\t\t\t\t\t_, err := tx5.Insert(table, g.Map{\"id\": 5, \"passport\": \"level5\"})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\treturn tx5.Transaction(ctx, func(ctx context.Context, tx6 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err := tx6.Insert(table, g.Map{\"id\": 6, \"passport\": \"level6\"})\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\treturn tx6.Transaction(ctx, func(ctx context.Context, tx7 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t_, err := tx7.Insert(table, g.Map{\"id\": 7, \"passport\": \"level7\"})\n\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\treturn tx7.Transaction(ctx, func(ctx context.Context, tx8 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t_, err := tx8.Insert(table, g.Map{\"id\": 8, \"passport\": \"level8\"})\n\t\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\t\treturn tx8.Transaction(ctx, func(ctx context.Context, tx9 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t\t_, err := tx9.Insert(table, g.Map{\"id\": 9, \"passport\": \"level9\"})\n\t\t\t\t\t\t\t\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t\t\t\t\t\t\t\treturn tx9.Transaction(ctx, func(ctx context.Context, tx10 gdb.TX) error {\n\t\t\t\t\t\t\t\t\t\t\t\t_, err := tx10.Insert(table, g.Map{\"id\": 10, \"passport\": \"level10\"})\n\t\t\t\t\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(10))\n\t})\n}\n\n// Test_Transaction_Nested_SavePoint_Multiple tests multiple savepoints in nested transactions\nfunc Test_Transaction_Nested_SavePoint_Multiple(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create first savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"sp1\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp1\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create second savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 2, \"passport\": \"sp2\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp2\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert and create third savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 3, \"passport\": \"sp3\"})\n\t\tt.AssertNil(err)\n\t\terr = tx.SavePoint(\"sp3\")\n\t\tt.AssertNil(err)\n\n\t\t// Insert without savepoint\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 4, \"passport\": \"no_sp\"})\n\t\tt.AssertNil(err)\n\n\t\t// Rollback to sp2\n\t\terr = tx.RollbackTo(\"sp2\")\n\t\tt.AssertNil(err)\n\n\t\t// Commit transaction\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Verify only records up to sp2 exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tv1, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v1.String(), \"sp1\")\n\n\t\tv2, err := db.Model(table).Where(\"id=2\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), \"sp2\")\n\t})\n}\n\n// Test_Transaction_Nested_SavePoint_RollbackToNonExistent tests rollback to non-existent savepoint\nfunc Test_Transaction_Nested_SavePoint_RollbackToNonExistent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\t// Try to rollback to non-existent savepoint\n\t\terr = tx.RollbackTo(\"non_existent\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Concurrent_Insert tests concurrent inserts in separate transactions\nfunc Test_Transaction_Concurrent_Insert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg = sync.WaitGroup{}\n\t\tconcurrency := 10\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(index int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":       index + 1,\n\t\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", index+1),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}(i)\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Verify all records exist\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(concurrency))\n\t})\n}\n\n// Test_Transaction_Concurrent_Update tests concurrent updates to same record\nfunc Test_Transaction_Concurrent_Update(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tvar wg = sync.WaitGroup{}\n\t\tconcurrency := 5\n\n\t\twg.Add(concurrency)\n\t\tfor i := 0; i < concurrency; i++ {\n\t\t\tgo func(index int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t_ = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t\t\t_, err := tx.Update(table, g.Map{\n\t\t\t\t\t\t\"nickname\": fmt.Sprintf(\"concurrent_%d\", index),\n\t\t\t\t\t}, \"id=1\")\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t}(i)\n\t\t}\n\n\t\twg.Wait()\n\n\t\t// Verify record was updated (one of the concurrent values should win)\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"nickname\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(v.String(), \"name_1\")\n\t})\n}\n\n// Test_Transaction_Mixed_Propagation_Nested tests mixed propagation modes in nested transactions\nfunc Test_Transaction_Mixed_Propagation_Nested(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\"id\": 1, \"passport\": \"outer\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// REQUIRES_NEW - should create independent transaction\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 2, \"passport\": \"independent\"})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// NESTED - should create savepoint\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 3, \"passport\": \"nested\"})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn gerror.New(\"rollback nested\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// REQUIRED - should use existing transaction\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\"id\": 4, \"passport\": \"required\"})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify results: outer, independent, and required should exist; nested should not\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\texists, err := db.Model(table).Where(\"passport\", \"nested\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exists, int64(0))\n\t})\n}\n\n// Test_Transaction_Rollback_After_Commit tests that rollback after commit fails\nfunc Test_Transaction_Rollback_After_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Try to rollback after commit\n\t\terr = tx.Rollback()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Commit_After_Rollback tests that commit after rollback fails\nfunc Test_Transaction_Commit_After_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// Try to commit after rollback\n\t\terr = tx.Commit()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Operation_After_Commit tests that operations after commit fail\nfunc Test_Transaction_Operation_After_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// Try to insert after commit\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Operation_After_Rollback tests that operations after rollback fail\nfunc Test_Transaction_Operation_After_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// Try to insert after rollback\n\t\t_, err = tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Context_Timeout tests transaction with context timeout\nfunc Test_Transaction_Context_Timeout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// Create context with timeout\n\t\tctx, cancel := context.WithTimeout(context.Background(), 100*gtime.MS)\n\t\tdefer cancel()\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Wait for context timeout instead of using fixed sleep.\n\t\t\t<-ctx.Done()\n\t\t\treturn ctx.Err()\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Context_Cancel tests transaction with context cancellation\nfunc Test_Transaction_Context_Cancel(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tcancel()\n\t\t}()\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\"id\": 1, \"passport\": \"test\"})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Wait for context cancellation instead of using fixed sleep.\n\t\t\t<-ctx.Done()\n\t\t\treturn ctx.Err()\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_Empty_NoOperations tests empty transaction with no operations\nfunc Test_Transaction_Empty_NoOperations(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// No operations\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Test_Transaction_Large_Batch_Insert tests transaction with large batch insert\nfunc Test_Transaction_Large_Batch_Insert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\tbatchSize := 1000\n\t\t\tdata := make(g.List, batchSize)\n\t\t\tfor i := 0; i < batchSize; i++ {\n\t\t\t\tdata[i] = g.Map{\n\t\t\t\t\t\"id\":       i + 1,\n\t\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", i+1),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_, err := tx.Insert(table, data)\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1000))\n\t})\n}\n\n// Test_Transaction_Large_Batch_Update tests transaction with large batch update\nfunc Test_Transaction_Large_Batch_Update(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// First insert records\n\t\tbatchSize := 500\n\t\tdata := make(g.List, batchSize)\n\t\tfor i := 0; i < batchSize; i++ {\n\t\t\tdata[i] = g.Map{\n\t\t\t\t\"id\":       i + 1,\n\t\t\t\t\"passport\": fmt.Sprintf(\"user_%d\", i+1),\n\t\t\t}\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\t// Update all records in transaction (WHERE required for safety)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Where(\"id > ?\", 0).Update(g.Map{\"nickname\": \"updated\"})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all records updated\n\t\tcount, err := db.Model(table).Where(\"nickname\", \"updated\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(batchSize))\n\t})\n}\n\n// Test_Transaction_ReadOnly_WithUpdate tests that updates fail in read-only transactions\nfunc Test_Transaction_ReadOnly_WithUpdate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Read operations should work\n\t\t\t_, err := tx.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Write operations should fail\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":       100,\n\t\t\t\t\"passport\": \"new_user\",\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Transaction_ReadOnly_WithDelete tests that deletes fail in read-only transactions\nfunc Test_Transaction_ReadOnly_WithDelete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Delete(table, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify record still exists\n\t\tcount, err := db.Model(table).Where(\"id=1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/mysql/testdata/date_time_example.sql",
    "content": "CREATE TABLE `date_time_example` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT,\n    `year` year DEFAULT NULL COMMENT 'year',\n    `date` date DEFAULT NULL COMMENT 'Date',\n    `time` time DEFAULT NULL COMMENT 'time',\n    `datetime` datetime DEFAULT NULL COMMENT 'datetime',\n    `timestamp` timestamp NULL DEFAULT NULL COMMENT 'Timestamp',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/fix_gdb_join.sql",
    "content": "\n\nDROP TABLE IF EXISTS `common_resource`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `common_resource` (\n    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) NOT NULL,\n    `resource_id` varchar(64) NOT NULL,\n    `src_instance_id` varchar(64) DEFAULT NULL,\n    `region` varchar(36) DEFAULT NULL,\n    `zone` varchar(36) DEFAULT NULL,\n    `database_kind` varchar(20) NOT NULL,\n    `source_type` varchar(64) NOT NULL,\n    `ip` varchar(64) DEFAULT NULL,\n    `port` int(10) DEFAULT NULL,\n    `vpc_id` varchar(20) DEFAULT NULL,\n    `subnet_id` varchar(20) DEFAULT NULL,\n    `proxy_ip` varchar(64) DEFAULT NULL,\n    `proxy_port` int(10) DEFAULT NULL,\n    `proxy_id` bigint(20) DEFAULT NULL,\n    `proxy_snat_ip` varchar(64) DEFAULT NULL,\n    `lease_at` timestamp NULL DEFAULT NULL,\n    `uin` varchar(32) NOT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `unique_resource` (`app_id`,`src_instance_id`,`vpc_id`,`subnet_id`,`ip`,`port`),\n    KEY `resource_id` (`resource_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COMMENT='资源公共信息表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `common_resource`\n--\n\nLOCK TABLES `common_resource` WRITE;\n/*!40000 ALTER TABLE `common_resource` DISABLE KEYS */;\nINSERT INTO `common_resource` VALUES (1,1,'2','2','2','3','1','1','1',1,'1','1','1',1,1,'1',NULL,''),(3,2,'3','3','3','3','3','3','3',3,'3','3','3',3,3,'3',NULL,''),(18,1303697168,'dmc-rgnh9qre','vdb-6b6m3u1u','ap-guangzhou','','vdb','cloud','10.0.1.16',80,'vpc-m3dchft7','subnet-9as3a3z2','9.27.72.189',11131,228476,'169.254.128.5, ','2023-11-08 08:13:04',''),(20,1303697168,'dmc-4grzi4jg','tdsqlshard-313spncx','ap-guangzhou','','tdsql','cloud','10.255.0.27',3306,'vpc-407k0e8x','subnet-qhkkk3bo','30.86.239.200',24087,0,'',NULL,'');\n/*!40000 ALTER TABLE `common_resource` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `managed_resource`\n--\n\nDROP TABLE IF EXISTS `managed_resource`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `managed_resource` (\n     `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n     `instance_id` varchar(64) NOT NULL,\n     `resource_id` varchar(64) NOT NULL,\n     `resource_name` varchar(64) DEFAULT NULL,\n     `status` varchar(36) NOT NULL DEFAULT 'valid',\n     `status_message` varchar(64) DEFAULT NULL,\n     `user` varchar(64) NOT NULL,\n     `password` varchar(1024) NOT NULL,\n     `pay_mode` tinyint(1) DEFAULT '0',\n     `safe_publication` bit(1) DEFAULT b'0',\n     `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n     `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n     `expired_at` timestamp NULL DEFAULT NULL,\n     `deleted` tinyint(1) NOT NULL DEFAULT '0',\n     `resource_mark_id` int(11) DEFAULT NULL,\n     `comments` varchar(64) DEFAULT NULL,\n     `rule_template_id` varchar(64) NOT NULL,\n     PRIMARY KEY (`id`),\n     UNIQUE KEY `resource_id` (`resource_id`),\n     KEY `instance_id` (`instance_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='管控实例表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `managed_resource`\n--\n\nLOCK TABLES `managed_resource` WRITE;\n/*!40000 ALTER TABLE `managed_resource` DISABLE KEYS */;\nINSERT INTO `managed_resource` VALUES (1,'2','3','1','1','1','1','1',1,_binary '\u0001','2023-11-06 12:14:21','2023-11-06 12:14:21',NULL,1,1,'1',''),(2,'3','2','1','1','1','1','1',1,_binary '\\0','2023-11-06 12:15:07','2023-11-06 12:15:07',NULL,1,2,'1',''),(5,'dmcins-jxy0x75m','dmc-rgnh9qre','erichmao-vdb-test','invalid','The Ip field is required','root','2e39af3dd1d447e2b1437b40c62c35995fa22b370c7455ff7815dace3a6e8891ccadcfc893fe1342a4102d742bd7a3e603cd0ac1fcdc072d7c0b5be5836ec87306981b629f9b59aedf0316e9504ab172fa1c95756d5b260114e4feaa0b19223fb61cb268cc4818307ed193dbab830cf556b91cde182686eb70f70ea77f69eff66230dec2ce92bd3352cad31abf47597a5cc6a0d638381dc3bae7aa1b142730790a6d4cefdef1bd460061c966ad5008c2b5fc971b7f4d7dddffa5b1456c45e2917763dd8fffb1fa7fc4783feca95dafc9a9f4edf21b0579f76b0a3154f087e3b9a7fc49af8ff92b12e7b03caa865e72e777dd9d35a11910df0d55ead90e47d5f8',1,_binary '\u0001','2023-11-08 08:13:20','2023-11-09 05:31:07',NULL,0,11,NULL,'12345'),(6,'dmcins-erxms6ya','dmc-4grzi4jg','erichmao-vdb-test','invalid','The Ip field is required','leotaowang','641d846cf75bc7944202251d97dca8335f7f149dd4fd911ca5b87c71ef1dc5d0a66c4e5021ef7ad53136cda2fb2567d34e3dd1a7666e3f64ebf532eb2a55d84952aac86b4211f563f7b9da7dd0f88ec288d6680d3513cea0c1b7ad7babb474717f77ebbc9d63bb458adaf982887da9e63df957ffda572c1c3ed187471b99fdc640b45fed76a6d50dc1090eee79b4d94d056c4d43416133481f55bd040759398680104a84d801e6475dcfe919a00859908296747430b728a00c8d54256ae220235a138e0bbf08fe8b6fc8589971436b55bff966154721a91adbdc9c2b6f50ef5849ed77e5b028116abac51584b8d401cd3a88d18df127006358ed33fc3fa6f480',1,_binary '\u0001','2023-11-08 22:15:17','2023-11-09 05:31:07',NULL,0,11,NULL,'12345');\n/*!40000 ALTER TABLE `managed_resource` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `rules_template`\n--\n\nDROP TABLE IF EXISTS `rules_template`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `rules_template` (\n    `id` bigint(20) NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) DEFAULT NULL,\n    `name` varchar(255) NOT NULL,\n    `database_kind` varchar(64) DEFAULT NULL,\n    `is_default` tinyint(1) NOT NULL DEFAULT '0',\n    `win_rules` varchar(2048) DEFAULT NULL,\n    `inception_rules` varchar(2048) DEFAULT NULL,\n    `auto_exec_rules` varchar(2048) DEFAULT NULL,\n    `order_check_step` varchar(2048) DEFAULT NULL,\n    `template_id` varchar(64) NOT NULL DEFAULT '',\n    `version` int(11) NOT NULL DEFAULT '1',\n    `deleted` tinyint(1) NOT NULL DEFAULT '0',\n    `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n    `is_system` tinyint(1) NOT NULL DEFAULT '0',\n    `uin` varchar(64) DEFAULT NULL,\n    `subAccountUin` varchar(64) DEFAULT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `uniq_template_id` (`template_id`),\n    UNIQUE KEY `uniq_name` (`name`,`app_id`,`deleted`,`uin`) USING BTREE\n) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `rules_template`\n--\n\nLOCK TABLES `rules_template` WRITE;\n/*!40000 ALTER TABLE `rules_template` DISABLE KEYS */;\n/*!40000 ALTER TABLE `rules_template` ENABLE KEYS */;\nUNLOCK TABLES;\n\n--\n-- Table structure for table `resource_mark`\n--\n\nDROP TABLE IF EXISTS `resource_mark`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!50503 SET character_set_client = utf8mb4 */;\nCREATE TABLE `resource_mark` (\n    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,\n    `app_id` bigint(20) NOT NULL,\n    `mark_name` varchar(64) NOT NULL,\n    `color` varchar(11) NOT NULL,\n    `creator` varchar(32) NOT NULL,\n    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `app_id_name` (`app_id`,`mark_name`)\n) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='标签信息表';\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Dumping data for table `resource_mark`\n--\n\nLOCK TABLES `resource_mark` WRITE;\n/*!40000 ALTER TABLE `resource_mark` DISABLE KEYS */;\nINSERT INTO `resource_mark` VALUES (10,1,'test','red','1','2023-11-06 02:45:46','2023-11-06 02:45:46');\n/*!40000 ALTER TABLE `resource_mark` ENABLE KEYS */;\nUNLOCK TABLES;\n\n"
  },
  {
    "path": "contrib/drivers/mysql/testdata/fix_gdb_join_expect.sql",
    "content": "SELECT `managed_resource`.`resource_id`,`managed_resource`.`user`,`managed_resource`.`status`,`managed_resource`.`status_message`,`managed_resource`.`safe_publication`,`managed_resource`.`rule_template_id`,`managed_resource`.`created_at`,`managed_resource`.`comments`,`managed_resource`.`expired_at`,`managed_resource`.`resource_mark_id`,`managed_resource`.`instance_id`,`managed_resource`.`resource_name`,`managed_resource`.`pay_mode`,`resource_mark`.`mark_name`,`resource_mark`.`color`,`rules_template`.`name`,`common_resource`.`src_instance_id`,`common_resource`.`database_kind`,`common_resource`.`source_type`,`common_resource`.`ip`,`common_resource`.`port` FROM `managed_resource` LEFT JOIN `common_resource` ON (`managed_resource`.`resource_id`=`common_resource`.`resource_id`) LEFT JOIN `resource_mark` ON (`managed_resource`.`resource_mark_id` = `resource_mark`.`id`) LEFT JOIN `rules_template` ON (`managed_resource`.`rule_template_id` = `rules_template`.`template_id`) ORDER BY `src_instance_id` ASC"
  },
  {
    "path": "contrib/drivers/mysql/testdata/fix_gdb_order_by.sql",
    "content": "CREATE TABLE IF NOT EXISTS `employee`\n(\n    id         BIGINT AUTO_INCREMENT PRIMARY KEY,\n    name       VARCHAR(255)                        NOT NULL,\n    age        INT                                 NOT NULL\n);\n\nINSERT INTO employee(name, age) VALUES ('John', 30);\nINSERT INTO employee(name, age) VALUES ('Mary', 28);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/1380.sql",
    "content": "CREATE TABLE `jfy_gift`  (\n`id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT,\n`gift_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品名称',\n`at_least_recharge_count` int(0) UNSIGNED NOT NULL DEFAULT 1 COMMENT '最少兑换数量',\n`comments` json NOT NULL COMMENT '礼品留言',\n`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品详情',\n`cost_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '成本价',\n`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '封面',\n`covers` json NOT NULL COMMENT '礼品图片库',\n`description` varchar(62) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '礼品备注',\n`express_type` json NOT NULL COMMENT '配送方式',\n`gift_type` int(0) NOT NULL COMMENT '礼品类型：1：实物；2：虚拟；3：优惠券；4：积分券',\n`has_props` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否有多个属性',\n`is_limit_sell` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否限购',\n`limit_customer_tags` json NOT NULL COMMENT '语序购买的会员标签',\n`limit_sell_custom` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启允许购买的会员标签',\n`limit_sell_cycle` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '限购周期',\n`limit_sell_cycle_count` int(0) NOT NULL COMMENT '限购期内允许购买的数量',\n`limit_sell_type` tinyint(0) NOT NULL COMMENT '限购类型',\n`market_price` decimal(10, 2) NOT NULL COMMENT '市场价',\n`out_sn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内部编码',\n`props` json NOT NULL COMMENT '规格',\n`skus` json NOT NULL COMMENT 'SKU',\n`score_price` decimal(10, 2) NOT NULL COMMENT '兑换所需积分',\n`stock` int(0) NOT NULL COMMENT '库存',\n`create_at` datetime(0) NOT NULL COMMENT '创建日期',\n`store_id` int(0) NOT NULL COMMENT '所属商城',\n`status` int(0) UNSIGNED NULL DEFAULT 1 COMMENT '1：下架；20：审核中；30：复审中；99：上架',\n`view_count` int(0) NOT NULL DEFAULT 0 COMMENT '访问量',\n`sell_count` int(0) NULL DEFAULT 0 COMMENT '销量',\nPRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n\nINSERT INTO `jfy_gift` VALUES (17, 'GIFT', 1, '[{\\\"name\\\": \\\"身份证\\\", \\\"field\\\": \\\"idcard\\\", \\\"required\\\": false}, {\\\"name\\\": \\\"留言2\\\", \\\"field\\\": \\\"text\\\", \\\"required\\\": false}]', '<p>礼品详情</p>', 0.00, '', '{\\\"list\\\": [{\\\"uid\\\": \\\"vc-upload-1629292486099-3\\\", \\\"url\\\": \\\"https://cdn.taobao.com/sULsYiwaOPjsKGoBXwKtuewPzACpBDfQ.jpg\\\", \\\"name\\\": \\\"O1CN01OH6PIP1Oc5ot06U17_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}, {\\\"uid\\\": \\\"vc-upload-1629292486099-4\\\", \\\"url\\\": \\\"https://cdn.taobao.com/lqLHDcrFTgNvlWyXfLYZwmsrODzIBtFH.jpg\\\", \\\"name\\\": \\\"O1CN018hBckI1Oc5ouc8ppl_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}, {\\\"uid\\\": \\\"vc-upload-1629292486099-5\\\", \\\"url\\\": \\\"https://cdn.taobao.com/pvqyutXckICmHhbPBQtrVLHuMlXuGxUg.jpg\\\", \\\"name\\\": \\\"O1CN0185Ubp91Oc5osQTTcc_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}]}', '支持个性定制的父亲节老师长辈的专属礼物', '[\\\"快递包邮\\\", \\\"同城配送\\\"]', 1, 0, 0, '[]', 0, 'day', 0, 1, 0.00, '259402', '[{\\\"name\\\": \\\"颜色\\\", \\\"values\\\": [\\\"红色\\\", \\\"蓝色\\\"]}]', '[{\\\"name\\\": \\\"red\\\", \\\"stock\\\": 10, \\\"gift_id\\\": 1, \\\"cost_price\\\": 80, \\\"score_price\\\": 188, \\\"market_price\\\": 388}, {\\\"name\\\": \\\"blue\\\", \\\"stock\\\": 100, \\\"gift_id\\\": 2, \\\"cost_price\\\": 81, \\\"score_price\\\": 200, \\\"market_price\\\": 288}]', 10.00, 0, '2021-08-18 21:26:13', 100004, 99, 0, 0);\n"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/1401.sql",
    "content": "-- ----------------------------\n-- Table structure for parcel_items\n-- ----------------------------\nDROP TABLE IF EXISTS `parcel_items`;\nCREATE TABLE `parcel_items`  (\n    `id` int(11) NOT NULL,\n    `parcel_id` int(11) NULL DEFAULT NULL,\n    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcel_items\n-- ----------------------------\nINSERT INTO `parcel_items` VALUES (1, 1, '新品');\nINSERT INTO `parcel_items` VALUES (2, 3, '新品2');\n\n-- ----------------------------\n-- Table structure for parcels\n-- ----------------------------\nDROP TABLE IF EXISTS `parcels`;\nCREATE TABLE `parcels`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcels\n-- ----------------------------\nINSERT INTO `parcels` VALUES (1);\nINSERT INTO `parcels` VALUES (2);\nINSERT INTO `parcels` VALUES (3);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/1412.sql",
    "content": "-- ----------------------------\n-- Table structure for items\n-- ----------------------------\nCREATE TABLE `items`  (\n    `id` int(11) NOT NULL,\n    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of items\n-- ----------------------------\nINSERT INTO `items` VALUES (1, '金秋产品1');\nINSERT INTO `items` VALUES (2, '金秋产品2');\n\n-- ----------------------------\n-- Table structure for parcels\n-- ----------------------------\nCREATE TABLE `parcels`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `item_id` int(11) NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcels\n-- ----------------------------\nINSERT INTO `parcels` VALUES (1, 1);\nINSERT INTO `parcels` VALUES (2, 2);\nINSERT INTO `parcels` VALUES (3, 0);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/2105.sql",
    "content": "CREATE TABLE `issue2105` (\n    `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,\n    `json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB;\n\n\nINSERT INTO `issue2105` VALUES ('1', NULL);\nINSERT INTO `issue2105` VALUES ('2', '[{\\\"Name\\\": \\\"任务类型\\\", \\\"Value\\\": \\\"高价值\\\"}, {\\\"Name\\\": \\\"优先级\\\", \\\"Value\\\": \\\"高\\\"}, {\\\"Name\\\": \\\"是否亮点功能\\\", \\\"Value\\\": \\\"是\\\"}]');\n"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/2119.sql",
    "content": "SET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for sys_role\n-- ----------------------------\nDROP TABLE IF EXISTS `sys_role`;\nCREATE TABLE `sys_role`  (\n                             `id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '||s',\n                             `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '角色名称||s,r',\n                             `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '角色 code||s,r',\n                             `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '描述信息|text',\n                             `weight` int(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '排序||r|min:0#发布状态不能小于 0',\n                             `status_id` int(0) UNSIGNED NOT NULL DEFAULT 1 COMMENT '发布状态|hasOne|f:status,fk:id',\n                             `created_at` datetime(0) NULL DEFAULT NULL,\n                             `updated_at` datetime(0) NULL DEFAULT NULL,\n                             PRIMARY KEY (`id`) USING BTREE,\n                             INDEX `code`(`code`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 1091 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色表' ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of sys_role\n-- ----------------------------\nINSERT INTO `sys_role` VALUES (1, '开发人员', 'developer', '123123', 900, 2, '2022-09-03 21:25:03', '2022-09-09 23:35:23');\nINSERT INTO `sys_role` VALUES (2, '管理员', 'admin', '', 800, 1, '2022-09-03 21:25:03', '2022-09-09 23:00:17');\nINSERT INTO `sys_role` VALUES (3, '运营', 'operator', '', 700, 1, '2022-09-03 21:25:03', '2022-09-03 21:25:03');\nINSERT INTO `sys_role` VALUES (4, '客服', 'service', '', 600, 1, '2022-09-03 21:25:03', '2022-09-03 21:25:03');\nINSERT INTO `sys_role` VALUES (5, '收银', 'account', '', 500, 1, '2022-09-03 21:25:03', '2022-09-03 21:25:03');\n\n-- ----------------------------\n-- Table structure for sys_status\n-- ----------------------------\nDROP TABLE IF EXISTS `sys_status`;\nCREATE TABLE `sys_status`  (\n                               `id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT,\n                               `en` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '英文名称',\n                               `cn` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '中文名称',\n                               `weight` int(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '排序权重',\n                               PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '发布状态' ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of sys_status\n-- ----------------------------\nINSERT INTO `sys_status` VALUES (1, 'on line', '上线', 900);\nINSERT INTO `sys_status` VALUES (2, 'undecided', '未决定', 800);\nINSERT INTO `sys_status` VALUES (3, 'off line', '下线', 700);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/2439.sql",
    "content": "CREATE TABLE `a`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    PRIMARY KEY (id) USING BTREE\n) ENGINE = InnoDB;\nINSERT INTO `a` (`id`) VALUES ('2');\n\nCREATE TABLE `b`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `name` varchar(255) NOT NULL ,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\nINSERT INTO `b` (`id`, `name`) VALUES ('2', 'a');\nINSERT INTO `b` (`id`, `name`) VALUES ('3', 'b');\n\nCREATE TABLE `c`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\nINSERT INTO `c` (`id`) VALUES ('2');"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/2643.sql",
    "content": "CREATE TABLE `issue2643` (\n    `id` INT(10) NULL DEFAULT NULL,\n    `name` VARCHAR(50) NULL DEFAULT NULL,\n    `value` INT(10) NULL DEFAULT NULL,\n    `dept` VARCHAR(50) NULL DEFAULT NULL\n)\nENGINE=InnoDB"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/3086.sql",
    "content": "CREATE TABLE `issue3086_user`\n(\n    `id`        int(10) unsigned NOT NULL COMMENT 'User ID',\n    `passport`  varchar(45) NOT NULL COMMENT 'User Passport',\n    `password`  varchar(45) DEFAULT NULL COMMENT 'User Password',\n    `nickname`  varchar(45) DEFAULT NULL COMMENT 'User Nickname',\n    `create_at` datetime DEFAULT NULL COMMENT 'Created Time',\n    `update_at` datetime DEFAULT NULL COMMENT 'Updated Time',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/3218.sql",
    "content": "CREATE TABLE `issue3218_sys_config`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '配置名称',\n    `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '配置值',\n    `created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间',\n    `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间',\n    PRIMARY KEY (`id`) USING BTREE,\n    UNIQUE INDEX `name`(`name`(191)) USING BTREE\n) ENGINE = InnoDB  CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;\n\n-- ----------------------------\n-- Records of sys_config\n-- ----------------------------\nINSERT INTO `issue3218_sys_config` VALUES (49, 'site', '{\\\"banned_ip\\\":\\\"22\\\",\\\"filings\\\":\\\"2222\\\",\\\"fixed_page\\\":\\\"\\\",\\\"site_name\\\":\\\"22\\\",\\\"version\\\":\\\"22\\\"}', '2023-12-19 14:08:25', '2023-12-19 14:08:25');"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/3626.sql",
    "content": "CREATE TABLE `issue3626` (\n    id        int(11) NOT NULL,\n    name      varchar(45) DEFAULT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/3754.sql",
    "content": "CREATE TABLE `issue3754` (\n    id        int(11) NOT NULL,\n    name      varchar(45) DEFAULT NULL,\n    create_at datetime(0) DEFAULT NULL,\n    update_at datetime(0) DEFAULT NULL,\n    delete_at datetime(0) DEFAULT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/3915.sql",
    "content": "CREATE TABLE `issue3915` (\n    `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'user id',\n    `a` float DEFAULT NULL COMMENT 'user name',\n    `b` float DEFAULT NULL COMMENT 'user status',\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB  DEFAULT CHARSET=utf8;\n\nINSERT INTO `issue3915` (`id`,`a`,`b`) VALUES (1,1,2);\nINSERT INTO `issue3915` (`id`,`a`,`b`) VALUES (2,5,4);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/4034.sql",
    "content": "CREATE TABLE issue4034 (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    passport VARCHAR(255),\n    password VARCHAR(255),\n    nickname VARCHAR(255),\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP\n);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/issues/4086.sql",
    "content": "DROP TABLE IF EXISTS `issue4086`;\nCREATE TABLE `issue4086` (\n    `proxy_id` bigint NOT NULL,\n    `recommend_ids` json DEFAULT NULL,\n    `photos` json DEFAULT NULL,\n    PRIMARY KEY (`proxy_id`)\n) ENGINE=InnoDB;\n\nINSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (1, '[584, 585]', 'null');\nINSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (2, '[]', NULL);"
  },
  {
    "path": "contrib/drivers/mysql/testdata/reservedwords_table_tpl.sql",
    "content": "CREATE TABLE %s (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `key` varchar(45) DEFAULT NULL,\n  `category_id` int(10) unsigned NOT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  `title` varchar(255) NOT NULL,\n  `content` mediumtext NOT NULL,\n  `sort` int(10) unsigned DEFAULT '0',\n  `brief` varchar(255) DEFAULT NULL,\n  `thumb` varchar(255) DEFAULT NULL,\n  `tags` varchar(900) DEFAULT NULL,\n  `referer` varchar(255) DEFAULT NULL,\n  `status` smallint(5) unsigned DEFAULT '0',\n  `view_count` int(10) unsigned DEFAULT '0',\n  `zan_count` int(10) unsigned DEFAULT NULL,\n  `cai_count` int(10) unsigned DEFAULT NULL,\n  `created_at` datetime DEFAULT NULL,\n  `updated_at` datetime DEFAULT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/table_with_prefix.sql",
    "content": "CREATE TABLE `instance`  (\n    `f_id` int(11) NOT NULL AUTO_INCREMENT,\n    `name` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`f_id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `instance` VALUES (1, 'john');"
  },
  {
    "path": "contrib/drivers/mysql/testdata/with_multiple_depends.sql",
    "content": "\nCREATE TABLE `table_a`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_a` VALUES (1, 'table_a_test1');\nINSERT INTO `table_a` VALUES (2, 'table_a_test2');\n\nCREATE TABLE `table_b`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_a_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_b` VALUES (10, 1, 'table_b_test1');\nINSERT INTO `table_b` VALUES (20, 2, 'table_b_test2');\nINSERT INTO `table_b` VALUES (30, 1, 'table_b_test3');\nINSERT INTO `table_b` VALUES (40, 2, 'table_b_test4');\n\nCREATE TABLE `table_c`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_b_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_c` VALUES (100, 10, 'table_c_test1');\nINSERT INTO `table_c` VALUES (200, 10, 'table_c_test2');\nINSERT INTO `table_c` VALUES (300, 20, 'table_c_test3');\nINSERT INTO `table_c` VALUES (400, 30, 'table_c_test4');"
  },
  {
    "path": "contrib/drivers/mysql/testdata/with_tpl_user.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id int(10) unsigned NOT NULL AUTO_INCREMENT,\n    name varchar(45) NOT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/with_tpl_user_detail.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    uid int(10) unsigned NOT NULL AUTO_INCREMENT,\n    address varchar(45) NOT NULL,\n    PRIMARY KEY (uid)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/mysql/testdata/with_tpl_user_scores.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id int(10) unsigned NOT NULL AUTO_INCREMENT,\n    uid int(10) unsigned NOT NULL,\n    score int(10) unsigned NOT NULL,\n    PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "contrib/drivers/oceanbase/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/oceanbase/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-sql-driver/mysql v1.7.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 => ../mysql\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/drivers/oceanbase/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=\ngithub.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/oceanbase/oceanbase.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package oceanbase implements gdb.Driver, which supports operations for database OceanBase.\npackage oceanbase\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\n// Driver is the driver for OceanBase database.\n//\n// OceanBase is a distributed relational database developed by Ant Group. It supports both MySQL and Oracle\n// protocol modes. This driver uses the MySQL protocol to communicate with OceanBase database in MySQL\n// compatibility mode.\n//\n// Although OceanBase is compatible with MySQL protocol, it is packaged as a separate driver component\n// rather than reusing the mysql adapter directly. This design allows for future extensibility,\n// such as implementing OceanBase-specific features like distributed transactions or Oracle mode support.\ntype Driver struct {\n\t*mysql.Driver\n}\n\nfunc init() {\n\tvar (\n\t\terr         error\n\t\tdriverObj   = New()\n\t\tdriverNames = g.SliceStr{\"oceanbase\"}\n\t)\n\tfor _, driverName := range driverNames {\n\t\tif err = gdb.Register(driverName, driverObj); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// New creates and returns a driver that implements gdb.Driver, which supports operations for OceanBase.\nfunc New() gdb.Driver {\n\tmysqlDriver := mysql.New().(*mysql.Driver)\n\treturn &Driver{\n\t\tDriver: mysqlDriver,\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/oracle/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/sijms/go-ora/v2 v2.7.10\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/oracle/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/sijms/go-ora/v2 v2.7.10 h1:GSLdj0PYYgSndhsnm7b6p32OqgnwnUZSkFb3j+htfhI=\ngithub.com/sijms/go-ora/v2 v2.7.10/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package oracle implements gdb.Driver, which supports operations for database Oracle.\npackage oracle\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Driver is the driver for oracle database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\trowNumberAliasForSelect = `ROW_NUMBER__`\n\tquoteChar               = `\"`\n)\n\nfunc init() {\n\tif err := gdb.Register(`oracle`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for Oracle.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for oracle.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_do_commit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// DoCommit commits current sql and arguments to underlying sql driver.\nfunc (d *Driver) DoCommit(ctx context.Context, in gdb.DoCommitInput) (out gdb.DoCommitOutput, err error) {\n\tout, err = d.Core.DoCommit(ctx, in)\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(out.Records) > 0 {\n\t\t// remove auto added field.\n\t\tfor i, record := range out.Records {\n\t\t\tdelete(record, rowNumberAliasForSelect)\n\t\t\tout.Records[i] = record\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_do_exec.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\treturningClause = \" RETURNING %s INTO ?\"\n)\n\n// DoExec commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\n// It handles INSERT statements specially to support LastInsertId.\nfunc (d *Driver) DoExec(\n\tctx context.Context, link gdb.Link, sql string, args ...interface{},\n) (result sql.Result, err error) {\n\tvar (\n\t\tisUseCoreDoExec = true\n\t\tprimaryKey      string\n\t\tpkField         gdb.TableField\n\t)\n\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\tlink = tx\n\t\t} else if link, err = d.MasterLink(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\tlink = tx\n\t\t}\n\t}\n\n\t// Check if it is an insert operation with primary key from context.\n\tif value := ctx.Value(internalPrimaryKeyInCtx); value != nil {\n\t\tif field, ok := value.(gdb.TableField); ok {\n\t\t\tpkField = field\n\t\t\tisUseCoreDoExec = false\n\t\t}\n\t}\n\n\t// Check if it is an INSERT statement with primary key.\n\tif !isUseCoreDoExec && pkField.Name != \"\" && strings.Contains(strings.ToUpper(sql), \"INSERT INTO\") {\n\t\tprimaryKey = pkField.Name\n\t\t// Oracle supports RETURNING clause to get the last inserted id\n\t\tsql += fmt.Sprintf(returningClause, d.QuoteWord(primaryKey))\n\t} else {\n\t\t// Use default DoExec for non-INSERT or no primary key scenarios\n\t\treturn d.Core.DoExec(ctx, link, sql, args...)\n\t}\n\n\t// Only the insert operation with primary key can execute the following code\n\n\t// SQL filtering.\n\tsql, args = d.FormatSqlBeforeExecuting(sql, args)\n\tsql, args, err = d.DoFilter(ctx, link, sql, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Prepare output variable for RETURNING clause\n\tvar lastInsertId int64\n\t// Append the output parameter for the RETURNING clause\n\targs = append(args, &lastInsertId)\n\n\t// Link execution.\n\t_, err = d.DoCommit(ctx, gdb.DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          gdb.SqlTypeExecContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\n\tif err != nil {\n\t\treturn &Result{\n\t\t\tlastInsertId:      0,\n\t\t\trowsAffected:      0,\n\t\t\tlastInsertIdError: err,\n\t\t}, err\n\t}\n\n\t// Get rows affected from the result\n\t// For single insert with RETURNING clause, affected is always 1\n\tvar affected int64 = 1\n\n\t// Check if the primary key field type supports LastInsertId\n\tif !strings.Contains(strings.ToLower(pkField.Type), \"int\") {\n\t\treturn &Result{\n\t\t\tlastInsertId: 0,\n\t\t\trowsAffected: affected,\n\t\t\tlastInsertIdError: gerror.NewCodef(\n\t\t\t\tgcode.CodeNotSupported,\n\t\t\t\t\"LastInsertId is not supported by primary key type: %s\",\n\t\t\t\tpkField.Type,\n\t\t\t),\n\t\t}, nil\n\t}\n\n\treturn &Result{\n\t\tlastInsertId: lastInsertId,\n\t\trowsAffected: affected,\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\tnewSqlReplacementTmp = `\nSELECT * FROM (\n\tSELECT GFORM.*, ROWNUM ROW_NUMBER__ FROM (%s %s) GFORM WHERE ROWNUM <= %d\n) WHERE ROW_NUMBER__ > %d\n`\n)\n\nfunc init() {\n\tvar err error\n\tnewSqlReplacementTmp, err = gdb.FormatMultiLineSqlToSingle(newSqlReplacementTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []any) (newSql string, newArgs []any, err error) {\n\tvar index int\n\tnewArgs = args\n\t// Convert placeholder char '?' to string \":vx\".\n\tnewSql, err = gregex.ReplaceStringFunc(\"\\\\?\", sql, func(s string) string {\n\t\tindex++\n\t\treturn fmt.Sprintf(\":v%d\", index)\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\tnewSql, err = gregex.ReplaceString(\"\\\"\", \"\", newSql)\n\tif err != nil {\n\t\treturn\n\t}\n\tnewSql, err = d.parseSql(newSql)\n\tif err != nil {\n\t\treturn\n\t}\n\treturn d.Core.DoFilter(ctx, link, newSql, newArgs)\n}\n\n// parseSql does some replacement of the sql before commits it to underlying driver,\n// for support of oracle server.\nfunc (d *Driver) parseSql(toBeCommittedSql string) (string, error) {\n\tvar (\n\t\terr       error\n\t\toperation = gstr.StrTillEx(toBeCommittedSql, \" \")\n\t\tkeyword   = strings.ToUpper(gstr.Trim(operation))\n\t)\n\tswitch keyword {\n\tcase \"SELECT\":\n\t\ttoBeCommittedSql, err = d.handleSelectSqlReplacement(toBeCommittedSql)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\treturn toBeCommittedSql, nil\n}\n\nfunc (d *Driver) handleSelectSqlReplacement(toBeCommittedSql string) (newSql string, err error) {\n\tvar (\n\t\tmatch  [][]string\n\t\tpatten = `^\\s*(?i)(SELECT)|(LIMIT\\s*(\\d+)\\s*,{0,1}\\s*(\\d*))`\n\t)\n\tmatch, err = gregex.MatchAllString(patten, toBeCommittedSql)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(match) == 0 {\n\t\treturn toBeCommittedSql, nil\n\t}\n\tvar index = 1\n\tif len(match) < 2 || strings.HasPrefix(match[index][0], \"LIMIT\") == false {\n\t\treturn toBeCommittedSql, nil\n\t}\n\t// only handle `SELECT ... LIMIT ...` statement.\n\tqueryExpr, err := gregex.MatchString(\"((?i)SELECT)(.+)((?i)LIMIT)\", toBeCommittedSql)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(queryExpr) == 0 {\n\t\treturn toBeCommittedSql, nil\n\t}\n\tif len(queryExpr) != 4 ||\n\t\tstrings.EqualFold(queryExpr[1], \"SELECT\") == false ||\n\t\tstrings.EqualFold(queryExpr[3], \"LIMIT\") == false {\n\t\treturn toBeCommittedSql, nil\n\t}\n\tpage, limit := 0, 0\n\tfor i := 1; i < len(match[index]); i++ {\n\t\tif len(strings.TrimSpace(match[index][i])) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasPrefix(match[index][i], \"LIMIT\") {\n\t\t\tif match[index][i+2] != \"\" {\n\t\t\t\tpage, err = strconv.Atoi(match[index][i+1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\tlimit, err = strconv.Atoi(match[index][i+2])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\tif page <= 0 {\n\t\t\t\t\tpage = 1\n\t\t\t\t}\n\t\t\t\tlimit = (page/limit + 1) * limit\n\t\t\t\tpage, err = strconv.Atoi(match[index][i+1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlimit, err = strconv.Atoi(match[index][i+1])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tvar newReplacedSql = fmt.Sprintf(\n\t\tnewSqlReplacementTmp,\n\t\tqueryExpr[1], queryExpr[2], limit, page,\n\t)\n\treturn newReplacedSql, nil\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tinternalPrimaryKeyInCtx gctx.StrKey = \"primary_key_field\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tswitch option.InsertOption {\n\tcase gdb.InsertOptionSave:\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionReplace:\n\t\t// Oracle does not support REPLACE INTO syntax, use SAVE instead.\n\t\treturn d.doSave(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionIgnore:\n\t\t// Oracle does not support INSERT IGNORE syntax, use MERGE instead.\n\t\treturn d.doInsertIgnore(ctx, link, table, list, option)\n\n\tcase gdb.InsertOptionDefault:\n\t\t// For default insert, set primary key field in context to support LastInsertId.\n\t\t// Only set it when the primary key is not provided in the data, for performance reason.\n\t\ttableFields, err := d.GetCore().GetDB().TableFields(ctx, table)\n\t\tif err == nil && len(list) > 0 {\n\t\t\tfor _, field := range tableFields {\n\t\t\t\tif strings.EqualFold(field.Key, \"pri\") {\n\t\t\t\t\t// Check if primary key is provided in the data.\n\t\t\t\t\tpkProvided := false\n\t\t\t\t\tfor key := range list[0] {\n\t\t\t\t\t\tif strings.EqualFold(key, field.Name) {\n\t\t\t\t\t\t\tpkProvided = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Only use RETURNING when primary key is not provided, for performance reason.\n\t\t\t\t\tif !pkProvided {\n\t\t\t\t\t\tpkField := *field\n\t\t\t\t\t\tctx = context.WithValue(ctx, internalPrimaryKeyInCtx, pkField)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t}\n\tvar (\n\t\tkeys   []string\n\t\tvalues []string\n\t\tparams []any\n\t)\n\t// Retrieve the table fields and length.\n\tvar (\n\t\tlistLength  = len(list)\n\t\tvalueHolder = make([]string, 0)\n\t)\n\tfor k := range list[0] {\n\t\tkeys = append(keys, k)\n\t\tvalueHolder = append(valueHolder, \"?\")\n\t}\n\tvar (\n\t\tbatchResult    = new(gdb.SqlResult)\n\t\tcharL, charR   = d.GetChars()\n\t\tkeyStr         = charL + strings.Join(keys, charL+\",\"+charR) + charR\n\t\tvalueHolderStr = strings.Join(valueHolder, \",\")\n\t)\n\t// Format \"INSERT...INTO...\" statement.\n\t// Note: Use standard INSERT INTO syntax instead of INSERT ALL to ensure triggers fire\n\tfor i := 0; i < listLength; i++ {\n\t\tfor _, k := range keys {\n\t\t\tif s, ok := list[i][k].(gdb.Raw); ok {\n\t\t\t\tparams = append(params, gconv.String(s))\n\t\t\t} else {\n\t\t\t\tparams = append(params, list[i][k])\n\t\t\t}\n\t\t}\n\t\tvalues = append(values, valueHolderStr)\n\n\t\t// Execute individual INSERT for each record to trigger row-level triggers\n\t\tr, err := d.DoExec(ctx, link, fmt.Sprintf(\n\t\t\t\"INSERT INTO %s(%s) VALUES(%s)\",\n\t\t\ttable, keyStr, valueHolderStr,\n\t\t), params...)\n\t\tif err != nil {\n\t\t\treturn r, err\n\t\t}\n\t\tif n, err := r.RowsAffected(); err != nil {\n\t\t\treturn r, err\n\t\t} else {\n\t\t\tbatchResult.Result = r\n\t\t\tbatchResult.Affected += n\n\t\t}\n\t\tparams = params[:0]\n\t}\n\treturn batchResult, nil\n}\n\n// doSave support upsert for Oracle\nfunc (d *Driver) doSave(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, true)\n}\n\n// doInsertIgnore implements INSERT IGNORE operation using MERGE statement for Oracle database.\n// It only inserts records when there's no conflict on primary/unique keys.\nfunc (d *Driver) doInsertIgnore(ctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\treturn d.doMergeInsert(ctx, link, table, list, option, false)\n}\n\n// doMergeInsert implements MERGE-based insert operations for Oracle database.\n// When withUpdate is true, it performs upsert (insert or update).\n// When withUpdate is false, it performs insert ignore (insert only when no conflict).\nfunc (d *Driver) doMergeInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, withUpdate bool,\n) (result sql.Result, err error) {\n\t// If OnConflict is not specified, automatically get the primary key of the table\n\tconflictKeys := option.OnConflict\n\tif len(conflictKeys) == 0 {\n\t\tprimaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\terr,\n\t\t\t\t`failed to get primary keys for table`,\n\t\t\t)\n\t\t}\n\t\tfoundPrimaryKey := false\n\t\tfor _, primaryKey := range primaryKeys {\n\t\t\tfor dataKey := range list[0] {\n\t\t\t\tif strings.EqualFold(dataKey, primaryKey) {\n\t\t\t\t\tfoundPrimaryKey = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif foundPrimaryKey {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !foundPrimaryKey {\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeMissingParameter,\n\t\t\t\t`Replace/Save/InsertIgnore operation requires conflict detection: `+\n\t\t\t\t\t`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,\n\t\t\t\ttable,\n\t\t\t)\n\t\t}\n\t\t// TODO consider composite primary keys.\n\t\tconflictKeys = primaryKeys\n\t}\n\n\tvar (\n\t\tone            = list[0]\n\t\toneLen         = len(one)\n\t\tcharL, charR   = d.GetChars()\n\t\tconflictKeySet = gset.NewStrSet(false)\n\n\t\t// queryHolders:\tHandle data with Holder that need to be upsert\n\t\t// queryValues:\t\tHandle data that need to be upsert\n\t\t// insertKeys:\t\tHandle valid keys that need to be inserted\n\t\t// insertValues:\tHandle values that need to be inserted\n\t\t// updateValues:\tHandle values that need to be updated\n\t\tqueryHolders = make([]string, oneLen)\n\t\tqueryValues  = make([]any, oneLen)\n\t\tinsertKeys   = make([]string, oneLen)\n\t\tinsertValues = make([]string, oneLen)\n\t\tupdateValues []string\n\t)\n\n\t// conflictKeys slice type conv to set type\n\tfor _, conflictKey := range conflictKeys {\n\t\tconflictKeySet.Add(gstr.ToUpper(conflictKey))\n\t}\n\n\tindex := 0\n\tfor key, value := range one {\n\t\tkeyWithChar := charL + key + charR\n\t\tqueryHolders[index] = fmt.Sprintf(\"? AS %s\", keyWithChar)\n\t\tqueryValues[index] = value\n\t\tinsertKeys[index] = keyWithChar\n\t\tinsertValues[index] = fmt.Sprintf(\"T2.%s\", keyWithChar)\n\n\t\t// Build updateValues only when withUpdate is true\n\t\t// Filter conflict keys and soft created fields from updateValues\n\t\tif withUpdate && !(conflictKeySet.Contains(key) || d.Core.IsSoftCreatedFieldName(key)) {\n\t\t\tupdateValues = append(\n\t\t\t\tupdateValues,\n\t\t\t\tfmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, keyWithChar),\n\t\t\t)\n\t\t}\n\t\tindex++\n\t}\n\n\tvar (\n\t\tbatchResult = new(gdb.SqlResult)\n\t\tsqlStr      = parseSqlForMerge(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys)\n\t)\n\tr, err := d.DoExec(ctx, link, sqlStr, queryValues...)\n\tif err != nil {\n\t\treturn r, err\n\t}\n\tif n, err := r.RowsAffected(); err != nil {\n\t\treturn r, err\n\t} else {\n\t\tbatchResult.Result = r\n\t\tbatchResult.Affected += n\n\t}\n\treturn batchResult, nil\n}\n\n// parseSqlForMerge generates MERGE statement for Oracle database.\n// When updateValues is empty, it only inserts (INSERT IGNORE behavior).\n// When updateValues is provided, it performs upsert (INSERT or UPDATE).\n// Examples:\n// - INSERT IGNORE: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...)\n// - UPSERT: MERGE INTO table T1 USING (...) T2 ON (...) WHEN NOT MATCHED THEN INSERT(...) VALUES (...) WHEN MATCHED THEN UPDATE SET ...\nfunc parseSqlForMerge(table string,\n\tqueryHolders, insertKeys, insertValues, updateValues, duplicateKey []string,\n) (sqlStr string) {\n\tvar (\n\t\tqueryHolderStr  = strings.Join(queryHolders, \",\")\n\t\tinsertKeyStr    = strings.Join(insertKeys, \",\")\n\t\tinsertValueStr  = strings.Join(insertValues, \",\")\n\t\tduplicateKeyStr string\n\t)\n\n\t// Build ON condition\n\tfor index, keys := range duplicateKey {\n\t\tif index != 0 {\n\t\t\tduplicateKeyStr += \" AND \"\n\t\t}\n\t\tduplicateKeyStr += fmt.Sprintf(\"T1.%s = T2.%s\", keys, keys)\n\t}\n\n\t// Build SQL based on whether UPDATE is needed\n\tpattern := gstr.Trim(\n\t\t`MERGE INTO %s T1 USING (SELECT %s FROM DUAL) T2 ON (%s) WHEN ` +\n\t\t\t`NOT MATCHED THEN INSERT(%s) VALUES (%s)`,\n\t)\n\tif len(updateValues) > 0 {\n\t\t// Upsert: INSERT or UPDATE\n\t\tpattern += gstr.Trim(` WHEN MATCHED THEN UPDATE SET %s`)\n\t\treturn fmt.Sprintf(\n\t\t\tpattern, table, queryHolderStr, duplicateKeyStr, insertKeyStr, insertValueStr,\n\t\t\tstrings.Join(updateValues, \",\"),\n\t\t)\n\t}\n\t// Insert Ignore: INSERT only\n\treturn fmt.Sprintf(pattern, table, queryHolderStr, duplicateKeyStr, insertKeyStr, insertValueStr)\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"database/sql\"\n\t\"strings\"\n\n\tgora \"github.com/sijms/go-ora/v2\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Open creates and returns an underlying sql.DB object for oracle.\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar (\n\t\tsource               string\n\t\tunderlyingDriverName = \"oracle\"\n\t)\n\n\toptions := map[string]string{\n\t\t\"CONNECTION TIMEOUT\": \"60\",\n\t\t\"PREFETCH_ROWS\":      \"25\",\n\t}\n\n\tif config.Debug {\n\t\toptions[\"TRACE FILE\"] = \"oracle_trace.log\"\n\t}\n\t// [username:[password]@]host[:port][/service_name][?param1=value1&...&paramN=valueN]\n\tif config.Extra != \"\" {\n\t\t// fix #3226\n\t\tlist := strings.Split(config.Extra, \"&\")\n\t\tfor _, v := range list {\n\t\t\tkv := strings.Split(v, \"=\")\n\t\t\tif len(kv) == 2 {\n\t\t\t\toptions[kv[0]] = kv[1]\n\t\t\t}\n\t\t}\n\t}\n\tsource = gora.BuildUrl(\n\t\tconfig.Host, gconv.Int(config.Port), config.Name, config.User, config.Pass, options,\n\t)\n\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_order.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\n// OrderRandomFunction returns the SQL function for random ordering.\nfunc (d *Driver) OrderRandomFunction() string {\n\treturn \"DBMS_RANDOM.VALUE()\"\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\n// Result implements sql.Result interface for Oracle database.\ntype Result struct {\n\tlastInsertId      int64\n\trowsAffected      int64\n\tlastInsertIdError error\n}\n\n// LastInsertId returns the last insert id.\nfunc (r *Result) LastInsertId() (int64, error) {\n\treturn r.lastInsertId, r.lastInsertIdError\n}\n\n// RowsAffected returns the rows affected.\nfunc (r *Result) RowsAffected() (int64, error) {\n\treturn r.rowsAffected, nil\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttableFieldsSqlTmp = `\nSELECT \n    c.COLUMN_NAME AS FIELD, \n    CASE   \n    WHEN (c.DATA_TYPE='NUMBER' AND NVL(c.DATA_SCALE,0)=0) THEN 'INT'||'('||c.DATA_PRECISION||','||c.DATA_SCALE||')'\n    WHEN (c.DATA_TYPE='NUMBER' AND NVL(c.DATA_SCALE,0)>0) THEN 'FLOAT'||'('||c.DATA_PRECISION||','||c.DATA_SCALE||')'\n    WHEN c.DATA_TYPE='FLOAT' THEN c.DATA_TYPE||'('||c.DATA_PRECISION||','||c.DATA_SCALE||')' \n    ELSE c.DATA_TYPE||'('||c.DATA_LENGTH||')' END AS TYPE,\n    c.NULLABLE,\n    CASE WHEN pk.COLUMN_NAME IS NOT NULL THEN 'PRI' ELSE '' END AS KEY\nFROM USER_TAB_COLUMNS c\nLEFT JOIN (\n    SELECT cols.COLUMN_NAME \n    FROM USER_CONSTRAINTS cons \n    JOIN USER_CONS_COLUMNS cols ON cons.CONSTRAINT_NAME = cols.CONSTRAINT_NAME \n    WHERE cons.TABLE_NAME = '%s' AND cons.CONSTRAINT_TYPE = 'P'\n) pk ON c.COLUMN_NAME = pk.COLUMN_NAME\nWHERE c.TABLE_NAME = '%s' \nORDER BY c.COLUMN_ID\n`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\n//\n// Also see DriverMysql.TableFields.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult       gdb.Result\n\t\tlink         gdb.Link\n\t\tusedSchema   = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t\tupperTable   = strings.ToUpper(table)\n\t\tstructureSql = fmt.Sprintf(tableFieldsSqlTmp, upperTable, upperTable)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, structureSql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tisNull := false\n\t\tif m[\"NULLABLE\"].String() == \"Y\" {\n\t\t\tisNull = true\n\t\t}\n\n\t\tfields[m[\"FIELD\"].String()] = &gdb.TableField{\n\t\t\tIndex: i,\n\t\t\tName:  m[\"FIELD\"].String(),\n\t\t\tType:  m[\"TYPE\"].String(),\n\t\t\tNull:  isNull,\n\t\t\tKey:   m[\"KEY\"].String(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = `SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME`\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\n// Note that it ignores the parameter `schema` in oracle database, as it is not necessary.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\t// DO NOT use `usedSchema` as parameter for function `SlaveLink`.\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, tablesSqlTmp)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_z_unit_basic_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Tables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"t_user1\", \"pop\", \"haha\"}\n\n\t\tfor _, v := range tables {\n\t\t\tcreateTable(v)\n\t\t}\n\n\t\tresult, err := db.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif strings.ToUpper(tables[i]) == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\n\t\tresult, err = db.Tables(ctx, TestSchema)\n\t\tgtest.AssertNil(err)\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif strings.ToUpper(tables[i]) == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\n\t\tfor _, v := range tables {\n\t\t\tdropTable(v)\n\t\t}\n\t})\n}\n\nfunc Test_Table_Fields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\t\tvar expect = map[string][]any{\n\t\t\t\"ID\":          {\"INT(10,0)\", false},\n\t\t\t\"PASSPORT\":    {\"VARCHAR2(45)\", false},\n\t\t\t\"PASSWORD\":    {\"CHAR(32)\", false},\n\t\t\t\"NICKNAME\":    {\"VARCHAR2(45)\", false},\n\t\t\t\"SALARY\":      {\"FLOAT(18,2)\", true},\n\t\t\t\"CREATE_TIME\": {\"VARCHAR2(45)\", true},\n\t\t}\n\n\t\t_, err := dbErr.TableFields(ctx, \"t_user\")\n\t\tgtest.AssertNE(err, nil)\n\n\t\tres, err := db.TableFields(ctx, \"t_user\")\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.Assert(res[k].Type, v[0])\n\t\t\tgtest.Assert(res[k].Null, v[1])\n\t\t}\n\n\t\tres, err = db.TableFields(ctx, \"t_user\", TestSchema)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.Assert(res[k].Type, v[0])\n\t\t\tgtest.Assert(res[k].Null, v[1])\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.TableFields(ctx, \"t_user t_user2\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Do_Insert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"ID\":          i,\n\t\t\t\"PASSPORT\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"PASSWORD\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"NICKNAME\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"SALARY\":      gconv.Float64(i * 500),\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, \"t_user\", data)\n\t\tgtest.AssertNil(err)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"ID\":          i,\n\t\t\t\"PASSPORT\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"PASSWORD\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"NICKNAME\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"SALARY\":      gconv.Float64(i * 450),\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNil(err)\n\n\t\t_, err = db.Replace(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ? from dual\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+? from dual\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+? from dual\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ? from dual\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Exec(ctx, \"ERROR\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":          1,\n\t\t\t\"PASSPORT\":    \"t1\",\n\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"NICKNAME\":    \"T1\",\n\t\t\t\"SALARY\":      2551.15,\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":          \"2\",\n\t\t\t\"PASSPORT\":    \"t2\",\n\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"NICKNAME\":    \"name_2\",\n\t\t\t\"SALARY\":      \"2552.25\",\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\ttype User struct {\n\t\t\tId         int     `gconv:\"ID\"`\n\t\t\tPassport   string  `json:\"PASSPORT\"`\n\t\t\tPassword   string  `gconv:\"PASSWORD\"`\n\t\t\tNickname   string  `gconv:\"NICKNAME\"`\n\t\t\tSalary     float64 `gconv:\"SALARY\"`\n\t\t\tCreateTime string  `json:\"CREATE_TIME\"`\n\t\t}\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tId:         3,\n\t\t\tPassport:   \"user_3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tSalary:     2553.35,\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"ID\", 3).One()\n\t\tt.AssertNil(err)\n\t\t// fmt.Println(one)\n\t\tt.Assert(one[\"ID\"].Int(), 3)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_3\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_3\")\n\t\tt.Assert(one[\"SALARY\"].Float64(), 2553.35)\n\t\tt.Assert(one[\"CREATE_TIME\"].GTime().String(), timeStr)\n\n\t\t// *struct\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_4\",\n\t\t\tSalary:     2554.35,\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Where(\"ID\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 4)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t4\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_4\")\n\t\tt.Assert(one[\"SALARY\"].Float64(), 2554.35)\n\t\tt.Assert(one[\"CREATE_TIME\"].GTime().String(), timeStr)\n\n\t\t// batch with Insert\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"ID\":          200,\n\t\t\t\t\"PASSPORT\":    \"t200\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d71qw07ad\",\n\t\t\t\t\"NICKNAME\":    \"T200\",\n\t\t\t\t\"SALARY\":      2556.35,\n\t\t\t\t\"CREATE_TIME\": timeStr,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"ID\":          300,\n\t\t\t\t\"PASSPORT\":    \"t300\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"T300\",\n\t\t\t\t\"SALARY\":      2557.35,\n\t\t\t\t\"CREATE_TIME\": timeStr,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"ID\", 200).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 200)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t200\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d71qw07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T200\")\n\t\tt.Assert(one[\"SALARY\"].Float64(), 2556.35)\n\t\tt.Assert(one[\"CREATE_TIME\"].GTime().String(), timeStr)\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"ID\":          2,\n\t\t\t\t\"PASSPORT\":    \"t2\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_2\",\n\t\t\t\t\"SALARY\":      2652.35,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"ID\":          3,\n\t\t\t\t\"PASSPORT\":    \"user_3\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_3\",\n\t\t\t\t\"SALARY\":      2653.35,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"ID\":          2,\n\t\t\t\t\"PASSPORT\":    \"t2\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_2\",\n\t\t\t\t\"SALARY\":      2652.35,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"ID\":          3,\n\t\t\t\t\"PASSPORT\":    \"user_3\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_3\",\n\t\t\t\t\"SALARY\":      2653.35,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"ID\":          1,\n\t\t\t\"PASSPORT\":    \"t1\",\n\t\t\t\"PASSWORD\":    \"p1\",\n\t\t\t\"NICKNAME\":    \"T1\",\n\t\t\t\"SALARY\":      2765.35,\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttype User struct {\n\t\t\tId         int         `c:\"ID\"`\n\t\t\tPassport   string      `c:\"PASSPORT\"`\n\t\t\tPassword   string      `c:\"PASSWORD\"`\n\t\t\tNickName   string      `c:\"NICKNAME\"`\n\t\t\tSalary     float64     `c:\"SALARY\"`\n\t\t\tCreateTime *gtime.Time `c:\"CREATE_TIME\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"t1\",\n\t\t\tPassword:   \"p1\",\n\t\t\tNickName:   \"T1\",\n\t\t\tSalary:     2761.35,\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\tresult, err := db.Insert(ctx, table, user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tresult, err = db.Update(ctx, table, \"salary=2675.13\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"ID\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"ID\"].Int(), 3)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_3\")\n\t\tt.Assert(strings.TrimSpace(one[\"PASSWORD\"].String()), \"987654321\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"name_3\")\n\t\tt.Assert(one[\"SALARY\"].String(), \"2675.13\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 2)\n\t\tt.Assert(result[2][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"NICKNAME\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"1=1\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// fix #3226\nfunc Test_Extra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnodeLink := gdb.ConfigNode{\n\t\t\tType: TestDbType,\n\t\t\tName: TestDbName,\n\t\t\tLink: fmt.Sprintf(\"%s:%s:%s@tcp(%s:%s)/%s?lob fetch=post&SSL VERIFY=false\",\n\t\t\t\tTestDbType, TestDbUser, TestDbPass, TestDbIP, TestDbPort, TestDbName,\n\t\t\t),\n\t\t}\n\t\tif r, err := gdb.New(nodeLink); err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t} else {\n\t\t\terr1 := r.PingMaster()\n\t\t\tt.Assert(err1, nil)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_z_unit_init_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t_ \"github.com/sijms/go-ora/v2\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tdb     gdb.DB\n\tdblink gdb.DB\n\tdbErr  gdb.DB\n\tctx    context.Context\n)\n\nconst (\n\tTableSize        = 10\n\tTableName        = \"t_user\"\n\tTestSchema1      = \"test1\"\n\tTestSchema2      = \"test2\"\n\tTableNamePrefix1 = \"gf_\"\n\tTestSchema       = \"XE\"\n)\n\nconst (\n\tTestDbIP   = \"127.0.0.1\"\n\tTestDbPort = \"1521\"\n\tTestDbUser = \"system\"\n\tTestDbPass = \"oracle\"\n\tTestDbName = \"XE\"\n\tTestDbType = \"oracle\"\n)\n\nfunc init() {\n\tnode := gdb.ConfigNode{\n\t\tHost:             TestDbIP,\n\t\tPort:             TestDbPort,\n\t\tUser:             TestDbUser,\n\t\tPass:             TestDbPass,\n\t\tName:             TestDbName,\n\t\tType:             TestDbType,\n\t\tRole:             \"master\",\n\t\tCharset:          \"utf8\",\n\t\tWeight:           1,\n\t\tMaxIdleConnCount: 10,\n\t\tMaxOpenConnCount: 10,\n\t}\n\n\tnodeLink := gdb.ConfigNode{\n\t\tType: TestDbType,\n\t\tName: TestDbName,\n\t\tLink: fmt.Sprintf(\"%s:%s:%s@tcp(%s:%s)/%s\",\n\t\t\tTestDbType, TestDbUser, TestDbPass, TestDbIP, TestDbPort, TestDbName,\n\t\t),\n\t}\n\n\tnodeErr := gdb.ConfigNode{\n\t\tHost:    TestDbIP,\n\t\tPort:    TestDbPort,\n\t\tUser:    TestDbUser,\n\t\tPass:    \"1234\",\n\t\tName:    TestDbName,\n\t\tType:    TestDbType,\n\t\tRole:    \"master\",\n\t\tCharset: \"utf8\",\n\t\tWeight:  1,\n\t}\n\n\tgdb.AddConfigNode(gdb.DefaultGroupName, node)\n\tif r, err := gdb.New(node); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\tgdb.AddConfigNode(\"dblink\", nodeLink)\n\tif r, err := gdb.New(nodeLink); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdblink = r\n\t}\n\n\tgdb.AddConfigNode(\"dbErr\", nodeErr)\n\tif r, err := gdb.New(nodeErr); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdbErr = r\n\t}\n\n\tctx = context.Background()\n}\n\nfunc createTable(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(\"user_%d\", gtime.Timestamp())\n\t}\n\n\tdropTable(name)\n\n\t// Step 1: Create table\n\tcreateTableSQL := fmt.Sprintf(`\n    CREATE TABLE %s (\n        ID NUMBER(10) NOT NULL,\n        PASSPORT VARCHAR(45) NOT NULL,\n        PASSWORD CHAR(32) NOT NULL,\n        NICKNAME VARCHAR(45) NOT NULL,\n        CREATE_TIME VARCHAR(45),\n        SALARY NUMBER(18,2),\n        PRIMARY KEY (ID)\n    )`, name)\n\n\tif _, err := db.Exec(ctx, createTableSQL); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// Step 2: Create sequence\n\tcreateSeqSQL := fmt.Sprintf(`\n    CREATE SEQUENCE %s_ID_SEQ\n    START WITH 1\n    INCREMENT BY 1\n    MINVALUE 1\n    MAXVALUE 9999999999\n    NOCYCLE\n    NOCACHE`, name)\n\n\tif _, err := db.Exec(ctx, createSeqSQL); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// Step 3: Create trigger - only set ID from sequence when it's NULL\n\tcreateTriggerSQL := fmt.Sprintf(`\nCREATE OR REPLACE TRIGGER %s_ID_TRG\nBEFORE INSERT ON %s\nFOR EACH ROW\nBEGIN\n    IF :NEW.ID IS NULL THEN\n        :NEW.ID := %s_ID_SEQ.NEXTVAL;\n    END IF;\nEND;`, name, name, name)\n\n\tif _, err := db.Exec(ctx, createTriggerSQL); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// db.Schema(\"test\")\n\treturn\n}\n\nfunc createInitTable(table ...string) (name string) {\n\tname = createTable(table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t}\n\tresult, err := db.Insert(context.Background(), name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTable(table string) {\n\tcount, err := db.GetCount(ctx, \"SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?\", strings.ToUpper(table))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tif count == 0 {\n\t\treturn\n\t}\n\n\t// Drop table\n\tif _, err = db.Exec(ctx, fmt.Sprintf(\"DROP TABLE %s\", table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\t// Drop sequence if exists\n\tseqCount, err := db.GetCount(ctx, \"SELECT COUNT(*) FROM USER_SEQUENCES WHERE SEQUENCE_NAME = ?\", strings.ToUpper(table+\"_ID_SEQ\"))\n\tif err == nil && seqCount > 0 {\n\t\tdb.Exec(ctx, fmt.Sprintf(\"DROP SEQUENCE %s_ID_SEQ\", table))\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/oracle/oracle_z_unit_model_test.go",
    "content": "// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage oracle_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_InnerJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 5).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 5)\n\n\t\tresult, err := db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 5)\n\n\t\tresult, err = db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ?\", 1).Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 4)\n\t})\n}\n\nfunc Test_Model_LeftJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table2).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t} else {\n\t\t\tt.Assert(n, 7)\n\t\t}\n\n\t\tresult, err := db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ? \", 2).All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 8)\n\t})\n}\n\nfunc Test_Model_RightJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 7)\n\n\t\tresult, err := db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").RightJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > 2\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tt.Assert(len(result), 1)\n\t})\n}\n\nfunc Test_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tresult, err := db.Model(table).Page(1, 2).Order(\"ID\").All()\n\tgtest.AssertNil(err)\n\tfmt.Println(\"page:1--------\", result)\n\tgtest.Assert(len(result), 2)\n\tgtest.Assert(result[0][\"ID\"], 1)\n\tgtest.Assert(result[1][\"ID\"], 2)\n\n\tresult, err = db.Model(table).Page(2, 2).Order(\"ID\").All()\n\tgtest.AssertNil(err)\n\tfmt.Println(\"page: 2--------\", result)\n\tgtest.Assert(len(result), 2)\n\tgtest.Assert(result[0][\"ID\"], 3)\n\tgtest.Assert(result[1][\"ID\"], 4)\n\n\tresult, err = db.Model(table).Page(3, 2).Order(\"ID\").All()\n\tgtest.AssertNil(err)\n\tfmt.Println(\"page:3 --------\", result)\n\tgtest.Assert(len(result), 2)\n\tgtest.Assert(result[0][\"ID\"], 5)\n\n\tresult, err = db.Model(table).Page(2, 3).All()\n\tgtest.AssertNil(err)\n\tgtest.Assert(len(result), 3)\n\tgtest.Assert(result[0][\"ID\"], 4)\n\tgtest.Assert(result[1][\"ID\"], 5)\n\tgtest.Assert(result[2][\"ID\"], 6)\n}\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"ID\":          1,\n\t\t\t\"UID\":         1,\n\t\t\t\"PASSPORT\":    \"t1\",\n\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"NICKNAME\":    \"name_1\",\n\t\t\t\"SALARY\":      2675.11,\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"ID\":          \"2\",\n\t\t\t\"UID\":         \"2\",\n\t\t\t\"PASSPORT\":    \"t2\",\n\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"NICKNAME\":    \"name_2\",\n\t\t\t\"SALARY\":      2675.12,\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"ID\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"PASSPORT\"`\n\t\t\tPassword   string      `gconv:\"PASSWORD\"`\n\t\t\tNickname   string      `gconv:\"NICKNAME\"`\n\t\t\tSalary     float64     `gconv:\"SALARY\"`\n\t\t\tCreateTime *gtime.Time `json:\"CREATE_TIME\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tSalary:     2675.13,\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"PASSPORT\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tSalary:     2675.14,\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err = db.Model(table).Fields(\"PASSPORT\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\t_, _ = result.RowsAffected()\n\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, 777),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, 777),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, 777),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"user_1\")\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, 777),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, 777),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, 777),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).InsertIgnore()\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_Model_InsertAndGetId(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, 1),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, 1),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, 1),\n\t\t\t\"create_time\": gtime.Now(),\n\t\t}\n\t\tlastId, err := db.Model(table).Data(data).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(lastId, 0)\n\t})\n\n}\n\n// https://github.com/gogf/gf/issues/3286\nfunc Test_Model_Insert_Raw(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"ID\":          1,\n\t\t\t\"UID\":         1,\n\t\t\t\"PASSPORT\":    \"t1\",\n\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"NICKNAME\":    gdb.Raw(\"name_1\"),\n\t\t\t\"SALARY\":      2675.11,\n\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"PASSPORT\").Where(\"id=1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t1\")\n\t})\n}\n\nfunc Test_Model_Insert_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"ID\":          1,\n\t\t\t\"PASSPORT\":    \"t1\",\n\t\t\t\"PASSWORD\":    \"p1\",\n\t\t\t\"NICKNAME\":    \"n1\",\n\t\t\t\"SALARY\":      2675.11,\n\t\t\t\"CREATE_TIME\": \"2020-10-10 20:09:18\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"ID\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), data[\"PASSPORT\"])\n\t\tt.Assert(one[\"CREATE_TIME\"].String(), \"2020-10-10 20:09:18\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), data[\"NICKNAME\"])\n\t\tt.Assert(one[\"SALARY\"].Float64(), data[\"SALARY\"])\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"ID\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"PASSPORT\":    \"t2\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_2\",\n\t\t\t\t\"SALARY\":      2675.12,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"ID\":          3,\n\t\t\t\t\"uid\":         3,\n\t\t\t\t\"PASSPORT\":    \"t3\",\n\t\t\t\t\"PASSWORD\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"NICKNAME\":    \"name_3\",\n\t\t\t\t\"SALARY\":      2675.13,\n\t\t\t\t\"CREATE_TIME\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t})\n\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"PASSPORT\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"PASSPORT\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"PASSPORT\").Data(g.Map{\n\t\t\t\"PASSPORT\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"ID\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"NICKNAME\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"ID\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICKNAME\").Where(\"ID\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICKNAME\").Where(\"ID\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"ID\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tfor k, v := range all.Array(\"ID\") {\n\t\t\tt.Assert(v.Int(), k+1)\n\t\t}\n\t\tt.Assert(all.Array(\"NICKNAME\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"NICKNAME\").Where(\"ID\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"NICKNAME\", \"ID\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"ID\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tSalary     float64\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tSalary     float64\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"ID\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"ID\", 3, \"NICKNAME\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"ID\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"ID\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"ID\":       g.Slice{1, 2, 3},\n\t\t\t\"PASSPORT\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 3).Where(\"NICKNAME\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 3).Where(\"NICKNAME\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 30).WhereOr(\"NICKNAME\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 30).WhereOr(\"NICKNAME\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"ID\", 30).WhereOr(\"NICKNAME\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"ID\": 3, \"NICKNAME\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"ID\": 3, \"NICKNAME\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"ID\": 3, \"NICKNAME\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"ID\": 3, \"NICKNAME\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"ID\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"ID\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"].Int(), 1)\n\t\tt.Assert(result[1][\"ID\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"ID\":       g.Slice{1, 3},\n\t\t\t\"NICKNAME\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"ID\"`\n\t\t\tNickname string `gconv:\"NICKNAME\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"ID\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id, count(*)\").Where(\"id > 1\").Group(\"ID\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\n// not support\n/*\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n*/\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(strings.ToUpper(table))\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"ID\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"ID\", g.Slice{1, 2, 3, 4}).WhereIn(\"ID\", g.Slice{3, 4, 5}).OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"ID\"], 3)\n\t\tt.Assert(result[1][\"ID\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"ID\", g.Slice{}).OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"ID\", g.Slice{}).OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"ID\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"ID\", g.Slice{3, 4, 5}).OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"ID\"], 6)\n\t\tt.Assert(result[1][\"ID\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"ID\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"ID\", g.Slice{3, 4, 5}).OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[4][\"ID\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"NICKNAME\", \"name%\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"NICKNAME\", \"name%\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"NICKNAME\", \"namexxx%\").WhereOrLike(\"NICKNAME\", \"name%\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"NICKNAME\", \"namexxx%\").WhereOrNotLike(\"NICKNAME\", \"name%\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"ID\"], 1)\n\t\tt.Assert(result[TableSize-1][\"ID\"], TableSize)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser       User\n\t\t\tcount      int\n\t\t\tresult     sql.Result\n\t\t\tcreateTime = gtime.Now().Format(\"Y-m-d\")\n\t\t\terr        error\n\t\t)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"15d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": createTime,\n\t\t}).OnConflict(\"id\").Save()\n\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"15d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(user.NickName, \"n1\")\n\t\tt.Assert(user.CreateTime.Format(\"Y-m-d\"), createTime)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"n2\",\n\t\t\t\"create_time\": createTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(user.NickName, \"n2\")\n\t\tt.Assert(user.CreateTime.Format(\"Y-m-d\"), createTime)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial record\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"pass1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Replace with new data (should update existing record using MERGE)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).OnConflict(\"id\").Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t11\")\n\t\tt.Assert(one[\"PASSWORD\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T11\")\n\n\t\t// Replace with new ID (insert new record)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t222\",\n\t\t\t\"password\":    \"pass2\",\n\t\t\t\"nickname\":    \"T222\",\n\t\t\t\"create_time\": \"2018-10-24 11:00:00\",\n\t\t}).OnConflict(\"id\").Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify new record was inserted\n\t\tone, err = db.Model(table).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"PASSPORT\"].String(), \"t222\")\n\t\tt.Assert(one[\"NICKNAME\"].String(), \"T222\")\n\n\t\t// Replace without OnConflict (primary key auto-detection is implemented)\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          3,\n\t\t\t\"passport\":    \"t3\",\n\t\t\t\"password\":    \"pass3\",\n\t\t\t\"nickname\":    \"T3\",\n\t\t\t\"create_time\": \"2018-10-24 12:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t// \"id\":          3,\n\t\t\t\"passport\":    \"t3\",\n\t\t\t\"password\":    \"pass3\",\n\t\t\t\"nickname\":    \"T3\",\n\t\t\t\"create_time\": \"2018-10-24 12:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_OrderRandom(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\n/* not support the \"AS\"\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"ID\", 8).\n\t\t\tWhereIn(\"ID\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"ID\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"ID\"], 7)\n\t\tt.Assert(all[1][\"ID\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"ID\", 8).\n\t\t\tWhereIn(\"ID\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"ID\").\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.\n\t\t// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)\n\t\t// WhereLT(\"ID\", 8): id < 8 -> (1, 5, 7)\n\t\t// WhereIn(\"ID\", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)\n\t\t// Result: 3 records match all conditions\n\t\tt.Assert(count, int64(3))\n\t})\n}\n\nfunc Test_Model_FieldCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"ID\").FieldCount(\"ID\", \"total\").Group(\"ID\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"], 1)\n\t})\n}\n\nfunc Test_Model_FieldMax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"ID\").FieldMax(\"ID\", \"total\").Group(\"ID\").OrderAsc(\"ID\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"ID\"], 1)\n\t\tt.Assert(all[0][\"total\"], 1)\n\t})\n}*/\n"
  },
  {
    "path": "contrib/drivers/pgsql/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/pgsql/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/lib/pq v1.10.9\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/pgsql/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=\ngithub.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package pgsql implements gdb.Driver, which supports operations for database PostgreSQL.\npackage pgsql\n\nimport (\n\t_ \"github.com/lib/pq\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// Driver is the driver for postgresql database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tinternalPrimaryKeyInCtx gctx.StrKey = \"primary_key\"\n\tdefaultSchema           string      = \"public\"\n\tquoteChar               string      = `\"`\n)\n\nfunc init() {\n\tif err := gdb.Register(`pgsql`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for PostgreSql.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for postgresql.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/lib/pq\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ConvertValueForField converts value to database acceptable value.\nfunc (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\tif g.IsNil(fieldValue) {\n\t\treturn d.Core.ConvertValueForField(ctx, fieldType, fieldValue)\n\t}\n\n\tvar fieldValueKind = reflect.TypeOf(fieldValue).Kind()\n\n\tif fieldValueKind == reflect.Slice {\n\t\t// For bytea type, pass []byte directly without any conversion.\n\t\tif _, ok := fieldValue.([]byte); ok && gstr.Contains(fieldType, \"bytea\") {\n\t\t\treturn d.Core.ConvertValueForField(ctx, fieldType, fieldValue)\n\t\t}\n\t\t// For pgsql, json or jsonb require '[]'\n\t\tif !gstr.Contains(fieldType, \"json\") {\n\t\t\tfieldValue = gstr.ReplaceByMap(gconv.String(fieldValue),\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"[\": \"{\",\n\t\t\t\t\t\"]\": \"}\",\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\treturn d.Core.ConvertValueForField(ctx, fieldType, fieldValue)\n}\n\n// CheckLocalTypeForField checks and returns corresponding local golang type for given db type.\n// The parameter `fieldType` is in lower case, like:\n// `int2`, `int4`, `int8`, `_int2`, `_int4`, `_int8`, `_float4`, `_float8`, etc.\n//\n// PostgreSQL type mapping:\n//\n//\t| PostgreSQL Type              | Local Go Type |\n//\t|------------------------------|---------------|\n//\t| int2, int4                   | int           |\n//\t| int8                         | int64         |\n//\t| uuid                         | uuid.UUID     |\n//\t| _int2, _int4                 | []int32       | // Note: pq package does not provide Int16Array; int32 is used for compatibility\n//\t| _int8                        | []int64       |\n//\t| _float4                      | []float32     |\n//\t| _float8                      | []float64     |\n//\t| _bool                        | []bool        |\n//\t| _varchar, _text              | []string      |\n//\t| _char, _bpchar               | []string      |\n//\t| _numeric, _decimal, _money   | []float64     |\n//\t| bytea                        | []byte        |\n//\t| _bytea                       | [][]byte      |\n//\t| _uuid                        | []uuid.UUID   |\nfunc (d *Driver) CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue any) (gdb.LocalType, error) {\n\tvar typeName string\n\tmatch, _ := gregex.MatchString(`(.+?)\\((.+)\\)`, fieldType)\n\tif len(match) == 3 {\n\t\ttypeName = gstr.Trim(match[1])\n\t} else {\n\t\ttypeName = fieldType\n\t}\n\ttypeName = strings.ToLower(typeName)\n\tswitch typeName {\n\tcase \"int2\", \"int4\":\n\t\treturn gdb.LocalTypeInt, nil\n\n\tcase \"int8\":\n\t\treturn gdb.LocalTypeInt64, nil\n\n\tcase \"uuid\":\n\t\treturn gdb.LocalTypeUUID, nil\n\n\tcase \"_int2\", \"_int4\":\n\t\treturn gdb.LocalTypeInt32Slice, nil\n\n\tcase \"_int8\":\n\t\treturn gdb.LocalTypeInt64Slice, nil\n\n\tcase \"_float4\":\n\t\treturn gdb.LocalTypeFloat32Slice, nil\n\n\tcase \"_float8\":\n\t\treturn gdb.LocalTypeFloat64Slice, nil\n\n\tcase \"_bool\":\n\t\treturn gdb.LocalTypeBoolSlice, nil\n\n\tcase \"_varchar\", \"_text\", \"_char\", \"_bpchar\":\n\t\treturn gdb.LocalTypeStringSlice, nil\n\n\tcase \"_uuid\":\n\t\treturn gdb.LocalTypeUUIDSlice, nil\n\n\tcase \"_numeric\", \"_decimal\", \"_money\":\n\t\treturn gdb.LocalTypeFloat64Slice, nil\n\n\tcase \"bytea\":\n\t\treturn gdb.LocalTypeBytes, nil\n\n\tcase \"_bytea\":\n\t\treturn gdb.LocalTypeBytesSlice, nil\n\n\tdefault:\n\t\treturn d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue)\n\t}\n}\n\n// ConvertValueForLocal converts value to local Golang type of value according field type name from database.\n// The parameter `fieldType` is in lower case, like:\n// `int2`, `int4`, `int8`, `_int2`, `_int4`, `_int8`, `uuid`, `_uuid`, etc.\n//\n// See: https://www.postgresql.org/docs/current/datatype.html\n//\n// PostgreSQL type mapping:\n//\n//\t| PostgreSQL Type | SQL Type                       | pq Type         | Go Type     |\n//\t|-----------------|--------------------------------|-----------------|-------------|\n//\t| int2            | int2, smallint                 | -               | int         |\n//\t| int4            | int4, integer                  | -               | int         |\n//\t| int8            | int8, bigint, bigserial        | -               | int64       |\n//\t| uuid            | uuid                           | -               | uuid.UUID   |\n//\t| _int2           | int2[], smallint[]             | pq.Int32Array   | []int32     |\n//\t| _int4           | int4[], integer[]              | pq.Int32Array   | []int32     |\n//\t| _int8           | int8[], bigint[]               | pq.Int64Array   | []int64     |\n//\t| _float4         | float4[], real[]               | pq.Float32Array | []float32   |\n//\t| _float8         | float8[], double precision[]   | pq.Float64Array | []float64   |\n//\t| _bool           | boolean[], bool[]              | pq.BoolArray    | []bool      |\n//\t| _varchar        | varchar[], character varying[] | pq.StringArray  | []string    |\n//\t| _text           | text[]                         | pq.StringArray  | []string    |\n//\t| _char, _bpchar  | char[], character[]            | pq.StringArray  | []string    |\n//\t| _numeric        | numeric[]                      | pq.Float64Array | []float64   |\n//\t| _decimal        | decimal[]                      | pq.Float64Array | []float64   |\n//\t| _money          | money[]                        | pq.Float64Array | []float64   |\n//\t| bytea           | bytea                          | -               | []byte      |\n//\t| _bytea          | bytea[]                        | pq.ByteaArray   | [][]byte    |\n//\t| _uuid           | uuid[]                         | pq.StringArray  | []uuid.UUID |\n//\n// Note: PostgreSQL also supports these array types but they are not yet mapped:\n//   - _date (date[]), _timestamp (timestamp[]), _timestamptz (timestamptz[])\n//   - _jsonb (jsonb[]), _json (json[])\nfunc (d *Driver) ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\ttypeName, _ := gregex.ReplaceString(`\\(.+\\)`, \"\", fieldType)\n\ttypeName = strings.ToLower(typeName)\n\n\t// Basic types are mostly handled by Core layer; handle array types and special-case bytea here.\n\tswitch typeName {\n\n\t// []byte\n\tcase \"bytea\":\n\t\tif v, ok := fieldValue.([]byte); ok {\n\t\t\treturn v, nil\n\t\t}\n\t\treturn fieldValue, nil\n\n\t// []int32\n\tcase \"_int2\", \"_int4\":\n\t\tvar result pq.Int32Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int32(result), nil\n\n\t// []int64\n\tcase \"_int8\":\n\t\tvar result pq.Int64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int64(result), nil\n\n\t// []float32\n\tcase \"_float4\":\n\t\tvar result pq.Float32Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float32(result), nil\n\n\t// []float64\n\tcase \"_float8\":\n\t\tvar result pq.Float64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float64(result), nil\n\n\t// []bool\n\tcase \"_bool\":\n\t\tvar result pq.BoolArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []bool(result), nil\n\n\t// []string\n\tcase \"_varchar\", \"_text\", \"_char\", \"_bpchar\":\n\t\tvar result pq.StringArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []string(result), nil\n\n\t// uuid.UUID\n\tcase \"uuid\":\n\t\tvar uuidStr string\n\t\tswitch v := fieldValue.(type) {\n\t\tcase []byte:\n\t\t\tuuidStr = string(v)\n\t\tcase string:\n\t\t\tuuidStr = v\n\t\tdefault:\n\t\t\tuuidStr = gconv.String(fieldValue)\n\t\t}\n\t\tresult, err := uuid.Parse(uuidStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn result, nil\n\n\t// []uuid.UUID\n\tcase \"_uuid\":\n\t\tvar strArray pq.StringArray\n\t\tif err := strArray.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult := make([]uuid.UUID, len(strArray))\n\t\tfor i, s := range strArray {\n\t\t\tparsed, err := uuid.Parse(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tresult[i] = parsed\n\t\t}\n\t\treturn result, nil\n\n\t// []float64\n\tcase \"_numeric\", \"_decimal\", \"_money\":\n\t\tvar result pq.Float64Array\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float64(result), nil\n\n\t// [][]byte\n\tcase \"_bytea\":\n\t\tvar result pq.ByteaArray\n\t\tif err := result.Scan(fieldValue); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn [][]byte(result), nil\n\n\tdefault:\n\t\treturn d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_do_exec.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// DoExec commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\nfunc (d *Driver) DoExec(ctx context.Context, link gdb.Link, sql string, args ...any) (result sql.Result, err error) {\n\tvar (\n\t\tisUseCoreDoExec bool   = false // Check whether the default method needs to be used\n\t\tprimaryKey      string = \"\"\n\t\tpkField         gdb.TableField\n\t)\n\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = tx\n\t\t} else if link, err = d.MasterLink(); err != nil {\n\t\t\t// Or else it creates one from master node.\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it checks and retrieves transaction from context.\n\t\tif tx := gdb.TXFromCtx(ctx, d.GetGroup()); tx != nil {\n\t\t\tlink = tx\n\t\t}\n\t}\n\n\t// Check if it is an insert operation with primary key.\n\tif value := ctx.Value(internalPrimaryKeyInCtx); value != nil {\n\t\tvar ok bool\n\t\tpkField, ok = value.(gdb.TableField)\n\t\tif !ok {\n\t\t\tisUseCoreDoExec = true\n\t\t}\n\t} else {\n\t\tisUseCoreDoExec = true\n\t}\n\n\t// check if it is an insert operation.\n\tif !isUseCoreDoExec && pkField.Name != \"\" && strings.Contains(sql, \"INSERT INTO\") {\n\t\tprimaryKey = pkField.Name\n\t\tsql += fmt.Sprintf(` RETURNING \"%s\"`, primaryKey)\n\t} else {\n\t\t// use default DoExec\n\t\treturn d.Core.DoExec(ctx, link, sql, args...)\n\t}\n\n\t// Only the insert operation with primary key can execute the following code\n\n\t// Sql filtering.\n\tsql, args = d.FormatSqlBeforeExecuting(sql, args)\n\tsql, args, err = d.DoFilter(ctx, link, sql, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Link execution.\n\tvar out gdb.DoCommitOutput\n\tout, err = d.DoCommit(ctx, gdb.DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          gdb.SqlTypeQueryContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\taffected := len(out.Records)\n\tif affected > 0 {\n\t\tif !strings.Contains(pkField.Type, \"int\") {\n\t\t\treturn Result{\n\t\t\t\taffected:     int64(affected),\n\t\t\t\tlastInsertId: 0,\n\t\t\t\tlastInsertIdError: gerror.NewCodef(\n\t\t\t\t\tgcode.CodeNotSupported,\n\t\t\t\t\t\"LastInsertId is not supported by primary key type: %s\", pkField.Type),\n\t\t\t}, nil\n\t\t}\n\n\t\tif out.Records[affected-1][primaryKey] != nil {\n\t\t\tlastInsertId := out.Records[affected-1][primaryKey].Int64()\n\t\t\treturn Result{\n\t\t\t\taffected:     int64(affected),\n\t\t\t\tlastInsertId: lastInsertId,\n\t\t\t}, nil\n\t\t}\n\t}\n\n\treturn Result{}, nil\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\tvar index int\n\t// Convert placeholder char '?' to string \"$x\".\n\tnewSql, err = gregex.ReplaceStringFunc(`\\?`, sql, func(s string) string {\n\t\tindex++\n\t\treturn fmt.Sprintf(`$%d`, index)\n\t})\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\t// Handle pgsql jsonb feature support, which contains place-holder char '?'.\n\t// Refer:\n\t// https://github.com/gogf/gf/issues/1537\n\t// https://www.postgresql.org/docs/12/functions-json.html\n\tnewSql, err = gregex.ReplaceStringFuncMatch(\n\t\t`(::jsonb([^\\w\\d]*)\\$\\d)`,\n\t\tnewSql,\n\t\tfunc(match []string) string {\n\t\t\treturn fmt.Sprintf(`::jsonb%s?`, match[2])\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tnewSql, err = gregex.ReplaceString(` LIMIT (\\d+),\\s*(\\d+)`, ` LIMIT $2 OFFSET $1`, newSql)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\t// Add support for pgsql INSERT OR IGNORE.\n\tif gstr.HasPrefix(newSql, gdb.InsertOperationIgnore) {\n\t\tnewSql = \"INSERT\" + newSql[len(gdb.InsertOperationIgnore):] + \" ON CONFLICT DO NOTHING\"\n\t}\n\n\tnewArgs = args\n\n\treturn d.Core.DoFilter(ctx, link, newSql, newArgs)\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_do_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// DoInsert inserts or updates data for given table.\n// The list parameter must contain at least one record, which was previously validated.\nfunc (d *Driver) DoInsert(\n\tctx context.Context,\n\tlink gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,\n) (result sql.Result, err error) {\n\tswitch option.InsertOption {\n\tcase\n\t\tgdb.InsertOptionSave,\n\t\tgdb.InsertOptionReplace:\n\t\t// PostgreSQL does not support REPLACE INTO syntax, use Save (ON CONFLICT ... DO UPDATE) instead.\n\t\t// Automatically detect primary keys if OnConflict is not specified.\n\t\tif len(option.OnConflict) == 0 {\n\t\t\tprimaryKeys, err := d.Core.GetPrimaryKeys(ctx, table)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.WrapCode(\n\t\t\t\t\tgcode.CodeInternalError,\n\t\t\t\t\terr,\n\t\t\t\t\t`failed to get primary keys for Save/Replace operation`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tfoundPrimaryKey := false\n\t\t\tfor _, primaryKey := range primaryKeys {\n\t\t\t\tfor dataKey := range list[0] {\n\t\t\t\t\tif strings.EqualFold(dataKey, primaryKey) {\n\t\t\t\t\t\tfoundPrimaryKey = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif foundPrimaryKey {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !foundPrimaryKey {\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeMissingParameter,\n\t\t\t\t\t`Replace/Save operation requires conflict detection: `+\n\t\t\t\t\t\t`either specify OnConflict() columns or ensure table '%s' has a primary key in the data`,\n\t\t\t\t\ttable,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// TODO consider composite primary keys.\n\t\t\toption.OnConflict = primaryKeys\n\t\t}\n\t\t// Treat Replace as Save operation\n\t\toption.InsertOption = gdb.InsertOptionSave\n\n\t// pgsql support InsertIgnore natively, so no need to set primary key in context.\n\tcase gdb.InsertOptionIgnore, gdb.InsertOptionDefault:\n\t\t// Get table fields to retrieve the primary key TableField object (not just the name)\n\t\t// because DoExec needs the `TableField.Type` to determine if LastInsertId is supported.\n\t\ttableFields, err := d.GetCore().GetDB().TableFields(ctx, table)\n\t\tif err == nil {\n\t\t\tfor _, field := range tableFields {\n\t\t\t\tif strings.EqualFold(field.Key, \"pri\") {\n\t\t\t\t\tpkField := *field\n\t\t\t\t\tctx = context.WithValue(ctx, internalPrimaryKeyInCtx, pkField)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t}\n\treturn d.Core.DoInsert(ctx, link, table, list, option)\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_format_upsert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// FormatUpsert returns SQL clause of type upsert for PgSQL.\n// For example: ON CONFLICT (id) DO UPDATE SET ...\nfunc (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInsertOption) (string, error) {\n\tif len(option.OnConflict) == 0 {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter, `Please specify conflict columns`,\n\t\t)\n\t}\n\n\tvar onDuplicateStr string\n\tif option.OnDuplicateStr != \"\" {\n\t\tonDuplicateStr = option.OnDuplicateStr\n\t} else if len(option.OnDuplicateMap) > 0 {\n\t\tfor k, v := range option.OnDuplicateMap {\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tswitch v.(type) {\n\t\t\tcase gdb.Raw, *gdb.Raw:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\tv,\n\t\t\t\t)\n\t\t\tcase gdb.Counter, *gdb.Counter:\n\t\t\t\tvar counter gdb.Counter\n\t\t\t\tswitch value := v.(type) {\n\t\t\t\tcase gdb.Counter:\n\t\t\t\t\tcounter = value\n\t\t\t\tcase *gdb.Counter:\n\t\t\t\t\tcounter = *value\n\t\t\t\t}\n\t\t\t\toperator, columnVal := \"+\", counter.Value\n\t\t\t\tif columnVal < 0 {\n\t\t\t\t\toperator, columnVal = \"-\", -columnVal\n\t\t\t\t}\n\t\t\t\t// Note: In PostgreSQL ON CONFLICT DO UPDATE, we use EXCLUDED to reference\n\t\t\t\t// the value that was proposed for insertion. This differs from MySQL's\n\t\t\t\t// ON DUPLICATE KEY UPDATE behavior where the column name without prefix\n\t\t\t\t// references the current row's value.\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s%s%s\",\n\t\t\t\t\td.QuoteWord(k),\n\t\t\t\t\td.QuoteWord(counter.Field),\n\t\t\t\t\toperator,\n\t\t\t\t\tgconv.String(columnVal),\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\td.Core.QuoteWord(gconv.String(v)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, column := range columns {\n\t\t\t// If it's SAVE operation, do not automatically update the creating time.\n\t\t\tif d.Core.IsSoftCreatedFieldName(column) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t)\n\t\t}\n\t}\n\n\tconflictKeys := gstr.Join(option.OnConflict, \",\")\n\n\treturn fmt.Sprintf(\"ON CONFLICT (%s) DO UPDATE SET \", conflictKeys) + onDuplicateStr, nil\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Open creates and returns an underlying sql.DB object for pgsql.\n// https://pkg.go.dev/github.com/lib/pq\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tsource, err := configNodeToSource(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tunderlyingDriverName := \"postgres\"\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n\nfunc configNodeToSource(config *gdb.ConfigNode) (string, error) {\n\tvar source string\n\tsource = fmt.Sprintf(\n\t\t\"user=%s password='%s' host=%s sslmode=disable\",\n\t\tconfig.User, config.Pass, config.Host,\n\t)\n\tif config.Port != \"\" {\n\t\tsource = fmt.Sprintf(\"%s port=%s\", source, config.Port)\n\t}\n\tif config.Name != \"\" {\n\t\tsource = fmt.Sprintf(\"%s dbname=%s\", source, config.Name)\n\t}\n\tif config.Namespace != \"\" {\n\t\tsource = fmt.Sprintf(\"%s search_path=%s\", source, config.Namespace)\n\t}\n\tif config.Timezone != \"\" {\n\t\tsource = fmt.Sprintf(\"%s timezone=%s\", source, config.Timezone)\n\t}\n\tif config.Extra != \"\" {\n\t\textraMap, err := gstr.Parse(config.Extra)\n\t\tif err != nil {\n\t\t\treturn \"\", gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\terr,\n\t\t\t\t`invalid extra configuration: %s`, config.Extra,\n\t\t\t)\n\t\t}\n\t\tfor k, v := range extraMap {\n\t\t\tsource += fmt.Sprintf(` %s=%s`, k, v)\n\t\t}\n\t}\n\treturn source, nil\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_order.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\n// OrderRandomFunction returns the SQL function for random ordering.\nfunc (d *Driver) OrderRandomFunction() string {\n\treturn \"RANDOM()\"\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport \"database/sql\"\n\ntype Result struct {\n\tsql.Result\n\taffected          int64\n\tlastInsertId      int64\n\tlastInsertIdError error\n}\n\nfunc (pgr Result) RowsAffected() (int64, error) {\n\treturn pgr.affected, nil\n}\n\nfunc (pgr Result) LastInsertId() (int64, error) {\n\treturn pgr.lastInsertId, pgr.lastInsertIdError\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttableFieldsSqlTmp = `\nSELECT\n    a.attname                                                                            AS field,\n    t.typname                                                                            AS type,\n    a.attnotnull                                                                         AS null,\n    (CASE WHEN d.contype = 'p' THEN 'pri' WHEN d.contype = 'u' THEN 'uni' ELSE '' END)   AS key,\n    ic.column_default                                                                    AS default_value,\n    b.description                                                                        AS comment,\n    COALESCE(character_maximum_length, numeric_precision, -1)                            AS length,\n    numeric_scale                                                                        AS scale\nFROM pg_attribute a\n    LEFT JOIN pg_class c                 ON a.attrelid = c.oid\n    LEFT JOIN pg_constraint d            ON d.conrelid = c.oid AND a.attnum = d.conkey[1]\n    LEFT JOIN pg_description b           ON a.attrelid = b.objoid AND a.attnum = b.objsubid\n    LEFT JOIN pg_type t                  ON a.atttypid = t.oid\n    LEFT JOIN information_schema.columns ic ON ic.column_name = a.attname AND ic.table_name = c.relname\nWHERE c.oid = '%s'::regclass\n    AND a.attisdropped IS FALSE\n    AND a.attnum > 0\nORDER BY a.attnum`\n)\n\nfunc init() {\n\tvar err error\n\ttableFieldsSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tableFieldsSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t\t// TODO duplicated `id` result?\n\t\tstructureSql = fmt.Sprintf(tableFieldsSqlTmp, table)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, structureSql)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tvar (\n\t\tindex         = 0\n\t\tname          string\n\t\tok            bool\n\t\texistingField *gdb.TableField\n\t)\n\tfor _, m := range result {\n\t\tname = m[\"field\"].String()\n\t\t// Merge duplicated fields, especially for key constraints.\n\t\t// Priority: pri > uni > others\n\t\tif existingField, ok = fields[name]; ok {\n\t\t\tcurrentKey := m[\"key\"].String()\n\t\t\t// Merge key information with priority: pri > uni\n\t\t\tif currentKey == \"pri\" || (currentKey == \"uni\" && existingField.Key != \"pri\") {\n\t\t\t\texistingField.Key = currentKey\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tvar (\n\t\t\tfieldType  string\n\t\t\tdataType   = m[\"type\"].String()\n\t\t\tdataLength = m[\"length\"].Int()\n\t\t)\n\t\tif dataLength > 0 {\n\t\t\tfieldType = fmt.Sprintf(\"%s(%d)\", dataType, dataLength)\n\t\t} else {\n\t\t\tfieldType = dataType\n\t\t}\n\n\t\tfields[name] = &gdb.TableField{\n\t\t\tIndex:   index,\n\t\t\tName:    name,\n\t\t\tType:    fieldType,\n\t\t\tNull:    !m[\"null\"].Bool(),\n\t\t\tKey:     m[\"key\"].String(),\n\t\t\tDefault: m[\"default_value\"].Val(),\n\t\t\tComment: m[\"comment\"].String(),\n\t\t}\n\t\tindex++\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\ttablesSqlTmp = `\nSELECT\n\tc.relname\nFROM\n\tpg_class c\nINNER JOIN pg_namespace n ON\n\tc.relnamespace = n.oid\nWHERE\n\tn.nspname = '%s'\n\tAND c.relkind IN ('r', 'p')\n\t%s\nORDER BY\n\tc.relname\n`\n\n\tversionRegex = regexp.MustCompile(`PostgreSQL (\\d+\\.\\d+)`)\n)\n\nfunc init() {\n\tvar err error\n\ttablesSqlTmp, err = gdb.FormatMultiLineSqlToSingle(tablesSqlTmp)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetConfig().Namespace, schema...)\n\t)\n\tif usedSchema == \"\" {\n\t\tusedSchema = defaultSchema\n\t}\n\t// DO NOT use `usedSchema` as parameter for function `SlaveLink`.\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tuseRelpartbound := \"\"\n\tif gstr.CompareVersion(d.version(ctx, link), \"10\") >= 0 {\n\t\tuseRelpartbound = \"AND c.relpartbound IS NULL\"\n\t}\n\n\tvar query = fmt.Sprintf(\n\t\ttablesSqlTmp,\n\t\tusedSchema,\n\t\tuseRelpartbound,\n\t)\n\n\tquery, _ = gregex.ReplaceString(`[\\n\\r\\s]+`, \" \", gstr.Trim(query))\n\tresult, err = d.DoSelect(ctx, link, query)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n\n// version checks and returns the database version.\nfunc (d *Driver) version(ctx context.Context, link gdb.Link) string {\n\tresult, err := d.DoSelect(ctx, link, \"SELECT version();\")\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif len(result) > 0 {\n\t\tif v, ok := result[0][\"version\"]; ok {\n\t\t\tmatches := versionRegex.FindStringSubmatch(v.String())\n\t\t\tif len(matches) >= 2 {\n\t\t\t\treturn matches[1]\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_convert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n)\n\n// Test_CheckLocalTypeForField tests the CheckLocalTypeForField method\n// for various PostgreSQL types\nfunc Test_CheckLocalTypeForField(t *testing.T) {\n\tvar (\n\t\tctx    = context.Background()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test basic integer types\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"int2\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"int4\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"int8\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt64)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test integer array types\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_int2\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt32Slice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_int4\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt32Slice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_int8\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt64Slice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test float array types\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_float4\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeFloat32Slice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_float8\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeFloat64Slice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test boolean array type\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_bool\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeBoolSlice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test string array types\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_varchar\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeStringSlice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_text\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeStringSlice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_char\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeStringSlice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_bpchar\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeStringSlice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test numeric array types\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_numeric\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeFloat64Slice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_decimal\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeFloat64Slice)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_money\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeFloat64Slice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test bytea type\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"bytea\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeBytes)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test bytea array type\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_bytea\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeBytesSlice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uuid type\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"uuid\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeUUID)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uuid array type\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"_uuid\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeUUIDSlice)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test type with precision, e.g., \"numeric(10,2)\"\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"int2(5)\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"int4(10)\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"INT8(20)\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt64)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uppercase type names\n\t\tlocalType, err := driver.CheckLocalTypeForField(ctx, \"INT2\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt)\n\n\t\tlocalType, err = driver.CheckLocalTypeForField(ctx, \"_INT4\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(localType, gdb.LocalTypeInt32Slice)\n\t})\n}\n\n// Test_ConvertValueForLocal tests the ConvertValueForLocal method\nfunc Test_ConvertValueForLocal(t *testing.T) {\n\tvar (\n\t\tctx    = context.Background()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _int2 array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_int2\", []byte(`{1,2,3}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []int32{1, 2, 3})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _int4 array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_int4\", []byte(`{10,20,30}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []int32{10, 20, 30})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _int8 array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_int8\", []byte(`{100,200,300}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []int64{100, 200, 300})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _float4 array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_float4\", []byte(`{1.1,2.2,3.3}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]float32)\n\t\tt.Assert(len(resultArr), 3)\n\t\tt.Assert(resultArr[0] > 1.0 && resultArr[0] < 1.2, true)\n\t\tt.Assert(resultArr[1] > 2.1 && resultArr[1] < 2.3, true)\n\t\tt.Assert(resultArr[2] > 3.2 && resultArr[2] < 3.4, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _float8 array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_float8\", []byte(`{1.11,2.22,3.33}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]float64)\n\t\tt.Assert(len(resultArr), 3)\n\t\tt.Assert(resultArr[0] > 1.1 && resultArr[0] < 1.12, true)\n\t\tt.Assert(resultArr[1] > 2.21 && resultArr[1] < 2.23, true)\n\t\tt.Assert(resultArr[2] > 3.32 && resultArr[2] < 3.34, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _bool array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_bool\", []byte(`{t,f,t}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []bool{true, false, true})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _varchar array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_varchar\", []byte(`{a,b,c}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []string{\"a\", \"b\", \"c\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _text array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_text\", []byte(`{hello,world}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []string{\"hello\", \"world\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _char array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_char\", []byte(`{x,y,z}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []string{\"x\", \"y\", \"z\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _bpchar array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_bpchar\", []byte(`{a,b}`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, []string{\"a\", \"b\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _numeric array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_numeric\", []byte(`{1.11,2.22}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]float64)\n\t\tt.Assert(len(resultArr), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _decimal array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_decimal\", []byte(`{3.33,4.44}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]float64)\n\t\tt.Assert(len(resultArr), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _money array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_money\", []byte(`{5.55,6.66}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]float64)\n\t\tt.Assert(len(resultArr), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _bytea array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_bytea\", []byte(`{\"\\\\x68656c6c6f\",\"\\\\x776f726c64\"}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([][]byte)\n\t\tt.Assert(len(resultArr), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uuid conversion from []byte\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"uuid\", []byte(`550e8400-e29b-41d4-a716-446655440000`))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.(uuid.UUID).String(), \"550e8400-e29b-41d4-a716-446655440000\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uuid conversion from string\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"uuid\", \"550e8400-e29b-41d4-a716-446655440000\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.(uuid.UUID).String(), \"550e8400-e29b-41d4-a716-446655440000\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test uuid conversion error case with invalid uuid\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"uuid\", \"invalid-uuid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _uuid array conversion\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"_uuid\", []byte(`{550e8400-e29b-41d4-a716-446655440000,6ba7b810-9dad-11d1-80b4-00c04fd430c8}`))\n\t\tt.AssertNil(err)\n\t\tresultArr := result.([]uuid.UUID)\n\t\tt.Assert(len(resultArr), 2)\n\t\tt.Assert(resultArr[0].String(), \"550e8400-e29b-41d4-a716-446655440000\")\n\t\tt.Assert(resultArr[1].String(), \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test _uuid array conversion error case\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_uuid\", []byte(`{invalid-uuid}`))\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _int2\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_int2\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _int4\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_int4\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _int8\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_int8\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _float4\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_float4\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _float8\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_float8\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _bool\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_bool\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _varchar\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_varchar\", 12345)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _numeric\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_numeric\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test error case with invalid data for _bytea\n\t\t_, err := driver.ConvertValueForLocal(ctx, \"_bytea\", \"invalid\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test bytea conversion - should preserve []byte as-is\n\t\tinput := []byte{0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x5D, 0x5B}\n\t\tresult, err := driver.ConvertValueForLocal(ctx, \"bytea\", input)\n\t\tt.AssertNil(err)\n\t\tresultBytes, ok := result.([]byte)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(len(resultBytes), len(input))\n\t\tt.Assert(resultBytes, input)\n\t})\n}\n\n// Test_ConvertValueForField tests the ConvertValueForField method\nfunc Test_ConvertValueForField(t *testing.T) {\n\tvar (\n\t\tctx    = context.Background()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test nil value\n\t\tresult, err := driver.ConvertValueForField(ctx, \"varchar\", nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test slice value for non-json type (should convert [] to {})\n\t\tresult, err := driver.ConvertValueForField(ctx, \"int4[]\", []int{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"{1,2,3}\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test slice value for non-json type with strings\n\t\t// Note: gconv.String for []string{\"a\",\"b\",\"c\"} produces [\"a\",\"b\",\"c\"] which then gets converted to {\"a\",\"b\",\"c\"}\n\t\tresult, err := driver.ConvertValueForField(ctx, \"varchar[]\", []string{\"a\", \"b\", \"c\"})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `{\"a\",\"b\",\"c\"}`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test slice value for json type (should keep [] as is)\n\t\tresult, err := driver.ConvertValueForField(ctx, \"json\", []int{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"[1,2,3]\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test slice value for jsonb type (should keep [] as is)\n\t\tresult, err := driver.ConvertValueForField(ctx, \"jsonb\", []string{\"a\", \"b\"})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `[\"a\",\"b\"]`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test []byte value for bytea type (should preserve raw bytes, not do []->{} replacement)\n\t\tinput := []byte{0xDE, 0xAD, 0x5B, 0x5D, 0xBE, 0xEF}\n\t\tresult, err := driver.ConvertValueForField(ctx, \"bytea\", input)\n\t\tt.AssertNil(err)\n\t\tresultBytes, ok := result.([]byte)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(resultBytes, input)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_db_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_DB_Query(t *testing.T) {\n\ttable := createTable(\"name\")\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, fmt.Sprintf(\"select * from %s \", table))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(\"select * from %s \", table))\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tanswer, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t2\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\t// Insert initial record\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, \"t_user\", data)\n\t\tgtest.AssertNil(err)\n\n\t\t// Replace with new data\n\t\tdata2 := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d_new`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d_new`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d_new`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err = db.Replace(ctx, \"t_user\", data2)\n\t\tgtest.AssertNil(err)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM t_user WHERE id=?\"), i)\n\t\tgtest.AssertNil(err)\n\t\tgtest.Assert(one[\"passport\"].String(), fmt.Sprintf(`t%d_new`, i))\n\t\tgtest.Assert(one[\"password\"].String(), fmt.Sprintf(`p%d_new`, i))\n\t\tgtest.Assert(one[\"nickname\"].String(), fmt.Sprintf(`T%d_new`, i))\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetArray(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.GetArray(ctx, fmt.Sprintf(\"SELECT password FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tarrays := make([]string, 0)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarrays = append(arrays, fmt.Sprintf(`pass_%d`, i))\n\t\t}\n\t\tt.Assert(array, arrays)\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"987654321\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, \"id>3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 7)\n\t})\n}\n\nfunc Test_DB_Tables(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables := []string{\"t_user1\", \"pop\", \"haha\"}\n\t\tfor _, v := range tables {\n\t\t\tcreateTable(v)\n\t\t}\n\t\tresult, err := db.Tables(ctx)\n\t\tgtest.AssertNil(err)\n\t\tfor i := 0; i < len(tables); i++ {\n\t\t\tfind := false\n\t\t\tfor j := 0; j < len(result); j++ {\n\t\t\t\tif tables[i] == result[j] {\n\t\t\t\t\tfind = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tgtest.AssertEQ(find, true)\n\t\t}\n\t})\n}\n\nfunc Test_DB_TableFields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\tvar expect = map[string][]any{\n\t\t\t// []string: Index Type Null Key Default Comment\n\t\t\t// id is bigserial so the default is a pgsql function\n\t\t\t\"id\":          {0, \"int8(64)\", false, \"pri\", fmt.Sprintf(\"nextval('%s_id_seq'::regclass)\", table), \"\"},\n\t\t\t\"passport\":    {1, \"varchar(45)\", false, \"\", nil, \"\"},\n\t\t\t\"password\":    {2, \"varchar(32)\", false, \"\", nil, \"\"},\n\t\t\t\"nickname\":    {3, \"varchar(45)\", false, \"\", nil, \"\"},\n\t\t\t\"create_time\": {4, \"timestamp\", false, \"\", nil, \"\"},\n\t\t}\n\n\t\tres, err := db.TableFields(ctx, table)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\n\t\t\tgtest.AssertEQ(res[k].Index, v[0])\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[1])\n\t\t\tgtest.AssertEQ(res[k].Null, v[2])\n\t\t\tgtest.AssertEQ(res[k].Key, v[3])\n\t\t\tgtest.AssertEQ(res[k].Default, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\t})\n}\n\nfunc Test_NoFields_Error(t *testing.T) {\n\tcreateSql := `CREATE TABLE IF NOT EXISTS %s (\nid bigint PRIMARY KEY,\nint_col INT);`\n\n\ttype Data struct {\n\t\tId     int64\n\t\tIntCol int64\n\t}\n\t// pgsql converts table names to lowercase\n\t// mark: [c.oid = '%s'::regclass] is not case-sensitive\n\ttableName := \"Error_table\"\n\t_, err := db.Exec(ctx, fmt.Sprintf(createSql, tableName))\n\tgtest.AssertNil(err)\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar data = Data{\n\t\t\tId:     2,\n\t\t\tIntCol: 2,\n\t\t}\n\t\t_, err = db.Model(tableName).Data(data).Insert()\n\t\tt.AssertNE(err, nil)\n\n\t\t// Insert a piece of test data using lowercase\n\t\t_, err = db.Model(strings.ToLower(tableName)).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Model(tableName).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"int_col\": 9999,\n\t\t}).Update()\n\t\tt.AssertNE(err, nil)\n\n\t})\n\t// The inserted field does not exist in the table\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]any{\n\t\t\t\"id1\":        22,\n\t\t\t\"int_col_22\": 11111,\n\t\t}\n\t\t_, err = db.Model(tableName).Data(data).Insert()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, tableName))\n\n\t\tlowerTableName := strings.ToLower(tableName)\n\t\t_, err = db.Model(lowerTableName).Data(data).Insert()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, lowerTableName))\n\n\t\t_, err = db.Model(lowerTableName).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"int_col-2\": 9999,\n\t\t}).Update()\n\t\tt.Assert(err, fmt.Errorf(`input data match no fields in table \"%s\"`, lowerTableName))\n\t})\n\n}\n\nfunc Test_DB_TableFields_DuplicateConstraints(t *testing.T) {\n\t// Test for the fix of duplicate field results with multiple constraints\n\t// This test verifies that when a field has multiple constraints (e.g., both primary key and unique),\n\t// the TableFields method correctly merges the results with proper priority (pri > uni > others)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"test_multi_constraint\"\n\t\tcreateSql := fmt.Sprintf(`\n\t\t\tCREATE TABLE %s (\n\t\t\t\tid bigserial NOT NULL PRIMARY KEY,\n\t\t\t\temail varchar(100) NOT NULL UNIQUE,\n\t\t\t\tusername varchar(50) NOT NULL,\n\t\t\t\tstatus int NOT NULL DEFAULT 1\n\t\t\t)`, tableName)\n\n\t\t_, err := db.Exec(ctx, createSql)\n\t\tt.AssertNil(err)\n\t\tdefer dropTable(tableName)\n\n\t\t// Get table fields\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// Verify id field has primary key constraint\n\t\tt.AssertNE(fields[\"id\"], nil)\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\t\tt.Assert(fields[\"id\"].Name, \"id\")\n\t\tt.Assert(fields[\"id\"].Type, \"int8(64)\")\n\n\t\t// Verify email field has unique constraint\n\t\tt.AssertNE(fields[\"email\"], nil)\n\t\tt.Assert(fields[\"email\"].Key, \"uni\")\n\t\tt.Assert(fields[\"email\"].Name, \"email\")\n\t\tt.Assert(fields[\"email\"].Type, \"varchar(100)\")\n\n\t\t// Verify username field has no constraint\n\t\tt.AssertNE(fields[\"username\"], nil)\n\t\tt.Assert(fields[\"username\"].Key, \"\")\n\t\tt.Assert(fields[\"username\"].Name, \"username\")\n\n\t\t// Verify status field has no constraint and has default value\n\t\tt.AssertNE(fields[\"status\"], nil)\n\t\tt.Assert(fields[\"status\"].Key, \"\")\n\t\tt.Assert(fields[\"status\"].Name, \"status\")\n\t\tt.Assert(fields[\"status\"].Default, 1)\n\n\t\t// Verify field count is correct (no duplicates)\n\t\tt.Assert(len(fields), 4)\n\t})\n\n\t// Test table with composite constraints\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"test_composite_constraint\"\n\t\tcreateSql := fmt.Sprintf(`\n\t\t\tCREATE TABLE %s (\n\t\t\t\tuser_id bigint NOT NULL,\n\t\t\t\tproject_id bigint NOT NULL,\n\t\t\t\trole varchar(50) NOT NULL,\n\t\t\t\tPRIMARY KEY (user_id, project_id)\n\t\t\t)`, tableName)\n\n\t\t_, err := db.Exec(ctx, createSql)\n\t\tt.AssertNil(err)\n\t\tdefer dropTable(tableName)\n\n\t\t// Get table fields\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// In PostgreSQL, composite primary keys may appear in query results\n\t\t// The first field in the composite key should be marked as 'pri'\n\t\tt.AssertNE(fields[\"user_id\"], nil)\n\t\tt.Assert(fields[\"user_id\"].Name, \"user_id\")\n\n\t\tt.AssertNE(fields[\"project_id\"], nil)\n\t\tt.Assert(fields[\"project_id\"].Name, \"project_id\")\n\n\t\tt.AssertNE(fields[\"role\"], nil)\n\t\tt.Assert(fields[\"role\"].Name, \"role\")\n\t\tt.Assert(fields[\"role\"].Key, \"\")\n\n\t\t// Verify field count is correct (no duplicates)\n\t\tt.Assert(len(fields), 3)\n\t})\n}\n\nfunc Test_DB_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\t// Insert test record\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tanswer, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// Ignore Duplicate record\n\t\tresult, err := db.InsertIgnore(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1_duplicate\",\n\t\t\t\"password\":    \"duplicate_password\",\n\t\t\t\"nickname\":    \"Duplicate\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 0)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"T1\")\n\n\t\t// Insert Correct Record\n\t\tresult, err = db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 1)\n\t\tt.Assert(answer[0][\"passport\"], \"t2\")\n\t\tt.Assert(answer[0][\"password\"], \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(answer[0][\"nickname\"], \"name_2\")\n\n\t\t// Insert Multiple Records Using g.Map Array\n\t\tdata := g.List{\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"t4\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1_conflict\",\n\t\t\t\t\"password\":    \"conflict_password\",\n\t\t\t\t\"nickname\":    \"conflict_name\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2_conflict\",\n\t\t\t\t\"password\":    \"conflict_password\",\n\t\t\t\t\"nickname\":    \"conflict_name\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}\n\n\t\t// Insert Multiple Records with Ignore\n\t\tresult, err = db.InsertIgnore(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tanswer, err = db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(answer), 4)\n\t\t// Should have four records in total (ID 1, 2, 3, 4)\n\n\t\tt.Assert(answer[0][\"passport\"], \"t1\")\n\t\tt.Assert(answer[1][\"passport\"], \"t2\")\n\t\tt.Assert(answer[2][\"passport\"], \"t3\")\n\t\tt.Assert(answer[3][\"passport\"], \"t4\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb, err := gdb.Instance()\n\t\tt.AssertNil(err)\n\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\n\t\tnewDb := db.Ctx(context.Background())\n\t\tt.AssertNE(newDb, nil)\n\t})\n}\n\nfunc Test_Ctx_Query(t *testing.T) {\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Query(ctx, \"select 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Query(ctx, \"select 2\")\n\t})\n}\n\nfunc Test_Ctx_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"12345678\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.1\")\n\t\tdb.Model(table).Ctx(ctx).All()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tdb.Model(table).All()\n\t})\n}\n\nfunc Test_Ctx_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tdb.GetLogger().(*glog.Logger).SetCtxKeys(\"SpanId\", \"TraceId\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\tctx := context.WithValue(context.Background(), \"TraceId\", \"tx_trace_123\")\n\t\tctx = context.WithValue(ctx, \"SpanId\", \"0.2\")\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Ctx(ctx).Where(\"id\", 1).One()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Ctx_Timeout(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10)\n\t\tdefer cancel()\n\n\t\t// Wait for the context to expire\n\t\ttime.Sleep(time.Millisecond * 50)\n\n\t\t// Query with expired context should return error\n\t\t_, err := db.Model(table).Ctx(ctx).All()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Hook_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"test\"] = gvar.New(100 + record[\"id\"].Int())\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(\"id > ?\", 6).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 4)\n\t\tt.Assert(all[0][\"id\"].Int(), 7)\n\t\tt.Assert(all[0][\"test\"].Int(), 107)\n\t\tt.Assert(all[1][\"test\"].Int(), 108)\n\t\tt.Assert(all[2][\"test\"].Int(), 109)\n\t\tt.Assert(all[3][\"test\"].Int(), 110)\n\t})\n}\n\nfunc Test_Model_Hook_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tInsert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {\n\t\t\t\tfor i, item := range in.Data {\n\t\t\t\t\titem[\"passport\"] = fmt.Sprintf(`test_port_%d`, item[\"id\"])\n\t\t\t\t\titem[\"nickname\"] = fmt.Sprintf(`test_name_%d`, item[\"id\"])\n\t\t\t\t\titem[\"password\"] = fmt.Sprintf(`test_pass_%d`, item[\"id\"])\n\t\t\t\t\titem[\"create_time\"] = CreateTime\n\t\t\t\t\tin.Data[i] = item\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Insert(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"nickname\": \"name_1\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `test_port_1`)\n\t\tt.Assert(one[\"nickname\"], `test_name_1`)\n\t})\n}\n\nfunc Test_Model_Hook_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tUpdate: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {\n\t\t\t\tswitch value := in.Data.(type) {\n\t\t\t\tcase gdb.List:\n\t\t\t\t\tfor i, data := range value {\n\t\t\t\t\t\tdata[\"passport\"] = `port`\n\t\t\t\t\t\tdata[\"nickname\"] = `name`\n\t\t\t\t\t\tvalue[i] = data\n\t\t\t\t\t}\n\t\t\t\t\tin.Data = value\n\n\t\t\t\tcase gdb.Map:\n\t\t\t\t\tvalue[\"passport\"] = `port`\n\t\t\t\t\tvalue[\"nickname\"] = `name`\n\t\t\t\t\tin.Data = value\n\t\t\t\t}\n\t\t\t\treturn in.Next(ctx)\n\t\t\t},\n\t\t})\n\t\t_, err := m.Data(g.Map{\n\t\t\t\"nickname\": \"name_1\",\n\t\t}).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := m.One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"], `port`)\n\t\tt.Assert(one[\"nickname\"], `name`)\n\t})\n}\n\nfunc Test_Model_Hook_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tDelete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {\n\t\t\t\treturn db.Model(table).Data(g.Map{\n\t\t\t\t\t\"nickname\": `deleted`,\n\t\t\t\t}).Where(in.Condition).Update()\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tfor _, item := range all {\n\t\t\tt.Assert(item[\"nickname\"].String(), `deleted`)\n\t\t}\n\t})\n}\n\nfunc Test_Model_Hook_Select_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Adding extra fields should not affect Count operations\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"extra\"] = gvar.New(\"extra_value\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tcount, err := m.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_Model_Hook_Chain(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Hook replacement: the last Hook replaces the previous one\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"hook1\"] = gvar.New(\"value1\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t}).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\tresult, err = in.Next(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor i, record := range result {\n\t\t\t\t\trecord[\"hook2\"] = gvar.New(\"value2\")\n\t\t\t\t\tresult[i] = record\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t},\n\t\t})\n\t\tall, err := m.Where(\"id\", 1).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\t// The last Hook should take effect (Hook replaces previous one)\n\t\tt.Assert(all[0][\"hook2\"].String(), \"value2\")\n\t})\n\n\t// Error chain: hook returns error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Hook(gdb.HookHandler{\n\t\t\tSelect: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {\n\t\t\t\treturn nil, gerror.New(\"hook error\")\n\t\t\t},\n\t\t})\n\t\t_, err := m.Where(\"id\", 1).All()\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"hook error\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_model_builder_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Model_Builder(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where And\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.Where(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).Where(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n\n\t// Where Or\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\tall, err := m.WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{1, 2, 3}).WhereOr(\"id\", g.Slice{4, 5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{2, 3}).WhereOr(\"id\", g.Slice{5, 6}),\n\t\t).WhereOr(\n\t\t\tb.Where(\"id\", g.Slice{3}).Where(\"id\", g.Slice{1, 2, 3}),\n\t\t).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 6)\n\t})\n\n\t// Where with struct which has a field type of *gtime.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=? AND \"nickname\" IS NULL`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with struct which has a field type of *gjson.Json\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tId       any\n\t\t\tNickname *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=? AND \"nickname\" IS NULL`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gtime.Time and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gtime.Time\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=?`)\n\t\tt.Assert(args, []any{1})\n\t})\n\n\t// Where with do struct which has a field type of *gjson.Json and generated by gf cli\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table)\n\t\tb := m.Builder()\n\n\t\ttype Query struct {\n\t\t\tgmeta.Meta `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tNickname   *gjson.Json\n\t\t}\n\n\t\twhere, args := b.Where(&Query{Id: 1}).Build()\n\t\tt.Assert(where, `\"id\"=?`)\n\t\tt.Assert(args, []any{1})\n\t})\n}\n\nfunc Test_Safe_Builder(t *testing.T) {\n\t// test whether m.Builder() is chain safe\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := db.Model().Builder()\n\t\tb.Where(\"id\", 1)\n\t\t_, args := b.Build()\n\t\tt.AssertNil(args)\n\n\t\tb = b.Where(\"id\", 1)\n\t\t_, args = b.Build()\n\t\tt.Assert(args, g.Slice{1})\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_model_do_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// createTableDO creates a table with nullable columns (no NOT NULL constraints)\n// suitable for DO (Data Object) partial insert tests.\nfunc createTableDO(table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"do_test\", gtime.TimestampNano())\n\t}\n\tdropTable(name)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial NOT NULL,\n\t\t\tpassport varchar(45) DEFAULT '',\n\t\t\tpassword varchar(32) DEFAULT '',\n\t\t\tnickname varchar(45) DEFAULT '',\n\t\t\tcreate_time timestamp DEFAULT NULL,\n\t\t\tPRIMARY KEY (id)\n\t\t);`, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc Test_Model_Insert_Data_DO(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_DO(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUser{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUser{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 2)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Update_Pointer_Data_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype NN string\n\t\ttype Req struct {\n\t\t\tId       int\n\t\t\tPassport *string\n\t\t\tPassword *string\n\t\t\tNickname *NN\n\t\t}\n\t\ttype UserDo struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tvar (\n\t\t\tnickname = NN(\"nickname_111\")\n\t\t\treq      = Req{\n\t\t\t\tPassword: gconv.PtrString(\"12345678\"),\n\t\t\t\tNickname: &nickname,\n\t\t\t}\n\t\t\tdata = UserDo{\n\t\t\t\tPassport: req.Passport,\n\t\t\t\tPassword: req.Password,\n\t\t\t\tNickname: req.Nickname,\n\t\t\t}\n\t\t)\n\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`password`], `12345678`)\n\t\tt.Assert(one[`nickname`], `nickname_111`)\n\t})\n}\n\nfunc Test_Model_Where_DO(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tg.Meta     `orm:\"do:true\"`\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := User{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Insert_Data_ForDao(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Insert_Data_List_ForDao(t *testing.T) {\n\ttable := createTableDO()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := g.Slice{\n\t\t\tUserForDao{\n\t\t\t\tId:       1,\n\t\t\t\tPassport: \"user_1\",\n\t\t\t\tPassword: \"pass_1\",\n\t\t\t},\n\t\t\tUserForDao{\n\t\t\t\tId:       2,\n\t\t\t\tPassport: \"user_2\",\n\t\t\t\tPassword: \"pass_2\",\n\t\t\t},\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], ``)\n\n\t\tone, err = db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 2)\n\t\tt.Assert(one[`passport`], `user_2`)\n\t\tt.Assert(one[`password`], `pass_2`)\n\t\tt.Assert(one[`nickname`], ``)\n\t})\n}\n\nfunc Test_Model_Update_Data_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\tdata := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_100\",\n\t\t\tPassword: \"pass_100\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_100`)\n\t\tt.Assert(one[`password`], `pass_100`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_ForDao(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserForDao struct {\n\t\t\tId         any\n\t\t\tPassport   any\n\t\t\tPassword   any\n\t\t\tNickname   any\n\t\t\tCreateTime any\n\t\t}\n\t\twhere := UserForDao{\n\t\t\tId:       1,\n\t\t\tPassport: \"user_1\",\n\t\t\tPassword: \"pass_1\",\n\t\t}\n\t\tone, err := db.Model(table).Where(where).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[`id`], 1)\n\t\tt.Assert(one[`passport`], `user_1`)\n\t\tt.Assert(one[`password`], `pass_1`)\n\t\tt.Assert(one[`nickname`], `name_1`)\n\t})\n}\n\nfunc Test_Model_Where_FieldPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n\t// With omitempty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := gstr.SplitAndTrim(gtest.DataContent(`table_with_prefix.sql`), \";\")\n\t\tfor _, v := range array {\n\t\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\t\tgtest.Error(err)\n\t\t\t}\n\t\t}\n\t\tdefer dropTable(\"instance\")\n\n\t\ttype Instance struct {\n\t\t\tID   int `orm:\"f_id,omitempty\"`\n\t\t\tName string\n\t\t}\n\n\t\ttype InstanceDo struct {\n\t\t\tg.Meta `orm:\"table:instance, do:true\"`\n\t\t\tID     any `orm:\"f_id,omitempty\"`\n\t\t}\n\t\tvar instance *Instance\n\t\terr := db.Model(\"instance\").Where(InstanceDo{\n\t\t\tID: 1,\n\t\t}).Scan(&instance)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(instance, nil)\n\t\tt.Assert(instance.ID, 1)\n\t\tt.Assert(instance.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_model_join_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_LeftJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_RightJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_InnerJoinOnField(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_LeftJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_RightJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tRightJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_InnerJoinOnFields(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tInnerJoinOnFields(table2, \"id\", \"=\", \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_FieldsPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"t_\" + gtime.TimestampNanoStr() + \"_table1\"\n\t\ttable2 = \"t_\" + gtime.TimestampNanoStr() + \"_table2\"\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"id\").\n\t\t\tFieldsPrefix(table2, \"nickname\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereIn(\"id\", g.Slice{1, 2}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_model_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Model_Embedded_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int    `json:\"id\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=100\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"john-test\")\n\t})\n}\n\nfunc Test_Model_Embedded_MapToStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Ids struct {\n\t\t\tId int `json:\"id\"`\n\t\t}\n\t\ttype Base struct {\n\t\t\tIds\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string `json:\"passport\"`\n\t\t\tPassword string `json:\"password\"`\n\t\t\tNickname string `json:\"nickname\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          100,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\n\t\tuser := new(User)\n\n\t\tt.Assert(one.Struct(user), nil)\n\t\tt.Assert(user.Id, data[\"id\"])\n\t\tt.Assert(user.Passport, data[\"passport\"])\n\t\tt.Assert(user.Password, data[\"password\"])\n\t\tt.Assert(user.Nickname, data[\"nickname\"])\n\t\tt.Assert(user.CreateTime, data[\"create_time\"])\n\t})\n}\n\nfunc Test_Struct_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tuser := new(User)\n\t\terr = one.Struct(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Scan(user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Scan(&user, \"id=1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(*user.Id, 1)\n\t\tt.Assert(*user.Passport, \"user_1\")\n\t\tt.Assert(*user.Password, \"pass_1\")\n\t\tt.Assert(user.Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Structs_Pointer_Attribute(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       *int\n\t\tPassport *string\n\t\tPassword *string\n\t\tNickname string\n\t}\n\t// All\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\tone, err := db.Model(table).All(\"id < 3\")\n\t\tt.AssertNil(err)\n\t\terr = one.Structs(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tusers := make([]*User, 0)\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Scan(&users, \"id < 3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(*users[0].Id, 1)\n\t\tt.Assert(*users[0].Passport, \"user_1\")\n\t\tt.Assert(*users[0].Password, \"pass_1\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t})\n}\n\nfunc Test_Struct_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=100\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t\tt.AssertNE(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Where(\"id=100\").One()\n\t\tt.AssertNil(err)\n\t\tvar user *User\n\t\tt.Assert(one.Struct(&user), nil)\n\t\tt.Assert(user, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, nil)\n\t})\n}\n\nfunc Test_Structs_Empty(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t\tPassword string\n\t\tNickname string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 0)\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tusers := make([]*User, 10)\n\t\tt.Assert(all.Structs(&users), sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id>100\").All()\n\t\tt.AssertNil(err)\n\t\tvar users []*User\n\t\tt.Assert(all.Structs(&users), nil)\n\t})\n}\n\ntype MyTime struct {\n\tgtime.Time\n}\n\ntype MyTimeSt struct {\n\tCreateTime MyTime\n}\n\nfunc (st *MyTimeSt) UnmarshalValue(v any) error {\n\tm := gconv.Map(v)\n\tt, err := gtime.StrToTime(gconv.String(m[\"create_time\"]))\n\tif err != nil {\n\t\treturn err\n\t}\n\tst.CreateTime = MyTime{*t}\n\treturn nil\n}\n\nfunc Test_Model_Scan_CustomType_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyTimeSt)\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar stSlice []*MyTimeSt\n\t\terr := db.Model(table).Fields(\"create_time\").Scan(&stSlice)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(stSlice), TableSize)\n\t\tt.Assert(stSlice[0].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t\tt.Assert(stSlice[9].CreateTime.String(), \"2018-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_Model_Scan_CustomType_String(t *testing.T) {\n\ttype MyString string\n\n\ttype MyStringSt struct {\n\t\tPassport MyString\n\t}\n\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := new(MyStringSt)\n\t\terr := db.Model(table).Fields(\"Passport\").WherePri(1).Scan(st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.Passport, \"user_1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar sts []MyStringSt\n\t\terr := db.Model(table).Fields(\"Passport\").Order(\"id asc\").Scan(&sts)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(sts), TableSize)\n\t\tt.Assert(sts[0].Passport, \"user_1\")\n\t})\n}\n\ntype User struct {\n\tId         int\n\tPassport   string\n\tPassword   string\n\tNickname   string\n\tCreateTime *gtime.Time\n}\n\nfunc (user *User) UnmarshalValue(value any) error {\n\tif record, ok := value.(gdb.Record); ok {\n\t\t*user = User{\n\t\t\tId:         record[\"id\"].Int(),\n\t\t\tPassport:   record[\"passport\"].String(),\n\t\t\tPassword:   \"\",\n\t\t\tNickname:   record[\"nickname\"].String(),\n\t\t\tCreateTime: record[\"create_time\"].GTime(),\n\t\t}\n\t\treturn nil\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value))\n}\n\nfunc Test_Model_Scan_UnmarshalValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Scan_Map(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t\tt.Assert(users[0].Password, \"\")\n\t\tt.Assert(users[0].Nickname, \"name_1\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\n\t\tt.Assert(users[9].Id, 10)\n\t\tt.Assert(users[9].Passport, \"user_10\")\n\t\tt.Assert(users[9].Password, \"\")\n\t\tt.Assert(users[9].Nickname, \"name_10\")\n\t\tt.Assert(users[9].CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Scan_AutoFilteringByStructAttributes(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId       int\n\t\tPassport string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).OrderAsc(\"id\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_model_subquery_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_SubQuery_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[1][\"id\"], 3)\n\t\tt.Assert(r[2][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(\n\t\t\t\"id in ?\",\n\t\t\tdb.Model(table).Fields(\"id\").Where(\"id\", g.Slice{1, 3, 5}),\n\t\t).Group(\"id\").Having(\n\t\t\t\"id > ?\",\n\t\t\tdb.Model(table).Fields(\"MAX(id)\").Where(\"id\", g.Slice{1, 3}),\n\t\t).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_SubQuery_Model(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery1 := db.Model(table).Where(\"id\", g.Slice{1, 3, 5})\n\t\tsubQuery2 := db.Model(table).Where(\"id\", g.Slice{5, 7, 9})\n\t\tr, err := db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2).Fields(\"a.id\").Where(\"a.id=b.id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_scanlist_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Table_Relation_One(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL,\n  course varchar(45) NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `orm:\"uid\"`\n\t\tName string `orm:\"name\"`\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int    `orm:\"uid\"`\n\t\tAddress string `orm:\"address\"`\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId     int    `orm:\"id\"`\n\t\tUid    int    `orm:\"uid\"`\n\t\tScore  int    `orm:\"score\"`\n\t\tCourse string `orm:\"course\"`\n\t}\n\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tr, err := tx.Model(tableUser).Data(g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tuid, err := r.LastInsertId()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserDetail).Data(g.Map{\n\t\t\t\t\"uid\":     uid,\n\t\t\t\t\"address\": \"Beijing DongZhiMen #66\",\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = tx.Model(tableUserScores).Data(g.Slice{\n\t\t\t\tg.Map{\"uid\": uid, \"score\": 100, \"course\": \"math\"},\n\t\t\t\tg.Map{\"uid\": uid, \"score\": 99, \"course\": \"physics\"},\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n\t// Data check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(tableUser).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"name\"].String(), \"john\")\n\n\t\tr, err = db.Model(tableUserDetail).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 1)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"address\"].String(), `Beijing DongZhiMen #66`)\n\n\t\tr, err = db.Model(tableUserScores).Where(\"uid\", r[0][\"uid\"].Int()).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Len(), 2)\n\t\tt.Assert(r[0][\"uid\"].Int(), 1)\n\t\tt.Assert(r[1][\"uid\"].Int(), 1)\n\t\tt.Assert(r[0][\"course\"].String(), `math`)\n\t\tt.Assert(r[1][\"course\"].String(), `physics`)\n\t})\n\t// Entity query.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user Entity\n\t\t// SELECT * FROM `user` WHERE `name`='john'\n\t\terr := db.Model(tableUser).Scan(&user.User, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid`=1\n\t\terr = db.Model(tableUserDetail).Scan(&user.UserDetail, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid`=1\n\t\terr = db.Model(tableUserScores).Scan(&user.UserScores, \"uid\", user.User.Uid)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(user.User, EntityUser{\n\t\t\tUid:  1,\n\t\t\tName: \"john\",\n\t\t})\n\t\tt.Assert(user.UserDetail, EntityUserDetail{\n\t\t\tUid:     1,\n\t\t\tAddress: \"Beijing DongZhiMen #66\",\n\t\t})\n\t\tt.Assert(user.UserScores, []EntityUserScores{\n\t\t\t{Id: 1, Uid: 1, Course: \"math\", Score: 100},\n\t\t\t{Id: 2, Uid: 1, Course: \"physics\", Score: 99},\n\t\t})\n\t})\n}\n\nfunc Test_Table_Relation_Many(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_Many_ModelScanList(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_EmptyData(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 0)\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid:uid\")\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Table_Relation_NoneEqualDataSize(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\tUser       *EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail and Scores are not inserted.\n\t\t}\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err = db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"User\", \"Uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"User\", \"UID\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n\n\t// Model ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).\n\t\t\tWhere(\"uid\", g.Slice{3, 4}).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"User\")\n\t\tt.AssertNil(err)\n\t\t// Detail\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"uid asc\").\n\t\t\tScanList(&users, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t\t// Scores\n\t\terr = db.Model(tableUserScores).\n\t\t\tWhere(\"uid\", gdb.ListItemValues(users, \"User\", \"Uid\")).\n\t\t\tOrder(\"id asc\").\n\t\t\tScanList(&users, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].User, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].User, &EntityUser{4, \"name_4\"})\n\n\t\tt.Assert(users[0].UserDetail, nil)\n\n\t\tt.Assert(len(users[0].UserScores), 0)\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct1(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\t*EntityUser\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\t*EntityUser\n\t\t*EntityUserDetail\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tscores []*EntityUserScores\n\t\t)\n\t\t// SELECT * FROM `user_scores`\n\t\terr = db.Model(tableUserScores).Scan(&scores)\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_scores` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUser).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUser\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// SELECT * FROM `user_detail` WHERE `uid` IN(1,2,3,4,5)\n\t\terr = db.Model(tableUserDetail).\n\t\t\tWhere(\"uid\", gdb.ListItemValuesUnique(&scores, \"Uid\")).\n\t\t\tScanList(&scores, \"EntityUserDetail\", \"uid:Uid\")\n\t\tt.AssertNil(err)\n\n\t\t// Assertions.\n\t\tt.Assert(len(scores), 25)\n\t\tt.Assert(scores[0].Id, 1)\n\t\tt.Assert(scores[0].Uid, 1)\n\t\tt.Assert(scores[0].Name, \"name_1\")\n\t\tt.Assert(scores[0].Address, \"address_1\")\n\t\tt.Assert(scores[24].Id, 25)\n\t\tt.Assert(scores[24].Uid, 5)\n\t\tt.Assert(scores[24].Name, \"name_5\")\n\t\tt.Assert(scores[24].Address, \"address_5\")\n\t})\n}\n\nfunc Test_Table_Relation_EmbeddedStruct2(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"user_\" + gtime.TimestampNanoStr()\n\t\ttableUserDetail = \"user_detail_\" + gtime.TimestampNanoStr()\n\t\ttableUserScores = \"user_scores_\" + gtime.TimestampNanoStr()\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  name varchar(45) NOT NULL\n);\n    `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  uid SERIAL PRIMARY KEY,\n  address varchar(45) NOT NULL\n);\n    `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id SERIAL PRIMARY KEY,\n  uid integer NOT NULL,\n  score integer NOT NULL\n);\n    `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype EntityUser struct {\n\t\tUid  int    `json:\"uid\"`\n\t\tName string `json:\"name\"`\n\t}\n\ttype EntityUserDetail struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\ttype EntityUserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\ttype Entity struct {\n\t\t*EntityUser\n\t\tUserDetail *EntityUserDetail\n\t\tUserScores []*EntityUserScores\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\t\"uid\":  i,\n\t\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"uid\":     i,\n\t\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\t\"uid\":   i,\n\t\t\t\t\t\"score\": j,\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// MapKeyValue.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"3\"].Map()[\"uid\"], 3)\n\t\tt.Assert(all.MapKeyValue(\"uid\")[\"4\"].Map()[\"uid\"], 4)\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", g.Slice{3, 4}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Len(), 10)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")), 2)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"3\"].Slice()), 5)\n\t\tt.Assert(len(all.MapKeyValue(\"uid\")[\"4\"].Slice()), 5)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[0])[\"score\"], 1)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"uid\"], 3)\n\t\tt.Assert(gconv.Map(all.MapKeyValue(\"uid\")[\"3\"].Slice()[4])[\"score\"], 5)\n\t})\n\n\t// Result ScanList with struct elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// Result ScanList with pointer elements and pointer attributes.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*Entity\n\t\t// User\n\t\terr := db.Model(tableUser).Where(\"uid\", g.Slice{3, 4}).Order(\"uid asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].EntityUser, &EntityUser{3, \"name_3\"})\n\t\tt.Assert(users[1].EntityUser, &EntityUser{4, \"name_4\"})\n\t\t// Detail\n\t\tall, err := db.Model(tableUserDetail).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"uid asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(users[0].UserDetail, &EntityUserDetail{3, \"address_3\"})\n\t\tt.Assert(users[1].UserDetail, &EntityUserDetail{4, \"address_4\"})\n\t\t// Scores\n\t\tall, err = db.Model(tableUserScores).Where(\"uid\", gdb.ListItemValues(users, \"Uid\")).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\terr = all.ScanList(&users, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_soft_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t// \"github.com/gogf/gf/v2/database/gdb\" // FIXME: Uncomment when boolean soft delete tests are enabled\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// CreateAt/UpdateAt/DeleteAt.\nfunc Test_SoftTime_CreateUpdateDelete1(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save (PostgreSQL uses OnConflict instead of REPLACE)\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreateAt/UpdateAt/DeleteAt with timestamp(0).\nfunc Test_SoftTime_CreateUpdateDelete2(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(0) DEFAULT NULL,\n  update_at timestamp(0) DEFAULT NULL,\n  delete_at timestamp(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Map(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  name       varchar(45) DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\": \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\n// CreatedAt/UpdatedAt/DeletedAt with struct.\nfunc Test_SoftTime_CreatedUpdatedDeleted_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  name       varchar(45) DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId        int\n\t\tName      string\n\t\tCreatedAT *gtime.Time\n\t\tUpdatedAT *gtime.Time\n\t\tDeletedAT *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"deleted_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"created_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := User{\n\t\t\tId:   1,\n\t\t\tName: \"name_10\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"updated_at\"].GTime().Timestamp(), oneInsert[\"updated_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := User{\n\t\t\tName: \"name_1000\",\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).OmitEmpty().WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"deleted_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"created_at\"].GTime().Timestamp(), oneInsert[\"created_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"updated_at\"].GTime().Timestamp(), gtime.Timestamp()-4)\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"deleted_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftUpdateTime(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  num       integer DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\tr, err = db.Model(table).Data(\"num=num+1\").Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_SoftUpdateTime_WithDO(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id         integer NOT NULL,\n  num        integer DEFAULT NULL,\n  created_at timestamp(6) DEFAULT NULL,\n  updated_at timestamp(6) DEFAULT NULL,\n  deleted_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":  1,\n\t\t\t\"num\": 10,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInserted, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInserted[\"id\"].Int(), 1)\n\t\tt.Assert(oneInserted[\"num\"].Int(), 10)\n\n\t\t// Update.\n\t\ttime.Sleep(2 * time.Second)\n\t\ttype User struct {\n\t\t\tg.Meta    `orm:\"do:true\"`\n\t\t\tId        any\n\t\t\tNum       any\n\t\t\tCreatedAt any\n\t\t\tUpdatedAt any\n\t\t\tDeletedAt any\n\t\t}\n\t\tr, err = db.Model(table).Data(User{\n\t\t\tNum: 100,\n\t\t}).Where(\"id=?\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdated, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdated[\"num\"].Int(), 100)\n\t\tt.Assert(oneUpdated[\"created_at\"].String(), oneInserted[\"created_at\"].String())\n\t\tt.AssertNE(oneUpdated[\"updated_at\"].String(), oneInserted[\"updated_at\"].String())\n\t})\n}\n\nfunc Test_SoftDelete(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(10).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"create_at\"].String(), \"\")\n\t\tt.AssertNE(one[\"update_at\"].String(), \"\")\n\t\tt.Assert(one[\"delete_at\"].String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", ids).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\n\t\tall, err := db.Model(table).Unscoped().Where(\"id\", ids).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.AssertNE(all[0][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[0][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[1][\"delete_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"create_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"update_at\"].String(), \"\")\n\t\tt.AssertNE(all[2][\"delete_at\"].String(), \"\")\n\t})\n}\n\nfunc Test_SoftDelete_Join(t *testing.T) {\n\ttable1 := \"time_test_table1_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table1)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table1)\n\n\ttable2 := \"time_test_table2_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  createat  timestamp(6) DEFAULT NULL,\n  updateat  timestamp(6) DEFAULT NULL,\n  deleteat  timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table2)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tdataInsert1 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table1).Data(dataInsert1).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tdataInsert2 := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_2\",\n\t\t}\n\t\tr, err = db.Model(table2).Data(dataInsert2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"], \"name_1\")\n\n\t\t// Soft deleting.\n\t\tr, err = db.Model(table1).Where(\"1=1\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table1, \"t1\").LeftJoin(table2, \"t2\", \"t2.id=t1.id\").Fields(\"t1.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\tone, err = db.Model(table2, \"t2\").LeftJoin(table1, \"t1\", \"t2.id=t1.id\").Fields(\"t2.name\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\t})\n}\n\nfunc Test_SoftDelete_WhereAndOr(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\t// Add datas.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tdata := g.Map{\n\t\t\t\t\"id\":   i,\n\t\t\t\t\"name\": fmt.Sprintf(\"name_%d\", i),\n\t\t\t}\n\t\t\tr, err := db.Model(table).Data(data).Insert()\n\t\t\tt.AssertNil(err)\n\t\t\tn, _ := r.RowsAffected()\n\t\t\tt.Assert(n, 1)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tids := g.SliceInt{1, 3, 5}\n\t\tr, err := db.Model(table).Where(\"id\", ids).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 3)\n\n\t\tcount, err := db.Model(table).Where(\"id\", 1).WhereOr(\"id\", 3).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n}\n\nfunc Test_CreateUpdateTime_Struct(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(6) DEFAULT NULL,\n  update_at timestamp(6) DEFAULT NULL,\n  delete_at timestamp(6) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// db.SetDebug(true)\n\t// defer db.SetDebug(false)\n\n\ttype Entity struct {\n\t\tId       uint64      `orm:\"id,primary\" json:\"id\"`\n\t\tName     string      `orm:\"name\"       json:\"name\"`\n\t\tCreateAt *gtime.Time `orm:\"create_at\"  json:\"create_at\"`\n\t\tUpdateAt *gtime.Time `orm:\"update_at\"  json:\"update_at\"`\n\t\tDeleteAt *gtime.Time `orm:\"delete_at\"  json:\"delete_at\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).OmitEmpty().Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.AssertGE(oneInsert[\"create_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\tt.AssertGE(oneInsert[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_10\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OmitEmpty().OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertNE(oneSave[\"update_at\"].GTime().Timestamp(), oneInsert[\"update_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneSave[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := &Entity{\n\t\t\tId:       1,\n\t\t\tName:     \"name_1000\",\n\t\t\tCreateAt: nil,\n\t\t\tUpdateAt: nil,\n\t\t\tDeleteAt: nil,\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).OmitEmpty().Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].GTime().Timestamp(), oneInsert[\"create_at\"].GTime().Timestamp())\n\t\tt.AssertGE(oneUpdate[\"update_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Delete\n\t\tr, err = db.Model(table).Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\t// Delete Select\n\t\tone4, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one4), 0)\n\t\tone5, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one5[\"id\"].Int(), 1)\n\t\tt.AssertGE(one5[\"delete_at\"].GTime().Timestamp(), gtime.Timestamp()-2)\n\t\t// Delete Count\n\t\ti, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 1)\n\n\t\t// Delete Unscoped\n\t\tr, err = db.Model(table).Unscoped().Delete(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone6, err := db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one6), 0)\n\t\ti, err = db.Model(table).Unscoped().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(i, 0)\n\t})\n}\n\nfunc Test_SoftTime_CreateUpdateDelete_UnixTimestamp(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at integer DEFAULT NULL,\n  update_at integer DEFAULT NULL,\n  delete_at integer DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\t// insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"name_1\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_1\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\t})\n\n\t// sleep some seconds to make update time greater than create time.\n\ttime.Sleep(2 * time.Second)\n\n\t// update\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// update: map\n\t\tdataInsert := g.Map{\n\t\t\t\"name\": \"name_11\",\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_11\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t\tt.Assert(len(one[\"create_at\"].String()), 10)\n\t\tt.Assert(len(one[\"update_at\"].String()), 10)\n\n\t\tvar (\n\t\t\tlastCreateTime = one[\"create_at\"].Int64()\n\t\t\tlastUpdateTime = one[\"update_at\"].Int64()\n\t\t)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// update: string\n\t\tr, err = db.Model(table).Data(\"name='name_111'\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.Assert(one[\"create_at\"].Int64(), lastCreateTime)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), lastUpdateTime)\n\t\tt.Assert(one[\"delete_at\"].Int64(), 0)\n\t})\n\n\t// delete\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).WherePri(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 0)\n\n\t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"name\"].String(), \"name_111\")\n\t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n\t\tt.AssertGT(one[\"delete_at\"].Int64(), 0)\n\t})\n}\n\n// FIXME: PostgreSQL boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but PostgreSQL boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports PostgreSQL boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Bool_Deleted(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at integer DEFAULT NULL,\n//   update_at integer DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \t//db.SetDebug(true)\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t\tt.Assert(len(one[\"create_at\"].String()), 10)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 10)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\n// FIXME: PostgreSQL boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but PostgreSQL boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports PostgreSQL boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampMilli(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at bigint DEFAULT NULL,\n//   update_at bigint DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \tvar softTimeOption = gdb.SoftTimeOption{\n// \t\tSoftTimeType: gdb.SoftTimeTypeTimestampMilli,\n// \t}\n//\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.Assert(len(one[\"create_at\"].String()), 13)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 13)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\n// FIXME: PostgreSQL boolean type soft delete is not supported yet.\n// The framework generates \"delete_at=0\" condition for soft delete query,\n// but PostgreSQL boolean cannot compare with integer directly.\n// Uncomment this test after the framework supports PostgreSQL boolean soft delete.\n//\n// func Test_SoftTime_CreateUpdateDelete_Option_SoftTimeTypeTimestampNano(t *testing.T) {\n// \ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// CREATE TABLE %s (\n//   id        integer NOT NULL,\n//   name      varchar(45) DEFAULT NULL,\n//   create_at bigint DEFAULT NULL,\n//   update_at bigint DEFAULT NULL,\n//   delete_at boolean DEFAULT NULL,\n//   PRIMARY KEY (id)\n// );\n//     `, table)); err != nil {\n// \t\tgtest.Error(err)\n// \t}\n// \tdefer dropTable(table)\n//\n// \tvar softTimeOption = gdb.SoftTimeOption{\n// \t\tSoftTimeType: gdb.SoftTimeTypeTimestampNano,\n// \t}\n//\n// \t// insert\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tdataInsert := g.Map{\n// \t\t\t\"id\":   1,\n// \t\t\t\"name\": \"name_1\",\n// \t\t}\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).Data(dataInsert).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.Assert(len(one[\"create_at\"].String()), 19)\n// \t\tt.Assert(len(one[\"update_at\"].String()), 19)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), false)\n// \t})\n//\n// \t// delete\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tr, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).Delete()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := r.RowsAffected()\n// \t\tt.Assert(n, 1)\n//\n// \t\tone, err := db.Model(table).SoftTime(softTimeOption).WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(one), 0)\n//\n// \t\tone, err = db.Model(table).Unscoped().WherePri(1).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one[\"name\"].String(), \"name_1\")\n// \t\tt.AssertGT(one[\"create_at\"].Int64(), 0)\n// \t\tt.AssertGT(one[\"update_at\"].Int64(), 0)\n// \t\tt.Assert(one[\"delete_at\"].Bool(), true)\n// \t})\n// }\n\nfunc Test_SoftTime_CreateUpdateDelete_Specified(t *testing.T) {\n\ttable := \"soft_time_test_table_\" + gtime.TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\n  id        integer NOT NULL,\n  name      varchar(45) DEFAULT NULL,\n  create_at timestamp(0) DEFAULT NULL,\n  update_at timestamp(0) DEFAULT NULL,\n  delete_at timestamp(0) DEFAULT NULL,\n  PRIMARY KEY (id)\n);\n    `, table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert\n\t\tdataInsert := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_1\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err := db.Model(table).Data(dataInsert).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneInsert, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneInsert[\"id\"].Int(), 1)\n\t\tt.Assert(oneInsert[\"name\"].String(), \"name_1\")\n\t\tt.Assert(oneInsert[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneInsert[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneInsert[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Save\n\t\tdataSave := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"name\":      \"name_10\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:15:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataSave).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneSave, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneSave[\"id\"].Int(), 1)\n\t\tt.Assert(oneSave[\"name\"].String(), \"name_10\")\n\t\tt.Assert(oneSave[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneSave[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneSave[\"update_at\"].String(), \"2024-05-30 20:15:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Update\n\t\tdataUpdate := g.Map{\n\t\t\t\"name\":      \"name_1000\",\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:30:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\toneUpdate, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneUpdate[\"id\"].Int(), 1)\n\t\tt.Assert(oneUpdate[\"name\"].String(), \"name_1000\")\n\t\tt.Assert(oneUpdate[\"delete_at\"].String(), \"\")\n\t\tt.Assert(oneUpdate[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneUpdate[\"update_at\"].String(), \"2024-05-30 20:30:00\")\n\n\t\t// For time asserting purpose.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Insert with delete_at\n\t\tdataInsertDelete := g.Map{\n\t\t\t\"id\":        2,\n\t\t\t\"name\":      \"name_2\",\n\t\t\t\"create_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"update_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t\t\"delete_at\": gtime.NewFromStr(\"2024-05-30 20:00:00\"),\n\t\t}\n\t\tr, err = db.Model(table).Data(dataInsertDelete).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Delete Select\n\t\toneDelete, err := db.Model(table).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(oneDelete), 0)\n\t\toneDeleteUnscoped, err := db.Model(table).Unscoped().WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(oneDeleteUnscoped[\"id\"].Int(), 2)\n\t\tt.Assert(oneDeleteUnscoped[\"name\"].String(), \"name_2\")\n\t\tt.Assert(oneDeleteUnscoped[\"delete_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"create_at\"].String(), \"2024-05-30 20:00:00\")\n\t\tt.Assert(oneDeleteUnscoped[\"update_at\"].String(), \"2024-05-30 20:00:00\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_union_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_Union(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Union(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_UnionAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").All()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 5)\n\t\tt.Assert(r[0][\"id\"], 3)\n\t\tt.Assert(r[1][\"id\"], 2)\n\t\tt.Assert(r[2][\"id\"], 2)\n\t\tt.Assert(r[3][\"id\"], 1)\n\t\tt.Assert(r[4][\"id\"], 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).UnionAll(\n\t\t\tdb.Model(table).Where(\"id\", 1),\n\t\t\tdb.Model(table).Where(\"id\", 2),\n\t\t\tdb.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).OrderDesc(\"id\"),\n\t\t).OrderDesc(\"id\").One()\n\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(r[\"id\"], 3)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_feature_with_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc Test_Table_Relation_With_Scan(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_scan_user\"\n\t\ttableUserDetail = \"with_scan_user_detail\"\n\t\ttableUserScores = \"with_scan_user_score\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScore struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user_score\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_scan_user\"`\n\t\tId         int          `json:\"id\"`\n\t\tName       string       `json:\"name\"`\n\t\tUserDetail *UserDetail  `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScore `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\t// User.\n\t\t\tuser := User{\n\t\t\t\tName: fmt.Sprintf(`name_%d`, i),\n\t\t\t}\n\t\t\tlastInsertId, err := db.Model(tableUser).Data(user).OmitEmpty().InsertAndGetId()\n\t\t\tt.AssertNil(err)\n\t\t\t// Detail.\n\t\t\tuserDetail := UserDetail{\n\t\t\t\tUid:     int(lastInsertId),\n\t\t\t\tAddress: fmt.Sprintf(`address_%d`, lastInsertId),\n\t\t\t}\n\t\t\t_, err = db.Model(tableUserDetail).Data(userDetail).OmitEmpty().Insert()\n\t\t\tt.AssertNil(err)\n\t\t\t// Scores.\n\t\t\tfor j := 1; j <= 5; j++ {\n\t\t\t\tuserScore := UserScore{\n\t\t\t\t\tUid:   int(lastInsertId),\n\t\t\t\t\tScore: j,\n\t\t\t\t}\n\t\t\t\t_, err = db.Model(tableUserScores).Data(userScore).OmitEmpty().Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Scan pointer.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", 3).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\t// Scan struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserDetail).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserDetail).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 0)\n\t})\n\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(user.UserScores).\n\t\t\tWhere(\"id\", 4).\n\t\t\tScan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.Assert(user.UserDetail, nil)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_rel_user\"\n\t\ttableUserDetail = \"with_rel_user_detail\"\n\t\ttableUserScores = \"with_rel_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_rel_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n\n\t// With part attribute: UserDetail.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserDetail).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 0)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 0)\n\t})\n\n\t// With part attribute: UserScores.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).\n\t\t\tWith(User{}.UserScores).\n\t\t\tWhere(\"id\", []int{3, 4}).\n\t\t\tScan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.Assert(users[1].UserDetail, nil)\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_user\"\n\t\ttableUserDetail = \"withall_user_detail\"\n\t\ttableUserScores = \"withall_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_list_user\"\n\t\ttableUserDetail = \"withall_list_user_detail\"\n\t\ttableUserScores = \"withall_list_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_list_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.AssertNE(users[0].UserDetail, nil)\n\t\tt.Assert(users[0].UserDetail.Uid, 3)\n\t\tt.Assert(users[0].UserDetail.Address, \"address_3\")\n\t\tt.Assert(len(users[0].UserScores), 5)\n\t\tt.Assert(users[0].UserScores[0].Uid, 3)\n\t\tt.Assert(users[0].UserScores[0].Score, 1)\n\t\tt.Assert(users[0].UserScores[4].Uid, 3)\n\t\tt.Assert(users[0].UserScores[4].Score, 5)\n\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 5)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 1)\n\t\tt.Assert(users[1].UserScores[4].Uid, 4)\n\t\tt.Assert(users[1].UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAllCondition_List(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_cond_user\"\n\t\ttableUserDetail = \"withall_cond_user_detail\"\n\t\ttableUserScores = \"withall_cond_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:withall_cond_user\"`\n\t\tId         int           `json:\"id\"`\n\t\tName       string        `json:\"name\"`\n\t\tUserDetail *UserDetail   `orm:\"with:uid=id, where:uid > 3\"`\n\t\tUserScores []*UserScores `orm:\"with:uid=id, where:score>1 and score<5, order:score desc\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []*User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", []int{3, 4}).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 3)\n\t\tt.Assert(users[0].Name, \"name_3\")\n\t\tt.Assert(users[0].UserDetail, nil)\n\t\tt.Assert(users[1].Id, 4)\n\t\tt.Assert(users[1].Name, \"name_4\")\n\t\tt.AssertNE(users[1].UserDetail, nil)\n\t\tt.Assert(users[1].UserDetail.Uid, 4)\n\t\tt.Assert(users[1].UserDetail.Address, \"address_4\")\n\t\tt.Assert(len(users[1].UserScores), 3)\n\t\tt.Assert(users[1].UserScores[0].Uid, 4)\n\t\tt.Assert(users[1].UserScores[0].Score, 4)\n\t\tt.Assert(users[1].UserScores[2].Uid, 4)\n\t\tt.Assert(users[1].UserScores[2].Score, 2)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_With_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_emsm_user\"\n\t\ttableUserDetail = \"withall_emsm_user_detail\"\n\t\ttableUserScores = \"withall_emsm_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_emsm_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_emsm_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_emsm_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Without_SelfMaintained_Attributes(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_emns_user\"\n\t\ttableUserDetail = \"withall_emns_user_detail\"\n\t\ttableUserScores = \"withall_emns_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_emns_user_detail\"`\n\t\tUid        int    `json:\"uid\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_emns_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tId   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_emns_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tUserEmbedded\n\t\tUserScores []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_WithoutMeta(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_nometa_user\"\n\t\ttableUserDetail = \"user_detail\"\n\t\ttableUserScores = \"user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetailBase struct {\n\t\tUid     int    `json:\"uid\"`\n\t\tAddress string `json:\"address\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tUserDetailBase\n\t}\n\n\ttype UserScores struct {\n\t\tId    int `json:\"id\"`\n\t\tUid   int `json:\"uid\"`\n\t\tScore int `json:\"score\"`\n\t}\n\n\ttype User struct {\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int           `json:\"id\"`\n\t\tName        string        `json:\"name\"`\n\t\tUserScores  []*UserScores `orm:\"with:uid=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_AttributeStructAlsoHasWithTag(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"withall_nested_user\"\n\t\ttableUserDetail = \"withall_nested_user_detail\"\n\t\ttableUserScores = \"withall_nested_user_scores\"\n\t)\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user.sql\"), tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_detail.sql\"), tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(gtest.DataContent(\"with_tpl_user_scores.sql\"), tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:withall_nested_user_scores\"`\n\t\tId         int `json:\"id\"`\n\t\tUid        int `json:\"uid\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:withall_nested_user_detail\"`\n\t\tUid        int           `json:\"uid\"`\n\t\tAddress    string        `json:\"address\"`\n\t\tUserScores []*UserScores `orm:\"with:uid\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta  `orm:\"table:withall_nested_user\"`\n\t\t*UserDetail `orm:\"with:uid=id\"`\n\t\tId          int    `json:\"id\"`\n\t\tName        string `json:\"name\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"uid\":     i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"uid\":   i,\n\t\t\t\t\"score\": j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 3)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 3)\n\t\tt.Assert(user.UserDetail.Address, `address_3`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 3)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.Uid, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserDetail.UserScores), 5)\n\t\tt.Assert(user.UserDetail.UserScores[0].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserDetail.UserScores[4].Uid, 4)\n\t\tt.Assert(user.UserDetail.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends1(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int     `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     *TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int     `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     *TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends2(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int       `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\tTableC     []*TableC `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int       `orm:\"id,primary\" json:\"id\"`\n\t\tTableB     []*TableB `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.Assert(len(tableA.TableB), 2)\n\t\tt.Assert(tableA.TableB[0].Id, 10)\n\t\tt.Assert(tableA.TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA.TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA.TableB[1].TableC), 1)\n\t\tt.Assert(tableA.TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA.TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA.TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA.TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA.TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA.TableB[1].TableC[0].TableBId, 30)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\n\t\tt.Assert(len(tableA[0].TableB), 2)\n\t\tt.Assert(tableA[0].TableB[0].Id, 10)\n\t\tt.Assert(tableA[0].TableB[1].Id, 30)\n\n\t\tt.Assert(len(tableA[0].TableB[0].TableC), 2)\n\t\tt.Assert(len(tableA[0].TableB[1].TableC), 1)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].Id, 100)\n\t\tt.Assert(tableA[0].TableB[0].TableC[0].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].Id, 200)\n\t\tt.Assert(tableA[0].TableB[0].TableC[1].TableBId, 10)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].Id, 400)\n\t\tt.Assert(tableA[0].TableB[1].TableC[0].TableBId, 30)\n\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].Id, 300)\n\t\tt.Assert(tableA[1].TableB[0].TableC[0].TableBId, 20)\n\n\t\tt.Assert(tableA[1].TableB[1].Id, 40)\n\t\tt.Assert(tableA[1].TableB[1].TableAId, 2)\n\t\tt.Assert(tableA[1].TableB[1].TableC, nil)\n\t})\n}\n\nfunc Test_Table_Relation_With_MultipleDepends_Embedded(t *testing.T) {\n\tdefer func() {\n\t\tdropTable(\"table_a\")\n\t\tdropTable(\"table_b\")\n\t\tdropTable(\"table_c\")\n\t}()\n\tfor _, v := range gstr.SplitAndTrim(gfile.GetContents(gtest.DataPath(\"with_multiple_depends.sql\")), \";\") {\n\t\tif _, err := db.Exec(ctx, v); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t}\n\n\ttype TableC struct {\n\t\tgmeta.Meta `orm:\"table_c\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableBId   int `orm:\"table_b_id\" json:\"table_b_id\"`\n\t}\n\n\ttype TableB struct {\n\t\tgmeta.Meta `orm:\"table_b\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\tTableAId   int `orm:\"table_a_id\" json:\"table_a_id\"`\n\t\t*TableC    `orm:\"with:table_b_id=id\"  json:\"table_c\"`\n\t}\n\n\ttype TableA struct {\n\t\tgmeta.Meta `orm:\"table_a\"`\n\t\tId         int `orm:\"id,primary\" json:\"id\"`\n\t\t*TableB    `orm:\"with:table_a_id=id\" json:\"table_b\"`\n\t}\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\t// Struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA *TableA\n\t\terr := db.Model(\"table_a\").WithAll().Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(tableA, nil)\n\t\tt.Assert(tableA.Id, 1)\n\n\t\tt.AssertNE(tableA.TableB, nil)\n\t\tt.AssertNE(tableA.TableB.TableC, nil)\n\t\tt.Assert(tableA.TableB.TableAId, 1)\n\t\tt.Assert(tableA.TableB.TableC.Id, 100)\n\t\tt.Assert(tableA.TableB.TableC.TableBId, 10)\n\t})\n\n\t// Structs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar tableA []*TableA\n\t\terr := db.Model(\"table_a\").WithAll().OrderAsc(\"id\").Scan(&tableA)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tableA), 2)\n\t\tt.AssertNE(tableA[0].TableB, nil)\n\t\tt.AssertNE(tableA[1].TableB, nil)\n\t\tt.AssertNE(tableA[0].TableB.TableC, nil)\n\t\tt.AssertNE(tableA[1].TableB.TableC, nil)\n\n\t\tt.Assert(tableA[0].Id, 1)\n\t\tt.Assert(tableA[0].TableB.Id, 10)\n\t\tt.Assert(tableA[0].TableB.TableC.Id, 100)\n\n\t\tt.Assert(tableA[1].Id, 2)\n\t\tt.Assert(tableA[1].TableB.Id, 20)\n\t\tt.Assert(tableA[1].TableB.TableC.Id, 300)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Embedded_Meta_NameMatchingRule(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_embed_user\"\n\t\ttableUserDetail = \"with_embed_user_detail\"\n\t\ttableUserScores = \"with_embed_user_scores\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\tdropTable(tableUserScores)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nuser_id integer NOT NULL,\nscore integer NOT NULL\n);\n `, tableUserScores)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserScores)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user_detail\"`\n\t\tUserID     int    `json:\"user_id\"`\n\t\tAddress    string `json:\"address\"`\n\t}\n\n\ttype UserScores struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user_scores\"`\n\t\tID         int `json:\"id\"`\n\t\tUserID     int `json:\"user_id\"`\n\t\tScore      int `json:\"score\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_embed_user\"`\n\t\tUserEmbedded\n\t\tUserDetail UserDetail    `orm:\"with:user_id=id\"`\n\t\tUserScores []*UserScores `orm:\"with:user_id=id\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Scores.\n\t\tfor j := 1; j <= 5; j++ {\n\t\t\t_, err = db.Insert(ctx, tableUserScores, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t\t\"score\":   j,\n\t\t\t})\n\t\t\tgtest.AssertNil(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.ID, 4)\n\t\tt.AssertNE(user.UserDetail, nil)\n\t\tt.Assert(user.UserDetail.UserID, 4)\n\t\tt.Assert(user.UserDetail.Address, `address_4`)\n\t\tt.Assert(len(user.UserScores), 5)\n\t\tt.Assert(user.UserScores[0].UserID, 4)\n\t\tt.Assert(user.UserScores[0].Score, 1)\n\t\tt.Assert(user.UserScores[4].UserID, 4)\n\t\tt.Assert(user.UserScores[4].Score, 5)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Unscoped(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_unscoped_user\"\n\t\ttableUserDetail = \"with_unscoped_user_detail\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL,\ndeleted_at timestamp default NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user_detail\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_unscoped_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n\nfunc Test_Table_Relation_WithAll_Order(t *testing.T) {\n\tvar (\n\t\ttableUser       = \"with_order_user\"\n\t\ttableUserDetail = \"with_order_user_detail\"\n\t)\n\t// Drop tables first to ensure clean state\n\tdropTable(tableUser)\n\tdropTable(tableUserDetail)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nid SERIAL PRIMARY KEY,\nname varchar(45) NOT NULL\n);\n `, tableUser)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\nCREATE TABLE %s (\nuser_id SERIAL PRIMARY KEY,\naddress varchar(45) NOT NULL,\ndeleted_at timestamp default NULL\n);\n `, tableUserDetail)); err != nil {\n\t\tgtest.Error(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\ttype UserDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user_detail\"`\n\t\tUserID     int         `json:\"user_id\"`\n\t\tAddress    string      `json:\"address\"`\n\t\tDeletedAt  *gtime.Time `json:\"deleted_at\"`\n\t}\n\n\t// For Test Only\n\ttype UserEmbedded struct {\n\t\tID   int    `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t}\n\n\ttype User struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id\"`\n\t}\n\ttype UserWithDeletedDetail struct {\n\t\tgmeta.Meta `orm:\"table:with_order_user\"`\n\t\tUserEmbedded\n\t\tUserDetail *UserDetail `orm:\"with:user_id=id, order:user_id asc,address desc, unscoped:true\"`\n\t}\n\n\t// Initialize the data.\n\tvar err error\n\tfor i := 1; i <= 5; i++ {\n\t\t// User.\n\t\t_, err = db.Insert(ctx, tableUser, g.Map{\n\t\t\t\"id\":   i,\n\t\t\t\"name\": fmt.Sprintf(`name_%d`, i),\n\t\t})\n\t\tgtest.AssertNil(err)\n\t\t// Detail.\n\t\t_, err = db.Insert(ctx, tableUserDetail, g.Map{\n\t\t\t\"user_id\": i,\n\t\t\t\"address\": fmt.Sprintf(`address_%d`, i),\n\t\t})\n\t\t// Delete detail where i = 3\n\t\tif i == 3 {\n\t\t\t_, err = db.Delete(ctx, tableUserDetail, g.Map{\n\t\t\t\t\"user_id\": i,\n\t\t\t})\n\t\t}\n\t\tgtest.AssertNil(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user0 User\n\t\terr := db.Model(tableUser).WithAll().Where(\"id\", 4).Scan(&user0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user0.ID, 4)\n\t\tt.AssertNE(user0.UserDetail, nil)\n\t\tt.AssertNil(user0.UserDetail.DeletedAt)\n\t\tt.Assert(user0.UserDetail.UserID, 4)\n\t\tt.Assert(user0.UserDetail.Address, `address_4`)\n\n\t\tvar user1 User\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user1.ID, 3)\n\t\tt.AssertNil(user1.UserDetail)\n\n\t\tvar user2 UserWithDeletedDetail\n\t\terr = db.Model(tableUser).WithAll().Where(\"id\", 3).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.ID, 3)\n\t\tt.AssertNE(user2.UserDetail, nil)\n\t\tt.AssertNE(user2.UserDetail.DeletedAt, nil)\n\t\tt.Assert(user2.UserDetail.UserID, 3)\n\t\tt.Assert(user2.UserDetail.Address, `address_3`)\n\n\t\t// Unscoped outside test\n\t\tvar user3 User\n\t\terr = db.Model(tableUser).Unscoped().WithAll().Where(\"id\", 3).Scan(&user3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user3.ID, 3)\n\t\tt.AssertNil(user3.UserDetail)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_field_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_TableFields tests the TableFields method for retrieving table field information\nfunc Test_TableFields(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields) > 0, true)\n\n\t\t// Test primary key field\n\t\tt.Assert(fields[\"id\"].Name, \"id\")\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\n\t\t// Test integer types\n\t\tt.Assert(fields[\"col_int2\"].Name, \"col_int2\")\n\t\tt.Assert(fields[\"col_int4\"].Name, \"col_int4\")\n\t\tt.Assert(fields[\"col_int8\"].Name, \"col_int8\")\n\n\t\t// Test float types\n\t\tt.Assert(fields[\"col_float4\"].Name, \"col_float4\")\n\t\tt.Assert(fields[\"col_float8\"].Name, \"col_float8\")\n\t\tt.Assert(fields[\"col_numeric\"].Name, \"col_numeric\")\n\n\t\t// Test character types\n\t\tt.Assert(fields[\"col_char\"].Name, \"col_char\")\n\t\tt.Assert(fields[\"col_varchar\"].Name, \"col_varchar\")\n\t\tt.Assert(fields[\"col_text\"].Name, \"col_text\")\n\n\t\t// Test boolean type\n\t\tt.Assert(fields[\"col_bool\"].Name, \"col_bool\")\n\n\t\t// Test date/time types\n\t\tt.Assert(fields[\"col_date\"].Name, \"col_date\")\n\t\tt.Assert(fields[\"col_timestamp\"].Name, \"col_timestamp\")\n\n\t\t// Test JSON types\n\t\tt.Assert(fields[\"col_json\"].Name, \"col_json\")\n\t\tt.Assert(fields[\"col_jsonb\"].Name, \"col_jsonb\")\n\n\t\t// Test array types\n\t\tt.Assert(fields[\"col_int2_arr\"].Name, \"col_int2_arr\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Name, \"col_int4_arr\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Name, \"col_varchar_arr\")\n\t})\n}\n\n// Test_TableFields_Types tests field type information\nfunc Test_TableFields_Types(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// Test integer type names\n\t\tt.Assert(fields[\"col_int2\"].Type, \"int2(16)\")\n\t\tt.Assert(fields[\"col_int4\"].Type, \"int4(32)\")\n\t\tt.Assert(fields[\"col_int8\"].Type, \"int8(64)\")\n\n\t\t// Test float type names\n\t\tt.Assert(fields[\"col_float4\"].Type, \"float4(24)\")\n\t\tt.Assert(fields[\"col_float8\"].Type, \"float8(53)\")\n\t\tt.Assert(fields[\"col_numeric\"].Type, \"numeric(10)\")\n\n\t\t// Test character type names\n\t\tt.Assert(fields[\"col_char\"].Type, \"bpchar(10)\")\n\t\tt.Assert(fields[\"col_varchar\"].Type, \"varchar(100)\")\n\t\tt.Assert(fields[\"col_text\"].Type, \"text\")\n\n\t\t// Test boolean type name\n\t\tt.Assert(fields[\"col_bool\"].Type, \"bool\")\n\n\t\t// Test date/time type names\n\t\tt.Assert(fields[\"col_date\"].Type, \"date\")\n\t\tt.Assert(fields[\"col_timestamp\"].Type, \"timestamp\")\n\t\tt.Assert(fields[\"col_timestamptz\"].Type, \"timestamptz\")\n\n\t\t// Test JSON type names\n\t\tt.Assert(fields[\"col_json\"].Type, \"json\")\n\t\tt.Assert(fields[\"col_jsonb\"].Type, \"jsonb\")\n\n\t\t// Test array type names (PostgreSQL uses _ prefix for array types)\n\t\tt.Assert(fields[\"col_int2_arr\"].Type, \"_int2\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Type, \"_int4\")\n\t\tt.Assert(fields[\"col_int8_arr\"].Type, \"_int8\")\n\t\tt.Assert(fields[\"col_float4_arr\"].Type, \"_float4\")\n\t\tt.Assert(fields[\"col_float8_arr\"].Type, \"_float8\")\n\t\tt.Assert(fields[\"col_numeric_arr\"].Type, \"_numeric\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Type, \"_varchar\")\n\t\tt.Assert(fields[\"col_text_arr\"].Type, \"_text\")\n\t\tt.Assert(fields[\"col_bool_arr\"].Type, \"_bool\")\n\t})\n}\n\n// Test_TableFields_Nullable tests field nullable information\nfunc Test_TableFields_Nullable(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// NOT NULL fields should have Null = false\n\t\tt.Assert(fields[\"col_int2\"].Null, false)\n\t\tt.Assert(fields[\"col_int4\"].Null, false)\n\t\tt.Assert(fields[\"col_numeric\"].Null, false)\n\t\tt.Assert(fields[\"col_varchar\"].Null, false)\n\t\tt.Assert(fields[\"col_bool\"].Null, false)\n\t\tt.Assert(fields[\"col_varchar_arr\"].Null, false)\n\n\t\t// Nullable fields should have Null = true\n\t\tt.Assert(fields[\"col_int8\"].Null, true)\n\t\tt.Assert(fields[\"col_text\"].Null, true)\n\t\tt.Assert(fields[\"col_json\"].Null, true)\n\t})\n}\n\n// Test_TableFields_Comments tests field comment information\nfunc Test_TableFields_Comments(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\t// Test fields with comments\n\t\tt.Assert(fields[\"id\"].Comment, \"Primary key ID\")\n\t\tt.Assert(fields[\"col_int2\"].Comment, \"int2 type (smallint)\")\n\t\tt.Assert(fields[\"col_int4\"].Comment, \"int4 type (integer)\")\n\t\tt.Assert(fields[\"col_int8\"].Comment, \"int8 type (bigint)\")\n\t\tt.Assert(fields[\"col_numeric\"].Comment, \"numeric type with precision\")\n\t\tt.Assert(fields[\"col_varchar\"].Comment, \"varchar type\")\n\t\tt.Assert(fields[\"col_bool\"].Comment, \"boolean type\")\n\t\tt.Assert(fields[\"col_timestamp\"].Comment, \"timestamp type\")\n\t\tt.Assert(fields[\"col_json\"].Comment, \"json type\")\n\t\tt.Assert(fields[\"col_jsonb\"].Comment, \"jsonb type\")\n\n\t\t// Test array field comments\n\t\tt.Assert(fields[\"col_int2_arr\"].Comment, \"int2 array type (_int2)\")\n\t\tt.Assert(fields[\"col_int4_arr\"].Comment, \"int4 array type (_int4)\")\n\t\tt.Assert(fields[\"col_int8_arr\"].Comment, \"int8 array type (_int8)\")\n\t\tt.Assert(fields[\"col_numeric_arr\"].Comment, \"numeric array type (_numeric)\")\n\t\tt.Assert(fields[\"col_varchar_arr\"].Comment, \"varchar array type (_varchar)\")\n\t\tt.Assert(fields[\"col_text_arr\"].Comment, \"text array type (_text)\")\n\t})\n}\n\n// Test_Field_Type_Conversion tests type conversion for various PostgreSQL types\nfunc Test_Field_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test integer type conversions\n\t\tt.Assert(one[\"col_int2\"].Int(), 1)\n\t\tt.Assert(one[\"col_int4\"].Int(), 10)\n\t\tt.Assert(one[\"col_int8\"].Int64(), int64(100))\n\n\t\t// Test float type conversions\n\t\tt.Assert(one[\"col_float4\"].Float32() > 0, true)\n\t\tt.Assert(one[\"col_float8\"].Float64() > 0, true)\n\n\t\t// Test string type conversions\n\t\tt.AssertNE(one[\"col_varchar\"].String(), \"\")\n\t\tt.AssertNE(one[\"col_text\"].String(), \"\")\n\n\t\t// Test boolean type conversion\n\t\tt.Assert(one[\"col_bool\"].Bool(), false) // i=1, 1%2==0 is false\n\t})\n}\n\n// Test_Field_Array_Type_Conversion tests array type conversion\nfunc Test_Field_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test integer array type conversions\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 1)\n\t\tt.Assert(int2Arr[1], 2)\n\t\tt.Assert(int2Arr[2], 1)\n\n\t\tint4Arr := one[\"col_int4_arr\"].Ints()\n\t\tt.Assert(len(int4Arr), 3)\n\t\tt.Assert(int4Arr[0], 10)\n\t\tt.Assert(int4Arr[1], 20)\n\t\tt.Assert(int4Arr[2], 1)\n\n\t\tint8Arr := one[\"col_int8_arr\"].Int64s()\n\t\tt.Assert(len(int8Arr), 3)\n\t\tt.Assert(int8Arr[0], int64(100))\n\t\tt.Assert(int8Arr[1], int64(200))\n\t\tt.Assert(int8Arr[2], int64(1))\n\n\t\t// Test string array type conversions\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"a\")\n\t\tt.Assert(varcharArr[1], \"b\")\n\t\tt.Assert(varcharArr[2], \"c1\")\n\n\t\ttextArr := one[\"col_text_arr\"].Strings()\n\t\tt.Assert(len(textArr), 3)\n\t\tt.Assert(textArr[0], \"x\")\n\t\tt.Assert(textArr[1], \"y\")\n\t\tt.Assert(textArr[2], \"z1\")\n\n\t\t// Test boolean array type conversions\n\t\t// col_bool_arr is '{true, false, %t}' where %t = i%2==0, for i=1 it's false\n\t\tboolArr := one[\"col_bool_arr\"].Bools()\n\t\tt.Assert(len(boolArr), 3)\n\t\tt.Assert(boolArr[0], true)  // literal true\n\t\tt.Assert(boolArr[1], false) // literal false\n\t\tt.Assert(boolArr[2], false) // i=1, 1%2==0 is false\n\t})\n}\n\n// Test_Field_Array_Insert tests inserting array data\nfunc Test_Field_Array_Insert(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_int2_arr\":    []int{1, 2, 3},\n\t\t\t\"col_int4_arr\":    []int{10, 20, 30},\n\t\t\t\"col_varchar_arr\": []string{\"a\", \"b\", \"c\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(one[\"col_int2\"].Int(), 1)\n\t\tt.Assert(one[\"col_varchar\"].String(), \"test\")\n\t\tt.Assert(one[\"col_bool\"].Bool(), true)\n\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 1)\n\t\tt.Assert(int2Arr[1], 2)\n\t\tt.Assert(int2Arr[2], 3)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"a\")\n\t\tt.Assert(varcharArr[1], \"b\")\n\t\tt.Assert(varcharArr[2], \"c\")\n\t})\n}\n\n// Test_Field_Array_Update tests updating array data\nfunc Test_Field_Array_Update(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Update array values\n\t\t_, err := db.Model(table).Where(\"id\", 1).Data(g.Map{\n\t\t\t\"col_int2_arr\":    []int{100, 200, 300},\n\t\t\t\"col_varchar_arr\": []string{\"x\", \"y\", \"z\"},\n\t\t}).Update()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 3)\n\t\tt.Assert(int2Arr[0], 100)\n\t\tt.Assert(int2Arr[1], 200)\n\t\tt.Assert(int2Arr[2], 300)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 3)\n\t\tt.Assert(varcharArr[0], \"x\")\n\t\tt.Assert(varcharArr[1], \"y\")\n\t\tt.Assert(varcharArr[2], \"z\")\n\t})\n}\n\n// Test_Field_JSON_Type tests JSON/JSONB type handling\nfunc Test_Field_JSON_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with JSON values\n\t\ttestData := g.Map{\n\t\t\t\"name\":  \"test\",\n\t\t\t\"value\": 123,\n\t\t\t\"items\": []string{\"a\", \"b\", \"c\"},\n\t\t}\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":    1,\n\t\t\t\"col_int4\":    10,\n\t\t\t\"col_numeric\": 99.99,\n\t\t\t\"col_varchar\": \"test\",\n\t\t\t\"col_bool\":    true,\n\t\t\t\"col_json\":    testData,\n\t\t\t\"col_jsonb\":   testData,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test JSON field\n\t\tjsonMap := one[\"col_json\"].Map()\n\t\tt.Assert(jsonMap[\"name\"], \"test\")\n\t\tt.Assert(jsonMap[\"value\"], 123)\n\n\t\t// Test JSONB field\n\t\tjsonbMap := one[\"col_jsonb\"].Map()\n\t\tt.Assert(jsonbMap[\"name\"], \"test\")\n\t\tt.Assert(jsonbMap[\"value\"], 123)\n\t})\n}\n\n// Test_Field_Scan_To_Struct tests scanning results to struct\nfunc Test_Field_Scan_To_Struct(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\ttype TestRecord struct {\n\t\tId         int64    `json:\"id\"`\n\t\tColInt2    int16    `json:\"col_int2\"`\n\t\tColInt4    int32    `json:\"col_int4\"`\n\t\tColInt8    int64    `json:\"col_int8\"`\n\t\tColVarchar string   `json:\"col_varchar\"`\n\t\tColBool    bool     `json:\"col_bool\"`\n\t\tColInt2Arr []int    `json:\"col_int2_arr\"`\n\t\tColInt4Arr []int    `json:\"col_int4_arr\"`\n\t\tColInt8Arr []int64  `json:\"col_int8_arr\"`\n\t\tColTextArr []string `json:\"col_text_arr\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar record TestRecord\n\t\terr := db.Model(table).Where(\"id\", 1).Scan(&record)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(record.Id, int64(1))\n\t\tt.Assert(record.ColInt2, int16(1))\n\t\tt.Assert(record.ColInt4, int32(10))\n\t\tt.Assert(record.ColInt8, int64(100))\n\t\tt.AssertNE(record.ColVarchar, \"\")\n\t\tt.Assert(record.ColBool, false)\n\n\t\t// Test array fields scanned to struct\n\t\tt.Assert(len(record.ColInt2Arr), 3)\n\t\tt.Assert(record.ColInt2Arr[0], 1)\n\t\tt.Assert(record.ColInt2Arr[1], 2)\n\t\tt.Assert(record.ColInt2Arr[2], 1)\n\n\t\tt.Assert(len(record.ColTextArr), 3)\n\t\tt.Assert(record.ColTextArr[0], \"x\")\n\t\tt.Assert(record.ColTextArr[1], \"y\")\n\t\tt.Assert(record.ColTextArr[2], \"z1\")\n\t})\n}\n\n// Test_Field_Scan_To_Struct_Slice tests scanning multiple results to struct slice\nfunc Test_Field_Scan_To_Struct_Slice(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\ttype TestRecord struct {\n\t\tId         int64    `json:\"id\"`\n\t\tColInt2    int16    `json:\"col_int2\"`\n\t\tColVarchar string   `json:\"col_varchar\"`\n\t\tColInt2Arr []int    `json:\"col_int2_arr\"`\n\t\tColTextArr []string `json:\"col_text_arr\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar records []TestRecord\n\t\terr := db.Model(table).OrderAsc(\"id\").Limit(5).Scan(&records)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(records), 5)\n\n\t\t// Verify first record\n\t\tt.Assert(records[0].Id, int64(1))\n\t\tt.Assert(records[0].ColInt2, int16(1))\n\t\tt.Assert(len(records[0].ColInt2Arr), 3)\n\n\t\t// Verify last record\n\t\tt.Assert(records[4].Id, int64(5))\n\t\tt.Assert(records[4].ColInt2, int16(5))\n\t})\n}\n\n// Test_Field_Empty_Array tests handling empty arrays\nfunc Test_Field_Empty_Array(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with empty array values (using default)\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":    1,\n\t\t\t\"col_int4\":    10,\n\t\t\t\"col_numeric\": 99.99,\n\t\t\t\"col_varchar\": \"test\",\n\t\t\t\"col_bool\":    true,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify empty arrays\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Default empty arrays\n\t\tint2Arr := one[\"col_int2_arr\"].Ints()\n\t\tt.Assert(len(int2Arr), 0)\n\n\t\tvarcharArr := one[\"col_varchar_arr\"].Strings()\n\t\tt.Assert(len(varcharArr), 0)\n\t})\n}\n\n// Test_Field_Null_Values tests handling NULL values\nfunc Test_Field_Null_Values(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert minimal required fields, leaving nullable fields as NULL\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL handling\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Nullable fields should return appropriate zero values\n\t\tt.Assert(one[\"col_text\"].IsNil() || one[\"col_text\"].IsEmpty(), true)\n\t\tt.Assert(one[\"col_int8_arr\"].IsNil() || one[\"col_int8_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_Float_Array_Type_Conversion tests float array type conversion (_float4, _float8)\nfunc Test_Field_Float_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test float4 array type conversions\n\t\tfloat4Arr := one[\"col_float4_arr\"].Float32s()\n\t\tt.Assert(len(float4Arr), 3)\n\t\tt.Assert(float4Arr[0] > 0, true)\n\t\tt.Assert(float4Arr[1] > 0, true)\n\n\t\t// Test float8 array type conversions\n\t\tfloat8Arr := one[\"col_float8_arr\"].Float64s()\n\t\tt.Assert(len(float8Arr), 3)\n\t\tt.Assert(float8Arr[0] > 0, true)\n\t\tt.Assert(float8Arr[1] > 0, true)\n\t})\n}\n\n// Test_Field_Numeric_Array_Type_Conversion tests numeric/decimal array type conversion\nfunc Test_Field_Numeric_Array_Type_Conversion(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query a single record\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\n\t\t// Test numeric array type conversions\n\t\tnumericArr := one[\"col_numeric_arr\"].Float64s()\n\t\tt.Assert(len(numericArr), 3)\n\t\tt.Assert(numericArr[0] > 0, true)\n\t\tt.Assert(numericArr[1] > 0, true)\n\n\t\t// Test decimal array type conversions\n\t\tdecimalArr := one[\"col_decimal_arr\"].Float64s()\n\t\tif !one[\"col_decimal_arr\"].IsNil() {\n\t\t\tt.Assert(len(decimalArr) > 0, true)\n\t\t}\n\t})\n}\n\n// Test_Field_Bool_Array_Type_Conversion tests bool array type conversion more thoroughly\nfunc Test_Field_Bool_Array_Type_Conversion(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with specific bool array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":     1,\n\t\t\t\"col_int4\":     10,\n\t\t\t\"col_numeric\":  99.99,\n\t\t\t\"col_varchar\":  \"test\",\n\t\t\t\"col_bool\":     true,\n\t\t\t\"col_bool_arr\": []bool{true, false, true},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bool array\n\t\tboolArr := one[\"col_bool_arr\"].Bools()\n\t\tt.Assert(len(boolArr), 3)\n\t\tt.Assert(boolArr[0], true)\n\t\tt.Assert(boolArr[1], false)\n\t\tt.Assert(boolArr[2], true)\n\t})\n}\n\n// Test_Field_Char_Array_Type tests char array type (_char)\nfunc Test_Field_Char_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with char array values\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_char_arr\":    []string{\"a\", \"b\", \"c\"},\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test char array\n\t\tcharArr := one[\"col_char_arr\"].Strings()\n\t\tt.Assert(len(charArr), 3)\n\t})\n}\n\n// Test_Field_Bytea_Type tests bytea (binary) type conversion\nfunc Test_Field_Bytea_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with binary data\n\t\tbinaryData := []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f} // \"Hello\" in hex\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_bytea\":       binaryData,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea field\n\t\tresult := one[\"col_bytea\"].Bytes()\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0], 0x48) // 'H'\n\t})\n}\n\n// Test_Field_Bytea_Array_Type tests bytea array type (_bytea)\nfunc Test_Field_Bytea_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with bytea array values using raw SQL\n\t\t// PostgreSQL bytea array literal format: ARRAY[E'\\\\x010203', E'\\\\x040506']::bytea[]\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\t\tINSERT INTO %s (col_int2, col_int4, col_numeric, col_varchar, col_bool, col_varchar_arr, col_bytea_arr)\n\t\t\tVALUES (1, 10, 99.99, 'test', true, '{}', ARRAY[E'\\\\x010203', E'\\\\x040506']::bytea[])\n\t\t`, table))\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify bytea array\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea array field - should be converted to [][]byte\n\t\tbyteaArrVal := one[\"col_bytea_arr\"]\n\t\tt.Assert(byteaArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\tbyteaArr := byteaArrVal.Interfaces()\n\t\tt.Assert(len(byteaArr), 2)\n\t})\n}\n\n// Test_Field_Date_Array_Type tests date array type (_date)\nfunc Test_Field_Date_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _date array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL date array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// date array should be nil or empty\n\t\tt.Assert(one[\"col_date_arr\"].IsNil() || one[\"col_date_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_Timestamp_Array_Type tests timestamp array type (_timestamp)\nfunc Test_Field_Timestamp_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _timestamp array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL timestamp array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// timestamp array should be nil or empty\n\t\tt.Assert(one[\"col_timestamp_arr\"].IsNil() || one[\"col_timestamp_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_JSONB_Array_Type tests JSONB array type (_jsonb)\nfunc Test_Field_JSONB_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Note: PostgreSQL _jsonb array is not yet mapped in the driver\n\t\t// This test documents the limitation but can be extended when support is added\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"col_int2\":        1,\n\t\t\t\"col_int4\":        10,\n\t\t\t\"col_numeric\":     99.99,\n\t\t\t\"col_varchar\":     \"test\",\n\t\t\t\"col_bool\":        true,\n\t\t\t\"col_varchar_arr\": []string{},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify NULL jsonb array is handled gracefully\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\t\t// jsonb array should be nil or empty\n\t\tt.Assert(one[\"col_jsonb_arr\"].IsNil() || one[\"col_jsonb_arr\"].IsEmpty(), true)\n\t})\n}\n\n// Test_Field_UUID_Array_Type tests UUID array type (_uuid)\nfunc Test_Field_UUID_Array_Type(t *testing.T) {\n\ttable := createAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with UUID array values using raw SQL\n\t\t// PostgreSQL uuid array literal format: ARRAY['uuid1', 'uuid2']::uuid[]\n\t\tuuid1 := \"550e8400-e29b-41d4-a716-446655440000\"\n\t\tuuid2 := \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\"\n\t\tuuid3 := \"6ba7b811-9dad-11d1-80b4-00c04fd430c8\"\n\t\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\t\t\tINSERT INTO %s (col_int2, col_int4, col_numeric, col_varchar, col_bool, col_varchar_arr, col_uuid_arr)\n\t\t\tVALUES (1, 10, 99.99, 'test', true, '{}', ARRAY['%s', '%s', '%s']::uuid[])\n\t\t`, table, uuid1, uuid2, uuid3))\n\t\tt.AssertNil(err)\n\n\t\t// Query and verify UUID array\n\t\tone, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test UUID array field - should be converted to []uuid.UUID\n\t\tuuidArrVal := one[\"col_uuid_arr\"]\n\t\tt.Assert(uuidArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data as []uuid.UUID\n\t\tuuidArr := uuidArrVal.Interfaces()\n\t\tt.Assert(len(uuidArr), 3)\n\n\t\t// Verify each element is uuid.UUID type\n\t\tu1, ok := uuidArr[0].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u1.String(), uuid1)\n\n\t\tu2, ok := uuidArr[1].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u2.String(), uuid2)\n\n\t\tu3, ok := uuidArr[2].(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(u3.String(), uuid3)\n\t})\n}\n\n// Test_Field_UUID_Type tests UUID type\nfunc Test_Field_UUID_Type(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify UUID field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test UUID field - should be converted to uuid.UUID\n\t\tuuidVal := one[\"col_uuid\"]\n\t\tt.Assert(uuidVal.IsNil(), false)\n\n\t\t// Verify the value is uuid.UUID type\n\t\tuuidObj, ok := uuidVal.Val().(uuid.UUID)\n\t\tt.Assert(ok, true)\n\n\t\t// Verify the UUID format\n\t\tuuidStr := uuidObj.String()\n\t\tt.Assert(len(uuidStr) > 0, true)\n\t\t// UUID should contain the pattern from insert: 550e8400-e29b-41d4-a716-44665544000X\n\t\tt.Assert(uuidStr, \"550e8400-e29b-41d4-a716-446655440001\")\n\n\t\t// Also verify we can still get string representation via .String()\n\t\tt.Assert(uuidVal.String(), \"550e8400-e29b-41d4-a716-446655440001\")\n\t})\n}\n\n// Test_Field_Bytea_Array_Type_Scan tests bytea array type and scanning\nfunc Test_Field_Bytea_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify bytea array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test bytea array field\n\t\tbyteaArrVal := one[\"col_bytea_arr\"]\n\t\t// bytea array should not be nil since we inserted data\n\t\tt.Assert(byteaArrVal.IsNil(), false)\n\t})\n}\n\n// Test_Field_Date_Array_Type_Scan tests date array type and scanning\nfunc Test_Field_Date_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify date array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test date array field\n\t\tdateArrVal := one[\"col_date_arr\"]\n\t\tt.Assert(dateArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\tdateArr := dateArrVal.Strings()\n\t\tt.Assert(len(dateArr) > 0, true)\n\t})\n}\n\n// Test_Field_Timestamp_Array_Type_Scan tests timestamp array type and scanning\nfunc Test_Field_Timestamp_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify timestamp array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test timestamp array field\n\t\ttimestampArrVal := one[\"col_timestamp_arr\"]\n\t\tt.Assert(timestampArrVal.IsNil(), false)\n\n\t\t// Verify the array contains the expected data\n\t\ttimestampArr := timestampArrVal.Strings()\n\t\tt.Assert(len(timestampArr) > 0, true)\n\t})\n}\n\n// Test_Field_JSONB_Array_Type_Scan tests JSONB array type and scanning\nfunc Test_Field_JSONB_Array_Type_Scan(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Query and verify JSONB array field\n\t\tone, err := db.Model(table).OrderAsc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\t// Test JSONB array field\n\t\tjsonbArrVal := one[\"col_jsonb_arr\"]\n\t\tt.Assert(jsonbArrVal.IsNil(), false)\n\t})\n}\n\n// Test_Field_UUID_Query tests querying by UUID field\nfunc Test_Field_UUID_Query(t *testing.T) {\n\ttable := createInitAllTypesTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test 1: Query by UUID string\n\t\tuuidStr := \"550e8400-e29b-41d4-a716-446655440001\"\n\t\tone, err := db.Model(table).Where(\"col_uuid\", uuidStr).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\n\t\t// Verify the returned UUID is correct\n\t\tuuidObj, ok := one[\"col_uuid\"].Val().(uuid.UUID)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(uuidObj.String(), uuidStr)\n\n\t\t// Test 2: Query by uuid.UUID type directly\n\t\tuuidVal, err := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440002\")\n\t\tt.AssertNil(err)\n\t\tone, err = db.Model(table).Where(\"col_uuid\", uuidVal).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 2)\n\n\t\t// Test 3: Query by UUID string using g.Map\n\t\tone, err = db.Model(table).Where(g.Map{\n\t\t\t\"col_uuid\": \"550e8400-e29b-41d4-a716-446655440003\",\n\t\t}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\n\t\t// Test 4: Query by uuid.UUID type using g.Map\n\t\tuuidVal, err = uuid.Parse(\"550e8400-e29b-41d4-a716-446655440004\")\n\t\tt.AssertNil(err)\n\t\tone, err = db.Model(table).Where(g.Map{\n\t\t\t\"col_uuid\": uuidVal,\n\t\t}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"].Int(), 4)\n\n\t\t// Test 5: Query non-existent UUID\n\t\tone, err = db.Model(table).Where(\"col_uuid\", \"00000000-0000-0000-0000-000000000000\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), true)\n\n\t\t// Test 6: Query multiple records by UUID IN clause with strings\n\t\tall, err := db.Model(table).WhereIn(\"col_uuid\", g.Slice{\n\t\t\t\"550e8400-e29b-41d4-a716-446655440001\",\n\t\t\t\"550e8400-e29b-41d4-a716-446655440002\",\n\t\t}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 2)\n\n\t\t// Test 7: Query multiple records by UUID IN clause with uuid.UUID types\n\t\tuuid1, _ := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440003\")\n\t\tuuid2, _ := uuid.Parse(\"550e8400-e29b-41d4-a716-446655440004\")\n\t\tall, err = db.Model(table).WhereIn(\"col_uuid\", g.Slice{uuid1, uuid2}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 4)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_filter_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n)\n\n// Test_DoFilter_LimitOffset tests LIMIT OFFSET conversion\nfunc Test_DoFilter_LimitOffset(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test MySQL style LIMIT x,y to PostgreSQL style LIMIT y OFFSET x\n\t\tsql := \"SELECT * FROM users LIMIT 10, 20\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 20 OFFSET 10\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with different numbers\n\t\tsql := \"SELECT * FROM users LIMIT 0, 100\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 100 OFFSET 0\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test no conversion needed\n\t\tsql := \"SELECT * FROM users LIMIT 50\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users LIMIT 50\")\n\t})\n}\n\n// Test_DoFilter_InsertIgnore tests INSERT IGNORE conversion\nfunc Test_DoFilter_InsertIgnore(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test INSERT IGNORE conversion\n\t\tsql := \"INSERT IGNORE INTO users (name) VALUES ($1)\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"INSERT INTO users (name) VALUES ($1) ON CONFLICT DO NOTHING\")\n\t})\n}\n\n// Test_DoFilter_PlaceholderConversion tests placeholder conversion\nfunc Test_DoFilter_PlaceholderConversion(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test ? placeholder conversion to $n\n\t\tsql := \"SELECT * FROM users WHERE id = ? AND name = ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE id = $1 AND name = $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test multiple placeholders\n\t\tsql := \"INSERT INTO users (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"INSERT INTO users (a, b, c, d, e) VALUES ($1, $2, $3, $4, $5)\")\n\t})\n}\n\n// Test_DoFilter_JsonbOperator tests JSONB operator handling\nfunc Test_DoFilter_JsonbOperator(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ?| operator\n\t\t// The jsonb ? is first converted to $1, then restored to ?\n\t\t// So the next placeholder becomes $2\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb ?| ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\t// After placeholder conversion, the ? in jsonb should be preserved\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb ?| $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ?& operator\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb &? ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb &? $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test jsonb ? operator\n\t\tsql := \"SELECT * FROM users WHERE (data)::jsonb ? ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE (data)::jsonb ? $2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test combination of jsonb and regular placeholders\n\t\tsql := \"SELECT * FROM users WHERE id = ? AND (data)::jsonb ?| ?\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE id = $1 AND (data)::jsonb ?| $3\")\n\t})\n}\n\n// Test_DoFilter_ComplexQuery tests complex queries with multiple features\nfunc Test_DoFilter_ComplexQuery(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test complex query with LIMIT and placeholders\n\t\tsql := \"SELECT * FROM users WHERE status = ? AND age > ? LIMIT 5, 10\"\n\t\tnewSql, _, err := driver.DoFilter(ctx, nil, sql, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newSql, \"SELECT * FROM users WHERE status = $1 AND age > $2 LIMIT 10 OFFSET 5\")\n\t})\n}\n\n// Test_Tables tests the Tables method\nfunc Test_Tables_Method(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttables, err := db.Tables(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tables) >= 0, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with specific schema - use the test schema\n\t\ttables, err := db.Tables(ctx, \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(tables) >= 0, true)\n\t})\n}\n\n// Test_OrderRandomFunction tests the OrderRandomFunction method\nfunc Test_OrderRandomFunction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test ORDER BY RANDOM()\n\t\tall, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t})\n}\n\n// Test_GetChars tests the GetChars method\nfunc Test_GetChars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tleft, right := driver.GetChars()\n\t\tt.Assert(left, `\"`)\n\t\tt.Assert(right, `\"`)\n\t})\n}\n\n// Test_New tests the New method\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.New()\n\t\tt.AssertNE(driver, nil)\n\t})\n}\n\n// Test_DoExec_NonIntPrimaryKey tests DoExec with non-integer primary key\nfunc Test_DoExec_NonIntPrimaryKey(t *testing.T) {\n\t// Create a table with UUID primary key\n\ttableName := \"t_uuid_pk_test\"\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE IF NOT EXISTS `+tableName+` (\n\t\t\tid uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n\t\t\tname varchar(100)\n\t\t)\n\t`)\n\tif err != nil {\n\t\t// If gen_random_uuid is not available, skip this test\n\t\tt.Log(\"Skipping UUID test:\", err)\n\t\treturn\n\t}\n\tdefer db.Exec(ctx, \"DROP TABLE IF EXISTS \"+tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert with UUID primary key\n\t\tresult, err := db.Model(tableName).Data(g.Map{\n\t\t\t\"name\": \"test_user\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// LastInsertId should return error for non-integer primary key\n\t\t_, err = result.LastInsertId()\n\t\t// For UUID, LastInsertId is not supported\n\t\tt.AssertNE(err, nil)\n\n\t\t// RowsAffected should still work\n\t\taffected, err := result.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(affected, int64(1))\n\t})\n}\n\n// Test_TableFields_WithSchema tests TableFields with specific schema\nfunc Test_TableFields_WithSchema(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with schema parameter\n\t\tfields, err := db.TableFields(ctx, table, \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(fields) > 0, true)\n\t})\n}\n\n// Test_TableFields_UniqueKey tests TableFields with unique key constraint\nfunc Test_TableFields_UniqueKey(t *testing.T) {\n\ttableName := \"t_unique_test\"\n\n\t// Create table with unique constraint\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE IF NOT EXISTS `+tableName+` (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\temail varchar(100) UNIQUE NOT NULL,\n\t\t\tname varchar(100)\n\t\t)\n\t`)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer db.Exec(ctx, \"DROP TABLE IF EXISTS \"+tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfields, err := db.TableFields(ctx, tableName)\n\t\tt.AssertNil(err)\n\n\t\t// Check primary key\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\n\t\t// Check unique key\n\t\tt.Assert(fields[\"email\"].Key, \"uni\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t_ \"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tTableSize   = 10\n\tTablePrefix = \"t_\"\n\tSchemaName  = \"test\"\n\tCreateTime  = \"2018-10-24 10:00:00\"\n)\n\nvar (\n\tdb         gdb.DB\n\tconfigNode gdb.ConfigNode\n\tctx        = context.TODO()\n)\n\nfunc init() {\n\tconfigNode = gdb.ConfigNode{\n\t\tLink: `pgsql:postgres:12345678@tcp(127.0.0.1:5432)`,\n\t}\n\n\t// pgsql only permit to connect to the designation database.\n\t// so you need to create the pgsql database before you use orm\n\tgdb.AddConfigNode(gdb.DefaultGroupName, configNode)\n\tif r, err := gdb.New(configNode); err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\tif configNode.Name == \"\" {\n\t\tschemaTemplate := \"SELECT 'CREATE DATABASE %s' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '%s')\"\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, SchemaName, SchemaName)); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\n\t\tdb = db.Schema(SchemaName)\n\t} else {\n\t\tdb = db.Schema(configNode.Name)\n\t}\n\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"test\", gtime.TimestampNano())\n\t}\n\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial  NOT NULL,\n\t\t   \tpassport varchar(45) NOT NULL,\n\t\t   \tpassword varchar(32) NOT NULL,\n\t\t   \tnickname varchar(45) NOT NULL,\n\t\t   \tcreate_time timestamp NOT NULL,\n\t\t    favorite_movie varchar[],\n\t\t    favorite_music text[],\n\t\t\tnumeric_values numeric[],\n\t\t\tdecimal_values decimal[],\n\t\t   \tPRIMARY KEY (id)\n\t\t) ;`, name,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS %s\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n\n// createAllTypesTable creates a table with all common PostgreSQL types for testing\nfunc createAllTypesTable(table ...string) string {\n\treturn createAllTypesTableWithDb(db, table...)\n}\n\nfunc createAllTypesTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TablePrefix+\"all_types\", gtime.TimestampNano())\n\t}\n\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\t-- Basic integer types\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tcol_int2 int2 NOT NULL DEFAULT 0,\n\t\t\tcol_int4 int4 NOT NULL DEFAULT 0,\n\t\t\tcol_int8 int8 DEFAULT 0,\n\t\t\tcol_smallint smallint,\n\t\t\tcol_integer integer,\n\t\t\tcol_bigint bigint,\n\n\t\t\t-- Float types\n\t\t\tcol_float4 float4 DEFAULT 0.0,\n\t\t\tcol_float8 float8 DEFAULT 0.0,\n\t\t\tcol_real real,\n\t\t\tcol_double double precision,\n\t\t\tcol_numeric numeric(10,2) NOT NULL DEFAULT 0.00,\n\t\t\tcol_decimal decimal(10,2),\n\n\t\t\t-- Character types\n\t\t\tcol_char char(10) DEFAULT '',\n\t\t\tcol_varchar varchar(100) NOT NULL DEFAULT '',\n\t\t\tcol_text text,\n\n\t\t\t-- Boolean type\n\t\t\tcol_bool boolean NOT NULL DEFAULT false,\n\n\t\t\t-- Date/Time types\n\t\t\tcol_date date DEFAULT CURRENT_DATE,\n\t\t\tcol_time time,\n\t\t\tcol_timetz timetz,\n\t\t\tcol_timestamp timestamp DEFAULT CURRENT_TIMESTAMP,\n\t\t\tcol_timestamptz timestamptz,\n\t\t\tcol_interval interval,\n\n\t\t\t-- Binary type\n\t\t\tcol_bytea bytea,\n\n\t\t\t-- JSON types\n\t\t\tcol_json json DEFAULT '{}',\n\t\t\tcol_jsonb jsonb DEFAULT '{}',\n\n\t\t\t-- UUID type\n\t\t\tcol_uuid uuid,\n\n\t\t\t-- Network types\n\t\t\tcol_inet inet,\n\t\t\tcol_cidr cidr,\n\t\t\tcol_macaddr macaddr,\n\n\t\t\t-- Array types - integers\n\t\t\tcol_int2_arr int2[] DEFAULT '{}',\n\t\t\tcol_int4_arr int4[] DEFAULT '{}',\n\t\t\tcol_int8_arr int8[],\n\n\t\t\t-- Array types - floats\n\t\t\tcol_float4_arr float4[],\n\t\t\tcol_float8_arr float8[],\n\t\t\tcol_numeric_arr numeric[] DEFAULT '{}',\n\t\t\tcol_decimal_arr decimal[],\n\n\t\t\t-- Array types - characters\n\t\t\tcol_varchar_arr varchar[] NOT NULL DEFAULT '{}',\n\t\t\tcol_text_arr text[],\n\t\t\tcol_char_arr char(10)[],\n\n\t\t\t-- Array types - boolean\n\t\t\tcol_bool_arr boolean[],\n\n\t\t\t-- Array types - bytea\n\t\t\tcol_bytea_arr bytea[],\n\n\t\t\t-- Array types - date/time\n\t\t\tcol_date_arr date[],\n\t\t\tcol_timestamp_arr timestamp[],\n\n\t\t\t-- Array types - JSON\n\t\t\tcol_jsonb_arr jsonb[],\n\n\t\t\t-- Array types - UUID\n\t\t\tcol_uuid_arr uuid[]\n\t\t);\n\n\t\t-- Add comments for columns\n\t\tCOMMENT ON TABLE %s IS 'Test table with all PostgreSQL types';\n\t\tCOMMENT ON COLUMN %s.id IS 'Primary key ID';\n\t\tCOMMENT ON COLUMN %s.col_int2 IS 'int2 type (smallint)';\n\t\tCOMMENT ON COLUMN %s.col_int4 IS 'int4 type (integer)';\n\t\tCOMMENT ON COLUMN %s.col_int8 IS 'int8 type (bigint)';\n\t\tCOMMENT ON COLUMN %s.col_numeric IS 'numeric type with precision';\n\t\tCOMMENT ON COLUMN %s.col_varchar IS 'varchar type';\n\t\tCOMMENT ON COLUMN %s.col_bool IS 'boolean type';\n\t\tCOMMENT ON COLUMN %s.col_timestamp IS 'timestamp type';\n\t\tCOMMENT ON COLUMN %s.col_json IS 'json type';\n\t\tCOMMENT ON COLUMN %s.col_jsonb IS 'jsonb type';\n\t\tCOMMENT ON COLUMN %s.col_int2_arr IS 'int2 array type (_int2)';\n\t\tCOMMENT ON COLUMN %s.col_int4_arr IS 'int4 array type (_int4)';\n\t\tCOMMENT ON COLUMN %s.col_int8_arr IS 'int8 array type (_int8)';\n\t\tCOMMENT ON COLUMN %s.col_numeric_arr IS 'numeric array type (_numeric)';\n\t\tCOMMENT ON COLUMN %s.col_varchar_arr IS 'varchar array type (_varchar)';\n\t\tCOMMENT ON COLUMN %s.col_text_arr IS 'text array type (_text)';\n\t\t`, name,\n\t\tname, name, name, name, name, name, name, name, name, name, name, name, name, name, name, name, name)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\n// createInitAllTypesTable creates and initializes a table with all common PostgreSQL types\nfunc createInitAllTypesTable(table ...string) string {\n\treturn createInitAllTypesTableWithDb(db, table...)\n}\n\nfunc createInitAllTypesTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createAllTypesTableWithDb(db, table...)\n\n\t// Insert test data\n\tfor i := 1; i <= TableSize; i++ {\n\t\tvar sql strings.Builder\n\n\t\t// Write INSERT statement header\n\t\tsql.WriteString(fmt.Sprintf(`INSERT INTO %s (\n\t\t\tcol_int2, col_int4, col_int8, col_smallint, col_integer, col_bigint,\n\t\t\tcol_float4, col_float8, col_real, col_double, col_numeric, col_decimal,\n\t\t\tcol_char, col_varchar, col_text, col_bool,\n\t\t\tcol_date, col_time, col_timestamp,\n\t\t\tcol_json, col_jsonb,\n\t\t\tcol_bytea,\n\t\t\tcol_uuid,\n\t\t\tcol_int2_arr, col_int4_arr, col_int8_arr,\n\t\t\tcol_float4_arr, col_float8_arr, col_numeric_arr, col_decimal_arr,\n\t\t\tcol_varchar_arr, col_text_arr, col_bool_arr, col_bytea_arr, col_date_arr, col_timestamp_arr, col_jsonb_arr, col_uuid_arr\n\t\t) VALUES (`, name))\n\n\t\t// Integer types: col_int2, col_int4, col_int8, col_smallint, col_integer, col_bigint\n\t\tsql.WriteString(fmt.Sprintf(\"%d, %d, %d, %d, %d, %d, \",\n\t\t\ti, i*10, i*100, i, i*10, i*100))\n\n\t\t// Float types: col_float4, col_float8, col_real, col_double, col_numeric, col_decimal\n\t\tsql.WriteString(fmt.Sprintf(\"%d.5, %d.5, %d.5, %d.5, %d.99, %d.99, \",\n\t\t\ti, i, i, i, i, i))\n\n\t\t// Character types: col_char, col_varchar, col_text, col_bool\n\t\tsql.WriteString(fmt.Sprintf(\"'char_%d', 'varchar_%d', 'text_%d', %t, \",\n\t\t\ti, i, i, i%2 == 0))\n\n\t\t// Date/Time types: col_date, col_time, col_timestamp\n\t\t// Calculate day as integer in range 1-28; %02d in fmt.Sprintf ensures two-digit zero-padded format\n\t\tdayOfMonth := (i-1)%28 + 1\n\t\tsql.WriteString(fmt.Sprintf(\"'2024-01-%02d', '10:00:%02d', '2024-01-%02d 10:00:00', \",\n\t\t\tdayOfMonth, (i-1)%60, dayOfMonth))\n\n\t\t// JSON types: col_json, col_jsonb\n\t\tsql.WriteString(fmt.Sprintf(`'{\"key\": \"value%d\"}', '{\"key\": \"value%d\"}', `, i, i))\n\n\t\t// Bytea type: col_bytea\n\t\tsql.WriteString(`E'\\\\xDEADBEEF', `)\n\n\t\t// UUID type: col_uuid (use %x for hex representation, padded to ensure valid UUID)\n\t\tsql.WriteString(fmt.Sprintf(\"'550e8400-e29b-41d4-a716-4466554400%02x', \", i))\n\n\t\t// Integer array types: col_int2_arr, col_int4_arr, col_int8_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{1, 2, %d}', '{10, 20, %d}', '{100, 200, %d}', \",\n\t\t\ti, i, i))\n\n\t\t// Float array types: col_float4_arr, col_float8_arr, col_numeric_arr, col_decimal_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{1.1, 2.2, %d.3}', '{1.1, 2.2, %d.3}', '{1.11, 2.22, %d.33}', '{1.11, 2.22, %d.33}', \",\n\t\t\ti, i, i, i))\n\n\t\t// Character array types: col_varchar_arr, col_text_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"a\", \"b\", \"c%d\"}', '{\"x\", \"y\", \"z%d\"}', `, i, i))\n\n\t\t// Boolean array type: col_bool_arr\n\t\tsql.WriteString(fmt.Sprintf(\"'{true, false, %t}', \", i%2 == 0))\n\n\t\t// Bytea array type: col_bytea_arr (use ARRAY syntax for bytea)\n\t\tsql.WriteString(`ARRAY[E'\\\\xDEADBEEF', E'\\\\xCAFEBABE']::bytea[], `)\n\n\t\t// Date array type: col_date_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"2024-01-%02d\", \"2024-01-%02d\"}', `, dayOfMonth, (dayOfMonth%28)+1))\n\n\t\t// Timestamp array type: col_timestamp_arr\n\t\tsql.WriteString(fmt.Sprintf(`'{\"2024-01-%02d 10:00:00\", \"2024-01-%02d 11:00:00\"}', `, dayOfMonth, dayOfMonth))\n\n\t\t// JSONB array type: col_jsonb_arr (store as text array first, then cast to jsonb array)\n\t\tsql.WriteString(`ARRAY['{\"key\": \"value1\"}', '{\"key\": \"value2\"}']::jsonb[], `)\n\n\t\t// UUID array type: col_uuid_arr\n\t\tsql.WriteString(fmt.Sprintf(\"ARRAY['550e8400-e29b-41d4-a716-4466554400%02x'::uuid, '6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid]\", i))\n\n\t\t// Close VALUES\n\t\tsql.WriteString(\")\")\n\n\t\tif _, err := db.Exec(ctx, sql.String()); err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// https://github.com/gogf/gf/issues/3330\nfunc Test_Issue3330(t *testing.T) {\n\tvar (\n\t\ttable      = fmt.Sprintf(`%s_%d`, TablePrefix+\"test\", gtime.TimestampNano())\n\t\tuniqueName = fmt.Sprintf(`%s_%d`, TablePrefix+\"test_unique\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial  NOT NULL,\n\t\t   \tpassport varchar(45) NOT NULL,\n\t\t   \tpassword varchar(32) NOT NULL,\n\t\t   \tnickname varchar(45) NOT NULL,\n\t\t   \tcreate_time timestamp NOT NULL,\n\t\t   \tPRIMARY KEY (id),\n\t\t\tCONSTRAINT %s unique (\"password\")\n\t\t) ;`, table, uniqueName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tlist []map[string]any\n\t\t\tone  gdb.Record\n\t\t\terr  error\n\t\t)\n\n\t\tfields, err := db.TableFields(ctx, table)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(fields[\"id\"].Key, \"pri\")\n\t\tt.Assert(fields[\"password\"].Key, \"uni\")\n\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tlist = append(list, g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(\"p%d\", i),\n\t\t\t\t\"password\":    fmt.Sprintf(\"pw%d\", i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(\"n%d\", i),\n\t\t\t\t\"create_time\": \"2016-06-01 00:00:00\",\n\t\t\t})\n\t\t}\n\n\t\t_, err = db.Model(table).Data(list).Insert()\n\t\tt.AssertNil(err)\n\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tone, err = db.Model(table).WherePri(i).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"id\"], list[i-1][\"id\"])\n\t\t\tt.Assert(one[\"passport\"], list[i-1][\"passport\"])\n\t\t\tt.Assert(one[\"password\"], list[i-1][\"password\"])\n\t\t\tt.Assert(one[\"nickname\"], list[i-1][\"nickname\"])\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3632\nfunc Test_Issue3632(t *testing.T) {\n\ttype Member struct {\n\t\tOne []int64    `json:\"one\" orm:\"one\"`\n\t\tTwo [][]string `json:\"two\" orm:\"two\"`\n\t}\n\tvar (\n\t\tsqlText = gtest.DataContent(\"issues\", \"issue3632.sql\")\n\t\ttable   = fmt.Sprintf(`%s_%d`, TablePrefix+\"issue3632\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(sqlText, table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdao    = db.Model(table)\n\t\t\tmember = Member{\n\t\t\t\tOne: []int64{1, 2, 3},\n\t\t\t\tTwo: [][]string{{\"a\", \"b\"}, {\"c\", \"d\"}},\n\t\t\t}\n\t\t)\n\n\t\t_, err := dao.Ctx(ctx).Data(&member).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3671\nfunc Test_Issue3671(t *testing.T) {\n\ttype SubMember struct {\n\t\tSeven string\n\t\tEight int64\n\t}\n\ttype Member struct {\n\t\tOne   []int64     `json:\"one\" orm:\"one\"`\n\t\tTwo   [][]string  `json:\"two\" orm:\"two\"`\n\t\tThree []string    `json:\"three\" orm:\"three\"`\n\t\tFour  []int64     `json:\"four\" orm:\"four\"`\n\t\tFive  []SubMember `json:\"five\" orm:\"five\"`\n\t}\n\tvar (\n\t\tsqlText = gtest.DataContent(\"issues\", \"issue3671.sql\")\n\t\ttable   = fmt.Sprintf(`%s_%d`, TablePrefix+\"issue3632\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(sqlText, table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdao    = db.Model(table)\n\t\t\tmember = Member{\n\t\t\t\tOne:   []int64{1, 2, 3},\n\t\t\t\tTwo:   [][]string{{\"a\", \"b\"}, {\"c\", \"d\"}},\n\t\t\t\tThree: []string{\"x\", \"y\", \"z\"},\n\t\t\t\tFour:  []int64{1, 2, 3},\n\t\t\t\tFive:  []SubMember{{Seven: \"1\", Eight: 2}, {Seven: \"3\", Eight: 4}},\n\t\t\t}\n\t\t)\n\n\t\t_, err := dao.Ctx(ctx).Data(&member).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3668\nfunc Test_Issue3668(t *testing.T) {\n\ttype Issue3668 struct {\n\t\tText   any\n\t\tNumber any\n\t}\n\tvar (\n\t\tsqlText = gtest.DataContent(\"issues\", \"issue3668.sql\")\n\t\ttable   = fmt.Sprintf(`%s_%d`, TablePrefix+\"issue3668\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(sqlText, table)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdao  = db.Model(table)\n\t\t\tdata = Issue3668{\n\t\t\t\tText:   \"我们都是自然的婴儿，卧在宇宙的摇篮里\",\n\t\t\t\tNumber: nil,\n\t\t\t}\n\t\t)\n\t\t_, err := dao.Ctx(ctx).\n\t\t\tData(data).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t})\n}\n\ntype Issue4033Status int\n\nconst (\n\tIssue4033StatusA Issue4033Status = 1\n)\n\nfunc (s Issue4033Status) String() string {\n\treturn \"somevalue\"\n}\n\nfunc (s Issue4033Status) Int64() int64 {\n\treturn int64(s)\n}\n\n// https://github.com/gogf/gf/issues/4033\nfunc Test_Issue4033(t *testing.T) {\n\tvar (\n\t\tsqlText = gtest.DataContent(\"issues\", \"issue4033.sql\")\n\t\ttable   = \"test_enum\"\n\t)\n\tif _, err := db.Exec(ctx, sqlText); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tquery := g.Map{\n\t\t\t\"status\": g.Slice{Issue4033StatusA},\n\t\t}\n\t\t_, err := db.Model(table).Ctx(ctx).Where(query).All()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4500\n// Raw() Count ignores Where condition\nfunc Test_Issue4500(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Test 1: Raw SQL with WHERE + external Where condition + Count\n\t// This tests that formatCondition correctly uses AND when Raw SQL already has WHERE\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw SQL: id IN (1,5,7,8,9,10) = 6 records\n\t\t// Where: id < 8 filters to {1,5,7} = 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 2: Raw SQL without WHERE + external Where condition + Count\n\t// This tests that formatCondition correctly adds WHERE\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s\", table)).\n\t\t\tWhereLT(\"id\", 5).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw SQL: all 10 records\n\t\t// Where: id < 5 = {1,2,3,4} = 4 records\n\t\tt.Assert(count, 4)\n\t})\n\n\t// Test 3: Raw + Where + ScanAndCount\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t}\n\t\tvar users []User\n\t\tvar total int\n\t\terr := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tScanAndCount(&users, &total, false)\n\t\tt.AssertNil(err)\n\t\t// Both scan result and count should respect Where condition\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(total, 3)\n\t})\n\n\t// Test 4: Raw + multiple Where conditions + Count\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id > ?\", table), 0).\n\t\t\tWhereLT(\"id\", 5).\n\t\t\tWhereGTE(\"id\", 2).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Raw: id > 0 (all 10 records)\n\t\t// Where: id < 5 AND id >= 2 = {2, 3, 4} = 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 5: Raw SQL with no external Where + Count (baseline test)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 2, 3}).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// Should count 3 records\n\t\tt.Assert(count, 3)\n\t})\n\n\t// Test 6: Verify All() still works correctly with Raw + Where\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"SELECT * FROM %s WHERE id IN (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4677\n// record.Get().Bytes() corrupts bytea data on retrieval from PostgreSQL.\nfunc Test_Issue4677(t *testing.T) {\n\ttable := fmt.Sprintf(`%s_%d`, TablePrefix+\"issue4677\", gtime.TimestampNano())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tbin_data bytea\n\t\t);`, table,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test 1: Binary data with various byte values including 0x00, 0x5D(']'), 0x5B('[')\n\t\toriginalBytes := []byte{\n\t\t\t0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01, 0x5B, 0x5D,\n\t\t\t0xFF, 0x7B, 0x7D, 0x80, 0xCA, 0xFE, 0xBA, 0xBE,\n\t\t}\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"bin_data\": originalBytes,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tretrievedBytes := record[\"bin_data\"].Bytes()\n\t\tt.Assert(len(retrievedBytes), len(originalBytes))\n\t\tt.Assert(retrievedBytes, originalBytes)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test 2: Larger binary data (simulating gob/protobuf encoded payload)\n\t\tlargeBytes := make([]byte, 1024)\n\t\tfor i := range largeBytes {\n\t\t\tlargeBytes[i] = byte(i % 256)\n\t\t}\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"bin_data\": largeBytes,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := db.Model(table).OrderDesc(\"id\").One()\n\t\tt.AssertNil(err)\n\n\t\tretrievedBytes := record[\"bin_data\"].Bytes()\n\t\tt.Assert(len(retrievedBytes), len(largeBytes))\n\t\tt.Assert(retrievedBytes, largeBytes)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4231\n// ConvertValueForField corrupts bytea data containing 0x5D on write.\nfunc Test_Issue4231(t *testing.T) {\n\ttable := fmt.Sprintf(`%s_%d`, TablePrefix+\"issue4231\", gtime.TimestampNano())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tbin_data bytea\n\t\t);`, table,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Bytes containing 0x5D (ASCII ']') which was being converted to 0x7D ('}')\n\t\toriginalBytes := []byte{0x01, 0x5D, 0x02, 0x5B, 0x03}\n\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"bin_data\": originalBytes,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\n\t\tretrievedBytes := record[\"bin_data\"].Bytes()\n\t\tt.Assert(len(retrievedBytes), len(originalBytes))\n\t\tt.Assert(retrievedBytes, originalBytes)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4595\n// FieldsPrefix silently drops fields when using table alias before LeftJoin.\nfunc Test_Issue4595(t *testing.T) {\n\tvar (\n\t\ttableUser       = fmt.Sprintf(`%s_%d`, TablePrefix+\"issue4595_user\", gtime.TimestampNano())\n\t\ttableUserDetail = fmt.Sprintf(`%s_%d`, TablePrefix+\"issue4595_user_detail\", gtime.TimestampNano())\n\t)\n\n\t// Create user table\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tname varchar(100),\n\t\t\temail varchar(100)\n\t\t);`, tableUser,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableUser)\n\n\t// Create user_detail table\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tuser_id bigint,\n\t\t\tphone varchar(20),\n\t\t\taddress varchar(200)\n\t\t);`, tableUserDetail,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableUserDetail)\n\n\t// Insert test data\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tINSERT INTO %s (id, name, email) VALUES (1, 'john', 'john@example.com');\n\t\tINSERT INTO %s (id, user_id, phone, address) VALUES (1, 1, '1234567890', '123 Main St');\n\t`, tableUser, tableUserDetail)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test case 1: FieldsPrefix called before LeftJoin\n\t\t// Both t1 and t2 fields should be present\n\t\tr, err := db.Model(tableUser).As(\"t1\").\n\t\t\tFieldsPrefix(\"t2\", \"phone\", \"address\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"name\", \"email\").\n\t\t\tLeftJoin(tableUserDetail, \"t2\", \"t1.id=t2.user_id\").\n\t\t\tAll()\n\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[0][\"name\"], \"john\")\n\t\tt.Assert(r[0][\"email\"], \"john@example.com\")\n\t\tt.Assert(r[0][\"phone\"], \"1234567890\")\n\t\tt.Assert(r[0][\"address\"], \"123 Main St\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test case 2: Using Fields() with prefix\n\t\tr, err := db.Model(tableUser).As(\"t1\").\n\t\t\tFields(\"t2.phone\", \"t2.address\", \"t1.id\", \"t1.name\", \"t1.email\").\n\t\t\tLeftJoin(tableUserDetail, \"t2\", \"t1.id=t2.user_id\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[0][\"name\"], \"john\")\n\t\tt.Assert(r[0][\"email\"], \"john@example.com\")\n\t\tt.Assert(r[0][\"phone\"], \"1234567890\")\n\t\tt.Assert(r[0][\"address\"], \"123 Main St\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test case 3: FieldsPrefix called after LeftJoin\n\t\tr, err := db.Model(tableUser).As(\"t1\").\n\t\t\tLeftJoin(tableUserDetail, \"t2\", \"t1.id=t2.user_id\").\n\t\t\tFieldsPrefix(\"t2\", \"phone\", \"address\").\n\t\t\tFieldsPrefix(\"t1\", \"id\", \"name\", \"email\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 1)\n\t\tt.Assert(r[0][\"name\"], \"john\")\n\t\tt.Assert(r[0][\"email\"], \"john@example.com\")\n\t\tt.Assert(r[0][\"phone\"], \"1234567890\")\n\t\tt.Assert(r[0][\"address\"], \"123 Main St\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value() // model value\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete() // model delete\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One() // model one\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", \"2\").Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser   User\n\t\t\tcount  int\n\t\t\tresult sql.Result\n\t\t\terr    error\n\t\t)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"pw1\")\n\t\tt.Assert(user.NickName, \"n1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw2\",\n\t\t\t\"nickname\":    \"n2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"p1\")\n\t\tt.Assert(user.Password, \"pw2\")\n\t\tt.Assert(user.NickName, \"n2\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial record\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"pass1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Replace with new data\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": \"2018-10-24 10:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify the data was replaced\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"].String(), \"t11\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\n\t\t// Replace with new ID (insert new record)\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t22\",\n\t\t\t\"password\":    \"pass22\",\n\t\t\t\"nickname\":    \"T22\",\n\t\t\t\"create_time\": \"2018-10-24 11:00:00\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// Verify new record was inserted\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 2)\n\t})\n}\n\nfunc Test_Model_OnConflict(t *testing.T) {\n\tvar (\n\t\ttable      = fmt.Sprintf(`%s_%d`, TablePrefix+\"test\", gtime.TimestampNano())\n\t\tuniqueName = fmt.Sprintf(`%s_%d`, TablePrefix+\"test_unique\", gtime.TimestampNano())\n\t)\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial  NOT NULL,\n\t\t   \tpassport varchar(45) NOT NULL,\n\t\t   \tpassword varchar(32) NOT NULL,\n\t\t   \tnickname varchar(45) NOT NULL,\n\t\t   \tcreate_time timestamp NOT NULL,\n\t\t   \tPRIMARY KEY (id),\n\t\t\tCONSTRAINT %s UNIQUE (\"passport\", \"password\")\n\t\t) ;`, table, uniqueName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"passport,password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"passport\", \"password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(g.Slice{\"passport\", \"password\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"n1\")\n\t})\n}\n\nfunc Test_Model_OnDuplicate(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(\"passport,password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(\"passport\", \"password\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Slice{\"passport\", \"password\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"passport\": \"nickname\",\n\t\t\t\"password\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"nickname\"])\n\t\tt.Assert(one[\"password\"], data[\"nickname\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map+raw.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.MapStrStr{\n\t\t\t\"id\":          \"1\",\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"passport\": gdb.Raw(\"CONCAT(EXCLUDED.passport, '1')\"),\n\t\t\t\"password\": gdb.Raw(\"CONCAT(EXCLUDED.password, '2')\"),\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"]+\"1\")\n\t\tt.Assert(one[\"password\"], data[\"password\"]+\"2\")\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_Model_OnDuplicateWithCounter(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"id\": gdb.Counter{Field: \"id\", Value: 999999},\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(one)\n\t})\n}\n\nfunc Test_Model_OnDuplicateEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string type 1.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(\"nickname,create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// string type 2.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(\"nickname\", \"create_time\").Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(g.Slice{\"nickname\", \"create_time\"}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n\n\t// map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicateEx(g.Map{\n\t\t\t\"nickname\":    \"nickname\",\n\t\t\t\"create_time\": \"nickname\",\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"password\"], data[\"password\"])\n\t\tt.Assert(one[\"nickname\"], \"name_1\")\n\t})\n}\n\nfunc Test_OrderRandom(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_ConvertSliceString(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId            int\n\t\t\tPassport      string\n\t\t\tPassword      string\n\t\t\tNickName      string\n\t\t\tCreateTime    *gtime.Time\n\t\t\tFavoriteMovie []string\n\t\t\tFavoriteMusic []string\n\t\t}\n\n\t\tvar (\n\t\t\tuser  User\n\t\t\tuser2 User\n\t\t\terr   error\n\t\t)\n\n\t\t// slice string not null\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":             1,\n\t\t\t\"passport\":       \"p1\",\n\t\t\t\"password\":       \"pw1\",\n\t\t\t\"nickname\":       \"n1\",\n\t\t\t\"create_time\":    CreateTime,\n\t\t\t\"favorite_movie\": g.Slice{\"Iron-Man\", \"Spider-Man\"},\n\t\t\t\"favorite_music\": g.Slice{\"Hey jude\", \"Let it be\"},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Where(\"id\", 1).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(user.FavoriteMusic), 2)\n\t\tt.Assert(user.FavoriteMusic[0], \"Hey jude\")\n\t\tt.Assert(user.FavoriteMusic[1], \"Let it be\")\n\t\tt.Assert(len(user.FavoriteMovie), 2)\n\t\tt.Assert(user.FavoriteMovie[0], \"Iron-Man\")\n\t\tt.Assert(user.FavoriteMovie[1], \"Spider-Man\")\n\n\t\t// slice string null\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"p1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Where(\"id\", 2).Scan(&user2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user2.FavoriteMusic, nil)\n\t\tt.Assert(len(user2.FavoriteMovie), 0)\n\t})\n}\n\nfunc Test_ConvertSliceFloat64(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\ttype Args struct {\n\t\tNumericValues []float64 `orm:\"numeric_values\"`\n\t\tDecimalValues []float64 `orm:\"decimal_values\"`\n\t}\n\ttype User struct {\n\t\tId         int         `orm:\"id\"`\n\t\tPassport   string      `orm:\"passport\"`\n\t\tPassword   string      `json:\"password\"`\n\t\tNickName   string      `json:\"nickname\"`\n\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\tArgs\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\targs Args\n\t}{\n\t\t{\n\t\t\tname: \"nil\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: nil,\n\t\t\t\tDecimalValues: nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"not nil\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: []float64{1.1, 2.2, 3.3},\n\t\t\t\tDecimalValues: []float64{1.1, 2.2, 3.3},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"not empty\",\n\t\t\targs: Args{\n\t\t\t\tNumericValues: []float64{},\n\t\t\t\tDecimalValues: []float64{},\n\t\t\t},\n\t\t},\n\t}\n\tnow := gtime.New(CreateTime)\n\tfor i, tt := range tests {\n\t\tgtest.C(t, func(t *gtest.T) {\n\t\t\tuser := User{\n\t\t\t\tId:         i + 1,\n\t\t\t\tPassport:   \"\",\n\t\t\t\tPassword:   \"\",\n\t\t\t\tNickName:   \"\",\n\t\t\t\tCreateTime: now,\n\t\t\t\tArgs:       tt.args,\n\t\t\t}\n\n\t\t\t_, err := db.Model(table).OmitNilData().Insert(user)\n\t\t\tt.AssertNil(err)\n\t\t\tvar got Args\n\t\t\terr = db.Model(table).Where(\"id\", user.Id).Limit(1).Scan(&got)\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(tt.args, got)\n\t\t})\n\t}\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNE(err, nil)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 0)\n\n\t\tvalue, err := db.Model(table).Fields(\"passport\").WherePri(1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t1\")\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\n\t\t// pgsql support ignore without primary key\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_model_where_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":         \"%name%\",\n\t\t\t\"id between ? and ?\":      g.Slice{1, 3},\n\t\t\t\"id > 0\":                  nil,\n\t\t\t\"create_time IS NOT NULL\": nil,\n\t\t\t\"id\":                      g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    \"1970-01-01\",\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":         \"%name%\",\n\t\t\t\"id between ? and ?\":      g.Slice{1, 3},\n\t\t\t\"id > 0\":                  nil,\n\t\t\t\"create_time IS NOT NULL\": nil,\n\t\t\t\"id\":                      g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    \"1970-01-01\",\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL(t *testing.T) {\n\t// Create a custom table with nullable nickname column for this test\n\ttable := fmt.Sprintf(`%s_%d`, TablePrefix+\"nullable\", gtime.TimestampNano())\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE %s (\n\t\t   \tid bigserial NOT NULL,\n\t\t   \tpassport varchar(45),\n\t\t   \tpassword varchar(32),\n\t\t   \tnickname varchar(45),\n\t\t   \tcreate_time timestamp,\n\t\t   \tPRIMARY KEY (id)\n\t\t) ;`, table,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(table)\n\n\t// Insert test data\n\tfor i := 1; i <= TableSize; i++ {\n\t\tif _, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t}); err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WhereExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          bigserial NOT NULL,\n    uid         int NOT NULL DEFAULT 0,\n    PRIMARY KEY (id)\n);`, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\"))\n\n\t\tr, err := db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereNotExists\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\n\t\t// Test WhereExists with empty result\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table).\n\t\t\tWhereExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereNotExists with all results\n\t\tr, err = db.Model(table).\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test combination of Where and WhereExists\n\t\tr, err = db.Model(table+\" as \\\"user\\\"\").\n\t\t\tWhere(\"id>?\", 3).\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 0)\n\n\t\t// Test WhereExists with complex subquery\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\")).\n\t\t\tWhere(\"id > ?\", 0)\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Fields\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tFields(\"id,passport\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[0][\"passport\"].String(), \"user_1\")\n\n\t\t// Test WhereExists with Group\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t\tt.Assert(r[1][\"id\"].Int(), 2)\n\n\t\t// Test WhereExists with Having\n\t\tr, err = db.Model(table+\" as \\\"user\\\"\").\n\t\t\tWhereExists(subQuery1).\n\t\t\tGroup(\"id\").\n\t\t\tHaving(\"id > ?\", 1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_WhereNotExists(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create another table for exists subquery\n\t\ttable2 := \"table2_\" + gtime.TimestampNanoStr()\n\t\tsqlCreate := fmt.Sprintf(`\nCREATE TABLE %s (\n    id          bigserial NOT NULL,\n    uid         int NOT NULL DEFAULT 0,\n    PRIMARY KEY (id)\n);`, table2)\n\t\tif _, err := db.Exec(ctx, sqlCreate); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\n\t\t// Insert test data\n\t\t_, err := db.Model(table2).Insert(g.List{\n\t\t\t{\"uid\": 1},\n\t\t\t{\"uid\": 2},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Test WhereNotExists with subquery\n\t\tsubQuery1 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\"))\n\n\t\tr, err := db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery1).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 8)\n\t\tt.Assert(r[0][\"id\"].Int(), 3)\n\t\tt.Assert(r[1][\"id\"].Int(), 4)\n\n\t\t// Test WhereNotExists with empty subquery\n\t\tsubQuery2 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = -1\")\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery2).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 10)\n\n\t\t// Test WhereNotExists with complex condition\n\t\tsubQuery3 := db.Model(table2).\n\t\t\tFields(\"id\").\n\t\t\tWhere(\"uid = ?\", db.Raw(\"\\\"user\\\".id\")).\n\t\t\tWhere(\"id > ?\", 1)\n\t\tr, err = db.Model(table + \" as \\\"user\\\"\").\n\t\t\tWhereNotExists(subQuery3).\n\t\t\tOrder(\"id asc\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 9)\n\t\tt.Assert(r[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_open_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n)\n\n// Test_Open tests the Open method with various configurations\nfunc Test_Open_WithNamespace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:      \"postgres\",\n\t\t\tPass:      \"12345678\",\n\t\t\tHost:      \"127.0.0.1\",\n\t\t\tPort:      \"5432\",\n\t\t\tName:      \"test\",\n\t\t\tNamespace: \"public\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithTimezone tests Open with timezone configuration\nfunc Test_Open_WithTimezone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:     \"postgres\",\n\t\t\tPass:     \"12345678\",\n\t\t\tHost:     \"127.0.0.1\",\n\t\t\tPort:     \"5432\",\n\t\t\tName:     \"test\",\n\t\t\tTimezone: \"Asia/Shanghai\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithExtra tests Open with extra configuration\nfunc Test_Open_WithExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:  \"postgres\",\n\t\t\tPass:  \"12345678\",\n\t\t\tHost:  \"127.0.0.1\",\n\t\t\tPort:  \"5432\",\n\t\t\tName:  \"test\",\n\t\t\tExtra: \"connect_timeout=10\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithInvalidExtra tests Open with invalid extra configuration\nfunc Test_Open_WithInvalidExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"5432\",\n\t\t\tName: \"test\",\n\t\t\t// Invalid extra format with invalid URL encoding that will cause parse error\n\t\t\tExtra: \"%Q=%Q&b\",\n\t\t}\n\t\t_, err := driver.Open(config)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_Open_WithFullConfig tests Open with all configuration options\nfunc Test_Open_WithFullConfig(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser:      \"postgres\",\n\t\t\tPass:      \"12345678\",\n\t\t\tHost:      \"127.0.0.1\",\n\t\t\tPort:      \"5432\",\n\t\t\tName:      \"test\",\n\t\t\tNamespace: \"public\",\n\t\t\tTimezone:  \"UTC\",\n\t\t\tExtra:     \"connect_timeout=10\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithoutPort tests Open without port\nfunc Test_Open_WithoutPort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tName: \"test\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_WithoutName tests Open without database name\nfunc Test_Open_WithoutName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"5432\",\n\t\t}\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(db, nil)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n\n// Test_Open_InvalidHost tests Open with invalid host\nfunc Test_Open_InvalidHost(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdriver := pgsql.Driver{}\n\t\tconfig := &gdb.ConfigNode{\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"12345678\",\n\t\t\tHost: \"invalid_host_that_does_not_exist\",\n\t\t\tPort: \"5432\",\n\t\t\tName: \"test\",\n\t\t}\n\t\t// Note: sql.Open doesn't actually connect, so no error here\n\t\t// The error would occur when actually using the connection\n\t\tdb, err := driver.Open(config)\n\t\tt.AssertNil(err)\n\t\tif db != nil {\n\t\t\tdb.Close()\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_raw_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Raw_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"passport\":    \"port_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(\n\t\t\tg.List{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"passport\":    \"port_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t\tg.Map{\n\t\t\t\t\t\"passport\":    \"port_4\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t\t\t},\n\t\t\t},\n\t\t).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_Raw_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\": gdb.Raw(\"id\"),\n\t\t}).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Raw_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          gdb.Raw(\"id+100\"),\n\t\t\t\"create_time\": gdb.Raw(\"now()\"),\n\t\t}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tn, err := user.Where(\"id\", 101).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(1))\n\t})\n}\n\nfunc Test_Raw_Where(t *testing.T) {\n\ttable1 := createTable(\"test_raw_where_table1\")\n\ttable2 := createTable(\"test_raw_where_table2\")\n\tdefer dropTable(table1)\n\tdefer dropTable(table2)\n\n\t// https://github.com/gogf/gf/issues/3922\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" AS A WHERE NOT EXISTS (SELECT B.id FROM \"test_raw_where_table2\" AS B WHERE \"B\".\"id\"=A.id) LIMIT 1`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(\"B.id\", gdb.Raw(\"A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" AS A WHERE NOT EXISTS (SELECT B.id FROM \"test_raw_where_table2\" AS B WHERE B.id=A.id) LIMIT 1`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\ts := db.Model(table2).As(\"B\").Ctx(ctx).Fields(\"B.id\").Where(gdb.Raw(\"B.id=A.id\"))\n\t\t\tm := db.Model(table1).As(\"A\").Ctx(ctx).Where(\"NOT EXISTS ?\", s).Limit(1)\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n\t// https://github.com/gogf/gf/issues/3915\n\tgtest.C(t, func(t *gtest.T) {\n\t\texpectSql := `SELECT * FROM \"test_raw_where_table1\" WHERE \"passport\" < \"nickname\"`\n\t\tsql, err := gdb.ToSQL(ctx, func(ctx context.Context) error {\n\t\t\tm := db.Model(table1).Ctx(ctx).WhereLT(\"passport\", gdb.Raw(`\"nickname\"`))\n\t\t\t_, err := m.All()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(expectSql, sql)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/drivers/pgsql/v2\"\n)\n\nfunc Test_LastInsertId(t *testing.T) {\n\t// err not nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(\"notexist\").Insert(g.List{\n\t\t\t{\"name\": \"user1\"},\n\t\t\t{\"name\": \"user2\"},\n\t\t\t{\"name\": \"user3\"},\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := createTable()\n\t\tdefer dropTable(tableName)\n\t\tres, err := db.Model(tableName).Insert(g.List{\n\t\t\t{\"passport\": \"user1\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t{\"passport\": \"user2\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t{\"passport\": \"user3\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tlastInsertId, err := res.LastInsertId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(lastInsertId, int64(3))\n\t\trowsAffected, err := res.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(rowsAffected, int64(3))\n\t})\n}\n\nfunc Test_TxLastInsertId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := createTable()\n\t\tdefer dropTable(tableName)\n\t\terr := db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// user\n\t\t\tres, err := tx.Model(tableName).Insert(g.List{\n\t\t\t\t{\"passport\": \"user1\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user2\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user3\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tlastInsertId, err := res.LastInsertId()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(lastInsertId, int64(3))\n\t\t\trowsAffected, err := res.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(rowsAffected, int64(3))\n\n\t\t\tres1, err := tx.Model(tableName).Insert(g.List{\n\t\t\t\t{\"passport\": \"user4\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t\t{\"passport\": \"user5\", \"password\": \"pwd\", \"nickname\": \"nickname\", \"create_time\": CreateTime},\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\tlastInsertId1, err := res1.LastInsertId()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(lastInsertId1, int64(5))\n\t\t\trowsAffected1, err := res1.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(rowsAffected1, int64(2))\n\t\t\treturn nil\n\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Driver_DoFilter(t *testing.T) {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tdriver = pgsql.Driver{}\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar data = g.Map{\n\t\t\t`select * from user where (role)::jsonb ?| 'admin'`: `select * from user where (role)::jsonb ?| 'admin'`,\n\t\t\t`select * from user where (role)::jsonb ?| '?'`:     `select * from user where (role)::jsonb ?| '$2'`,\n\t\t\t`select * from user where (role)::jsonb &? '?'`:     `select * from user where (role)::jsonb &? '$2'`,\n\t\t\t`select * from user where (role)::jsonb ? '?'`:      `select * from user where (role)::jsonb ? '$2'`,\n\t\t\t`select * from user where '?'`:                      `select * from user where '$1'`,\n\t\t}\n\t\tfor k, v := range data {\n\t\t\tnewSql, _, err := driver.DoFilter(ctx, nil, k, nil)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(newSql, v)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_transaction_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_TX_Query(t *testing.T) {\n\t// Test successful queries\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int+$2::int\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"SELECT $1::int+$2::int\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test error query - in PostgreSQL, once a statement fails,\n\t// the transaction is aborted and must be rolled back\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Query(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Exec(t *testing.T) {\n\t// Test successful exec operations\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int+$2::int\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"SELECT $1::int+$2::int\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test error exec - in PostgreSQL, once a statement fails,\n\t// the transaction is aborted and must be rolled back\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Exec(\"ERROR\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Commit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Rollback(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tst, err := tx.Prepare(\"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0], \"?column?\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_IsClosed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), false)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), false)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tuser := tx.Model(table)\n\n\t\t_, err = user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(2))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_BatchInsert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Insert(table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 10)\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(2))\n\t})\n}\n\nfunc Test_TX_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.Update(table, \"create_time='2019-10-24 10:00:00'\", \"id=3\")\n\t\tt.AssertNil(err)\n\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"create_time\").Where(\"id\", 3).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"2019-10-24 10:00:00\")\n\t})\n}\n\nfunc Test_TX_Delete_Commit(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize-1))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Delete_Rollback(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Where(\"id\", 1).Delete()\n\t\tt.AssertNil(err)\n\n\t\tn, err := tx.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize-1))\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tn, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\t\tt.AssertNE(n, int64(0))\n\t\tt.Assert(tx.IsClosed(), true)\n\t})\n}\n\nfunc Test_TX_Save(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_TX_BatchSave(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          4,\n\t\t\t\t\"passport\":    \"USER_4\",\n\t\t\t\t\"password\":    \"PASS_4\",\n\t\t\t\t\"nickname\":    \"NAME_4\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\tn, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, int64(TableSize))\n\n\t\tvalue, err := db.Model(table).Fields(\"password\").Where(\"id\", 4).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"PASS_4\")\n\t})\n}\n\nfunc Test_TX_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := tx.GetAll(fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\trecord, err := tx.GetOne(fmt.Sprintf(\"SELECT * FROM %s WHERE passport=$1\", table), \"user_2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(record, nil)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_2\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := tx.GetValue(fmt.Sprintf(\"SELECT id FROM %s WHERE passport=$1\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\tcount, err := tx.GetCount(\"SELECT * FROM \" + table)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetStruct(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetStructs(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_TX_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr = tx.GetScan(user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=$1\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t\tt.Assert(user.CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr = tx.GetScan(&users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=$1\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[2].CreateTime.String(), \"2018-10-24 10:00:00\")\n\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Ctx(ctx).Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(tx.IsClosed(), false)\n\t\t\treturn gerror.New(\"error\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Ctx(ctx).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"NAME_1\")\n\t})\n}\n\nfunc Test_Transaction_Panic(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.TODO()\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Model(table).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).OnConflict(\"id\").Save()\n\t\t\tt.AssertNil(err)\n\t\t\tpanic(\"error\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n}\n\nfunc Test_Transaction_Method(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = db.Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\tt.AssertNil(err)\n\n\t\t\t_, err = db.Ctx(ctx).Exec(ctx, fmt.Sprintf(\n\t\t\t\t\"INSERT INTO %s(passport,password,nickname,create_time,id) \"+\n\t\t\t\t\t\"VALUES('t2','25d55ad283aa400af464c76d713c07ad','T2','2021-08-25 21:53:00',2) \",\n\t\t\t\ttable))\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n}\n\nfunc Test_Transaction_Nested_Begin_Rollback_Commit(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx begin.\n\t\terr = tx.Begin()\n\t\tt.AssertNil(err)\n\n\t\t// tx rollback.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 2)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseTX(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\t// another record.\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = tx2.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = tx.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_TX_Transaction_UseDB(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          1,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// commit\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t\t\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\t\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\t\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t\t\t\t}).Insert()\n\t\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t})\n\t\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\t\t\t\t\tt.AssertNil(err)\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// rollback\n\t\t\terr = db.Transaction(ctx, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"USER_2\",\n\t\t\t\t\t\"password\":    \"PASS_2\",\n\t\t\t\t\t\"nickname\":    \"NAME_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t}).Insert()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\t// panic makes this transaction rollback.\n\t\t\t\tpanic(\"error\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[1][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Nested_SavePoint_RollbackTo(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\n\t\t// tx save point.\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\terr = tx.SavePoint(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t_, err = tx.Model(table).Data(g.Map{\n\t\t\t\"id\":          2,\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\t// tx rollback to.\n\t\terr = tx.RollbackTo(\"MyPoint\")\n\t\tt.AssertNil(err)\n\n\t\t// tx commit.\n\t\terr = tx.Commit()\n\t\tt.AssertNil(err)\n\n\t\t// check data.\n\t\tall, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Required(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"required\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequired,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"required_nested\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Transaction_Propagation_RequiresNew(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"outer\",\n\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\"passport\":    \"inner_new\",\n\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"rollback inner transaction\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_Propagation_Nested(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          5,\n\t\t\t\t\"passport\":    \"nested_outer\",\n\t\t\t\t\"password\":    \"pass_5\",\n\t\t\t\t\"nickname\":    \"name_5\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, _ = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          6,\n\t\t\t\t\t\"passport\":    \"nested_inner\",\n\t\t\t\t\t\"password\":    \"pass_6\",\n\t\t\t\t\t\"nickname\":    \"name_6\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"rollback to savepoint\")\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          7,\n\t\t\t\t\"passport\":    \"nested_after\",\n\t\t\t\t\"password\":    \"pass_7\",\n\t\t\t\t\"nickname\":    \"name_7\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"nested_inner\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"nested_outer\", \"nested_after\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n}\n\nfunc Test_Transaction_Propagation_NotSupported(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"tx_record\",\n\t\t\t\t\"password\":    \"pass_8\",\n\t\t\t\t\"nickname\":    \"name_8\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table, g.Map{\n\t\t\t\t\t\"id\":          9,\n\t\t\t\t\t\"passport\":    \"non_tx_record\",\n\t\t\t\t\t\"password\":    \"pass_9\",\n\t\t\t\t\t\"nickname\":    \"name_9\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Where(\"passport\", \"tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"non_tx_record\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_Propagation_Mandatory(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationMandatory,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          10,\n\t\t\t\t\t\"passport\":    \"mandatory\",\n\t\t\t\t\t\"password\":    \"pass_10\",\n\t\t\t\t\t\"nickname\":    \"name_10\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Never(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationNever,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\t\"id\":          11,\n\t\t\t\t\"passport\":    \"never\",\n\t\t\t\t\"password\":    \"pass_11\",\n\t\t\t\t\"nickname\":    \"name_11\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\treturn tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNever,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Supports(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\t// scenario1: when in a transaction, use PropagationSupports to execute a transaction\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"user_1\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = tx.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationSupports,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"user_2\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn gerror.New(\"error\")\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\t// scenario2: when not in a transaction, do not use transaction but direct db link.\n\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationSupports,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = tx.Insert(table, g.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tresult, err := db.Model(table).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t})\n}\n\nfunc Test_Transaction_Propagation_Complex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createTable()\n\t\ttable2 := createTable()\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table1, g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"outer\",\n\t\t\t\t\"password\":    \"pass_1\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// First nested transaction (NESTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = tx2.Insert(table1, g.Map{\n\t\t\t\t\t\"id\":          2,\n\t\t\t\t\t\"passport\":    \"nested1\",\n\t\t\t\t\t\"password\":    \"pass_2\",\n\t\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\tt.AssertNil(err)\n\n\t\t\t\t// Second nested transaction (REQUIRES_NEW)\n\t\t\t\terr = tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":          3,\n\t\t\t\t\t\t\"passport\":    \"new1\",\n\t\t\t\t\t\t\"password\":    \"pass_3\",\n\t\t\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn gerror.New(\"rollback new transaction\")\n\t\t\t\t})\n\t\t\t\tt.AssertNE(err, nil)\n\n\t\t\t\t// Third nested transaction (NESTED)\n\t\t\t\treturn tx2.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\t\tPropagation: gdb.PropagationNested,\n\t\t\t\t}, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, _ = tx3.Insert(table1, g.Map{\n\t\t\t\t\t\t\"id\":          4,\n\t\t\t\t\t\t\"passport\":    \"nested2\",\n\t\t\t\t\t\t\"password\":    \"pass_4\",\n\t\t\t\t\t\t\"nickname\":    \"name_4\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn gerror.New(\"rollback nested transaction\")\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Fourth transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err = db.Insert(ctx, table2, g.Map{\n\t\t\t\t\t\"id\":          5,\n\t\t\t\t\t\"passport\":    \"not_supported\",\n\t\t\t\t\t\"password\":    \"pass_5\",\n\t\t\t\t\t\"nickname\":    \"name_5\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tcount, err := db.Model(table1).Where(\"passport\", \"outer\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"new1\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table1).Where(\"passport\", \"nested2\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table2).Where(\"passport\", \"not_supported\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.Transaction(ctx, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t_, err := tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          6,\n\t\t\t\t\"passport\":    \"suspend_outer\",\n\t\t\t\t\"password\":    \"pass6\",\n\t\t\t\t\"nickname\":    \"suspend_outer\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Suspend current transaction (NOT_SUPPORTED)\n\t\t\terr = tx1.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationNotSupported,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\treturn db.Transaction(ctx, func(ctx context.Context, tx3 gdb.TX) error {\n\t\t\t\t\t_, err := tx3.Insert(table, g.Map{\n\t\t\t\t\t\t\"id\":          7,\n\t\t\t\t\t\t\"passport\":    \"independent\",\n\t\t\t\t\t\t\"password\":    \"pass7\",\n\t\t\t\t\t\t\"nickname\":    \"independent\",\n\t\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t\t})\n\t\t\t\t\treturn err\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Resume original transaction\n\t\t\t_, err = tx1.Insert(table, g.Map{\n\t\t\t\t\"id\":          8,\n\t\t\t\t\"passport\":    \"suspend_resume\",\n\t\t\t\t\"password\":    \"pass8\",\n\t\t\t\t\"nickname\":    \"suspend_resume\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\treturn gerror.New(\"rollback outer transaction\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tcount, err := db.Model(table).Where(\"passport IN(?,?)\",\n\t\t\t\"suspend_outer\", \"suspend_resume\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\n\t\tcount, err = db.Model(table).Where(\"passport\", \"independent\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Transaction_ReadOnly(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tReadOnly: true,\n\t\t}, func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err := tx.Update(table, g.Map{\"passport\": \"changed\"}, \"id=1\")\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNE(err, nil)\n\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"user_1\")\n\t})\n}\n\nfunc Test_Transaction_Isolation_ReadCommitted(t *testing.T) {\n\t// PgSQL default isolation level is READ COMMITTED.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelReadCommitted,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\"passport\": \"committed_value\"}, \"id=1\")\n\t\t\t\treturn err\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Should see new value in READ COMMITTED\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), \"committed_value\")\n\t\t\tt.AssertNE(v2.String(), initialValue)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Isolation_RepeatableRead(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelRepeatableRead,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// First read\n\t\t\tv1, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tinitialValue := v1.String()\n\n\t\t\t// Another transaction updates and commits the value\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Update(table, g.Map{\n\t\t\t\t\t\"passport\": \"changed_value\",\n\t\t\t\t}, \"id=1\")\n\t\t\t\tt.AssertNil(err)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Verify the change is visible outside transaction\n\t\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v.String(), \"changed_value\")\n\n\t\t\t// Should still see old value in REPEATABLE READ transaction\n\t\t\tv2, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v2.String(), initialValue)\n\n\t\t\t// Even after multiple reads, should still see the same value\n\t\t\tv3, err := tx1.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(v3.String(), initialValue)\n\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// After transaction ends, should see the committed change\n\t\tv, err := db.Model(table).Where(\"id=1\").Value(\"passport\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"changed_value\")\n\t})\n}\n\nfunc Test_Transaction_Isolation_Serializable(t *testing.T) {\n\t// PgSQL uses SSI (Serializable Snapshot Isolation) for SERIALIZABLE level.\n\t// Concurrent writes to the same data may cause serialization failures.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\terr := db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\tIsolation:   sql.LevelSerializable,\n\t\t}, func(ctx context.Context, tx1 gdb.TX) error {\n\t\t\t// Read all records\n\t\t\t_, err := tx1.Model(table).All()\n\t\t\tt.AssertNil(err)\n\n\t\t\t// Try concurrent insert in another transaction\n\t\t\terr = db.TransactionWithOptions(ctx, gdb.TxOptions{\n\t\t\t\tPropagation: gdb.PropagationRequiresNew,\n\t\t\t\tIsolation:   sql.LevelSerializable,\n\t\t\t}, func(ctx context.Context, tx2 gdb.TX) error {\n\t\t\t\t_, err := tx2.Insert(table, g.Map{\n\t\t\t\t\t\"id\":          1000,\n\t\t\t\t\t\"passport\":    \"new_user\",\n\t\t\t\t\t\"password\":    \"pass_1000\",\n\t\t\t\t\t\"nickname\":    \"name_1000\",\n\t\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t\t})\n\t\t\t\treturn err\n\t\t\t})\n\t\t\t// Note: PostgreSQL SSI may or may not cause serialization failure\n\t\t\t// depending on timing and whether there's an actual conflict.\n\t\t\t// For new rows with unique IDs, it typically succeeds.\n\t\t\t// We only verify the outer transaction completes.\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Transaction_Spread(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tdb.SetDebug(true)\n\tdefer db.SetDebug(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tctx = context.TODO()\n\t\t)\n\t\ttx, err := db.Begin(ctx)\n\t\tt.AssertNil(err)\n\t\terr = db.Transaction(tx.GetCtx(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t_, err = db.Model(table).Ctx(ctx).Data(g.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"passport\":    \"USER_1\",\n\t\t\t\t\"password\":    \"PASS_1\",\n\t\t\t\t\"nickname\":    \"NAME_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t}).Insert()\n\t\t\treturn err\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tall, err := tx.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(all[0][\"id\"], 1)\n\n\t\terr = tx.Rollback()\n\t\tt.AssertNil(err)\n\n\t\tall, err = db.Ctx(ctx).Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 0)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/pgsql_z_unit_upsert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage pgsql_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_FormatUpsert_WithOnDuplicateStr tests FormatUpsert with OnDuplicateStr\nfunc Test_FormatUpsert_WithOnDuplicateStr(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user1\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test Save with OnConflict (upsert)\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user1\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify the update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick\")\n\t})\n}\n\n// Test_FormatUpsert_WithOnDuplicateMap tests FormatUpsert with OnDuplicateMap\nfunc Test_FormatUpsert_WithOnDuplicateMap(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user2\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test OnDuplicate with map - values should be column names to use EXCLUDED.column\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user2\",\n\t\t\t\"password\":    \"newpwd2\",\n\t\t\t\"nickname\":    \"newnick2\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"password\": \"password\",\n\t\t\t\"nickname\": \"nickname\",\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify - values should be from the inserted data\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd2\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick2\")\n\t})\n}\n\n// Test_FormatUpsert_WithCounter tests FormatUpsert with Counter type on numeric column.\n// Note: In PostgreSQL, Counter uses EXCLUDED.column which references the NEW value being inserted,\n// not the current table value. This differs from MySQL's ON DUPLICATE KEY UPDATE behavior.\nfunc Test_FormatUpsert_WithCounter(t *testing.T) {\n\t// Create a special table with numeric id for counter test\n\ttableName := \"t_counter_test\"\n\tdropTable(tableName)\n\t_, err := db.Exec(ctx, `\n\t\tCREATE TABLE `+tableName+` (\n\t\t\tid bigserial PRIMARY KEY,\n\t\t\tcounter_value int NOT NULL DEFAULT 0,\n\t\t\tname varchar(45)\n\t\t)\n\t`)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(tableName).Data(g.Map{\n\t\t\t\"counter_value\": 10,\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Get initial ID\n\t\tone, err := db.Model(tableName).Where(\"name\", \"counter_test\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// Test OnDuplicate with Counter\n\t\t// In PostgreSQL: counter_value = EXCLUDED.counter_value + 5\n\t\t// EXCLUDED.counter_value is the value we're trying to insert (20)\n\t\t// So result = 20 + 5 = 25\n\t\t_, err = db.Model(tableName).Data(g.Map{\n\t\t\t\"id\":            initialId,\n\t\t\t\"counter_value\": 20, // This is the EXCLUDED value\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"counter_value\": &gdb.Counter{\n\t\t\t\tField: \"counter_value\",\n\t\t\t\tValue: 5,\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify: EXCLUDED.counter_value(20) + 5 = 25\n\t\tone, err = db.Model(tableName).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"counter_value\"].Int(), 25)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Counter with negative value (decrement)\n\t\tone, err := db.Model(tableName).Where(\"name\", \"counter_test\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// In PostgreSQL: counter_value = EXCLUDED.counter_value - 3\n\t\t// EXCLUDED.counter_value is 100, so result = 100 - 3 = 97\n\t\t_, err = db.Model(tableName).Data(g.Map{\n\t\t\t\"id\":            initialId,\n\t\t\t\"counter_value\": 100, // This is the EXCLUDED value\n\t\t\t\"name\":          \"counter_test\",\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"counter_value\": &gdb.Counter{\n\t\t\t\tField: \"counter_value\",\n\t\t\t\tValue: -3,\n\t\t\t},\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify: EXCLUDED.counter_value(100) - 3 = 97\n\t\tone, err = db.Model(tableName).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"counter_value\"].Int(), 97)\n\t})\n}\n\n// Test_FormatUpsert_WithRaw tests FormatUpsert with Raw type\nfunc Test_FormatUpsert_WithRaw(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"raw_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Get initial ID\n\t\tone, err := db.Model(table).Where(\"passport\", \"raw_user\").One()\n\t\tt.AssertNil(err)\n\t\tinitialId := one[\"id\"].Int64()\n\n\t\t// Test OnDuplicate with Raw SQL\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          initialId,\n\t\t\t\"passport\":    \"raw_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"password\": gdb.Raw(\"'raw_password'\"),\n\t\t}).Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify\n\t\tone, err = db.Model(table).Where(\"id\", initialId).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"raw_password\")\n\t})\n}\n\n// Test_FormatUpsert_NoOnConflict tests FormatUpsert without OnConflict (should fail)\nfunc Test_FormatUpsert_NoOnConflict(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"no_conflict_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Try Save without OnConflict and without primary key in data - should fail\n\t\t// because driver cannot auto-detect conflict columns when primary key is missing\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t// \"id\":          1,\n\t\t\t\"passport\":    \"no_conflict_user\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Save()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test_FormatUpsert_MultipleConflictKeys tests FormatUpsert with multiple conflict keys\nfunc Test_FormatUpsert_MultipleConflictKeys(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Insert initial data\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"multi_key_user\",\n\t\t\t\"password\":    \"pwd\",\n\t\t\t\"nickname\":    \"nick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Test with multiple conflict keys using only \"id\" which has a unique constraint\n\t\t// Note: Using multiple keys requires a composite unique constraint to exist\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"multi_key_user\",\n\t\t\t\"password\":    \"newpwd\",\n\t\t\t\"nickname\":    \"newnick\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\t// Verify the update\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"].String(), \"newpwd\")\n\t\tt.Assert(one[\"nickname\"].String(), \"newnick\")\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/issues/issue3632.sql",
    "content": "CREATE TABLE \"public\".\"%s\" (\n  \"one\" int8[] NOT NULL,\n  \"two\" text[][] NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/issues/issue3668.sql",
    "content": "CREATE TABLE \"public\".\"%s\" (\n  \"text\" varchar(255) COLLATE \"pg_catalog\".\"default\",\n  \"number\" int4\n);\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/issues/issue3671.sql",
    "content": "CREATE TABLE \"public\".\"%s\"\n(\n    \"one\"   int8[] NOT NULL,\n    \"two\"   text[][] NOT NULL,\n    \"three\" jsonb,\n    \"four\"  json,\n    \"five\"  jsonb\n);\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/issues/issue4033.sql",
    "content": "CREATE TABLE test_enum (\n    id int8 NOT NULL,\n    status int2 DEFAULT 0 NOT NULL,\n    CONSTRAINT test_enum_pk PRIMARY KEY (id)\n);"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/table_with_prefix.sql",
    "content": "DROP TABLE IF EXISTS instance;\nCREATE TABLE instance (\n    f_id SERIAL NOT NULL PRIMARY KEY,\n    name varchar(255) DEFAULT ''\n);\nINSERT INTO instance VALUES (1, 'john');\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/with_multiple_depends.sql",
    "content": "\nCREATE TABLE table_a (\n    id SERIAL PRIMARY KEY,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_a VALUES (1, 'table_a_test1');\nINSERT INTO table_a VALUES (2, 'table_a_test2');\n\nCREATE TABLE table_b (\n    id SERIAL PRIMARY KEY,\n    table_a_id integer NOT NULL,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_b VALUES (10, 1, 'table_b_test1');\nINSERT INTO table_b VALUES (20, 2, 'table_b_test2');\nINSERT INTO table_b VALUES (30, 1, 'table_b_test3');\nINSERT INTO table_b VALUES (40, 2, 'table_b_test4');\n\nCREATE TABLE table_c (\n    id SERIAL PRIMARY KEY,\n    table_b_id integer NOT NULL,\n    alias varchar(255) DEFAULT ''\n);\n\nINSERT INTO table_c VALUES (100, 10, 'table_c_test1');\nINSERT INTO table_c VALUES (200, 10, 'table_c_test2');\nINSERT INTO table_c VALUES (300, 20, 'table_c_test3');\nINSERT INTO table_c VALUES (400, 30, 'table_c_test4');\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/with_tpl_user.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id SERIAL PRIMARY KEY,\n    name varchar(45) NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/with_tpl_user_detail.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    uid SERIAL PRIMARY KEY,\n    address varchar(45) NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/pgsql/testdata/with_tpl_user_scores.sql",
    "content": "CREATE TABLE IF NOT EXISTS %s (\n    id SERIAL PRIMARY KEY,\n    uid integer NOT NULL,\n    score integer NOT NULL\n);\n"
  },
  {
    "path": "contrib/drivers/sqlite/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/sqlite/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/glebarez/go-sqlite v1.21.2\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/dustin/go-humanize v1.0.1 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tmodernc.org/libc v1.22.5 // indirect\n\tmodernc.org/mathutil v1.5.0 // indirect\n\tmodernc.org/memory v1.5.0 // indirect\n\tmodernc.org/sqlite v1.23.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/sqlite/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=\ngithub.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=\ngithub.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nmodernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=\nmodernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=\nmodernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=\nmodernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=\nmodernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=\nmodernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=\nmodernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package sqlite implements gdb.Driver, which supports operations for database SQLite.\npackage sqlite\n\nimport (\n\t_ \"github.com/glebarez/go-sqlite\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Driver is the driver for sqlite database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tquoteChar = \"`\"\n)\n\nfunc init() {\n\tif err := gdb.Register(`sqlite`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for SQLite.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for sqlite.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\t// Special insert/ignore operation for sqlite.\n\tswitch {\n\tcase gstr.HasPrefix(sql, gdb.InsertOperationIgnore):\n\t\tsql = \"INSERT OR IGNORE\" + sql[len(gdb.InsertOperationIgnore):]\n\n\tcase gstr.HasPrefix(sql, gdb.InsertOperationReplace):\n\t\tsql = \"INSERT OR REPLACE\" + sql[len(gdb.InsertOperationReplace):]\n\t}\n\treturn d.Core.DoFilter(ctx, link, sql, args)\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_format_upsert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// FormatUpsert returns SQL clause of type upsert for SQLite.\n// For example: ON CONFLICT (id) DO UPDATE SET ...\nfunc (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInsertOption) (string, error) {\n\tif len(option.OnConflict) == 0 {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter, `Please specify conflict columns`,\n\t\t)\n\t}\n\n\tvar onDuplicateStr string\n\tif option.OnDuplicateStr != \"\" {\n\t\tonDuplicateStr = option.OnDuplicateStr\n\t} else if len(option.OnDuplicateMap) > 0 {\n\t\tfor k, v := range option.OnDuplicateMap {\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tswitch v.(type) {\n\t\t\tcase gdb.Raw, *gdb.Raw:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\tv,\n\t\t\t\t)\n\t\t\tcase gdb.Counter, *gdb.Counter:\n\t\t\t\tvar counter gdb.Counter\n\t\t\t\tswitch value := v.(type) {\n\t\t\t\tcase gdb.Counter:\n\t\t\t\t\tcounter = value\n\t\t\t\tcase *gdb.Counter:\n\t\t\t\t\tcounter = *value\n\t\t\t\t}\n\t\t\t\toperator, columnVal := \"+\", counter.Value\n\t\t\t\tif columnVal < 0 {\n\t\t\t\t\toperator, columnVal = \"-\", -columnVal\n\t\t\t\t}\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s%s%s\",\n\t\t\t\t\td.QuoteWord(k),\n\t\t\t\t\td.QuoteWord(counter.Field),\n\t\t\t\t\toperator,\n\t\t\t\t\tgconv.String(columnVal),\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\td.Core.QuoteWord(gconv.String(v)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, column := range columns {\n\t\t\t// If it's SAVE operation, do not automatically update the creating time.\n\t\t\tif d.Core.IsSoftCreatedFieldName(column) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t)\n\t\t}\n\t}\n\n\tconflictKeys := gstr.Join(option.OnConflict, \",\")\n\n\treturn fmt.Sprintf(\"ON CONFLICT (%s) DO UPDATE SET \", conflictKeys) + onDuplicateStr, nil\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Open creates and returns an underlying sql.DB object for sqlite.\n// https://github.com/glebarez/go-sqlite\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar (\n\t\tsource               string\n\t\tunderlyingDriverName = \"sqlite\"\n\t)\n\tsource = config.Name\n\t// It searches the source file to locate its absolute path..\n\tif absolutePath, _ := gfile.Search(source); absolutePath != \"\" {\n\t\tsource = absolutePath\n\t}\n\t// Multiple PRAGMAs can be specified, e.g.:\n\t// path/to/some.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)\n\tif config.Extra != \"\" {\n\t\tvar (\n\t\t\toptions  string\n\t\t\textraMap map[string]any\n\t\t)\n\t\tif extraMap, err = gstr.Parse(config.Extra); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor k, v := range extraMap {\n\t\t\tif options != \"\" {\n\t\t\t\toptions += \"&\"\n\t\t\t}\n\t\t\toptions += fmt.Sprintf(`_pragma=%s(%s)`, k, gurl.Encode(gconv.String(v)))\n\t\t}\n\t\tif len(options) > 1 {\n\t\t\tsource += \"?\" + options\n\t\t}\n\t}\n\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_order.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\n// OrderRandomFunction returns the SQL function for random ordering.\nfunc (d *Driver) OrderRandomFunction() string {\n\treturn \"RANDOM()\"\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\n//\n// Also see DriverMysql.TableFields.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, d.QuoteWord(table)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tmKey := \"\"\n\t\tif m[\"pk\"].Bool() {\n\t\t\tmKey = \"pri\"\n\t\t}\n\t\tfields[m[\"name\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"name\"].String(),\n\t\t\tType:    m[\"type\"].String(),\n\t\t\tKey:     mKey,\n\t\t\tDefault: m[\"dflt_value\"].Val(),\n\t\t\tNull:    !m[\"notnull\"].Bool(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err = d.DoSelect(ctx, link, tablesSqlTmp)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_z_unit_core_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := gdb.ConfigNode{\n\t\t\tType:    \"sqlite\",\n\t\t\tName:    gfile.Join(dbDir, \"test.db\"),\n\t\t\tCharset: \"utf8\",\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_New_Path_With_Colon(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tdbFilePathWithColon := gfile.Join(dbDir, \"test:1\")\n\t\tif err := gfile.Mkdir(dbFilePathWithColon); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tnode := gdb.ConfigNode{\n\t\t\tType:    \"sqlite\",\n\t\t\tLink:    fmt.Sprintf(`sqlite::@file(%s)`, gfile.Join(dbFilePathWithColon, \"test.db\")),\n\t\t\tCharset: \"utf8\",\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst, err := db.Prepare(ctx, \"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0], \"100\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\ttype User struct {\n\t\t\tId         int    `gconv:\"id\"`\n\t\t\tPassport   string `json:\"passport\"`\n\t\t\tPassword   string `gconv:\"password\"`\n\t\t\tNickname   string `gconv:\"nickname\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tId:         3,\n\t\t\tPassport:   \"user_3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\n\t\t// *struct\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_4\",\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Where(\"id\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 4)\n\t\tt.Assert(one[\"passport\"].String(), \"t4\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_4\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\n\t\t// batch with Insert\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          200,\n\t\t\t\t\"passport\":    \"t200\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d71qw07ad\",\n\t\t\t\t\"nickname\":    \"T200\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          300,\n\t\t\t\t\"passport\":    \"t300\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T300\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"id\", 200).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 200)\n\t\tt.Assert(one[\"passport\"].String(), \"t200\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d71qw07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T200\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_DB_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_DB_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Update(ctx, table, data, \"id=1\")\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.InsertIgnore(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tn, _ = r.LastInsertId()\n\t\tt.Assert(n, 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttype User struct {\n\t\t\tId         int         `c:\"id\"`\n\t\t\tPassport   string      `c:\"passport\"`\n\t\t\tPassword   string      `c:\"password\"`\n\t\t\tNickName   string      `c:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `c:\"create_time\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"t1\",\n\t\t\tPassword:   \"p1\",\n\t\t\tNickName:   \"T1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\tresult, err := db.Insert(ctx, table, user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\t_, err := db.Replace(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t1\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"987654321\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetArray(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.GetArray(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(array), TableSize-1)\n\t\tfor i, v := range array {\n\t\t\tt.Assert(v.Int(), i+2)\n\t\t}\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_DB_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          200,\n\t\t\t\"passport\":    \"t200\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T200\",\n\t\t\t\"create_time\": time.Now(),\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 200)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t200\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := time.Now()\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          300,\n\t\t\t\"passport\":    \"t300\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T300\",\n\t\t\t\"create_time\": &t1,\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 300)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t300\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_DB_ToJson(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := make([]User, 0)\n\n\t\terr = result.Structs(users)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = result.Structs(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\t// ToJson\n\t\tresultJson, err := gjson.LoadContent([]byte(result.Json()))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(users[0].Id, resultJson.Get(\"0.id\").Int())\n\t\tt.Assert(users[0].Passport, resultJson.Get(\"0.passport\").String())\n\t\tt.Assert(users[0].Password, resultJson.Get(\"0.password\").String())\n\t\tt.Assert(users[0].NickName, resultJson.Get(\"0.nickname\").String())\n\t\tt.Assert(users[0].CreateTime, resultJson.Get(\"0.create_time\").String())\n\n\t\tresult = nil\n\t\tt.Assert(result.Structs(&users), sql.ErrNoRows)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := User{}\n\n\t\terr = result.Struct(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult = nil\n\t\terr = result.Struct(&users)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_ToXml(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tuser := User{}\n\t\terr = record.Struct(&user)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult, err := gxml.Decode([]byte(record.Xml(\"doc\")))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultXml := result[\"doc\"].(map[string]any)\n\t\tif v, ok := resultXml[\"id\"]; ok {\n\t\t\tt.Assert(user.Id, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"passport\"]; ok {\n\t\t\tt.Assert(user.Passport, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"password\"]; ok {\n\t\t\tt.Assert(user.Password, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"nickname\"]; ok {\n\t\t\tt.Assert(user.NickName, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"create_time\"]; ok {\n\t\t\tt.Assert(user.CreateTime, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\t})\n}\n\nfunc Test_DB_ToStringMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringMap := result.MapKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultStringMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultStringMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultStringMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultStringMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToIntMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToUintMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintMap := result.MapKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintMap[uint(id)][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultUintMap[uint(id)][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultUintMap[uint(id)][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultUintMap[uint(id)][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultUintMap[uint(id)][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToStringRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tids := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringRecord := result.RecordKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringRecord[ids][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultStringRecord[ids][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultStringRecord[ids][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultStringRecord[ids][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultStringRecord[ids][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToIntRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntRecord := result.RecordKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntRecord[id][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultIntRecord[id][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultIntRecord[id][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultIntRecord[id][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultIntRecord[id][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToUintRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintRecord := result.RecordKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintRecord[uint(id)][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultUintRecord[uint(id)][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultUintRecord[uint(id)][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultUintRecord[uint(id)][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultUintRecord[uint(id)][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_TableField(t *testing.T) {\n\tname := \"field_test\"\n\tdropTable(name)\n\tdefer dropTable(name)\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tfield_tinyint  tinyint(8) NULL ,\n\t\tfield_int  int(8) NULL ,\n\t\tfield_integer  integer(8) NULL ,\n\t\tfield_bigint  bigint(8) NULL ,\n\t\tfield_real  real(8,0) NULL ,\n\t\tfield_double  double(12,2) NULL ,\n\t\tfield_varchar  varchar(10) NULL ,\n\t\tfield_varbinary  varbinary(255) NULL\n\t);\n\t`, name))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tdata := gdb.Map{\n\t\t\"field_tinyint\":   1,\n\t\t\"field_int\":       2,\n\t\t\"field_integer\":   3,\n\t\t\"field_bigint\":    4,\n\t\t\"field_real\":      123,\n\t\t\"field_double\":    123.25,\n\t\t\"field_varchar\":   \"abc\",\n\t\t\"field_varbinary\": \"aaa\",\n\t}\n\tres, err := db.Model(name).Data(data).Insert()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tn, err := res.RowsAffected()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tgtest.Assert(n, 1)\n\t}\n\n\tresult, err := db.Model(name).Fields(\"*\").Where(\"field_int = ?\", 2).All()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tgtest.Assert(result[0], data)\n}\n\nfunc Test_DB_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\tnoPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\ttable := TableNamePrefix + noPrefixName\n\tcreateTableWithDb(db, table)\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Insert(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Replace(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Update(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:03\").String(),\n\t\t}, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Delete(ctx, noPrefixName, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := db.Insert(ctx, noPrefixName, array.Slice())\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InnerJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 5).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 5)\n\n\t\tresult, err := db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 5)\n\n\t\tresult, err = db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ?\", 1).Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 4)\n\t})\n}\n\nfunc Test_Model_LeftJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table2).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t} else {\n\t\t\tt.Assert(n, 7)\n\t\t}\n\n\t\tresult, err := db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ? \", 2).All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 8)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// update counter test.\nfunc Test_DB_UpdateCounter(t *testing.T) {\n\ttableName := \"gf_update_counter_test_\" + gtime.TimestampNanoStr()\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\tviews  int(8) DEFAULT '0'  NOT NULL ,\n\t\tupdated_time int(10) DEFAULT '0' NOT NULL\n\t);\n\t`, tableName))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tinsertData := g.Map{\n\t\t\t\"id\":           1,\n\t\t\t\"views\":        0,\n\t\t\t\"updated_time\": 0,\n\t\t}\n\t\t_, err = db.Insert(ctx, tableName, insertData)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"id\",\n\t\t\tValue: 1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\": gdbCounter,\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"views\",\n\t\t\tValue: -1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\":        gdbCounter,\n\t\t\t\"updated_time\": gtime.Now().Unix(),\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 1)\n\t})\n}\n\nfunc Test_DB_Ctx_Logger(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype TraceId string\n\t\tdefer db.SetDebug(db.GetDebug())\n\t\tdb.SetDebug(true)\n\t\tctx := context.WithValue(context.Background(), TraceId(\"Trace-Id\"), \"123456789\")\n\t\t_, err := db.Query(ctx, \"SELECT 1\")\n\t\tt.AssertNil(err)\n\t})\n}\n\n// All types testing.\n// https://www.sqlite.org/datatype3.html\nfunc Test_Types(t *testing.T) {\n\ttableName := \"types_\" + gtime.TimestampNanoStr()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\t%s blob NOT NULL,\n\t\t%s binary(8) NOT NULL,\n\t\t%s date NOT NULL,\n\t\t%s time NOT NULL,\n\t\t%s timestamp(6) NOT NULL,\n\t\t%s decimal(5,2) NOT NULL,\n\t\t%s double NOT NULL,\n\t\t%s tinyint(1) NOT NULL,\n\t\t%s bool NOT NULL\n\t);\n\t`,\n\t\t\ttableName,\n\t\t\t\"`blob`\",\n\t\t\t\"`binary`\",\n\t\t\t\"`date`\",\n\t\t\t\"`time`\",\n\t\t\t\"`timestamp`\",\n\t\t\t\"`decimal`\",\n\t\t\t\"`double`\",\n\t\t\t\"`tinyint`\",\n\t\t\t\"`bool`\")); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tdefer dropTable(tableName)\n\t\tdata := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"blob\":      \"i love gf\",\n\t\t\t\"binary\":    []byte(\"abcdefgh\"),\n\t\t\t\"date\":      \"1880-10-24\",\n\t\t\t\"time\":      \"10:00:01\",\n\t\t\t\"timestamp\": \"2022-02-14 12:00:01.123456\",\n\t\t\t\"decimal\":   -123.456,\n\t\t\t\"double\":    -123.456,\n\t\t\t\"tinyint\":   true,\n\t\t\t\"bool\":      false,\n\t\t}\n\t\tr, err := db.Model(tableName).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(tableName).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"blob\"].String(), data[\"blob\"])\n\t\tt.Assert(one[\"binary\"].String(), data[\"binary\"])\n\t\tt.Assert(one[\"date\"].String(), data[\"date\"])\n\t\tt.Assert(one[\"time\"].String(), `10:00:01`)\n\t\tt.Assert(one[\"timestamp\"].GTime().Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(one[\"decimal\"].String(), data[\"decimal\"]) // In SQLite, the datatype of a value is associated with the value itself, not with its container.\n\t\tt.Assert(one[\"double\"].String(), data[\"double\"])\n\t\tt.Assert(one[\"tinyint\"].Bool(), data[\"tinyint\"])\n\n\t\ttype T struct {\n\t\t\tId        int\n\t\t\tBlob      []byte\n\t\t\tBinary    []byte\n\t\t\tDate      *gtime.Time\n\t\t\tTime      *gtime.Time\n\t\t\tTimestamp *gtime.Time\n\t\t\tDecimal   float64\n\t\t\tDouble    float64\n\t\t\tBit       int8\n\t\t\tTinyInt   bool\n\t\t}\n\t\tvar obj *T\n\t\terr = db.Model(tableName).Scan(&obj)\n\t\tt.AssertNil(err)\n\t\tt.Assert(obj.Id, 1)\n\t\tt.Assert(obj.Blob, data[\"blob\"])\n\t\tt.Assert(obj.Binary, data[\"binary\"])\n\t\tt.Assert(obj.Date.Format(\"Y-m-d\"), data[\"date\"])\n\t\tt.Assert(obj.Time.String(), `10:00:01`)\n\t\tt.Assert(obj.Timestamp.Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(obj.Decimal, data[\"decimal\"])\n\t\tt.Assert(obj.Double, data[\"double\"])\n\t\tt.Assert(obj.TinyInt, data[\"tinyint\"])\n\t})\n}\n\nfunc Test_TableFields(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"fields_\" + gtime.TimestampNanoStr()\n\t\tcreateTable(tableName)\n\t\tdefer dropTable(tableName)\n\t\tvar expect = map[string][]any{\n\t\t\t// fields\t\ttype\tnull\tkey\tdefault\textra\tcomment\n\t\t\t\"id\":          {\"INTEGER\", false, \"pri\", nil, \"\", \"\"},\n\t\t\t\"passport\":    {\"VARCHAR(45)\", false, \"\", \"passport\", \"\", \"\"},\n\t\t\t\"password\":    {\"VARCHAR(128)\", false, \"\", \"password\", \"\", \"\"},\n\t\t\t\"nickname\":    {\"VARCHAR(45)\", true, \"\", nil, \"\", \"\"},\n\t\t\t\"create_time\": {\"DATETIME\", true, \"\", nil, \"\", \"\"},\n\t\t}\n\n\t\tres, err := db.TableFields(context.Background(), tableName)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[0])\n\t\t\tgtest.AssertEQ(res[k].Null, v[1])\n\t\t\tgtest.AssertEQ(res[k].Key, v[2])\n\t\t\tgtest.AssertEQ(res[k].Default, v[3])\n\t\t\tgtest.AssertEQ(res[k].Extra, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.TableFields(context.Background(), \"t1 t2\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_TableNameIsKeyword(t *testing.T) {\n\ttable := createInitTable(TableNameWhichIsKeyword)\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"create_time\"])\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tdb         gdb.DB\n\tdbPrefix   gdb.DB\n\tdbInvalid  gdb.DB\n\tconfigNode gdb.ConfigNode\n\tdbDir      = gfile.Temp(\"sqlite\")\n\tctx        = gctx.New()\n)\n\nconst (\n\tTableSize               = 10\n\tTableName               = \"user\"\n\tTableNameWhichIsKeyword = \"group\"\n\tTestSchema1             = \"test1\"\n\tTestSchema2             = \"test2\"\n\tTableNamePrefix         = \"gf_\"\n\tCreateTime              = \"2018-10-24 10:00:00\"\n\tDBGroupTest             = \"test\"\n\tDBGroupPrefix           = \"prefix\"\n\tDBGroupInvalid          = \"invalid\"\n)\n\nfunc init() {\n\tfmt.Println(\"init sqlite db start\")\n\n\tif err := gfile.Mkdir(dbDir); err != nil {\n\t\tgtest.Error(err)\n\t}\n\n\tfmt.Println(\"init sqlite db dir: \", dbDir)\n\n\tdbFilePath := gfile.Join(dbDir, \"test.db\")\n\tconfigNode = gdb.ConfigNode{\n\t\tType:    \"sqlite\",\n\t\tLink:    fmt.Sprintf(`sqlite::@file(%s)`, dbFilePath),\n\t\tCharset: \"utf8\",\n\t}\n\tnodePrefix := configNode\n\tnodePrefix.Prefix = TableNamePrefix\n\n\tnodeInvalid := configNode\n\n\tgdb.AddConfigNode(DBGroupTest, configNode)\n\tgdb.AddConfigNode(DBGroupPrefix, nodePrefix)\n\tgdb.AddConfigNode(DBGroupInvalid, nodeInvalid)\n\tgdb.AddConfigNode(gdb.DefaultGroupName, configNode)\n\n\t// Default db.\n\tif r, err := gdb.NewByGroup(); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\t// Prefix db.\n\tif r, err := gdb.NewByGroup(DBGroupPrefix); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbPrefix = r\n\t}\n\n\t// Invalid db.\n\tif r, err := gdb.NewByGroup(DBGroupInvalid); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbInvalid = r\n\t}\n\n\tfmt.Println(\"init sqlite db finish\")\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\t}\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid          INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,\n\t\tpassport    VARCHAR(45)  NOT NULL DEFAULT passport,\n\t\tpassword    VARCHAR(128) NOT NULL DEFAULT password,\n\t\tnickname    VARCHAR(45),\n\t\tcreate_time DATETIME\n\t);\n\t`, db.GetCore().QuoteWord(name),\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/sqlite/sqlite_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlite_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_Model_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         999999,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", data.Id).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Insert_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2020-10-10 20:09:18.334\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], \"2020-10-10 20:09:18\")\n\t\tt.Assert(one[\"nickname\"], data[\"nickname\"])\n\t})\n}\n\nfunc Test_Model_BatchInsertWithArrayStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tarray := garray.New()\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"uid\":         i,\n\t\t\t\t\"passport\":    fmt.Sprintf(\"t%d\", i),\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    fmt.Sprintf(\"name_%d\", i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := user.Data(array).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"uid\":         3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert, retrieving last insert auto-increment id.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\"passport\": \"t1\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t2\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t3\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t4\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t5\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t}).Batch(2).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 5)\n\t})\n\n\t// batch replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t\tv[\"id\"].Set(v[\"id\"].Int() + 100)\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Replace()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t11\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser   User\n\t\t\tcount  int\n\t\t\tresult sql.Result\n\t\t\terr    error\n\t\t)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"CN\",\n\t\t\t\"password\":    \"12345678\",\n\t\t\t\"nickname\":    \"oldme\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Id, 1)\n\t\tt.Assert(user.Passport, \"CN\")\n\t\tt.Assert(user.Password, \"12345678\")\n\t\tt.Assert(user.NickName, \"oldme\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"CN\",\n\t\t\t\"password\":    \"abc123456\",\n\t\t\t\"nickname\":    \"to be not to be\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"CN\")\n\t\tt.Assert(user.Password, \"abc123456\")\n\t\tt.Assert(user.NickName, \"to be not to be\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\n\t\tcount, err = db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// UPDATE...LIMIT\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tresult, err := db.Model(table).Data(\"nickname\", \"T100\").Where(1).Limit(2).Update()\n\t// \tt.AssertNil(err)\n\t// \tn, _ := result.RowsAffected()\n\t// \tt.Assert(n, 2)\n\n\t// \tv1, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 10).Value()\n\t// \tt.AssertNil(err)\n\t// \tt.Assert(v1.String(), \"T100\")\n\n\t// \tv2, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 8).Value()\n\t// \tt.AssertNil(err)\n\t// \tt.Assert(v2.String(), \"name_8\")\n\t// })\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_UpdateAndGetAffected(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn, err := db.Model(table).Data(\"nickname\", \"T100\").\n\t\t\tWhere(1).\n\t\t\tUpdateAndGetAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := md.Safe(true).Order(\"id DESC\").One()\n\t\tt.AssertNil(err)\n\n\t\tresult, err := md.Safe(true).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(2))\n\t\tt.Assert(record[\"id\"].Int(), 3)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Safe(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(false).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe().Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd1 := db.Model(table).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmd1 := db.Model(table).Where(\"id>\", 0).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tmd3 := md1.Where(\"id in (?)\", g.Slice{4, 5, 6})\n\n\t\t// 1,3\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 3)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// 4,5,6\n\t\tcount, err = md3.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\tall, err = md3.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"].Int(), 4)\n\t\tt.Assert(all[1][\"id\"].Int(), 5)\n\t\tt.Assert(all[2][\"id\"].Int(), 6)\n\n\t\tall, err = md3.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_AllAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// AllAndCount with all data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\n\t// AllAndCount with no data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id<0\").AllAndCount(false)\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n\t// AllAndCount with page\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(count, TableSize)\n\t})\n\t// AllAndCount with normal result\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id=?\", 1).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(result[0][\"passport\"], \"user_1\")\n\t})\n\t// AllAndCount with distinct\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"DISTINCT nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(result[0][\"nickname\"], \"name_1\")\n\t\tt.AssertNil(result[0][\"id\"])\n\t})\n\t// AllAndCount with Join\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, count, err := db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t\tt.Assert(count, 1)\n\t})\n\t// AllAndCount with Join and multiple fields\n\t// Regression test for #4698 - should use COUNT(1) not COUNT(field1, field2, ...)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, count, err := db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Fields(t *testing.T) {\n\ttableName1 := createInitTable()\n\tdefer dropTable(tableName1)\n\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u\").Fields(\"u.passport,u.id\").Where(\"u.id<2\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName1, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.id AS u2id\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Struct_CustomType(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype MyInt int\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         MyInt\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Structs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// Auto create struct slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Where(\"id<0\").Scan(&users)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_StructsWithOrmTag(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\ttype User struct {\n\t\t\tUid      int `orm:\"id\"`\n\t\t\tPassport string\n\t\t\tPassword string     `orm:\"password\"`\n\t\t\tName     string     `orm:\"nickname\"`\n\t\t\tTime     gtime.Time `orm:\"create_time\"`\n\t\t}\n\t\tvar (\n\t\t\tusers  []User\n\t\t\tbuffer = bytes.NewBuffer(nil)\n\t\t)\n\t\tdb.GetLogger().(*glog.Logger).SetWriter(buffer)\n\t\tdefer db.GetLogger().(*glog.Logger).SetWriter(os.Stdout)\n\t\tdb.Model(table).Order(\"id asc\").Scan(&users)\n\t\t// fmt.Println(buffer.String())\n\t\tt.Assert(\n\t\t\tgstr.Contains(buffer.String(), \"SELECT `id`,`passport`,`password`,`nickname`,`create_time` FROM `user\"),\n\t\t\ttrue,\n\t\t)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t}\n\t\ttype B struct {\n\t\t\tA\n\t\t\tNickName string\n\t\t}\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_ScanAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// ScanAndCount with normal struct result\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id=1\").ScanAndCount(user, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t\tt.Assert(count, 1)\n\t})\n\t// ScanAndCount with normal array result\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Order(\"id asc\").ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t\tt.Assert(count, len(users))\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\tvar count1 int\n\t\tvar count2 int\n\t\terr1 := db.Model(table).Where(\"id < 0\").ScanAndCount(user, &count1, true)\n\t\terr2 := db.Model(table).Where(\"id < 0\").ScanAndCount(users, &count2, true)\n\t\tt.Assert(count1, 0)\n\t\tt.Assert(count2, 0)\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n\t// ScanAndCount with page\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Order(\"id asc\").Page(1, 3).ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(count, TableSize)\n\t})\n\t// ScanAndCount with distinct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).Fields(\"distinct id\").ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 10)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n\t// ScanAndCount with join\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tName     string\n\t\t\tAge      int\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 1)\n\t\tt.Assert(count, 1)\n\t\tt.AssertEQ(users[0].Name, \"table2_1\")\n\t})\n\t// ScanAndCount with join return CodeDbOperationError\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tName     string\n\t\t\tAge      int\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tScanAndCount(&users, &count, true)\n\t\t// Regression test for #4698 - should use COUNT(1) not COUNT(field1, field2, ...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 1)\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\ttype Response struct {\n\t\t\tUsers []User `json:\"users\"`\n\t\t}\n\t\tvar res Response\n\t\terr := db.Model(table).Scan(&res.Users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(res.Users, nil)\n\t})\n}\n\nfunc Test_Model_OrderBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(\"id DESC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), fmt.Sprintf(\"name_%d\", TableSize))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"NULL\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n\n}\n\nfunc Test_Model_GroupBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Group(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_Model_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(\"nickname=?\", \"test\").Where(\"id=?\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := make([]g.MapStrAny, 0)\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers = append(users, g.MapStrAny{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := garray.New()\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers.Append(g.MapStrAny{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_1(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_2(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// complicated one.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\t// table := createInitTable()\n\t// defer dropTable(table)\n\n\t// DELETE...LIMIT\n\t// https://github.com/mattn/go-sqlite3/pull/802\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tresult, err := db.Model(table).Where(1).Limit(2).Delete()\n\t// \tt.AssertNil(err)\n\t// \tn, _ := result.RowsAffected()\n\t// \tt.Assert(n, 2)\n\t// })\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Offset(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(2).Offset(5).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(3, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t\tt.Assert(result[1][\"id\"], 8)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel := db.Model(table).Safe().Order(\"id\")\n\t\tall, err := model.Page(3, 3).All()\n\t\tt.AssertNil(err)\n\t\tcount, err := model.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], \"7\")\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Option_Map(t *testing.T) {\n\t// Insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, passport\", \"password\", \"create_time\").Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"1\",\n\t\t\t\"password\":    \"1\",\n\t\t\t\"nickname\":    \"1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"password\"].String(), \"2\")\n\t\tt.AssertNE(one[\"nickname\"].String(), \"2\")\n\t\tt.Assert(one[\"passport\"].String(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"1\",\n\t\t\t\"password\":    \"1\",\n\t\t\t\"nickname\":    \"\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"\")\n\t})\n\n\t// Replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\t})\n\n\t// Update\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tr, err := db.Model(table).Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmptyData().Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 2).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmpty().Fields(\"nickname\").Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 4).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().\n\t\t\tFields(\"password\").Data(g.Map{\n\t\t\t\"nickname\": \"\",\n\t\t\t\"passport\": \"123\",\n\t\t\t\"password\": \"456\",\n\t\t}).Where(\"id\", 5).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 5).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"], \"456\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"123\")\n\t})\n}\n\nfunc Test_Model_Option_Where(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 0, \"passport\": \"\"}).Where(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_FieldsEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, id\").Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(len(r[0]), 3)\n\t\tt.Assert(r[0][\"id\"], \"\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[0][\"password\"], \"pass_1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"create_time\"], \"\")\n\t\tt.Assert(r[1][\"id\"], \"\")\n\t\tt.Assert(r[1][\"passport\"], \"user_2\")\n\t\tt.Assert(r[1][\"password\"], \"pass_2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"create_time\"], \"\")\n\t})\n\t// Update.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"password\").Data(g.Map{\"nickname\": \"123\", \"password\": \"456\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"123\")\n\t\tt.AssertNE(one[\"password\"], \"456\")\n\t})\n}\n\nfunc Test_Model_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\tnoPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\ttable := TableNamePrefix + noPrefixName\n\tcreateInitTableWithDb(db, table)\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName).Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName+\" as u\").Where(\"u.id in (?)\", g.Slice{1, 2}).Order(\"u.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias to struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickName string\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(noPrefixName+\" u\").Where(\"u.id in (?)\", g.Slice{1, 5}).Order(\"u.id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 5)\n\t})\n\t// Select with alias and join statement.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName+\" as u1\").LeftJoin(noPrefixName+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName).As(\"u1\").LeftJoin(noPrefixName+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_FieldsExStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"passport\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tNickName string    `orm:\"nickname\" json:\"nick__name\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tNickName: \"333\",\n\t\t\tTime:     time.Now(),\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"nickname\").OmitEmpty().Data(user).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"passport\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tNickName string    `orm:\"nickname\" json:\"nick__name\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tusers := make([]*User, 0)\n\t\tfor i := 100; i < 110; i++ {\n\t\t\tusers = append(users, &User{\n\t\t\t\tId:       i,\n\t\t\t\tPassport: fmt.Sprintf(`passport_%d`, i),\n\t\t\t\tPassword: fmt.Sprintf(`password_%d`, i),\n\t\t\t\tNickName: fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\tTime:     time.Now(),\n\t\t\t})\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"nickname\").\n\t\t\tOmitEmpty().\n\t\t\tBatch(2).\n\t\t\tData(users).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_OmitEmpty_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tTime:     time.Time{},\n\t\t}\n\t\tr, err := db.Model(table).OmitEmpty().Data(user).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Result_Chunk(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tchunks := r.Chunk(3)\n\t\tt.Assert(len(chunks), 4)\n\t\tt.Assert(chunks[0][0][\"id\"].Int(), 1)\n\t\tt.Assert(chunks[1][0][\"id\"].Int(), 4)\n\t\tt.Assert(chunks[2][0][\"id\"].Int(), 7)\n\t\tt.Assert(chunks[3][0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_DryRun(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.SetDryRun(true)\n\tdefer db.SetDryRun(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Data(\"passport\", \"port_1\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_Model_Join_SubQuery(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery := fmt.Sprintf(\"select * from `%s`\", table)\n\t\tr, err := db.Model(table, \"t1\").Fields(\"t2.id\").LeftJoin(subQuery, \"t2\", \"t2.id=t1.id\").Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), TableSize)\n\t\tt.Assert(r[0], \"1\")\n\t\tt.Assert(r[TableSize-1], TableSize)\n\t})\n}\n\nfunc Test_Model_Cache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_100\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\ttime.Sleep(time.Second * 2)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_100\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_200\").Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_200\")\n\t})\n\t// transaction.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 3\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_300\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test3\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(3).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_300\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 4\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_400\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Cache feature disabled.\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test4\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(4).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_400\")\n\t\t\t// Update the cache.\n\t\t\tr, err := tx.Model(table).Data(\"passport\", \"user_4000\").\n\t\t\t\tCache(gdb.CacheOption{\n\t\t\t\t\tDuration: -1,\n\t\t\t\t\tName:     \"test4\",\n\t\t\t\t\tForce:    false,\n\t\t\t\t}).WherePri(4).Update()\n\t\t\tt.AssertNil(err)\n\t\t\tn, err := r.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(n, 1)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Read from db.\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4000\")\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Group(\"id\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Group(\"id\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Group(\"id\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Group(\"id\").Having(\"id\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table, \"t\").Fields(\"distinct t.id\").Where(\"id > 1\").Group(\"id\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n\nfunc Test_Model_Fields_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"ID\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICK_NAME\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":        1,\n\t\t\t\"NICK_NAME\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tID       int\n\t\t\tNICKNAME int\n\t\t}\n\t\tone, err := db.Model(table).Fields(&T{\n\t\t\tID:       0,\n\t\t\tNICKNAME: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_FieldsEx_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// \"id\":          i,\n\t// \"passport\":    fmt.Sprintf(`user_%d`, i),\n\t// \"password\":    fmt.Sprintf(`pass_%d`, i),\n\t// \"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t// \"create_time\": gtime.NewFromStr(CreateTime).String(),\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"Passport, Password, NickName, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"ID, Passport, Password, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).FieldsEx(g.Map{\n\t\t\t\"Passport\":   1,\n\t\t\t\"Password\":   1,\n\t\t\t\"CreateTime\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tPassport   int\n\t\t\tPassword   int\n\t\t\tCreateTime int\n\t\t}\n\t\tone, err := db.Model(table).FieldsEx(&T{\n\t\t\tPassport:   0,\n\t\t\tPassword:   0,\n\t\t\tCreateTime: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_Fields_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype A struct {\n\t\tPassport string\n\t\tPassword string\n\t}\n\ttype B struct {\n\t\tA\n\t\tNickName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(table)\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Issue: https://github.com/gogf/gf/issues/1002\nfunc Test_Model_Issue1002(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tresult, err := db.Model(table).Data(g.Map{\n\t\t\"id\":          1,\n\t\t\"passport\":    \"port_1\",\n\t\t\"password\":    \"pass_1\",\n\t\t\"nickname\":    \"name_2\",\n\t\t\"create_time\": \"2020-10-27 19:03:33\",\n\t}).Insert()\n\tgtest.AssertNil(err)\n\tn, _ := result.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// where + string.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + string arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", \"2020-10-27 19:03:32\", \"2020-10-27 19:03:34\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + gtime.Time arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", gtime.New(\"2020-10-27 19:03:32\"), gtime.New(\"2020-10-27 19:03:34\")).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// TODO\n\t// where + time.Time arguments, UTC.\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tt1, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:32\")\n\t// \tt2, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:34\")\n\t// \t{\n\t// \t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", t1, t2).Value()\n\t// \t\tt.AssertNil(err)\n\t// \t\tt.Assert(v.Int(), 1)\n\t// \t}\n\t// })\n}\n\nfunc createTableForTimeZoneTest() string {\n\ttableName := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\tpassport    varchar(45) NULL,\n\t\tpassword    char(32) NULL,\n\t\tnickname    varchar(45) NULL,\n\t\tcreated_at timestamp NULL,\n\t\tupdated_at timestamp NULL,\n\t\tdeleted_at timestamp NULL\n\t);\n\t`, tableName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn tableName\n}\n\n// https://github.com/gogf/gf/issues/1012\nfunc Test_TimeZoneInsert(t *testing.T) {\n\ttableName := createTableForTimeZoneTest()\n\tdefer dropTable(tableName)\n\n\ttokyoLoc, err := time.LoadLocation(\"Asia/Tokyo\")\n\tgtest.AssertNil(err)\n\n\tCreateTime := \"2020-11-22 12:23:45\"\n\tUpdateTime := \"2020-11-22 13:23:45\"\n\tDeleteTime := \"2020-11-22 14:23:45\"\n\ttype User struct {\n\t\tId        int         `json:\"id\"`\n\t\tCreatedAt *gtime.Time `json:\"created_at\"`\n\t\tUpdatedAt gtime.Time  `json:\"updated_at\"`\n\t\tDeletedAt time.Time   `json:\"deleted_at\"`\n\t}\n\tt1, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", CreateTime, tokyoLoc)\n\tt2, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", UpdateTime, tokyoLoc)\n\tt3, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", DeleteTime, tokyoLoc)\n\tu := &User{\n\t\tId:        1,\n\t\tCreatedAt: gtime.New(t1.UTC()),\n\t\tUpdatedAt: *gtime.New(t2.UTC()),\n\t\tDeletedAt: t3.UTC(),\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, _ = db.Model(tableName).Unscoped().Insert(u)\n\t\tuserEntity := &User{}\n\t\terr := db.Model(tableName).Where(\"id\", 1).Unscoped().Scan(&userEntity)\n\t\tt.AssertNil(err)\n\t\t// TODO\n\t\t// t.Assert(userEntity.CreatedAt.String(), \"2020-11-22 11:23:45\")\n\t\t// t.Assert(userEntity.UpdatedAt.String(), \"2020-11-22 12:23:45\")\n\t\t// t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), \"2020-11-22 13:23:45\")\n\t})\n}\n\nfunc Test_Model_Fields_Map_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":         1,\n\t\t\t\"PASSPORT\":   1,\n\t\t\t\"NONE_EXIST\": 1,\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[\"id\"], 1)\n\t\tt.Assert(result[\"passport\"], \"user_1\")\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\ta := A{}\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// *struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// **struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(&a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Min_Max_Avg_Sum(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 5.5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 55)\n\t})\n}\n\nfunc Test_Model_CountColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 3)\n\t})\n}\n\nfunc Test_Model_InsertAndGetId(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 2)\n\t})\n}\n\nfunc Test_Model_Increment_Decrement(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 1).Increment(\"id\", 100)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 101).Decrement(\"id\", 10)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 91).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 7)\n\t\tt.Assert(all[1][\"id\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.\n\t\t// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)\n\t\t// WhereLT(\"id\", 8): id < 8 -> (1, 5, 7)\n\t\t// WhereIn(\"id\", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)\n\t\t// Result: 3 records match all conditions\n\t\tt.Assert(count, int64(3))\n\t})\n}\n\nfunc Test_Model_Handler(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Safe().Handler(\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Page(0, 3)\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Where(\"id\", g.Slice{1, 2, 3, 4, 5, 6})\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.OrderDesc(\"id\")\n\t\t\t},\n\t\t)\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], 6)\n\t\tt.Assert(all[2][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_FieldCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldCount(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMax(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMin(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldAvg(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldAvg(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_OmitEmptyWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Basic type where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Where(\"nickname\", \"\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Slice where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Struct Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Map Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       []int{},\n\t\t\t\"nickname\": []string{},\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1387\nfunc Test_Model_GTime_DefaultValue(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\t// Insert\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Select\n\t\tvar (\n\t\t\tuser *User\n\t\t)\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, data.Passport)\n\t\tt.Assert(user.Password, data.Password)\n\t\tt.Assert(user.CreateTime, data.CreateTime)\n\t\tt.Assert(user.Nickname, data.Nickname)\n\n\t\t// Insert\n\t\tuser.Id = 2\n\t\t_, err = db.Model(table).Data(user).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Using filter does not affect the outside value inside function.\nfunc Test_Model_Insert_Filter(t *testing.T) {\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tt.Assert(data[\"uid\"], 1)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.List{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"uid\":         1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}\n\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tt.Assert(data[0][\"uid\"], 1)\n\t\tt.Assert(data[1][\"uid\"], 2)\n\t})\n}\n\nfunc Test_Model_Embedded_Filter(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int\n\t\t\tUid        int\n\t\t\tCreateTime string\n\t\t\tNoneExist  string\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tUid:        100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tvar user *User\n\t\terr = db.Model(table).Fields(user).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"john-test\")\n\t\tt.Assert(user.Id, 100)\n\t})\n}\n\n// This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0.\nfunc Test_Model_Insert_KeyFieldNameMapping_Error(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId             int\n\t\t\tPassport       string\n\t\t\tPassword       string\n\t\t\tNickname       string\n\t\t\tCreateTime     string\n\t\t\tNoneExistField string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\ttable1 := \"user\"\n\t\ttable2 := \"score\"\n\t\ttable3 := \"info\"\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tname varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t\t`, table1,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table1)\n\t\t_, err = db.Model(table1).Insert(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t\tnumber varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t    `, table2,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\t\t_, err = db.Model(table2).Insert(g.Map{\n\t\t\t\"id\":      1,\n\t\t\t\"user_id\": 1,\n\t\t\t\"number\":  \"n\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t\tdescription varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t\t`, table3,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table3)\n\t\t_, err = db.Model(table3).Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"user_id\":     1,\n\t\t\t\"description\": \"brief\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(\"user\").\n\t\t\tWhere(\"user.id\", 1).\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tOrder(\"user.id asc\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\n\t\tone, err = db.Model(\"user\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne *S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_StructAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  *S1\n\t\t\tMany []*S2\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  S1\n\t\t\tMany []S2\n\t\t}\n\t\tvar (\n\t\t\ts   []S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\nfunc TestResult_Structs1(t *testing.T) {\n\ttype A struct {\n\t\tId int `orm:\"id\"`\n\t}\n\ttype B struct {\n\t\t*A\n\t\tName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gdb.Result{\n\t\t\tgdb.Record{\"id\": gvar.New(nil), \"name\": gvar.New(\"john\")},\n\t\t\tgdb.Record{\"id\": gvar.New(nil), \"name\": gvar.New(\"smith\")},\n\t\t}\n\t\tarray := make([]*B, 2)\n\t\terr := r.Structs(&array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0].Id, 0)\n\t\tt.Assert(array[1].Id, 0)\n\t\tt.Assert(array[0].Name, \"john\")\n\t\tt.Assert(array[1].Name, \"smith\")\n\t})\n}\n\nfunc Test_OrderRandom(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OrderRandom().All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_OnDuplicateWithCounter(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"id\": gdb.Counter{Field: \"id\", Value: 999999},\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(one)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/sqlitecgo/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/mattn/go-sqlite3 v1.14.17\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=\ngithub.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package sqlitecgo implements gdb.Driver, which supports operations for database SQLite.\n//\n// Note:\n//  1. Using sqlitecgo is for building a 32-bit Windows operating system\n//  2. You need to set the environment variable CGO_ENABLED=1 and make sure that GCC is installed\n//     on your path. windows gcc: https://jmeubank.github.io/tdm-gcc/\npackage sqlitecgo\n\nimport (\n\t_ \"github.com/mattn/go-sqlite3\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\n// Driver is the driver for sqlite database.\ntype Driver struct {\n\t*gdb.Core\n}\n\nconst (\n\tquoteChar = \"`\"\n)\n\nfunc init() {\n\tif err := gdb.Register(`sqlite`, New()); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New create and returns a driver that implements gdb.Driver, which supports operations for SQLite.\nfunc New() gdb.Driver {\n\treturn &Driver{}\n}\n\n// New creates and returns a database object for sqlite.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\treturn &Driver{\n\t\tCore: core,\n\t}, nil\n}\n\n// GetChars returns the security char for this type of database.\nfunc (d *Driver) GetChars() (charLeft string, charRight string) {\n\treturn quoteChar, quoteChar\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_do_filter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DoFilter deals with the sql string before commits it to underlying sql driver.\nfunc (d *Driver) DoFilter(\n\tctx context.Context, link gdb.Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\t// Special insert/ignore operation for sqlite.\n\tswitch {\n\tcase gstr.HasPrefix(sql, gdb.InsertOperationIgnore):\n\t\tsql = \"INSERT OR IGNORE\" + sql[len(gdb.InsertOperationIgnore):]\n\n\tcase gstr.HasPrefix(sql, gdb.InsertOperationReplace):\n\t\tsql = \"INSERT OR REPLACE\" + sql[len(gdb.InsertOperationReplace):]\n\t}\n\treturn d.Core.DoFilter(ctx, link, sql, args)\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_format_upsert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// FormatUpsert returns SQL clause of type upsert for SQLite.\n// For example: ON CONFLICT (id) DO UPDATE SET ...\nfunc (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInsertOption) (string, error) {\n\tif len(option.OnConflict) == 0 {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter, `Please specify conflict columns`,\n\t\t)\n\t}\n\n\tvar onDuplicateStr string\n\tif option.OnDuplicateStr != \"\" {\n\t\tonDuplicateStr = option.OnDuplicateStr\n\t} else if len(option.OnDuplicateMap) > 0 {\n\t\tfor k, v := range option.OnDuplicateMap {\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tswitch v.(type) {\n\t\t\tcase gdb.Raw, *gdb.Raw:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\tv,\n\t\t\t\t)\n\t\t\tcase gdb.Counter, *gdb.Counter:\n\t\t\t\tvar counter gdb.Counter\n\t\t\t\tswitch value := v.(type) {\n\t\t\t\tcase gdb.Counter:\n\t\t\t\t\tcounter = value\n\t\t\t\tcase *gdb.Counter:\n\t\t\t\t\tcounter = *value\n\t\t\t\t}\n\t\t\t\toperator, columnVal := \"+\", counter.Value\n\t\t\t\tif columnVal < 0 {\n\t\t\t\t\toperator, columnVal = \"-\", -columnVal\n\t\t\t\t}\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s%s%s\",\n\t\t\t\t\td.QuoteWord(k),\n\t\t\t\t\td.QuoteWord(counter.Field),\n\t\t\t\t\toperator,\n\t\t\t\t\tgconv.String(columnVal),\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\t\td.Core.QuoteWord(k),\n\t\t\t\t\td.Core.QuoteWord(gconv.String(v)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, column := range columns {\n\t\t\t// If it's SAVE operation, do not automatically update the creating time.\n\t\t\tif d.Core.IsSoftCreatedFieldName(column) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\"%s=EXCLUDED.%s\",\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t\td.Core.QuoteWord(column),\n\t\t\t)\n\t\t}\n\t}\n\n\tconflictKeys := gstr.Join(option.OnConflict, \",\")\n\n\treturn fmt.Sprintf(\"ON CONFLICT (%s) DO UPDATE SET \", conflictKeys) + onDuplicateStr, nil\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_open.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package sqlitecgo implements gdb.Driver, which supports operations for database SQLite.\n//\n// Note:\n//  1. Using sqlitecgo is for building a 32-bit Windows operating system\n//  2. You need to set the environment variable CGO_ENABLED=1 and make sure that GCC is installed\n//     on your path. windows gcc: https://jmeubank.github.io/tdm-gcc/\npackage sqlitecgo\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Open creates and returns an underlying sql.DB object for sqlite.\n// https://github.com/mattn/go-sglite3\nfunc (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {\n\tvar (\n\t\tsource               string\n\t\tunderlyingDriverName = \"sqlite3\"\n\t)\n\tsource = config.Name\n\t// It searches the source file to locate its absolute path..\n\tif absolutePath, _ := gfile.Search(source); absolutePath != \"\" {\n\t\tsource = absolutePath\n\t}\n\n\t// Multiple PRAGMAs can be specified, e.g.:\n\t// path/to/some.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)\n\tif config.Extra != \"\" {\n\t\tvar (\n\t\t\toptions  string\n\t\t\textraMap map[string]any\n\t\t)\n\t\tif extraMap, err = gstr.Parse(config.Extra); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor k, v := range extraMap {\n\t\t\tif options != \"\" {\n\t\t\t\toptions += \"&\"\n\t\t\t}\n\t\t\toptions += fmt.Sprintf(`_pragma=%s(%s)`, k, gurl.Encode(gconv.String(v)))\n\t\t}\n\t\tif len(options) > 1 {\n\t\t\tsource += \"?\" + options\n\t\t}\n\t}\n\n\tif db, err = sql.Open(underlyingDriverName, source); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeDbOperationError, err,\n\t\t\t`sql.Open failed for driver \"%s\" by source \"%s\"`, underlyingDriverName, source,\n\t\t)\n\t\treturn nil, err\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_table_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package sqlitecgo implements gdb.Driver, which supports operations for database SQLite.\n//\n// Note:\n//  1. Using sqlitecgo is for building a 32-bit Windows operating system\n//  2. You need to set the environment variable CGO_ENABLED=1 and make sure that GCC is installed\n//     on your path. windows gcc: https://jmeubank.github.io/tdm-gcc/\npackage sqlitecgo\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// TableFields retrieves and returns the fields' information of specified table of current schema.\n//\n// Also see DriverMysql.TableFields.\nfunc (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {\n\tvar (\n\t\tresult     gdb.Result\n\t\tlink       gdb.Link\n\t\tusedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)\n\t)\n\tif link, err = d.SlaveLink(usedSchema); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, d.QuoteWord(table)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfields = make(map[string]*gdb.TableField)\n\tfor i, m := range result {\n\t\tmKey := \"\"\n\t\tif m[\"pk\"].Bool() {\n\t\t\tmKey = \"pri\"\n\t\t}\n\t\tfields[m[\"name\"].String()] = &gdb.TableField{\n\t\t\tIndex:   i,\n\t\t\tName:    m[\"name\"].String(),\n\t\t\tType:    m[\"type\"].String(),\n\t\t\tKey:     mKey,\n\t\t\tDefault: m[\"dflt_value\"].Val(),\n\t\t\tNull:    !m[\"notnull\"].Bool(),\n\t\t}\n\t}\n\treturn fields, nil\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_tables.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n)\n\nconst (\n\ttablesSqlTmp = `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`\n)\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tvar result gdb.Result\n\tlink, err := d.SlaveLink(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err = d.DoSelect(ctx, link, tablesSqlTmp)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, m := range result {\n\t\tfor _, v := range m {\n\t\t\ttables = append(tables, v.String())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_z_unit_core_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := gdb.ConfigNode{\n\t\t\tType:    \"sqlite\",\n\t\t\tName:    gfile.Join(dbDir, \"test.db\"),\n\t\t\tCharset: \"utf8\",\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_New_Path_With_Colon(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tdbFilePathWithColon := gfile.Join(dbDir, \"test:1\")\n\t\tif err := gfile.Mkdir(dbFilePathWithColon); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tnode := gdb.ConfigNode{\n\t\t\tType:    \"sqlite\",\n\t\t\tLink:    fmt.Sprintf(`sqlite::@file(%s)`, gfile.Join(dbFilePathWithColon, \"test.db\")),\n\t\t\tCharset: \"utf8\",\n\t\t}\n\t\tnewDb, err := gdb.New(node)\n\t\tt.AssertNil(err)\n\t\tvalue, err := newDb.GetValue(ctx, `select 1`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `1`)\n\t\tt.AssertNil(newDb.Close(ctx))\n\t})\n}\n\nfunc Test_DB_Ping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := db.PingMaster()\n\t\terr2 := db.PingSlave()\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_DB_Query(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Query(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", 1, 2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = db.Query(ctx, \"SELECT ?+?\", g.Slice{1, 2})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Exec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Exec(ctx, \"SELECT ?\", 1)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Prepare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst, err := db.Prepare(ctx, \"SELECT 100\")\n\t\tt.AssertNil(err)\n\n\t\trows, err := st.Query()\n\t\tt.AssertNil(err)\n\n\t\tarray, err := rows.Columns()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0], \"100\")\n\n\t\terr = rows.Close()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// normal map\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t// struct\n\t\ttype User struct {\n\t\t\tId         int    `gconv:\"id\"`\n\t\t\tPassport   string `json:\"passport\"`\n\t\t\tPassword   string `gconv:\"password\"`\n\t\t\tNickname   string `gconv:\"nickname\"`\n\t\t\tCreateTime string `json:\"create_time\"`\n\t\t}\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, User{\n\t\t\tId:         3,\n\t\t\tPassport:   \"user_3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\n\t\t// *struct\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tresult, err = db.Insert(ctx, table, &User{\n\t\t\tId:         4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_4\",\n\t\t\tCreateTime: timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Where(\"id\", 4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 4)\n\t\tt.Assert(one[\"passport\"].String(), \"t4\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_4\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\n\t\t// batch with Insert\n\t\ttimeStr = gtime.New(\"2024-10-01 12:01:01\").String()\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          200,\n\t\t\t\t\"passport\":    \"t200\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d71qw07ad\",\n\t\t\t\t\"nickname\":    \"T200\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          300,\n\t\t\t\t\"passport\":    \"t300\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"T300\",\n\t\t\t\t\"create_time\": timeStr,\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tone, err = db.Model(table).Where(\"id\", 200).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 200)\n\t\tt.Assert(one[\"passport\"].String(), \"t200\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d71qw07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T200\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_DB_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_DB_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Insert(ctx, table, data)\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Update(ctx, table, data, \"id=1\")\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_DB_InsertIgnore(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.InsertIgnore(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_DB_BatchInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Insert(ctx, table, g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\n\t\tn, _ = r.LastInsertId()\n\t\tt.Assert(n, 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\t// []any\n\t\tr, err := db.Insert(ctx, table, g.Slice{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"passport\":    \"user_3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"T1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_BatchInsert_Struct(t *testing.T) {\n\t// batch insert struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\n\t\ttype User struct {\n\t\t\tId         int         `c:\"id\"`\n\t\t\tPassport   string      `c:\"passport\"`\n\t\t\tPassword   string      `c:\"password\"`\n\t\t\tNickName   string      `c:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `c:\"create_time\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"t1\",\n\t\t\tPassword:   \"p1\",\n\t\t\tNickName:   \"T1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\tresult, err := db.Insert(ctx, table, user)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_DB_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcreateTable(\"t_user\")\n\t\tdefer dropTable(\"t_user\")\n\n\t\ti := 10\n\t\tdata := g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`t%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`p%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`T%d`, i),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Save(ctx, \"t_user\", data, 10)\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := gtime.New(\"2024-10-01 12:01:01\").String()\n\t\t_, err := db.Replace(ctx, table, g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": timeStr,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t1\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), timeStr)\n\t})\n}\n\nfunc Test_DB_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Update(ctx, table, \"password='987654321'\", \"id=3\")\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t\tt.Assert(one[\"passport\"].String(), \"user_3\")\n\t\tt.Assert(one[\"password\"].String(), \"987654321\")\n\t\tt.Assert(one[\"nickname\"].String(), \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetAll(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), g.Slice{1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id in(?,?,?)\", table), g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE id>=? AND id <=?\", table), g.Slice{1, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 2)\n\t\tt.Assert(result[2][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetOne(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.GetOne(ctx, fmt.Sprintf(\"SELECT * FROM %s WHERE passport=?\", table), \"user_1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_DB_GetValue(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE passport=?\", table), \"user_3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 3)\n\t})\n}\n\nfunc Test_DB_GetCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.GetCount(ctx, fmt.Sprintf(\"SELECT * FROM %s\", table))\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t})\n}\n\nfunc Test_DB_GetStruct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n}\n\nfunc Test_DB_GetStructs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_GetArray(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.GetArray(ctx, fmt.Sprintf(\"SELECT id FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(array), TableSize-1)\n\t\tfor i, v := range array {\n\t\t\tt.Assert(v.Int(), i+2)\n\t\t}\n\t})\n}\n\nfunc Test_DB_GetScan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.GetScan(ctx, &user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.GetScan(ctx, user, fmt.Sprintf(\"SELECT * FROM %s WHERE id=?\", table), 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_3\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.GetScan(ctx, &users, fmt.Sprintf(\"SELECT * FROM %s WHERE id>?\", table), 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize-1)\n\t\tt.Assert(users[0].Id, 2)\n\t\tt.Assert(users[1].Id, 3)\n\t\tt.Assert(users[2].Id, 4)\n\t\tt.Assert(users[0].NickName, \"name_2\")\n\t\tt.Assert(users[1].NickName, \"name_3\")\n\t\tt.Assert(users[2].NickName, \"name_4\")\n\t})\n}\n\nfunc Test_DB_Delete(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_DB_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          200,\n\t\t\t\"passport\":    \"t200\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T200\",\n\t\t\t\"create_time\": time.Now(),\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 200)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t200\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := time.Now()\n\t\tresult, err := db.Insert(ctx, table, g.Map{\n\t\t\t\"id\":          300,\n\t\t\t\"passport\":    \"t300\",\n\t\t\t\"password\":    \"123456\",\n\t\t\t\"nickname\":    \"T300\",\n\t\t\t\"create_time\": &t1,\n\t\t})\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.GetValue(ctx, fmt.Sprintf(\"select `passport` from `%s` where id=?\", table), 300)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t300\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Delete(ctx, table, 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n}\n\nfunc Test_DB_ToJson(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := make([]User, 0)\n\n\t\terr = result.Structs(users)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = result.Structs(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\t// ToJson\n\t\tresultJson, err := gjson.LoadContent([]byte(result.Json()))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(users[0].Id, resultJson.Get(\"0.id\").Int())\n\t\tt.Assert(users[0].Passport, resultJson.Get(\"0.passport\").String())\n\t\tt.Assert(users[0].Password, resultJson.Get(\"0.password\").String())\n\t\tt.Assert(users[0].NickName, resultJson.Get(\"0.nickname\").String())\n\t\tt.Assert(users[0].CreateTime, resultJson.Get(\"0.create_time\").String())\n\n\t\tresult = nil\n\t\tt.Assert(result.Structs(&users), sql.ErrNoRows)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id =? \", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tusers := User{}\n\n\t\terr = result.Struct(&users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult = nil\n\t\terr = result.Struct(&users)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DB_ToXml(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).One()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tuser := User{}\n\t\terr = record.Struct(&user)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresult, err := gxml.Decode([]byte(record.Xml(\"doc\")))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultXml := result[\"doc\"].(map[string]any)\n\t\tif v, ok := resultXml[\"id\"]; ok {\n\t\t\tt.Assert(user.Id, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"passport\"]; ok {\n\t\t\tt.Assert(user.Passport, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"password\"]; ok {\n\t\t\tt.Assert(user.Password, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"nickname\"]; ok {\n\t\t\tt.Assert(user.NickName, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\n\t\tif v, ok := resultXml[\"create_time\"]; ok {\n\t\t\tt.Assert(user.CreateTime, v)\n\t\t} else {\n\t\t\tgtest.Fatal(\"FAIL\")\n\t\t}\n\t})\n}\n\nfunc Test_DB_ToStringMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", 1).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringMap := result.MapKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultStringMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultStringMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultStringMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultStringMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToIntMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToUintMap(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintMap := result.MapKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintMap[uint(id)][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultUintMap[uint(id)][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultUintMap[uint(id)][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultUintMap[uint(id)][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultUintMap[uint(id)][\"create_time\"])\n\t})\n}\n\nfunc Test_DB_ToStringRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tids := \"1\"\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultStringRecord := result.RecordKeyStr(\"id\")\n\t\tt.Assert(t_users[0].Id, resultStringRecord[ids][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultStringRecord[ids][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultStringRecord[ids][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultStringRecord[ids][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultStringRecord[ids][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToIntRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntRecord := result.RecordKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntRecord[id][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultIntRecord[id][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultIntRecord[id][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultIntRecord[id][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultIntRecord[id][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_ToUintRecord(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultUintRecord := result.RecordKeyUint(\"id\")\n\t\tt.Assert(t_users[0].Id, resultUintRecord[uint(id)][\"id\"].Int())\n\t\tt.Assert(t_users[0].Passport, resultUintRecord[uint(id)][\"passport\"].String())\n\t\tt.Assert(t_users[0].Password, resultUintRecord[uint(id)][\"password\"].String())\n\t\tt.Assert(t_users[0].NickName, resultUintRecord[uint(id)][\"nickname\"].String())\n\t\tt.Assert(t_users[0].CreateTime, resultUintRecord[uint(id)][\"create_time\"].String())\n\t})\n}\n\nfunc Test_DB_TableField(t *testing.T) {\n\tname := \"field_test\"\n\tdropTable(name)\n\tdefer dropTable(name)\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tfield_tinyint  tinyint(8) NULL ,\n\t\tfield_int  int(8) NULL ,\n\t\tfield_integer  integer(8) NULL ,\n\t\tfield_bigint  bigint(8) NULL ,\n\t\tfield_real  real(8,0) NULL ,\n\t\tfield_double  double(12,2) NULL ,\n\t\tfield_varchar  varchar(10) NULL ,\n\t\tfield_varbinary  varbinary(255) NULL\n\t);\n\t`, name))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tdata := gdb.Map{\n\t\t\"field_tinyint\":   1,\n\t\t\"field_int\":       2,\n\t\t\"field_integer\":   3,\n\t\t\"field_bigint\":    4,\n\t\t\"field_real\":      123,\n\t\t\"field_double\":    123.25,\n\t\t\"field_varchar\":   \"abc\",\n\t\t\"field_varbinary\": \"aaa\",\n\t}\n\tres, err := db.Model(name).Data(data).Insert()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tn, err := res.RowsAffected()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t} else {\n\t\tgtest.Assert(n, 1)\n\t}\n\n\tresult, err := db.Model(name).Fields(\"*\").Where(\"field_int = ?\", 2).All()\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\tgtest.Assert(result[0], data)\n}\n\nfunc Test_DB_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\tnoPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\ttable := TableNamePrefix + noPrefixName\n\tcreateTableWithDb(db, table)\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Insert(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Replace(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Update(ctx, noPrefixName, g.Map{\n\t\t\t\"id\":          id,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, id),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, id),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, id),\n\t\t\t\"create_time\": gtime.NewFromStr(\"2018-10-24 10:00:03\").String(),\n\t\t}, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 10000\n\t\tresult, err := db.Delete(ctx, noPrefixName, \"id=?\", id)\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := db.Insert(ctx, noPrefixName, array.Slice())\n\t\tt.AssertNil(err)\n\n\t\tn, e := result.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InnerJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table1).Where(\"id > ?\", 5).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(n, 5)\n\n\t\tresult, err := db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 5)\n\n\t\tresult, err = db.Model(table1+\" u1\").InnerJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ?\", 1).Order(\"u1.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 4)\n\t})\n}\n\nfunc Test_Model_LeftJoin(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable1 := createInitTable(\"user1\")\n\t\ttable2 := createInitTable(\"user2\")\n\n\t\tdefer dropTable(table1)\n\t\tdefer dropTable(table2)\n\n\t\tres, err := db.Model(table2).Where(\"id > ?\", 3).Delete()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tn, err := res.RowsAffected()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t} else {\n\t\t\tt.Assert(n, 7)\n\t\t}\n\n\t\tresult, err := db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 10)\n\n\t\tresult, err = db.Model(table1+\" u1\").LeftJoin(table2+\" u2\", \"u1.id = u2.id\").Where(\"u1.id > ? \", 2).All()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Assert(len(result), 8)\n\t})\n}\n\nfunc Test_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\n// update counter test.\nfunc Test_DB_UpdateCounter(t *testing.T) {\n\ttableName := \"gf_update_counter_test_\" + gtime.TimestampNanoStr()\n\t_, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\tviews  int(8) DEFAULT '0'  NOT NULL ,\n\t\tupdated_time int(10) DEFAULT '0' NOT NULL\n\t);\n\t`, tableName))\n\tif err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\tdefer dropTable(tableName)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tinsertData := g.Map{\n\t\t\t\"id\":           1,\n\t\t\t\"views\":        0,\n\t\t\t\"updated_time\": 0,\n\t\t}\n\t\t_, err = db.Insert(ctx, tableName, insertData)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"id\",\n\t\t\tValue: 1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\": gdbCounter,\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdbCounter := &gdb.Counter{\n\t\t\tField: \"views\",\n\t\t\tValue: -1,\n\t\t}\n\t\tupdateData := g.Map{\n\t\t\t\"views\":        gdbCounter,\n\t\t\t\"updated_time\": gtime.Now().Unix(),\n\t\t}\n\t\tresult, err := db.Update(ctx, tableName, updateData, \"id\", 1)\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(tableName).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"views\"].Int(), 1)\n\t})\n}\n\nfunc Test_DB_Ctx_Logger(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype TraceId string\n\t\tdefer db.SetDebug(db.GetDebug())\n\t\tdb.SetDebug(true)\n\t\tctx := context.WithValue(context.Background(), TraceId(\"Trace-Id\"), \"123456789\")\n\t\t_, err := db.Query(ctx, \"SELECT 1\")\n\t\tt.AssertNil(err)\n\t})\n}\n\n// All types testing.\n// https://www.sqlite.org/datatype3.html\nfunc Test_Types(t *testing.T) {\n\ttableName := \"types_\" + gtime.TimestampNanoStr()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n    CREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\t%s blob NOT NULL,\n\t\t%s binary(8) NOT NULL,\n\t\t%s date NOT NULL,\n\t\t%s time NOT NULL,\n\t\t%s timestamp(6) NOT NULL,\n\t\t%s decimal(5,2) NOT NULL,\n\t\t%s double NOT NULL,\n\t\t%s tinyint(1) NOT NULL,\n\t\t%s bool NOT NULL\n\t);\n\t`,\n\t\t\ttableName,\n\t\t\t\"`blob`\",\n\t\t\t\"`binary`\",\n\t\t\t\"`date`\",\n\t\t\t\"`time`\",\n\t\t\t\"`timestamp`\",\n\t\t\t\"`decimal`\",\n\t\t\t\"`double`\",\n\t\t\t\"`tinyint`\",\n\t\t\t\"`bool`\")); err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tdefer dropTable(tableName)\n\t\tdata := g.Map{\n\t\t\t\"id\":        1,\n\t\t\t\"blob\":      \"i love gf\",\n\t\t\t\"binary\":    []byte(\"abcdefgh\"),\n\t\t\t\"date\":      \"1880-10-24\",\n\t\t\t\"time\":      \"10:00:01\",\n\t\t\t\"timestamp\": \"2022-02-14 12:00:01.123456\",\n\t\t\t\"decimal\":   -123.456,\n\t\t\t\"double\":    -123.456,\n\t\t\t\"tinyint\":   true,\n\t\t\t\"bool\":      false,\n\t\t}\n\t\tr, err := db.Model(tableName).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(tableName).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"blob\"].String(), data[\"blob\"])\n\t\tt.Assert(one[\"binary\"].String(), data[\"binary\"])\n\t\tt.Assert(one[\"date\"].String(), data[\"date\"])\n\t\tt.Assert(one[\"time\"].String(), `10:00:01`)\n\t\tt.Assert(one[\"timestamp\"].GTime().Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(one[\"decimal\"].String(), data[\"decimal\"]) // In SQLite, the datatype of a value is associated with the value itself, not with its container.\n\t\tt.Assert(one[\"double\"].String(), data[\"double\"])\n\t\tt.Assert(one[\"tinyint\"].Bool(), data[\"tinyint\"])\n\n\t\ttype T struct {\n\t\t\tId        int\n\t\t\tBlob      []byte\n\t\t\tBinary    []byte\n\t\t\tDate      *gtime.Time\n\t\t\tTime      *gtime.Time\n\t\t\tTimestamp *gtime.Time\n\t\t\tDecimal   float64\n\t\t\tDouble    float64\n\t\t\tBit       int8\n\t\t\tTinyInt   bool\n\t\t}\n\t\tvar obj *T\n\t\terr = db.Model(tableName).Scan(&obj)\n\t\tt.AssertNil(err)\n\t\tt.Assert(obj.Id, 1)\n\t\tt.Assert(obj.Blob, data[\"blob\"])\n\t\tt.Assert(obj.Binary, data[\"binary\"])\n\t\tt.Assert(obj.Date.Format(\"Y-m-d\"), data[\"date\"])\n\t\tt.Assert(obj.Time.String(), `10:00:01`)\n\t\tt.Assert(obj.Timestamp.Format(`Y-m-d H:i:s.u`), `2022-02-14 12:00:01.123`)\n\t\tt.Assert(obj.Decimal, data[\"decimal\"])\n\t\tt.Assert(obj.Double, data[\"double\"])\n\t\tt.Assert(obj.TinyInt, data[\"tinyint\"])\n\t})\n}\n\nfunc Test_TableFields(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttableName := \"fields_\" + gtime.TimestampNanoStr()\n\t\tcreateTable(tableName)\n\t\tdefer dropTable(tableName)\n\t\tvar expect = map[string][]any{\n\t\t\t// fields\t\ttype\tnull\tkey\tdefault\textra\tcomment\n\t\t\t\"id\":          {\"INTEGER\", false, \"pri\", nil, \"\", \"\"},\n\t\t\t\"passport\":    {\"VARCHAR(45)\", false, \"\", \"passport\", \"\", \"\"},\n\t\t\t\"password\":    {\"VARCHAR(128)\", false, \"\", \"password\", \"\", \"\"},\n\t\t\t\"nickname\":    {\"VARCHAR(45)\", true, \"\", nil, \"\", \"\"},\n\t\t\t\"create_time\": {\"DATETIME\", true, \"\", nil, \"\", \"\"},\n\t\t}\n\n\t\tres, err := db.TableFields(context.Background(), tableName)\n\t\tgtest.AssertNil(err)\n\n\t\tfor k, v := range expect {\n\t\t\t_, ok := res[k]\n\t\t\tgtest.AssertEQ(ok, true)\n\t\t\tgtest.AssertEQ(res[k].Name, k)\n\t\t\tgtest.AssertEQ(res[k].Type, v[0])\n\t\t\tgtest.AssertEQ(res[k].Null, v[1])\n\t\t\tgtest.AssertEQ(res[k].Key, v[2])\n\t\t\tgtest.AssertEQ(res[k].Default, v[3])\n\t\t\tgtest.AssertEQ(res[k].Extra, v[4])\n\t\t\tgtest.AssertEQ(res[k].Comment, v[5])\n\t\t}\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.TableFields(context.Background(), \"t1 t2\")\n\t\tgtest.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_TableNameIsKeyword(t *testing.T) {\n\ttable := createInitTable(TableNameWhichIsKeyword)\n\tdefer dropTable(table)\n\t_, err := db.Update(ctx, table, \"create_time='2010-10-10 00:00:01'\", \"id=?\", 1)\n\tgtest.AssertNil(err)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid := 1\n\t\tresult, err := db.Model(table).Fields(\"*\").Where(\"id = ?\", id).All()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\ttype t_user struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime string\n\t\t}\n\n\t\tt_users := make([]t_user, 0)\n\t\terr = result.Structs(&t_users)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tresultIntMap := result.MapKeyInt(\"id\")\n\t\tt.Assert(t_users[0].Id, resultIntMap[id][\"id\"])\n\t\tt.Assert(t_users[0].Passport, resultIntMap[id][\"passport\"])\n\t\tt.Assert(t_users[0].Password, resultIntMap[id][\"password\"])\n\t\tt.Assert(t_users[0].NickName, resultIntMap[id][\"nickname\"])\n\t\tt.Assert(t_users[0].CreateTime, resultIntMap[id][\"create_time\"])\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_z_unit_init_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tdb         gdb.DB\n\tdbPrefix   gdb.DB\n\tdbInvalid  gdb.DB\n\tconfigNode gdb.ConfigNode\n\tdbDir      = gfile.Temp(\"sqlite\")\n\tctx        = gctx.New()\n)\n\nconst (\n\tTableSize               = 10\n\tTableName               = \"user\"\n\tTableNameWhichIsKeyword = \"group\"\n\tTestSchema1             = \"test1\"\n\tTestSchema2             = \"test2\"\n\tTableNamePrefix         = \"gf_\"\n\tCreateTime              = \"2018-10-24 10:00:00\"\n\tDBGroupTest             = \"test\"\n\tDBGroupPrefix           = \"prefix\"\n\tDBGroupInvalid          = \"invalid\"\n)\n\nfunc init() {\n\tfmt.Println(\"init sqlite db start\")\n\n\tif err := gfile.Mkdir(dbDir); err != nil {\n\t\tgtest.Error(err)\n\t}\n\n\tfmt.Println(\"init sqlite db dir: \", dbDir)\n\n\tdbFilePath := gfile.Join(dbDir, \"test.db\")\n\tconfigNode = gdb.ConfigNode{\n\t\tType:    \"sqlite\",\n\t\tLink:    fmt.Sprintf(`sqlite::@file(%s)`, dbFilePath),\n\t\tCharset: \"utf8\",\n\t}\n\tnodePrefix := configNode\n\tnodePrefix.Prefix = TableNamePrefix\n\n\tnodeInvalid := configNode\n\n\tgdb.AddConfigNode(DBGroupTest, configNode)\n\tgdb.AddConfigNode(DBGroupPrefix, nodePrefix)\n\tgdb.AddConfigNode(DBGroupInvalid, nodeInvalid)\n\tgdb.AddConfigNode(gdb.DefaultGroupName, configNode)\n\n\t// Default db.\n\tif r, err := gdb.NewByGroup(); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdb = r\n\t}\n\n\t// Prefix db.\n\tif r, err := gdb.NewByGroup(DBGroupPrefix); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbPrefix = r\n\t}\n\n\t// Invalid db.\n\tif r, err := gdb.NewByGroup(DBGroupInvalid); err != nil {\n\t\tgtest.Error(err)\n\t} else {\n\t\tdbInvalid = r\n\t}\n\n\tfmt.Println(\"init sqlite db finish\")\n}\n\nfunc createTable(table ...string) string {\n\treturn createTableWithDb(db, table...)\n}\n\nfunc createInitTable(table ...string) string {\n\treturn createInitTableWithDb(db, table...)\n}\n\nfunc dropTable(table string) {\n\tdropTableWithDb(db, table)\n}\n\nfunc createTableWithDb(db gdb.DB, table ...string) (name string) {\n\tif len(table) > 0 {\n\t\tname = table[0]\n\t} else {\n\t\tname = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\t}\n\tdropTableWithDb(db, name)\n\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid          INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tpassport    VARCHAR(45)  NOT NULL\n\t\t\t\t\t\t\t\t\tDEFAULT passport,\n\t\tpassword    VARCHAR(128) NOT NULL\n\t\t\t\t\t\t\t\t\tDEFAULT password,\n\t\tnickname    VARCHAR(45),\n\t\tcreate_time DATETIME\n\t);\n\t`, db.GetCore().QuoteWord(name),\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\n\treturn\n}\n\nfunc createInitTableWithDb(db gdb.DB, table ...string) (name string) {\n\tname = createTableWithDb(db, table...)\n\tarray := garray.New(true)\n\tfor i := 1; i <= TableSize; i++ {\n\t\tarray.Append(g.Map{\n\t\t\t\"id\":          i,\n\t\t\t\"passport\":    fmt.Sprintf(`user_%d`, i),\n\t\t\t\"password\":    fmt.Sprintf(`pass_%d`, i),\n\t\t\t\"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t\t\t\"create_time\": gtime.NewFromStr(CreateTime).String(),\n\t\t})\n\t}\n\n\tresult, err := db.Insert(ctx, name, array.Slice())\n\tgtest.AssertNil(err)\n\n\tn, e := result.RowsAffected()\n\tgtest.Assert(e, nil)\n\tgtest.Assert(n, TableSize)\n\treturn\n}\n\nfunc dropTableWithDb(db gdb.DB, table string) {\n\tif _, err := db.Exec(ctx, fmt.Sprintf(\"DROP TABLE IF EXISTS `%s`\", table)); err != nil {\n\t\tgtest.Error(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage sqlitecgo_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Model_Insert(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tresult, err := user.Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tresult, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          \"2\",\n\t\t\t\"uid\":         \"2\",\n\t\t\t\"passport\":    \"t2\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\ttype User struct {\n\t\t\tId         int         `gconv:\"id\"`\n\t\t\tUid        int         `gconv:\"uid\"`\n\t\t\tPassport   string      `json:\"passport\"`\n\t\t\tPassword   string      `gconv:\"password\"`\n\t\t\tNickname   string      `gconv:\"nickname\"`\n\t\t\tCreateTime *gtime.Time `json:\"create_time\"`\n\t\t}\n\t\t// Model inserting.\n\t\tresult, err = db.Model(table).Data(User{\n\t\t\tId:         3,\n\t\t\tUid:        3,\n\t\t\tPassport:   \"t3\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"name_3\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err := db.Model(table).Fields(\"passport\").Where(\"id=3\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t3\")\n\n\t\tresult, err = db.Model(table).Data(&User{\n\t\t\tId:         4,\n\t\t\tUid:        4,\n\t\t\tPassport:   \"t4\",\n\t\t\tPassword:   \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\tNickname:   \"T4\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tvalue, err = db.Model(table).Fields(\"passport\").Where(\"id=4\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"t4\")\n\n\t\tresult, err = db.Model(table).Where(\"id>?\", 1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ = result.RowsAffected()\n\t\tt.Assert(n, 3)\n\t})\n}\n\n// Fix issue: https://github.com/gogf/gf/issues/819\nfunc Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Password struct {\n\t\t\tSalt string `json:\"salt\"`\n\t\t\tPass string `json:\"pass\"`\n\t\t}\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    &Password{\"123\", \"456\"},\n\t\t\t\"nickname\":    []string{\"A\", \"B\", \"C\"},\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], data[\"create_time\"])\n\t\tt.Assert(one[\"nickname\"], gjson.New(data[\"nickname\"]).MustToJson())\n\t})\n}\n\nfunc Test_Model_Insert_KeyFieldNameMapping(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Update_KeyFieldNameMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         999999,\n\t\t\tPassport:   \"user_10\",\n\t\t\tPassword:   \"pass_10\",\n\t\t\tNickname:   \"name_10\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).Where(\"id\", data.Id).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data.Passport)\n\t\tt.Assert(one[\"create_time\"], data.CreateTime)\n\t\tt.Assert(one[\"nickname\"], data.Nickname)\n\t})\n}\n\nfunc Test_Model_Insert_Time(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"p1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2020-10-10 20:09:18.334\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(table).One(\"id\", 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], data[\"passport\"])\n\t\tt.Assert(one[\"create_time\"], \"2020-10-10 20:09:18\")\n\t\tt.Assert(one[\"nickname\"], data[\"nickname\"])\n\t})\n}\n\nfunc Test_Model_BatchInsertWithArrayStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := db.Model(table)\n\t\tarray := garray.New()\n\t\tfor i := 1; i <= TableSize; i++ {\n\t\t\tarray.Append(g.Map{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"uid\":         i,\n\t\t\t\t\"passport\":    fmt.Sprintf(\"t%d\", i),\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    fmt.Sprintf(\"name_%d\", i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\n\t\tresult, err := user.Data(array).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_InsertIgnore(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).InsertIgnore()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Batch(t *testing.T) {\n\t// batch insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t2\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\":          3,\n\t\t\t\t\"uid\":         3,\n\t\t\t\t\"passport\":    \"t3\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_3\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}).Batch(1).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 2)\n\t})\n\n\t// batch insert, retrieving last insert auto-increment id.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(g.List{\n\t\t\t{\"passport\": \"t1\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t2\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t3\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t4\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t\t{\"passport\": \"t5\", \"password\": \"25d55ad283aa400af464c76d713c07ad\", \"nickname\": \"name\", \"create_time\": gtime.Now().String()},\n\t\t}).Batch(2).Insert()\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 5)\n\t})\n\n\t// batch replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tfor _, v := range result {\n\t\t\tv[\"nickname\"].Set(v[\"nickname\"].String() + v[\"id\"].String())\n\t\t\tv[\"id\"].Set(v[\"id\"].Int() + 100)\n\t\t}\n\t\tr, e := db.Model(table).Data(result).Replace()\n\t\tt.Assert(e, nil)\n\t\tn, e := r.RowsAffected()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Replace(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"t11\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"T11\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"].Int(), 1)\n\t\tt.Assert(one[\"passport\"].String(), \"t11\")\n\t\tt.Assert(one[\"password\"].String(), \"25d55ad283aa400af464c76d713c07ad\")\n\t\tt.Assert(one[\"nickname\"].String(), \"T11\")\n\t\tt.Assert(one[\"create_time\"].GTime().String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Save(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t)\n\n\t\t_, err = db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"CN\",\n\t\t\t\"password\":    \"12345678\",\n\t\t\t\"nickname\":    \"oldme\",\n\t\t\t\"create_time\": CreateTime,\n\t\t}).OnConflict(\"id\").Save()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Update(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// UPDATE...LIMIT\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tresult, err := db.Model(table).Data(\"nickname\", \"T100\").Where(1).Limit(2).Update()\n\t// \tt.AssertNil(err)\n\t// \tn, _ := result.RowsAffected()\n\t// \tt.Assert(n, 2)\n\n\t// \tv1, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 10).Value()\n\t// \tt.AssertNil(err)\n\t// \tt.Assert(v1.String(), \"T100\")\n\n\t// \tv2, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 8).Value()\n\t// \tt.AssertNil(err)\n\t// \tt.Assert(v2.String(), \"name_8\")\n\t// })\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_22\").Where(\"passport=?\", \"user_2\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport\", \"user_2\").Where(\"passport='user_22'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\n\t// Update + Data(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Data(\"passport='user_33'\").Where(\"passport='user_3'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\t// Update + Fields(string)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(\"passport\").Data(g.Map{\n\t\t\t\"passport\": \"user_44\",\n\t\t\t\"none\":     \"none\",\n\t\t}).Where(\"passport='user_4'\").Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Model_UpdateAndGetAffected(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tn, err := db.Model(table).Data(\"nickname\", \"T100\").\n\t\t\tWhere(1).\n\t\t\tUpdateAndGetAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Clone(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\n\t\trecord, err := md.Safe(true).Order(\"id DESC\").One()\n\t\tt.AssertNil(err)\n\n\t\tresult, err := md.Safe(true).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(count, int64(2))\n\t\tt.Assert(record[\"id\"].Int(), 3)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Safe(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(false).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe(true).Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd := db.Model(table).Safe().Where(\"id IN(?)\", g.Slice{1, 3})\n\t\tcount, err := md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tmd.Where(\"id = ?\", 1)\n\t\tcount, err = md.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmd1 := db.Model(table).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tmd1 := db.Model(table).Where(\"id>\", 0).Safe()\n\t\tmd2 := md1.Where(\"id in (?)\", g.Slice{1, 3})\n\t\tmd3 := md1.Where(\"id in (?)\", g.Slice{4, 5, 6})\n\n\t\t// 1,3\n\t\tcount, err := md2.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\n\t\tall, err := md2.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 1)\n\t\tt.Assert(all[1][\"id\"].Int(), 3)\n\n\t\tall, err = md2.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\n\t\t// 4,5,6\n\t\tcount, err = md3.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\n\t\tall, err = md3.Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"].Int(), 4)\n\t\tt.Assert(all[1][\"id\"].Int(), 5)\n\t\tt.Assert(all[2][\"id\"].Int(), 6)\n\n\t\tall, err = md3.Page(1, 10).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t})\n}\n\nfunc Test_Model_All(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id<0\").All()\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_AllAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// AllAndCount with all data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(count, TableSize)\n\t})\n\t// AllAndCount with no data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id<0\").AllAndCount(false)\n\t\tt.Assert(result, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 0)\n\t})\n\t// AllAndCount with page\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Page(1, 5).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(count, TableSize)\n\t})\n\t// AllAndCount with normal result\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Where(\"id=?\", 1).AllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(result[0][\"passport\"], \"user_1\")\n\t})\n\t// AllAndCount with distinct\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, count, err := db.Model(table).Fields(\"DISTINCT nickname\").AllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(result[0][\"nickname\"], \"name_1\")\n\t\tt.AssertNil(result[0][\"id\"])\n\t})\n\t// AllAndCount with Join\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, count, err := db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAllAndCount(false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t\tt.Assert(count, 1)\n\t})\n\t// AllAndCount with Join and useFieldForCount=true\n\t// Regression test for #4698 - verifies COUNT(1) is used instead of COUNT(multiple fields)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, count, err := db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAllAndCount(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t\tt.Assert(count, 1)\n\t})\n}\n\nfunc Test_Model_Fields(t *testing.T) {\n\ttableName1 := createInitTable()\n\tdefer dropTable(tableName1)\n\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u\").Fields(\"u.passport,u.id\").Where(\"u.id<2\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName1, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.id AS u2id\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(tableName1).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t\tt.Assert(len(all[0]), 4)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"age\"], 18)\n\t\tt.Assert(all[0][\"name\"], \"table2_1\")\n\t\tt.Assert(all[0][\"passport\"], \"user_1\")\n\t})\n}\n\nfunc Test_Model_One(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record[\"nickname\"].String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\trecord, err := db.Model(table).Where(\"id\", 0).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(record, nil)\n\t})\n}\n\nfunc Test_Model_Value(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 1).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"nickname\").Where(\"id\", 0).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Model_Array(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(all.Array(\"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(all.Array(\"nickname\"), g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Fields(\"nickname\").Where(\"id\", g.Slice{1, 2, 3}).Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray, err := db.Model(table).Array(\"nickname\", \"id\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(array, g.Slice{\"name_1\", \"name_2\", \"name_3\"})\n\t})\n}\n\nfunc Test_Model_Count(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Count with cache, check internal ctx data feature.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tcount, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second * 10,\n\t\t\t\tName:     guid.S(),\n\t\t\t\tForce:    false,\n\t\t\t}).Count()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(count, int64(TableSize))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).FieldsEx(\"id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Fields(\"distinct id\").Where(\"id>8\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(2))\n\t})\n\t// COUNT...LIMIT...\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Page(1, 2).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Exist(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := db.Model(table).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, TableSize > 0)\n\t\texist, err = db.Model(table).Where(\"id\", -1).Exist()\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\t})\n}\n\nfunc Test_Model_Select(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype User struct {\n\t\tId         int\n\t\tPassport   string\n\t\tPassword   string\n\t\tNickName   string\n\t\tCreateTime gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := db.Model(table).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t})\n}\n\nfunc Test_Model_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// Auto creating struct object.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := (*User)(nil)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(&user)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(user)\n\t\tt.Assert(err, sql.ErrNoRows)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar user *User\n\t\terr := db.Model(table).Where(\"id=-1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Struct_CustomType(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype MyInt int\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         MyInt\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n}\n\nfunc Test_Model_Structs(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// Auto create struct slice.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// Just using Scan.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tif err != nil {\n\t\t\tgtest.Error(err)\n\t\t}\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Where(\"id<0\").Scan(&users)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_StructsWithOrmTag(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdb.SetDebug(true)\n\t\tdefer db.SetDebug(false)\n\t\ttype User struct {\n\t\t\tUid      int `orm:\"id\"`\n\t\t\tPassport string\n\t\t\tPassword string     `orm:\"password\"`\n\t\t\tName     string     `orm:\"nickname\"`\n\t\t\tTime     gtime.Time `orm:\"create_time\"`\n\t\t}\n\t\tvar (\n\t\t\tusers  []User\n\t\t\tbuffer = bytes.NewBuffer(nil)\n\t\t)\n\t\tdb.GetLogger().(*glog.Logger).SetWriter(buffer)\n\t\tdefer db.GetLogger().(*glog.Logger).SetWriter(os.Stdout)\n\t\tdb.Model(table).Order(\"id asc\").Scan(&users)\n\t\t// fmt.Println(buffer.String())\n\t\tt.Assert(\n\t\t\tgstr.Contains(buffer.String(), \"SELECT `id`,`passport`,`password`,`nickname`,`create_time` FROM `user\"),\n\t\t\ttrue,\n\t\t)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t}\n\t\ttype B struct {\n\t\t\tA\n\t\t\tNickName string\n\t\t}\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n}\n\nfunc Test_Model_Scan(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\terr := db.Model(table).Where(\"id=1\").Scan(user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar users []*User\n\t\terr := db.Model(table).Order(\"id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\terr1 := db.Model(table).Where(\"id < 0\").Scan(user)\n\t\terr2 := db.Model(table).Where(\"id < 0\").Scan(users)\n\t\tt.Assert(err1, sql.ErrNoRows)\n\t\tt.Assert(err2, nil)\n\t})\n}\n\nfunc Test_Model_ScanAndCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\ttableName2 := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE %s (\n\t\tid         INTEGER       PRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\tNOT NULL,\n\t\tname       varchar(45) NULL,\n\t\tage        int(10)\n\t);\n\t`, tableName2,\n\t)); err != nil {\n\t\tgtest.AssertNil(err)\n\t}\n\tdefer dropTable(tableName2)\n\tr, err := db.Insert(ctx, tableName2, g.Map{\n\t\t\"id\":   1,\n\t\t\"name\": \"table2_1\",\n\t\t\"age\":  18,\n\t})\n\tgtest.AssertNil(err)\n\tn, _ := r.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// ScanAndCount with normal struct result\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tuser := new(User)\n\t\tvar count int\n\t\terr := db.Model(table).Where(\"id=1\").ScanAndCount(user, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.NickName, \"name_1\")\n\t\tt.Assert(user.CreateTime.String(), CreateTime)\n\t\tt.Assert(count, 1)\n\t})\n\t// ScanAndCount with normal array result\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Order(\"id asc\").ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 2)\n\t\tt.Assert(users[2].Id, 3)\n\t\tt.Assert(users[0].NickName, \"name_1\")\n\t\tt.Assert(users[1].NickName, \"name_2\")\n\t\tt.Assert(users[2].NickName, \"name_3\")\n\t\tt.Assert(users[0].CreateTime.String(), CreateTime)\n\t\tt.Assert(count, len(users))\n\t})\n\t// sql.ErrNoRows\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\tuser  = new(User)\n\t\t\tusers = new([]*User)\n\t\t)\n\t\tvar count1 int\n\t\tvar count2 int\n\t\terr1 := db.Model(table).Where(\"id < 0\").ScanAndCount(user, &count1, true)\n\t\terr2 := db.Model(table).Where(\"id < 0\").ScanAndCount(users, &count2, true)\n\t\tt.Assert(count1, 0)\n\t\tt.Assert(count2, 0)\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t})\n\t// ScanAndCount with page\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr := db.Model(table).Order(\"id asc\").Page(1, 3).ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 3)\n\t\tt.Assert(count, TableSize)\n\t})\n\t// ScanAndCount with distinct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).Fields(\"distinct id\").ScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 10)\n\t\tt.Assert(count, TableSize)\n\t\tt.Assert(users[0].Id, 1)\n\t})\n\t// ScanAndCount with join\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tName     string\n\t\t\tAge      int\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tScanAndCount(&users, &count, false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 1)\n\t\tt.Assert(count, 1)\n\t\tt.AssertEQ(users[0].Name, \"table2_1\")\n\t})\n\t// ScanAndCount with join and useFieldForCount=true\n\t// Regression test for #4698 - verifies COUNT(1) is used instead of COUNT(multiple fields)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tName     string\n\t\t\tAge      int\n\t\t}\n\t\tvar users []User\n\t\tvar count int\n\t\terr = db.Model(table).As(\"u1\").\n\t\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n\t\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n\t\t\tWhere(\"u1.id<2\").\n\t\t\tScanAndCount(&users, &count, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 1)\n\t\tt.Assert(count, 1)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[0].Age, 18)\n\t\tt.Assert(users[0].Name, \"table2_1\")\n\t\tt.Assert(users[0].Passport, \"user_1\")\n\t})\n}\n\nfunc Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickName   string\n\t\t\tCreateTime gtime.Time\n\t\t}\n\t\ttype Response struct {\n\t\t\tUsers []User `json:\"users\"`\n\t\t}\n\t\tvar res Response\n\t\terr := db.Model(table).Scan(&res.Users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(res.Users, nil)\n\t})\n}\n\nfunc Test_Model_OrderBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(\"id DESC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), fmt.Sprintf(\"name_%d\", TableSize))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Order(gdb.Raw(\"NULL\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n\n}\n\nfunc Test_Model_GroupBy(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Group(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"nickname\"].String(), \"name_1\")\n\t})\n}\n\nfunc Test_Model_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Data(\"nickname=?\", \"test\").Where(\"id=?\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := make([]g.MapStrAny, 0)\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers = append(users, g.MapStrAny{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tusers := garray.New()\n\t\tfor i := 1; i <= 10; i++ {\n\t\t\tusers.Append(g.MapStrAny{\n\t\t\t\t\"id\":          i,\n\t\t\t\t\"passport\":    fmt.Sprintf(`passport_%d`, i),\n\t\t\t\t\"password\":    fmt.Sprintf(`password_%d`, i),\n\t\t\t\t\"nickname\":    fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t})\n\t\t}\n\t\tresult, err := db.Model(table).Data(users).Batch(2).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_Where(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Slice{\"id\", 3, \"nickname\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct, automatic mapping and filtering.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).Where(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).Where(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_1(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tresult, err := db.Model(table).Data(\"nickname\", nil).Where(\"id\", 2).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"nickname\", nil).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one.IsEmpty(), false)\n\t\tt.Assert(one[\"id\"], 2)\n\t})\n}\n\nfunc Test_Model_Where_ISNULL_2(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// complicated one.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_Where_OmitEmpty(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconditions := g.Map{\n\t\t\t\"id < 4\": \"\",\n\t\t}\n\t\tresult, err := db.Model(table).Where(conditions).OmitEmpty().Order(\"id desc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t\tt.Assert(result[0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_Where_GTime(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"create_time>?\", *gtime.NewFromStr(\"2010-09-01\")).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 10)\n\t})\n}\n\nfunc Test_Model_WherePri(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// primary key\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one, nil)\n\t\tt.Assert(one[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).WherePri(g.Slice{3, 9}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"].Int(), 3)\n\t\tt.Assert(all[1][\"id\"].Int(), 9)\n\t})\n\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", 3, \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map like\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"passport like\": \"user_1%\",\n\t\t}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].GMap().Get(\"id\"), 1)\n\t\tt.Assert(result[1].GMap().Get(\"id\"), 10)\n\t})\n\t// map + slice parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).Where(\"id=? and nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=3\", g.Slice{}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=?\", g.Slice{3}).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).WherePri(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 3).Where(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>?\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id\", 30).WhereOr(\"nickname\", \"name_3\").Where(\"id>\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}...).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id=? AND nickname=?\", g.Slice{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"passport like ? and nickname like ?\", g.Slice{\"user_3\", \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id\": 3, \"nickname\": \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\"id>\": 1, \"id<\": 3}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// gmap.Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// gmap.Map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// list map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// list map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// tree map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id\": 3, \"nickname\": \"name_3\"})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// tree map key operator\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{\"id>\": 1, \"id<\": 3})).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n\n\t// complicated where 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id > 0\":             nil,\n\t\t\t\"create_time > 0\":    nil,\n\t\t\t\"id\":                 g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// complicated where 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// db.SetDebug(true)\n\t\tconditions := g.Map{\n\t\t\t\"nickname like ?\":    \"%name%\",\n\t\t\t\"id between ? and ?\": g.Slice{1, 3},\n\t\t\t\"id >= ?\":            1,\n\t\t\t\"create_time > ?\":    0,\n\t\t\t\"id in(?)\":           g.Slice{1, 2, 3},\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(conditions).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\n\t\tresult, err = db.Model(table).WherePri(&User{3, \"name_3\"}).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"id\"].Int(), 3)\n\t})\n\t// slice single\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"id IN(?)\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"].Int(), 1)\n\t\tt.Assert(result[1][\"id\"].Int(), 3)\n\t})\n\t// slice + string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(\"nickname=? AND id IN(?)\", \"name_3\", g.Slice{1, 3}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WherePri(g.Map{\n\t\t\t\"id\":       g.Slice{1, 3},\n\t\t\t\"nickname\": \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n\t// slice + struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tIds      []int  `json:\"id\"`\n\t\t\tNickname string `gconv:\"nickname\"`\n\t\t}\n\t\tresult, err := db.Model(table).WherePri(User{\n\t\t\tIds:      []int{1, 3},\n\t\t\tNickname: \"name_3\",\n\t\t}).Order(\"id ASC\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"].Int(), 3)\n\t})\n}\n\nfunc Test_Model_Delete(t *testing.T) {\n\t// table := createInitTable()\n\t// defer dropTable(table)\n\n\t// DELETE...LIMIT\n\t// https://github.com/mattn/go-sqlite3/pull/802\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tresult, err := db.Model(table).Where(1).Limit(2).Delete()\n\t// \tt.AssertNil(err)\n\t// \tn, _ := result.RowsAffected()\n\t// \tt.Assert(n, 2)\n\t// })\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tresult, err := db.Model(table).Where(1).Delete()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Offset(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Limit(2).Offset(5).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Page(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Page(3, 3).Order(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t\tt.Assert(result[1][\"id\"], 8)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmodel := db.Model(table).Safe().Order(\"id\")\n\t\tall, err := model.Page(3, 3).All()\n\t\tt.AssertNil(err)\n\t\tcount, err := model.Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], \"7\")\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\nfunc Test_Model_Option_Map(t *testing.T) {\n\t// Insert\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).Fields(\"id, passport\", \"password\", \"create_time\").Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"1\",\n\t\t\t\"password\":    \"1\",\n\t\t\t\"nickname\":    \"1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"password\"].String(), \"2\")\n\t\tt.AssertNE(one[\"nickname\"].String(), \"2\")\n\t\tt.Assert(one[\"passport\"].String(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"1\",\n\t\t\t\"password\":    \"1\",\n\t\t\t\"nickname\":    \"\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"\")\n\t})\n\n\t// Replace\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\t_, err := db.Model(table).OmitEmptyData().Data(g.Map{\n\t\t\t\"id\":       1,\n\t\t\t\"passport\": 0,\n\t\t\t\"password\": 0,\n\t\t\t\"nickname\": \"1\",\n\t\t}).Replace()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(one[\"passport\"].String(), \"0\")\n\t\tt.AssertNE(one[\"password\"].String(), \"0\")\n\t\tt.Assert(one[\"nickname\"].String(), \"1\")\n\t})\n\n\t// Update\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\n\t\tr, err := db.Model(table).Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmptyData().Data(g.Map{\"nickname\": \"\"}).Where(\"id\", 2).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\t_, err = db.Model(table).OmitEmpty().Fields(\"nickname\").Data(g.Map{\"nickname\": \"\", \"password\": \"123\"}).Where(\"id\", 4).Update()\n\t\tt.AssertNE(err, nil)\n\n\t\tr, err = db.Model(table).OmitEmpty().\n\t\t\tFields(\"password\").Data(g.Map{\n\t\t\t\"nickname\": \"\",\n\t\t\t\"passport\": \"123\",\n\t\t\t\"password\": \"456\",\n\t\t}).Where(\"id\", 5).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ = r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 5).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"password\"], \"456\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"\")\n\t\tt.AssertNE(one[\"passport\"].String(), \"123\")\n\t})\n}\n\nfunc Test_Model_Option_Where(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createInitTable()\n\t\tdefer dropTable(table)\n\t\tr, err := db.Model(table).OmitEmpty().Data(\"nickname\", 1).Where(g.Map{\"id\": 0, \"passport\": \"\"}).Where(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, TableSize)\n\t})\n}\n\nfunc Test_Model_Where_MultiSliceArguments(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3, 4},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\", \"user_4\"},\n\t\t\t\"nickname\": g.Slice{\"name_2\", \"name_4\"},\n\t\t\t\"id >= 4\":  nil,\n\t\t}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], 4)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       g.Slice{1, 2, 3},\n\t\t\t\"passport\": g.Slice{\"user_2\", \"user_3\"},\n\t\t}).WhereOr(\"nickname=?\", g.Slice{\"name_4\"}).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(result), 0)\n\t\tt.Assert(result[\"id\"].Int(), 2)\n\t})\n}\n\nfunc Test_Model_FieldsEx(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"create_time, id\").Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(len(r[0]), 3)\n\t\tt.Assert(r[0][\"id\"], \"\")\n\t\tt.Assert(r[0][\"passport\"], \"user_1\")\n\t\tt.Assert(r[0][\"password\"], \"pass_1\")\n\t\tt.Assert(r[0][\"nickname\"], \"name_1\")\n\t\tt.Assert(r[0][\"create_time\"], \"\")\n\t\tt.Assert(r[1][\"id\"], \"\")\n\t\tt.Assert(r[1][\"passport\"], \"user_2\")\n\t\tt.Assert(r[1][\"password\"], \"pass_2\")\n\t\tt.Assert(r[1][\"nickname\"], \"name_2\")\n\t\tt.Assert(r[1][\"create_time\"], \"\")\n\t})\n\t// Update.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).FieldsEx(\"password\").Data(g.Map{\"nickname\": \"123\", \"password\": \"456\"}).Where(\"id\", 3).Update()\n\t\tt.AssertNil(err)\n\t\tn, _ := r.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tone, err := db.Model(table).Where(\"id\", 3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"nickname\"], \"123\")\n\t\tt.AssertNE(one[\"password\"], \"456\")\n\t})\n}\n\nfunc Test_Model_Prefix(t *testing.T) {\n\tdb := dbPrefix\n\tnoPrefixName := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())\n\ttable := TableNamePrefix + noPrefixName\n\tcreateInitTableWithDb(db, table)\n\tdefer dropTable(table)\n\t// Select.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName).Where(\"id in (?)\", g.Slice{1, 2}).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName+\" as u\").Where(\"u.id in (?)\", g.Slice{1, 2}).Order(\"u.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\t// Select with alias to struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickName string\n\t\t}\n\t\tvar users []User\n\t\terr := db.Model(noPrefixName+\" u\").Where(\"u.id in (?)\", g.Slice{1, 5}).Order(\"u.id asc\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(users), 2)\n\t\tt.Assert(users[0].Id, 1)\n\t\tt.Assert(users[1].Id, 5)\n\t})\n\t// Select with alias and join statement.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName+\" as u1\").LeftJoin(noPrefixName+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(noPrefixName).As(\"u1\").LeftJoin(noPrefixName+\" as u2\", \"u2.id=u1.id\").Where(\"u1.id in (?)\", g.Slice{1, 2}).Order(\"u1.id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_FieldsExStruct(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"passport\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tNickName string    `orm:\"nickname\" json:\"nick__name\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tNickName: \"333\",\n\t\t\tTime:     time.Now(),\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"nickname\").OmitEmpty().Data(user).Insert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"passport\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tNickName string    `orm:\"nickname\" json:\"nick__name\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tusers := make([]*User, 0)\n\t\tfor i := 100; i < 110; i++ {\n\t\t\tusers = append(users, &User{\n\t\t\t\tId:       i,\n\t\t\t\tPassport: fmt.Sprintf(`passport_%d`, i),\n\t\t\t\tPassword: fmt.Sprintf(`password_%d`, i),\n\t\t\t\tNickName: fmt.Sprintf(`nickname_%d`, i),\n\t\t\t\tTime:     time.Now(),\n\t\t\t})\n\t\t}\n\t\tr, err := db.Model(table).FieldsEx(\"nickname\").\n\t\t\tOmitEmpty().\n\t\t\tBatch(2).\n\t\t\tData(users).\n\t\t\tInsert()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 10)\n\t})\n}\n\nfunc Test_Model_OmitEmpty_Time(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int       `orm:\"id\"       json:\"id\"`\n\t\t\tPassport string    `orm:\"password\" json:\"pass_port\"`\n\t\t\tPassword string    `orm:\"password\" json:\"password\"`\n\t\t\tTime     time.Time `orm:\"create_time\" `\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tPassport: \"111\",\n\t\t\tPassword: \"222\",\n\t\t\tTime:     time.Time{},\n\t\t}\n\t\tr, err := db.Model(table).OmitEmpty().Data(user).Where(\"id\", 1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_Result_Chunk(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Order(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tchunks := r.Chunk(3)\n\t\tt.Assert(len(chunks), 4)\n\t\tt.Assert(chunks[0][0][\"id\"].Int(), 1)\n\t\tt.Assert(chunks[1][0][\"id\"].Int(), 4)\n\t\tt.Assert(chunks[2][0][\"id\"].Int(), 7)\n\t\tt.Assert(chunks[3][0][\"id\"].Int(), 10)\n\t})\n}\n\nfunc Test_Model_DryRun(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tdb.SetDryRun(true)\n\tdefer db.SetDryRun(false)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"id\"], 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table).Data(\"passport\", \"port_1\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_Model_Join_SubQuery(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsubQuery := fmt.Sprintf(\"select * from `%s`\", table)\n\t\tr, err := db.Model(table, \"t1\").Fields(\"t2.id\").LeftJoin(subQuery, \"t2\", \"t2.id=t1.id\").Array()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), TableSize)\n\t\tt.Assert(r[0], \"1\")\n\t\tt.Assert(r[TableSize-1], TableSize)\n\t})\n}\n\nfunc Test_Model_Cache(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_100\").WherePri(1).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_1\")\n\n\t\ttime.Sleep(time.Second * 2)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test1\",\n\t\t\tForce:    false,\n\t\t}).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_100\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_200\").Cache(gdb.CacheOption{\n\t\t\tDuration: -1,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test2\",\n\t\t\tForce:    false,\n\t\t}).WherePri(2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_200\")\n\t})\n\t// transaction.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 3\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_300\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test3\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(3).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_300\")\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(3).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// make cache for id 4\n\t\tone, err := db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4\")\n\n\t\tr, err := db.Model(table).Data(\"passport\", \"user_400\").Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test3\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).Update()\n\t\tt.AssertNil(err)\n\t\tn, err := r.RowsAffected()\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\terr = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t\t// Cache feature disabled.\n\t\t\tone, err := tx.Model(table).Cache(gdb.CacheOption{\n\t\t\t\tDuration: time.Second,\n\t\t\t\tName:     \"test4\",\n\t\t\t\tForce:    false,\n\t\t\t}).WherePri(4).One()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(one[\"passport\"], \"user_400\")\n\t\t\t// Update the cache.\n\t\t\tr, err := tx.Model(table).Data(\"passport\", \"user_4000\").\n\t\t\t\tCache(gdb.CacheOption{\n\t\t\t\t\tDuration: -1,\n\t\t\t\t\tName:     \"test4\",\n\t\t\t\t\tForce:    false,\n\t\t\t\t}).WherePri(4).Update()\n\t\t\tt.AssertNil(err)\n\t\t\tn, err := r.RowsAffected()\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(n, 1)\n\t\t\treturn nil\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Read from db.\n\t\tone, err = db.Model(table).Cache(gdb.CacheOption{\n\t\t\tDuration: time.Second,\n\t\t\tName:     \"test4\",\n\t\t\tForce:    false,\n\t\t}).WherePri(4).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(one[\"passport\"], \"user_4000\")\n\t})\n}\n\nfunc Test_Model_Having(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Group(\"id\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > 1\").Group(\"id\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Group(\"id\").Having(\"id > ?\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Where(\"id > ?\", 1).Group(\"id\").Having(\"id\", 8).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 1)\n\t})\n}\n\nfunc Test_Model_Distinct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table, \"t\").Fields(\"distinct t.id\").Where(\"id > 1\").Group(\"id\").Having(\"id > 8\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id > 1\").Distinct().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(9))\n\t})\n}\n\nfunc Test_Model_Min_Max(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"min(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table, \"t\").Fields(\"max(t.id)\").Where(\"id > 1\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 10)\n\t})\n}\n\nfunc Test_Model_Fields_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"ID\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).Fields(\"NICK_NAME\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":        1,\n\t\t\t\"NICK_NAME\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tID       int\n\t\t\tNICKNAME int\n\t\t}\n\t\tone, err := db.Model(table).Fields(&T{\n\t\t\tID:       0,\n\t\t\tNICKNAME: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_FieldsEx_AutoMapping(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// \"id\":          i,\n\t// \"passport\":    fmt.Sprintf(`user_%d`, i),\n\t// \"password\":    fmt.Sprintf(`pass_%d`, i),\n\t// \"nickname\":    fmt.Sprintf(`name_%d`, i),\n\t// \"create_time\": gtime.NewFromStr(CreateTime).String(),\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"Passport, Password, NickName, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.Int(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue, err := db.Model(table).FieldsEx(\"ID, Passport, Password, CreateTime\").Where(\"id\", 2).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.String(), \"name_2\")\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).FieldsEx(g.Map{\n\t\t\t\"Passport\":   1,\n\t\t\t\"Password\":   1,\n\t\t\t\"CreateTime\": 1,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\t// Struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tPassport   int\n\t\t\tPassword   int\n\t\t\tCreateTime int\n\t\t}\n\t\tone, err := db.Model(table).FieldsEx(&T{\n\t\t\tPassport:   0,\n\t\t\tPassword:   0,\n\t\t\tCreateTime: 0,\n\t\t}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"id\"], 2)\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\nfunc Test_Model_Fields_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\ttype A struct {\n\t\tPassport string\n\t\tPassword string\n\t}\n\ttype B struct {\n\t\tA\n\t\tNickName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&A{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tone, err := db.Model(table).Fields(&B{}).Where(\"id\", 2).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 3)\n\t\tt.Assert(one[\"passport\"], \"user_2\")\n\t\tt.Assert(one[\"password\"], \"pass_2\")\n\t\tt.Assert(one[\"nickname\"], \"name_2\")\n\t})\n}\n\n// func Test_Model_NullField(t *testing.T) {\n// \ttable := createTable()\n// \tdefer dropTable(table)\n\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\ttype User struct {\n// \t\t\tId       int\n// \t\t\tPassport *string\n// \t\t}\n// \t\tdata := g.Map{\n// \t\t\t\"id\":       1,\n// \t\t\t\"passport\": nil,\n// \t\t}\n// \t\tresult, err := db.Model(table).Data(data).Insert()\n// \t\tt.AssertNil(err)\n// \t\tn, _ := result.RowsAffected()\n// \t\tt.Assert(n, 1)\n// \t\tone, err := db.Model(table).WherePri(1).One()\n// \t\tt.AssertNil(err)\n\n// \t\tvar user *User\n// \t\terr = one.Struct(&user)\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(user.Id, data[\"id\"])\n// \t\tt.Assert(user.Passport, data[\"passport\"])\n// \t})\n// }\n\nfunc Test_Model_Empty_Slice_Argument(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_HasTable(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(table)\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(db.GetCore().ClearCacheAll(ctx))\n\t\tresult, err := db.GetCore().HasTable(\"table12321\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_HasField(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id\")\n\t\tt.Assert(result, true)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).HasField(\"id123\")\n\t\tt.Assert(result, false)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Issue: https://github.com/gogf/gf/issues/1002\nfunc Test_Model_Issue1002(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tresult, err := db.Model(table).Data(g.Map{\n\t\t\"id\":          1,\n\t\t\"passport\":    \"port_1\",\n\t\t\"password\":    \"pass_1\",\n\t\t\"nickname\":    \"name_2\",\n\t\t\"create_time\": \"2020-10-27 19:03:33\",\n\t}).Insert()\n\tgtest.AssertNil(err)\n\tn, _ := result.RowsAffected()\n\tgtest.Assert(n, 1)\n\n\t// where + string.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + string arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", \"2020-10-27 19:03:32\", \"2020-10-27 19:03:34\").Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// where + gtime.Time arguments.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", gtime.New(\"2020-10-27 19:03:32\"), gtime.New(\"2020-10-27 19:03:34\")).Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Int(), 1)\n\t})\n\t// TODO\n\t// where + time.Time arguments, UTC.\n\t// gtest.C(t, func(t *gtest.T) {\n\t// \tt1, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:32\")\n\t// \tt2, _ := time.Parse(\"2006-01-02 15:04:05\", \"2020-10-27 11:03:34\")\n\t// \t{\n\t// \t\tv, err := db.Model(table).Fields(\"id\").Where(\"create_time>? and create_time<?\", t1, t2).Value()\n\t// \t\tt.AssertNil(err)\n\t// \t\tt.Assert(v.Int(), 1)\n\t// \t}\n\t// })\n}\n\nfunc createTableForTimeZoneTest() string {\n\ttableName := \"user_\" + gtime.Now().TimestampNanoStr()\n\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\tCREATE TABLE IF NOT EXISTS %s (\n\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\tUNIQUE\n\t\t\t\t\tNOT NULL,\n\t\tpassport    varchar(45) NULL,\n\t\tpassword    char(32) NULL,\n\t\tnickname    varchar(45) NULL,\n\t\tcreated_at timestamp NULL,\n\t\tupdated_at timestamp NULL,\n\t\tdeleted_at timestamp NULL\n\t);\n\t`, tableName,\n\t)); err != nil {\n\t\tgtest.Fatal(err)\n\t}\n\treturn tableName\n}\n\n// https://github.com/gogf/gf/issues/1012\nfunc Test_TimeZoneInsert(t *testing.T) {\n\ttableName := createTableForTimeZoneTest()\n\tdefer dropTable(tableName)\n\n\ttokyoLoc, err := time.LoadLocation(\"Asia/Tokyo\")\n\tgtest.AssertNil(err)\n\n\tCreateTime := \"2020-11-22 12:23:45\"\n\tUpdateTime := \"2020-11-22 13:23:45\"\n\tDeleteTime := \"2020-11-22 14:23:45\"\n\ttype User struct {\n\t\tId        int         `json:\"id\"`\n\t\tCreatedAt *gtime.Time `json:\"created_at\"`\n\t\tUpdatedAt gtime.Time  `json:\"updated_at\"`\n\t\tDeletedAt time.Time   `json:\"deleted_at\"`\n\t}\n\tt1, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", CreateTime, tokyoLoc)\n\tt2, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", UpdateTime, tokyoLoc)\n\tt3, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", DeleteTime, tokyoLoc)\n\tu := &User{\n\t\tId:        1,\n\t\tCreatedAt: gtime.New(t1.UTC()),\n\t\tUpdatedAt: *gtime.New(t2.UTC()),\n\t\tDeletedAt: t3.UTC(),\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, _ = db.Model(tableName).Unscoped().Insert(u)\n\t\tuserEntity := &User{}\n\t\terr := db.Model(tableName).Where(\"id\", 1).Unscoped().Scan(&userEntity)\n\t\tt.AssertNil(err)\n\t\t// TODO\n\t\t// t.Assert(userEntity.CreatedAt.String(), \"2020-11-22 11:23:45\")\n\t\t// t.Assert(userEntity.UpdatedAt.String(), \"2020-11-22 12:23:45\")\n\t\t// t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), \"2020-11-22 13:23:45\")\n\t})\n}\n\nfunc Test_Model_Fields_Map_Struct(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Fields(g.Map{\n\t\t\t\"ID\":         1,\n\t\t\t\"PASSPORT\":   1,\n\t\t\t\"NONE_EXIST\": 1,\n\t\t}).Where(\"id\", 1).One()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[\"id\"], 1)\n\t\tt.Assert(result[\"passport\"], \"user_1\")\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\ta := A{}\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// *struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n\t// **struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tID       int\n\t\t\tPASSPORT string\n\t\t\tXXX_TYPE int\n\t\t}\n\t\tvar a *A\n\t\terr := db.Model(table).Fields(&a).Where(\"id\", 1).Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.ID, 1)\n\t\tt.Assert(a.PASSPORT, \"user_1\")\n\t\tt.Assert(a.XXX_TYPE, 0)\n\t})\n}\n\nfunc Test_Model_WhereIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3, 4}).WhereIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).OmitEmptyWhere().WhereIn(\"id\", g.Slice{}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 6)\n\t\tt.Assert(result[1][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereOrIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 5)\n\t})\n}\n\nfunc Test_Model_WhereOrNotIn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotIn(\"id\", g.Slice{1, 2, 3, 4}).WhereOrNotIn(\"id\", g.Slice{3, 4, 5}).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[4][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_WhereBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereBetween(\"id\", 1, 4).WhereBetween(\"id\", 3, 5).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 3)\n\t\tt.Assert(result[1][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotBetween(\"id\", 2, 8).WhereNotBetween(\"id\", 3, 100).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrBetween(\"id\", 1, 4).WhereOrBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 5)\n\t\tt.Assert(result[0][\"id\"], 5)\n\t\tt.Assert(result[4][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereOrNotBetween(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\t// db.SetDebug(true)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotBetween(\"id\", 1, 4).WhereOrNotBetween(\"id\", 3, 5).OrderDesc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 8)\n\t\tt.Assert(result[0][\"id\"], 10)\n\t\tt.Assert(result[4][\"id\"], 6)\n\t})\n}\n\nfunc Test_Model_WhereLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereOrLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrLike(\"nickname\", \"namexxx%\").WhereOrLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereOrNotLike(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotLike(\"nickname\", \"namexxx%\").WhereOrNotLike(\"nickname\", \"name%\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNull(\"nickname\").WhereNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_Model_WhereNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereNotNull(\"nickname\").WhereNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\n// func Test_Model_WhereOrNull(t *testing.T) {\n// \ttable := createInitTable()\n// \tdefer dropTable(table)\n\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\tresult, err := db.Model(table).WhereOrNull(\"nickname\").WhereOrNull(\"passport\").OrderAsc(\"id\").OrderRandom().All()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(len(result), 0)\n// \t})\n// }\n\nfunc Test_Model_WhereOrNotNull(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereOrNotNull(\"nickname\").WhereOrNotNull(\"passport\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), TableSize)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[TableSize-1][\"id\"], TableSize)\n\t})\n}\n\nfunc Test_Model_WhereLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t})\n}\n\nfunc Test_Model_WhereGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0][\"id\"], 9)\n\t})\n}\n\nfunc Test_Model_WhereGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrLT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLT(\"id\", 3).WhereOrLT(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[2][\"id\"], 3)\n\t})\n}\n\nfunc Test_Model_WhereOrLTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereLTE(\"id\", 3).WhereOrLTE(\"id\", 4).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 1)\n\t\tt.Assert(result[3][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_WhereOrGT(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGT(\"id\", 8).WhereOrGT(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 3)\n\t\tt.Assert(result[0][\"id\"], 8)\n\t})\n}\n\nfunc Test_Model_WhereOrGTE(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereGTE(\"id\", 8).WhereOrGTE(\"id\", 7).OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 4)\n\t\tt.Assert(result[0][\"id\"], 7)\n\t})\n}\n\nfunc Test_Model_Min_Max_Avg_Sum(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Min(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Max(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Avg(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 5.5)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Sum(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 55)\n\t})\n}\n\nfunc Test_Model_CountColumn(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, TableSize)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).WhereIn(\"id\", g.Slice{1, 2, 3}).CountColumn(\"id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, 3)\n\t})\n}\n\nfunc Test_Model_InsertAndGetId(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"user_1\",\n\t\t\t\"password\":    \"pass_1\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid, err := db.Model(table).Data(g.Map{\n\t\t\t\"passport\":    \"user_2\",\n\t\t\t\"password\":    \"pass_2\",\n\t\t\t\"nickname\":    \"name_2\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}).InsertAndGetId()\n\t\tt.AssertNil(err)\n\t\tt.Assert(id, 2)\n\t})\n}\n\nfunc Test_Model_Increment_Decrement(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 1).Increment(\"id\", 100)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := db.Model(table).Where(\"id\", 101).Decrement(\"id\", 10)\n\t\tt.AssertNil(err)\n\t\trows, _ := result.RowsAffected()\n\t\tt.Assert(rows, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 91).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(1))\n\t})\n}\n\nfunc Test_Model_Raw(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tAll()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 2)\n\t\tt.Assert(all[0][\"id\"], 7)\n\t\tt.Assert(all[1][\"id\"], 5)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.\n\t\t\tRaw(fmt.Sprintf(\"select * from %s where id in (?)\", table), g.Slice{1, 5, 7, 8, 9, 10}).\n\t\t\tWhereLT(\"id\", 8).\n\t\t\tWhereIn(\"id\", g.Slice{1, 2, 3, 4, 5, 6, 7}).\n\t\t\tOrderDesc(\"id\").\n\t\t\tLimit(2).\n\t\t\tCount()\n\t\tt.AssertNil(err)\n\t\t// After fix for issue #4500, Where conditions are correctly applied to Raw SQL Count.\n\t\t// Raw SQL matches: id in (1, 5, 7, 8, 9, 10)\n\t\t// WhereLT(\"id\", 8): id < 8 -> (1, 5, 7)\n\t\t// WhereIn(\"id\", {1-7}): id in (1, 2, 3, 4, 5, 6, 7) -> (1, 5, 7)\n\t\t// Result: 3 records match all conditions\n\t\tt.Assert(count, int64(3))\n\t})\n}\n\nfunc Test_Model_Handler(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := db.Model(table).Safe().Handler(\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Page(0, 3)\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.Where(\"id\", g.Slice{1, 2, 3, 4, 5, 6})\n\t\t\t},\n\t\t\tfunc(m *gdb.Model) *gdb.Model {\n\t\t\t\treturn m.OrderDesc(\"id\")\n\t\t\t},\n\t\t)\n\t\tall, err := m.All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), 3)\n\t\tt.Assert(all[0][\"id\"], 6)\n\t\tt.Assert(all[2][\"id\"], 4)\n\t})\n}\n\nfunc Test_Model_FieldCount(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldCount(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMax(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMax(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldMin(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldMin(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_FieldAvg(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tall, err := db.Model(table).Fields(\"id\").FieldAvg(\"id\", \"total\").Group(\"id\").OrderAsc(\"id\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(all), TableSize)\n\t\tt.Assert(all[0][\"id\"], 1)\n\t\tt.Assert(all[0][\"total\"].Int(), 1)\n\t})\n}\n\nfunc Test_Model_OmitEmptyWhere(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\t// Basic type where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", 0).Where(\"nickname\", \"\").Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Slice where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{1, 2, 3}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(3))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).OmitEmptyWhere().Where(\"id\", g.Slice{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(\"id\", g.Slice{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Struct Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Input struct {\n\t\t\tId   []int\n\t\t\tName []string\n\t\t}\n\t\tcount, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n\t// Map Where.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\":       []int{},\n\t\t\t\"nickname\": []string{},\n\t\t}).Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(0))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcount, err := db.Model(table).Where(g.Map{\n\t\t\t\"id\": []int{},\n\t\t}).OmitEmptyWhere().Count()\n\t\tt.AssertNil(err)\n\t\tt.Assert(count, int64(TableSize))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1387\nfunc Test_Model_GTime_DefaultValue(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId         int\n\t\t\tPassport   string\n\t\t\tPassword   string\n\t\t\tNickname   string\n\t\t\tCreateTime *gtime.Time\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: gtime.Now(),\n\t\t}\n\t\t// Insert\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\n\t\t// Select\n\t\tvar (\n\t\t\tuser *User\n\t\t)\n\t\terr = db.Model(table).Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, data.Passport)\n\t\tt.Assert(user.Password, data.Password)\n\t\tt.Assert(user.CreateTime, data.CreateTime)\n\t\tt.Assert(user.Nickname, data.Nickname)\n\n\t\t// Insert\n\t\tuser.Id = 2\n\t\t_, err = db.Model(table).Data(user).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\n// Using filter does not affect the outside value inside function.\nfunc Test_Model_Insert_Filter(t *testing.T) {\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"uid\":         1,\n\t\t\t\"passport\":    \"t1\",\n\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\"create_time\": gtime.Now().String(),\n\t\t}\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 1)\n\n\t\tt.Assert(data[\"uid\"], 1)\n\t})\n\t// slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttable := createTable()\n\t\tdefer dropTable(table)\n\t\tdata := g.List{\n\t\t\tg.Map{\n\t\t\t\t\"id\":          1,\n\t\t\t\t\"uid\":         1,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t\tg.Map{\n\t\t\t\t\"id\":          2,\n\t\t\t\t\"uid\":         2,\n\t\t\t\t\"passport\":    \"t1\",\n\t\t\t\t\"password\":    \"25d55ad283aa400af464c76d713c07ad\",\n\t\t\t\t\"nickname\":    \"name_1\",\n\t\t\t\t\"create_time\": gtime.Now().String(),\n\t\t\t},\n\t\t}\n\n\t\tresult, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.LastInsertId()\n\t\tt.Assert(n, 2)\n\n\t\tt.Assert(data[0][\"uid\"], 1)\n\t\tt.Assert(data[1][\"uid\"], 2)\n\t})\n}\n\nfunc Test_Model_Embedded_Filter(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tId         int\n\t\t\tUid        int\n\t\t\tCreateTime string\n\t\t\tNoneExist  string\n\t\t}\n\t\ttype User struct {\n\t\t\tBase\n\t\t\tPassport string\n\t\t\tPassword string\n\t\t\tNickname string\n\t\t}\n\t\tresult, err := db.Model(table).Data(User{\n\t\t\tPassport: \"john-test\",\n\t\t\tPassword: \"123456\",\n\t\t\tNickname: \"John\",\n\t\t\tBase: Base{\n\t\t\t\tId:         100,\n\t\t\t\tUid:        100,\n\t\t\t\tCreateTime: gtime.Now().String(),\n\t\t\t},\n\t\t}).Insert()\n\t\tt.AssertNil(err)\n\t\tn, _ := result.RowsAffected()\n\t\tt.Assert(n, 1)\n\n\t\tvar user *User\n\t\terr = db.Model(table).Fields(user).Where(\"id=100\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user.Passport, \"john-test\")\n\t\tt.Assert(user.Id, 100)\n\t})\n}\n\n// This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0.\nfunc Test_Model_Insert_KeyFieldNameMapping_Error(t *testing.T) {\n\ttable := createTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId             int\n\t\t\tPassport       string\n\t\t\tPassword       string\n\t\t\tNickname       string\n\t\t\tCreateTime     string\n\t\t\tNoneExistField string\n\t\t}\n\t\tdata := User{\n\t\t\tId:         1,\n\t\t\tPassport:   \"user_1\",\n\t\t\tPassword:   \"pass_1\",\n\t\t\tNickname:   \"name_1\",\n\t\t\tCreateTime: \"2020-10-10 12:00:01\",\n\t\t}\n\t\t_, err := db.Model(table).Data(data).Insert()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\ttable1 := \"user\"\n\t\ttable2 := \"score\"\n\t\ttable3 := \"info\"\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tname varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t\t`, table1,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table1)\n\t\t_, err = db.Model(table1).Insert(g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t\tnumber varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t    `, table2,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table2)\n\t\t_, err = db.Model(table2).Insert(g.Map{\n\t\t\t\"id\":      1,\n\t\t\t\"user_id\": 1,\n\t\t\t\"number\":  \"n\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tif _, err := db.Exec(ctx, fmt.Sprintf(`\n\t\tCREATE TABLE IF NOT EXISTS %s (\n\t\t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\tNOT NULL,\n\t\t\tuser_id int(11) NOT NULL DEFAULT 0,\n\t\t\tdescription varchar(500) NOT NULL DEFAULT ''\n\t\t);\n\t\t`, table3,\n\t\t)); err != nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tdefer dropTable(table3)\n\t\t_, err = db.Model(table3).Insert(g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"user_id\":     1,\n\t\t\t\"description\": \"brief\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tone, err := db.Model(\"user\").\n\t\t\tWhere(\"user.id\", 1).\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tOrder(\"user.id asc\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\n\t\tone, err = db.Model(\"user\").\n\t\t\tLeftJoin(\"score\", \"user.id=score.user_id\").\n\t\t\tLeftJoin(\"info\", \"info.id=info.user_id\").\n\t\t\tFields(\"score.number,user.name\").\n\t\t\tOne()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(one), 2)\n\t\tt.Assert(one[\"name\"].String(), \"john\")\n\t\tt.Assert(one[\"number\"].String(), \"n\")\n\t})\n}\n\nfunc Test_Model_WherePrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t})\n}\n\nfunc Test_Model_WhereOrPrefix(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWhereOrPrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2},\n\t\t\t}).\n\t\t\tWhereOrPrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{8, 9},\n\t\t\t}).\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0][\"id\"], \"1\")\n\t\tt.Assert(r[1][\"id\"], \"2\")\n\t\tt.Assert(r[2][\"id\"], \"8\")\n\t\tt.Assert(r[3][\"id\"], \"9\")\n\t})\n}\n\nfunc Test_Model_WherePrefixLike(t *testing.T) {\n\tvar (\n\t\ttable1 = \"table1_\" + gtime.TimestampNanoStr()\n\t\ttable2 = \"table2_\" + gtime.TimestampNanoStr()\n\t)\n\tcreateInitTable(table1)\n\tdefer dropTable(table1)\n\tcreateInitTable(table2)\n\tdefer dropTable(table2)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := db.Model(table1).\n\t\t\tFieldsPrefix(table1, \"*\").\n\t\t\tLeftJoinOnField(table2, \"id\").\n\t\t\tWherePrefix(table1, g.Map{\n\t\t\t\t\"id\": g.Slice{1, 2, 3},\n\t\t\t}).\n\t\t\tWherePrefix(table2, g.Map{\n\t\t\t\t\"id\": g.Slice{3, 4, 5},\n\t\t\t}).\n\t\t\tWherePrefixLike(table2, \"nickname\", \"name%\").\n\t\t\tOrder(\"id asc\").All()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0][\"id\"], \"3\")\n\t})\n}\n\n// TODO\n// https://github.com/gogf/gf/issues/1700\n// func Test_Model_Issue1700(t *testing.T) {\n// \ttable := \"user_\" + gtime.Now().TimestampNanoStr()\n// \tif _, err := db.Exec(ctx, fmt.Sprintf(`\n// \tCREATE TABLE IF NOT EXISTS %s (\n// \t\tid INTEGER\tPRIMARY KEY AUTOINCREMENT\n// \t\t\t\t\tUNIQUE\n// \t\t\t\t\tNOT NULL,\n// \t\tuser_id\tint(10) NOT NULL,\n// \t\tUserId\tint(10) NOT NULL\n// \t);\n// \t`, table,\n// \t)); err != nil {\n// \t\tgtest.AssertNil(err)\n// \t}\n// \tdefer dropTable(table)\n\n// \tgtest.C(t, func(t *gtest.T) {\n// \t\ttype User struct {\n// \t\t\tId     int `orm:\"id\"`\n// \t\t\tUserid int `orm:\"user_id\"`\n// \t\t\tUserId int `orm:\"UserId\"`\n// \t\t}\n// \t\t_, err := db.Model(table).Data(User{\n// \t\t\tId:     1,\n// \t\t\tUserid: 2,\n// \t\t\tUserId: 3,\n// \t\t}).Insert()\n// \t\tt.AssertNil(err)\n\n// \t\tone, err := db.Model(table).One()\n// \t\tt.AssertNil(err)\n// \t\tt.Assert(one, g.Map{\n// \t\t\t\"id\":      1,\n// \t\t\t\"user_id\": 2,\n// \t\t\t\"UserId\":  3,\n// \t\t})\n\n// \t\tfor i := 0; i < 1000; i++ {\n// \t\t\tvar user *User\n// \t\t\terr = db.Model(table).Scan(&user)\n// \t\t\tt.AssertNil(err)\n// \t\t\tt.Assert(user.Id, 1)\n// \t\t\tt.Assert(user.Userid, 2)\n// \t\t\tt.Assert(user.UserId, 3)\n// \t\t}\n// \t})\n// }\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne *S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_StructAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne S1\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(1),\n\t\t\t\t\"age\": gvar.New(20),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(2),\n\t\t\t\t\"age\": gvar.New(21),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"One\", \"One\", \"id:Id\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 20)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 21)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  *S1\n\t\t\tMany []*S2\n\t\t}\n\t\tvar (\n\t\t\ts   []*S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1159\nfunc Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S1 struct {\n\t\t\tId    int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S2 struct {\n\t\t\tId    int\n\t\t\tPid   int\n\t\t\tName  string\n\t\t\tAge   int\n\t\t\tScore int\n\t\t}\n\t\ttype S3 struct {\n\t\t\tOne  S1\n\t\t\tMany []S2\n\t\t}\n\t\tvar (\n\t\t\ts   []S3\n\t\t\terr error\n\t\t)\n\t\tr1 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(1),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t\t\"age\":  gvar.New(16),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(2),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t\t\"age\":  gvar.New(18),\n\t\t\t},\n\t\t}\n\t\terr = r1.ScanList(&s, \"One\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\n\t\tr2 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(100),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(30),\n\t\t\t\t\"name\": gvar.New(\"john\"),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":   gvar.New(200),\n\t\t\t\t\"pid\":  gvar.New(1),\n\t\t\t\t\"age\":  gvar.New(31),\n\t\t\t\t\"name\": gvar.New(\"smith\"),\n\t\t\t},\n\t\t}\n\t\terr = r2.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 30)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 31)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\n\t\tr3 := gdb.Result{\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(100),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(40),\n\t\t\t},\n\t\t\tgdb.Record{\n\t\t\t\t\"id\":  gvar.New(200),\n\t\t\t\t\"pid\": gvar.New(1),\n\t\t\t\t\"age\": gvar.New(41),\n\t\t\t},\n\t\t}\n\t\terr = r3.ScanList(&s, \"Many\", \"One\", \"pid:Id\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(s), 2)\n\t\tt.Assert(s[0].One.Name, \"john\")\n\t\tt.Assert(s[0].One.Age, 16)\n\t\tt.Assert(len(s[0].Many), 2)\n\t\tt.Assert(s[0].Many[0].Name, \"john\")\n\t\tt.Assert(s[0].Many[0].Age, 40)\n\t\tt.Assert(s[0].Many[1].Name, \"smith\")\n\t\tt.Assert(s[0].Many[1].Age, 41)\n\n\t\tt.Assert(s[1].One.Name, \"smith\")\n\t\tt.Assert(s[1].One.Age, 18)\n\t\tt.Assert(len(s[1].Many), 0)\n\t})\n}\n\nfunc TestResult_Structs1(t *testing.T) {\n\ttype A struct {\n\t\tId int `orm:\"id\"`\n\t}\n\ttype B struct {\n\t\t*A\n\t\tName string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr := gdb.Result{\n\t\t\tgdb.Record{\"id\": gvar.New(nil), \"name\": gvar.New(\"john\")},\n\t\t\tgdb.Record{\"id\": gvar.New(nil), \"name\": gvar.New(\"smith\")},\n\t\t}\n\t\tarray := make([]*B, 2)\n\t\terr := r.Structs(&array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(array[0].Id, 0)\n\t\tt.Assert(array[1].Id, 0)\n\t\tt.Assert(array[0].Name, \"john\")\n\t\tt.Assert(array[1].Name, \"smith\")\n\t})\n}\n\nfunc Test_Model_OnDuplicateWithCounter(t *testing.T) {\n\ttable := createInitTable()\n\tdefer dropTable(table)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"id\":          1,\n\t\t\t\"passport\":    \"pp1\",\n\t\t\t\"password\":    \"pw1\",\n\t\t\t\"nickname\":    \"n1\",\n\t\t\t\"create_time\": \"2016-06-06\",\n\t\t}\n\t\t_, err := db.Model(table).OnConflict(\"id\").OnDuplicate(g.Map{\n\t\t\t\"id\": gdb.Counter{Field: \"id\", Value: 999999},\n\t\t}).Data(data).Save()\n\t\tt.AssertNil(err)\n\t\tone, err := db.Model(table).WherePri(1).One()\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(one)\n\t})\n}\n"
  },
  {
    "path": "contrib/drivers/tidb/go.mod",
    "content": "module github.com/gogf/gf/contrib/drivers/tidb/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 v2.10.0\n\tgithub.com/gogf/gf/v2 v2.10.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-sql-driver/mysql v1.7.1 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/gogf/gf/contrib/drivers/mysql/v2 => ../mysql\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/drivers/tidb/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=\ngithub.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/drivers/tidb/tidb.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package tidb implements gdb.Driver, which supports operations for database TiDB.\npackage tidb\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\n\t\"github.com/gogf/gf/contrib/drivers/mysql/v2\"\n)\n\n// Driver is the driver for TiDB database.\n//\n// TiDB is an open-source NewSQL database that supports Hybrid Transactional and Analytical Processing (HTAP).\n// This driver uses the MySQL protocol to communicate with TiDB database, as TiDB is designed to be highly\n// compatible with the MySQL protocol.\n//\n// Although TiDB is compatible with MySQL protocol, it is packaged as a separate driver component\n// rather than reusing the mysql adapter directly. This design allows for future extensibility,\n// such as implementing TiDB-specific features like distributed transactions or optimizations.\ntype Driver struct {\n\t*mysql.Driver\n}\n\nfunc init() {\n\tvar (\n\t\terr         error\n\t\tdriverObj   = New()\n\t\tdriverNames = g.SliceStr{\"tidb\"}\n\t)\n\tfor _, driverName := range driverNames {\n\t\tif err = gdb.Register(driverName, driverObj); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// New creates and returns a driver that implements gdb.Driver, which supports operations for TiDB.\nfunc New() gdb.Driver {\n\tmysqlDriver := mysql.New().(*mysql.Driver)\n\treturn &Driver{\n\t\tDriver: mysqlDriver,\n\t}\n}\n\n// New creates and returns a database object for TiDB.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {\n\tmysqlDB, err := d.Driver.New(core, node)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Driver{\n\t\tDriver: mysqlDB.(*mysql.Driver),\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/README.MD",
    "content": "# GoFrame Metric In OpenTelemetry\n\n## Installation\n\n```\ngo get -u -v github.com/gogf/gf/contrib/metric/otelmetric/v2\n```\n\nsuggested using `go.mod`:\n\n```\nrequire github.com/gogf/gf/contrib/metric/otelmetric/v2 latest\n```\n\n## Example\n\n### [basic](../../../example/metric/basic/main.go)\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\t\"go.opentelemetry.io/otel/exporters/prometheus\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\n\t\"github.com/gogf/gf/contrib/metric/otelmetric/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\nvar (\n\tmeter = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\tInstrumentVersion: \"v1.0\",\n\t})\n\tcounter = meter.MustCounter(\n\t\t\"goframe.metric.demo.counter\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for Counter usage\",\n\t\t\tUnit: \"bytes\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_1\", 1),\n\t\t\t},\n\t\t},\n\t)\n\tupDownCounter = meter.MustUpDownCounter(\n\t\t\"goframe.metric.demo.updown_counter\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for UpDownCounter usage\",\n\t\t\tUnit: \"%\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_2\", 2),\n\t\t\t},\n\t\t},\n\t)\n\thistogram = meter.MustHistogram(\n\t\t\"goframe.metric.demo.histogram\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for histogram usage\",\n\t\t\tUnit: \"ms\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_3\", 3),\n\t\t\t},\n\t\t\tBuckets: []float64{0, 10, 20, 50, 100, 500, 1000, 2000, 5000, 10000},\n\t\t},\n\t)\n\tobservableCounter = meter.MustObservableCounter(\n\t\t\"goframe.metric.demo.observable_counter\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for ObservableCounter usage\",\n\t\t\tUnit: \"%\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_4\", 4),\n\t\t\t},\n\t\t},\n\t)\n\tobservableUpDownCounter = meter.MustObservableUpDownCounter(\n\t\t\"goframe.metric.demo.observable_updown_counter\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for ObservableUpDownCounter usage\",\n\t\t\tUnit: \"%\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_5\", 5),\n\t\t\t},\n\t\t},\n\t)\n\tobservableGauge = meter.MustObservableGauge(\n\t\t\"goframe.metric.demo.observable_gauge\",\n\t\tgmetric.MetricOption{\n\t\t\tHelp: \"This is a simple demo for ObservableGauge usage\",\n\t\t\tUnit: \"%\",\n\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\tgmetric.NewAttribute(\"const_label_6\", 6),\n\t\t\t},\n\t\t},\n\t)\n)\n\nfunc main() {\n\tvar ctx = gctx.New()\n\n\t// Callback for observable metrics.\n\tmeter.MustRegisterCallback(func(ctx context.Context, obs gmetric.Observer) error {\n\t\tobs.Observe(observableCounter, 10)\n\t\tobs.Observe(observableUpDownCounter, 20)\n\t\tobs.Observe(observableGauge, 30)\n\t\treturn nil\n\t}, observableCounter, observableUpDownCounter, observableGauge)\n\n\t// Prometheus exporter to export metrics as Prometheus format.\n\texporter, err := prometheus.New(\n\t\tprometheus.WithoutCounterSuffixes(),\n\t\tprometheus.WithoutUnits(),\n\t)\n\tif err != nil {\n\t\tg.Log().Fatal(ctx, err)\n\t}\n\n\t// OpenTelemetry provider.\n\tprovider := otelmetric.MustProvider(metric.WithReader(exporter))\n\tprovider.SetAsGlobal()\n\tdefer provider.Shutdown(ctx)\n\n\t// Counter.\n\tcounter.Inc(ctx)\n\tcounter.Add(ctx, 10)\n\n\t// UpDownCounter.\n\tupDownCounter.Inc(ctx)\n\tupDownCounter.Add(ctx, 10)\n\tupDownCounter.Dec(ctx)\n\n\t// Record values for histogram.\n\thistogram.Record(1)\n\thistogram.Record(20)\n\thistogram.Record(30)\n\thistogram.Record(101)\n\thistogram.Record(2000)\n\thistogram.Record(9000)\n\thistogram.Record(20000)\n\n\t// HTTP Server for metrics exporting.\n\ts := g.Server()\n\ts.BindHandler(\"/metrics\", ghttp.WrapH(promhttp.Handler()))\n\ts.SetPort(8000)\n\ts.Run()\n}\n```\n\n### [more examples](../../../example/metric/)\n\n## License\n\n`GoFrame Polaris` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n\n"
  },
  {
    "path": "contrib/metric/otelmetric/go.mod",
    "content": "module github.com/gogf/gf/contrib/metric/otelmetric/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/prometheus/client_golang v1.23.2\n\tgo.opentelemetry.io/contrib/instrumentation/runtime v0.63.0\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/exporters/prometheus v0.60.0\n\tgo.opentelemetry.io/otel/metric v1.38.0\n\tgo.opentelemetry.io/otel/sdk v1.38.0\n\tgo.opentelemetry.io/otel/sdk/metric v1.38.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/prometheus/client_model v0.6.2 // indirect\n\tgithub.com/prometheus/common v0.66.1 // indirect\n\tgithub.com/prometheus/otlptranslator v0.0.2 // indirect\n\tgithub.com/prometheus/procfs v0.17.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.2 // indirect\n\tgolang.org/x/net v0.43.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.8 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/metric/otelmetric/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=\ngithub.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=\ngithub.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=\ngithub.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=\ngithub.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ=\ngithub.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=\ngithub.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=\ngithub.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ=\ngo.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo=\ngo.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=\ngo.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=\ngolang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=\ngolang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngoogle.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=\ngoogle.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package otelmetric provides metric functionalities using OpenTelemetry metric.\npackage otelmetric\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// NewProvider creates and returns a metrics provider.\nfunc NewProvider(option ...Option) (gmetric.Provider, error) {\n\tprovider, err := newProvider(option...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn provider, nil\n}\n\n// MustProvider creates and returns a metrics provider.\n// It panics if any error occurs.\nfunc MustProvider(option ...Option) gmetric.Provider {\n\tprovider, err := NewProvider(option...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn provider\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_callback.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localObserver implements interface gmetric.Observer.\ntype localObserver struct {\n\tmetric.Observer\n\tgmetric.MeterOption\n}\n\n// newObserver creates and returns gmetric.Observer.\nfunc newObserver(observer metric.Observer, meterOption gmetric.MeterOption) gmetric.Observer {\n\treturn &localObserver{\n\t\tObserver:    observer,\n\t\tMeterOption: meterOption,\n\t}\n}\n\n// Observe observes the value for certain initialized Metric.\n// It adds the value to total result if the observed Metrics is type of Counter.\n// It sets the value as the result if the observed Metrics is type of Gauge.\nfunc (l *localObserver) Observe(om gmetric.ObservableMetric, value float64, option ...gmetric.Option) {\n\tvar (\n\t\tm                      = om.(gmetric.Metric)\n\t\tconstOption            = getConstOptionByMetric(l.MeterOption, m)\n\t\tdynamicOption          = getDynamicOptionByMetricOption(option...)\n\t\tglobalAttributesOption = getGlobalAttributesOption(gmetric.GetGlobalAttributesOption{\n\t\t\tInstrument:        m.Info().Instrument().Name(),\n\t\t\tInstrumentVersion: m.Info().Instrument().Version(),\n\t\t})\n\t\tobserveOptions = make([]metric.ObserveOption, 0)\n\t)\n\tif globalAttributesOption != nil {\n\t\tobserveOptions = append(observeOptions, globalAttributesOption)\n\t}\n\tif constOption != nil {\n\t\tobserveOptions = append(observeOptions, constOption)\n\t}\n\tif dynamicOption != nil {\n\t\tobserveOptions = append(observeOptions, dynamicOption)\n\t}\n\tl.Observer.ObserveFloat64(metricToFloat64Observable(m), value, observeOptions...)\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localCounterPerformer is an implementer for interface gmetric.CounterPerformer.\ntype localCounterPerformer struct {\n\tgmetric.MeterOption\n\tgmetric.MetricOption\n\tmetric.Float64Counter\n\tconstOption metric.MeasurementOption\n}\n\n// newCounterPerformer creates and returns a CounterPerformer that truly takes action to implement Counter.\nfunc (l *localMeterPerformer) newCounterPerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.CounterPerformer, error) {\n\tvar (\n\t\toptions = []metric.Float64CounterOption{\n\t\t\tmetric.WithDescription(metricOption.Help),\n\t\t\tmetric.WithUnit(metricOption.Unit),\n\t\t}\n\t)\n\tcounter, err := meter.Float64Counter(metricName, options...)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64Counter \"%s\" failed with option: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localCounterPerformer{\n\t\tMetricOption:   metricOption,\n\t\tMeterOption:    l.MeterOption,\n\t\tFloat64Counter: counter,\n\t\tconstOption:    genConstOptionForMetric(l.MeterOption, metricOption),\n\t}, nil\n}\n\n// Inc increments the counter by 1.\nfunc (l *localCounterPerformer) Inc(ctx context.Context, option ...gmetric.Option) {\n\tl.Add(ctx, 1, option...)\n}\n\n// Add adds the given value to the counter. It panics if the value is < 0.\nfunc (l *localCounterPerformer) Add(ctx context.Context, increment float64, option ...gmetric.Option) {\n\tl.Float64Counter.Add(ctx, increment, generateAddOptions(l.MeterOption, l.constOption, option...)...)\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_histogram_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localHistogramPerformer is an implementer for interface HistogramPerformer.\ntype localHistogramPerformer struct {\n\tgmetric.MeterOption\n\tgmetric.MetricOption\n\tmetric.Float64Histogram\n\tconstOption metric.MeasurementOption\n}\n\n// newHistogramPerformer creates and returns a HistogramPerformer that truly takes action to implement Histogram.\nfunc (l *localMeterPerformer) newHistogramPerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.HistogramPerformer, error) {\n\thistogram, err := meter.Float64Histogram(\n\t\tmetricName,\n\t\tmetric.WithDescription(metricOption.Help),\n\t\tmetric.WithUnit(metricOption.Unit),\n\t\tmetric.WithExplicitBucketBoundaries(metricOption.Buckets...),\n\t)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64Histogram \"%s\" failed with option: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localHistogramPerformer{\n\t\tMeterOption:      l.MeterOption,\n\t\tMetricOption:     metricOption,\n\t\tFloat64Histogram: histogram,\n\t\tconstOption:      genConstOptionForMetric(l.MeterOption, metricOption),\n\t}, nil\n}\n\n// Record adds a single value to the histogram. The value is usually positive or zero.\nfunc (l *localHistogramPerformer) Record(increment float64, option ...gmetric.Option) {\n\tl.Float64Histogram.Record(\n\t\tcontext.Background(),\n\t\tincrement,\n\t\tl.generateRecordOptions(option...)...,\n\t)\n}\n\nfunc (l *localHistogramPerformer) generateRecordOptions(option ...gmetric.Option) []metric.RecordOption {\n\tvar (\n\t\tdynamicOption          = getDynamicOptionByMetricOption(option...)\n\t\trecordOptions          = make([]metric.RecordOption, 0)\n\t\tglobalAttributesOption = getGlobalAttributesOption(gmetric.GetGlobalAttributesOption{\n\t\t\tInstrument:        l.MeterOption.Instrument,\n\t\t\tInstrumentVersion: l.MeterOption.InstrumentVersion,\n\t\t})\n\t)\n\tif globalAttributesOption != nil {\n\t\trecordOptions = append(recordOptions, globalAttributesOption)\n\t}\n\tif l.constOption != nil {\n\t\trecordOptions = append(recordOptions, l.constOption)\n\t}\n\tif dynamicOption != nil {\n\t\trecordOptions = append(recordOptions, dynamicOption)\n\t}\n\treturn recordOptions\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_observable_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localCounterPerformer is an implementer for interface CounterPerformer.\ntype localObservableCounterPerformer struct {\n\tgmetric.ObservableMetric\n\tmetric.Float64ObservableCounter\n}\n\n// newObservableCounterPerformer creates and returns a CounterPerformer that truly takes action to implement Counter.\nfunc (l *localMeterPerformer) newObservableCounterPerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.ObservableCounterPerformer, error) {\n\tvar (\n\t\toptions = []metric.Float64ObservableCounterOption{\n\t\t\tmetric.WithDescription(metricOption.Help),\n\t\t\tmetric.WithUnit(metricOption.Unit),\n\t\t}\n\t)\n\tif metricOption.Callback != nil {\n\t\tcallback := metric.WithFloat64Callback(func(ctx context.Context, observer metric.Float64Observer) error {\n\t\t\treturn metricOption.Callback(ctx, l.newMetricObserver(metricOption, observer))\n\t\t})\n\t\toptions = append(options, callback)\n\t}\n\tcounter, err := meter.Float64ObservableCounter(metricName, options...)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64ObservableCounter \"%s\" failed with option: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localObservableCounterPerformer{\n\t\tFloat64ObservableCounter: counter,\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_observable_gauge_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localGaugePerformer is an implementer for interface GaugePerformer.\ntype localObservableGaugePerformer struct {\n\tgmetric.ObservableMetric\n\tmetric.Float64ObservableGauge\n}\n\n// newObservableGaugePerformer creates and returns a GaugePerformer that truly takes action to implement Gauge.\nfunc (l *localMeterPerformer) newObservableGaugePerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.ObservableGaugePerformer, error) {\n\tvar (\n\t\toptions = []metric.Float64ObservableGaugeOption{\n\t\t\tmetric.WithDescription(metricOption.Help),\n\t\t\tmetric.WithUnit(metricOption.Unit),\n\t\t}\n\t)\n\tif metricOption.Callback != nil {\n\t\tcallback := metric.WithFloat64Callback(func(ctx context.Context, observer metric.Float64Observer) error {\n\t\t\treturn metricOption.Callback(ctx, l.newMetricObserver(metricOption, observer))\n\t\t})\n\t\toptions = append(options, callback)\n\t}\n\tgauge, err := meter.Float64ObservableGauge(metricName, options...)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64ObservableGauge \"%s\" failed with option: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localObservableGaugePerformer{\n\t\tFloat64ObservableGauge: gauge,\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_observable_updown_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localObservableUpDownCounterPerformer is an implementer for interface CounterPerformer.\ntype localObservableUpDownCounterPerformer struct {\n\tgmetric.ObservableMetric\n\tmetric.Float64ObservableUpDownCounter\n}\n\n// newObservableUpDownCounterPerformer creates and returns a UpDownCounterPerformer that truly takes action to\n// implement ObservableUpDownCounter.\nfunc (l *localMeterPerformer) newObservableUpDownCounterPerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.ObservableUpDownCounterPerformer, error) {\n\tvar (\n\t\toptions = []metric.Float64ObservableUpDownCounterOption{\n\t\t\tmetric.WithDescription(metricOption.Help),\n\t\t\tmetric.WithUnit(metricOption.Unit),\n\t\t}\n\t)\n\tif metricOption.Callback != nil {\n\t\tcallback := metric.WithFloat64Callback(func(ctx context.Context, observer metric.Float64Observer) error {\n\t\t\treturn metricOption.Callback(ctx, l.newMetricObserver(metricOption, observer))\n\t\t})\n\t\toptions = append(options, callback)\n\t}\n\tcounter, err := meter.Float64ObservableUpDownCounter(metricName, options...)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64ObservableUpDownCounter \"%s\" failed with option: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localObservableUpDownCounterPerformer{\n\t\tFloat64ObservableUpDownCounter: counter,\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\totelmetric \"go.opentelemetry.io/otel/metric\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localMeterPerformer implements interface gmetric.Performer.\ntype localMeterPerformer struct {\n\tgmetric.MeterOption\n\t*metric.MeterProvider\n}\n\n// newMeterPerformer creates and returns gmetric.Meter.\nfunc newMeterPerformer(provider *metric.MeterProvider, option gmetric.MeterOption) gmetric.MeterPerformer {\n\tmeterPerformer := &localMeterPerformer{\n\t\tMeterOption:   option,\n\t\tMeterProvider: provider,\n\t}\n\treturn meterPerformer\n}\n\n// CounterPerformer creates and returns a CounterPerformer that performs\n// the operations for Counter metric.\nfunc (l *localMeterPerformer) CounterPerformer(name string, option gmetric.MetricOption) (gmetric.CounterPerformer, error) {\n\treturn l.newCounterPerformer(l.createMeter(), name, option)\n}\n\n// UpDownCounterPerformer creates and returns a UpDownCounterPerformer that performs\n// the operations for UpDownCounter metric.\nfunc (l *localMeterPerformer) UpDownCounterPerformer(name string, option gmetric.MetricOption) (gmetric.UpDownCounterPerformer, error) {\n\treturn l.newUpDownCounterPerformer(l.createMeter(), name, option)\n}\n\n// HistogramPerformer creates and returns a HistogramPerformer that performs\n// the operations for Histogram metric.\nfunc (l *localMeterPerformer) HistogramPerformer(name string, option gmetric.MetricOption) (gmetric.HistogramPerformer, error) {\n\treturn l.newHistogramPerformer(l.createMeter(), name, option)\n}\n\n// ObservableCounterPerformer creates and returns an ObservableMetric that performs\n// the operations for ObservableCounter metric.\nfunc (l *localMeterPerformer) ObservableCounterPerformer(name string, option gmetric.MetricOption) (gmetric.ObservableMetric, error) {\n\treturn l.newObservableCounterPerformer(l.createMeter(), name, option)\n}\n\n// ObservableUpDownCounterPerformer creates and returns an ObservableMetric that performs\n// the operations for ObservableUpDownCounter metric.\nfunc (l *localMeterPerformer) ObservableUpDownCounterPerformer(name string, option gmetric.MetricOption) (gmetric.ObservableMetric, error) {\n\treturn l.newObservableUpDownCounterPerformer(l.createMeter(), name, option)\n}\n\n// ObservableGaugePerformer creates and returns an ObservableMetric that performs\n// the operations for ObservableGauge metric.\nfunc (l *localMeterPerformer) ObservableGaugePerformer(name string, option gmetric.MetricOption) (gmetric.ObservableMetric, error) {\n\treturn l.newObservableGaugePerformer(l.createMeter(), name, option)\n}\n\n// RegisterCallback registers callback on certain metrics.\n// A callback is bound to certain component and version, it is called when the associated metrics are read.\n// Multiple callbacks on the same component and version will be called by their registered sequence.\nfunc (l *localMeterPerformer) RegisterCallback(\n\tcallback gmetric.Callback, observableMetrics ...gmetric.ObservableMetric,\n) error {\n\tvar metrics = make([]gmetric.Metric, 0)\n\tfor _, v := range observableMetrics {\n\t\tm, ok := v.(gmetric.Metric)\n\t\tif !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid metric parameter \"%s\" for RegisterCallback, which does not implement interface Metric`,\n\t\t\t\treflect.TypeOf(v).String(),\n\t\t\t)\n\t\t}\n\t\tmetrics = append(metrics, m)\n\t}\n\t// group the metric by instrument and instrument version.\n\tvar (\n\t\tinstrumentSet      = gset.NewStrSet()\n\t\tunderlyingMeterMap = map[otelmetric.Meter][]otelmetric.Observable{}\n\t)\n\tfor _, m := range metrics {\n\t\tvar meter = l.Meter(\n\t\t\tm.Info().Instrument().Name(),\n\t\t\totelmetric.WithInstrumentationVersion(m.Info().Instrument().Version()),\n\t\t)\n\t\tinstrumentSet.Add(fmt.Sprintf(\n\t\t\t`%s@%s`,\n\t\t\tm.Info().Instrument().Name(),\n\t\t\tm.Info().Instrument().Version(),\n\t\t))\n\t\tif _, ok := underlyingMeterMap[meter]; !ok {\n\t\t\tunderlyingMeterMap[meter] = make([]otelmetric.Observable, 0)\n\t\t}\n\t\tunderlyingMeterMap[meter] = append(underlyingMeterMap[meter], metricToFloat64Observable(m))\n\t}\n\tif len(underlyingMeterMap) > 1 {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`multiple instrument or instrument version metrics used in the same callback: %s`,\n\t\t\tinstrumentSet.Join(\",\"),\n\t\t)\n\t}\n\t// do callback registering.\n\tfor meter, observables := range underlyingMeterMap {\n\t\t_, err := meter.RegisterCallback(\n\t\t\tfunc(ctx context.Context, observer otelmetric.Observer) error {\n\t\t\t\treturn callback(ctx, newObserver(observer, l.MeterOption))\n\t\t\t},\n\t\t\tobservables...,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn gerror.WrapCode(\n\t\t\t\tgcode.CodeInternalError, err,\n\t\t\t\t`RegisterCallback failed`,\n\t\t\t)\n\t\t}\n\t}\n\treturn nil\n}\n\n// createMeter creates and returns an OpenTelemetry Meter.\nfunc (l *localMeterPerformer) createMeter() otelmetric.Meter {\n\treturn l.Meter(\n\t\tl.Instrument,\n\t\totelmetric.WithInstrumentationVersion(l.InstrumentVersion),\n\t)\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_meter_updown_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localUpDownCounterPerformer is an implementer for interface gmetric.UpDownCounterPerformer.\ntype localUpDownCounterPerformer struct {\n\tgmetric.MeterOption\n\tgmetric.MetricOption\n\tmetric.Float64UpDownCounter\n\tconstOption metric.MeasurementOption\n}\n\n// newUpDownCounterPerformer creates and returns a CounterPerformer that truly takes action to implement Counter.\nfunc (l *localMeterPerformer) newUpDownCounterPerformer(\n\tmeter metric.Meter,\n\tmetricName string,\n\tmetricOption gmetric.MetricOption,\n) (gmetric.UpDownCounterPerformer, error) {\n\tvar (\n\t\toptions = []metric.Float64UpDownCounterOption{\n\t\t\tmetric.WithDescription(metricOption.Help),\n\t\t\tmetric.WithUnit(metricOption.Unit),\n\t\t}\n\t)\n\tcounter, err := meter.Float64UpDownCounter(metricName, options...)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError,\n\t\t\terr,\n\t\t\t`create Float64Counter \"%s\" failed with config: %s`,\n\t\t\tmetricName, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\treturn &localUpDownCounterPerformer{\n\t\tMeterOption:          l.MeterOption,\n\t\tMetricOption:         metricOption,\n\t\tFloat64UpDownCounter: counter,\n\t\tconstOption:          genConstOptionForMetric(l.MeterOption, metricOption),\n\t}, nil\n}\n\n// Inc increments the counter by 1.\nfunc (l *localUpDownCounterPerformer) Inc(ctx context.Context, option ...gmetric.Option) {\n\tl.Add(ctx, 1, option...)\n}\n\n// Dec decrements the counter by 1.\nfunc (l *localUpDownCounterPerformer) Dec(ctx context.Context, option ...gmetric.Option) {\n\tl.Add(ctx, -1, option...)\n}\n\n// Add adds the given value to the counter.\nfunc (l *localUpDownCounterPerformer) Add(ctx context.Context, increment float64, option ...gmetric.Option) {\n\tl.Float64UpDownCounter.Add(ctx, increment, generateAddOptions(l.MeterOption, l.constOption, option...)...)\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_metric_callback.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localMetricObserver implements interface gmetric.CallbackObserver.\ntype localMetricObserver struct {\n\tgmetric.MeterOption\n\tgmetric.MetricOption\n\tmetric.Float64Observer\n}\n\nfunc (l *localMeterPerformer) newMetricObserver(\n\tmetricOption gmetric.MetricOption,\n\tfloat64Observer metric.Float64Observer,\n) gmetric.MetricObserver {\n\treturn &localMetricObserver{\n\t\tMeterOption:     l.MeterOption,\n\t\tMetricOption:    metricOption,\n\t\tFloat64Observer: float64Observer,\n\t}\n}\n\n// Observe observes the value for certain initialized Metric.\n// It adds the value to total result if the observed Metrics is type of Counter.\n// It sets the value as the result if the observed Metrics is type of Gauge.\nfunc (l *localMetricObserver) Observe(value float64, option ...gmetric.Option) {\n\tvar (\n\t\tconstOption            = genConstOptionForMetric(l.MeterOption, l.MetricOption)\n\t\tdynamicOption          = getDynamicOptionByMetricOption(option...)\n\t\tglobalAttributesOption = getGlobalAttributesOption(gmetric.GetGlobalAttributesOption{\n\t\t\tInstrument:        l.Instrument,\n\t\t\tInstrumentVersion: l.InstrumentVersion,\n\t\t})\n\t\tobserveOptions = make([]metric.ObserveOption, 0)\n\t)\n\tif globalAttributesOption != nil {\n\t\tobserveOptions = append(observeOptions, globalAttributesOption)\n\t}\n\tif constOption != nil {\n\t\tobserveOptions = append(observeOptions, constOption)\n\t}\n\tif dynamicOption != nil {\n\t\tobserveOptions = append(observeOptions, dynamicOption)\n\t}\n\tl.Float64Observer.Observe(value, observeOptions...)\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_option.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\t\"go.opentelemetry.io/otel/sdk/metric/exemplar\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n)\n\n// newProviderConfigByOptions returns a config configured with options.\nfunc newProviderConfigByOptions(options []Option) providerConfig {\n\tconf := providerConfig{}\n\tfor _, o := range options {\n\t\tconf = o.apply(conf)\n\t}\n\treturn conf\n}\n\n// Option applies a configuration option value to a MeterProvider.\ntype Option interface {\n\tapply(providerConfig) providerConfig\n}\n\n// optionFunc applies a set of options to a config.\ntype optionFunc func(providerConfig) providerConfig\n\n// apply returns a config with option(s) applied.\nfunc (o optionFunc) apply(conf providerConfig) providerConfig {\n\treturn o(conf)\n}\n\n// providerConfig is the configuration for Provider.\ntype providerConfig struct {\n\tviewOption            metric.Option\n\treaderOption          metric.Option\n\tresourceOption        metric.Option\n\texemplarFilter        metric.Option\n\tenabledBuiltInMetrics bool\n}\n\n// IsBuiltInMetricsEnabled returns whether the builtin metrics is enabled.\nfunc (cfg providerConfig) IsBuiltInMetricsEnabled() bool {\n\treturn cfg.enabledBuiltInMetrics\n}\n\n// MetricOptions converts and returns the providerConfig as metrics options.\nfunc (cfg providerConfig) MetricOptions() []metric.Option {\n\tvar metricOptions = make([]metric.Option, 0)\n\tif cfg.viewOption != nil {\n\t\tmetricOptions = append(metricOptions, cfg.viewOption)\n\t}\n\tif cfg.readerOption != nil {\n\t\tmetricOptions = append(metricOptions, cfg.readerOption)\n\t}\n\tif cfg.resourceOption != nil {\n\t\tmetricOptions = append(metricOptions, cfg.resourceOption)\n\t}\n\tif cfg.exemplarFilter != nil {\n\t\tmetricOptions = append(metricOptions, cfg.exemplarFilter)\n\t}\n\treturn metricOptions\n}\n\n// WithBuiltInMetrics enables builtin metrics.\nfunc WithBuiltInMetrics() Option {\n\treturn optionFunc(func(cfg providerConfig) providerConfig {\n\t\tcfg.enabledBuiltInMetrics = true\n\t\treturn cfg\n\t})\n}\n\n// WithResource associates a Resource with a MeterProvider. This Resource\n// represents the entity producing telemetry and is associated with all Meters\n// the MeterProvider will create.\nfunc WithResource(res *resource.Resource) Option {\n\treturn optionFunc(func(cfg providerConfig) providerConfig {\n\t\tcfg.resourceOption = metric.WithResource(res)\n\t\treturn cfg\n\t})\n}\n\n// WithReader associates Reader r with a MeterProvider.\n//\n// By default, if this option is not used, the MeterProvider will perform no\n// operations; no data will be exported without a Reader.\nfunc WithReader(reader metric.Reader) Option {\n\treturn optionFunc(func(cfg providerConfig) providerConfig {\n\t\tif reader == nil {\n\t\t\treturn cfg\n\t\t}\n\t\tcfg.readerOption = metric.WithReader(reader)\n\t\treturn cfg\n\t})\n}\n\n// WithView associates views a MeterProvider.\n//\n// Views are appended to existing ones in a MeterProvider if this option is\n// used multiple times.\n//\n// By default, if this option is not used, the MeterProvider will use the\n// default view.\nfunc WithView(views ...metric.View) Option {\n\treturn optionFunc(func(cfg providerConfig) providerConfig {\n\t\tcfg.viewOption = metric.WithView(views...)\n\t\treturn cfg\n\t})\n}\n\n// WithExemplarFilter configures the exemplar filter.\n//\n// The exemplar filter determines which measurements are offered to the\n// exemplar reservoir, but the exemplar reservoir makes the final decision of\n// whether to store an exemplar.\n//\n// By default, the [exemplar.SampledFilter]\n// is used. Exemplars can be entirely disabled by providing the\n// [exemplar.AlwaysOffFilter].\nfunc WithExemplarFilter(filter exemplar.Filter) Option {\n\treturn optionFunc(func(cfg providerConfig) providerConfig {\n\t\tcfg.exemplarFilter = metric.WithExemplarFilter(filter)\n\t\treturn cfg\n\t})\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_prometheus.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/collectors\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n)\n\n// PrometheusHandler returns the http handler for prometheus metrics exporting.\nfunc PrometheusHandler(r *ghttp.Request) {\n\t// Remove all builtin metrics that are produced by prometheus client.\n\tprometheus.Unregister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))\n\tprometheus.Unregister(collectors.NewGoCollector())\n\n\thandler := promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})\n\thandler.ServeHTTP(r.Response.Writer, r.Request)\n}\n\n// StartPrometheusMetricsServer starts running a http server for metrics exporting.\nfunc StartPrometheusMetricsServer(port int, path string) {\n\ts := g.Server()\n\ts.BindHandler(path, PrometheusHandler)\n\ts.SetPort(port)\n\ts.Run()\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_provider.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"time\"\n\n\t\"go.opentelemetry.io/contrib/instrumentation/runtime\"\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/sdk/instrumentation\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n)\n\n// localProvider implements interface gmetric.Provider.\ntype localProvider struct {\n\t*metric.MeterProvider\n}\n\n// newProvider creates and returns an object that implements gmetric.Provider.\n// DO NOT set this as global provider internally.\nfunc newProvider(options ...Option) (gmetric.Provider, error) {\n\t// TODO global logger set for otel.\n\t// otel.SetLogger()\n\n\tvar (\n\t\terr          error\n\t\tmetrics      = gmetric.GetAllMetrics()\n\t\tbuiltinViews = createViewsForBuiltInMetrics()\n\t\tcallbacks    = gmetric.GetRegisteredCallbacks()\n\t)\n\toptions = append(options, WithView(builtinViews...))\n\n\tvar (\n\t\tconfig   = newProviderConfigByOptions(options)\n\t\tprovider = &localProvider{\n\t\t\t// MeterProvider is the core object that can create otel metrics.\n\t\t\tMeterProvider: metric.NewMeterProvider(config.MetricOptions()...),\n\t\t}\n\t)\n\n\tif err = provider.initializeMetrics(metrics); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = provider.initializeCallback(callbacks); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// builtin metrics: golang.\n\tif config.IsBuiltInMetricsEnabled() {\n\t\terr = runtime.Start(\n\t\t\truntime.WithMinimumReadMemStatsInterval(time.Second),\n\t\t\truntime.WithMeterProvider(provider),\n\t\t)\n\t}\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(\n\t\t\tgcode.CodeInternalError, err, `start built-in runtime metrics failed`,\n\t\t)\n\t}\n\n\treturn provider, nil\n}\n\n// SetAsGlobal sets current provider as global meter provider for current process,\n// which makes the following metrics creating on this Provider, especially the metrics created in runtime.\nfunc (l *localProvider) SetAsGlobal() {\n\tgmetric.SetGlobalProvider(l)\n\totel.SetMeterProvider(l)\n}\n\n// MeterPerformer creates and returns a MeterPerformer.\n// A Performer can produce types of Metric performer.\nfunc (l *localProvider) MeterPerformer(option gmetric.MeterOption) gmetric.MeterPerformer {\n\treturn newMeterPerformer(l.MeterProvider, option)\n}\n\n// createViewsForBuiltInMetrics creates and returns views for builtin metrics.\nfunc createViewsForBuiltInMetrics() []metric.View {\n\tvar views = make([]metric.View, 0)\n\tviews = append(views, metric.NewView(\n\t\tmetric.Instrument{\n\t\t\tName: \"process.runtime.go.gc.pause_ns\",\n\t\t\tScope: instrumentation.Scope{\n\t\t\t\tName:    runtime.ScopeName,\n\t\t\t\tVersion: runtime.Version(),\n\t\t\t},\n\t\t},\n\t\tmetric.Stream{\n\t\t\tAggregation: metric.AggregationExplicitBucketHistogram{\n\t\t\t\tBoundaries: []float64{\n\t\t\t\t\t500, 1000, 5000, 10000, 50000, 100000, 500000, 1000000,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t))\n\tviews = append(views, metric.NewView(\n\t\tmetric.Instrument{\n\t\t\tName: \"runtime.uptime\",\n\t\t\tScope: instrumentation.Scope{\n\t\t\t\tName:    runtime.ScopeName,\n\t\t\t\tVersion: runtime.Version(),\n\t\t\t},\n\t\t},\n\t\tmetric.Stream{\n\t\t\tName: \"process.runtime.uptime\",\n\t\t},\n\t))\n\treturn views\n}\n\n// initializeMetrics initializes all metrics in provider creating.\n// The initialization replaces the underlying metric performer using noop-performer with truly performer\n// that implements operations for types of metric.\nfunc (l *localProvider) initializeMetrics(metrics []gmetric.Metric) error {\n\tfor _, m := range metrics {\n\t\tif initializer, ok := m.(gmetric.MetricInitializer); ok {\n\t\t\tif err := initializer.Init(l); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (l *localProvider) initializeCallback(callbackItems []gmetric.CallbackItem) error {\n\tvar err error\n\tfor _, callbackItem := range callbackItems {\n\t\tif callbackItem.Provider != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif len(callbackItem.Metrics) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tcallbackItem.Provider = l\n\t\tif err = l.MeterPerformer(callbackItem.MeterOption).RegisterCallback(\n\t\t\tcallbackItem.Callback, callbackItem.Metrics...,\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_util.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric\n\nimport (\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc generateAddOptions(\n\tmeterOption gmetric.MeterOption, constOption metric.MeasurementOption, option ...gmetric.Option,\n) []metric.AddOption {\n\tvar (\n\t\taddOptions             = make([]metric.AddOption, 0)\n\t\tglobalAttributesOption = getGlobalAttributesOption(gmetric.GetGlobalAttributesOption{\n\t\t\tInstrument:        meterOption.Instrument,\n\t\t\tInstrumentVersion: meterOption.InstrumentVersion,\n\t\t})\n\t)\n\tif constOption != nil {\n\t\taddOptions = append(addOptions, constOption)\n\t}\n\tif globalAttributesOption != nil {\n\t\taddOptions = append(addOptions, globalAttributesOption)\n\t}\n\tif len(option) > 0 {\n\t\taddOptions = append(\n\t\t\taddOptions,\n\t\t\tmetric.WithAttributes(attributesToKeyValues(option[0].Attributes)...),\n\t\t)\n\t}\n\treturn addOptions\n}\n\nfunc getGlobalAttributesOption(option gmetric.GetGlobalAttributesOption) metric.MeasurementOption {\n\tvar (\n\t\tglobalAttributesOption metric.MeasurementOption\n\t\tglobalAttributes       = gmetric.GetGlobalAttributes(gmetric.GetGlobalAttributesOption{})\n\t\tinstrumentAttributes   gmetric.Attributes\n\t)\n\tif option.Instrument != \"\" {\n\t\tinstrumentAttributes = gmetric.GetGlobalAttributes(option)\n\t}\n\tif len(globalAttributes) > 0 {\n\t\tglobalAttributesOption = metric.WithAttributes(attributesToKeyValues(globalAttributes)...)\n\t}\n\tif len(instrumentAttributes) > 0 {\n\t\tglobalAttributesOption = metric.WithAttributes(attributesToKeyValues(instrumentAttributes)...)\n\t}\n\treturn globalAttributesOption\n}\n\nfunc getDynamicOptionByMetricOption(option ...gmetric.Option) metric.MeasurementOption {\n\tvar (\n\t\tusedOption    gmetric.Option\n\t\tdynamicOption metric.MeasurementOption\n\t)\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tif len(usedOption.Attributes) > 0 {\n\t\tdynamicOption = metric.WithAttributes(attributesToKeyValues(usedOption.Attributes)...)\n\t}\n\treturn dynamicOption\n}\n\nfunc genConstOptionForMetric(\n\tmeterOption gmetric.MeterOption,\n\tmetricOption gmetric.MetricOption,\n) metric.MeasurementOption {\n\treturn genConstOptionForMetricByAttributes(meterOption.Attributes, metricOption.Attributes)\n}\n\nfunc getConstOptionByMetric(meterOption gmetric.MeterOption, m gmetric.Metric) metric.MeasurementOption {\n\treturn genConstOptionForMetricByAttributes(meterOption.Attributes, m.Info().Attributes())\n}\n\nfunc genConstOptionForMetricByAttributes(\n\tmeterAttrs gmetric.Attributes,\n\tmetricAttrs gmetric.Attributes,\n) metric.MeasurementOption {\n\tvar (\n\t\tconstOption metric.MeasurementOption\n\t\tattributes  = make([]attribute.KeyValue, 0)\n\t)\n\tif len(meterAttrs) > 0 {\n\t\tattributes = append(attributes, attributesToKeyValues(meterAttrs)...)\n\t}\n\tif len(metricAttrs) > 0 {\n\t\tattributes = append(attributes, attributesToKeyValues(metricAttrs)...)\n\t}\n\tconstOption = metric.WithAttributes(attributes...)\n\treturn constOption\n}\n\nfunc metricToFloat64Observable(m gmetric.Metric) metric.Float64Observable {\n\tperformer := m.(gmetric.PerformerExporter).Performer()\n\tswitch m.Info().Type() {\n\tcase gmetric.MetricTypeObservableCounter:\n\t\treturn performer.(*localObservableCounterPerformer).Float64ObservableCounter\n\n\tcase gmetric.MetricTypeObservableUpDownCounter:\n\t\treturn performer.(*localObservableUpDownCounterPerformer).Float64ObservableUpDownCounter\n\n\tcase gmetric.MetricTypeObservableGauge:\n\t\treturn performer.(*localObservableGaugePerformer).Float64ObservableGauge\n\n\tdefault:\n\t\tpanic(gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`Histogram is not support for converting to metric.Float64Observable`,\n\t\t))\n\t}\n\treturn nil\n}\n\n// attributesToKeyValues converts attributes to OpenTelemetry key-value pair attributes.\nfunc attributesToKeyValues(attrs gmetric.Attributes) []attribute.KeyValue {\n\tvar keyValues = make([]attribute.KeyValue, 0)\n\tfor _, attr := range attrs {\n\t\tkeyValues = append(keyValues, attributeToKeyValue(attr))\n\t}\n\treturn keyValues\n}\n\n// attributeToKeyValue converts attribute to OpenTelemetry key-value pair attribute.\nfunc attributeToKeyValue(attr gmetric.Attribute) attribute.KeyValue {\n\tvar (\n\t\tkey   = string(attr.Key())\n\t\tvalue = attr.Value()\n\t)\n\tswitch result := value.(type) {\n\tcase bool:\n\t\treturn attribute.Bool(key, result)\n\tcase []bool:\n\t\treturn attribute.BoolSlice(key, result)\n\n\tcase int:\n\t\treturn attribute.Int(key, result)\n\tcase []int:\n\t\treturn attribute.IntSlice(key, result)\n\n\tcase int64:\n\t\treturn attribute.Int64(key, result)\n\tcase []int64:\n\t\treturn attribute.Int64Slice(key, result)\n\n\tcase float64:\n\t\treturn attribute.Float64(key, result)\n\tcase []float64:\n\t\treturn attribute.Float64Slice(key, result)\n\n\tcase string:\n\t\treturn attribute.String(key, result)\n\tcase []string:\n\t\treturn attribute.StringSlice(key, result)\n\n\tdefault:\n\t\treturn attribute.String(key, gconv.String(value))\n\t}\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_z_unit_http_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\t\"go.opentelemetry.io/otel/exporters/prometheus\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/metric/otelmetric/v2\"\n)\n\nfunc Test_HTTP_Server(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.BindHandler(\"/user/:id\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"user\")\n\t\t})\n\t\ts.BindHandler(\"/order/:id\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"order\")\n\t\t})\n\t\ts.BindHandler(\"/metrics\", ghttp.WrapH(promhttp.Handler()))\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tvar ctx = gctx.New()\n\t\t// Prometheus exporter to export metrics as Prometheus format.\n\t\texporter, err := prometheus.New(\n\t\t\tprometheus.WithoutCounterSuffixes(),\n\t\t\tprometheus.WithoutUnits(),\n\t\t)\n\t\tif err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\n\t\t// OpenTelemetry provider.\n\t\tprovider := otelmetric.MustProvider(otelmetric.WithReader(exporter))\n\t\tdefer provider.Shutdown(ctx)\n\n\t\tgmetric.SetGlobalProvider(provider)\n\t\tdefer gmetric.SetGlobalProvider(nil)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tc.GetContent(ctx, \"/user/1\")\n\t\tc.PutContent(ctx, \"/user/1\", \"123\")\n\t\tc.PostContent(ctx, \"/user/2\", \"123\")\n\t\tc.DeleteContent(ctx, \"/user/3\")\n\t\tc.GetContent(ctx, \"/order/1\")\n\t\tc.PutContent(ctx, \"/order/1\", \"1234\")\n\t\tc.PostContent(ctx, \"/order/2\", \"1234\")\n\t\tc.DeleteContent(ctx, \"/order/3\")\n\n\t\tvar (\n\t\t\tmetricsContent = c.GetContent(ctx, \"/metrics\")\n\t\t\texpectContent  = gtest.DataContent(\"http.prometheus.metrics.txt\")\n\t\t)\n\t\texpectContent, _ = gregex.ReplaceString(\n\t\t\t`otel_scope_version=\".+?\"`,\n\t\t\tfmt.Sprintf(`otel_scope_version=\"%s\"`, gf.VERSION),\n\t\t\texpectContent,\n\t\t)\n\t\texpectContent, _ = gregex.ReplaceString(\n\t\t\t`server_port=\".+?\"`,\n\t\t\tfmt.Sprintf(`server_port=\"%d\"`, s.GetListenedPort()),\n\t\t\texpectContent,\n\t\t)\n\t\t// fmt.Println(metricsContent)\n\t\tfor _, line := range gstr.SplitAndTrim(expectContent, \"\\n\") {\n\t\t\t// fmt.Println(line)\n\t\t\tt.Assert(gstr.Contains(metricsContent, line), true)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/otelmetric_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage otelmetric_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\t\"go.opentelemetry.io/otel/sdk/metric/metricdata\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\n\t\"github.com/gogf/gf/contrib/metric/otelmetric/v2\"\n)\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tmeterV11 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.1\",\n\t\t\t})\n\t\t\tmeterV12 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.2\",\n\t\t\t})\n\t\t\tmeterV13 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.3\",\n\t\t\t})\n\t\t\tmeterV14 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.4\",\n\t\t\t})\n\t\t\tcounter = meterV11.MustCounter(\n\t\t\t\t\"goframe.metric.demo.counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for Counter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_1\", 1),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\tupDownCounter = meterV12.MustUpDownCounter(\n\t\t\t\t\"goframe.metric.demo.updown_counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for UpDownCounter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_2\", 2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\thistogram = meterV13.MustHistogram(\n\t\t\t\t\"goframe.metric.demo.histogram\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for histogram usage\",\n\t\t\t\t\tUnit: \"ms\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_3\", 3),\n\t\t\t\t\t},\n\t\t\t\t\tBuckets: []float64{0, 10, 20, 50, 100, 500, 1000, 2000, 5000, 10000},\n\t\t\t\t},\n\t\t\t)\n\t\t\tobservableCounter = meterV14.MustObservableCounter(\n\t\t\t\t\"goframe.metric.demo.observable_counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for ObservableCounter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_4\", 4),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\tobservableUpDownCounter = meterV14.MustObservableUpDownCounter(\n\t\t\t\t\"goframe.metric.demo.observable_updown_counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for ObservableUpDownCounter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_5\", 5),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t\tobservableGauge = meterV14.MustObservableGauge(\n\t\t\t\t\"goframe.metric.demo.observable_gauge\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for ObservableGauge usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_6\", 6),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t)\n\n\t\tmeterV14.MustRegisterCallback(func(ctx context.Context, obs gmetric.Observer) error {\n\t\t\tobs.Observe(observableCounter, 10, gmetric.Option{\n\t\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_4\", \"4\")},\n\t\t\t})\n\t\t\tobs.Observe(observableUpDownCounter, 20, gmetric.Option{\n\t\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_5\", \"5\")},\n\t\t\t})\n\t\t\tobs.Observe(observableGauge, 30, gmetric.Option{\n\t\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_6\", \"6\")},\n\t\t\t})\n\t\t\treturn nil\n\t\t}, observableCounter, observableUpDownCounter, observableGauge)\n\n\t\treader := metric.NewManualReader()\n\n\t\t// OpenTelemetry provider.\n\t\tprovider := otelmetric.MustProvider(otelmetric.WithReader(reader))\n\t\tdefer provider.Shutdown(ctx)\n\n\t\t// Counter.\n\t\tcounter.Inc(ctx)\n\t\tcounter.Add(ctx, 10, gmetric.Option{\n\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_1\", \"1\")},\n\t\t})\n\n\t\tupDownCounter.Add(ctx, 10)\n\t\tupDownCounter.Dec(ctx, gmetric.Option{\n\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_2\", \"2\")},\n\t\t})\n\n\t\t// Record values for histogram.\n\t\thistogram.Record(1)\n\t\thistogram.Record(20)\n\t\thistogram.Record(30)\n\t\thistogram.Record(101)\n\t\thistogram.Record(2000)\n\t\thistogram.Record(9000)\n\t\thistogram.Record(20000)\n\n\t\thistogramOption := gmetric.Option{\n\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_3\", \"3\")},\n\t\t}\n\t\thistogram.Record(100, histogramOption)\n\t\thistogram.Record(200, histogramOption)\n\n\t\trm := metricdata.ResourceMetrics{}\n\t\terr := reader.Collect(ctx, &rm)\n\t\tt.AssertNil(err)\n\n\t\tmetricsJsonContent := gjson.MustEncodeString(rm)\n\n\t\tt.Assert(len(rm.ScopeMetrics), 4)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.counter`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.updown_counter`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.histogram`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_counter`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_updown_counter\"`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_gauge`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_2\",\"Value\":{\"Type\":\"INT64\",\"Value\":2}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_2\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"2\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_3\",\"Value\":{\"Type\":\"INT64\",\"Value\":3}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `\"Count\":7,\"Bounds\":[0,10,20,50,100,500,1000,2000,5000,10000],\"BucketCounts\":[0,1,1,1,0,1,0,1,0,1,1],\"Min\":1,\"Max\":20000,\"Sum\":31152`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_3\",\"Value\":{\"Type\":\"INT64\",\"Value\":3}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_3\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"3\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `\"Count\":2,\"Bounds\":[0,10,20,50,100,500,1000,2000,5000,10000],\"BucketCounts\":[0,0,0,0,1,1,0,0,0,0,0],\"Min\":100,\"Max\":200,\"Sum\":300`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_4\",\"Value\":{\"Type\":\"INT64\",\"Value\":4}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_4\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"4\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_5\",\"Value\":{\"Type\":\"INT64\",\"Value\":5}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_5\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"5\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_6\",\"Value\":{\"Type\":\"INT64\",\"Value\":6}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_6\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"6\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_1\",\"Value\":{\"Type\":\"INT64\",\"Value\":1}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_1\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"1\"}}`), 1)\n\t})\n}\n\nfunc Test_GlobalAttributes(t *testing.T) {\n\tgmetric.SetGlobalAttributes(gmetric.Attributes{\n\t\tgmetric.NewAttribute(\"g1\", 1),\n\t}, gmetric.SetGlobalAttributesOption{\n\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\tInstrumentVersion: \"v1.1\",\n\t\tInstrumentPattern: \"\",\n\t})\n\tgmetric.SetGlobalAttributes(gmetric.Attributes{\n\t\tgmetric.NewAttribute(\"g2\", 2),\n\t}, gmetric.SetGlobalAttributesOption{\n\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\tInstrumentVersion: \"v1.3\",\n\t\tInstrumentPattern: \"\",\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tmeterV11 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.1\",\n\t\t\t})\n\t\t\tmeterV12 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.2\",\n\t\t\t})\n\t\t\tmeterV13 = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.3\",\n\t\t\t})\n\t\t\tcounter = meterV11.MustCounter(\n\t\t\t\t\"goframe.metric.demo.counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for Counter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_1\", 1),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\n\t\t\thistogram = meterV12.MustHistogram(\n\t\t\t\t\"goframe.metric.demo.histogram\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for histogram usage\",\n\t\t\t\t\tUnit: \"ms\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_2\", 2),\n\t\t\t\t\t},\n\t\t\t\t\tBuckets: []float64{0, 10, 20, 50, 100, 500, 1000, 2000, 5000, 10000},\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tobservableCounter = meterV13.MustObservableCounter(\n\t\t\t\t\"goframe.metric.demo.observable_counter\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for ObservableCounter usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_3\", 3),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tobservableGauge = meterV13.MustObservableGauge(\n\t\t\t\t\"goframe.metric.demo.observable_gauge\",\n\t\t\t\tgmetric.MetricOption{\n\t\t\t\t\tHelp: \"This is a simple demo for ObservableGauge usage\",\n\t\t\t\t\tUnit: \"%\",\n\t\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\t\tgmetric.NewAttribute(\"const_label_4\", 4),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t)\n\n\t\tmeterV13.MustRegisterCallback(func(ctx context.Context, obs gmetric.Observer) error {\n\t\t\tobs.Observe(observableCounter, 10, gmetric.Option{\n\t\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_3\", \"3\")},\n\t\t\t})\n\t\t\tobs.Observe(observableGauge, 10, gmetric.Option{\n\t\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_4\", \"4\")},\n\t\t\t})\n\t\t\treturn nil\n\t\t}, observableCounter, observableGauge)\n\n\t\treader := metric.NewManualReader()\n\n\t\t// OpenTelemetry provider.\n\t\tprovider := otelmetric.MustProvider(otelmetric.WithReader(reader))\n\t\tdefer provider.Shutdown(ctx)\n\n\t\t// Add value for counter.\n\t\tcounter.Inc(ctx)\n\t\tcounter.Add(ctx, 10, gmetric.Option{\n\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_1\", \"1\")},\n\t\t})\n\n\t\t// Record values for histogram.\n\t\thistogram.Record(1)\n\t\thistogram.Record(20)\n\t\thistogram.Record(30)\n\t\thistogram.Record(101)\n\t\thistogram.Record(2000)\n\t\thistogram.Record(9000)\n\t\thistogram.Record(20000)\n\n\t\thistogramOption := gmetric.Option{\n\t\t\tAttributes: gmetric.Attributes{gmetric.NewAttribute(\"dynamic_label_2\", \"2\")},\n\t\t}\n\t\thistogram.Record(100, histogramOption)\n\t\thistogram.Record(200, histogramOption)\n\n\t\trm := metricdata.ResourceMetrics{}\n\t\terr := reader.Collect(ctx, &rm)\n\t\tt.AssertNil(err)\n\n\t\tmetricsJsonContent := gjson.MustEncodeString(rm)\n\t\tt.Assert(len(rm.ScopeMetrics), 3)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.counter`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.histogram`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_counter`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_gauge`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `goframe.metric.demo.observable_gauge`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_1\",\"Value\":{\"Type\":\"INT64\",\"Value\":1}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"g1\",\"Value\":{\"Type\":\"INT64\",\"Value\":1}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_1\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"1\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_2\",\"Value\":{\"Type\":\"INT64\",\"Value\":2}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_2\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"2\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `\"Count\":2,\"Bounds\":[0,10,20,50,100,500,1000,2000,5000,10000],\"BucketCounts\":[0,0,0,0,1,1,0,0,0,0,0],\"Min\":100,\"Max\":200,\"Sum\":300`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `\"Count\":7,\"Bounds\":[0,10,20,50,100,500,1000,2000,5000,10000],\"BucketCounts\":[0,1,1,1,0,1,0,1,0,1,1],\"Min\":1,\"Max\":20000,\"Sum\":31152`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_3\",\"Value\":{\"Type\":\"INT64\",\"Value\":3}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_3\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"3\"}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"g2\",\"Value\":{\"Type\":\"INT64\",\"Value\":2}}`), 2)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"const_label_4\",\"Value\":{\"Type\":\"INT64\",\"Value\":4}}`), 1)\n\t\tt.Assert(gstr.Count(metricsJsonContent, `{\"Key\":\"dynamic_label_4\",\"Value\":{\"Type\":\"STRING\",\"Value\":\"4\"}}`), 1)\n\t})\n}\n"
  },
  {
    "path": "contrib/metric/otelmetric/testdata/http.prometheus.metrics.txt",
    "content": "\n# HELP http_client_connection_duration Measures the connection establish duration of client requests.\n# TYPE http_client_connection_duration histogram\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"25\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"50\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"75\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"100\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"250\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"500\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"750\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1000\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"2500\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5000\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"7500\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10000\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"30000\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"60000\"}\nhttp_client_connection_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"+Inf\"}\nhttp_client_connection_duration_sum{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"}\nhttp_client_connection_duration_count{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"} 9\n# HELP http_client_request_active Number of active client requests.\n# TYPE http_client_request_active gauge\nhttp_client_request_active{http_request_method=\"DELETE\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_client_request_active{http_request_method=\"GET\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_client_request_active{http_request_method=\"POST\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_client_request_active{http_request_method=\"PUT\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\n# HELP http_client_request_body_size Outgoing request bytes total.\n# TYPE http_client_request_body_size counter\nhttp_client_request_body_size{http_request_method=\"POST\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 7\nhttp_client_request_body_size{http_request_method=\"PUT\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 7\n# HELP http_client_request_duration Measures the duration of client requests.\n# TYPE http_client_request_duration histogram\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"25\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"50\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"75\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"100\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"250\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"500\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"750\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1000\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"2500\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5000\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"7500\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10000\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"30000\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"60000\"}\nhttp_client_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"+Inf\"}\nhttp_client_request_duration_sum{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"}\nhttp_client_request_duration_count{otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"} 8\n# HELP http_client_request_duration_total Total execution duration of request.\n# TYPE http_client_request_duration_total counter\nhttp_client_request_duration_total{http_request_method=\"DELETE\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_client_request_duration_total{http_request_method=\"GET\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_client_request_duration_total{http_request_method=\"POST\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_client_request_duration_total{http_request_method=\"PUT\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\n# HELP http_client_request_total Total processed request number.\n# TYPE http_client_request_total counter\nhttp_client_request_total{http_request_method=\"DELETE\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 2\nhttp_client_request_total{http_request_method=\"GET\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 2\nhttp_client_request_total{http_request_method=\"POST\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 2\nhttp_client_request_total{http_request_method=\"PUT\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/gclient.Client\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 2\n# HELP http_server_request_active Number of active server requests.\n# TYPE http_server_request_active gauge\nhttp_server_request_active{http_request_method=\"DELETE\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"DELETE\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"GET\",http_route=\"/metrics\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_active{http_request_method=\"GET\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"GET\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"POST\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"POST\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"PUT\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_active{http_request_method=\"PUT\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\n# HELP http_server_request_body_size Incoming request bytes total.\n# TYPE http_server_request_body_size counter\nhttp_server_request_body_size{http_request_method=\"DELETE\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_body_size{http_request_method=\"DELETE\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_body_size{http_request_method=\"GET\",http_route=\"/metrics\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_body_size{http_request_method=\"GET\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_body_size{http_request_method=\"GET\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 0\nhttp_server_request_body_size{http_request_method=\"POST\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\nhttp_server_request_body_size{http_request_method=\"POST\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 3\nhttp_server_request_body_size{http_request_method=\"PUT\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\nhttp_server_request_body_size{http_request_method=\"PUT\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 3\n# HELP http_server_request_duration Measures the duration of inbound request.\n# TYPE http_server_request_duration histogram\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"25\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"50\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"75\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"100\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"250\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"500\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"750\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"1000\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"2500\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"5000\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"7500\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"10000\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"30000\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"60000\"}\nhttp_server_request_duration_bucket{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",le=\"+Inf\"}\nhttp_server_request_duration_sum{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"}\nhttp_server_request_duration_count{otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\"}\n# HELP http_server_request_duration_total Total execution duration of request.\n# TYPE http_server_request_duration_total counter\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\nhttp_server_request_duration_total{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"}\n# HELP http_server_request_total Total processed request number.\n# TYPE http_server_request_total counter\nhttp_server_request_total{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\nhttp_server_request_total{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 1\n# HELP http_server_response_body_size Response bytes total.\n# TYPE http_server_response_body_size counter\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 5\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"DELETE\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 5\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"GET\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 5\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"POST\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/order/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 5\nhttp_server_response_body_size{error_code=\"0\",http_request_method=\"PUT\",http_response_status_code=\"200\",http_route=\"/user/:id\",network_protocol_version=\"1.1\",otel_scope_name=\"github.com/gogf/gf/v2/net/ghttp.Server\",otel_scope_schema_url=\"\",otel_scope_version=\"v2.6.4\",server_address=\"127.0.0.1\",server_port=\"62730\",url_schema=\"http\"} 4\n"
  },
  {
    "path": "contrib/nosql/redis/README.MD",
    "content": "# redis\nGoFrame `gredis.Adapter` implements using `go-redis`.\n\n# Installation\n```\ngo get -u github.com/gogf/gf/contrib/nosql/redis/v2\n```\n\nCommonly imported at top of `main.go`:\n```go\npackage main\n\nimport (\n\t_ \"github.com/gogf/gf/contrib/nosql/redis/v2\"\n\n\t// Other imported packages.\n)\n\nfunc main() {\n\t// Main logics.\n}\n```\n"
  },
  {
    "path": "contrib/nosql/redis/go.mod",
    "content": "module github.com/gogf/gf/contrib/nosql/redis/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/redis/go-redis/v9 v9.12.1\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/trace v1.38.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/nosql/redis/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=\ngithub.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=\ngithub.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=\ngithub.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/nosql/redis/redis.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package redis provides gredis.Adapter implements using go-redis.\npackage redis\n\nimport (\n\t\"crypto/tls\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Redis is an implement of Adapter using go-redis.\ntype Redis struct {\n\tgredis.AdapterOperation\n\n\tclient redis.UniversalClient\n\tconfig *gredis.Config\n}\n\nconst (\n\tdefaultPoolMaxIdle     = 10\n\tdefaultPoolMaxActive   = 100\n\tdefaultPoolIdleTimeout = 10 * time.Second\n\tdefaultPoolWaitTimeout = 10 * time.Second\n\tdefaultPoolMaxLifeTime = 30 * time.Second\n\tdefaultMaxRetries      = -1\n)\n\nfunc init() {\n\tgredis.RegisterAdapterFunc(func(config *gredis.Config) gredis.Adapter {\n\t\treturn New(config)\n\t})\n}\n\n// New creates and returns a redis adapter using go-redis.\nfunc New(config *gredis.Config) *Redis {\n\tfillWithDefaultConfiguration(config)\n\topts := &redis.UniversalOptions{\n\t\tAddrs:            gstr.SplitAndTrim(config.Address, \",\"),\n\t\tUsername:         config.User,\n\t\tPassword:         config.Pass,\n\t\tSentinelUsername: config.SentinelUser,\n\t\tSentinelPassword: config.SentinelPass,\n\t\tDB:               config.Db,\n\t\tMaxRetries:       defaultMaxRetries,\n\t\tPoolSize:         config.MaxActive,\n\t\tMinIdleConns:     config.MinIdle,\n\t\tMaxIdleConns:     config.MaxIdle,\n\t\tConnMaxLifetime:  config.MaxConnLifetime,\n\t\tConnMaxIdleTime:  config.IdleTimeout,\n\t\tPoolTimeout:      config.WaitTimeout,\n\t\tDialTimeout:      config.DialTimeout,\n\t\tReadTimeout:      config.ReadTimeout,\n\t\tWriteTimeout:     config.WriteTimeout,\n\t\tMasterName:       config.MasterName,\n\t\tTLSConfig:        config.TLSConfig,\n\t\tProtocol:         config.Protocol,\n\t}\n\n\tvar client redis.UniversalClient\n\tif opts.MasterName != \"\" {\n\t\tredisSentinel := opts.Failover()\n\t\tredisSentinel.ReplicaOnly = config.SlaveOnly\n\t\tclient = redis.NewFailoverClient(redisSentinel)\n\t} else if len(opts.Addrs) > 1 || config.Cluster {\n\t\tclient = redis.NewClusterClient(opts.Cluster())\n\t} else {\n\t\tclient = redis.NewClient(opts.Simple())\n\t}\n\n\tr := &Redis{\n\t\tclient: client,\n\t\tconfig: config,\n\t}\n\tr.AdapterOperation = r\n\treturn r\n}\n\nfunc fillWithDefaultConfiguration(config *gredis.Config) {\n\t// The MaxIdle is the most important attribute of the connection pool.\n\t// Only if this attribute is set, the created connections from client\n\t// can not exceed the limit of the server.\n\tif config.MaxIdle == 0 {\n\t\tconfig.MaxIdle = defaultPoolMaxIdle\n\t}\n\t// This value SHOULD NOT exceed the connection limit of redis server.\n\tif config.MaxActive == 0 {\n\t\tconfig.MaxActive = defaultPoolMaxActive\n\t}\n\tif config.IdleTimeout == 0 {\n\t\tconfig.IdleTimeout = defaultPoolIdleTimeout\n\t}\n\tif config.WaitTimeout == 0 {\n\t\tconfig.WaitTimeout = defaultPoolWaitTimeout\n\t}\n\tif config.MaxConnLifetime == 0 {\n\t\tconfig.MaxConnLifetime = defaultPoolMaxLifeTime\n\t}\n\tif config.WriteTimeout == 0 {\n\t\tconfig.WriteTimeout = -1\n\t}\n\tif config.ReadTimeout == 0 {\n\t\tconfig.ReadTimeout = -1\n\t}\n\tif config.TLSConfig == nil && config.TLS {\n\t\tconfig.TLSConfig = &tls.Config{\n\t\t\tInsecureSkipVerify: config.TLSSkipVerify,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_conn.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Conn manages the connection operations.\ntype Conn struct {\n\tps    *redis.PubSub\n\tredis *Redis\n}\n\n// traceItem holds the information for redis trace.\ntype traceItem struct {\n\terr       error\n\tcommand   string\n\targs      []any\n\tcostMilli int64\n}\n\nconst (\n\ttraceInstrumentName               = \"github.com/gogf/gf/v2/database/gredis\"\n\ttraceAttrRedisAddress             = \"redis.address\"\n\ttraceAttrRedisDb                  = \"redis.db\"\n\ttraceEventRedisExecution          = \"redis.execution\"\n\ttraceEventRedisExecutionCommand   = \"redis.execution.command\"\n\ttraceEventRedisExecutionCost      = \"redis.execution.cost\"\n\ttraceEventRedisExecutionArguments = \"redis.execution.arguments\"\n)\n\n// Do send a command to the server and returns the received reply.\n// It uses json.Marshal for struct/slice/map type values before committing them to redis.\nfunc (c *Conn) Do(ctx context.Context, command string, args ...any) (reply *gvar.Var, err error) {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\tfor k, v := range args {\n\t\tvar (\n\t\t\treflectInfo = gutil.OriginTypeAndKind(v)\n\t\t)\n\t\tswitch reflectInfo.OriginKind {\n\t\tcase\n\t\t\treflect.Struct,\n\t\t\treflect.Map,\n\t\t\treflect.Slice,\n\t\t\treflect.Array:\n\t\t\t// Ignore slice types of: []byte.\n\t\t\tif _, ok := v.([]byte); !ok {\n\t\t\t\tif args[k], err = gjson.Marshal(v); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Trace span start.\n\ttr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))\n\t_, span := tr.Start(ctx, \"Redis.\"+command, trace.WithSpanKind(trace.SpanKindClient))\n\tdefer span.End()\n\n\ttimestampMilli1 := gtime.TimestampMilli()\n\treply, err = c.doCommand(ctx, command, args...)\n\ttimestampMilli2 := gtime.TimestampMilli()\n\n\t// Trace span end.\n\tc.traceSpanEnd(ctx, span, &traceItem{\n\t\terr:       err,\n\t\tcommand:   command,\n\t\targs:      args,\n\t\tcostMilli: timestampMilli2 - timestampMilli1,\n\t})\n\treturn\n}\n\n// Do send a command to the server and returns the received reply.\n// It uses json.Marshal for struct/slice/map type values before committing them to redis.\nfunc (c *Conn) doCommand(ctx context.Context, command string, args ...any) (reply *gvar.Var, err error) {\n\targStrSlice := gconv.Strings(args)\n\tswitch gstr.ToLower(command) {\n\tcase `subscribe`:\n\t\tc.ps = c.redis.client.Subscribe(ctx, argStrSlice...)\n\n\tcase `psubscribe`:\n\t\tc.ps = c.redis.client.PSubscribe(ctx, argStrSlice...)\n\n\tcase `unsubscribe`:\n\t\tif c.ps != nil {\n\t\t\terr = c.ps.Unsubscribe(ctx, argStrSlice...)\n\t\t\tif err != nil {\n\t\t\t\terr = gerror.Wrapf(err, `Redis PubSub Unsubscribe failed with arguments \"%v\"`, argStrSlice)\n\t\t\t}\n\t\t}\n\n\tcase `punsubscribe`:\n\t\tif c.ps != nil {\n\t\t\terr = c.ps.PUnsubscribe(ctx, argStrSlice...)\n\t\t\tif err != nil {\n\t\t\t\terr = gerror.Wrapf(err, `Redis PubSub PUnsubscribe failed with arguments \"%v\"`, argStrSlice)\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\targuments := make([]any, len(args)+1)\n\t\tcopy(arguments, []any{command})\n\t\tcopy(arguments[1:], args)\n\t\treply, err = c.resultToVar(c.redis.client.Do(ctx, arguments...).Result())\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `Redis Client Do failed with arguments \"%v\"`, arguments)\n\t\t}\n\t}\n\treturn\n}\n\n// resultToVar converts redis operation result to gvar.Var.\nfunc (c *Conn) resultToVar(result any, err error) (*gvar.Var, error) {\n\tif err == redis.Nil {\n\t\terr = nil\n\t}\n\tif err == nil {\n\t\tswitch v := result.(type) {\n\t\tcase []byte:\n\t\t\treturn gvar.New(string(v)), err\n\n\t\tcase []any:\n\t\t\treturn gvar.New(gconv.Strings(v)), err\n\n\t\tcase *redis.Message:\n\t\t\tresult = &gredis.Message{\n\t\t\t\tChannel:      v.Channel,\n\t\t\t\tPattern:      v.Pattern,\n\t\t\t\tPayload:      v.Payload,\n\t\t\t\tPayloadSlice: v.PayloadSlice,\n\t\t\t}\n\n\t\tcase *redis.Subscription:\n\t\t\tresult = &gredis.Subscription{\n\t\t\t\tKind:    v.Kind,\n\t\t\t\tChannel: v.Channel,\n\t\t\t\tCount:   v.Count,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn gvar.New(result), err\n}\n\n// Receive receives a single reply as gvar.Var from the Redis server.\nfunc (c *Conn) Receive(ctx context.Context) (*gvar.Var, error) {\n\tif c.ps != nil {\n\t\tv, err := c.resultToVar(c.ps.Receive(ctx))\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `Redis PubSub Receive failed`)\n\t\t}\n\t\treturn v, err\n\t}\n\treturn nil, nil\n}\n\n// Close closes current PubSub or puts the connection back to connection pool.\nfunc (c *Conn) Close(ctx context.Context) (err error) {\n\tif c.ps != nil {\n\t\terr = c.ps.Close()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `Redis PubSub Close failed`)\n\t\t}\n\t}\n\treturn\n}\n\n// Subscribe subscribes the client to the specified channels.\n//\n// https://redis.io/commands/subscribe/\nfunc (c *Conn) Subscribe(ctx context.Context, channel string, channels ...string) ([]*gredis.Subscription, error) {\n\targs := append([]any{channel}, gconv.Interfaces(channels)...)\n\t_, err := c.Do(ctx, \"Subscribe\", args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsubs := make([]*gredis.Subscription, len(args))\n\tfor i := 0; i < len(subs); i++ {\n\t\tv, err := c.Receive(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubs[i] = v.Val().(*gredis.Subscription)\n\t}\n\treturn subs, err\n}\n\n// PSubscribe subscribes the client to the given patterns.\n//\n// Supported glob-style patterns:\n// - h?llo subscribes to hello, hallo and hxllo\n// - h*llo subscribes to hllo and heeeello\n// - h[ae]llo subscribes to hello and hallo, but not hillo\n//\n// Use \\ to escape special characters if you want to match them verbatim.\n//\n// https://redis.io/commands/psubscribe/\nfunc (c *Conn) PSubscribe(ctx context.Context, pattern string, patterns ...string) ([]*gredis.Subscription, error) {\n\targs := append([]any{pattern}, gconv.Interfaces(patterns)...)\n\t_, err := c.Do(ctx, \"PSubscribe\", args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsubs := make([]*gredis.Subscription, len(args))\n\tfor i := 0; i < len(subs); i++ {\n\t\tv, err := c.Receive(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubs[i] = v.Val().(*gredis.Subscription)\n\t}\n\treturn subs, err\n}\n\n// ReceiveMessage receives a single message of subscription from the Redis server.\nfunc (c *Conn) ReceiveMessage(ctx context.Context) (*gredis.Message, error) {\n\tv, err := c.Receive(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn v.Val().(*gredis.Message), nil\n}\n\n// traceSpanEnd checks and adds redis trace information to OpenTelemetry.\nfunc (c *Conn) traceSpanEnd(ctx context.Context, span trace.Span, item *traceItem) {\n\tif gtrace.IsUsingDefaultProvider() || !gtrace.IsTracingInternal() {\n\t\treturn\n\t}\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\tif item.err != nil {\n\t\tspan.SetStatus(codes.Error, fmt.Sprintf(`%+v`, item.err))\n\t}\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\tspan.SetAttributes(\n\t\tattribute.String(traceAttrRedisAddress, c.redis.config.Address),\n\t\tattribute.Int(traceAttrRedisDb, c.redis.config.Db),\n\t)\n\n\tjsonBytes, _ := gjson.Marshal(item.args)\n\tspan.AddEvent(traceEventRedisExecution, trace.WithAttributes(\n\t\tattribute.String(traceEventRedisExecutionCommand, item.command),\n\t\tattribute.String(traceEventRedisExecutionCost, fmt.Sprintf(`%d ms`, item.costMilli)),\n\t\tattribute.String(traceEventRedisExecutionArguments, string(jsonBytes)),\n\t))\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n)\n\nfunc mustMergeOptionToArgs(args []any, option any) []any {\n\tif option == nil {\n\t\treturn args\n\t}\n\tvar (\n\t\terr        error\n\t\toptionArgs []any\n\t)\n\toptionArgs, err = convertOptionToArgs(option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn append(args, optionArgs...)\n}\n\nfunc convertOptionToArgs(option any) ([]any, error) {\n\tif option == nil {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr       error\n\t\targs      = make([]any, 0)\n\t\tfields    []gstructs.Field\n\t\tsubFields []gstructs.Field\n\t)\n\tfields, err = gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         option,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, field := range fields {\n\t\tswitch field.OriginalKind() {\n\t\t// See SetOption\n\t\tcase reflect.Bool:\n\t\t\tif field.Value.Bool() {\n\t\t\t\targs = append(args, field.Name())\n\t\t\t}\n\n\t\t// See ZRangeOption\n\t\tcase reflect.Struct:\n\t\t\tif field.Value.IsNil() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !field.IsEmbedded() {\n\t\t\t\targs = append(args, field.Name())\n\t\t\t}\n\t\t\tsubFields, err = gstructs.Fields(gstructs.FieldsInput{\n\t\t\t\tPointer:         option,\n\t\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor _, subField := range subFields {\n\t\t\t\targs = append(args, subField.Value.Interface())\n\t\t\t}\n\n\t\t// See TTLOption\n\t\tdefault:\n\t\t\tfieldValue := field.Value.Interface()\n\t\t\tif field.Value.Kind() == reflect.Pointer {\n\t\t\t\tif field.Value.IsNil() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfieldValue = field.Value.Elem().Interface()\n\t\t\t}\n\t\t\targs = append(args, field.Name(), fieldValue)\n\t\t}\n\t}\n\treturn args, nil\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_generic.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupGeneric provides generic functions of redis.\ntype GroupGeneric struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupGeneric creates and returns GroupGeneric.\nfunc (r *Redis) GroupGeneric() gredis.IGroupGeneric {\n\treturn GroupGeneric{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// Copy copies the value stored at the source key to the destination key.\n//\n// By default, the destination key is created in the logical database used by the connection.\n// The DB option allows specifying an alternative logical database index for the destination key.\n//\n// The command returns an error when the destination key already exists.\n//\n// It returns:\n// - 1 if source was copied.\n// - 0 if source was not copied.\n//\n// https://redis.io/commands/copy/\nfunc (r GroupGeneric) Copy(ctx context.Context, source, destination string, option ...gredis.CopyOption) (int64, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"Copy\", mustMergeOptionToArgs(\n\t\t[]any{source, destination}, usedOption,\n\t)...)\n\treturn v.Int64(), err\n}\n\n// Exists returns if key exists.\n// The user should be aware that if the same existing key is mentioned in the arguments multiple times,\n// it will be counted multiple times.\n//\n// It returns the number of keys that exist from those specified as arguments.\n//\n// https://redis.io/commands/exists/\nfunc (r GroupGeneric) Exists(ctx context.Context, keys ...string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Exists\", gconv.Interfaces(keys)...)\n\treturn v.Int64(), err\n}\n\n// Type returns the string representation of the type of the value stored at key.\n// The different types that can be returned are: string, list, set, zset, hash and stream.\n//\n// It returns type of key, or none when key does not exist.\n//\n// https://redis.io/commands/type/\nfunc (r GroupGeneric) Type(ctx context.Context, key string) (string, error) {\n\tv, err := r.Operation.Do(ctx, \"Type\", key)\n\treturn v.String(), err\n}\n\n// Unlink is very similar to DEL: it removes the specified keys. Just like DEL a key is ignored if it does not exist.\n// However, the command performs the actual memory reclaiming in a different thread, so it is not blocking, while DEL is.\n// This is where the command name comes from: the command just unlinks the keys from the keyspace.\n// The actual removal will happen later asynchronously.\n//\n// It returns the number of keys that were unlinked.\n//\n// https://redis.io/commands/unlink/\nfunc (r GroupGeneric) Unlink(ctx context.Context, keys ...string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Unlink\", gconv.Interfaces(keys)...)\n\treturn v.Int64(), err\n}\n\n// Rename renames key to newKey. It returns an error when key does not exist.\n// If newKey already exists it is overwritten, when this happens RENAME executes an implicit DEL operation,\n// so if the deleted key contains a very big value it may cause high latency even if RENAME itself is usually a constant-time operation.\n//\n// In Cluster mode, both key and newKey must be in the same hash slot,\n// meaning that in practice only keys that have the same hashtag can be reliably renamed in cluster.\n//\n// https://redis.io/commands/rename/\nfunc (r GroupGeneric) Rename(ctx context.Context, key, newKey string) error {\n\t_, err := r.Operation.Do(ctx, \"Rename\", key, newKey)\n\treturn err\n}\n\n// RenameNX renames key to newKey if newKey does not yet exist.\n// It returns an error when key does not exist.\n// In Cluster mode, both key and newKey must be in the same hash slot,\n// meaning that in practice only keys that have the same hashtag can be reliably renamed in cluster.\n//\n// It returns:\n// - 1 if key was renamed to newKey.\n// - 0 if newKey already exists.\n//\n// https://redis.io/commands/renamenx/\nfunc (r GroupGeneric) RenameNX(ctx context.Context, key, newKey string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"RenameNX\", key, newKey)\n\treturn v.Int64(), err\n}\n\n// Move moves key from the currently selected database (see SELECT) to the specified destination database.\n// When key already exists in the destination database, or it does not exist in the source database,\n// it does nothing.\n// It is possible to use MOVE as a locking primitive because of this.\n//\n// It returns:\n// - 1 if key was moved.\n// - 0 if key was not moved.\n//\n// https://redis.io/commands/move/\nfunc (r GroupGeneric) Move(ctx context.Context, key string, db int) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Move\", key, db)\n\treturn v.Int64(), err\n}\n\n// Del removes the specified keys.\n// a key is ignored if it does not exist.\n//\n// It returns the number of keys that were removed.\n//\n// https://redis.io/commands/del/\nfunc (r GroupGeneric) Del(ctx context.Context, keys ...string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Del\", gconv.Interfaces(keys)...)\n\treturn v.Int64(), err\n}\n\n// RandomKey return a random key from the currently selected database.\n//\n// It returns the random key, or nil when the database is empty.\n//\n// https://redis.io/commands/randomkey/\nfunc (r GroupGeneric) RandomKey(ctx context.Context) (string, error) {\n\tv, err := r.Operation.Do(ctx, \"RandomKey\")\n\treturn v.String(), err\n}\n\n// DBSize return the number of keys in the currently-selected database.\n//\n// https://redis.io/commands/dbsize/\nfunc (r GroupGeneric) DBSize(ctx context.Context) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"DBSize\")\n\treturn v.Int64(), err\n}\n\n// Keys return all keys matching pattern.\n//\n// While the time complexity for this operation is O(N), the constant times are fairly low.\n// For example, Redis running on an entry level laptop can scan a 1 million key database in 40 milliseconds.\n//\n// https://redis.io/commands/keys/\nfunc (r GroupGeneric) Keys(ctx context.Context, pattern string) ([]string, error) {\n\tv, err := r.Operation.Do(ctx, \"Keys\", pattern)\n\treturn v.Strings(), err\n}\n\n// Scan executes a single iteration of the SCAN command, returning a subset of keys matching the pattern along with the next cursor position.\n// This method provides more efficient and safer way to iterate over large datasets compared to KEYS command.\n//\n// Users are responsible for controlling the iteration by managing the cursor.\n//\n// The `count` optional parameter advises Redis on the number of keys to return. While it's not a strict limit, it guides the operation's granularity.\n//\n// https://redis.io/commands/scan/\nfunc (r GroupGeneric) Scan(ctx context.Context, cursor uint64, option ...gredis.ScanOption) (uint64, []string, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0].ToUsedOption()\n\t}\n\n\tv, err := r.Operation.Do(ctx, \"Scan\", mustMergeOptionToArgs(\n\t\t[]any{cursor}, usedOption,\n\t)...)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\tnextCursor := gconv.Uint64(v.Slice()[0])\n\tkeys := gconv.SliceStr(v.Slice()[1])\n\n\treturn nextCursor, keys, nil\n}\n\n// FlushDB delete all the keys of the currently selected DB. This command never fails.\n//\n// https://redis.io/commands/flushdb/\nfunc (r GroupGeneric) FlushDB(ctx context.Context, option ...gredis.FlushOp) error {\n\t_, err := r.Operation.Do(ctx, \"FlushDB\", gconv.Interfaces(option)...)\n\treturn err\n}\n\n// FlushAll delete all the keys of all the existing databases, not just the currently selected one.\n// This command never fails.\n// By default, FlushAll will synchronously flush all the databases.\n//\n// It is possible to use one of the following modifiers to dictate the flushing mode explicitly:\n// ASYNC: flushes the databases asynchronously\n// SYNC: flushes the databases synchronously\n//\n// Note: an asynchronous FlushAll command only deletes keys that were present at the time the command was invoked.\n// Keys created during an asynchronous flush will be unaffected.\n//\n// https://redis.io/commands/flushall/\nfunc (r GroupGeneric) FlushAll(ctx context.Context, option ...gredis.FlushOp) error {\n\t_, err := r.Operation.Do(ctx, \"FlushAll\", gconv.Interfaces(option)...)\n\treturn err\n}\n\n// Expire sets a timeout on key.\n// After the timeout has expired, the key will automatically be deleted.\n//\n// It returns:\n// - 1 if the timeout was set.\n// - 0 if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.\n//\n// https://redis.io/commands/expire/\nfunc (r GroupGeneric) Expire(ctx context.Context, key string, seconds int64, option ...gredis.ExpireOption) (int64, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"Expire\", mustMergeOptionToArgs(\n\t\t[]any{key, seconds}, usedOption,\n\t)...)\n\treturn v.Int64(), err\n}\n\n// ExpireAt has the same effect and semantic as EXPIRE, but instead of specifying the number of\n// seconds representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since\n// January 1, 1970).\n// A timestamp in the past will delete the key immediately.\n//\n// It returns:\n// - 1 if the timeout was set.\n// - 0 if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.\n//\n// https://redis.io/commands/expireat/\nfunc (r GroupGeneric) ExpireAt(ctx context.Context, key string, time time.Time, option ...gredis.ExpireOption) (int64, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"ExpireAt\", mustMergeOptionToArgs(\n\t\t[]any{key, gtime.New(time).Timestamp()}, usedOption,\n\t)...)\n\treturn v.Int64(), err\n}\n\n// ExpireTime returns the absolute time at which the given key will expire.\n//\n// It returns:\n// - -1 if the key exists but has no associated expiration time.\n// - -2 if the key does not exist.\n//\n// https://redis.io/commands/expiretime/\nfunc (r GroupGeneric) ExpireTime(ctx context.Context, key string) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"ExpireTime\", key)\n}\n\n// TTL returns the remaining time to live of a key that has a timeout.\n// This introspection capability allows a Redis client to check how many seconds a given key\n// will continue to be part of the dataset.\n// In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has\n// no associated expire.\n//\n// Starting with Redis 2.8 the return value in case of error changed:\n//\n// The command returns -2 if the key does not exist.\n// The command returns -1 if the key exists but has no associated expire.\n// See also the PTTL command that returns the same information with milliseconds resolution\n// (Only available in Redis 2.6 or greater).\n//\n// It returns TTL in seconds, or a negative value in order to signal an error (see the description above).\n//\n// https://redis.io/commands/ttl/\nfunc (r GroupGeneric) TTL(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"TTL\", key)\n\treturn v.Int64(), err\n}\n\n// Persist removes the existing timeout on key, turning the key from volatile (a key with an expire set)\n// to persistent (a key that will never expire as no timeout is associated).\n//\n// It returns:\n// - 1 if the timeout was removed.\n// - 0 if key does not exist or does not have an associated timeout.\n//\n// https://redis.io/commands/persist/\nfunc (r GroupGeneric) Persist(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Persist\", key)\n\treturn v.Int64(), err\n}\n\n// PExpire works exactly like EXPIRE but the time to live of the key is specified in milliseconds\n// instead of seconds.\n//\n// It returns:\n// - 1 if the timeout was set.\n// - 0 if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.\n//\n// https://redis.io/commands/pexpire/\nfunc (r GroupGeneric) PExpire(ctx context.Context, key string, milliseconds int64, option ...gredis.ExpireOption) (int64, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"PExpire\", mustMergeOptionToArgs(\n\t\t[]any{key, milliseconds}, usedOption,\n\t)...)\n\treturn v.Int64(), err\n}\n\n// PExpireAt has the same effect and semantic as ExpireAt, but the Unix time at which the key will\n// expire is specified in milliseconds instead of seconds.\n//\n// https://redis.io/commands/pexpireat/\nfunc (r GroupGeneric) PExpireAt(ctx context.Context, key string, time time.Time, option ...gredis.ExpireOption) (int64, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"PExpireAt\", mustMergeOptionToArgs(\n\t\t[]any{key, gtime.New(time).TimestampMilli()}, usedOption,\n\t)...)\n\treturn v.Int64(), err\n}\n\n// PExpireTime returns the expiration time of given `key`.\n//\n// It returns:\n// - -1 if the key exists but has no associated expiration time.\n// - -2 if the key does not exist.\n//\n// https://redis.io/commands/pexpiretime/\nfunc (r GroupGeneric) PExpireTime(ctx context.Context, key string) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"PExpireTime\", key)\n}\n\n// PTTL like TTL this command returns the remaining time to live of a key that has an expired set,\n// with the sole difference that TTL returns the amount of remaining time in seconds while PTTL\n// returns it in milliseconds.\n//\n// In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has\n// no associated expire.\n//\n// It returns TTL in milliseconds, or a negative value in order to signal an error (see the description above).\n//\n//\thttps://redis.io/commands/pttl/\nfunc (r GroupGeneric) PTTL(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"PTTL\", key)\n\treturn v.Int64(), err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_hash.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupHash is the redis group object for hash operations.\ntype GroupHash struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupHash creates and returns a redis group object for hash operations.\nfunc (r *Redis) GroupHash() gredis.IGroupHash {\n\treturn GroupHash{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// HSet sets field in the hash stored at key to value.\n// If key does not exist, a new key holding a hash is created.\n// If field already exists in the hash, it is overwritten.\n//\n// It returns the number of fields that were added.\n//\n// https://redis.io/commands/hset/\nfunc (r GroupHash) HSet(ctx context.Context, key string, fields map[string]any) (int64, error) {\n\tvar s = []any{key}\n\tfor k, v := range fields {\n\t\ts = append(s, k, v)\n\t}\n\tv, err := r.Operation.Do(ctx, \"HSet\", s...)\n\treturn v.Int64(), err\n}\n\n// HSetNX sets field in the hash stored at key to value, only if field does not yet exist.\n// If key does not exist, a new key holding a hash is created.\n// If field already exists, this operation has no effect.\n//\n// It returns:\n// - 1 if field is a new field in the hash and value was set.\n// - 0 if field already exists in the hash and no operation was performed.\n//\n// https://redis.io/commands/hsetnx/\nfunc (r GroupHash) HSetNX(ctx context.Context, key, field string, value any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HSetNX\", key, field, value)\n\treturn v.Int64(), err\n}\n\n// HGet returns the value associated with field in the hash stored at key.\n//\n// It returns the value associated with field, or nil when field is not present in the hash or key does not exist.\n//\n// https://redis.io/commands/hget/\nfunc (r GroupHash) HGet(ctx context.Context, key, field string) (*gvar.Var, error) {\n\tv, err := r.Operation.Do(ctx, \"HGet\", key, field)\n\treturn v, err\n}\n\n// HStrLen Returns the string length of the value associated with field in the hash stored at key.\n// If the key or the field do not exist, 0 is returned.\n//\n// It returns the string length of the value associated with field,\n// or zero when field is not present in the hash or key does not exist at all.\n//\n// https://redis.io/commands/hstrlen/\nfunc (r GroupHash) HStrLen(ctx context.Context, key, field string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HSTRLEN\", key, field)\n\treturn v.Int64(), err\n}\n\n// HExists returns if field is an existing field in the hash stored at key.\n//\n// It returns:\n// - 1 if the hash contains field.\n// - 0 if the hash does not contain field, or key does not exist.\n//\n// https://redis.io/commands/hexists/\nfunc (r GroupHash) HExists(ctx context.Context, key, field string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HExists\", key, field)\n\treturn v.Int64(), err\n}\n\n// HDel removes the specified fields from the hash stored at key.\n// Specified fields that do not exist within this hash are ignored.\n// If key does not exist, it is treated as an empty hash and this command returns 0.\n//\n// It returns the number of fields that were removed from the hash, not including specified but non-existing fields.\n//\n// https://redis.io/commands/hdel/\nfunc (r GroupHash) HDel(ctx context.Context, key string, fields ...string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HDel\", append([]any{key}, gconv.Interfaces(fields)...)...)\n\treturn v.Int64(), err\n}\n\n// HLen returns the number of fields contained in the hash stored at key.\n//\n// https://redis.io/commands/hlen/\nfunc (r GroupHash) HLen(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HLen\", key)\n\treturn v.Int64(), err\n}\n\n// HIncrBy increments the number stored at field in the hash stored at key by increment.\n// If key does not exist, a new key holding a hash is created.\n// If field does not exist the value is set to 0 before the operation is performed.\n//\n// The range of values supported by HIncrBy is limited to 64-bit signed integers.\n//\n// https://redis.io/commands/hincrby/\nfunc (r GroupHash) HIncrBy(ctx context.Context, key, field string, increment int64) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"HIncrBy\", key, field, increment)\n\treturn v.Int64(), err\n}\n\n// HIncrByFloat increments the specified field of a hash stored at key, and representing a floating\n// point number, by the specified increment. If the increment value is negative, the result is to\n// have the hash field value decremented instead of incremented. If the field does not exist, it is\n// set to 0 before performing the operation.\n// An error is returned if one of the following conditions occur:\n//\n// The field contains a value of the wrong type (not a string).\n// The current field content or the specified increment are not parsable as a double precision\n// floating point number.\n// The exact behavior of this command is identical to the one of the HIncrByFloat command,\n// please refer to the documentation of HIncrByFloat for further information.\n//\n// It returns the value of field after the increment.\n//\n// https://redis.io/commands/hincrbyfloat/\nfunc (r GroupHash) HIncrByFloat(ctx context.Context, key, field string, increment float64) (float64, error) {\n\tv, err := r.Operation.Do(ctx, \"HIncrByFloat\", key, field, increment)\n\treturn v.Float64(), err\n}\n\n// HMSet sets the specified fields to their respective values in the hash stored at key.\n// This command overwrites any specified fields already existing in the hash.\n// If key does not exist, a new key holding a hash is created.\n//\n// https://redis.io/commands/hmset/\nfunc (r GroupHash) HMSet(ctx context.Context, key string, fields map[string]any) error {\n\tvar s = []any{key}\n\tfor k, v := range fields {\n\t\ts = append(s, k, v)\n\t}\n\t_, err := r.Operation.Do(ctx, \"HMSet\", s...)\n\treturn err\n}\n\n// HMGet return  the values associated with the specified fields in the hash stored at key.\n// For every field that does not exist in the hash, a nil value is returned.\n// Because non-existing keys are treated as empty hashes, running HMGet against a non-existing key\n// will return a list of nil values.\n//\n// https://redis.io/commands/hmget/\nfunc (r GroupHash) HMGet(ctx context.Context, key string, fields ...string) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"HMGet\", append([]any{key}, gconv.Interfaces(fields)...)...)\n\treturn v.Vars(), err\n}\n\n// HKeys returns all field names in the hash stored at key.\n//\n// https://redis.io/commands/hkeys/\nfunc (r GroupHash) HKeys(ctx context.Context, key string) ([]string, error) {\n\tv, err := r.Operation.Do(ctx, \"HKeys\", key)\n\treturn v.Strings(), err\n}\n\n// HVals return all values in the hash stored at key.\n//\n// https://redis.io/commands/hvals/\nfunc (r GroupHash) HVals(ctx context.Context, key string) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"HVals\", key)\n\treturn v.Vars(), err\n}\n\n// HGetAll returns all fields and values of the hash stored at key.\n// In the returned value, every field name is followed by its value,\n// so the length of the reply is twice the size of the hash.\n//\n// https://redis.io/commands/hgetall/\nfunc (r GroupHash) HGetAll(ctx context.Context, key string) (*gvar.Var, error) {\n\tv, err := r.Operation.Do(ctx, \"HGetAll\", key)\n\treturn v, err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupList is the redis group list object.\ntype GroupList struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupList creates and returns a redis group object for list operations.\nfunc (r *Redis) GroupList() gredis.IGroupList {\n\treturn GroupList{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// LPush inserts all the specified values at the head of the list stored at key\n// Insert all the specified values at the head of the list stored at key.\n// If key does not exist, it is created as empty list before performing the push operations.\n// When key holds a value that is not a list, an error is returned.\n//\n// It returns the length of the list after the push operations.\n//\n// https://redis.io/commands/lpush/\nfunc (r GroupList) LPush(ctx context.Context, key string, values ...any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"LPush\", append([]any{key}, values...)...)\n\treturn v.Int64(), err\n}\n\n// LPushX insert value at the head of the list stored at key, only if key exists and holds a list.\n// Inserts specified values at the head of the list stored at key, only if key already exists and holds a list.\n// In contrary to LPush, no operation will be performed when key does not yet exist.\n// Return Integer reply: the length of the list after the push operation.\n//\n// It returns the length of the list after the push operations.\n//\n// https://redis.io/commands/lpushx\nfunc (r GroupList) LPushX(ctx context.Context, key string, element any, elements ...any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"LPushX\", append([]any{key, element}, elements...)...)\n\treturn v.Int64(), err\n}\n\n// RPush inserts all the specified values at the tail of the list stored at key.\n// Insert all the specified values at the tail of the list stored at key.\n// If key does not exist, it is created as empty list before performing the push operation.\n//\n// When key holds a value that is not a list, an error is returned.\n// It is possible to push multiple elements using a single command call just specifying multiple\n// arguments at  the end of the command. Elements are inserted one after the other to the tail of the\n// list, from the leftmost element to the rightmost element.\n// So for instance the command RPush mylist a b c will result into a list containing a as first element,\n// b as second element and c as third element.\n//\n// It returns the length of the list after the push operation.\n//\n// https://redis.io/commands/rpush\nfunc (r GroupList) RPush(ctx context.Context, key string, values ...any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"RPush\", append([]any{key}, values...)...)\n\treturn v.Int64(), err\n}\n\n// RPushX inserts value at the tail of the list stored at key, only if key exists and holds a list.\n// Inserts specified values at the tail of the list stored at key, only if key already exists and\n// holds a list.\n//\n// In contrary to RPush, no operation will be performed when key does not yet exist.\n//\n// It returns the length of the list after the push operation.\n//\n// https://redis.io/commands/rpushx\nfunc (r GroupList) RPushX(ctx context.Context, key string, value any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"RPushX\", key, value)\n\treturn v.Int64(), err\n}\n\n// LPop remove and returns the first element of the list stored at key.\n// Removes and returns the first elements of the list stored at key.\n//\n// Starting with Redis version 6.2.0: Added the count argument.\n//\n// By default, the command pops a single element from the beginning of the list.\n// When provided with the optional count argument, the reply will consist of up to count elements,\n// depending on the list's length.\n//\n// Return When called without the count argument:\n// Bulk string reply: the value of the first element, or nil when key does not exist.\n//\n// When called with the count argument:\n// Array reply: list of popped elements, or nil when key does not exist.\n//\n// https://redis.io/commands/lpop\nfunc (r GroupList) LPop(ctx context.Context, key string, count ...int) (*gvar.Var, error) {\n\tif len(count) > 0 {\n\t\treturn r.Operation.Do(ctx, \"LPop\", key, count[0])\n\t}\n\treturn r.Operation.Do(ctx, \"LPop\", key)\n}\n\n// RPop remove and returns the last element of the list stored at key.\n// Removes and returns the last elements of the list stored at key.\n//\n// Starting with Redis version 6.2.0: Added the count argument.\n//\n// By default, the command pops a single element from the end of the list.\n// When provided with the optional count argument, the reply will consist of up to count elements,\n// depending on the list's length.\n//\n// It returns:\n//   - When called without the count argument:\n//     the value of the last element, or nil when key does not exist.\n//   - When called with the count argument:\n//     list of popped elements, or nil when key does not exist.\n//\n// https://redis.io/commands/rpop\nfunc (r GroupList) RPop(ctx context.Context, key string, count ...int) (*gvar.Var, error) {\n\tif len(count) > 0 {\n\t\treturn r.Operation.Do(ctx, \"RPop\", key, count[0])\n\t}\n\treturn r.Operation.Do(ctx, \"RPop\", key)\n}\n\n// LRem removes the first count occurrences of elements equal to value from the list stored at key.\n//\n// It returns the number of removed elements.\n//\n// https://redis.io/commands/lrem/\nfunc (r GroupList) LRem(ctx context.Context, key string, count int64, value any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"LRem\", key, count, value)\n\treturn v.Int64(), err\n}\n\n// LLen returns the length of the list stored at key.\n// Returns the length of the list stored at key.\n// If key does not exist, it is interpreted as an empty list and 0 is returned.\n// An error is returned when the value stored at key is not a list.\n//\n// https://redis.io/commands/llen\nfunc (r GroupList) LLen(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"LLen\", key)\n\treturn v.Int64(), err\n}\n\n// LIndex return the element at index in the list stored at key.\n// Returns the element at index in the list stored at key.\n// The index is zero-based, so 0 means the first element, 1 the second element and so on.\n// Negative indices can be used to designate elements starting at the tail of the list.\n// Here, -1 means the last element, -2 means the penultimate and so forth.\n// When the value at key is not a list, an error is returned.\n//\n// It returns the requested element, or nil when index is out of range.\n//\n// https://redis.io/commands/lindex\nfunc (r GroupList) LIndex(ctx context.Context, key string, index int64) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"LIndex\", key, index)\n}\n\n// LInsert inserts element in the list stored at key either before or after the reference value pivot.\n// When key does not exist, it is considered an empty list and no operation is performed.\n// An error is returned when key exists but does not hold a list value.\n//\n// It returns the length of the list after the insert operation, or -1 when the value pivot was not found.\n//\n// https://redis.io/commands/linsert/\nfunc (r GroupList) LInsert(ctx context.Context, key string, op gredis.LInsertOp, pivot, value any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"LInsert\", key, string(op), pivot, value)\n\treturn v.Int64(), err\n}\n\n// LSet sets the list element at index to element.\n// For more information on the index argument, see LIndex.\n// An error is returned for out of range indexes.\n//\n// https://redis.io/commands/lset/\nfunc (r GroupList) LSet(ctx context.Context, key string, index int64, value any) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"LSet\", key, index, value)\n}\n\n// LRange returns the specified elements of the list stored at key.\n// The offsets start and stop are zero-based indexes, with 0 being the first element of the list (the\n// head of the list), 1 being the next element and so on.\n//\n// These offsets can also be negative numbers indicating offsets starting at the end of the list.\n// For example, -1 is the last element of the list, -2 the penultimate, and so on.\n//\n// https://redis.io/commands/lrange/\nfunc (r GroupList) LRange(ctx context.Context, key string, start, stop int64) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"LRange\", key, start, stop)\n\treturn v.Vars(), err\n}\n\n// LTrim trims an existing list so that it will contain only the specified range of elements\n// specified. Both start and stop are zero-based indexes, where 0 is the first element of the list\n// (the head), 1 the next element and so on.\n//\n// https://redis.io/commands/ltrim/\nfunc (r GroupList) LTrim(ctx context.Context, key string, start, stop int64) error {\n\t_, err := r.Operation.Do(ctx, \"LTrim\", key, start, stop)\n\treturn err\n}\n\n// BLPop is a blocking list pop primitive.\n// It is the blocking version of LPop because it blocks the connection when there are no elements to\n// pop from any of the given lists.\n// An element is popped from the head of the first list that is non-empty, with the given keys being\n// checked in the order that they are given.\n//\n// The timeout argument is interpreted as a double value specifying the maximum number of seconds to\n// block. A timeout of zero can be used to block indefinitely.\n//\n// https://redis.io/commands/blpop/\nfunc (r GroupList) BLPop(ctx context.Context, timeout int64, keys ...string) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"BLPop\", append(gconv.Interfaces(keys), timeout)...)\n\treturn v.Vars(), err\n}\n\n// BRPop is a blocking list pop primitive.\n// It is the blocking version of RPop because it blocks the connection when there are no elements to\n// pop from any of the given lists. An element is popped from the tail of the first list that is\n// non-empty, with the given keys being checked in the order that they are given.\n//\n// The timeout argument is interpreted as a double value specifying the maximum number of seconds to\n// block. A timeout of zero can be used to block indefinitely.\n//\n// https://redis.io/commands/brpop/\nfunc (r GroupList) BRPop(ctx context.Context, timeout int64, keys ...string) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"BRPop\", append(gconv.Interfaces(keys), timeout)...)\n\treturn v.Vars(), err\n}\n\n// RPopLPush remove the last element in list source, appends it to the front of list destination and\n// returns it.\n//\n// https://redis.io/commands/rpoplpush/\nfunc (r GroupList) RPopLPush(ctx context.Context, source, destination string) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"RPopLPush\", source, destination)\n}\n\n// BRPopLPush is the blocking variant of RPopLPush.\n// When source contains elements, this command behaves exactly like RPopLPush. When used inside a\n// MULTI/EXEC block,\n// this command behaves exactly like RPopLPush. When source is empty, Redis will block the connection\n// until another // client pushes to it or until timeout is reached.\n// A timeout of zero can be used to block indefinitely.\n//\n// It returns the element being popped from source and pushed to destination.\n// If timeout is reached, a Null reply is returned.\n//\n// https://redis.io/commands/brpoplpush/\nfunc (r GroupList) BRPopLPush(ctx context.Context, source, destination string, timeout int64) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"BRPopLPush\", source, destination, timeout)\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_pubsub.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n)\n\n// GroupPubSub provides pub/sub functions for redis.\ntype GroupPubSub struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupPubSub creates and returns GroupPubSub.\nfunc (r *Redis) GroupPubSub() gredis.IGroupPubSub {\n\treturn GroupPubSub{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// Publish posts a message to the given channel.\n//\n// In a Redis Cluster clients can publish to every node. The cluster makes sure that published\n// messages are forwarded as needed, so clients can subscribe to any channel by connecting to any one\n// of the nodes.\n//\n// It returns the number of clients that received the message.\n// Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client\n// are included in the count.\n//\n// https://redis.io/commands/publish/\nfunc (r GroupPubSub) Publish(ctx context.Context, channel string, message any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Publish\", channel, message)\n\treturn v.Int64(), err\n}\n\n// Subscribe subscribes the client to the specified channels.\n//\n// https://redis.io/commands/subscribe/\nfunc (r GroupPubSub) Subscribe(\n\tctx context.Context, channel string, channels ...string,\n) (gredis.Conn, []*gredis.Subscription, error) {\n\tconn, err := r.Operation.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tsubs, err := conn.Subscribe(ctx, channel, channels...)\n\tif err != nil {\n\t\treturn conn, nil, err\n\t}\n\treturn conn, subs, nil\n}\n\n// PSubscribe subscribes the client to the given patterns.\n//\n// Supported glob-style patterns:\n// - h?llo subscribes to hello, hallo and hxllo\n// - h*llo subscribes to hllo and heeeello\n// - h[ae]llo subscribes to hello and hallo, but not hillo\n//\n// Use \\ to escape special characters if you want to match them verbatim.\n//\n// https://redis.io/commands/psubscribe/\nfunc (r GroupPubSub) PSubscribe(\n\tctx context.Context, pattern string, patterns ...string,\n) (gredis.Conn, []*gredis.Subscription, error) {\n\tconn, err := r.Operation.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tsubs, err := conn.PSubscribe(ctx, pattern, patterns...)\n\tif err != nil {\n\t\treturn conn, nil, err\n\t}\n\treturn conn, subs, nil\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_script.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupScript provides script functions for redis.\ntype GroupScript struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupScript creates and returns GroupScript.\nfunc (r *Redis) GroupScript() gredis.IGroupScript {\n\treturn GroupScript{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// Eval invokes the execution of a server-side Lua script.\n//\n// https://redis.io/commands/eval/\nfunc (r GroupScript) Eval(ctx context.Context, script string, numKeys int64, keys []string, args []any) (*gvar.Var, error) {\n\tvar s = []any{script, numKeys}\n\ts = append(s, gconv.Interfaces(keys)...)\n\ts = append(s, args...)\n\tv, err := r.Operation.Do(ctx, \"Eval\", s...)\n\treturn v, err\n}\n\n// EvalSha evaluates a script from the server's cache by its SHA1 digest.\n//\n// The server caches scripts by using the SCRIPT LOAD command.\n// The command is otherwise identical to EVAL.\n//\n// https://redis.io/commands/evalsha/\nfunc (r GroupScript) EvalSha(ctx context.Context, sha1 string, numKeys int64, keys []string, args []any) (*gvar.Var, error) {\n\tvar s = []any{sha1, numKeys}\n\ts = append(s, gconv.Interfaces(keys)...)\n\ts = append(s, args...)\n\tv, err := r.Operation.Do(ctx, \"EvalSha\", s...)\n\treturn v, err\n}\n\n// ScriptLoad loads a script into the scripts cache, without executing it.\n//\n// It returns the SHA1 digest of the script added into the script cache.\n//\n// https://redis.io/commands/script-load/\nfunc (r GroupScript) ScriptLoad(ctx context.Context, script string) (string, error) {\n\tv, err := r.Operation.Do(ctx, \"Script\", \"Load\", script)\n\treturn v.String(), err\n}\n\n// ScriptExists returns information about the existence of the scripts in the script cache.\n//\n// It returns an array of integers that correspond to the specified SHA1 digest arguments.\n// For every corresponding SHA1 digest of a script that actually exists in the script cache,\n// a 1 is returned, otherwise 0 is returned.\n//\n// https://redis.io/commands/script-exists/\nfunc (r GroupScript) ScriptExists(ctx context.Context, sha1 string, sha1s ...string) (map[string]bool, error) {\n\tvar (\n\t\ts         []any\n\t\tsha1Array = append([]any{sha1}, gconv.Interfaces(sha1s)...)\n\t)\n\ts = append(s, \"Exists\")\n\ts = append(s, sha1Array...)\n\tresult, err := r.Operation.Do(ctx, \"Script\", s...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tm           = make(map[string]bool)\n\t\tresultArray = result.Vars()\n\t)\n\tfor i := 0; i < len(sha1Array); i++ {\n\t\tm[gconv.String(sha1Array[i])] = resultArray[i].Bool()\n\t}\n\treturn m, err\n}\n\n// ScriptFlush flush the Lua scripts cache.\n//\n// https://redis.io/commands/script-flush/\nfunc (r GroupScript) ScriptFlush(ctx context.Context, option ...gredis.ScriptFlushOption) error {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tvar s []any\n\ts = append(s, \"Flush\")\n\ts = append(s, mustMergeOptionToArgs(\n\t\t[]any{}, usedOption,\n\t)...)\n\t_, err := r.Operation.Do(ctx, \"Script\", s...)\n\treturn err\n}\n\n// ScriptKill kills the currently executing EVAL script, assuming no write operation was yet performed\n// by the script.\n//\n// https://redis.io/commands/script-kill/\nfunc (r GroupScript) ScriptKill(ctx context.Context) error {\n\t_, err := r.Operation.Do(ctx, \"Script\", \"Kill\")\n\treturn err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupSet provides set functions for redis.\ntype GroupSet struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupSet creates and returns GroupSet.\nfunc (r *Redis) GroupSet() gredis.IGroupSet {\n\treturn GroupSet{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// SAdd adds the specified members to the set stored at key.\n// Specified members that are already a member of this set are ignored.\n// If key does not exist, a new set is created before adding the specified members.\n//\n// An error is returned when the value stored at key is not a set.\n//\n// It returns the number of elements that were added to the set,\n// not including all the elements already present in the set.\n//\n// https://redis.io/commands/sadd/\nfunc (r GroupSet) SAdd(ctx context.Context, key string, member any, members ...any) (int64, error) {\n\tvar s = []any{key}\n\ts = append(s, member)\n\ts = append(s, members...)\n\tv, err := r.Operation.Do(ctx, \"SAdd\", s...)\n\treturn v.Int64(), err\n}\n\n// SIsMember returns if member is a member of the set stored at key.\n//\n// It returns:\n// - 1 if the element is a member of the set.\n// - 0 if the element is not a member of the set, or if key does not exist.\n//\n// https://redis.io/commands/sismember/\nfunc (r GroupSet) SIsMember(ctx context.Context, key string, member any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"SIsMember\", key, member)\n\treturn v.Int64(), err\n}\n\n// SPop removes and returns one or more random members from the set value store at key.\n//\n// This operation is similar to SRandMember, that returns one or more random elements from a set but\n// does not remove it.\n// By default, the command pops a single member from the set. When provided with the optional count\n// argument, the reply will consist of up to count members, depending on the set's cardinality.\n//\n// It returns:\n//   - When called without the count argument:\n//     Bulk string reply: the removed member, or nil when key does not exist.\n//   - When called with the count argument:\n//     Array reply: the removed members, or an empty array when key does not exist.\n//\n// https://redis.io/commands/spop/\nfunc (r GroupSet) SPop(ctx context.Context, key string, count ...int) (*gvar.Var, error) {\n\tvar s = []any{key}\n\ts = append(s, gconv.Interfaces(count)...)\n\tv, err := r.Operation.Do(ctx, \"SPop\", s...)\n\treturn v, err\n}\n\n// SRandMember called with just the key argument, return a random element from the set value stored\n// at key.\n// If the provided count argument is positive, return an array of distinct elements.\n// The array's length is either count or the set's cardinality (SCard), whichever is lower.\n// If called with a negative count, the behavior changes and the command is allowed to return the\n// same element multiple times. In this case, the number of returned elements is the absolute value\n// of the specified count.\n//\n// It returns:\n//   - Bulk string reply: without the additional count argument, the command returns a Bulk Reply with the\n//     randomly selected element, or nil when key does not exist.\n//   - Array reply: when the additional count argument is passed, the command returns an array of elements,\n//     or an empty array when key does not exist.\n//\n// https://redis.io/commands/srandmember/\nfunc (r GroupSet) SRandMember(ctx context.Context, key string, count ...int) (*gvar.Var, error) {\n\tvar s = []any{key}\n\ts = append(s, gconv.Interfaces(count)...)\n\tv, err := r.Operation.Do(ctx, \"SRandMember\", s...)\n\treturn v, err\n}\n\n// SRem removes the specified members from the set stored at key.\n// Specified members that are not a member of this set are ignored.\n// If key does not exist, it is treated as an empty set and this command returns 0.\n//\n// An error is returned when the value stored at key is not a set.\n//\n// It returns the number of members that were removed from the set, not including non existing members.\n//\n// https://redis.io/commands/srem/\nfunc (r GroupSet) SRem(ctx context.Context, key string, member any, members ...any) (int64, error) {\n\tvar s = []any{key}\n\ts = append(s, member)\n\ts = append(s, members...)\n\tv, err := r.Operation.Do(ctx, \"SRem\", s...)\n\treturn v.Int64(), err\n}\n\n// SMove moves member from the set at source to the set at destination.\n// This operation is atomic. In every given moment the element will appear to be a member of source or\n// destination for other clients.\n// If the source set does not exist or does not contain the specified element, no operation is performed and 0\n// is returned. Otherwise, the element is removed from the source set and added to the destination set.\n// When the specified element already exists in the destination set, it is only removed from the source set.\n//\n// An error is returned if source or destination does not hold a set value.\n//\n// It returns:\n// - 1 if the element is moved.\n// - 0 if the element is not a member of source and no operation was performed.\n//\n// https://redis.io/commands/smove/\nfunc (r GroupSet) SMove(ctx context.Context, source, destination string, member any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"SMove\", source, destination, member)\n\treturn v.Int64(), err\n}\n\n// SCard returns the set cardinality (number of elements) of the set stored at key.\n//\n// It returns the cardinality (number of elements) of the set, or 0 if key does not exist.\n//\n// https://redis.io/commands/scard/\nfunc (r GroupSet) SCard(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"SCard\", key)\n\treturn v.Int64(), err\n}\n\n// SMembers returns all the members of the set value stored at key.\n// This has the same effect as running SINTER with one argument key.\n//\n// It returns all elements of the set.\n//\n// https://redis.io/commands/smembers/\nfunc (r GroupSet) SMembers(ctx context.Context, key string) (gvar.Vars, error) {\n\tv, err := r.Operation.Do(ctx, \"SMembers\", key)\n\treturn v.Vars(), err\n}\n\n// SMIsMember returns whether each member is a member of the set stored at key.\n//\n// For every member, 1 is returned if the value is a member of the set, or 0 if the element is not a member of\n// the set or if key does not exist.\n//\n// It returns list representing the membership of the given elements, in the same order as they are requested.\n//\n// https://redis.io/commands/smismember/\nfunc (r GroupSet) SMIsMember(ctx context.Context, key, member any, members ...any) ([]int, error) {\n\tvar s = []any{key, member}\n\ts = append(s, members...)\n\tv, err := r.Operation.Do(ctx, \"SMIsMember\", s...)\n\treturn v.Ints(), err\n}\n\n// SInter returns the members of the set resulting from the intersection of all the given sets.\n//\n// It returns list with members of the resulting set.\n//\n// https://redis.io/commands/sinter/\nfunc (r GroupSet) SInter(ctx context.Context, key string, keys ...string) (gvar.Vars, error) {\n\tvar s = []any{key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SInter\", s...)\n\treturn v.Vars(), err\n}\n\n// SInterStore is equal to SInter, but instead of returning the resulting set, it is stored in\n// destination.\n//\n// If destination already exists, it is overwritten.\n//\n// It returns the number of elements in the resulting set.\n//\n// https://redis.io/commands/sinterstore/\nfunc (r GroupSet) SInterStore(ctx context.Context, destination string, key string, keys ...string) (int64, error) {\n\tvar s = []any{destination, key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SInterStore\", s...)\n\treturn v.Int64(), err\n}\n\n// SUnion returns the members of the set resulting from the union of all the given sets.\n//\n// It returns list with members of the resulting set.\n//\n// https://redis.io/commands/sunion/\nfunc (r GroupSet) SUnion(ctx context.Context, key string, keys ...string) (gvar.Vars, error) {\n\tvar s = []any{key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SUnion\", s...)\n\treturn v.Vars(), err\n}\n\n// SUnionStore is equal to SUnion, but instead of returning the resulting set, it is stored in destination.\n//\n//\tIf destination already exists, it is overwritten.\n//\n// It returns the number of elements in the resulting set.\n//\n// https://redis.io/commands/sunionstore/\nfunc (r GroupSet) SUnionStore(ctx context.Context, destination, key string, keys ...string) (int64, error) {\n\tvar s = []any{destination, key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SUnionStore\", s...)\n\treturn v.Int64(), err\n}\n\n// SDiff returns the members of the set resulting from the difference between the first set and all the\n// successive sets.\n//\n// It returns list with members of the resulting set.\n//\n// https://redis.io/commands/sdiff/\nfunc (r GroupSet) SDiff(ctx context.Context, key string, keys ...string) (gvar.Vars, error) {\n\tvar s = []any{key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SDiff\", s...)\n\treturn v.Vars(), err\n}\n\n// SDiffStore is equal to SDiff, but instead of returning the resulting set, it is stored in destination.\n//\n// If destination already exists, it is overwritten.\n//\n// It returns the number of elements in the resulting set.\n//\n// https://redis.io/commands/sdiffstore/\nfunc (r GroupSet) SDiffStore(ctx context.Context, destination string, key string, keys ...string) (int64, error) {\n\tvar s = []any{destination, key}\n\ts = append(s, gconv.Interfaces(keys)...)\n\tv, err := r.Operation.Do(ctx, \"SDiffStore\", s...)\n\treturn v.Int64(), err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_sorted_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n)\n\n// GroupSortedSet provides sorted set functions for redis.\ntype GroupSortedSet struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupSortedSet creates and returns GroupSortedSet.\nfunc (r *Redis) GroupSortedSet() gredis.IGroupSortedSet {\n\treturn GroupSortedSet{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// ZAdd adds all the specified members with the specified scores to the sorted set stored at key.\n// It is possible to specify multiple score / member pairs.\n// If a specified member is already a member of the sorted set, the score is updated and the element reinserted\n// at the right position to ensure the correct ordering.\n//\n// If key does not exist, a new sorted set with the specified members as sole members is created, like if the\n// sorted set was empty. If the key exists but does not hold a sorted set, an error is returned.\n//\n// The score values should be the string representation of a double precision floating point number. +inf and\n// -inf values are valid values as well.\n//\n// It returns:\n// - When used without optional arguments, the number of elements added to the sorted set (excluding score updates).\n// - If the CH option is specified, the number of elements that were changed (added or updated).\n//\n// If the INCR option is specified, the return value will be Bulk string reply:\n//   - The new score of member (a double precision floating point number) represented as string, or nil if the operation\n//     was aborted (when called with either the XX or the NX option).\n//\n// https://redis.io/commands/zadd/\nfunc (r GroupSortedSet) ZAdd(\n\tctx context.Context, key string, option *gredis.ZAddOption, member gredis.ZAddMember, members ...gredis.ZAddMember,\n) (*gvar.Var, error) {\n\ts := mustMergeOptionToArgs(\n\t\t[]any{key}, option,\n\t)\n\ts = append(s, member.Score, member.Member)\n\tfor _, item := range members {\n\t\ts = append(s, item.Score, item.Member)\n\t}\n\tv, err := r.Operation.Do(ctx, \"ZAdd\", s...)\n\treturn v, err\n}\n\n// ZScore Returns the score of member in the sorted set at key.\n//\n// If member does not exist in the sorted set, or key does not exist, nil is returned.\n//\n// It returns the score of member (a double precision floating point number), represented as string.\n//\n// https://redis.io/commands/zscore/\nfunc (r GroupSortedSet) ZScore(ctx context.Context, key string, member any) (float64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZScore\", key, member)\n\treturn v.Float64(), err\n}\n\n// ZIncrBy increments the score of member in the sorted set stored at key by increment.\n// If member does not exist in the sorted set, it is added with increment as its score (as if its previous score\n// was 0.0). If key does not exist, a new sorted set with the specified member as its sole member is created.\n//\n// An error is returned when key exists but does not hold a sorted set.\n//\n// The score value should be the string representation of a numeric value, and accepts double precision floating\n// point numbers. It is possible to provide a negative value to decrement the score.\n//\n// It returns the new score of member (a double precision floating point number).\n//\n// https://redis.io/commands/zincrby/\nfunc (r GroupSortedSet) ZIncrBy(ctx context.Context, key string, increment float64, member any) (float64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZIncrBy\", key, increment, member)\n\treturn v.Float64(), err\n}\n\n// ZCard returns the sorted set cardinality (number of elements) of the sorted set stored at key.\n//\n// It returns the cardinality (number of elements) of the sorted set, or 0 if key does not exist.\n//\n// https://redis.io/commands/zcard/\nfunc (r GroupSortedSet) ZCard(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZCard\", key)\n\treturn v.Int64(), err\n}\n\n// ZCount returns the number of elements in the sorted set at key with a score between min and max.\n//\n// The min and max arguments have the same semantic as described for ZRangeByScore.\n//\n// Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see ZRANK) to get an\n// idea of the range. Because of this there is no need to do a work proportional to the size of the range.\n//\n// It returns the number of elements in the specified score range.\n//\n// https://redis.io/commands/zcount/\nfunc (r GroupSortedSet) ZCount(ctx context.Context, key string, min, max string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZCount\", key, min, max)\n\treturn v.Int64(), err\n}\n\n// ZRange return the specified range of elements in the sorted set stored at <key>.\n//\n// ZRange can perform different types of range queries: by index (rank), by the score, or by lexicographical\n// order.\n//\n// https://redis.io/commands/zrange/\nfunc (r GroupSortedSet) ZRange(ctx context.Context, key string, start, stop int64, option ...gredis.ZRangeOption) (gvar.Vars, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tv, err := r.Operation.Do(ctx, \"ZRange\", mustMergeOptionToArgs(\n\t\t[]any{key, start, stop}, usedOption,\n\t)...)\n\treturn v.Vars(), err\n}\n\n// ZRevRange returns the specified range of elements in the sorted set stored at key.\n// The elements are considered to be ordered from the highest to the lowest score.\n// Descending lexicographical order is used for elements with equal score.\n//\n// Apart from the reversed ordering, ZRevRange is similar to ZRange.\n//\n// It returns list of elements in the specified range (optionally with their scores).\n//\n// https://redis.io/commands/zrevrange/\nfunc (r GroupSortedSet) ZRevRange(ctx context.Context, key string, start, stop int64, option ...gredis.ZRevRangeOption) (*gvar.Var, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\treturn r.Operation.Do(ctx, \"ZRevRange\", mustMergeOptionToArgs(\n\t\t[]any{key, start, stop}, usedOption,\n\t)...)\n}\n\n// ZRank returns the rank of member in the sorted set stored at key, with the scores ordered from low to high.\n// The rank (or index) is 0-based, which means that the member with the lowest score has rank 0.\n//\n// Use ZRevRank to get the rank of an element with the scores ordered from high to low.\n//\n// It returns:\n// - If member exists in the sorted set, Integer reply: the rank of member.\n// - If member does not exist in the sorted set or key does not exist, Bulk string reply: nil.\n//\n// https://redis.io/commands/zrank/\nfunc (r GroupSortedSet) ZRank(ctx context.Context, key string, member any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZRank\", key, member)\n\treturn v.Int64(), err\n}\n\n// ZRevRank returns the rank of member in the sorted set stored at key, with the scores ordered from high to low.\n// The rank (or index) is 0-based, which means that the member with the highest score has rank 0.\n//\n// Use ZRank to get the rank of an element with the scores ordered from low to high.\n//\n// It returns:\n// - If member exists in the sorted set, Integer reply: the rank of member.\n// - If member does not exist in the sorted set or key does not exist, Bulk string reply: nil.\n//\n// https://redis.io/commands/zrevrank/\nfunc (r GroupSortedSet) ZRevRank(ctx context.Context, key string, member any) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZRevRank\", key, member)\n\treturn v.Int64(), err\n}\n\n// ZRem remove the specified members from the sorted set stored at key.\n// Non-existing members are ignored.\n//\n// An error is returned when key exists and does not hold a sorted set.\n//\n// It returns the number of members removed from the sorted set, not including non existing members.\n//\n// https://redis.io/commands/zrem/\nfunc (r GroupSortedSet) ZRem(ctx context.Context, key string, member any, members ...any) (int64, error) {\n\tvar s = []any{key}\n\ts = append(s, member)\n\ts = append(s, members...)\n\tv, err := r.Operation.Do(ctx, \"ZRem\", s...)\n\treturn v.Int64(), err\n}\n\n// ZRemRangeByRank removes all elements in the sorted set stored at key with rank between start and stop.\n// Both start and stop are 0 -based indexes with 0 being the element with the lowest score.\n//\n// These indexes can be negative numbers, where they indicate offsets starting at the element with the highest\n// score. For example: -1 is the element with the highest score, -2 the element with the second-highest score\n// and so forth.\n//\n// It returns the number of elements removed.\n//\n// https://redis.io/commands/zremrangebyrank/\nfunc (r GroupSortedSet) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZRemRangeByRank\", key, start, stop)\n\treturn v.Int64(), err\n}\n\n// ZRemRangeByScore removes all elements in the sorted set stored at key with a score between min and max\n// (inclusive).\n//\n// It returns the number of elements removed.\n//\n// https://redis.io/commands/zremrangebyscore/\nfunc (r GroupSortedSet) ZRemRangeByScore(ctx context.Context, key string, min, max string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZRemRangeByScore\", key, min, max)\n\treturn v.Int64(), err\n}\n\n// ZRemRangeByLex removes all elements in the sorted set stored at key between the\n// lexicographical range specified by min and max.\n//\n// The meaning of min and max are the same of the ZRangeByLex command.\n// Similarly, this command actually removes the same elements that ZRangeByLex would return if called with the\n// same min and max arguments.\n//\n// It returns the number of elements removed.\n//\n// https://redis.io/commands/zremrangebylex/\nfunc (r GroupSortedSet) ZRemRangeByLex(ctx context.Context, key string, min, max string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZRemRangeByLex\", key, min, max)\n\treturn v.Int64(), err\n}\n\n// ZLexCount all the elements in a sorted set are inserted with the same score,\n// in order to force lexicographical ordering, this command returns the number of elements in the sorted\n// set at key with a value between min and max.\n//\n// The min and max arguments have the same meaning as described for ZRangeByLex.\n//\n// Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see ZRank) to get an\n// idea of the range. Because of this there is no need to do a work proportional to the size of the range.\n//\n// It returns the number of elements in the specified score range.\n//\n// https://redis.io/commands/zlexcount/\nfunc (r GroupSortedSet) ZLexCount(ctx context.Context, key, min, max string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"ZLexCount\", key, min, max)\n\treturn v.Int64(), err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_group_string.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GroupString is the function group manager for string operations.\ntype GroupString struct {\n\tOperation gredis.AdapterOperation\n}\n\n// GroupString is the redis group object for string operations.\nfunc (r *Redis) GroupString() gredis.IGroupString {\n\treturn GroupString{\n\t\tOperation: r.AdapterOperation,\n\t}\n}\n\n// Set key to hold the string value. If key already holds a value, it is overwritten,\n// regardless of its type.\n// Any previous time to live associated with the key is discarded on successful SET operation.\n//\n// https://redis.io/commands/set/\nfunc (r GroupString) Set(ctx context.Context, key string, value any, option ...gredis.SetOption) (*gvar.Var, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\treturn r.Operation.Do(ctx, \"Set\", mustMergeOptionToArgs(\n\t\t[]any{key, value}, usedOption,\n\t)...)\n}\n\n// SetNX sets key to hold string value if key does not exist.\n// In that case, it is equal to SET.\n// When key already holds a value, no operation is performed.\n// SetNX is short for \"SET if Not exists\".\n//\n// It returns:\n// true:  if the all the keys were set.\n// false: if no key was set (at least one key already existed).\n//\n// https://redis.io/commands/setnx/\nfunc (r GroupString) SetNX(ctx context.Context, key string, value any) (bool, error) {\n\tv, err := r.Operation.Do(ctx, \"SetNX\", key, value)\n\treturn v.Bool(), err\n}\n\n// SetEX sets key to hold the string value and set key to timeout after a given number of seconds.\n// This command is equivalent to executing the following commands:\n//\n//\tSET myKey value\n//\tEXPIRE myKey seconds\n//\n// SetEX is atomic, and can be reproduced by using the previous two commands inside an MULTI / EXEC block.\n// It is provided as a faster alternative to the given sequence of operations, because this operation is very\n// common when Redis is used as a cache.\n//\n// An error is returned when seconds invalid.\n//\n// https://redis.io/commands/setex/\nfunc (r GroupString) SetEX(ctx context.Context, key string, value any, ttlInSeconds int64) error {\n\t_, err := r.Operation.Do(ctx, \"SetEX\", key, ttlInSeconds, value)\n\treturn err\n}\n\n// Get the value of key. If the key does not exist the special value nil is returned.\n// An error is returned if the value stored at key is not a string, because GET only handles string values.\n//\n// https://redis.io/commands/get/\nfunc (r GroupString) Get(ctx context.Context, key string) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"Get\", key)\n}\n\n// GetDel gets the value of key and delete the key.\n// This command is similar to GET, except for the fact that it also deletes the key on success\n// (if and only if the key's value type is a string).\n//\n// https://redis.io/commands/getdel/\nfunc (r GroupString) GetDel(ctx context.Context, key string) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"GetDel\", key)\n}\n\n// GetEX is similar to GET, but is a write command with additional options.\n//\n// https://redis.io/commands/getex/\nfunc (r GroupString) GetEX(ctx context.Context, key string, option ...gredis.GetEXOption) (*gvar.Var, error) {\n\tvar usedOption any\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\treturn r.Operation.Do(ctx, \"GetEX\", mustMergeOptionToArgs(\n\t\t[]any{key}, usedOption,\n\t)...)\n}\n\n// GetSet atomically sets key to value and returns the old value stored at key.\n// Returns an error when key exists but does not hold a string value. Any previous time to live associated with\n// the key is discarded on successful SET operation.\n//\n// https://redis.io/commands/getset/\nfunc (r GroupString) GetSet(ctx context.Context, key string, value any) (*gvar.Var, error) {\n\treturn r.Operation.Do(ctx, \"GetSet\", key, value)\n}\n\n// StrLen returns the length of the string value stored at key.\n// An error is returned when key holds a non-string value.\n//\n// It returns the length of the string at key, or 0 when key does not exist.\n//\n// https://redis.io/commands/strlen/\nfunc (r GroupString) StrLen(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"StrLen\", key)\n\treturn v.Int64(), err\n}\n\n// Append appends the value at the end of the string, if key already exists and is a string.\n// If key does not exist it is created and set as an empty string,\n// so APPEND will be similar to SET in this special case.\n//\n// https://redis.io/commands/append/\nfunc (r GroupString) Append(ctx context.Context, key string, value string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Append\", key, value)\n\treturn v.Int64(), err\n}\n\n// SetRange overwrites part of the string stored at key, starting at the specified offset, for the entire length\n// of value. If the offset is larger than the current length of the string at key, the string is padded with\n// zero-bytes to make offset fit. Non-existing keys are considered as empty strings, so this command will\n// make sure it holds a string large enough to be able to set value at offset.\n//\n// It returns the length of the string after it was modified by the command.\n//\n// https://redis.io/commands/setrange/\nfunc (r GroupString) SetRange(ctx context.Context, key string, offset int64, value string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"SetRange\", key, offset, value)\n\treturn v.Int64(), err\n}\n\n// GetRange returns the substring of the string value stored at key,\n// determined by the offsets start and end (both are inclusive). Negative offsets can be used in order to provide\n// an offset starting from the end of the string. So -1 means the last character, -2 the penultimate and so forth.\n//\n// The function handles out of range requests by limiting the resulting range to the actual length of the string.\n//\n// https://redis.io/commands/getrange/\nfunc (r GroupString) GetRange(ctx context.Context, key string, start, end int64) (string, error) {\n\tv, err := r.Operation.Do(ctx, \"GetRange\", key, start, end)\n\treturn v.String(), err\n}\n\n// Incr increments the number stored at key by one.\n// If the key does not exist, it is set to 0 before performing the operation.\n// An error is returned if the key contains a value of the wrong type or contains a string that can not be\n// represented as integer. This operation is limited to 64 bits signed integers.\n//\n// https://redis.io/commands/incr/\nfunc (r GroupString) Incr(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Incr\", key)\n\treturn v.Int64(), err\n}\n\n// IncrBy increments the number stored at key by increment. If the key does not exist, it is set to 0 before\n// performing the operation.\n//\n// An error is returned if the key contains a value of the wrong type or contains a\n// string that can not be represented as integer. This operation is limited to 64 bits signed integers.\n//\n// https://redis.io/commands/incrby/\nfunc (r GroupString) IncrBy(ctx context.Context, key string, increment int64) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"IncrBy\", key, increment)\n\treturn v.Int64(), err\n}\n\n// IncrByFloat increments the string representing a floating point number stored at key by the specified increment.\n//\n// https://redis.io/commands/incrbyfloat/\nfunc (r GroupString) IncrByFloat(ctx context.Context, key string, increment float64) (float64, error) {\n\tv, err := r.Operation.Do(ctx, \"IncrByFloat\", key, increment)\n\treturn v.Float64(), err\n}\n\n// Decr decrements the number stored at key by one.\n//\n// https://redis.io/commands/decr/\nfunc (r GroupString) Decr(ctx context.Context, key string) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"Decr\", key)\n\treturn v.Int64(), err\n}\n\n// DecrBy decrements the number stored at key by decrement.\n//\n// https://redis.io/commands/decrby/\nfunc (r GroupString) DecrBy(ctx context.Context, key string, decrement int64) (int64, error) {\n\tv, err := r.Operation.Do(ctx, \"DecrBy\", key, decrement)\n\treturn v.Int64(), err\n}\n\n// MSet sets the given keys to their respective values.\n// MSet replaces existing values with new values, just as regular SET.\n// See MSetNX if you don't want to overwrite existing values.\n//\n// MSet is atomic, so all given keys are set at once. It is not possible for clients to see that some keys\n// were updated while others are unchanged.\n//\n// https://redis.io/commands/mset/\nfunc (r GroupString) MSet(ctx context.Context, keyValueMap map[string]any) error {\n\tvar args []any\n\tfor k, v := range keyValueMap {\n\t\targs = append(args, k, v)\n\t}\n\t_, err := r.Operation.Do(ctx, \"MSet\", args...)\n\treturn err\n}\n\n// MSetNX sets the given keys to their respective values.\n//\n// It returns:\n// true:  if the all the keys were set.\n// false: if no key was set (at least one key already existed).\nfunc (r GroupString) MSetNX(ctx context.Context, keyValueMap map[string]any) (bool, error) {\n\tvar args []any\n\tfor k, v := range keyValueMap {\n\t\targs = append(args, k, v)\n\t}\n\tv, err := r.Operation.Do(ctx, \"MSetNX\", args...)\n\treturn v.Bool(), err\n}\n\n// MGet returns the values of all specified keys.\n//\n// https://redis.io/commands/mget/\nfunc (r GroupString) MGet(ctx context.Context, keys ...string) (map[string]*gvar.Var, error) {\n\tvar result = make(map[string]*gvar.Var)\n\tv, err := r.Operation.Do(ctx, \"MGet\", gconv.Interfaces(keys)...)\n\tif err == nil {\n\t\tvalues := v.Vars()\n\t\tfor i, key := range keys {\n\t\t\tresult[key] = values[i]\n\t\t}\n\t}\n\treturn result, err\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_operation.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Do send a command to the server and returns the received reply.\n// It uses json.Marshal for struct/slice/map type values before committing them to redis.\nfunc (r *Redis) Do(ctx context.Context, command string, args ...any) (*gvar.Var, error) {\n\tconn, err := r.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = conn.Close(ctx)\n\t}()\n\treturn conn.Do(ctx, command, args...)\n}\n\n// Close closes the redis connection pool, which will release all connections reserved by this pool.\n// It is commonly not necessary to call Close manually.\nfunc (r *Redis) Close(ctx context.Context) (err error) {\n\tif err = r.client.Close(); err != nil {\n\t\terr = gerror.Wrap(err, `Operation Client Close failed`)\n\t}\n\treturn\n}\n\n// Conn retrieves and returns a connection object for continuous operations.\n// Note that you should call Close function manually if you do not use this connection any further.\nfunc (r *Redis) Conn(ctx context.Context) (gredis.Conn, error) {\n\treturn &Conn{\n\t\tredis: r,\n\t}, nil\n}\n\n// Client returns the underlying redis client instance.\n// This method provides access to the raw redis client for advanced operations\n// that are not covered by the standard Redis interface.\n//\n// Example usage with type assertion:\n//\n//\timport goredis \"github.com/redis/go-redis/v9\"\n//\n//\tfunc ExampleUsage(ctx context.Context, redis *Redis) error {\n//\t\tclient := redis.Client()\n//\t\tuniversalClient, ok := client.(goredis.UniversalClient)\n//\t\tif !ok {\n//\t\t\treturn errors.New(\"failed to assert to UniversalClient\")\n//\t\t}\n//\n//\t\t// Use universalClient for advanced operations like Pipeline\n//\t\tpipe := universalClient.Pipeline()\n//\t\tpipe.Set(ctx, \"key1\", \"value1\", 0)\n//\t\tpipe.Set(ctx, \"key2\", \"value2\", 0)\n//\t\tresults, err := pipe.Exec(ctx)\n//\t\tif err != nil {\n//\t\t\treturn err\n//\t\t}\n//\t\t// ... handle results\n//\t\treturn nil\n//\t}\nfunc (r *Redis) Client() gredis.RedisRawClient {\n\treturn r.client\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nvar (\n\tctx    = gctx.GetInitCtx()\n\tconfig = &gredis.Config{\n\t\tAddress: `:6379`,\n\t\tDb:      1,\n\t}\n\tredis, _ = gredis.New(config)\n)\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_func_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_mustMergeOptionToArgs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar args []any\n\t\tnewArgs := mustMergeOptionToArgs(args, gredis.SetOption{\n\t\t\tNX:  true,\n\t\t\tGet: true,\n\t\t})\n\t\tt.Assert(newArgs, []any{\"NX\", \"Get\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar args []any\n\t\tnewArgs := mustMergeOptionToArgs(args, gredis.SetOption{\n\t\t\tNX:  true,\n\t\t\tGet: true,\n\t\t\tTTLOption: gredis.TTLOption{\n\t\t\t\tEX: gconv.PtrInt64(60),\n\t\t\t},\n\t\t})\n\t\tt.Assert(newArgs, []any{\"EX\", 60, \"NX\", \"Get\"})\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_generic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\tTestKey   = \"mykey\"\n\tTestValue = \"hello\"\n)\n\nfunc Test_GroupGeneric_Copy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1     = guid.S()\n\t\t\tv1     = guid.S()\n\t\t\tk2     = guid.S()\n\t\t\tresult int64\n\t\t\terr    error\n\t\t)\n\t\t_, err = redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\tresult, err = redis.GroupGeneric().Copy(ctx, k1, k2)\n\t\tt.AssertEQ(result, int64(1))\n\t\tt.AssertNil(err)\n\t\tv2, err := redis.GroupString().Get(ctx, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), v1)\n\t})\n\t// With Option.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1     = guid.S()\n\t\t\tv1     = guid.S()\n\t\t\tk2     = guid.S()\n\t\t\tresult int64\n\t\t\terr    error\n\t\t)\n\t\t_, err = redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\tresult, err = redis.GroupGeneric().Copy(ctx, k1, k2, gredis.CopyOption{\n\t\t\tDB:      1,\n\t\t\tREPLACE: true,\n\t\t})\n\t\tt.AssertEQ(result, int64(1))\n\t\tt.AssertNil(err)\n\t\tv2, err := redis.GroupString().Get(ctx, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v2.String(), v1)\n\t})\n}\n\nfunc Test_GroupGeneric_Exists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Exists(ctx, k1)\n\t\tt.AssertEQ(result, int64(1))\n\t\tt.AssertNil(err)\n\t\tresult, err = redis.GroupGeneric().Exists(ctx, \"nosuchkey\")\n\t\tt.AssertEQ(result, int64(0))\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, k2, v2)\n\t\tt.AssertNil(err)\n\t\tresult, err = redis.GroupGeneric().Exists(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, int64(2))\n\t})\n}\n\nfunc Test_GroupGeneric_Type(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupList().LPush(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupSet().SAdd(ctx, \"k3\", \"v3\")\n\t\tt.AssertNil(err)\n\n\t\tt1, err := redis.GroupGeneric().Type(ctx, \"k1\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(t1, \"string\")\n\t\tt2, err := redis.GroupGeneric().Type(ctx, \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(t2, \"list\")\n\t\tt3, err := redis.GroupGeneric().Type(ctx, \"k3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(t3, \"set\")\n\t})\n}\n\nfunc Test_GroupGeneric_Unlink(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\n\t\tresult, err := redis.GroupGeneric().Unlink(ctx, \"k1\", \"k2\", \"k3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(2))\n\t\tv1, err := redis.GroupString().Get(ctx, \"k1\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v1.String(), \"\")\n\t\tv2, err := redis.GroupString().Get(ctx, \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v2.String(), \"\")\n\t})\n}\n\nfunc Test_GroupGeneric_Rename(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\terr = redis.GroupGeneric().Rename(ctx, \"k1\", \"k2\")\n\t\tt.AssertNil(err)\n\t\tv1, err := redis.GroupString().Get(ctx, \"k1\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v1.String(), \"\")\n\t\tv2, err := redis.GroupString().Get(ctx, \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v2.String(), \"v1\")\n\t})\n}\n\nfunc Test_GroupGeneric_RenameNX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().RenameNX(ctx, \"k1\", \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(0))\n\t\tresult, err = redis.GroupGeneric().RenameNX(ctx, \"k1\", \"k3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tv2, err := redis.GroupString().Get(ctx, \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v2.String(), \"v2\")\n\t\tv3, err := redis.GroupString().Get(ctx, \"k3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v3.String(), \"v1\")\n\t})\n}\n\nfunc Test_GroupGeneric_Move(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushAll(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Move(ctx, \"k1\", 0)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t})\n}\n\nfunc Test_GroupGeneric_Del(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Del(ctx, \"k1\", \"k2\", \"k3\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(2))\n\t\tv1, err := redis.GroupString().Get(ctx, \"k1\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v1.String(), \"\")\n\t\tv2, err := redis.GroupString().Get(ctx, \"k2\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(v2.String(), \"\")\n\t})\n}\n\nfunc Test_GroupGeneric_RandomKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tkey, err := redis.GroupGeneric().RandomKey(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(key, \"\")\n\n\t\t_, err = redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\n\t\tkey, err = redis.GroupGeneric().RandomKey(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(key, []string{\"k1\", \"k2\"})\n\t})\n}\n\nfunc Test_GroupGeneric_DBSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tdbSize, err := redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(0))\n\n\t\t_, err = redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\n\t\tdbSize, err = redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(2))\n\t})\n}\n\nfunc Test_GroupGeneric_Keys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\terr := redis.GroupString().MSet(ctx, map[string]any{\n\t\t\t\"firstname\": \"Jack\",\n\t\t\t\"lastname\":  \"Stuntman\",\n\t\t\t\"age\":       35,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tkeys, err := redis.GroupGeneric().Keys(ctx, \"*name*\")\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(keys, []string{\"lastname\", \"firstname\"})\n\t\tkeys, err = redis.GroupGeneric().Keys(ctx, \"a??\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(keys, []string{\"age\"})\n\t\tkeys, err = redis.GroupGeneric().Keys(ctx, \"*\")\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(keys, []string{\"lastname\", \"firstname\", \"age\"})\n\t})\n}\n\nfunc Test_GroupGeneric_Scan(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\terr := redis.GroupString().MSet(ctx, map[string]any{\n\t\t\t\"firstname\": \"Jack\",\n\t\t\t\"lastname\":  \"Stuntman\",\n\t\t\t\"age\":       35,\n\t\t\t\"nickname\":  \"Jumper\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tperformScan := func(cursor uint64, option ...gredis.ScanOption) ([]string, error) {\n\t\t\tvar allKeys = []string{}\n\t\t\tfor {\n\t\t\t\tvar nextCursor uint64\n\t\t\t\tvar keys []string\n\t\t\t\tvar err error\n\n\t\t\t\tif option != nil {\n\t\t\t\t\tnextCursor, keys, err = redis.Scan(ctx, cursor, option[0])\n\t\t\t\t} else {\n\t\t\t\t\tnextCursor, keys, err = redis.Scan(ctx, cursor)\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tallKeys = append(allKeys, keys...)\n\t\t\t\tif nextCursor == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcursor = nextCursor\n\t\t\t}\n\t\t\treturn allKeys, nil\n\t\t}\n\n\t\t// Test scanning for keys with `*name*` pattern\n\t\toptWithName := gredis.ScanOption{Match: \"*name*\", Count: 10}\n\t\tkeysWithName, err := performScan(0, optWithName)\n\t\tt.AssertNil(err)\n\t\tt.AssertGE(len(keysWithName), 3)\n\t\tt.AssertIN(keysWithName, []string{\"lastname\", \"firstname\", \"nickname\"})\n\n\t\t// Test scanning with a pattern that matches exactly one key\n\t\toptWithAge := gredis.ScanOption{Match: \"a??\", Count: 10}\n\t\tkeysWithAge, err := performScan(0, optWithAge)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(len(keysWithAge), 1)\n\t\tt.AssertEQ(keysWithAge, []string{\"age\"})\n\n\t\t// Test scanning for all keys\n\t\toptWithAll := gredis.ScanOption{Match: \"*\", Count: 10}\n\t\tall, err := performScan(0, optWithAll)\n\t\tt.AssertNil(err)\n\t\tt.AssertGE(len(all), 4)\n\t\tt.AssertIN(all, []string{\"lastname\", \"firstname\", \"age\", \"nickname\"})\n\n\t\t// Test empty pattern\n\t\toptWithEmptyPattern := gredis.ScanOption{Match: \"\"}\n\t\temptyPatternKeys, err := performScan(0, optWithEmptyPattern)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(len(emptyPatternKeys), 4)\n\n\t\t// Test pattern with no matches\n\t\toptWithNoMatch := gredis.ScanOption{Match: \"xyz*\", Count: 10}\n\t\tnoMatchKeys, err := performScan(0, optWithNoMatch)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(len(noMatchKeys), 0)\n\n\t\t// Test scanning for keys with invalid count value\n\t\toptWithInvalidCount := gredis.ScanOption{Count: -1}\n\t\t_, err = performScan(0, optWithInvalidCount)\n\t\tt.AssertNQ(err, nil)\n\n\t\t// Test scanning for all keys without options\n\t\tallWithoutOpt, err := performScan(0)\n\t\tt.AssertNil(err)\n\t\tt.AssertGE(len(allWithoutOpt), 4)\n\t\tt.AssertIN(all, []string{\"lastname\", \"firstname\", \"age\", \"nickname\"})\n\t})\n}\n\nfunc Test_GroupGeneric_FlushDB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\n\t\tdbSize, err := redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(2))\n\n\t\terr = redis.GroupGeneric().FlushDB(ctx)\n\t\tt.AssertNil(err)\n\n\t\tdbSize, err = redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(0))\n\t})\n}\n\nfunc Test_GroupGeneric_FlushAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, \"k1\", \"v1\")\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, \"k2\", \"v2\")\n\t\tt.AssertNil(err)\n\n\t\tdbSize, err := redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(2))\n\n\t\terr = redis.GroupGeneric().FlushAll(ctx)\n\t\tt.AssertNil(err)\n\n\t\tdbSize, err = redis.GroupGeneric().DBSize(ctx)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(dbSize, int64(0))\n\t})\n}\n\nfunc Test_GroupGeneric_Expire(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Expire(ctx, TestKey, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tttl, err := redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(ttl, int64(1))\n\t})\n\t// With Option.\n\t// Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tttl, err := redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(ttl, int64(-1))\n\t\tresult, err := redis.GroupGeneric().Expire(ctx, TestKey, 1, gredis.ExpireOption{XX: true})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(0))\n\t\tttl, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(ttl, int64(-1))\n\t\tresult, err = redis.GroupGeneric().Expire(ctx, TestKey, 1, gredis.ExpireOption{NX: true})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tttl, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(ttl, int64(1))\n\t})\n}\n\nfunc Test_GroupGeneric_ExpireAt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Exists(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().ExpireAt(ctx, TestKey, time.Now().Add(time.Millisecond*100))\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\ttime.Sleep(time.Millisecond * 200)\n\t\tresult, err = redis.GroupGeneric().Exists(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(0))\n\t})\n\t// With Option.\n\t// Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tttl, err := redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(ttl, int64(-1))\n\t\tresult, err := redis.GroupGeneric().ExpireAt(ctx, TestKey, time.Now().Add(time.Millisecond*100), gredis.ExpireOption{XX: true})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(0))\n\t\tresult, err = redis.GroupGeneric().ExpireAt(ctx, TestKey, time.Now().Add(time.Minute), gredis.ExpireOption{NX: true})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tttl, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(ttl, int64(0))\n\t})\n}\n\nfunc Test_GroupGeneric_ExpireTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\texpireTime := time.Now().Add(time.Minute)\n\t\tresult, err := redis.GroupGeneric().ExpireAt(ctx, TestKey, expireTime)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresultTime, err := redis.GroupGeneric().ExpireTime(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(resultTime.Int64(), expireTime.Unix())\n\n\t\t_, err = redis.GroupString().Set(ctx, \"noExpireKey\", TestValue)\n\t\tt.AssertNil(err)\n\t\tresultTime, err = redis.GroupGeneric().ExpireTime(ctx, \"noExpireKey\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(resultTime.Int64(), int64(-1))\n\n\t\tresultTime, err = redis.GroupGeneric().ExpireTime(ctx, \"noExistKey\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(resultTime.Int64(), int64(-2))\n\t})\n}\n\nfunc Test_GroupGeneric_TTL(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Expire(ctx, TestKey, 10)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(10))\n\t})\n}\n\nfunc Test_GroupGeneric_Persist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Expire(ctx, TestKey, 10)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(10))\n\t\tresult, err = redis.GroupGeneric().Persist(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(-1))\n\t})\n}\n\nfunc Test_GroupGeneric_PExpire(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().PExpire(ctx, TestKey, 2500)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().PTTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertLE(result, int64(2500))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().PExpire(ctx, TestKey, 2500, gredis.ExpireOption{\n\t\t\tNX: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\n\t\tresult, err = redis.GroupGeneric().PExpire(ctx, TestKey, 2500, gredis.ExpireOption{\n\t\t\tNX: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(0))\n\n\t\tresult, err = redis.GroupGeneric().PTTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertLE(result, int64(2500))\n\t})\n}\n\nfunc Test_GroupGeneric_PExpireAt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().PExpireAt(ctx, TestKey, time.Now().Add(-time.Hour))\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().TTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(-2))\n\t\tresult, err = redis.GroupGeneric().PTTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(-2))\n\t})\n}\n\nfunc Test_GroupGeneric_PExpireTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\texpireTime := time.Now().Add(time.Hour)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().PExpireAt(ctx, TestKey, expireTime)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresultTime, err := redis.GroupGeneric().PExpireTime(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(resultTime.Int64(), gtime.NewFromTime(expireTime).TimestampMilli())\n\t})\n}\n\nfunc Test_GroupGeneric_PTTL(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\t_, err := redis.GroupString().Set(ctx, TestKey, TestValue)\n\t\tt.AssertNil(err)\n\t\tresult, err := redis.GroupGeneric().Expire(ctx, TestKey, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(result, int64(1))\n\t\tresult, err = redis.GroupGeneric().PTTL(ctx, TestKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertLE(result, int64(1000))\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_hash_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GroupHash_HSet(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = \"Hello\"\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HGet(ctx, key, field1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), field1Value)\n\t})\n}\n\nfunc Test_GroupHash_HSetNX(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = \"Hello\"\n\t\t\tkey         = \"myhash\"\n\t\t)\n\t\tr1, err := redis.HSetNX(ctx, key, field1, field1Value)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 1)\n\n\t\tr2, err := redis.HSetNX(ctx, key, field1, \"World\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, 0)\n\t})\n}\n\nfunc Test_GroupHash_HStrLen(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = \"Hello\"\n\t\t\tfield2      = \"field2\"\n\t\t\tfield2Value = \"Hello World\"\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tfieldValueLen, err := redis.HStrLen(ctx, key, field1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(5, fieldValueLen)\n\n\t\tfields[field2] = field2Value\n\t\t_, err = redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tfieldValueLen, err = redis.HStrLen(ctx, key, field2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(11, fieldValueLen)\n\t})\n}\n\nfunc Test_GroupHash_HExists(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = \"Hello\"\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HExists(ctx, key, field1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(1, r1)\n\n\t\tr2, err := redis.HExists(ctx, key, \"name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(0, r2)\n\t})\n}\n\nfunc Test_GroupHash_HDel(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tk2     = \"k2\"\n\t\t\tv2     = \"v2\"\n\t\t\tk3     = \"k3\"\n\t\t\tv3     = \"v3\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t\tk2: v2,\n\t\t\t\tk3: v3,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HDel(ctx, key, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(1, r1)\n\n\t\tr2, err := redis.HDel(ctx, key, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(0, r2)\n\n\t\tr3, err := redis.HDel(ctx, key, k2, k3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(2, r3)\n\t})\n}\n\nfunc Test_GroupHash_HLen(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = \"Hello\"\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tfieldLen, err := redis.HLen(ctx, key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(1, fieldLen)\n\n\t\tfields = map[string]any{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tfieldLen, err = redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\t\tt.Assert(2, fieldLen)\n\t})\n}\n\nfunc Test_GroupHash_HIncrBy(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = 1\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HIncrBy(ctx, key, field1, 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(3, r1)\n\n\t\tr2, err := redis.HGet(ctx, key, field1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(3, r2.Int64())\n\n\t\tr3, err := redis.HIncrBy(ctx, key, field1, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(2, r3)\n\t})\n}\n\nfunc Test_GroupHash_HIncrByFloat(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey         = \"myhash\"\n\t\t\tfield1      = \"field1\"\n\t\t\tfield1Value = 10.50\n\t\t\tfields      = map[string]any{\n\t\t\t\tfield1: field1Value,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HIncrByFloat(ctx, key, field1, 0.1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(10.60, r1)\n\n\t\tr2, err := redis.HGet(ctx, key, field1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(10.60, r2.Float64())\n\n\t\tr3, err := redis.HIncrByFloat(ctx, key, field1, -5)\n\t\tt.AssertNil(err)\n\t\tt.Assert(5.60, r3)\n\t})\n}\n\nfunc Test_GroupHash_HMSet(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tk2     = \"k2\"\n\t\t\tv2     = \"v2\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t\tk2: v2,\n\t\t\t}\n\t\t)\n\t\terr := redis.HMSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HGet(ctx, key, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\tr2, err := redis.HGet(ctx, key, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v2)\n\t})\n}\n\nfunc Test_GroupHash_HMGet(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tk2     = \"k2\"\n\t\t\tv2     = \"v2\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t\tk2: v2,\n\t\t\t}\n\t\t)\n\t\terr := redis.HMSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HMGet(ctx, key, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v1, v2})\n\t})\n}\n\nfunc Test_GroupHash_HKeys(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HKeys(ctx, key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{k1})\n\t})\n}\n\nfunc Test_GroupHash_HVals(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HVals(ctx, key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v1})\n\t})\n}\n\nfunc Test_GroupHash_HGetAll(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"myhash\"\n\t\t\tk1     = \"k1\"\n\t\t\tv1     = \"v1\"\n\t\t\tk2     = \"k2\"\n\t\t\tv2     = \"v2\"\n\t\t\tfields = map[string]any{\n\t\t\t\tk1: v1,\n\t\t\t\tk2: v2,\n\t\t\t}\n\t\t)\n\t\t_, err := redis.HSet(ctx, key, fields)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.HGetAll(ctx, key)\n\t\tt.Assert(r1.Map(), fields)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_GroupList_LPush(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupList().LPush(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v2, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v2, v1})\n\t})\n}\n\nfunc Test_GroupList_LPushX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPushX(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupList().LPush(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupList().LPushX(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v1, v2})\n\t})\n}\n\nfunc Test_GroupList_RPush(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().RPush(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupList().RPush(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v1, v2})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().RPush(ctx, k1, v1, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v1, v2})\n\t})\n}\n\nfunc Test_GroupList_RPushX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().RPushX(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupList().RPush(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupList().RPushX(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v2, v1})\n\t})\n}\n\nfunc InfoServerMap() map[string]string {\n\tv, err := redis.Do(ctx, \"INFO\", \"server\")\n\tif err != nil {\n\t\treturn nil\n\t}\n\tserver := make(map[string]string)\n\tlist := strings.Split(v.String(), \"\\r\\n\")\n\tfor _, v := range list {\n\t\tif strings.Contains(v, \":\") {\n\t\t\tkv := strings.Split(v, \":\")\n\t\t\tif len(kv) == 2 {\n\t\t\t\tserver[kv[0]] = kv[1]\n\t\t\t}\n\t\t}\n\t}\n\treturn server\n}\n\nfunc GetRedisVersion() string {\n\tsvr := InfoServerMap()\n\tif svr != nil {\n\t\treturn svr[\"redis_version\"]\n\t}\n\treturn \"\"\n}\n\nfunc Test_GroupList_LPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LPop(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v3)\n\n\t\tr3, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r3, []string{v2, v1})\n\t})\n\n\t// redis version check\n\tif gstr.CompareVersion(GetRedisVersion(), \"6.2.0\") > 0 {\n\t\tgtest.C(t, func(t *gtest.T) {\n\t\t\tdefer redis.FlushDB(ctx)\n\t\t\tvar (\n\t\t\t\tk1 = \"k1\"\n\t\t\t\tv1 = \"v1\"\n\t\t\t\tv2 = \"v2\"\n\t\t\t\tv3 = \"v3\"\n\t\t\t)\n\t\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\t\tt.AssertNil(err)\n\n\t\t\tr1, err := redis.GroupList().LPop(ctx, k1, 2)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(r1, []string{v3, v2})\n\n\t\t\tr3, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(r3, []string{v1})\n\t\t})\n\t}\n}\n\nfunc Test_GroupList_RPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().RPop(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v1)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v2})\n\t})\n\n\t// redis version check\n\tif gstr.CompareVersion(GetRedisVersion(), \"6.2.0\") > 0 {\n\t\tgtest.C(t, func(t *gtest.T) {\n\t\t\tdefer redis.FlushDB(ctx)\n\t\t\tvar (\n\t\t\t\tk1 = \"k1\"\n\t\t\t\tv1 = \"v1\"\n\t\t\t\tv2 = \"v2\"\n\t\t\t\tv3 = \"v3\"\n\t\t\t)\n\t\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\t\tt.AssertNil(err)\n\n\t\t\tr1, err := redis.GroupList().RPop(ctx, k1, 2)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(r1, []string{v1, v2})\n\n\t\t\tr3, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(r3, []string{v3})\n\t\t})\n\t}\n}\n\nfunc Test_GroupList_LRem(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRem(ctx, k1, 1, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(1))\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v2, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRem(ctx, k1, -1, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(1))\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v1, v2})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRem(ctx, k1, 0, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(2))\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v2})\n\t})\n}\n\nfunc Test_GroupList_LLen(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LLen(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(3))\n\t})\n}\n\nfunc Test_GroupList_LIndex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LIndex(ctx, k1, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LIndex(ctx, k1, -2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LIndex(ctx, k1, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(r1)\n\t})\n}\n\nfunc Test_GroupList_LInsert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LInsert(ctx, k1, gredis.LInsertBefore, v2, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(4))\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v1, v2, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LInsert(ctx, k1, gredis.LInsertAfter, v2, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, int64(4))\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v2, v1, v1})\n\t})\n}\n\nfunc Test_GroupList_LSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LSet(ctx, k1, 1, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, \"OK\")\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v1, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LSet(ctx, k1, -2, v1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, \"OK\")\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v1, v1})\n\t})\n}\n\nfunc Test_GroupList_LRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v3, v2})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v3, v2, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 0, 100)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v3, v2, v1})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, 10, 100)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(r1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().LRange(ctx, k1, -3, -2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{v3, v2})\n\t})\n}\n\nfunc Test_GroupList_LTrim(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\terr = redis.GroupList().LTrim(ctx, k1, 1, 2)\n\t\tt.AssertNil(err)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v2})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\terr = redis.GroupList().LTrim(ctx, k1, 5, 10)\n\t\tt.AssertNil(err)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(r2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\terr = redis.GroupList().LTrim(ctx, k1, -3, -2)\n\t\tt.AssertNil(err)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v3, v2})\n\t})\n}\n\nfunc Test_GroupList_BLPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().BLPop(ctx, 1, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{k1, v4})\n\t})\n}\n\nfunc Test_GroupList_BRPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().BRPop(ctx, 1, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, []string{k1, v1})\n\t})\n}\n\nfunc Test_GroupList_RPopLPush(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().RPopLPush(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v1)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v4, v3, v2})\n\n\t\tr3, err := redis.GroupList().LRange(ctx, k2, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r3, []string{v1})\n\t})\n}\n\nfunc Test_GroupList_BRPopLPush(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t\tv3 = \"v3\"\n\t\t\tv4 = \"v4\"\n\t\t)\n\t\t_, err := redis.GroupList().LPush(ctx, k1, v1, v2, v3, v4)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupList().BRPopLPush(ctx, k1, k2, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, v1)\n\n\t\tr2, err := redis.GroupList().LRange(ctx, k1, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2, []string{v4, v3, v2})\n\n\t\tr3, err := redis.GroupList().LRange(ctx, k2, 0, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r3, []string{v1})\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_pubsub_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GroupPubSub_Publish(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, subs, err := redis.Subscribe(ctx, \"gf\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(subs[0].Channel, \"gf\")\n\n\t\tdefer conn.Close(ctx)\n\n\t\t_, err = redis.Publish(ctx, \"gf\", \"test\")\n\t\tt.AssertNil(err)\n\n\t\tmsg, err := conn.ReceiveMessage(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(msg.Channel, \"gf\")\n\t\tt.Assert(msg.Payload, \"test\")\n\t})\n}\n\nfunc Test_GroupPubSub_Subscribe(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, subs, err := redis.Subscribe(ctx, \"aa\", \"bb\", \"gf\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(subs), 3)\n\t\tt.Assert(subs[0].Channel, \"aa\")\n\t\tt.Assert(subs[1].Channel, \"bb\")\n\t\tt.Assert(subs[2].Channel, \"gf\")\n\n\t\tdefer conn.Close(ctx)\n\n\t\t_, err = redis.Publish(ctx, \"gf\", \"test\")\n\t\tt.AssertNil(err)\n\n\t\tmsg, err := conn.ReceiveMessage(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(msg.Channel, \"gf\")\n\t\tt.Assert(msg.Payload, \"test\")\n\t})\n}\n\nfunc Test_GroupPubSub_PSubscribe(t *testing.T) {\n\tdefer redis.FlushAll(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, subs, err := redis.PSubscribe(ctx, \"aa\", \"bb\", \"g?\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(subs), 3)\n\t\tt.Assert(subs[0].Channel, \"aa\")\n\t\tt.Assert(subs[1].Channel, \"bb\")\n\t\tt.Assert(subs[2].Channel, \"g?\")\n\n\t\tdefer conn.Close(ctx)\n\n\t\t_, err = redis.Publish(ctx, \"gf\", \"test\")\n\t\tt.AssertNil(err)\n\n\t\tmsg, err := conn.ReceiveMessage(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(msg.Channel, \"gf\")\n\t\tt.Assert(msg.Payload, \"test\")\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_script_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gsha1\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GroupScript_Eval(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tscript  = `return ARGV[1]`\n\t\t\tnumKeys int64\n\t\t\tkeys    = []string{\"hello\"}\n\t\t\targs    = []any(nil)\n\t\t)\n\t\tv, err := redis.GroupScript().Eval(ctx, script, numKeys, keys, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"hello\")\n\t})\n}\n\nfunc Test_GroupScript_EvalSha(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tscript  = gsha1.Encrypt(`return ARGV[1]`)\n\t\t\tnumKeys int64\n\t\t\tkeys    = []string{\"hello\"}\n\t\t\targs    = []any(nil)\n\t\t)\n\t\tv, err := redis.GroupScript().EvalSha(ctx, script, numKeys, keys, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"hello\")\n\t})\n}\n\n// https://redis.io/docs/manual/programmability/eval-intro/\nfunc Test_GroupScript_ScriptLoad(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tscript     = \"return 'Immabe a cached script'\"\n\t\t\tscriptSha1 = gsha1.Encrypt(script)\n\t\t)\n\t\t_, err := redis.GroupScript().ScriptLoad(ctx, script)\n\t\tt.AssertNil(err)\n\n\t\tv, err := redis.GroupScript().EvalSha(ctx, scriptSha1, 0, nil, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"Immabe a cached script\")\n\t})\n}\n\nfunc Test_GroupScript_ScriptExists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tscript     = \"return 'Immabe a cached script'\"\n\t\t\tscriptSha1 = gsha1.Encrypt(script)\n\t\t\tscriptSha2 = gsha1.Encrypt(\"none\")\n\t\t)\n\t\t_, err := redis.GroupScript().ScriptLoad(ctx, script)\n\t\tt.AssertNil(err)\n\n\t\tv, err := redis.GroupScript().ScriptExists(ctx, scriptSha1, scriptSha2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, g.MapStrBool{\n\t\t\tscriptSha1: true,\n\t\t\tscriptSha2: false,\n\t\t})\n\t})\n}\n\nfunc Test_GroupScript_ScriptFlush(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tscript     = \"return 'Immabe a cached script'\"\n\t\t\tscriptSha1 = gsha1.Encrypt(script)\n\t\t\tscriptSha2 = gsha1.Encrypt(\"none\")\n\t\t)\n\t\t_, err := redis.GroupScript().ScriptLoad(ctx, script)\n\t\tt.AssertNil(err)\n\n\t\tv, err := redis.GroupScript().ScriptExists(ctx, scriptSha1, scriptSha2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, g.MapStrBool{\n\t\t\tscriptSha1: true,\n\t\t\tscriptSha2: false,\n\t\t})\n\n\t\terr = redis.GroupScript().ScriptFlush(ctx, gredis.ScriptFlushOption{SYNC: true})\n\t\tt.AssertNil(err)\n\n\t\tv, err = redis.GroupScript().ScriptExists(ctx, scriptSha1, scriptSha2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, g.MapStrBool{\n\t\t\tscriptSha1: false,\n\t\t\tscriptSha2: false,\n\t\t})\n\t})\n}\n\nfunc Test_GroupScript_ScriptKill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\terr := redis.GroupScript().ScriptKill(ctx)\n\t\tt.Assert(err.Error(), `Redis Client Do failed with arguments \"[Script Kill]\": NOTBUSY No scripts in execution right now.`)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_set_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_GroupSet_SAdd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tmembers = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\t\tnum, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members...)\n\t\tt.Assert(num, 3)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_GroupSet_SIsMember(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tmembers = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members...)\n\t\tt.AssertNil(err)\n\n\t\tnum, err := redis.GroupSet().SIsMember(ctx, k1, \"v1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(1, num)\n\t})\n}\n\nfunc Test_GroupSet_SPop(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tmembers = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members...)\n\t\tt.AssertNil(err)\n\n\t\tm1, err := redis.GroupSet().SPop(ctx, k1, 2)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(m1, []string{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_GroupSet_SRandMember(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tmembers = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members...)\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.GroupSet().SRandMember(ctx, k1, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(r, []string{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_GroupSet_SRem(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tmembers = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members...)\n\t\tt.AssertNil(err)\n\n\t\tn, err := redis.GroupSet().SRem(ctx, k1, \"v1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\t})\n}\n\nfunc Test_GroupSet_SMove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v5\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v4\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tn, err := redis.GroupSet().SMove(ctx, k1, k2, \"v2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 1)\n\n\t\tm1s, err := redis.GroupSet().SMembers(ctx, k1)\n\t\tt.Assert(2, len(m1s))\n\n\t\tm2s, err := redis.GroupSet().SMembers(ctx, k2)\n\t\tt.Assert(4, len(m2s))\n\n\t})\n}\n\nfunc Test_GroupSet_SCard(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\tn, err := redis.GroupSet().SCard(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(n, 3)\n\t})\n}\n\nfunc Test_GroupSet_SMembers(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupSet().SMembers(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(r1, []string{\"v1\", \"v2\", \"v3\"})\n\t})\n}\n\nfunc Test_GroupSet_SMIsMember(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SMIsMember(ctx, k1, \"v1\")\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_GroupSet_SInter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v3\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v4\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tn, err := redis.GroupSet().SInter(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(\"v3\", n)\n\t\tt.AssertNI(\"v4\", n)\n\n\t})\n}\n\nfunc Test_GroupSet_SInterStore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v4\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\n\t\t\tk3 = guid.S()\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v3\", members2...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SInterStore(ctx, k3, k1, k2)\n\t\tt.AssertNil(err)\n\n\t\tmember3, err := redis.GroupSet().SMembers(ctx, k3)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(\"v3\", member3)\n\t})\n}\n\nfunc Test_GroupSet_SUnion(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v5\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v3\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tunion, err := redis.GroupSet().SUnion(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(union), 5)\n\t})\n}\n\nfunc Test_GroupSet_SUnionStore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v5\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\n\t\t\tk3 = guid.S()\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v3\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tunion, err := redis.GroupSet().SUnionStore(ctx, k3, k1, k2)\n\t\tt.AssertNil(err)\n\n\t\tmember3, err := redis.GroupSet().SMembers(ctx, k3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(member3), union)\n\t})\n}\n\nfunc Test_GroupSet_SDiff(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v5\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v3\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tdiff, err := redis.GroupSet().SDiff(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(diff), 2)\n\t})\n}\n\nfunc Test_GroupSet_SDiffStore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1       = guid.S()\n\t\t\tmembers1 = []any{\n\t\t\t\t\"v2\",\n\t\t\t\t\"v3\",\n\t\t\t}\n\n\t\t\tk2       = guid.S()\n\t\t\tmembers2 = []any{\n\t\t\t\t\"v5\",\n\t\t\t\t\"v6\",\n\t\t\t}\n\n\t\t\tk3 = guid.S()\n\t\t)\n\n\t\t_, err := redis.GroupSet().SAdd(ctx, k1, \"v1\", members1...)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSet().SAdd(ctx, k2, \"v3\", members2...)\n\t\tt.AssertNil(err)\n\n\t\tdiffStore, err := redis.GroupSet().SDiffStore(ctx, k3, k1, k2)\n\t\tt.AssertNil(err)\n\n\t\tmembers3, err := redis.GroupSet().SMembers(ctx, k3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(members3), diffStore)\n\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_sorted_set_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_GroupSortedSet_ZADD(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tmaxn int = 100000000\n\t\t\tk1       = guid.S()\n\t\t\tk1m1     = guid.S()\n\t\t\tk1m2     = guid.S()\n\n\t\t\toption  gredis.ZAddOption\n\t\t\tmember1 gredis.ZAddMember\n\t\t\tmember2 gredis.ZAddMember\n\t\t)\n\n\t\tmember1 = gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k1m1,\n\t\t}\n\n\t\t_, err := redis.GroupSortedSet().ZAdd(ctx, k1, &option, member1)\n\t\tt.AssertNil(err)\n\n\t\tmember2 = gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(1000000)),\n\t\t\tMember: k1m2,\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, &option, member2)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSortedSet().ZScore(ctx, k1, k1m1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupSortedSet().ZScore(ctx, k1, k1m2)\n\t\tt.AssertNil(err)\n\n\t\tvar (\n\t\t\tk2   string = guid.S()\n\t\t\tk2m1 string = guid.S()\n\t\t\tk2m2 string = guid.S()\n\t\t\tk2m3 int    = grand.Intn(maxn)\n\t\t)\n\n\t\tmember3 := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k2m1,\n\t\t}\n\n\t\tmember4 := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k2m2,\n\t\t}\n\n\t\tmember5 := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k2m3,\n\t\t}\n\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k2, &option, member3, member4, member5)\n\t})\n\n\t// with option\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tmaxn int = 100000000\n\t\t\tk1       = guid.S()\n\t\t\tk1m1     = guid.S()\n\t\t)\n\n\t\tmember1 := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k1m1,\n\t\t}\n\n\t\toption := gredis.ZAddOption{}\n\t\t_, err := redis.GroupSortedSet().ZAdd(ctx, k1, &option, member1)\n\t\tt.AssertNil(err)\n\n\t\t// option XX\n\t\toptionXX := &gredis.ZAddOption{\n\t\t\tXX: true,\n\t\t}\n\t\tmemberXX := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: k1m1,\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionXX, memberXX)\n\t\tt.AssertNil(err)\n\n\t\tscoreXX, err := redis.GroupSortedSet().ZScore(ctx, k1, memberXX.Member)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(scoreXX, memberXX.Score)\n\n\t\t// option NX\n\t\toptionNX := &gredis.ZAddOption{\n\t\t\tNX: true,\n\t\t}\n\t\tmemberNX := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: guid.S(),\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionNX, memberNX)\n\t\tt.AssertNil(err)\n\n\t\tscoreNXOrigin := memberNX.Score\n\t\tmemberNX.Score = float64(grand.Intn(maxn))\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionNX, memberNX)\n\t\tt.AssertNil(err)\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k1, memberNX.Member)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, scoreNXOrigin)\n\n\t\t// option LT\n\t\toptionLT := &gredis.ZAddOption{\n\t\t\tLT: true,\n\t\t}\n\t\tmemberLT := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: guid.S(),\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionLT, memberLT)\n\t\tt.AssertNil(err)\n\n\t\tmemberLT.Score += 1\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionLT, memberLT)\n\t\tt.AssertNil(err)\n\t\tscoreLT, err := redis.GroupSortedSet().ZScore(ctx, k1, memberLT.Member)\n\t\tt.AssertLT(scoreLT, memberLT.Score)\n\n\t\tmemberLT.Score -= 3\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionLT, memberLT)\n\t\tt.AssertNil(err)\n\t\tscoreLT, err = redis.GroupSortedSet().ZScore(ctx, k1, memberLT.Member)\n\t\tt.AssertEQ(scoreLT, memberLT.Score)\n\n\t\t// option GT\n\t\toptionGT := &gredis.ZAddOption{\n\t\t\tGT: true,\n\t\t}\n\t\tmemberGT := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: guid.S(),\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionGT, memberGT)\n\t\tt.AssertNil(err)\n\n\t\tmemberLT.Score -= 1\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionGT, memberGT)\n\t\tt.AssertNil(err)\n\t\tscoreGT, err := redis.GroupSortedSet().ZScore(ctx, k1, memberLT.Member)\n\t\tt.AssertGT(scoreGT, memberLT.Score)\n\n\t\tmemberLT.Score += 3\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionGT, memberGT)\n\t\tt.AssertNil(err)\n\t\tscoreGT, err = redis.GroupSortedSet().ZScore(ctx, k1, memberGT.Member)\n\t\tt.AssertEQ(scoreGT, memberGT.Score)\n\n\t\t// option CH\n\t\toptionCH := &gredis.ZAddOption{\n\t\t\tCH: true,\n\t\t}\n\t\tmemberCH := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: guid.S(),\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionCH, memberCH)\n\t\tt.AssertNil(err)\n\n\t\tchanged, err := redis.GroupSortedSet().ZAdd(ctx, k1, optionCH, memberCH)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(changed.Val(), int64(0))\n\n\t\tmemberCH.Score += 1\n\t\tchanged, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionCH, memberCH)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(changed.Val(), int64(1))\n\n\t\tmemberCH.Member = guid.S()\n\t\tchanged, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionCH, memberCH)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(changed.Val(), int64(1))\n\n\t\t// option INCR\n\t\toptionINCR := &gredis.ZAddOption{\n\t\t\tINCR: true,\n\t\t}\n\t\tmemberINCR := gredis.ZAddMember{\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t\tMember: guid.S(),\n\t\t}\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionINCR, memberINCR)\n\t\tt.AssertNil(err)\n\n\t\tscoreIncrOrigin := memberINCR.Score\n\t\tmemberINCR.Score += 1\n\t\t_, err = redis.GroupSortedSet().ZAdd(ctx, k1, optionINCR, memberINCR)\n\t\tt.AssertNil(err)\n\n\t\tscoreINCR, err := redis.GroupSortedSet().ZScore(ctx, k1, memberINCR.Member)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(scoreINCR, memberINCR.Score+scoreIncrOrigin)\n\t})\n}\n\nfunc Test_GroupSortedSet_ZScore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk1   string = guid.S()\n\t\t\tm1   string = guid.S()\n\t\t\tmaxn int    = 1000000\n\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tmember := gredis.ZAddMember{\n\t\t\tMember: m1,\n\t\t\tScore:  float64(grand.Intn(maxn)),\n\t\t}\n\n\t\t_, err := redis.GroupSortedSet().ZAdd(ctx, k1, option, member)\n\t\tt.AssertNil(err)\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k1, m1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, member.Score)\n\n\t\tm2 := guid.S()\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k1, m2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tk2 := guid.S()\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k2, m2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\t})\n}\n\nfunc Test_GroupSortedSet_ZIncrBy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tk := guid.S()\n\t\tm := guid.S()\n\n\t\tvar incr float64 = 6\n\t\t_, err := redis.GroupSortedSet().ZIncrBy(ctx, k, incr, m)\n\t\tt.AssertNil(err)\n\n\t\tincr2 := float64(3)\n\t\tincredScore, err := redis.GroupSortedSet().ZIncrBy(ctx, k, incr2, m)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(incredScore, incr+incr2)\n\t})\n}\n\nfunc Test_GroupSortedSet_ZCard(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\trand := grand.N(10, 20)\n\t\tfor i := 1; i <= rand; i++ {\n\t\t\t_, err := redis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(i),\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\n\t\t\tcnt, err := redis.GroupSortedSet().ZCard(ctx, k)\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertEQ(cnt, int64(i))\n\t\t}\n\t})\n}\n\nfunc Test_GroupSortedSet_ZCount(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk      string             = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tmin, max := \"5\", \"378\"\n\t\tmemSlice := []int{-6, 3, 7, 9, 100, 500, 666}\n\n\t\tfor i := 0; i < len(memSlice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: memSlice[i],\n\t\t\t\tScore:  float64(memSlice[i]),\n\t\t\t})\n\t\t}\n\n\t\tcnt, err := redis.GroupSortedSet().ZCount(ctx, k, min, max)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(3))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCount(ctx, k, \"-inf\", max)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(5))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCount(ctx, k, \"-inf\", \"+inf\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(len(memSlice)))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCount(ctx, k, \"(500\", \"(567\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(0))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCount(ctx, k, \"(500\", \"+inf\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(1))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCount(ctx, k, \"(3\", \"(567\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(4))\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []string{\"one\", \"two\", \"three\"}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: slice[i],\n\t\t\t\tScore:  float64(i + 1),\n\t\t\t})\n\t\t}\n\n\t\tret, err := redis.GroupSortedSet().ZRange(ctx, k, 0, -1)\n\t\tt.AssertNil(err)\n\t\texpected := []string{\"one\", \"two\", \"three\"}\n\t\tfor i := 0; i < len(ret); i++ {\n\t\t\tt.AssertEQ(ret[i].String(), expected[i])\n\t\t}\n\n\t\tret, err = redis.GroupSortedSet().ZRange(ctx, k, 2, 3)\n\t\tt.AssertNil(err)\n\t\texpected = []string{\"three\"}\n\t\tfor i := 0; i < len(ret); i++ {\n\t\t\tt.AssertEQ(ret[i].String(), expected[i])\n\t\t}\n\n\t\t// ret, err = redis.GroupSortedSet().ZRange(ctx, k, 0, -1,\n\t\t// \tgredis.ZRangeOption{WithScores: true})\n\t\t// t.AssertNil(err)\n\t\t// expectedScore := []any{1, \"one\", 2, \"two\", 3, \"three\"}\n\t\t// for i := 0; i < len(ret); i++ {\n\t\t// \tt.AssertEQ(ret[i].String(), expectedScore[i])\n\t\t// }\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRevRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []string{\"one\", \"two\", \"three\"}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: slice[i],\n\t\t\t\tScore:  float64(i + 1),\n\t\t\t})\n\t\t}\n\n\t\tret, err := redis.GroupSortedSet().ZRevRange(ctx, k, 0, -1)\n\t\tt.AssertNil(err)\n\t\texpected := []any{\"three\", \"two\", \"one\"}\n\t\tt.AssertEQ(ret.Slice(), expected)\n\n\t\tret, err = redis.GroupSortedSet().ZRevRange(ctx, k, 0, 1)\n\t\tt.AssertNil(err)\n\t\texpected = []any{\"three\", \"two\"}\n\t\tt.AssertEQ(ret.Slice(), expected)\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRank(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trank, err := redis.ZRank(ctx, k, 0)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(0))\n\n\t\trank, err = redis.ZRank(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(3))\n\n\t\trank, err = redis.ZRank(ctx, k, 6)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(0))\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRevRank(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trank, err := redis.ZRevRank(ctx, k, 0)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(4))\n\n\t\trank, err = redis.ZRevRank(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(1))\n\n\t\trank, err = redis.ZRevRank(ctx, k, 9)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(0))\n\n\t\trank, err = redis.ZRevRank(ctx, k, 6)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rank, int64(0))\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRem(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk      = guid.S()\n\t\t\tm      = guid.S()\n\t\t\toption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tcnt, err := redis.ZRem(ctx, k, m)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(0))\n\n\t\tmember := gredis.ZAddMember{\n\t\t\tMember: m,\n\t\t\tScore:  123,\n\t\t}\n\t\tredis.ZAdd(ctx, k, option, member)\n\n\t\tcnt, err = redis.ZRem(ctx, k, m)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(1))\n\n\t\tmember2 := gredis.ZAddMember{\n\t\t\tMember: guid.S(),\n\t\t\tScore:  456,\n\t\t}\n\t\t_, err = redis.ZAdd(ctx, k, option, member, member2)\n\t\tt.AssertNil(err)\n\n\t\tcnt, err = redis.ZRem(ctx, k, m, \"non_exists\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(1))\n\n\t\t_, err = redis.ZAdd(ctx, k, option, member, member2)\n\t\tt.AssertNil(err)\n\n\t\tcnt, err = redis.ZRem(ctx, k, m, member2.Member)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(2))\n\t})\n}\n\nfunc Test_GroupSortedSet_ZRemRangeByRank(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByRank(ctx, k, 0, 2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(3))\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k, 0)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(7))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByRank(ctx, k, -3, -2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(2))\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k, 2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 4)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(9))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByRank(ctx, k, 3, -1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(2))\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 4)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(3))\n\t})\n}\nfunc Test_GroupSortedSet_ZRemRangeByScore(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByScore(ctx, k, \"(3\", \"9\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(3))\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 4)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 5)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(3))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByScore(ctx, k, \"3\", \"(9\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(3))\n\n\t\tscore, err := redis.GroupSortedSet().ZScore(ctx, k, 1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 3)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(0))\n\n\t\tscore, err = redis.GroupSortedSet().ZScore(ctx, k, 4)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(score, float64(9))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByScore(ctx, k, \"-inf\", \"9\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(5))\n\n\t\tcnt, err := redis.GroupSortedSet().ZCard(ctx, k)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(0))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []int64{1, 3, 5, 7, 9}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: i,\n\t\t\t\tScore:  float64(slice[i]),\n\t\t\t})\n\t\t}\n\n\t\trmd, err := redis.GroupSortedSet().ZRemRangeByScore(ctx, k, \"-inf\", \"+inf\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(rmd, int64(5))\n\n\t\tcnt, err := redis.GroupSortedSet().ZCard(ctx, k)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(0))\n\t})\n}\nfunc Test_GroupSortedSet_ZRemRangeByLex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []string{\"aaaa\", \"b\", \"c\", \"d\", \"e\", \"foo\", \"zap\", \"zip\", \"ALPHA\", \"alpha\"}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: slice[i],\n\t\t\t\tScore:  float64(0),\n\t\t\t})\n\t\t}\n\n\t\tcnt, err := redis.GroupSortedSet().ZRemRangeByLex(ctx, k, \"[alpha\", \"[omega\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(6))\n\n\t\tcnt, err = redis.GroupSortedSet().ZCard(ctx, k)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(4))\n\t})\n}\nfunc Test_GroupSortedSet_ZLexCount(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\n\t\tvar (\n\t\t\tk                         = guid.S()\n\t\t\toption *gredis.ZAddOption = new(gredis.ZAddOption)\n\t\t)\n\n\t\tslice := []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"}\n\t\tfor i := 0; i < len(slice); i++ {\n\t\t\tredis.GroupSortedSet().ZAdd(ctx, k, option, gredis.ZAddMember{\n\t\t\t\tMember: slice[i],\n\t\t\t\tScore:  float64(0),\n\t\t\t})\n\t\t}\n\n\t\tcnt, err := redis.GroupSortedSet().ZLexCount(ctx, k, \"-\", \"+\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(7))\n\n\t\tcnt, err = redis.GroupSortedSet().ZLexCount(ctx, k, \"[b\", \"[f\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(cnt, int64(5))\n\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_group_string_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_GroupString_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.GroupString().Set(ctx, k2, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\t\tr2, err := redis.GroupString().Get(ctx, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v2)\n\t})\n\t// With Option.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupString().Set(ctx, k1, v2, gredis.SetOption{\n\t\t\tNX: true,\n\t\t\tTTLOption: gredis.TTLOption{\n\t\t\t\tEX: gconv.PtrInt64(60),\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\t_, err = redis.GroupString().Set(ctx, k1, v2, gredis.SetOption{\n\t\t\tXX: true,\n\t\t\tTTLOption: gredis.TTLOption{\n\t\t\t\tEX: gconv.PtrInt64(60),\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v2)\n\t})\n}\n\nfunc Test_GroupString_SetNX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.GroupString().SetNX(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\t})\n}\n\nfunc Test_GroupString_SetEX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t)\n\t\terr := redis.GroupString().SetEX(ctx, k1, v1, 1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\ttime.Sleep(time.Second * 2)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), \"\")\n\t})\n}\n\nfunc Test_GroupString_GetDel(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().GetDel(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), \"\")\n\t})\n}\n\nfunc Test_GroupString_GetEX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t)\n\t\terr := redis.GroupString().SetEX(ctx, k1, v1, 1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().GetEX(ctx, k1, gredis.GetEXOption{\n\t\t\tPersist: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\ttime.Sleep(2 * time.Second)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v1)\n\t})\n}\n\nfunc Test_GroupString_GetSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tk2 = \"k2\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\tr2, err := redis.GroupString().GetSet(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v1)\n\n\t\tr3, err := redis.GroupString().GetSet(ctx, k2, v2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r3.String(), \"\")\n\n\t\tr4, err := redis.GroupString().GetSet(ctx, k2, v2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r4.String(), v2)\n\t})\n}\n\nfunc Test_GroupString_StrLen(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().StrLen(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 2)\n\t})\n}\n\nfunc Test_GroupString_Append(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Append(ctx, k1, v2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, len(v1+v2))\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v1+v2)\n\t})\n}\n\nfunc Test_GroupString_SetRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"v1\"\n\t\t\tv2 = \"v2\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().SetRange(ctx, k1, 2, v2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, len(v1+v2))\n\n\t\tr2, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v1+v2)\n\t})\n}\n\nfunc Test_GroupString_GetRange(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = \"hello gf\"\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().GetRange(ctx, k1, 6, 8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, \"gf\")\n\t})\n}\n\nfunc Test_GroupString_Incr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = 1\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Incr(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 2)\n\t})\n}\n\nfunc Test_GroupString_IncrBy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = 1\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().IncrBy(ctx, k1, 10)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 11)\n\t})\n}\n\nfunc Test_GroupString_IncrByFloat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = 1\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().IncrByFloat(ctx, k1, 1.01)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 2.01)\n\t})\n}\n\nfunc Test_GroupString_Decr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = 10\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Decr(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 9)\n\t})\n}\n\nfunc Test_GroupString_DecrBy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = \"k1\"\n\t\t\tv1 = 10\n\t\t)\n\t\t_, err := redis.GroupString().Set(ctx, k1, v1)\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().DecrBy(ctx, k1, 3)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1, 7)\n\t})\n}\n\nfunc Test_GroupString_MSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\terr := redis.GroupString().MSet(ctx, map[string]any{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), v2)\n\t})\n}\n\nfunc Test_GroupString_MSetNX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\tok, err := redis.GroupString().MSetNX(ctx, map[string]any{\n\t\t\tk1: v1,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tok, err = redis.GroupString().MSetNX(ctx, map[string]any{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\n\t\tr1, err := redis.GroupString().Get(ctx, k1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r1.String(), v1)\n\n\t\tr2, err := redis.GroupString().Get(ctx, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r2.String(), \"\")\n\t})\n}\n\nfunc Test_GroupString_MGet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer redis.FlushDB(ctx)\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\terr := redis.GroupString().MSet(ctx, map[string]any{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tr1, err := redis.GroupString().MGet(ctx, k1, k2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r1), 2)\n\t\tt.Assert(r1[k1].String(), v1)\n\t\tt.Assert(r1[k2].String(), v2)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ConfigFromMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gredis.ConfigFromMap(g.Map{\n\t\t\t`address`:     `127.0.0.1:6379`,\n\t\t\t`db`:          `10`,\n\t\t\t`pass`:        `&*^%$#65Gv`,\n\t\t\t`minIdle`:     `10`,\n\t\t\t`MaxIdle`:     `100`,\n\t\t\t`ReadTimeout`: `10s`,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(c.Address, `127.0.0.1:6379`)\n\t\tt.Assert(c.Db, `10`)\n\t\tt.Assert(c.Pass, `&*^%$#65Gv`)\n\t\tt.Assert(c.MinIdle, 10)\n\t\tt.Assert(c.MaxIdle, 100)\n\t\tt.Assert(c.ReadTimeout, 10*time.Second)\n\t})\n}\n\nfunc Test_ConfigAddUser(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tc   *gredis.Redis\n\t\t\terr error\n\t\t\tr   *gvar.Var\n\t\t)\n\n\t\tc, err = gredis.New(&gredis.Config{\n\t\t\tAddress: `127.0.0.1`,\n\t\t\tDb:      1,\n\t\t\tUser:    \"root\",\n\t\t\tPass:    \"\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t_, err = c.Conn(ctx)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\n\t\tr, err = redis.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, []byte(\"v\"))\n\n\t\t_, err = redis.Do(ctx, \"DEL\", \"k\")\n\t\tt.AssertNil(err)\n\n\t\tr, err = redis.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_conn_sentinel_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tsentinelCtx    = context.TODO()\n\tsentinelConfig = &gredis.Config{\n\t\tAddress:    `127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381`,\n\t\tMasterName: `mymaster`,\n\t\tPass:       \"111111\",\n\t}\n)\n\nfunc TestConn_sentinel_master(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsentinelConfig.SlaveOnly = false\n\t\tredis, err := gredis.New(sentinelConfig)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(sentinelCtx)\n\n\t\tconn, err := redis.Conn(sentinelCtx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(sentinelCtx)\n\n\t\t_, err = conn.Do(sentinelCtx, \"set\", \"test\", \"123\")\n\t\tt.AssertNil(err)\n\t\tdefer conn.Do(sentinelCtx, \"del\", \"test\")\n\n\t\tr, err := conn.Do(sentinelCtx, \"get\", \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.String(), \"123\")\n\t})\n}\n\nfunc TestConn_sentinel_slave(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsentinelConfig.SlaveOnly = true\n\t\tredis, err := gredis.New(sentinelConfig)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(sentinelCtx)\n\n\t\tconn, err := redis.Conn(sentinelCtx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(sentinelCtx)\n\n\t\t_, err = conn.Do(sentinelCtx, \"set\", \"test\", \"123\")\n\t\tt.AssertNQ(err, nil)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_conn_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestConn_DoWithTimeout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := redis.Conn(ctx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(ctx)\n\n\t\t_, err = conn.Do(ctx, \"set\", \"test\", \"123\")\n\t\tt.AssertNil(err)\n\t\tdefer conn.Do(ctx, \"del\", \"test\")\n\n\t\tr, err := conn.Do(ctx, \"get\", \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.String(), \"123\")\n\t})\n}\n\nfunc TestConn_ReceiveVarWithTimeout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := redis.Conn(ctx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(ctx)\n\n\t\tsub, err := conn.Subscribe(ctx, \"gf\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(sub[0].Channel, \"gf\")\n\n\t\t_, err = redis.Publish(ctx, \"gf\", \"test\")\n\t\tt.AssertNil(err)\n\n\t\tmsg, err := conn.ReceiveMessage(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(msg.Channel, \"gf\")\n\t\tt.Assert(msg.Payload, \"test\")\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_gcache_adapter_test.go",
    "content": "// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tcacheRedis  = gcache.New()\n\tredisConfig = &gredis.Config{\n\t\tAddress: \"127.0.0.1:6379\",\n\t\tDb:      2,\n\t}\n)\n\nfunc init() {\n\tredis, err := gredis.New(redisConfig)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tcacheRedis.SetAdapter(gcache.NewAdapterRedis(redis))\n}\n\nfunc Test_AdapterRedis_Basic1(t *testing.T) {\n\t// Set\n\tsize := 10\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < size; i++ {\n\t\t\tt.AssertNil(cacheRedis.Set(ctx, i, i*10, 0))\n\t\t}\n\t\tfor i := 0; i < size; i++ {\n\t\t\tv, _ := cacheRedis.Get(ctx, i)\n\t\t\tt.Assert(v, i*10)\n\t\t}\n\t\tn, _ := cacheRedis.Size(ctx)\n\t\tt.Assert(n, size)\n\t})\n\t// Data\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata, _ := cacheRedis.Data(ctx)\n\t\tt.Assert(len(data), size)\n\t\tt.Assert(data[\"0\"], \"0\")\n\t\tt.Assert(data[\"1\"], \"10\")\n\t\tt.Assert(data[\"9\"], \"90\")\n\t})\n\t// Clear\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.Clear(ctx))\n\t\tn, _ := cacheRedis.Size(ctx)\n\t\tt.Assert(n, 0)\n\t})\n\t// Close\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.Close(ctx))\n\t})\n}\n\nfunc Test_AdapterRedis_Basic2(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tsize := 10\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < size; i++ {\n\t\t\tt.AssertNil(cacheRedis.Set(ctx, i, i*10, -1))\n\t\t}\n\t\tfor i := 0; i < size; i++ {\n\t\t\tv, _ := cacheRedis.Get(ctx, i)\n\t\t\tt.Assert(v, nil)\n\t\t}\n\t\tn, _ := cacheRedis.Size(ctx)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_AdapterRedis_Basic3(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tsize := 10\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < size; i++ {\n\t\t\tt.AssertNil(cacheRedis.Set(ctx, i, i*10, time.Second))\n\t\t}\n\t\tfor i := 0; i < size; i++ {\n\t\t\tv, _ := cacheRedis.Get(ctx, i)\n\t\t\tt.Assert(v, i*10)\n\t\t}\n\t\tn, _ := cacheRedis.Size(ctx)\n\t\tt.Assert(n, size)\n\t})\n\ttime.Sleep(time.Second * 2)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < size; i++ {\n\t\t\tv, _ := cacheRedis.Get(ctx, i)\n\t\t\tt.Assert(v, nil)\n\t\t}\n\t\tn, _ := cacheRedis.Size(ctx)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc Test_AdapterRedis_Update(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"value1\"\n\t\t\tvalue2 = \"value2\"\n\t\t)\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value1, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value1)\n\n\t\td, _ := cacheRedis.GetExpire(ctx, key)\n\t\tt.Assert(d > time.Millisecond*500, true)\n\t\tt.Assert(d <= time.Second, true)\n\n\t\t_, _, err := cacheRedis.Update(ctx, key, value2)\n\t\tt.AssertNil(err)\n\n\t\tv, _ = cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value2)\n\t\td, _ = cacheRedis.GetExpire(ctx, key)\n\t\tt.Assert(d > time.Millisecond*500, true)\n\t\tt.Assert(d <= time.Second, true)\n\t})\n}\n\nfunc Test_AdapterRedis_UpdateExpire(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey   = \"key\"\n\t\t\tvalue = \"value\"\n\t\t)\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value)\n\n\t\td, _ := cacheRedis.GetExpire(ctx, key)\n\t\tt.Assert(d > time.Millisecond*500, true)\n\t\tt.Assert(d <= time.Second, true)\n\n\t\t_, err := cacheRedis.UpdateExpire(ctx, key, time.Second*2)\n\t\tt.AssertNil(err)\n\n\t\td, _ = cacheRedis.GetExpire(ctx, key)\n\t\tt.Assert(d > time.Second, true)\n\t\tt.Assert(d <= 2*time.Second, true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey   = \"key\"\n\t\t\tvalue = \"value\"\n\t\t)\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value)\n\n\t\t_, err := cacheRedis.UpdateExpire(ctx, key, -1)\n\t\tt.AssertNil(err)\n\t\tv, _ = cacheRedis.Get(ctx, key)\n\t\tt.AssertNil(v)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey   = \"key\"\n\t\t\tvalue = \"value\"\n\t\t)\n\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value)\n\n\t\t_, err := cacheRedis.UpdateExpire(ctx, key, 0)\n\t\tt.AssertNil(err)\n\t\tv, _ = cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value)\n\t})\n}\n\nfunc Test_AdapterRedis_SetIfNotExist(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"value1\"\n\t\t\tvalue2 = \"value2\"\n\t\t)\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value1, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value1)\n\n\t\tr, _ := cacheRedis.SetIfNotExist(ctx, key, value2, time.Second*2)\n\n\t\tt.Assert(r, false)\n\n\t\tv, _ = cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value1)\n\n\t\td, _ := cacheRedis.GetExpire(ctx, key)\n\t\tt.Assert(d > time.Millisecond*500, true)\n\t\tt.Assert(d <= time.Second, true)\n\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"value1\"\n\t\t\tkey2   = \"key2\"\n\t\t\tvalue2 = \"value2\"\n\t\t)\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value1, time.Second))\n\t\tv, _ := cacheRedis.Get(ctx, key)\n\t\tt.Assert(v, value1)\n\n\t\tr, _ := cacheRedis.SetIfNotExist(ctx, key, value1, -1)\n\t\tt.Assert(r, true)\n\t\tv, _ = cacheRedis.Get(ctx, key)\n\t\tt.AssertNil(v)\n\n\t\tr, _ = cacheRedis.SetIfNotExist(ctx, key, value2, -1)\n\t\tt.Assert(r, false)\n\n\t\tr, _ = cacheRedis.SetIfNotExist(ctx, key2, value2, time.Second)\n\t\tt.Assert(r, true)\n\t})\n}\n\nfunc Test_AdapterRedis_SetIfNotExistFunc(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := cacheRedis.SetIfNotExistFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, true)\n\t})\n}\n\nfunc Test_AdapterRedis_SetIfNotExistFuncLock(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\texist, err := cacheRedis.SetIfNotExistFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, true)\n\t})\n}\n\nfunc Test_AdapterRedis_GetOrSet(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"valueFunc\"\n\t\t)\n\t\tv, err := cacheRedis.GetOrSet(ctx, key, value1, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, value1)\n\n\t\tv, err = cacheRedis.GetOrSet(ctx, key, value1, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, value1)\n\t})\n}\n\nfunc Test_AdapterRedis_GetOrSetFunc(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"valueFunc\"\n\t\t)\n\t\tv, err := cacheRedis.GetOrSetFunc(ctx, key, func(ctx context.Context) (value any, err error) {\n\t\t\tvalue = value1\n\t\t\treturn\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, value1)\n\n\t\tv, err = cacheRedis.GetOrSetFunc(ctx, key, func(ctx context.Context) (value any, err error) {\n\t\t\tvalue = value1\n\t\t\treturn\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, value1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey = \"key1\"\n\t\t)\n\t\tv, err := cacheRedis.GetOrSetFunc(ctx, key, func(ctx context.Context) (any, error) {\n\t\t\treturn nil, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc Test_AdapterRedis_GetOrSetFuncLock(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey    = \"key\"\n\t\t\tvalue1 = \"valueFuncLock\"\n\t\t)\n\t\tv, err := cacheRedis.GetOrSetFuncLock(ctx, key, func(ctx context.Context) (value any, err error) {\n\t\t\tvalue = value1\n\t\t\treturn\n\t\t}, time.Second*60)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, value1)\n\t})\n}\n\nfunc Test_AdapterRedis_SetMap(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.SetMap(ctx, g.MapAnyAny{}, 0))\n\n\t\tt.AssertNil(cacheRedis.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, 0))\n\t\tv, _ := cacheRedis.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tt.AssertNil(cacheRedis.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, -1))\n\t\tv, _ = cacheRedis.Get(ctx, 1)\n\t\tt.AssertNil(v)\n\t})\n}\n\nfunc Test_AdapterRedis_Contains(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.Set(ctx, \"key\", \"value\", 0))\n\n\t\tresult, err := cacheRedis.Contains(ctx, \"key\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, true)\n\n\t\tresult, err = cacheRedis.Contains(ctx, \"key1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, false)\n\t})\n}\n\nfunc Test_AdapterRedis_Keys(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.Set(ctx, \"key1\", \"value1\", 0))\n\n\t\tkeys, err := cacheRedis.Keys(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(keys), 1)\n\n\t\tt.AssertNil(cacheRedis.Set(ctx, \"key2\", \"value2\", 0))\n\n\t\tkeys, err = cacheRedis.Keys(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(keys), 2)\n\t})\n}\n\nfunc Test_AdapterRedis_Values(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(cacheRedis.Set(ctx, \"key1\", \"value1\", 0))\n\n\t\tvalues, err := cacheRedis.Values(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(values), 1)\n\n\t\tt.AssertNil(cacheRedis.Set(ctx, \"key2\", \"value2\", 0))\n\n\t\tvalues, err = cacheRedis.Values(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(values), 2)\n\t})\n}\n\nfunc Test_AdapterRedis_Remove(t *testing.T) {\n\tdefer cacheRedis.Clear(ctx)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey   = \"key\"\n\t\t\tvalue = \"value\"\n\t\t)\n\t\tval, err := cacheRedis.Remove(ctx)\n\t\tt.AssertNil(val)\n\t\tt.AssertNil(err)\n\n\t\tt.AssertNil(cacheRedis.Set(ctx, key, value, 0))\n\n\t\tval, err = cacheRedis.Remove(ctx, key)\n\t\tt.Assert(val, value)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_gins_redis_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GINS_Redis(t *testing.T) {\n\tredisContent := gfile.GetContents(\n\t\tgtest.DataPath(\"redis\", \"config.toml\"),\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"config.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), redisContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\n\t\t// for gfsnotify callbacks to refresh cache of config file\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\t// fmt.Println(\"gins Test_Redis\", Config().Get(\"test\"))\n\n\t\tvar (\n\t\t\tredisDefault = gins.Redis()\n\t\t\tredisCache   = gins.Redis(\"cache\")\n\t\t\tredisDisk    = gins.Redis(\"disk\")\n\t\t)\n\t\tt.AssertNE(redisDefault, nil)\n\t\tt.AssertNE(redisCache, nil)\n\t\tt.AssertNE(redisDisk, nil)\n\n\t\tr, err := redisDefault.Do(ctx, \"PING\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, \"PONG\")\n\n\t\tr, err = redisCache.Do(ctx, \"PING\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, \"PONG\")\n\n\t\t_, err = redisDisk.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\t\tr, err = redisDisk.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, []byte(\"v\"))\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/redis_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage redis_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\tgoredis \"github.com/redis/go-redis/v9\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_NewClose(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\n\t\terr = redis.Close(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Client(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\n\t\t// Test getting the client\n\t\tclient := redis.Client()\n\t\tt.AssertNE(client, nil)\n\n\t\t// Test type assertion to goredis.UniversalClient\n\t\tuniversalClient, ok := client.(goredis.UniversalClient)\n\t\tt.Assert(ok, true)\n\t\tt.AssertNE(universalClient, nil)\n\n\t\t// Test that we can use the client directly for redis operations\n\t\t// This demonstrates that the returned client is properly configured\n\t\tresult := universalClient.Set(ctx, \"test-client-key\", \"test-value\", 0)\n\t\tt.AssertNil(result.Err())\n\n\t\tgetResult := universalClient.Get(ctx, \"test-client-key\")\n\t\tt.AssertNil(getResult.Err())\n\t\tt.Assert(getResult.Val(), \"test-value\")\n\n\t\t// Clean up\n\t\tdelResult := universalClient.Del(ctx, \"test-client-key\")\n\t\tt.AssertNil(delResult.Err())\n\n\t\t// Test Pipeline functionality\n\t\tpipe := universalClient.Pipeline()\n\t\tt.AssertNE(pipe, nil)\n\n\t\t// Add multiple commands to the pipeline\n\t\tpipe.Set(ctx, \"pipeline-key1\", \"value1\", 0)\n\t\tpipe.Set(ctx, \"pipeline-key2\", \"value2\", 0)\n\t\tpipe.Set(ctx, \"pipeline-key3\", \"value3\", 0)\n\t\tpipe.Get(ctx, \"pipeline-key1\")\n\t\tpipe.Get(ctx, \"pipeline-key2\")\n\t\tpipe.Get(ctx, \"pipeline-key3\")\n\n\t\t// Execute the pipeline\n\t\tresults, err := pipe.Exec(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(results), 6) // 3 SET commands + 3 GET commands\n\n\t\t// Verify the SET results\n\t\tfor i := range 3 {\n\t\t\tt.AssertNil(results[i].Err())\n\t\t}\n\n\t\t// Verify the GET results\n\t\tgetResults := results[3:]\n\t\tt.Assert(getResults[0].(*goredis.StringCmd).Val(), \"value1\")\n\t\tt.Assert(getResults[1].(*goredis.StringCmd).Val(), \"value2\")\n\t\tt.Assert(getResults[2].(*goredis.StringCmd).Val(), \"value3\")\n\n\t\t// Clean up pipeline test keys\n\t\tcleanupPipe := universalClient.Pipeline()\n\t\tcleanupPipe.Del(ctx, \"pipeline-key1\")\n\t\tcleanupPipe.Del(ctx, \"pipeline-key2\")\n\t\tcleanupPipe.Del(ctx, \"pipeline-key3\")\n\t\t_, err = cleanupPipe.Exec(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Do(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := redis.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, []byte(\"v\"))\n\n\t\t_, err = redis.Do(ctx, \"DEL\", \"k\")\n\t\tt.AssertNil(err)\n\t\tr, err = redis.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, nil)\n\t})\n}\n\nfunc Test_Conn(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := redis.Conn(ctx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(ctx)\n\n\t\tkey := gconv.String(gtime.TimestampNano())\n\t\tvalue := []byte(\"v\")\n\t\tr, err := conn.Do(ctx, \"SET\", key, value)\n\t\tt.AssertNil(err)\n\n\t\tr, err = conn.Do(ctx, \"GET\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, value)\n\n\t\t_, err = conn.Do(ctx, \"DEL\", key)\n\t\tt.AssertNil(err)\n\t\tr, err = conn.Do(ctx, \"GET\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, nil)\n\t})\n}\n\nfunc Test_Instance(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgroup := \"my-test\"\n\t\tgredis.SetConfig(config, group)\n\t\tdefer gredis.RemoveConfig(group)\n\n\t\tredis := gredis.Instance(group)\n\t\tdefer redis.Close(ctx)\n\n\t\tconn, err := redis.Conn(ctx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(ctx)\n\n\t\t_, err = conn.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\n\t\tr, err := conn.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, []byte(\"v\"))\n\n\t\t_, err = conn.Do(ctx, \"DEL\", \"k\")\n\t\tt.AssertNil(err)\n\t\tr, err = conn.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, nil)\n\t})\n}\n\nfunc Test_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig1 := &gredis.Config{\n\t\t\tAddress:     \"192.111.0.2:6379\",\n\t\t\tDb:          1,\n\t\t\tDialTimeout: time.Second,\n\t\t}\n\t\tr, err := gredis.New(config1)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(r, nil)\n\t\tdefer r.Close(ctx)\n\n\t\t_, err = r.Do(ctx, \"info\")\n\t\tt.AssertNE(err, nil)\n\n\t\tconfig1 = &gredis.Config{\n\t\t\tAddress: \"127.0.0.1:6379\",\n\t\t\tDb:      100,\n\t\t}\n\t\tr, err = gredis.New(config1)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(r, nil)\n\t\tdefer r.Close(ctx)\n\n\t\t_, err = r.Do(ctx, \"info\")\n\t\tt.AssertNE(err, nil)\n\n\t\tr = gredis.Instance(\"gf\")\n\t\tt.Assert(r == nil, true)\n\t\tgredis.ClearConfig()\n\n\t\tr, err = gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(r, nil)\n\t\tdefer r.Close(ctx)\n\n\t\t_, err = r.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\n\t\tv, err := r.Do(ctx, \"GET\", \"k\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.String(), \"v\")\n\n\t\tconn, err := r.Conn(ctx)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close(ctx)\n\t\t_, err = conn.Do(ctx, \"SET\", \"k\", \"v\")\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Bool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tredis.Do(ctx, \"DEL\", \"key-true\")\n\t\t\tredis.Do(ctx, \"DEL\", \"key-false\")\n\t\t}()\n\n\t\t_, err := redis.Do(ctx, \"SET\", \"key-true\", true)\n\t\tt.AssertNil(err)\n\n\t\t_, err = redis.Do(ctx, \"SET\", \"key-false\", false)\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"GET\", \"key-true\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Bool(), true)\n\n\t\tr, err = redis.Do(ctx, \"GET\", \"key-false\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Bool(), false)\n\t})\n}\n\nfunc Test_Int(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\n\t\tkey := guid.S()\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"SET\", key, 1)\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"GET\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Int(), 1)\n\t})\n}\n\nfunc Test_HSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\n\t\tkey := guid.S()\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"HSET\", key, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"HGETALL\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.MapStrStr(), g.MapStrStr{\"name\": \"john\"})\n\t})\n}\n\nfunc Test_HGetAll1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey = guid.S()\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"HSET\", key, \"id\", 100)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.Do(ctx, \"HSET\", key, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"HGETALL\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Map(), g.MapStrAny{\n\t\t\t\"id\":   100,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t})\n}\n\nfunc Test_HGetAll2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey = guid.S()\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"HSET\", key, \"id\", 100)\n\t\tt.AssertNil(err)\n\t\t_, err = redis.Do(ctx, \"HSET\", key, \"name\", \"john\")\n\t\tt.AssertNil(err)\n\n\t\tresult, err := redis.Do(ctx, \"HGETALL\", key)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gconv.Uint(result.MapStrVar()[\"id\"]), 100)\n\t\tt.Assert(result.MapStrVar()[\"id\"].Uint(), 100)\n\t})\n}\n\nfunc Test_HMSet(t *testing.T) {\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey  = guid.S()\n\t\t\tdata = g.Map{\n\t\t\t\t\"name\":  \"gf\",\n\t\t\t\t\"sex\":   0,\n\t\t\t\t\"score\": 100,\n\t\t\t}\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"HMSET\", append(g.Slice{key}, gutil.MapToSlice(data)...)...)\n\t\tt.AssertNil(err)\n\t\tv, err := redis.Do(ctx, \"HMGET\", key, \"name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Slice(), g.Slice{data[\"name\"]})\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName  string `json:\"name\"`\n\t\t\tSex   int    `json:\"sex\"`\n\t\t\tScore int    `json:\"score\"`\n\t\t}\n\t\tvar (\n\t\t\tkey  = guid.S()\n\t\t\tdata = &User{\n\t\t\t\tName:  \"gf\",\n\t\t\t\tSex:   0,\n\t\t\t\tScore: 100,\n\t\t\t}\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\t_, err = redis.Do(ctx, \"HMSET\", append(g.Slice{key}, gutil.StructToSlice(data)...)...)\n\t\tt.AssertNil(err)\n\t\tv, err := redis.Do(ctx, \"HMGET\", key, \"name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Slice(), g.Slice{data.Name})\n\t})\n}\n\nfunc Test_Auto_Marshal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey = guid.S()\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Close(ctx)\n\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t}\n\n\t\tuser := &User{\n\t\t\tId:   10000,\n\t\t\tName: \"john\",\n\t\t}\n\n\t\t_, err = redis.Do(ctx, \"SET\", key, user)\n\t\tt.AssertNil(err)\n\n\t\tr, err := redis.Do(ctx, \"GET\", key)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Map(), g.MapStrAny{\n\t\t\t\"Id\":   user.Id,\n\t\t\t\"Name\": user.Name,\n\t\t})\n\n\t\tvar user2 *User\n\t\tt.Assert(r.Struct(&user2), nil)\n\t\tt.Assert(user2.Id, user.Id)\n\t\tt.Assert(user2.Name, user.Name)\n\t})\n}\n\nfunc Test_Auto_MarshalSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey = \"user-slice\"\n\t\t)\n\t\tredis, err := gredis.New(config)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(redis, nil)\n\t\tdefer redis.Do(ctx, \"DEL\", key)\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t}\n\t\tvar (\n\t\t\tresult *gvar.Var\n\t\t\tusers1 = []User{\n\t\t\t\t{\n\t\t\t\t\tId:   1,\n\t\t\t\t\tName: \"john1\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tId:   2,\n\t\t\t\t\tName: \"john2\",\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\n\t\t_, err = redis.Do(ctx, \"SET\", key, users1)\n\t\tt.AssertNil(err)\n\n\t\tresult, err = redis.Do(ctx, \"GET\", key)\n\t\tt.AssertNil(err)\n\n\t\tvar users2 []User\n\t\terr = result.Structs(&users2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users2, users1)\n\t})\n}\n"
  },
  {
    "path": "contrib/nosql/redis/testdata/redis/config.toml",
    "content": "# Template directory\nviewpath = \"/home/www/templates/\"\ntest = \"v=3\"\n# MySQL config\n[database]\n    [[database.default]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"\"\n        # pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n    [[database.test]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"\"\n        # pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n# Redis config\n[redis]\n    [redis.default]\n        address = \"127.0.0.1:6379\"\n        db      = 7\n    [redis.cache]\n        address = \"127.0.0.1:6379\"\n        db      = 8\n    [redis.disk]\n        address         = \"127.0.0.1:6379\"\n        db              = 9\n        maxIdle         = 1\n        maxActive       = 10\n        idleTimeout     = \"10s\"\n        maxConnLifetime = \"10s\"\n\n"
  },
  {
    "path": "contrib/registry/README.MD",
    "content": "# Service registrar and discovery\n\nPlease refer to certain sub folder.\n"
  },
  {
    "path": "contrib/registry/consul/README.MD",
    "content": "# GoFrame Consul Registry\n\nUse `consul` as service registration and discovery management.\n\n## Installation\n```bash\ngo get -u github.com/gogf/gf/contrib/registry/consul/v2\n```\nsuggested using `go.mod`:\n```bash\nrequire github.com/gogf/gf/contrib/registry/consul/v2 latest\n```\n\n## Example\n\n### HTTP Server\n```go\npackage main\n\nimport (\n    \"context\"\n    \n    \"github.com/gogf/gf/contrib/registry/consul/v2\"\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/ghttp\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n    registry, err := consul.New(consul.WithAddress(\"127.0.0.1:8500\"))\n    if err != nil {\n        g.Log().Fatal(context.Background(), err)\n    }\n    gsvc.SetRegistry(registry)\n\n    s := g.Server(\"hello.svc\")\n    s.BindHandler(\"/\", func(r *ghttp.Request) {\n        g.Log().Info(r.Context(), \"request received\")\n        r.Response.Write(\"Hello world\")\n    })\n    s.Run()\n}\n```\n\n### HTTP Client\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"time\"\n\n    \"github.com/gogf/gf/contrib/registry/consul/v2\"\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/gsel\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n    registry, err := consul.New(consul.WithAddress(\"127.0.0.1:8500\"))\n    if err != nil {\n        g.Log().Fatal(context.Background(), err)\n    }\n    gsvc.SetRegistry(registry)\n    gsel.SetBuilder(gsel.NewBuilderRoundRobin())\n\n    client := g.Client()\n    for i := 0; i < 100; i++ {\n        res, err := client.Get(gctx.New(), \"http://hello.svc/\")\n        if err != nil {\n            panic(err)\n        }\n        fmt.Println(res.ReadAllString())\n        res.Close()\n        time.Sleep(time.Second)\n    }\n}\n```\n\n## Configuration Options\n\nThe registry supports the following configuration options:\n\n- `WithAddress(address string)`: Sets the Consul server address (default: \"127.0.0.1:8500\")\n- `WithToken(token string)`: Sets the ACL token for Consul authentication\n\n## Features\n\n- Service registration with TTL health check\n- Service discovery with health status filtering\n- Service metadata support\n- Watch support for service changes\n- Consul ACL token support\n\n## Requirements\n\n- Go 1.18 or higher\n- Consul 1.0 or higher\n\n## License\n\n`GoFrame Consul` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n"
  },
  {
    "path": "contrib/registry/consul/consul.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package consul implements service Registry and Discovery using consul.\npackage consul\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/hashicorp/consul/api\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nconst (\n\t// DefaultTTL is the default TTL for service registration\n\tDefaultTTL = 20 * time.Second\n\n\t// DefaultHealthCheckInterval is the default interval for health check\n\tDefaultHealthCheckInterval = 10 * time.Second\n)\n\nvar (\n\t_ gsvc.Registry = (*Registry)(nil)\n)\n\n// Registry implements gsvc.Registry interface using consul.\ntype Registry struct {\n\tclient  *api.Client       // Consul client\n\taddress string            // Consul address\n\toptions map[string]string // Additional options\n\tmu      sync.RWMutex      // Mutex for thread safety\n}\n\n// Option is the configuration option type for registry.\ntype Option func(r *Registry)\n\n// WithAddress sets the address for consul client.\nfunc WithAddress(address string) Option {\n\treturn func(r *Registry) {\n\t\tr.mu.Lock()\n\t\tr.address = address\n\t\tr.mu.Unlock()\n\t}\n}\n\n// WithToken sets the ACL token for consul client.\nfunc WithToken(token string) Option {\n\treturn func(r *Registry) {\n\t\tr.mu.Lock()\n\t\tr.options[\"token\"] = token\n\t\tr.mu.Unlock()\n\t}\n}\n\n// New creates and returns a new Registry.\nfunc New(opts ...Option) (gsvc.Registry, error) {\n\tr := &Registry{\n\t\taddress: \"127.0.0.1:8500\",\n\t\toptions: make(map[string]string),\n\t}\n\n\t// Apply options\n\tfor _, opt := range opts {\n\t\topt(r)\n\t}\n\n\t// Create consul config\n\tconfig := api.DefaultConfig()\n\tr.mu.RLock()\n\tconfig.Address = r.address\n\tif token, ok := r.options[\"token\"]; ok {\n\t\tconfig.Token = token\n\t}\n\tr.mu.RUnlock()\n\n\t// Create consul client\n\tclient, err := api.NewClient(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr.client = client\n\n\treturn r, nil\n}\n\n// Register registers a service to consul.\nfunc (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Service, error) {\n\tmetadata := service.GetMetadata()\n\tif metadata == nil {\n\t\tmetadata = make(map[string]any)\n\t}\n\n\t// Convert metadata to string map\n\tmeta := make(map[string]string)\n\tif len(metadata) > 0 {\n\t\tmetadataBytes, err := json.Marshal(metadata)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrap(err, \"failed to marshal metadata\")\n\t\t}\n\t\tmeta[\"metadata\"] = string(metadataBytes)\n\t}\n\n\t// Add version to meta\n\tmeta[\"version\"] = service.GetVersion()\n\n\tendpoints := service.GetEndpoints()\n\tif len(endpoints) == 0 {\n\t\treturn nil, gerror.New(\"no endpoints found in service\")\n\t}\n\n\t// Create service ID\n\tserviceID := fmt.Sprintf(\"%s-%s-%s:%d\", service.GetName(), service.GetVersion(), endpoints[0].Host(), endpoints[0].Port())\n\n\t// Create registration\n\treg := &api.AgentServiceRegistration{\n\t\tID:      serviceID,\n\t\tName:    service.GetName(),\n\t\tTags:    []string{service.GetVersion()},\n\t\tMeta:    meta,\n\t\tAddress: endpoints[0].Host(),\n\t\tPort:    endpoints[0].Port(),\n\t}\n\n\t// Add health check\n\tcheckID := fmt.Sprintf(\"service:%s\", serviceID)\n\treg.Check = &api.AgentServiceCheck{\n\t\tCheckID:                        checkID,\n\t\tTTL:                            DefaultTTL.String(),\n\t\tDeregisterCriticalServiceAfter: \"1m\",\n\t}\n\n\t// Register service\n\tif err := r.client.Agent().ServiceRegister(reg); err != nil {\n\t\treturn nil, gerror.Wrap(err, \"failed to register service\")\n\t}\n\n\t// Start TTL health check\n\tif err := r.client.Agent().PassTTL(checkID, \"\"); err != nil {\n\t\t// Try to deregister service if health check fails\n\t\t_ = r.client.Agent().ServiceDeregister(serviceID)\n\t\treturn nil, gerror.Wrap(err, \"failed to pass TTL health check\")\n\t}\n\n\t// Start TTL health check goroutine\n\tgo r.ttlHealthCheck(serviceID)\n\n\treturn service, nil\n}\n\n// Deregister deregisters a service from consul.\nfunc (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {\n\tendpoints := service.GetEndpoints()\n\tif len(endpoints) == 0 {\n\t\treturn gerror.New(\"no endpoints found in service\")\n\t}\n\n\t// Create service ID\n\tserviceID := fmt.Sprintf(\"%s-%s-%s:%d\", service.GetName(), service.GetVersion(), endpoints[0].Host(), endpoints[0].Port())\n\n\treturn r.client.Agent().ServiceDeregister(serviceID)\n}\n\n// ttlHealthCheck maintains the TTL health check for a service\nfunc (r *Registry) ttlHealthCheck(serviceID string) {\n\tticker := time.NewTicker(DefaultHealthCheckInterval)\n\tdefer ticker.Stop()\n\n\tcheckID := fmt.Sprintf(\"service:%s\", serviceID)\n\tfor range ticker.C {\n\t\tif err := r.client.Agent().PassTTL(checkID, \"\"); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// GetAddress returns the consul address\nfunc (r *Registry) GetAddress() string {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\treturn r.address\n}\n\n// Watch creates and returns a watcher for specified service.\nfunc (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {\n\twatcher, err := newWatcher(r, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn watcher, nil\n}\n"
  },
  {
    "path": "contrib/registry/consul/consul_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consul\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/consul/api\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Search searches and returns services with specified condition.\nfunc (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {\n\t// Get services from consul\n\tservices, _, err := r.client.Health().Service(in.Name, \"\", true, &api.QueryOptions{\n\t\tWaitTime: time.Second * 3,\n\t})\n\tif err != nil {\n\t\treturn nil, gerror.Wrap(err, \"failed to get services from consul\")\n\t}\n\n\tvar result []gsvc.Service\n\tfor _, service := range services {\n\t\tif service.Checks.AggregatedStatus() != api.HealthPassing {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse metadata\n\t\tvar metadata map[string]any\n\t\tif metaStr, ok := service.Service.Meta[\"metadata\"]; ok && metaStr != \"\" {\n\t\t\tif err = json.Unmarshal([]byte(metaStr), &metadata); err != nil {\n\t\t\t\treturn nil, gerror.Wrap(err, \"failed to unmarshal service metadata\")\n\t\t\t}\n\t\t}\n\n\t\t// Skip if version doesn't match\n\t\tif in.Version != \"\" {\n\t\t\tif len(service.Service.Tags) == 0 || service.Service.Tags[0] != in.Version {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Skip if metadata doesn't match\n\t\tif len(in.Metadata) > 0 {\n\t\t\tif metadata == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmatch := true\n\t\t\tfor k, v := range in.Metadata {\n\t\t\t\tif mv, ok := metadata[k]; !ok || mv != v {\n\t\t\t\t\tmatch = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !match {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Get version from tags\n\t\tversion := \"\"\n\t\tif len(service.Service.Tags) > 0 {\n\t\t\tversion = service.Service.Tags[0]\n\t\t}\n\n\t\t// Create service instance\n\t\tlocalService := &gsvc.LocalService{\n\t\t\tHead:       \"\",\n\t\t\tDeployment: \"\",\n\t\t\tNamespace:  \"\",\n\t\t\tName:       service.Service.Service,\n\t\t\tVersion:    version,\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(fmt.Sprintf(\"%s:%d\", service.Service.Address, service.Service.Port)),\n\t\t\t},\n\t\t\tMetadata: metadata,\n\t\t}\n\t\tresult = append(result, localService)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "contrib/registry/consul/consul_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consul\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\ttestServiceName    = \"test-service\"\n\ttestServiceVersion = \"1.0.0\"\n\ttestServiceAddress = \"127.0.0.1\"\n\ttestServicePort    = 8000\n)\n\nfunc createTestService() gsvc.Service {\n\treturn &gsvc.LocalService{\n\t\tName:    testServiceName,\n\t\tVersion: testServiceVersion,\n\t\tMetadata: map[string]any{\n\t\t\t\"region\": \"cn-east-1\",\n\t\t\t\"zone\":   \"a\",\n\t\t},\n\t\tEndpoints: []gsvc.Endpoint{\n\t\t\tgsvc.NewEndpoint(fmt.Sprintf(\"%s:%d\", testServiceAddress, testServicePort)),\n\t\t},\n\t}\n}\n\nfunc Test_Registry_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create registry\n\t\tregistry, err := New()\n\t\tt.AssertNil(err)\n\t\tt.Assert(registry != nil, true)\n\n\t\t// Test invalid service\n\t\tinvalidService := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: testServiceVersion,\n\t\t}\n\t\t_, err = registry.Register(context.Background(), invalidService)\n\t\tt.AssertNE(err, nil) // Should fail due to no endpoints\n\n\t\t// Create service with invalid metadata\n\t\tserviceWithInvalidMeta := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: testServiceVersion,\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"invalid\": make(chan int), // This will fail JSON marshaling\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(fmt.Sprintf(\"%s:%d\", testServiceAddress, testServicePort)),\n\t\t\t},\n\t\t}\n\t\t_, err = registry.Register(context.Background(), serviceWithInvalidMeta)\n\t\tt.AssertNE(err, nil) // Should fail due to invalid metadata\n\n\t\t// Create service\n\t\tservice := createTestService()\n\n\t\t// Register service\n\t\tctx := context.Background()\n\t\tregisteredService, err := registry.Register(ctx, service)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registeredService != nil, true)\n\n\t\t// Wait for service to be registered\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Search service\n\t\tservices, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: testServiceVersion,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 1)\n\n\t\t// Test service properties\n\t\tfoundService := services[0]\n\t\tt.Assert(foundService.GetName(), testServiceName)\n\t\tt.Assert(foundService.GetVersion(), testServiceVersion)\n\t\tt.Assert(len(foundService.GetEndpoints()), 1)\n\n\t\tendpoint := foundService.GetEndpoints()[0]\n\t\tt.Assert(endpoint.Host(), testServiceAddress)\n\t\tt.Assert(endpoint.Port(), testServicePort)\n\n\t\tmetadata := foundService.GetMetadata()\n\t\tt.Assert(metadata != nil, true)\n\t\tt.Assert(metadata[\"region\"], \"cn-east-1\")\n\t\tt.Assert(metadata[\"zone\"], \"a\")\n\n\t\t// Search with invalid metadata\n\t\tservicesWithInvalidMeta, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:     testServiceName,\n\t\t\tVersion:  testServiceVersion,\n\t\t\tMetadata: map[string]any{\"nonexistent\": \"value\"},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(servicesWithInvalidMeta), 0)\n\n\t\t// Test deregister with invalid service\n\t\terr = registry.Deregister(ctx, invalidService)\n\t\tt.AssertNE(err, nil) // Should fail due to no endpoints\n\n\t\t// Deregister service\n\t\terr = registry.Deregister(ctx, service)\n\t\tt.AssertNil(err)\n\n\t\t// Wait for service to be deregistered\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Verify service is deregistered\n\t\tderegisteredServices, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: testServiceVersion,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(deregisteredServices), 0)\n\t})\n}\n\nfunc Test_Registry_Watch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create registry\n\t\tregistry, err := New()\n\t\tt.AssertNil(err)\n\n\t\t// Create service\n\t\tservice := createTestService()\n\n\t\t// Register service first\n\t\tctx := context.Background()\n\t\t_, err = registry.Register(ctx, service)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service)\n\n\t\t// Wait for service to be registered\n\t\ttime.Sleep(time.Second)\n\n\t\t// Create watcher after service is registered\n\t\twatcher, err := registry.Watch(ctx, testServiceName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(watcher != nil, true)\n\t\tdefer watcher.Close()\n\n\t\t// Wait for initial service query\n\t\ttime.Sleep(time.Second)\n\n\t\t// Should receive initial service list\n\t\tservices, err := watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 1)\n\t\tt.Assert(services[0].GetName(), testServiceName)\n\t\tt.Assert(services[0].GetVersion(), testServiceVersion)\n\n\t\t// Test closing watcher\n\t\terr = watcher.Close()\n\t\tt.AssertNil(err)\n\n\t\t// Test watch with invalid service name\n\t\twatcher, err = registry.Watch(ctx, \"nonexistent-service\")\n\t\tt.AssertNil(err)\n\t\tdefer watcher.Close()\n\n\t\t// Wait for initial query\n\t\ttime.Sleep(time.Second)\n\n\t\t// Should receive empty service list for non-existent service\n\t\tservices, err = watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 0)\n\n\t\t// Test watch after service deregistration\n\t\twatcher, err = registry.Watch(ctx, testServiceName)\n\t\tt.AssertNil(err)\n\t\tdefer watcher.Close()\n\n\t\t// Wait for initial query\n\t\ttime.Sleep(time.Second)\n\n\t\terr = registry.Deregister(ctx, service)\n\t\tt.AssertNil(err)\n\n\t\t// Wait for service to be deregistered\n\t\ttime.Sleep(time.Second)\n\n\t\t// Should receive empty service list after deregistration\n\t\tservices, err = watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 0)\n\t})\n}\n\nfunc Test_Registry_MultipleServices(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create registry\n\t\tregistry, err := New()\n\t\tt.AssertNil(err)\n\n\t\t// Create multiple services\n\t\tservice1 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"1.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-east-1\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8001\"),\n\t\t\t},\n\t\t}\n\n\t\tservice2 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"2.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-west-1\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8002\"),\n\t\t\t},\n\t\t}\n\n\t\t// Register services\n\t\tctx := context.Background()\n\t\t_, err = registry.Register(ctx, service1)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service1)\n\n\t\t_, err = registry.Register(ctx, service2)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service2)\n\n\t\t// Wait for services to be registered\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Search all services without version filter\n\t\tallServices, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: testServiceName,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(allServices), 2)\n\n\t\t// Test search with different versions\n\t\tservices1, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"1.0.0\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services1), 1)\n\t\tt.Assert(services1[0].GetVersion(), \"1.0.0\")\n\n\t\tservices2, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"2.0.0\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services2), 1)\n\t\tt.Assert(services2[0].GetVersion(), \"2.0.0\")\n\n\t\t// Test search with metadata\n\t\tservicesEast, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: testServiceName,\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-east-1\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(servicesEast), 1)\n\t\tt.Assert(servicesEast[0].GetMetadata()[\"region\"], \"us-east-1\")\n\n\t\t// Watch both services\n\t\twatcher, err := registry.Watch(ctx, testServiceName)\n\t\tt.AssertNil(err)\n\t\tdefer watcher.Close()\n\n\t\t// Wait for initial query\n\t\ttime.Sleep(time.Second)\n\n\t\t// Should receive updates for both services\n\t\tservices, err := watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 2)\n\n\t\t// Verify services are sorted by version\n\t\tt.Assert(services[0].GetVersion() < services[1].GetVersion(), true)\n\t})\n}\n\nfunc Test_Registry_Options(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with custom address\n\t\tregistry1, err := New(WithAddress(\"localhost:8500\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(registry1.(*Registry).GetAddress(), \"localhost:8500\")\n\n\t\t// Test with token\n\t\tregistry2, err := New(WithAddress(\"localhost:8500\"), WithToken(\"test-token\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(registry2.(*Registry).options[\"token\"], \"test-token\")\n\n\t\t// Test with invalid address (should still create registry but fail on operations)\n\t\tregistry3, err := New(WithAddress(\"invalid:99999\"))\n\t\tt.AssertNil(err)\n\t\t_, err = registry3.Register(context.Background(), createTestService())\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Registry_MultipleServicesMetadataFiltering(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create registry\n\t\tregistry, err := New()\n\t\tt.AssertNil(err)\n\n\t\t// Create multiple services\n\t\tservice1 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"1.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-east-1\",\n\t\t\t\t\"env\":    \"dev\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8001\"),\n\t\t\t},\n\t\t}\n\n\t\tservice2 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"2.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-west-1\",\n\t\t\t\t\"env\":    \"prod\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8002\"),\n\t\t\t},\n\t\t}\n\n\t\t// Register services\n\t\tctx := context.Background()\n\t\t_, err = registry.Register(ctx, service1)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service1)\n\n\t\t_, err = registry.Register(ctx, service2)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service2)\n\n\t\ttime.Sleep(time.Second) // Wait for services to be registered\n\n\t\t// Test search with metadata filtering\n\t\tservicesDev, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: testServiceName,\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"env\": \"dev\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(servicesDev), 1)\n\t\tt.Assert(servicesDev[0].GetMetadata()[\"env\"], \"dev\")\n\n\t\tservicesProd, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: testServiceName,\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"env\": \"prod\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(servicesProd), 1)\n\t\tt.Assert(servicesProd[0].GetMetadata()[\"env\"], \"prod\")\n\t})\n}\n\nfunc Test_Registry_MultipleServicesVersionFiltering(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create registry\n\t\tregistry, err := New()\n\t\tt.AssertNil(err)\n\n\t\t// Create multiple services\n\t\tservice1 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"1.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-east-1\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8001\"),\n\t\t\t},\n\t\t}\n\n\t\tservice2 := &gsvc.LocalService{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"2.0.0\",\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"region\": \"us-west-1\",\n\t\t\t},\n\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\tgsvc.NewEndpoint(\"127.0.0.1:8002\"),\n\t\t\t},\n\t\t}\n\n\t\t// Register services\n\t\tctx := context.Background()\n\t\t_, err = registry.Register(ctx, service1)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service1)\n\n\t\t_, err = registry.Register(ctx, service2)\n\t\tt.AssertNil(err)\n\t\tdefer registry.Deregister(ctx, service2)\n\n\t\ttime.Sleep(time.Second) // Wait for services to be registered\n\n\t\t// Test search with version filtering\n\t\tservices, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"1.0.0\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 1)\n\t\tt.Assert(services[0].GetVersion(), \"1.0.0\")\n\n\t\tservices, err = registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName:    testServiceName,\n\t\t\tVersion: \"2.0.0\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(services), 1)\n\t\tt.Assert(services[0].GetVersion(), \"2.0.0\")\n\t})\n}\n"
  },
  {
    "path": "contrib/registry/consul/consul_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage consul\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/consul/api\"\n\t\"github.com/hashicorp/consul/api/watch\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Watcher watches the service changes.\ntype Watcher struct {\n\tregistry  *Registry      // The registry instance\n\tkey       string         // The service name to watch\n\tcloseChan chan struct{}  // Channel for closing\n\teventChan chan struct{}  // Channel for notifying changes\n\tmu        sync.RWMutex   // Mutex for thread safety\n\tplan      *watch.Plan    // The watch plan\n\tservices  []gsvc.Service // Current services\n}\n\n// New creates and returns a new watcher.\nfunc newWatcher(registry *Registry, key string) (*Watcher, error) {\n\tw := &Watcher{\n\t\tregistry:  registry,\n\t\tkey:       key,\n\t\tcloseChan: make(chan struct{}),\n\t\teventChan: make(chan struct{}, 1),\n\t}\n\n\t// Start watching\n\tgo w.watch()\n\n\treturn w, nil\n}\n\n// watch starts the watching process.\nfunc (w *Watcher) watch() {\n\t// Get initial service list\n\tinitServices, err := w.Services()\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// Set initial services\n\tw.mu.Lock()\n\tw.services = initServices\n\tw.mu.Unlock()\n\n\t// Create watch plan\n\tplan, err := watch.Parse(map[string]any{\n\t\t\"type\":    \"service\",\n\t\t\"service\": w.key,\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\n\tw.mu.Lock()\n\tw.plan = plan\n\tw.mu.Unlock()\n\n\t// Set handler\n\tplan.Handler = func(idx uint64, data any) {\n\t\t// Check if watcher is closed\n\t\tselect {\n\t\tcase <-w.closeChan:\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\t// Get current services\n\t\tservices, _ := w.Services()\n\n\t\t// Update services\n\t\tw.mu.Lock()\n\t\tw.services = services\n\t\tw.mu.Unlock()\n\n\t\t// Notify changes\n\t\tselect {\n\t\tcase w.eventChan <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n\n\t// Start watching\n\tgo func() {\n\t\tdefer func() {\n\t\t\tw.mu.Lock()\n\t\t\tif w.plan != nil {\n\t\t\t\tw.plan.Stop()\n\t\t\t\tw.plan = nil\n\t\t\t}\n\t\t\tw.mu.Unlock()\n\t\t}()\n\n\t\tif err = plan.Run(w.registry.GetAddress()); err != nil {\n\t\t\treturn\n\t\t}\n\t}()\n\n\t// Wait for close signal\n\t<-w.closeChan\n}\n\n// Proceed returns current services and waits for the next service change.\nfunc (w *Watcher) Proceed() ([]gsvc.Service, error) {\n\t// Check if watcher is closed\n\tselect {\n\tcase <-w.closeChan:\n\t\treturn nil, gerror.New(\"watcher closed\")\n\tdefault:\n\t}\n\n\tw.mu.RLock()\n\tservices := w.services\n\tw.mu.RUnlock()\n\n\t// Wait for changes\n\tselect {\n\tcase <-w.closeChan:\n\t\treturn nil, gerror.New(\"watcher closed\")\n\tcase <-w.eventChan:\n\t\tw.mu.RLock()\n\t\tservices = w.services\n\t\tw.mu.RUnlock()\n\t\treturn services, nil\n\t}\n}\n\n// Close closes the watcher.\nfunc (w *Watcher) Close() error {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\tselect {\n\tcase <-w.closeChan:\n\t\treturn nil\n\tdefault:\n\t\tclose(w.closeChan)\n\t\tif w.plan != nil {\n\t\t\tw.plan.Stop()\n\t\t\tw.plan = nil\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// Services returns current services from the watcher.\nfunc (w *Watcher) Services() ([]gsvc.Service, error) {\n\t// Query services directly from Consul\n\tentries, _, err := w.registry.client.Health().Service(w.key, \"\", true, &api.QueryOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Convert entries to services\n\tvar services []gsvc.Service\n\tfor _, entry := range entries {\n\t\tif entry.Checks.AggregatedStatus() == api.HealthPassing {\n\t\t\tmetadata := make(map[string]any)\n\t\t\tif entry.Service.Meta != nil {\n\t\t\t\tif metaStr, ok := entry.Service.Meta[\"metadata\"]; ok {\n\t\t\t\t\tif err := json.Unmarshal([]byte(metaStr), &metadata); err != nil {\n\t\t\t\t\t\treturn nil, gerror.Wrap(err, \"failed to unmarshal metadata\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Get version from metadata or tags\n\t\t\tversion := \"\"\n\t\t\tif v, ok := entry.Service.Meta[\"version\"]; ok {\n\t\t\t\tversion = v\n\t\t\t} else if len(entry.Service.Tags) > 0 {\n\t\t\t\tversion = entry.Service.Tags[0]\n\t\t\t}\n\n\t\t\t// Create service instance\n\t\t\tservice := &gsvc.LocalService{\n\t\t\t\tName:     entry.Service.Service,\n\t\t\t\tVersion:  version,\n\t\t\t\tMetadata: metadata,\n\t\t\t\tEndpoints: []gsvc.Endpoint{\n\t\t\t\t\tgsvc.NewEndpoint(fmt.Sprintf(\"%s:%d\", entry.Service.Address, entry.Service.Port)),\n\t\t\t\t},\n\t\t\t}\n\t\t\tservices = append(services, service)\n\t\t}\n\t}\n\n\t// Sort services by version\n\tif len(services) > 0 {\n\t\tsort.Slice(services, func(i, j int) bool {\n\t\t\treturn services[i].GetVersion() < services[j].GetVersion()\n\t\t})\n\t}\n\treturn services, nil\n}\n"
  },
  {
    "path": "contrib/registry/consul/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/consul/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/hashicorp/consul/api v1.26.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/armon/go-metrics v0.4.1 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-hclog v1.5.0 // indirect\n\tgithub.com/hashicorp/go-immutable-radix v1.3.1 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-rootcerts v1.0.2 // indirect\n\tgithub.com/hashicorp/golang-lru v0.5.4 // indirect\n\tgithub.com/hashicorp/serf v0.10.1 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/consul/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=\ngithub.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=\ngithub.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=\ngithub.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=\ngithub.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=\ngithub.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=\ngithub.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=\ngithub.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=\ngithub.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=\ngithub.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=\ngithub.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=\ngithub.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=\ngithub.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=\ngithub.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=\ngithub.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\ngolang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=\ngolang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/registry/etcd/README.MD",
    "content": "# GoFrame Etcd Registry\n\n\nUse `etcd` as service registration and discovery management.\n\n\n## Installation\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/etcd/v2\n```\nsuggested using `go.mod`:\n```\nrequire github.com/gogf/gf/contrib/registry/etcd/v2 latest\n```\n\n\n## Example\n\n### Reference example\n\n[server](../../../example/registry/etcd/http/server/server.go)\n```go\npackage main\n\nimport (\n\t\"github.com/gogf/gf/contrib/registry/etcd/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))\n\n\ts := g.Server(`hello.svc`)\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tg.Log().Info(r.Context(), `request received`)\n\t\tr.Response.Write(`Hello world`)\n\t})\n\ts.Run()\n}\n```\n\n[client](../../../example/registry/etcd/http/client/client.go)\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/contrib/registry/etcd/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))\n\tgsel.SetBuilder(gsel.NewBuilderRoundRobin())\n\n\tclient := g.Client()\n\tfor i := 0; i < 100; i++ {\n\t\tres, err := client.Get(gctx.New(), `http://hello.svc/`)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Println(res.ReadAllString())\n\t\tres.Close()\n\t\ttime.Sleep(time.Second)\n\t}\n}\n```\n\n## License\n\n`GoFrame etcd` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n\n"
  },
  {
    "path": "contrib/registry/etcd/etcd.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package etcd implements service Registry and Discovery using etcd.\npackage etcd\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\tetcd3 \"go.etcd.io/etcd/client/v3\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\t_ gsvc.Registry = &Registry{}\n)\n\n// Registry implements gsvc.Registry interface.\ntype Registry struct {\n\tclient       *etcd3.Client\n\tkv           etcd3.KV\n\tlease        etcd3.Lease\n\tkeepaliveTTL time.Duration\n\tlogger       glog.ILogger\n\tetcdConfig   etcd3.Config\n}\n\n// Option is the option for the etcd registry.\ntype Option struct {\n\tLogger       glog.ILogger\n\tKeepaliveTTL time.Duration\n\n\t// DialTimeout is the timeout for failing to establish a connection.\n\tDialTimeout time.Duration\n\n\t// AutoSyncInterval is the interval to update endpoints with its latest members.\n\tAutoSyncInterval time.Duration\n\n\tDialOptions []grpc.DialOption\n}\n\nconst (\n\t// DefaultKeepAliveTTL is the default keepalive TTL.\n\tDefaultKeepAliveTTL = 10 * time.Second\n\n\t// DefaultDialTimeout is the timeout for failing to establish a connection.\n\tDefaultDialTimeout = time.Second * 5\n)\n\n// New creates and returns a new etcd registry.\n// Support Etcd Address format: ip:port,ip:port...,ip:port@username:password\nfunc New(address string, option ...Option) *Registry {\n\tif address == \"\" {\n\t\tpanic(gerror.NewCode(gcode.CodeInvalidParameter, `invalid etcd address \"\"`))\n\t}\n\taddressAndAuth := gstr.SplitAndTrim(address, \"@\")\n\tvar (\n\t\tendpoints          []string\n\t\tuserName, password string\n\t)\n\tswitch len(addressAndAuth) {\n\tcase 1:\n\t\tendpoints = gstr.SplitAndTrim(address, \",\")\n\tdefault:\n\t\tendpoints = gstr.SplitAndTrim(addressAndAuth[0], \",\")\n\t\tparts := gstr.SplitAndTrim(strings.Join(addressAndAuth[1:], \"@\"), \":\")\n\t\tswitch len(parts) {\n\t\tcase 2:\n\t\t\tuserName = parts[0]\n\t\t\tpassword = parts[1]\n\t\tdefault:\n\t\t\tpanic(gerror.NewCode(gcode.CodeInvalidParameter, `invalid etcd auth not support \":\" at username or password `))\n\t\t}\n\t}\n\tif len(endpoints) == 0 {\n\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid etcd address \"%s\"`, address))\n\t}\n\tcfg := etcd3.Config{Endpoints: endpoints}\n\tif userName != \"\" {\n\t\tcfg.Username = userName\n\t}\n\tif password != \"\" {\n\t\tcfg.Password = password\n\t}\n\n\tcfg.DialTimeout = DefaultDialTimeout\n\n\tvar usedOption Option\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tif usedOption.DialTimeout > 0 {\n\t\tcfg.DialTimeout = usedOption.DialTimeout\n\t}\n\tif usedOption.AutoSyncInterval > 0 {\n\t\tcfg.AutoSyncInterval = usedOption.AutoSyncInterval\n\t}\n\n\tclient, err := etcd3.New(cfg)\n\tif err != nil {\n\t\tpanic(gerror.Wrap(err, `create etcd client failed`))\n\t}\n\tr := NewWithClient(client, option...)\n\tr.etcdConfig = cfg\n\treturn r\n}\n\n// NewWithClient creates and returns a new etcd registry with the given client.\nfunc NewWithClient(client *etcd3.Client, option ...Option) *Registry {\n\tr := &Registry{\n\t\tclient: client,\n\t\tkv:     etcd3.NewKV(client),\n\t}\n\tr.etcdConfig.DialTimeout = DefaultDialTimeout\n\tif len(option) > 0 {\n\t\tr.logger = option[0].Logger\n\t\tr.keepaliveTTL = option[0].KeepaliveTTL\n\t\tif option[0].DialTimeout > 0 {\n\t\t\tr.etcdConfig.DialTimeout = option[0].DialTimeout\n\t\t}\n\t}\n\tif r.logger == nil {\n\t\tr.logger = g.Log()\n\t}\n\tif r.keepaliveTTL == 0 {\n\t\tr.keepaliveTTL = DefaultKeepAliveTTL\n\t}\n\treturn r\n}\n\n// extractResponseToServices extracts etcd watch response context to service list.\nfunc extractResponseToServices(res *etcd3.GetResponse) ([]gsvc.Service, error) {\n\tif res == nil || res.Kvs == nil {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\tservices         []gsvc.Service\n\t\tservicePrefixMap = make(map[string]*Service)\n\t)\n\tfor _, kv := range res.Kvs {\n\t\tservice, err := gsvc.NewServiceWithKV(\n\t\t\tstring(kv.Key), string(kv.Value),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn services, err\n\t\t}\n\t\ts := NewService(service)\n\t\tif v, ok := servicePrefixMap[service.GetPrefix()]; ok {\n\t\t\tv.Endpoints = append(v.Endpoints, service.GetEndpoints()...)\n\t\t} else {\n\t\t\tservicePrefixMap[s.GetPrefix()] = s\n\t\t\tservices = append(services, s)\n\t\t}\n\t}\n\treturn services, nil\n}\n"
  },
  {
    "path": "contrib/registry/etcd/etcd_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage etcd\n\nimport (\n\t\"context\"\n\n\tetcd3 \"go.etcd.io/etcd/client/v3\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Search searches and returns services with specified condition.\nfunc (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {\n\tif in.Prefix == \"\" && in.Name != \"\" {\n\t\tin.Prefix = gsvc.NewServiceWithName(in.Name).GetPrefix()\n\t}\n\n\tres, err := r.kv.Get(ctx, in.Prefix, etcd3.WithPrefix())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tservices, err := extractResponseToServices(res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Service filter.\n\tfilteredServices := make([]gsvc.Service, 0)\n\tfor _, service := range services {\n\t\tif in.Prefix != \"\" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Name != \"\" && service.GetName() != in.Name {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Version != \"\" && service.GetVersion() != in.Version {\n\t\t\tcontinue\n\t\t}\n\t\tif len(in.Metadata) != 0 {\n\t\t\tm1 := gmap.NewStrAnyMapFrom(in.Metadata)\n\t\t\tm2 := gmap.NewStrAnyMapFrom(service.GetMetadata())\n\t\t\tif !m1.IsSubOf(m2) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresultItem := service\n\t\tfilteredServices = append(filteredServices, resultItem)\n\t}\n\treturn filteredServices, nil\n}\n\n// Watch watches specified condition changes.\n// The `key` is the prefix of service key.\nfunc (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {\n\treturn newWatcher(key, r.client, r.etcdConfig.DialTimeout)\n}\n"
  },
  {
    "path": "contrib/registry/etcd/etcd_registrar.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\tetcd3 \"go.etcd.io/etcd/client/v3\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\n// Register registers `service` to Registry.\n// Note that it returns a new Service if it changes the input Service with custom one.\nfunc (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Service, error) {\n\tservice = NewService(service)\n\tif err := r.doRegisterLease(ctx, service); err != nil {\n\t\treturn nil, err\n\t}\n\treturn service, nil\n}\n\nfunc (r *Registry) doRegisterLease(ctx context.Context, service gsvc.Service) error {\n\tr.lease = etcd3.NewLease(r.client)\n\n\tctx, cancel := context.WithTimeout(context.Background(), r.etcdConfig.DialTimeout)\n\tdefer cancel()\n\n\tgrant, err := r.lease.Grant(ctx, int64(r.keepaliveTTL.Seconds()))\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `etcd grant failed with keepalive ttl \"%s\"`, r.keepaliveTTL)\n\t}\n\tvar (\n\t\tkey   = service.GetKey()\n\t\tvalue = service.GetValue()\n\t)\n\t_, err = r.client.Put(ctx, key, value, etcd3.WithLease(grant.ID))\n\tif err != nil {\n\t\treturn gerror.Wrapf(\n\t\t\terr,\n\t\t\t`etcd put failed with key \"%s\", value \"%s\", lease \"%d\"`,\n\t\t\tkey, value, grant.ID,\n\t\t)\n\t}\n\tr.logger.Debugf(\n\t\tctx,\n\t\t`etcd put success with key \"%s\", value \"%s\", lease \"%d\"`,\n\t\tkey, value, grant.ID,\n\t)\n\tkeepAliceCh, err := r.client.KeepAlive(context.Background(), grant.ID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tgo r.doKeepAlive(service, grant.ID, keepAliceCh)\n\treturn nil\n}\n\n// Deregister off-lines and removes `service` from the Registry.\nfunc (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {\n\t_, err := r.client.Delete(ctx, service.GetKey())\n\tif r.lease != nil {\n\t\t_ = r.lease.Close()\n\t}\n\treturn err\n}\n\n// doKeepAlive continuously keeps alive the lease from ETCD.\nfunc (r *Registry) doKeepAlive(\n\tservice gsvc.Service, leaseID etcd3.LeaseID, keepAliceCh <-chan *etcd3.LeaseKeepAliveResponse,\n) {\n\tvar ctx = context.Background()\n\tfor {\n\t\tselect {\n\t\tcase <-r.client.Ctx().Done():\n\t\t\tr.logger.Infof(ctx, \"keepalive done for lease id: %d\", leaseID)\n\t\t\treturn\n\n\t\tcase res, ok := <-keepAliceCh:\n\t\t\tif res != nil {\n\t\t\t\t// r.logger.Debugf(ctx, `keepalive loop: %v, %s`, ok, res.String())\n\t\t\t}\n\t\t\tif !ok {\n\t\t\t\t// KeepAlive channel closed, attempt to re-register the service.\n\t\t\t\tr.logger.Warningf(ctx, `keepalive exit, lease id: %d, retry register`, leaseID)\n\t\t\t\tfor {\n\t\t\t\t\t// Check if client context is cancelled before retry.\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-r.client.Ctx().Done():\n\t\t\t\t\t\tr.logger.Infof(ctx, \"retry register cancelled, client context done\")\n\t\t\t\t\t\treturn\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := r.doRegisterLease(ctx, service); err != nil {\n\t\t\t\t\t\tretryDuration := grand.D(time.Second, time.Second*3)\n\t\t\t\t\t\tr.logger.Errorf(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t`keepalive retry register failed, will retry in %s: %+v`,\n\t\t\t\t\t\t\tretryDuration, err,\n\t\t\t\t\t\t)\n\t\t\t\t\t\ttime.Sleep(retryDuration)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tr.logger.Infof(ctx, `keepalive retry register success for service \"%s\"`, service.GetKey())\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/etcd/etcd_service.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage etcd\n\nimport (\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Service wrapper.\ntype Service struct {\n\tgsvc.Service\n\tEndpoints gsvc.Endpoints\n\tMetadata  gsvc.Metadata\n}\n\n// NewService creates and returns local Service from gsvc.Service interface object.\nfunc NewService(service gsvc.Service) *Service {\n\ts, ok := service.(*Service)\n\tif ok {\n\t\tif s.Endpoints == nil {\n\t\t\ts.Endpoints = make(gsvc.Endpoints, 0)\n\t\t}\n\t\tif s.Metadata == nil {\n\t\t\ts.Metadata = make(gsvc.Metadata)\n\t\t}\n\t\treturn s\n\t}\n\ts = &Service{\n\t\tService:   service,\n\t\tEndpoints: make(gsvc.Endpoints, 0),\n\t\tMetadata:  make(gsvc.Metadata),\n\t}\n\tif len(service.GetEndpoints()) > 0 {\n\t\ts.Endpoints = service.GetEndpoints()\n\t}\n\tif len(service.GetMetadata()) > 0 {\n\t\ts.Metadata = service.GetMetadata()\n\t}\n\treturn s\n}\n\n// GetMetadata returns the Metadata map of service.\n// The Metadata is key-value pair map specifying extra attributes of a service.\nfunc (s *Service) GetMetadata() gsvc.Metadata {\n\treturn s.Metadata\n}\n\n// GetEndpoints returns the Endpoints of service.\n// The Endpoints contain multiple host/port information of service.\nfunc (s *Service) GetEndpoints() gsvc.Endpoints {\n\treturn s.Endpoints\n}\n\n// GetValue formats and returns the value of the service.\n// The result value is commonly used for key-value registrar server.\nfunc (s *Service) GetValue() string {\n\tb, _ := gjson.Marshal(s.Metadata)\n\treturn string(b)\n}\n"
  },
  {
    "path": "contrib/registry/etcd/etcd_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\tetcd3 \"go.etcd.io/etcd/client/v3\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nvar (\n\t_ gsvc.Watcher = &watcher{}\n)\n\ntype watcher struct {\n\tkey       string\n\tctx       context.Context\n\tcancel    context.CancelFunc\n\twatchChan etcd3.WatchChan\n\twatcher   etcd3.Watcher\n\tkv        etcd3.KV\n}\n\nfunc newWatcher(key string, client *etcd3.Client, dialTimeout time.Duration) (*watcher, error) {\n\tw := &watcher{\n\t\tkey:     key,\n\t\twatcher: etcd3.NewWatcher(client),\n\t\tkv:      etcd3.NewKV(client),\n\t}\n\n\t// Create context with timeout\n\tctx, cancel := context.WithTimeout(context.Background(), dialTimeout)\n\tdefer cancel()\n\n\t// Test connection first.\n\tif _, err := client.Get(ctx, \"ping\"); err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeOperationFailed, err, \"failed to connect to etcd\")\n\t}\n\n\tw.ctx, w.cancel = context.WithCancel(context.Background())\n\tw.watchChan = w.watcher.Watch(w.ctx, key, etcd3.WithPrefix(), etcd3.WithRev(0))\n\n\tif err := w.watcher.RequestProgress(context.Background()); err != nil {\n\t\t// Clean up\n\t\tw.cancel()\n\t\treturn nil, gerror.WrapCode(gcode.CodeOperationFailed, err, \"failed to establish watch connection\")\n\t}\n\n\treturn w, nil\n}\n\n// Proceed is used to watch the key.\nfunc (w *watcher) Proceed() ([]gsvc.Service, error) {\n\tselect {\n\tcase <-w.ctx.Done():\n\t\treturn nil, w.ctx.Err()\n\tcase <-w.watchChan:\n\t\t// It retrieves, merges and returns all services by prefix if any changes.\n\t\treturn w.getServicesByPrefix()\n\t}\n}\n\n// Close is used to close the watcher.\nfunc (w *watcher) Close() error {\n\tw.cancel()\n\treturn w.watcher.Close()\n}\n\nfunc (w *watcher) getServicesByPrefix() ([]gsvc.Service, error) {\n\tres, err := w.kv.Get(w.ctx, w.key, etcd3.WithPrefix())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn extractResponseToServices(res)\n}\n"
  },
  {
    "path": "contrib/registry/etcd/etcd_z_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage etcd_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/registry/etcd/v2\"\n)\n\nfunc TestRegistry(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tregistry = etcd.New(`127.0.0.1:2379@root:123`)\n\t)\n\tsvc := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc.GetName())\n\t})\n\n\t// Search by name.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.Name,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by prefix.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tPrefix: svc.GetPrefix(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by metadata.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"https\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"grpc\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestWatch(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tregistry = etcd.New(`127.0.0.1:2379@root:123`)\n\t)\n\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc1.GetName())\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\twatcher, err := registry.Watch(ctx, svc1.GetPrefix())\n\t\tt.AssertNil(err)\n\n\t\t// Register another service.\n\t\tsvc2 := &gsvc.LocalService{\n\t\t\tName:      svc1.Name,\n\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9999\"),\n\t\t}\n\t\tregistered, err := registry.Register(ctx, svc2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc2.GetName())\n\n\t\t// Watch and retrieve the service changes:\n\t\t// svc1 and svc2 is the same service name, which has 2 endpoints.\n\t\tproceedResult, err := watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proceedResult), 1)\n\t\tt.Assert(\n\t\t\tproceedResult[0].GetEndpoints(),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0], svc2.GetEndpoints()[0]},\n\t\t)\n\n\t\t// Watch and retrieve the service changes:\n\t\t// left only svc1, which means this service has only 1 endpoint.\n\t\terr = registry.Deregister(ctx, svc2)\n\t\tt.AssertNil(err)\n\t\tproceedResult, err = watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tproceedResult[0].GetEndpoints(),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0]},\n\t\t)\n\t\tt.AssertNil(watcher.Close())\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc1)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "contrib/registry/etcd/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/etcd/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgo.etcd.io/etcd/client/v3 v3.5.17\n\tgoogle.golang.org/grpc v1.59.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/coreos/go-semver v0.3.0 // indirect\n\tgithub.com/coreos/go-systemd/v22 v22.3.2 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.etcd.io/etcd/api/v3 v3.5.17 // indirect\n\tgo.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgo.uber.org/zap v1.17.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect\n\tgoogle.golang.org/protobuf v1.33.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/etcd/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=\ngithub.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.etcd.io/etcd/api/v3 v3.5.17 h1:cQB8eb8bxwuxOilBpMJAEo8fAONyrdXTHUNcMd8yT1w=\ngo.etcd.io/etcd/api/v3 v3.5.17/go.mod h1:d1hvkRuXkts6PmaYk2Vrgqbv7H4ADfAKhyJqHNLJCB4=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.17 h1:XxnDXAWq2pnxqx76ljWwiQ9jylbpC4rvkAeRVOUKKVw=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.17/go.mod h1:4DqK1TKacp/86nJk4FLQqo6Mn2vvQFBmruW3pP14H/w=\ngo.etcd.io/etcd/client/v3 v3.5.17 h1:o48sINNeWz5+pjy/Z0+HKpj/xSnBkuVhVvXkjEXbqZY=\ngo.etcd.io/etcd/client/v3 v3.5.17/go.mod h1:j2d4eXTHWkT2ClBgnnEPm/Wuu7jsqku41v9DZ3OtjQo=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=\ngo.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=\ngoogle.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=\ngoogle.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=\ngoogle.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=\ngoogle.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/registry/file/README.MD",
    "content": "# GoFrame File Registry\n\n\nUse `file` as service registration and discovery management.\n\n\n## Installation\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/file/v2\n```\nsuggested using `go.mod`:\n```\nrequire github.com/gogf/gf/contrib/registry/file/v2 latest\n```\n\n\n## Example\n\n### Reference example\n\n[server](../../../example/registry/file/server/server.go)\n```go\npackage main\n\nimport (\n\t\"github.com/gogf/gf/contrib/registry/file/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(file.New(gfile.Temp(\"gsvc\")))\n\n\ts := g.Server(`hello.svc`)\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tg.Log().Info(r.Context(), `request received`)\n\t\tr.Response.Write(`Hello world`)\n\t})\n\ts.Run()\n}\n\n```\n\n[client](../../../example/registry/file/client/client.go)\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/contrib/registry/file/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(file.New(gfile.Temp(\"gsvc\")))\n\n\tclient := g.Client()\n\tfor i := 0; i < 100; i++ {\n\t\tres, err := client.Get(gctx.New(), `http://hello.svc/`)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Println(res.ReadAllString())\n\t\tres.Close()\n\t\ttime.Sleep(time.Second)\n\t}\n}\n\n```\n\n"
  },
  {
    "path": "contrib/registry/file/file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package file implements service Registry and Discovery using file.\npackage file\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nvar (\n\t_ gsvc.Registry = &Registry{}\n)\n\nconst (\n\tupdateAtKey                      = \"UpdateAt\"\n\tserviceTTL                       = 20 * time.Second\n\tserviceUpdateInterval            = 10 * time.Second\n\tdefaultSeparator                 = \"#\"\n\tdefaultEndpointHostPortDelimiter = \"-\"\n)\n\n// Registry implements interface Registry using file.\n// This implement is usually for testing only.\ntype Registry struct {\n\tpath string // Local storing folder path for Services.\n}\n\n// New creates and returns a gsvc.Registry implements using file.\nfunc New(path string) gsvc.Registry {\n\tif !gfile.Exists(path) {\n\t\t_ = gfile.Mkdir(path)\n\t}\n\treturn &Registry{\n\t\tpath: path,\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/file/file_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Search searches and returns services with specified condition.\nfunc (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) (result []gsvc.Service, err error) {\n\tservices, err := r.getServices(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, service := range services {\n\t\tif in.Prefix != \"\" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Name != \"\" && service.GetName() != in.Name {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Version != \"\" && service.GetVersion() != in.Version {\n\t\t\tcontinue\n\t\t}\n\t\tif len(in.Metadata) != 0 {\n\t\t\tm1 := gmap.NewStrAnyMapFrom(in.Metadata)\n\t\t\tm2 := gmap.NewStrAnyMapFrom(service.GetMetadata())\n\t\t\tif !m1.IsSubOf(m2) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresultItem := service\n\t\tresult = append(result, resultItem)\n\t}\n\tresult = r.mergeServices(result)\n\treturn\n}\n\n// Watch watches specified condition changes.\n// The `key` is the prefix of service key.\nfunc (r *Registry) Watch(ctx context.Context, key string) (watcher gsvc.Watcher, err error) {\n\tfileWatcher := &Watcher{\n\t\tprefix:    key,\n\t\tdiscovery: r,\n\t\tch:        make(chan gsvc.Service, 100),\n\t\tclosed:    gtype.NewBool(false),\n\t}\n\t_, err = gfsnotify.Add(r.path, func(event *gfsnotify.Event) {\n\t\tif fileWatcher.closed.Val() {\n\t\t\treturn\n\t\t}\n\t\tif event.IsChmod() {\n\t\t\treturn\n\t\t}\n\t\tif !gstr.HasPrefix(gfile.Basename(event.Path), r.getServiceKeyForFile(key)) {\n\t\t\treturn\n\t\t}\n\t\tservice, err := r.getServiceByFilePath(event.Path)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tfileWatcher.ch <- service\n\t})\n\treturn fileWatcher, err\n}\n\nfunc (r *Registry) getServices(ctx context.Context) (services []gsvc.Service, err error) {\n\tfilePaths, err := gfile.ScanDirFile(r.path, \"*\", false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, filePath := range filePaths {\n\t\ts, e := r.getServiceByFilePath(filePath)\n\t\tif e != nil {\n\t\t\treturn nil, e\n\t\t}\n\t\t// Check service TTL.\n\t\tvar (\n\t\t\tupdateAt    = s.GetMetadata().Get(updateAtKey).GTime()\n\t\t\tnowTime     = gtime.Now()\n\t\t\tsubDuration = nowTime.Sub(updateAt)\n\t\t)\n\t\tif updateAt.IsZero() || subDuration > serviceTTL {\n\t\t\tg.Log().Debugf(\n\t\t\t\tctx,\n\t\t\t\t`service \"%s\" is expired, update at: %s, current: %s, sub duration: %s`,\n\t\t\t\ts.GetKey(), updateAt.String(), nowTime.String(), subDuration.String(),\n\t\t\t)\n\t\t\t_ = gfile.RemoveFile(filePath)\n\t\t\tcontinue\n\t\t}\n\t\tservices = append(services, s)\n\t}\n\tservices = r.mergeServices(services)\n\treturn\n}\n\nfunc (r *Registry) getServiceByFilePath(filePath string) (gsvc.Service, error) {\n\tvar (\n\t\tfileName    = gfile.Basename(filePath)\n\t\tfileContent = gfile.GetContents(filePath)\n\t\tserviceKey  = gstr.Replace(fileName, defaultSeparator, gsvc.DefaultSeparator)\n\t)\n\n\tserviceKey = gstr.Replace(serviceKey, defaultEndpointHostPortDelimiter, gsvc.EndpointHostPortDelimiter)\n\tserviceKey = gsvc.DefaultSeparator + serviceKey\n\treturn gsvc.NewServiceWithKV(serviceKey, fileContent)\n}\n\nfunc (r *Registry) mergeServices(services []gsvc.Service) []gsvc.Service {\n\tif len(services) == 0 {\n\t\treturn services\n\t}\n\n\tvar (\n\t\tservicePrefixMap = make(map[string]*Service)\n\t\tmergeServices    = make([]gsvc.Service, 0)\n\t)\n\tfor _, service := range services {\n\t\tif v, ok := servicePrefixMap[service.GetPrefix()]; ok {\n\t\t\tv.Endpoints = append(v.Endpoints, service.GetEndpoints()...)\n\t\t} else {\n\t\t\ts := NewService(service)\n\t\t\tservicePrefixMap[s.GetPrefix()] = s\n\t\t\tmergeServices = append(mergeServices, s)\n\t\t}\n\t}\n\treturn mergeServices\n}\n"
  },
  {
    "path": "contrib/registry/file/file_registrar.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Register registers `service` to Registry.\n// Note that it returns a new Service if it changes the input Service with custom one.\nfunc (r *Registry) Register(ctx context.Context, service gsvc.Service) (registered gsvc.Service, err error) {\n\tservice = NewService(service)\n\tservice.GetMetadata().Set(updateAtKey, gtime.Now())\n\tvar (\n\t\tfilePath    = r.getServiceFilePath(service)\n\t\tfileContent = service.GetValue()\n\t)\n\terr = gfile.PutContents(filePath, fileContent)\n\tif err == nil {\n\t\tgtimer.Add(ctx, serviceUpdateInterval, func(ctx context.Context) {\n\t\t\tif !gfile.Exists(filePath) {\n\t\t\t\tgtimer.Exit()\n\t\t\t}\n\t\t\t// Update TTL in timer.\n\t\t\tservice, _ = r.getServiceByFilePath(filePath)\n\t\t\tif service != nil {\n\t\t\t\tservice.GetMetadata().Set(updateAtKey, gtime.Now())\n\t\t\t}\n\t\t\t_ = gfile.PutContents(filePath, service.GetValue())\n\t\t})\n\t}\n\treturn service, err\n}\n\n// Deregister off-lines and removes `service` from the Registry.\nfunc (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {\n\treturn gfile.RemoveFile(r.getServiceFilePath(service))\n}\n\nfunc (r *Registry) getServiceFilePath(service gsvc.Service) string {\n\treturn gfile.Join(r.path, r.getServiceFileName(service))\n}\n\nfunc (r *Registry) getServiceFileName(service gsvc.Service) string {\n\treturn r.getServiceKeyForFile(service.GetKey())\n}\n\nfunc (r *Registry) getServiceKeyForFile(key string) string {\n\tkey = gstr.Replace(key, gsvc.DefaultSeparator, defaultSeparator)\n\tkey = gstr.Trim(key, defaultSeparator)\n\tkey = gstr.Replace(key, gsvc.EndpointHostPortDelimiter, defaultEndpointHostPortDelimiter)\n\treturn key\n}\n"
  },
  {
    "path": "contrib/registry/file/file_service.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file\n\nimport (\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Service wrapper.\ntype Service struct {\n\tgsvc.Service\n\tEndpoints gsvc.Endpoints\n\tMetadata  gsvc.Metadata\n}\n\n// NewService creates and returns local Service from gsvc.Service interface object.\nfunc NewService(service gsvc.Service) *Service {\n\ts, ok := service.(*Service)\n\tif ok {\n\t\tif s.Endpoints == nil {\n\t\t\ts.Endpoints = make(gsvc.Endpoints, 0)\n\t\t}\n\t\tif s.Metadata == nil {\n\t\t\ts.Metadata = make(gsvc.Metadata)\n\t\t}\n\t\treturn s\n\t}\n\ts = &Service{\n\t\tService:   service,\n\t\tEndpoints: make(gsvc.Endpoints, 0),\n\t\tMetadata:  make(gsvc.Metadata),\n\t}\n\tif len(service.GetEndpoints()) > 0 {\n\t\ts.Endpoints = service.GetEndpoints()\n\t}\n\tif len(service.GetMetadata()) > 0 {\n\t\ts.Metadata = service.GetMetadata()\n\t}\n\treturn s\n}\n\n// GetMetadata returns the Metadata map of service.\n// The Metadata is key-value pair map specifying extra attributes of a service.\nfunc (s *Service) GetMetadata() gsvc.Metadata {\n\treturn s.Metadata\n}\n\n// GetEndpoints returns the Endpoints of service.\n// The Endpoints contain multiple host/port information of service.\nfunc (s *Service) GetEndpoints() gsvc.Endpoints {\n\treturn s.Endpoints\n}\n\n// GetValue formats and returns the value of the service.\n// The result value is commonly used for key-value registrar server.\nfunc (s *Service) GetValue() string {\n\tb, _ := gjson.Marshal(s.Metadata)\n\treturn string(b)\n}\n"
  },
  {
    "path": "contrib/registry/file/file_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Watcher for file changes watch.\ntype Watcher struct {\n\tprefix    string            // Watched prefix key, not file name prefix.\n\tdiscovery gsvc.Discovery    // Service discovery.\n\tch        chan gsvc.Service // Changes that caused by inotify.\n\tclosed    *gtype.Bool       // Whether the channel has been closed\n}\n\n// Proceed proceeds watch in blocking way.\n// It returns all complete services that watched by `key` if any change.\nfunc (w *Watcher) Proceed() (services []gsvc.Service, err error) {\n\tif w.closed.Val() {\n\t\treturn nil, gerror.New(\"discovery service was closed\")\n\t}\n\t<-w.ch\n\treturn w.discovery.Search(context.Background(), gsvc.SearchInput{\n\t\tPrefix: w.prefix,\n\t})\n}\n\n// Close closes the watcher.\nfunc (w *Watcher) Close() error {\n\tif w.closed.Cas(false, true) {\n\t\tclose(w.ch)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "contrib/registry/file/file_z_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/registry/file/v2\"\n)\n\nfunc TestRegistry(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tpath     = gfile.Temp(guid.S())\n\t\tregistry = file.New(path)\n\t)\n\tdefer gfile.Remove(path)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc.GetName())\n\t})\n\n\t// Search by name.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.Name,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by prefix.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tPrefix: svc.GetPrefix(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by metadata.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"https\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"grpc\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestWatch(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tpath     = gfile.Temp(guid.S())\n\t\tregistry = file.New(path)\n\t)\n\tdefer gfile.Remove(path)\n\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc1.GetName())\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\twatcher, err := registry.Watch(ctx, svc1.GetPrefix())\n\t\tt.AssertNil(err)\n\n\t\t// Register another service.\n\t\tsvc2 := &gsvc.LocalService{\n\t\t\tName:      svc1.Name,\n\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9999\"),\n\t\t}\n\t\tregistered, err := registry.Register(ctx, svc2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc2.GetName())\n\n\t\t// Watch and retrieve the service changes:\n\t\t// svc1 and svc2 is the same service name, which has 2 endpoints.\n\t\tproceedResult, err := watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(proceedResult), 1)\n\t\tt.Assert(\n\t\t\tproceedResult[0].GetEndpoints(),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0], svc2.GetEndpoints()[0]},\n\t\t)\n\n\t\t// Watch and retrieve the service changes:\n\t\t// left only svc1, which means this service has only 1 endpoint.\n\t\terr = registry.Deregister(ctx, svc2)\n\t\tt.AssertNil(err)\n\t\tproceedResult, err = watcher.Proceed()\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tproceedResult[0].GetEndpoints(),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0]},\n\t\t)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc1)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "contrib/registry/file/file_z_http_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage file_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/registry/file/v2\"\n)\n\nvar ctx = gctx.GetInitCtx()\n\nfunc Test_HTTP_Registry(t *testing.T) {\n\tvar (\n\t\tsvcName = guid.S()\n\t\tdirPath = gfile.Temp(svcName)\n\t)\n\tdefer gfile.Remove(dirPath)\n\tgsvc.SetRegistry(file.New(dirPath))\n\n\ts := g.Server(svcName)\n\ts.BindHandler(\"/http-registry\", func(r *ghttp.Request) {\n\t\tr.Response.Write(svcName)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetDiscovery(gsvc.GetRegistry())\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://%s\", svcName))\n\t\t// GET\n\t\tt.Assert(client.GetContent(ctx, \"/http-registry\"), svcName)\n\t})\n}\n\nfunc Test_HTTP_Discovery_Disable(t *testing.T) {\n\tvar (\n\t\tsvcName = guid.S()\n\t\tdirPath = gfile.Temp(svcName)\n\t)\n\tdefer gfile.Remove(dirPath)\n\tgsvc.SetRegistry(file.New(dirPath))\n\n\ts := g.Server(svcName)\n\ts.BindHandler(\"/http-registry\", func(r *ghttp.Request) {\n\t\tr.Response.Write(svcName)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetDiscovery(gsvc.GetRegistry())\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://%s\", svcName))\n\t\tresult, err := client.Get(ctx, \"/http-registry\")\n\t\tdefer result.Close()\n\t\tt.AssertNil(err)\n\t\tt.Assert(result.ReadAllString(), svcName)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://%s\", svcName))\n\t\tresult, err := client.Discovery(nil).Get(ctx, \"/http-registry\")\n\t\tdefer result.Close()\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_HTTP_Server_Endpoints(t *testing.T) {\n\tvar (\n\t\tsvcName = guid.S()\n\t\tdirPath = gfile.Temp(svcName)\n\t)\n\tdefer gfile.Remove(dirPath)\n\tgsvc.SetRegistry(file.New(dirPath))\n\n\tendpoints := []string{\"10.0.0.1:8000\", \"10.0.0.2:8000\"}\n\ts := g.Server(svcName)\n\ts.SetEndpoints(endpoints)\n\ts.BindHandler(\"/http-registry\", func(r *ghttp.Request) {\n\t\tr.Response.Write(svcName)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tservice, err := gsvc.Get(ctx, svcName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(service.GetEndpoints(), gstr.Join(endpoints, \",\"))\n\t})\n}\n"
  },
  {
    "path": "contrib/registry/file/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/file/v2\n\ngo 1.23.0\n\nrequire github.com/gogf/gf/v2 v2.10.0\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/file/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/registry/nacos/README.MD",
    "content": "# GoFrame Nacos Registry\n\nUse `nacos` as service registration and discovery management.\n\n## Installation\n\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/nacos/v2\n```\n\nsuggested using `go.mod`:\n\n```\nrequire github.com/gogf/gf/contrib/registry/nacos/v2 latest\n```\n\n## Example\n\n### Reference example\n\n[server](../../../example/registry/nacos/http/server/main.go)\n\n```go\npackage main\n\nimport (\n\t\"github.com/gogf/gf/contrib/registry/nacos/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(nacos.New(`127.0.0.1:8848`).\n        SetClusterName(\"DEFAULT\").\n        SetGroupName(\"DEFAULT_GROUP\"))\n\n\ts := g.Server(`hello.svc`)\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tg.Log().Info(r.Context(), `request received`)\n\t\tr.Response.Write(`Hello world`)\n\t})\n\ts.Run()\n}\n```\n\n[client](../../../example/registry/nacos/http/client/main.go)\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/contrib/registry/nacos/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(nacos.New(`127.0.0.1:8848`))\n\tgsel.SetBuilder(gsel.NewBuilderRoundRobin())\n\n\tclient := g.Client()\n\tfor i := 0; i < 100; i++ {\n\t\tres, err := client.Get(gctx.New(), `http://hello.svc/`)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Println(res.ReadAllString())\n\t\tres.Close()\n\t\ttime.Sleep(time.Second)\n\t}\n}\n```\n\n## License\n\n`GoFrame Nacos` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n"
  },
  {
    "path": "contrib/registry/nacos/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/nacos/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/nacos-group/nacos-sdk-go/v2 v2.3.5\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect\n\tgithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect\n\tgithub.com/alibabacloud-go/darabonba-array v0.1.0 // indirect\n\tgithub.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect\n\tgithub.com/alibabacloud-go/darabonba-map v0.0.2 // indirect\n\tgithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 // indirect\n\tgithub.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect\n\tgithub.com/alibabacloud-go/darabonba-string v1.0.2 // indirect\n\tgithub.com/alibabacloud-go/debug v1.0.1 // indirect\n\tgithub.com/alibabacloud-go/endpoint-util v1.1.0 // indirect\n\tgithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3 // indirect\n\tgithub.com/alibabacloud-go/openapi-util v0.1.0 // indirect\n\tgithub.com/alibabacloud-go/tea v1.2.2 // indirect\n\tgithub.com/alibabacloud-go/tea-utils v1.4.4 // indirect\n\tgithub.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect\n\tgithub.com/alibabacloud-go/tea-xml v1.1.3 // indirect\n\tgithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect\n\tgithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 // indirect\n\tgithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 // indirect\n\tgithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect\n\tgithub.com/aliyun/credentials-go v1.4.3 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/buger/jsonparser v1.1.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/deckarep/golang-set v1.7.1 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/mock v1.6.0 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/prometheus/client_golang v1.12.2 // indirect\n\tgithub.com/prometheus/client_model v0.2.0 // indirect\n\tgithub.com/prometheus/common v0.32.1 // indirect\n\tgithub.com/prometheus/procfs v0.7.3 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/tjfoc/gmsm v1.4.1 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgo.uber.org/zap v1.21.0 // indirect\n\tgolang.org/x/crypto v0.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sync v0.14.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/time v0.1.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect\n\tgoogle.golang.org/grpc v1.67.3 // indirect\n\tgoogle.golang.org/protobuf v1.36.5 // indirect\n\tgopkg.in/ini.v1 v1.67.0 // indirect\n\tgopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/nacos/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=\ngithub.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=\ngithub.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=\ngithub.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=\ngithub.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=\ngithub.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=\ngithub.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=\ngithub.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=\ngithub.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=\ngithub.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=\ngithub.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=\ngithub.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=\ngithub.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=\ngithub.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=\ngithub.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=\ngithub.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=\ngithub.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=\ngithub.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=\ngithub.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=\ngithub.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=\ngithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw=\ngithub.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw=\ngithub.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=\ngithub.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=\ngithub.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=\ngithub.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=\ngithub.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=\ngithub.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=\ngithub.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=\ngithub.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=\ngithub.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=\ngithub.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=\ngithub.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=\ngithub.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=\ngithub.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=\ngithub.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=\ngithub.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=\ngithub.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=\ngithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU=\ngithub.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=\ngithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=\ngithub.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=\ngithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=\ngithub.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=\ngithub.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=\ngithub.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=\ngithub.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=\ngithub.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=\ngithub.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=\ngithub.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=\ngithub.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=\ngithub.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/nacos-group/nacos-sdk-go/v2 v2.3.5 h1:Hux7C4N4rWhwBF5Zm4yyYskrs9VTgrRTA8DZjoEhQTs=\ngithub.com/nacos-group/nacos-sdk-go/v2 v2.3.5/go.mod h1:ygUBdt7eGeYBt6Lz2HO3wx7crKXk25Mp80568emGMWU=\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=\ngithub.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=\ngithub.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=\ngithub.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=\ngithub.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=\ngithub.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=\ngithub.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=\ngo.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=\ngolang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=\ngolang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=\ngolang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=\ngolang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=\ngolang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=\ngolang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=\ngolang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=\ngolang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=\ngolang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=\ngolang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=\ngolang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=\ngolang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=\ngoogle.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=\ngoogle.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=\ngopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "contrib/registry/nacos/nacos.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package nacos implements service Registry and Discovery using nacos.\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/clients\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/common/constant\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tcstServiceSeparator = \"@@\"\n)\n\nvar (\n\t_ gsvc.Registry = &Registry{}\n)\n\n// Registry is nacos registry.\ntype Registry struct {\n\tclient          naming_client.INamingClient\n\tclusterName     string\n\tgroupName       string\n\tdefaultEndpoint string\n\tdefaultMetadata map[string]string\n}\n\n// Config is the configuration object for nacos client.\ntype Config struct {\n\tServerConfigs []constant.ServerConfig `v:\"required\"` // See constant.ServerConfig\n\tClientConfig  *constant.ClientConfig  `v:\"required\"` // See constant.ClientConfig\n}\n\n// New new a registry with address and opts\nfunc New(address string, opts ...constant.ClientOption) (reg *Registry) {\n\tendpoints := gstr.SplitAndTrim(address, \",\")\n\tif len(endpoints) == 0 {\n\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid nacos address \"%s\"`, address))\n\t}\n\n\tclientConfig := constant.NewClientConfig(opts...)\n\n\tif len(clientConfig.NamespaceId) == 0 {\n\t\tclientConfig.NamespaceId = \"public\"\n\t}\n\n\tserverConfigs := make([]constant.ServerConfig, 0, len(endpoints))\n\tfor _, endpoint := range endpoints {\n\t\ttmp := gstr.Split(endpoint, \":\")\n\t\tip := tmp[0]\n\t\tport := gconv.Uint64(tmp[1])\n\t\tif port == 0 {\n\t\t\tport = 8848\n\t\t}\n\t\tserverConfigs = append(serverConfigs, *constant.NewServerConfig(ip, port))\n\t}\n\tctx := gctx.New()\n\treg, err := NewWithConfig(ctx, Config{\n\t\tServerConfigs: serverConfigs,\n\t\tClientConfig:  clientConfig,\n\t})\n\n\tif err != nil {\n\t\tpanic(gerror.Wrap(err, `create nacos client failed`))\n\t}\n\treturn\n}\n\n// NewWithConfig creates and returns registry with Config.\nfunc NewWithConfig(ctx context.Context, config Config) (reg *Registry, err error) {\n\t// Data validation.\n\terr = g.Validator().Data(config).Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnameingClient, err := clients.NewNamingClient(vo.NacosClientParam{\n\t\tClientConfig:  config.ClientConfig,\n\t\tServerConfigs: config.ServerConfigs,\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\treturn NewWithClient(nameingClient), nil\n}\n\n// NewWithClient new the instance with INamingClient\nfunc NewWithClient(client naming_client.INamingClient) *Registry {\n\tr := &Registry{\n\t\tclient:          client,\n\t\tclusterName:     \"DEFAULT\",\n\t\tgroupName:       \"DEFAULT_GROUP\",\n\t\tdefaultMetadata: make(map[string]string),\n\t}\n\treturn r\n}\n\n// SetClusterName can set the clusterName. The default is 'DEFAULT'\nfunc (reg *Registry) SetClusterName(clusterName string) *Registry {\n\treg.clusterName = clusterName\n\treturn reg\n}\n\n// SetGroupName can set the groupName. The default is 'DEFAULT_GROUP'\nfunc (reg *Registry) SetGroupName(groupName string) *Registry {\n\treg.groupName = groupName\n\treturn reg\n}\n\n// SetDefaultEndpoint sets the default endpoint for service registration.\n// It overrides the service endpoints when registering if it's not empty.\nfunc (reg *Registry) SetDefaultEndpoint(endpoint string) *Registry {\n\treg.defaultEndpoint = endpoint\n\treturn reg\n}\n\n// SetDefaultMetadata sets the default metadata for service registration.\n// It will be merged with service's original metadata when registering.\nfunc (reg *Registry) SetDefaultMetadata(metadata map[string]string) *Registry {\n\treg.defaultMetadata = metadata\n\treturn reg\n}\n"
  },
  {
    "path": "contrib/registry/nacos/nacos_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/model\"\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Search searches and returns services with specified condition.\nfunc (reg *Registry) Search(_ context.Context, in gsvc.SearchInput) (result []gsvc.Service, err error) {\n\tif in.Prefix == \"\" && in.Name != \"\" {\n\t\tin.Prefix = gsvc.NewServiceWithName(in.Name).GetPrefix()\n\t}\n\n\tc := reg.client\n\n\tserviceName := in.Name\n\tif serviceName == \"\" {\n\t\tinfo := gstr.SplitAndTrim(gstr.Trim(in.Prefix, gsvc.DefaultSeparator), gsvc.DefaultSeparator)\n\t\tif len(info) >= 2 {\n\t\t\tserviceName = info[len(info)-2]\n\t\t}\n\t}\n\tparam := vo.SelectInstancesParam{\n\t\tGroupName:   reg.groupName,\n\t\tClusters:    []string{reg.clusterName},\n\t\tServiceName: serviceName,\n\t\tHealthyOnly: true,\n\t}\n\tinstances, err := c.SelectInstances(param)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tinsts := make([]model.Instance, 0, len(instances))\ninst_loop:\n\tfor _, inst := range instances {\n\t\tif len(in.Metadata) > 0 {\n\t\t\tfor k, v := range in.Metadata {\n\t\t\t\tif inst.Metadata[k] != v {\n\t\t\t\t\tcontinue inst_loop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tinsts = append(insts, inst)\n\t}\n\n\tresult = NewServicesFromInstances(insts)\n\treturn\n}\n\n// Watch watches specified condition changes.\n// The `key` is the prefix of service key.\nfunc (reg *Registry) Watch(ctx context.Context, key string) (watcher gsvc.Watcher, err error) {\n\tc := reg.client\n\n\tw := newWatcher(ctx)\n\n\tfn := func(services []model.Instance, err error) {\n\t\tw.Push(services, err)\n\t}\n\n\tsArr := gstr.Split(key, gsvc.DefaultSeparator)\n\tif len(sArr) < 5 {\n\t\terr = gerror.NewCode(gcode.CodeInvalidParameter, \"The 'key' is invalid\")\n\t\treturn\n\t}\n\tserviceName := sArr[4]\n\n\tparam := &vo.SubscribeParam{\n\t\tServiceName:       serviceName,\n\t\tGroupName:         reg.groupName,\n\t\tClusters:          []string{reg.clusterName},\n\t\tSubscribeCallback: fn,\n\t}\n\n\tw.SetCloseFunc(func() error {\n\t\treturn c.Unsubscribe(param)\n\t})\n\n\tif err = c.Subscribe(param); err != nil {\n\t\treturn\n\t}\n\n\twatcher = w\n\treturn\n}\n"
  },
  {
    "path": "contrib/registry/nacos/nacos_register.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/vo\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Register registers `service` to Registry.\n// Note that it returns a new Service if it changes the input Service with custom one.\nfunc (reg *Registry) Register(_ context.Context, service gsvc.Service) (registered gsvc.Service, err error) {\n\tmetadata := map[string]string{}\n\tendpoints := service.GetEndpoints()\n\n\t// Apply default endpoint override if configured\n\tif reg.defaultEndpoint != \"\" {\n\t\tendpoints = gsvc.Endpoints{gsvc.NewEndpoint(reg.defaultEndpoint)}\n\t}\n\n\tp := vo.BatchRegisterInstanceParam{\n\t\tServiceName: service.GetName(),\n\t\tGroupName:   reg.groupName,\n\t\tInstances:   make([]vo.RegisterInstanceParam, 0, len(endpoints)),\n\t}\n\n\t// Copy service metadata\n\tfor k, v := range service.GetMetadata() {\n\t\tmetadata[k] = gconv.String(v)\n\t}\n\n\t// Apply default metadata if configured\n\tfor k, v := range reg.defaultMetadata {\n\t\tmetadata[k] = v\n\t}\n\n\tfor _, endpoint := range endpoints {\n\t\tp.Instances = append(p.Instances, vo.RegisterInstanceParam{\n\t\t\tIp:          endpoint.Host(),\n\t\t\tPort:        uint64(endpoint.Port()),\n\t\t\tServiceName: service.GetName(),\n\t\t\tMetadata:    metadata,\n\t\t\tWeight:      100,\n\t\t\tEnable:      true,\n\t\t\tHealthy:     true,\n\t\t\tEphemeral:   true,\n\t\t\tClusterName: reg.clusterName,\n\t\t\tGroupName:   reg.groupName,\n\t\t})\n\t}\n\n\tif _, err = reg.client.BatchRegisterInstance(p); err != nil {\n\t\treturn\n\t}\n\n\tregistered = service\n\n\treturn\n}\n\n// Deregister off-lines and removes `service` from the Registry.\nfunc (reg *Registry) Deregister(_ context.Context, service gsvc.Service) (err error) {\n\tc := reg.client\n\n\tfor _, endpoint := range service.GetEndpoints() {\n\t\tif _, err = c.DeregisterInstance(vo.DeregisterInstanceParam{\n\t\t\tIp:          endpoint.Host(),\n\t\t\tPort:        uint64(endpoint.Port()),\n\t\t\tServiceName: service.GetName(),\n\t\t\tEphemeral:   true,\n\t\t\tCluster:     reg.clusterName,\n\t\t\tGroupName:   reg.groupName,\n\t\t}); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "contrib/registry/nacos/nacos_service.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/model\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// NewServiceFromInstance new one service from instance\nfunc NewServiceFromInstance(instance []model.Instance) gsvc.Service {\n\tn := len(instance)\n\tif n == 0 {\n\t\treturn nil\n\t}\n\tserviceName := instance[0].ServiceName\n\tendpoints := make(gsvc.Endpoints, 0, n)\n\tfor i := 0; i < n; i++ {\n\t\tif instance[0].ServiceName != serviceName {\n\t\t\treturn nil\n\t\t}\n\t\tendpoints = append(endpoints, gsvc.NewEndpoint(fmt.Sprintf(\"%s%s%d\", instance[i].Ip, gsvc.EndpointHostPortDelimiter, int(instance[i].Port))))\n\t}\n\tif gstr.Contains(serviceName, cstServiceSeparator) {\n\t\tarr := gstr.SplitAndTrim(serviceName, cstServiceSeparator)\n\t\tserviceName = arr[1]\n\t}\n\n\treturn &gsvc.LocalService{\n\t\tEndpoints: endpoints,\n\t\tName:      serviceName,\n\t\tMetadata:  gmap.NewStrStrMapFrom(instance[0].Metadata).MapStrAny(),\n\t\tVersion:   gsvc.DefaultVersion,\n\t}\n}\n\n// NewServicesFromInstances new some services from some instances\nfunc NewServicesFromInstances(instances []model.Instance) []gsvc.Service {\n\tserviceMap := map[string][]model.Instance{}\n\tfor _, inst := range instances {\n\t\tserviceMap[inst.ServiceName] = append(serviceMap[inst.ServiceName], inst)\n\t}\n\n\tservices := make([]gsvc.Service, 0, len(serviceMap))\n\tfor _, insts := range serviceMap {\n\t\tservices = append(services, NewServiceFromInstance(insts))\n\t}\n\n\treturn services\n}\n"
  },
  {
    "path": "contrib/registry/nacos/nacos_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos\n\nimport (\n\t\"context\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/model\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Watcher used to mange service event such as update.\ntype Watcher struct {\n\tctx   context.Context\n\tevent chan *watchEvent\n\tclose func() error\n}\n\n// watchEvent\ntype watchEvent struct {\n\tServices []model.Instance\n\tErr      error\n}\n\n// newWatcher new a Watcher's instance\nfunc newWatcher(ctx context.Context) *Watcher {\n\tw := &Watcher{\n\t\tctx:   ctx,\n\t\tevent: make(chan *watchEvent, 10),\n\t}\n\treturn w\n}\n\n// Proceed proceeds watch in blocking way.\n// It returns all complete services that watched by `key` if any change.\nfunc (w *Watcher) Proceed() (services []gsvc.Service, err error) {\n\te, ok := <-w.event\n\tif !ok || e == nil {\n\t\terr = gerror.NewCode(gcode.CodeNil)\n\t\treturn\n\t}\n\tif e.Err != nil {\n\t\terr = e.Err\n\t\treturn\n\t}\n\tservices = NewServicesFromInstances(e.Services)\n\treturn\n}\n\n// Close closes the watcher.\nfunc (w *Watcher) Close() (err error) {\n\tif w.close != nil {\n\t\terr = w.close()\n\t}\n\treturn\n}\n\n// SetCloseFunc set the close callback function\nfunc (w *Watcher) SetCloseFunc(close func() error) {\n\tw.close = close\n}\n\n// Push add the services watchevent to event queue\nfunc (w *Watcher) Push(services []model.Instance, err error) {\n\tw.event <- &watchEvent{\n\t\tServices: services,\n\t\tErr:      err,\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/nacos/nacos_z_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage nacos_test\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nacos-group/nacos-sdk-go/v2/common/constant\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/registry/nacos/v2\"\n)\n\nconst (\n\tNACOS_ADDRESS   = `localhost:8848`\n\tNACOS_CACHE_DIR = `/tmp/nacos`\n\tNACOS_LOG_DIR   = `/tmp/nacos`\n)\n\nfunc TestRegistry(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tregistry = nacos.New(NACOS_ADDRESS, func(cc *constant.ClientConfig) {\n\t\t\tcc.CacheDir = NACOS_CACHE_DIR\n\t\t\tcc.LogDir = NACOS_LOG_DIR\n\t\t})\n\t)\n\tsvc := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc.GetName())\n\t})\n\n\t// Search by name.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.Name,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by prefix.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tPrefix: svc.GetPrefix(),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\n\t// Search by metadata.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"https\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].GetName(), svc.Name)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := registry.Search(ctx, gsvc.SearchInput{\n\t\t\tName: svc.GetName(),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"grpc\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestWatch(t *testing.T) {\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tregistry = nacos.New(NACOS_ADDRESS, func(cc *constant.ClientConfig) {\n\t\t\tcc.CacheDir = NACOS_CACHE_DIR\n\t\t\tcc.LogDir = NACOS_LOG_DIR\n\t\t})\n\t\tregistry2 = nacos.New(NACOS_ADDRESS, func(cc *constant.ClientConfig) {\n\t\t\tcc.CacheDir = NACOS_CACHE_DIR\n\t\t\tcc.LogDir = NACOS_LOG_DIR\n\t\t})\n\t)\n\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      guid.S(),\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:8888\"),\n\t\tMetadata: map[string]any{\n\t\t\t\"protocol\": \"https\",\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistered, err := registry.Register(ctx, svc1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc1.GetName())\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := gctx.New()\n\t\twatcher, err := registry.Watch(ctx, svc1.GetPrefix())\n\t\tt.AssertNil(err)\n\n\t\tvar latestProceedResult atomic.Value\n\t\tg.Go(ctx, func(ctx context.Context) {\n\t\t\tvar (\n\t\t\t\terr error\n\t\t\t\tres []gsvc.Service\n\t\t\t)\n\t\t\tfor err == nil {\n\t\t\t\tres, err = watcher.Proceed()\n\t\t\t\tt.AssertNil(err)\n\t\t\t\tlatestProceedResult.Store(res)\n\t\t\t}\n\t\t}, func(ctx context.Context, exception error) {\n\t\t\tt.Fatal(exception)\n\t\t})\n\n\t\t// Register another service.\n\t\tsvc2 := &gsvc.LocalService{\n\t\t\tName:      svc1.Name,\n\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.2:9999\"),\n\t\t\tMetadata: map[string]any{\n\t\t\t\t\"protocol\": \"https\",\n\t\t\t},\n\t\t}\n\t\tregistered, err := registry2.Register(ctx, svc2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(registered.GetName(), svc2.GetName())\n\n\t\ttime.Sleep(time.Second * 10)\n\n\t\t// Watch and retrieve the service changes:\n\t\t// svc1 and svc2 is the same service name, which has 2 endpoints.\n\t\tproceedResult, ok := latestProceedResult.Load().([]gsvc.Service)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(len(proceedResult), 1)\n\t\tt.Assert(\n\t\t\tallEndpoints(proceedResult),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0], svc2.GetEndpoints()[0]},\n\t\t)\n\n\t\t// Watch and retrieve the service changes:\n\t\t// left only svc1, which means this service has only 1 endpoint.\n\t\terr = registry2.Deregister(ctx, svc2)\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(time.Second * 10)\n\t\tproceedResult, ok = latestProceedResult.Load().([]gsvc.Service)\n\t\tt.Assert(ok, true)\n\t\tt.Assert(len(proceedResult), 1)\n\t\tt.Assert(\n\t\t\tallEndpoints(proceedResult),\n\t\t\tgsvc.Endpoints{svc1.GetEndpoints()[0]},\n\t\t)\n\t\tt.AssertNil(watcher.Close())\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := registry.Deregister(ctx, svc1)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc allEndpoints(services []gsvc.Service) gsvc.Endpoints {\n\tm := map[gsvc.Endpoint]struct{}{}\n\tfor _, s := range services {\n\t\tfor _, ep := range s.GetEndpoints() {\n\t\t\tm[ep] = struct{}{}\n\t\t}\n\t}\n\tvar endpoints gsvc.Endpoints\n\tfor ep := range m {\n\t\tendpoints = append(endpoints, ep)\n\t}\n\treturn sortEndpoints(endpoints)\n}\n\nfunc sortEndpoints(in gsvc.Endpoints) gsvc.Endpoints {\n\tvar endpoints gsvc.Endpoints\n\tendpoints = append(endpoints, in...)\n\tn := len(endpoints)\n\tfor i := 0; i < n; i++ {\n\t\tfor t := i; t < n; t++ {\n\t\t\tif endpoints[i].String() > endpoints[t].String() {\n\t\t\t\tendpoints[i], endpoints[t] = endpoints[t], endpoints[i]\n\t\t\t}\n\t\t}\n\t}\n\treturn endpoints\n}\n"
  },
  {
    "path": "contrib/registry/polaris/README.MD",
    "content": "# GoFrame Polaris Registry\n\nEnglish | [简体中文](README_ZH.MD)\n\nUse `PolarisMesh` as service registration, discovery management and heartbeat reporting.\n\n## Installation\n\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/polaris/v2\n```\n\nsuggested using `go.mod`:\n\n```\nrequire github.com/gogf/gf/contrib/registry/polaris/v2 latest\n```\n\n## Example\n\n### Reference example\n\n[server](../../../example/registry/polaris/server/server.go)\n\n```go\npackage main\n\nimport (\n    \"github.com/polarismesh/polaris-go/pkg/config\"\n    \n    \"github.com/gogf/gf/contrib/registry/polaris/v2\"\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/ghttp\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n    conf := config.NewDefaultConfiguration([]string{\"183.47.111.80:8091\"})\n    \n    // TTL egt 2*time.Second\n    gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(10)))\n    \n    s := g.Server(`hello.svc`)\n    s.BindHandler(\"/\", func(r *ghttp.Request) {\n        g.Log().Info(r.Context(), `request received`)\n        r.Response.Write(`Hello world`)\n    })\n    s.Run()\n}\n```\n\n[client](../../../example/registry/polaris/client/client.go)\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"time\"\n    \n    \"github.com/polarismesh/polaris-go/pkg/config\"\n    \n    \"github.com/gogf/gf/contrib/registry/polaris/v2\"\n    \n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n    conf := config.NewDefaultConfiguration([]string{\"183.47.111.80:8091\"})\n    \n    gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(10)))\n    \n    for i := 0; i < 100; i++ {\n        res, err := g.Client().Get(gctx.New(), `http://hello.svc/`)\n        if err != nil {\n            panic(err)\n        }\n        fmt.Println(res.ReadAllString())\n        res.Close()\n        time.Sleep(time.Second)\n    }\n}\n```\n\n## License\n\n`GoFrame Polaris` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n\n"
  },
  {
    "path": "contrib/registry/polaris/README_ZH.MD",
    "content": "# GoFrame Polaris Registry\n\n[English](README.MD) | 简体中文\n\n使用`PolarisMesh`作为服务注册、发现管理和心跳上报。\n\n## 安装\n\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/polaris/v2\n```\n\nsuggested using `go.mod`:\n\n```\nrequire github.com/gogf/gf/contrib/registry/polaris/v2 latest\n```\n\n## Golang版本限制\n\n```\ngolang version >= 1.20\n```\n\n## 示例\n\n### 引用示例\n\n[服务端](example/registry/polaris/server/main.go)\n\n```go\npackage main\n\nimport (\n    \"github.com/polarismesh/polaris-go/pkg/config\"\n    \n    \"github.com/gogf/gf/contrib/registry/polaris/v2\"\n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/ghttp\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n    conf := config.NewDefaultConfiguration([]string{\"183.47.111.80:8091\"})\n    \n    // TTL egt 2*time.Second\n    gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(10)))\n    \n    s := g.Server(`hello.svc`)\n    s.BindHandler(\"/\", func(r *ghttp.Request) {\n        g.Log().Info(r.Context(), `request received`)\n        r.Response.Write(`Hello world`)\n    })\n    s.Run()\n}\n\n```\n\n[客户端](example/registry/polaris/client/main.go)\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"time\"\n    \n    \"github.com/polarismesh/polaris-go/pkg/config\"\n    \n    \"github.com/gogf/gf/contrib/registry/polaris/v2\"\n    \n    \"github.com/gogf/gf/v2/frame/g\"\n    \"github.com/gogf/gf/v2/net/gsvc\"\n    \"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n    conf := config.NewDefaultConfiguration([]string{\"183.47.111.80:8091\"})\n    \n    gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(10)))\n    \n    for i := 0; i < 100; i++ {\n        res, err := g.Client().Get(gctx.New(), `http://hello.svc/`)\n        if err != nil {\n            panic(err)\n        }\n        fmt.Println(res.ReadAllString())\n        res.Close()\n        time.Sleep(time.Second)\n    }\n}\n\n```\n\n## 协议\n\n`GoFrame Polaris` 使用非常友好的 [MIT](../../../LICENSE) 开源协议进行发布，永久`100%`开源免费。\n"
  },
  {
    "path": "contrib/registry/polaris/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/polaris/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgithub.com/polarismesh/polaris-go v1.6.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.1.2 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/dlclark/regexp2 v1.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/protobuf v1.5.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.0.0 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/natefinch/lumberjack v2.0.0+incompatible // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/polarismesh/specification v1.5.5-alpha.1 // indirect\n\tgithub.com/prometheus/client_golang v1.12.2 // indirect\n\tgithub.com/prometheus/client_model v0.2.0 // indirect\n\tgithub.com/prometheus/common v0.32.1 // indirect\n\tgithub.com/prometheus/procfs v0.7.3 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/spaolacci/murmur3 v1.1.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgo.uber.org/zap v1.21.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect\n\tgoogle.golang.org/grpc v1.51.0 // indirect\n\tgoogle.golang.org/protobuf v1.28.1 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/polaris/go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=\ncloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=\ncloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=\ncloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=\ncloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=\ncloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=\ncloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=\ncloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=\ncloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=\ncloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=\ncloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=\ncloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=\ncloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=\ncloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=\ncloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=\ncloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=\ncloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=\ncloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=\ncloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=\ncloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=\ncloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=\ncloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=\ncloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=\ncloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=\ncloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=\ncloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=\ncloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=\ncloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=\ncloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=\ncloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=\ncloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=\ncloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=\ncloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=\ncloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=\ncloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=\ncloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=\ncloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=\ncloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=\ncloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=\ncloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=\ncloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=\ncloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=\ncloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=\ncloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=\ncloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=\ncloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=\ncloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=\ncloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=\ncloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=\ncloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=\ncloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=\ncloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=\ncloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=\ncloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=\ncloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=\ncloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=\ncloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=\ncloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=\ncloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=\ncloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=\ncloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=\ncloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=\ncloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=\ncloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=\ncloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=\ncloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=\ncloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=\ncloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=\ncloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=\ncloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=\ncloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=\ncloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=\ncloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=\ncloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=\ncloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=\ncloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=\ncloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=\ncloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=\ncloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=\ncloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=\ncloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=\ncloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=\ncloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=\ncloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=\ncloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=\ncloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=\ncloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=\ncloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=\ncloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=\ncloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=\ncloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=\ncloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=\ncloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=\ncloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=\ncloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=\ncloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=\ncloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=\ncloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=\ncloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=\ncloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=\ncloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=\ncloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=\ncloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=\ncloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=\ncloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=\ncloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=\ncloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=\ncloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=\ncloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=\ncloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=\ncloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=\ncloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=\ncloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=\ncloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=\ncloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ncloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=\ncloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=\ncloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=\ncloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=\ncloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=\ncloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=\ncloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=\ncloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=\ncloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=\ncloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=\ncloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=\ncloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=\ncloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=\ngithub.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc=\ngithub.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg=\ngithub.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y=\ngithub.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks=\ngithub.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A=\ngithub.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=\ngithub.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=\ngithub.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=\ngithub.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=\ngithub.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=\ngithub.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=\ngithub.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=\ngithub.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/polarismesh/polaris-go v1.6.1 h1:dNhYZVpO4eTLEV+mm4uBRT2YAdzPsMsPs2or8KDjOhM=\ngithub.com/polarismesh/polaris-go v1.6.1/go.mod h1:gGEe8mz4qMv199gzc+Bf8rmzOxuPox7aiEoHRNH3OKQ=\ngithub.com/polarismesh/specification v1.5.5-alpha.1 h1:lGLaj+I6iD25F0FuQnR83sR+1SJ8KqykS0vCnGx2ZAQ=\ngithub.com/polarismesh/specification v1.5.5-alpha.1/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=\ngithub.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=\ngithub.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=\ngithub.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=\ngo.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=\ngolang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=\ngoogle.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=\ngoogle.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=\ngoogle.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=\ngoogle.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=\ngoogle.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=\ngoogle.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=\ngoogle.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=\ngoogle.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=\ngoogle.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=\ngoogle.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=\ngoogle.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=\ngoogle.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=\ngoogle.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=\ngoogle.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=\ngoogle.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=\ngoogle.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=\ngoogle.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=\ngoogle.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=\ngoogle.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=\ngoogle.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=\ngoogle.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=\ngoogle.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=\ngoogle.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=\ngoogle.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=\ngoogle.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=\ngoogle.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=\ngoogle.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=\ngoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a h1:GH6UPn3ixhWcKDhpnEC55S75cerLPdpp3hrhfKYjZgw=\ngoogle.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=\ngoogle.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=\ngoogle.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=\ngoogle.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=\ngoogle.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "contrib/registry/polaris/polaris.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package polaris implements service Registry and Discovery using polaris.\npackage polaris\n\nimport (\n\t\"time\"\n\n\t\"github.com/polarismesh/polaris-go\"\n\t\"github.com/polarismesh/polaris-go/pkg/config\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\nvar (\n\t_ gsvc.Registry = &Registry{}\n)\n\nconst (\n\tinstanceIDSeparator = \"-\"\n\tmetadataKeyKind     = \"kind\"\n\tmetadataKeyVersion  = \"version\"\n)\n\ntype options struct {\n\t// required, namespace in polaris\n\tNamespace string\n\n\t// required, service access token\n\tServiceToken string\n\n\t// optional, protocol in polaris. Default value is nil, it means use protocol config in service\n\tProtocol *string\n\n\t// service weight in polaris. Default value is 100, 0 <= weight <= 10000\n\tWeight int\n\n\t// service priority. Default value is 0. The smaller the value, the lower the priority\n\tPriority int\n\n\t// To show service is healthy or not. Default value is True.\n\tHealthy bool\n\n\t// To show service is isolate or not. Default value is False.\n\tIsolate bool\n\n\t// TTL timeout. if the node needs to use a heartbeat to report, required. If not set,server will throw ErrorCode-400141\n\tTTL int\n\n\t// Timeout for the single query. Default value is global config\n\t// Total is (1+RetryCount) * Timeout\n\tTimeout time.Duration\n\n\t// optional, retry count. Default value is global config\n\tRetryCount int\n\n\t// optional, logger for polaris\n\tLogger glog.ILogger\n}\n\n// Option The option is a polaris option.\ntype Option func(o *options)\n\n// Registry is polaris registry.\ntype Registry struct {\n\topt      options\n\tprovider polaris.ProviderAPI\n\tconsumer polaris.ConsumerAPI\n}\n\n// WithNamespace with the Namespace option.\nfunc WithNamespace(namespace string) Option {\n\treturn func(o *options) { o.Namespace = namespace }\n}\n\n// WithServiceToken with ServiceToken option.\nfunc WithServiceToken(serviceToken string) Option {\n\treturn func(o *options) { o.ServiceToken = serviceToken }\n}\n\n// WithProtocol with the Protocol option.\nfunc WithProtocol(protocol string) Option {\n\treturn func(o *options) { o.Protocol = &protocol }\n}\n\n// WithWeight with the Weight option.\nfunc WithWeight(weight int) Option {\n\treturn func(o *options) { o.Weight = weight }\n}\n\n// WithHealthy with the Healthy option.\nfunc WithHealthy(healthy bool) Option {\n\treturn func(o *options) { o.Healthy = healthy }\n}\n\n// WithIsolate with the Isolate option.\nfunc WithIsolate(isolate bool) Option {\n\treturn func(o *options) { o.Isolate = isolate }\n}\n\n// WithTTL with the TTL option.\nfunc WithTTL(TTL int) Option {\n\treturn func(o *options) { o.TTL = TTL }\n}\n\n// WithTimeout the Timeout option.\nfunc WithTimeout(timeout time.Duration) Option {\n\treturn func(o *options) { o.Timeout = timeout }\n}\n\n// WithRetryCount with RetryCount option.\nfunc WithRetryCount(retryCount int) Option {\n\treturn func(o *options) { o.RetryCount = retryCount }\n}\n\n// WithLogger with the Logger option.\nfunc WithLogger(logger glog.ILogger) Option {\n\treturn func(o *options) { o.Logger = logger }\n}\n\n// New create a new registry.\nfunc New(provider polaris.ProviderAPI, consumer polaris.ConsumerAPI, opts ...Option) gsvc.Registry {\n\top := options{\n\t\tNamespace:    gsvc.DefaultNamespace,\n\t\tServiceToken: \"\",\n\t\tProtocol:     nil,\n\t\tWeight:       100,\n\t\tPriority:     0,\n\t\tHealthy:      true,\n\t\tIsolate:      false,\n\t\tTTL:          0,\n\t\tTimeout:      0,\n\t\tRetryCount:   0,\n\t\tLogger:       g.Log(),\n\t}\n\tfor _, option := range opts {\n\t\toption(&op)\n\t}\n\treturn &Registry{\n\t\topt:      op,\n\t\tprovider: provider,\n\t\tconsumer: consumer,\n\t}\n}\n\n// NewWithConfig new a registry with config.\nfunc NewWithConfig(conf config.Configuration, opts ...Option) gsvc.Registry {\n\tprovider, err := polaris.NewProviderAPIByConfig(conf)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tconsumer, err := polaris.NewConsumerAPIByConfig(conf)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn New(provider, consumer, opts...)\n}\n"
  },
  {
    "path": "contrib/registry/polaris/polaris_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage polaris\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/polarismesh/polaris-go\"\n\t\"github.com/polarismesh/polaris-go/pkg/model\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Search returns the service instances in memory according to the service name.\nfunc (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {\n\tif in.Prefix == \"\" && in.Name != \"\" {\n\t\tservice := &Service{\n\t\t\tService: gsvc.NewServiceWithName(in.Name),\n\t\t}\n\t\tin.Prefix = service.GetPrefix()\n\t}\n\tin.Prefix = trimAndReplace(in.Prefix)\n\t// get instances\n\tinstancesResponse, err := r.consumer.GetInstances(&polaris.GetInstancesRequest{\n\t\tGetInstancesRequest: model.GetInstancesRequest{\n\t\t\tService:    in.Prefix,\n\t\t\tNamespace:  r.opt.Namespace,\n\t\t\tTimeout:    &r.opt.Timeout,\n\t\t\tRetryCount: &r.opt.RetryCount,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tserviceInstances := instancesToServiceInstances(instancesResponse.GetInstances())\n\t// Service filter.\n\tfilteredServices := make([]gsvc.Service, 0)\n\tfor _, service := range serviceInstances {\n\t\tif in.Prefix != \"\" && !gstr.HasPrefix(trimAndReplace(service.GetKey()), in.Prefix) {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Name != \"\" && service.GetName() != in.Name {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Version != \"\" && service.GetVersion() != in.Version {\n\t\t\tcontinue\n\t\t}\n\t\tif len(in.Metadata) != 0 {\n\t\t\tm1 := gmap.NewStrAnyMapFrom(in.Metadata)\n\t\t\tm2 := gmap.NewStrAnyMapFrom(service.GetMetadata())\n\t\t\tif !m1.IsSubOf(m2) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresultItem := service\n\t\tfilteredServices = append(filteredServices, resultItem)\n\t}\n\treturn filteredServices, nil\n}\n\n// Watch creates a watcher according to the service name.\nfunc (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {\n\treturn newWatcher(ctx, r.opt.Namespace, trimAndReplace(key), r.consumer)\n}\n\nfunc instancesToServiceInstances(instances []model.Instance) []gsvc.Service {\n\tvar (\n\t\tserviceInstances = make([]gsvc.Service, 0, len(instances))\n\t\tendpointStr      bytes.Buffer\n\t)\n\n\tfor _, instance := range instances {\n\t\tif instance.IsHealthy() {\n\t\t\tendpointStr.WriteString(fmt.Sprintf(\"%s:%d%s\", instance.GetHost(), instance.GetPort(), gsvc.EndpointsDelimiter))\n\t\t}\n\t}\n\tif endpointStr.Len() > 0 {\n\t\tfor _, instance := range instances {\n\t\t\tif instance.IsHealthy() {\n\t\t\t\tserviceInstances = append(serviceInstances, instanceToServiceInstance(instance, gstr.TrimRight(endpointStr.String(), gsvc.EndpointsDelimiter), \"\"))\n\t\t\t}\n\t\t}\n\t}\n\treturn serviceInstances\n}\n\n// instanceToServiceInstance converts the instance to service instance.\n// instanceID Must be null when creating and adding, and non-null when updating and deleting\nfunc instanceToServiceInstance(instance model.Instance, endpointStr, instanceID string) gsvc.Service {\n\tvar (\n\t\ts         *gsvc.LocalService\n\t\tmetadata  = instance.GetMetadata()\n\t\tnames     = strings.Split(instance.GetService(), instanceIDSeparator)\n\t\tendpoints = gsvc.NewEndpoints(endpointStr)\n\t)\n\tif names != nil && len(names) > 4 {\n\t\tvar name bytes.Buffer\n\t\tfor i := 3; i < len(names)-1; i++ {\n\t\t\tname.WriteString(names[i])\n\t\t\tif i < len(names)-2 {\n\t\t\t\tname.WriteString(instanceIDSeparator)\n\t\t\t}\n\t\t}\n\t\ts = &gsvc.LocalService{\n\t\t\tHead:       names[0],\n\t\t\tDeployment: names[1],\n\t\t\tNamespace:  names[2],\n\t\t\tName:       name.String(),\n\t\t\tVersion:    metadata[metadataKeyVersion],\n\t\t\tMetadata:   gconv.Map(metadata),\n\t\t\tEndpoints:  endpoints,\n\t\t}\n\t} else {\n\t\ts = &gsvc.LocalService{\n\t\t\tName:      instance.GetService(),\n\t\t\tNamespace: instance.GetNamespace(),\n\t\t\tVersion:   metadata[metadataKeyVersion],\n\t\t\tMetadata:  gconv.Map(metadata),\n\t\t\tEndpoints: endpoints,\n\t\t}\n\t}\n\tservice := &Service{\n\t\tService: s,\n\t}\n\tif instance.GetId() != \"\" {\n\t\tservice.ID = instance.GetId()\n\t}\n\tif gstr.Trim(instanceID) != \"\" {\n\t\tservice.ID = instanceID\n\t}\n\treturn service\n}\n\n// trimAndReplace trims the prefix and suffix separator and replaces the separator in the middle.\nfunc trimAndReplace(key string) string {\n\tkey = gstr.Trim(key, gsvc.DefaultSeparator)\n\tkey = gstr.Replace(key, gsvc.DefaultSeparator, instanceIDSeparator)\n\treturn key\n}\n"
  },
  {
    "path": "contrib/registry/polaris/polaris_registry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage polaris\n\nimport (\n\t\"context\"\n\n\t\"github.com/polarismesh/polaris-go\"\n\t\"github.com/polarismesh/polaris-go/pkg/model\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Register the registration.\nfunc (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Service, error) {\n\t// Replace input service to custom service types.\n\tservice = &Service{\n\t\tService: service,\n\t}\n\t// Register logic.\n\tvar ids = make([]string, 0, len(service.GetEndpoints()))\n\tfor _, endpoint := range service.GetEndpoints() {\n\t\t// medata\n\t\tvar (\n\t\t\trmd            map[string]any\n\t\t\tserviceName    = service.GetPrefix()\n\t\t\tserviceVersion = service.GetVersion()\n\t\t)\n\t\tif service.GetMetadata().IsEmpty() {\n\t\t\trmd = map[string]any{\n\t\t\t\tmetadataKeyKind:    gsvc.DefaultProtocol,\n\t\t\t\tmetadataKeyVersion: serviceVersion,\n\t\t\t}\n\t\t} else {\n\t\t\trmd = make(map[string]any, len(service.GetMetadata())+2)\n\t\t\trmd[metadataKeyKind] = gsvc.DefaultProtocol\n\t\t\tif protocol, ok := service.GetMetadata()[gsvc.MDProtocol]; ok {\n\t\t\t\trmd[metadataKeyKind] = gconv.String(protocol)\n\t\t\t}\n\t\t\trmd[metadataKeyVersion] = serviceVersion\n\t\t\tfor k, v := range service.GetMetadata() {\n\t\t\t\trmd[k] = v\n\t\t\t}\n\t\t}\n\t\t// Register RegisterInstance Service registration is performed synchronously,\n\t\t// and heartbeat reporting is automatically performed\n\t\tregisteredService, err := r.provider.RegisterInstance(\n\t\t\t&polaris.InstanceRegisterRequest{\n\t\t\t\tInstanceRegisterRequest: model.InstanceRegisterRequest{\n\t\t\t\t\tService:      serviceName,\n\t\t\t\t\tServiceToken: r.opt.ServiceToken,\n\t\t\t\t\tNamespace:    r.opt.Namespace,\n\t\t\t\t\tHost:         endpoint.Host(),\n\t\t\t\t\tPort:         endpoint.Port(),\n\t\t\t\t\tProtocol:     r.opt.Protocol,\n\t\t\t\t\tWeight:       &r.opt.Weight,\n\t\t\t\t\tPriority:     &r.opt.Priority,\n\t\t\t\t\tVersion:      &serviceVersion,\n\t\t\t\t\tMetadata:     gconv.MapStrStr(rmd),\n\t\t\t\t\tHealthy:      &r.opt.Healthy,\n\t\t\t\t\tIsolate:      &r.opt.Isolate,\n\t\t\t\t\tTTL:          &r.opt.TTL,\n\t\t\t\t\tTimeout:      &r.opt.Timeout,\n\t\t\t\t\tRetryCount:   &r.opt.RetryCount,\n\t\t\t\t},\n\t\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tids = append(ids, registeredService.InstanceID)\n\t}\n\t// need to set InstanceID for Deregister\n\tservice.(*Service).ID = gstr.Join(ids, instanceIDSeparator)\n\treturn service, nil\n}\n\n// Deregister the registration.\nfunc (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {\n\tvar (\n\t\terr   error\n\t\tsplit = gstr.Split(service.(*Service).ID, instanceIDSeparator)\n\t)\n\tfor i, endpoint := range service.GetEndpoints() {\n\t\t// Deregister\n\t\terr = r.provider.Deregister(\n\t\t\t&polaris.InstanceDeRegisterRequest{\n\t\t\t\tInstanceDeRegisterRequest: model.InstanceDeRegisterRequest{\n\t\t\t\t\tService:      service.GetPrefix(),\n\t\t\t\t\tServiceToken: r.opt.ServiceToken,\n\t\t\t\t\tNamespace:    r.opt.Namespace,\n\t\t\t\t\tInstanceID:   split[i],\n\t\t\t\t\tHost:         endpoint.Host(),\n\t\t\t\t\tPort:         endpoint.Port(),\n\t\t\t\t\tTimeout:      &r.opt.Timeout,\n\t\t\t\t\tRetryCount:   &r.opt.RetryCount,\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "contrib/registry/polaris/polaris_service.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage polaris\n\nimport (\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Service for wrapping gsvc.Server and extends extra attributes for polaris purpose.\ntype Service struct {\n\tgsvc.Service        // Common service object.\n\tID           string // ID is the unique instance ID as registered, for some registrar server.\n}\n\n// GetKey overwrites the GetKey function of gsvc.Service for replacing separator string.\nfunc (s *Service) GetKey() string {\n\tkey := s.Service.GetKey()\n\tkey = gstr.Replace(key, gsvc.DefaultSeparator, instanceIDSeparator)\n\tkey = gstr.TrimLeft(key, instanceIDSeparator)\n\treturn key\n}\n\n// GetPrefix overwrites the GetPrefix function of gsvc.Service for replacing separator string.\nfunc (s *Service) GetPrefix() string {\n\tprefix := s.Service.GetPrefix()\n\tprefix = gstr.Replace(prefix, gsvc.DefaultSeparator, instanceIDSeparator)\n\tprefix = gstr.TrimLeft(prefix, instanceIDSeparator)\n\treturn prefix\n}\n"
  },
  {
    "path": "contrib/registry/polaris/polaris_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage polaris\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/polarismesh/polaris-go\"\n\t\"github.com/polarismesh/polaris-go/pkg/model\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Watcher is a service watcher.\ntype Watcher struct {\n\tServiceName      string\n\tNamespace        string\n\tCtx              context.Context\n\tCancel           context.CancelFunc\n\tChannel          <-chan model.SubScribeEvent\n\tServiceInstances []gsvc.Service\n}\n\nfunc newWatcher(ctx context.Context, namespace string, key string, consumer polaris.ConsumerAPI) (*Watcher, error) {\n\twatchServiceResponse, err := consumer.WatchService(&polaris.WatchServiceRequest{\n\t\tWatchServiceRequest: model.WatchServiceRequest{\n\t\t\tKey: model.ServiceKey{\n\t\t\t\tNamespace: namespace,\n\t\t\t\tService:   key,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tw := &Watcher{\n\t\tNamespace:        namespace,\n\t\tServiceName:      key,\n\t\tChannel:          watchServiceResponse.EventChannel,\n\t\tServiceInstances: instancesToServiceInstances(watchServiceResponse.GetAllInstancesResp.GetInstances()),\n\t}\n\tw.Ctx, w.Cancel = context.WithCancel(ctx)\n\treturn w, nil\n}\n\n// Proceed returns services in the following two cases:\n// 1.the first time to watch and the service instance list is not empty.\n// 2.any service instance changes found.\n// if the above two conditions are not met, it will block until the context deadline is exceeded or canceled\nfunc (w *Watcher) Proceed() ([]gsvc.Service, error) {\n\tselect {\n\tcase <-w.Ctx.Done():\n\t\treturn nil, w.Ctx.Err()\n\tcase event := <-w.Channel:\n\t\tif event.GetSubScribeEventType() == model.EventInstance {\n\t\t\t// these are always true, but we need to check it to make sure EventType not change\n\t\t\tinstanceEvent, ok := event.(*model.InstanceEvent)\n\t\t\tif !ok {\n\t\t\t\treturn w.ServiceInstances, nil\n\t\t\t}\n\t\t\t// handle DeleteEvent\n\t\t\tif instanceEvent.DeleteEvent != nil {\n\t\t\t\tvar endpointStr bytes.Buffer\n\t\t\t\tfor _, instance := range instanceEvent.DeleteEvent.Instances {\n\t\t\t\t\t// Iterate through existing service instances, deleting them if they exist\n\t\t\t\t\tfor i, serviceInstance := range w.ServiceInstances {\n\t\t\t\t\t\tif serviceInstance.(*Service).ID == instance.GetId() {\n\t\t\t\t\t\t\tendpointStr.WriteString(fmt.Sprintf(\"%s:%d%s\", instance.GetHost(), instance.GetPort(), gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t\tif len(w.ServiceInstances) <= 1 {\n\t\t\t\t\t\t\t\tw.ServiceInstances = w.ServiceInstances[0:0]\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tw.ServiceInstances = append(w.ServiceInstances[:i], w.ServiceInstances[i+1:]...)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif endpointStr.Len() > 0 && len(w.ServiceInstances) > 0 {\n\t\t\t\t\tvar (\n\t\t\t\t\t\tnewEndpointStr     bytes.Buffer\n\t\t\t\t\t\tserviceEndpointStr = w.ServiceInstances[0].(*Service).GetEndpoints().String()\n\t\t\t\t\t)\n\t\t\t\t\tfor _, address := range gstr.SplitAndTrim(serviceEndpointStr, gsvc.EndpointsDelimiter) {\n\t\t\t\t\t\tif !gstr.Contains(endpointStr.String(), address) {\n\t\t\t\t\t\t\tnewEndpointStr.WriteString(fmt.Sprintf(\"%s%s\", address, gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor i := 0; i < len(w.ServiceInstances); i++ {\n\t\t\t\t\t\tw.ServiceInstances[i] = instanceToServiceInstance(instanceEvent.DeleteEvent.Instances[0], gstr.TrimRight(newEndpointStr.String(), gsvc.EndpointsDelimiter), w.ServiceInstances[i].(*Service).ID)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// handle UpdateEvent\n\t\t\tif instanceEvent.UpdateEvent != nil {\n\t\t\t\tvar (\n\t\t\t\t\tupdateEndpointStr bytes.Buffer\n\t\t\t\t\tnewEndpointStr    bytes.Buffer\n\t\t\t\t)\n\t\t\t\tfor _, serviceInstance := range w.ServiceInstances {\n\t\t\t\t\t// update the current department or all instances\n\t\t\t\t\tfor _, update := range instanceEvent.UpdateEvent.UpdateList {\n\t\t\t\t\t\tif serviceInstance.(*Service).ID == update.Before.GetId() {\n\t\t\t\t\t\t\t// update equal\n\t\t\t\t\t\t\tif update.After.IsHealthy() {\n\t\t\t\t\t\t\t\tnewEndpointStr.WriteString(fmt.Sprintf(\"%s:%d%s\", update.After.GetHost(), update.After.GetPort(), gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tupdateEndpointStr.WriteString(fmt.Sprintf(\"%s:%d%s\", update.Before.GetHost(), update.Before.GetPort(), gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(w.ServiceInstances) > 0 {\n\t\t\t\t\tvar serviceEndpointStr = w.ServiceInstances[0].(*Service).GetEndpoints().String()\n\t\t\t\t\t// old instance addresses are culled\n\t\t\t\t\tif updateEndpointStr.Len() > 0 {\n\t\t\t\t\t\tfor _, address := range gstr.SplitAndTrim(serviceEndpointStr, gsvc.EndpointsDelimiter) {\n\t\t\t\t\t\t\t// If the historical instance is not in the change instance, it remains\n\t\t\t\t\t\t\tif !gstr.Contains(updateEndpointStr.String(), address) {\n\t\t\t\t\t\t\t\tnewEndpointStr.WriteString(fmt.Sprintf(\"%s%s\", address, gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tinstance := instanceEvent.UpdateEvent.UpdateList[0].After\n\t\t\t\t\tfor i := 0; i < len(w.ServiceInstances); i++ {\n\t\t\t\t\t\tw.ServiceInstances[i] = instanceToServiceInstance(instance, gstr.TrimRight(newEndpointStr.String(), gsvc.EndpointsDelimiter), w.ServiceInstances[i].(*Service).ID)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// handle AddEvent\n\t\t\tif instanceEvent.AddEvent != nil {\n\t\t\t\tvar (\n\t\t\t\t\tnewEndpointStr bytes.Buffer\n\t\t\t\t\tallEndpointStr string\n\t\t\t\t)\n\t\t\t\tif len(w.ServiceInstances) > 0 {\n\t\t\t\t\tallEndpointStr = w.ServiceInstances[0].(*Service).GetEndpoints().String()\n\t\t\t\t}\n\t\t\t\tfor i := 0; i < len(instanceEvent.AddEvent.Instances); i++ {\n\t\t\t\t\tinstance := instanceEvent.AddEvent.Instances[i]\n\t\t\t\t\tif instance.IsHealthy() {\n\t\t\t\t\t\taddress := fmt.Sprintf(\"%s:%d\", instance.GetHost(), instance.GetPort())\n\t\t\t\t\t\tif !gstr.Contains(allEndpointStr, address) {\n\t\t\t\t\t\t\tnewEndpointStr.WriteString(fmt.Sprintf(\"%s%s\", address, gsvc.EndpointsDelimiter))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif newEndpointStr.Len() > 0 {\n\t\t\t\t\tallEndpointStr = fmt.Sprintf(\"%s%s\", newEndpointStr.String(), allEndpointStr)\n\t\t\t\t}\n\t\t\t\tfor i := 0; i < len(w.ServiceInstances); i++ {\n\t\t\t\t\tw.ServiceInstances[i] = instanceToServiceInstance(instanceEvent.AddEvent.Instances[0], gstr.TrimRight(allEndpointStr, gsvc.EndpointsDelimiter), w.ServiceInstances[i].(*Service).ID)\n\t\t\t\t}\n\n\t\t\t\tfor i := 0; i < len(instanceEvent.AddEvent.Instances); i++ {\n\t\t\t\t\tinstance := instanceEvent.AddEvent.Instances[i]\n\t\t\t\t\tif instance.IsHealthy() {\n\t\t\t\t\t\tw.ServiceInstances = append(w.ServiceInstances, instanceToServiceInstance(instance, gstr.TrimRight(allEndpointStr, gsvc.EndpointsDelimiter), \"\"))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn w.ServiceInstances, nil\n}\n\n// Close the watcher.\nfunc (w *Watcher) Close() error {\n\tw.Cancel()\n\treturn nil\n}\n"
  },
  {
    "path": "contrib/registry/polaris/polaris_z_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage polaris\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/polarismesh/polaris-go/api\"\n\t\"github.com/polarismesh/polaris-go/pkg/config\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// TestRegistry_Register TestRegistryManyService\nfunc TestRegistry_Register(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-registry/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-registry/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-register-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestRegistry_Deregister TestRegistryManyService\nfunc TestRegistry_Deregister(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-registry/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-registry/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-deregister-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestRegistryMany TestRegistryManyService\nfunc TestRegistryMany(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-registry-many/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-registry-many/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-1-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-2-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9001\"),\n\t}\n\tsvc2 := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-3-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9002\"),\n\t}\n\n\ts0, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts2, err := r.Register(context.Background(), svc2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s0); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s2); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestRegistry_Search Test GetService\nfunc TestRegistry_Search(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-get-service/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-get-service/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-4-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttime.Sleep(time.Second * 1)\n\tserviceInstances, err := r.Search(context.Background(), gsvc.SearchInput{\n\t\tPrefix:   s.GetPrefix(),\n\t\tName:     svc.Name,\n\t\tVersion:  svc.Version,\n\t\tMetadata: svc.Metadata,\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range serviceInstances {\n\t\tt.Log(instance)\n\t}\n\n\tif err = r.Deregister(context.Background(), s); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestRegistry_Watch Test Watch\nfunc TestRegistry_Watch(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-watch/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-watch/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-5-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts := &Service{\n\t\tService: svc,\n\t}\n\n\twatch, err := r.Watch(context.Background(), s.GetPrefix())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Register service success svc instance id:\", s1.(*Service).ID)\n\t// watch svc\n\ttime.Sleep(time.Second * 1)\n\n\t// svc register, AddEvent\n\tnext, err := watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output one instance\n\t\tt.Log(\"Register Proceed service: \", instance.GetEndpoints().String())\n\t}\n\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tt.Log(\"Deregister Proceed first delete service: \", instance.GetEndpoints().String(), \", instance id: \", instance.(*Service).ID)\n\t}\n\n\tif err = watch.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err = watch.Proceed(); err == nil {\n\t\t// if nil, stop failed\n\t\tt.Fatal()\n\t}\n\tt.Log(\"Watch close success\")\n}\n\n// TestWatcher_Proceed Test Watch\nfunc TestWatcher_Proceed(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-watch/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-watch/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-5-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts := &Service{\n\t\tService: svc,\n\t}\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-5-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9001\"),\n\t}\n\n\twatch, err := r.Watch(context.Background(), s.GetPrefix())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Register service success svc instance id:\", s1.(*Service).ID)\n\ts22, err := r.Register(context.Background(), svc1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Register service success svc1 instance id:\", s22.(*Service).ID)\n\t// watch svc\n\ttime.Sleep(time.Second * 1)\n\n\t// svc register, AddEvent\n\tnext, err := watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output one instance\n\t\tt.Log(\"Register Proceed service: \", instance.GetEndpoints().String())\n\t}\n\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tt.Log(\"Deregister Proceed first delete service: \", instance.GetEndpoints().String(), \", instance id: \", instance.(*Service).ID)\n\t}\n\n\t// ReRegister\n\ts1, err = r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Register service Regin register svc instance id:\", s1.(*Service).ID)\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tt.Log(\"Deregister Proceed second register service: \", instance.GetEndpoints().String(), \", instance id: \", instance.(*Service).ID)\n\t}\n\n\tif err = r.Deregister(context.Background(), s22); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tt.Log(\"Deregister Proceed second delete service: \", instance.GetEndpoints().String(), \", instance id: \", instance.(*Service).ID)\n\t}\n\n\t// svc register, deleteEvent Deregister s1\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tt.Log(\"Deregister Proceed third delete service: \", instance.GetEndpoints().String(), \", instance id: \", instance.(*Service).ID)\n\t}\n\n\tif err = watch.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err = watch.Proceed(); err == nil {\n\t\t// if nil, stop failed\n\t\tt.Fatal()\n\t}\n\tt.Log(\"Watch close success\")\n}\n\n// BenchmarkRegister\nfunc BenchmarkRegister(b *testing.B) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-registry/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-registry/log\"); err != nil {\n\t\tb.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-0-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\tfor i := 0; i < b.N; i++ {\n\t\ts, err := r.Register(context.Background(), svc)\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\n\t\tif err = r.Deregister(context.Background(), s); err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n}\n\n// TestRegistryManyForEndpoints TestRegistryManyForEndpointsService\nfunc TestRegistryManyForEndpoints(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-registry-many/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-registry-many/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tvar (\n\t\tserviceName   = \"goframe-provider-tcp\"\n\t\tversion       = \"latest\"\n\t\tendpointOne   = \"127.0.0.1:9000\"\n\t\tendpointTwo   = \"127.0.0.1:9001\"\n\t\tendpointThree = \"127.0.0.1:9002\"\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      serviceName,\n\t\tVersion:   version,\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(endpointOne),\n\t}\n\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      serviceName,\n\t\tVersion:   version,\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(endpointTwo),\n\t}\n\n\tsvc2 := &gsvc.LocalService{\n\t\tName:      serviceName,\n\t\tVersion:   version,\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(endpointThree),\n\t}\n\n\t// svc register, AddEvent\n\ts0, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc register, AddEvent\n\ts1, err := r.Register(context.Background(), svc1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc register, AddEvent\n\ts2, err := r.Register(context.Background(), svc2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Register service success sleep 1s\")\n\ttime.Sleep(time.Second * 2)\n\n\t// serviceName = \"service-default-default-goframe-provider-tcp-latest\"\n\tresult, err := r.Search(context.Background(), gsvc.SearchInput{\n\t\tName: serviceName,\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(\"Search service success size:\", len(result))\n\tfor i := 0; i < len(result); i++ {\n\t\tt.Log(\"Endpoints:\", result[i].GetEndpoints().String())\n\t\tif !gstr.Contains(result[i].GetEndpoints().String(), endpointOne) {\n\t\t\tt.Fatal(\"endpointOne not found\")\n\t\t}\n\t\tif !gstr.Contains(result[i].GetEndpoints().String(), endpointTwo) {\n\t\t\tt.Fatal(\"endpointTwo not found\")\n\t\t}\n\t\tif !gstr.Contains(result[i].GetEndpoints().String(), endpointThree) {\n\t\t\tt.Fatal(\"endpointThree not found\")\n\t\t}\n\t}\n\tt.Log(\"Search service success sleep 1s\")\n\ttime.Sleep(time.Second * 1)\n\tif err = r.Deregister(context.Background(), s0); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = r.Deregister(context.Background(), s2); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tt.Log(\"Deregister success\")\n}\n\n// TestWatcher_Close Test Close\nfunc TestWatcher_Close(t *testing.T) {\n\tconf := config.NewDefaultConfiguration([]string{\"127.0.0.1:8091\"})\n\tconf.GetGlobal().GetStatReporter().SetEnable(false)\n\tconf.Consumer.LocalCache.SetPersistDir(os.TempDir() + \"/polaris-watch/backup\")\n\tif err := api.SetLoggersDir(os.TempDir() + \"/polaris-watch/log\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tr := NewWithConfig(\n\t\tconf,\n\t\tWithTimeout(time.Second*10),\n\t\tWithTTL(100),\n\t)\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-close-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts := &Service{\n\t\tService: svc,\n\t}\n\n\twatch, err := r.Watch(context.Background(), s.GetPrefix())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// watch svc\n\ttime.Sleep(time.Second * 1)\n\tif err = r.Deregister(context.Background(), s1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err = watch.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err = watch.Proceed(); err == nil {\n\t\t// if nil, stop failed\n\t\tt.Fatal()\n\t}\n\tt.Log(\"Watch close success\")\n}\n\n// TestGetKey Test get key\nfunc TestGetKey(t *testing.T) {\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-key-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts := &Service{\n\t\tService: svc,\n\t}\n\tif s.GetKey() != \"service-default-default-goframe-provider-key-tcp-test-127.0.0.1:9000\" {\n\t\tt.Fatal(\"GetKey error key:\", s.GetKey())\n\t}\n\tt.Log(\"GetKey success \")\n}\n\n// TestService_GetPrefix Test GetPrefix\nfunc TestService_GetPrefix(t *testing.T) {\n\ttype fields struct {\n\t\tService gsvc.Service\n\t\tID      string\n\t}\n\ttests := []struct {\n\t\tname   string\n\t\tfields fields\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname: \"TestService_GetPrefix-0\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tName:      \"goframe-provider-0-tcp\",\n\t\t\t\t\tVersion:   \"test\",\n\t\t\t\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t\t\t\t},\n\t\t\t\tID: \"test\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-0-tcp-test\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestService_GetPrefix-1\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tName:      \"goframe-provider-1-tcp\",\n\t\t\t\t\tVersion:   \"test\",\n\t\t\t\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9001\"),\n\t\t\t\t},\n\t\t\t\tID: \"test\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-1-tcp-test\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestService_GetPrefix-2\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tName:      \"goframe-provider-2-tcp\",\n\t\t\t\t\tVersion:   \"latest\",\n\t\t\t\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9002\"),\n\t\t\t\t},\n\t\t\t\tID: \"latest\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-2-tcp-latest\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ts := &Service{\n\t\t\t\tService: tt.fields.Service,\n\t\t\t\tID:      tt.fields.ID,\n\t\t\t}\n\t\t\tif got := s.GetPrefix(); got != tt.want {\n\t\t\t\tt.Errorf(\"GetPrefix() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestService_GetKey Test GetKey\nfunc TestService_GetKey(t *testing.T) {\n\ttype fields struct {\n\t\tService gsvc.Service\n\t\tID      string\n\t}\n\ttests := []struct {\n\t\tname   string\n\t\tfields fields\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname: \"TestService_GetKey-0\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tNamespace:  gsvc.DefaultNamespace,\n\t\t\t\t\tDeployment: gsvc.DefaultDeployment,\n\t\t\t\t\tName:       \"goframe-provider-0-tcp\",\n\t\t\t\t\tVersion:    \"test\",\n\t\t\t\t\tMetadata:   map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints:  gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t\t\t\t},\n\t\t\t\tID: \"test\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-0-tcp-test-127.0.0.1:9000\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestService_GetKey-1\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tNamespace:  gsvc.DefaultNamespace,\n\t\t\t\t\tDeployment: gsvc.DefaultDeployment,\n\t\t\t\t\tName:       \"goframe-provider-1-tcp\",\n\t\t\t\t\tVersion:    \"latest\",\n\t\t\t\t\tMetadata:   map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints:  gsvc.NewEndpoints(\"127.0.0.1:9001\"),\n\t\t\t\t},\n\t\t\t\tID: \"latest\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-1-tcp-latest-127.0.0.1:9001\",\n\t\t},\n\t\t{\n\t\t\tname: \"TestService_GetKey-2\",\n\t\t\tfields: fields{\n\t\t\t\tService: &gsvc.LocalService{\n\t\t\t\t\tNamespace:  gsvc.DefaultNamespace,\n\t\t\t\t\tDeployment: gsvc.DefaultDeployment,\n\t\t\t\t\tName:       \"goframe-provider-2-tcp\",\n\t\t\t\t\tVersion:    \"latest\",\n\t\t\t\t\tMetadata:   map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\t\t\t\tEndpoints:  gsvc.NewEndpoints(\"127.0.0.1:9002\"),\n\t\t\t\t},\n\t\t\t\tID: \"latest\",\n\t\t\t},\n\t\t\twant: \"service-default-default-goframe-provider-2-tcp-latest-127.0.0.1:9002\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ts := &Service{\n\t\t\t\tService: tt.fields.Service,\n\t\t\t\tID:      tt.fields.ID,\n\t\t\t}\n\t\t\tif got := s.GetKey(); got != tt.want {\n\t\t\t\tt.Errorf(\"GetKey() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Test_trimAndReplace Test trimAndReplace\nfunc Test_trimAndReplace(t *testing.T) {\n\ttype args struct {\n\t\tkey string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"Test_trimAndReplace-0\",\n\t\t\targs: args{key: \"/service/default/default/goframe-provider-0-tcp/latest/127.0.0.1:9000\"},\n\t\t\twant: \"service-default-default-goframe-provider-0-tcp-latest-127.0.0.1:9000\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test_trimAndReplace-1\",\n\t\t\targs: args{key: \"/service/default/default/goframe-provider-1-tcp/latest/127.0.0.1:9001\"},\n\t\t\twant: \"service-default-default-goframe-provider-1-tcp-latest-127.0.0.1:9001\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test_trimAndReplace-2\",\n\t\t\targs: args{key: \"/service/default/default/goframe-provider-2-tcp/latest/127.0.0.1:9002\"},\n\t\t\twant: \"service-default-default-goframe-provider-2-tcp-latest-127.0.0.1:9002\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := trimAndReplace(tt.args.key); got != tt.want {\n\t\t\t\tt.Errorf(\"trimAndReplace() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/README.MD",
    "content": "# GoFrame Etcd Registry\n\nUse `zookeeper` as service registration and discovery management.\n\n## Installation\n```\ngo get -u -v github.com/gogf/gf/contrib/registry/zookeeper/v2\n```\nsuggested using `go.mod`:\n```\nrequire github.com/gogf/gf/contrib/registry/zookeeper/v2 latest\n```\n\n```go\npackage main\n\nimport (\n\t\"github.com/gogf/gf/contrib/registry/zookeeper/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(zookeeper.New(\n\t\t[]string{\"127.0.0.1:2181\"}, zookeeper.WithRootPath(\"/gogf\"),\n    ))\n\t\n\ts := g.Server(`hello.svc`)\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tg.Log().Info(r.Context(), `request received`)\n\t\tr.Response.Write(`Hello world`)\n\t})\n\ts.Run()\n}\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/contrib/registry/zookeeper/v2\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc main() {\n\tgsvc.SetRegistry(zookeeper.New(\n\t\t[]string{\"127.0.0.1:2181\"}, zookeeper.WithRootPath(\"/gogf\"),\n\t))\n\tgsel.SetBuilder(gsel.NewBuilderRoundRobin())\n\n\tclient := g.Client()\n\tfor i := 0; i < 100; i++ {\n\t\tres, err := client.Get(gctx.New(), `http://hello.svc/`)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Println(res.ReadAllString())\n\t\tres.Close()\n\t\ttime.Sleep(time.Second)\n\t}\n}\n```\n\n## License\n\n`GoFrame zookeeper` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.\n\n"
  },
  {
    "path": "contrib/registry/zookeeper/go.mod",
    "content": "module github.com/gogf/gf/contrib/registry/zookeeper/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/go-zookeeper/zk v1.0.3\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgolang.org/x/sync v0.16.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/registry/zookeeper/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=\ngithub.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=\ngolang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package zookeeper implements service Registry and Discovery using zookeeper.\npackage zookeeper\n\nimport (\n\t\"time\"\n\n\t\"github.com/go-zookeeper/zk\"\n\t\"golang.org/x/sync/singleflight\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nvar _ gsvc.Registry = (*Registry)(nil)\n\n// Content for custom service Marshal/Unmarshal.\ntype Content struct {\n\tKey   string\n\tValue string\n}\n\n// Option is etcd registry option.\ntype Option func(o *options)\n\ntype options struct {\n\tnamespace string\n\tuser      string\n\tpassword  string\n}\n\n// WithRootPath with registry root path.\nfunc WithRootPath(path string) Option {\n\treturn func(o *options) { o.namespace = path }\n}\n\n// WithDigestACL with registry password.\nfunc WithDigestACL(user string, password string) Option {\n\treturn func(o *options) {\n\t\to.user = user\n\t\to.password = password\n\t}\n}\n\n// Registry is consul registry\ntype Registry struct {\n\topts  *options\n\tconn  *zk.Conn\n\tgroup singleflight.Group\n}\n\nfunc New(address []string, opts ...Option) *Registry {\n\tconn, _, err := zk.Connect(address, time.Second*120)\n\tif err != nil {\n\t\tpanic(gerror.Wrapf(err,\n\t\t\t\"Error with connect to zookeeper\"),\n\t\t)\n\t}\n\toptions := &options{\n\t\tnamespace: \"/microservices\",\n\t}\n\tfor _, o := range opts {\n\t\to(options)\n\t}\n\treturn &Registry{\n\t\topts: options,\n\t\tconn: conn,\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage zookeeper\n\nimport (\n\t\"context\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Search searches and returns services with specified condition.\nfunc (r *Registry) Search(_ context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {\n\tprefix := strings.Trim(strings.ReplaceAll(in.Prefix, \"/\", \"-\"), \"-\")\n\tinstances, err, _ := r.group.Do(prefix, func() (any, error) {\n\t\tserviceNamePath := path.Join(r.opts.namespace, prefix)\n\t\tservicesID, _, err := r.conn.Children(serviceNamePath)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t\"Error with search the children node under %s\",\n\t\t\t\tserviceNamePath,\n\t\t\t)\n\t\t}\n\t\titems := make([]gsvc.Service, 0, len(servicesID))\n\t\tfor _, service := range servicesID {\n\t\t\tservicePath := path.Join(serviceNamePath, service)\n\t\t\tbyteData, _, err := r.conn.Get(servicePath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with node data which name is %s\",\n\t\t\t\t\tservicePath,\n\t\t\t\t)\n\t\t\t}\n\t\t\titem, err := unmarshal(byteData)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with unmarshal node data to Content\",\n\t\t\t\t)\n\t\t\t}\n\t\t\tsvc, err := gsvc.NewServiceWithKV(item.Key, item.Value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with new service with KV in Content\",\n\t\t\t\t)\n\t\t\t}\n\t\t\titems = append(items, svc)\n\t\t}\n\t\treturn items, nil\n\t})\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error with group do\",\n\t\t)\n\t}\n\t// Service filter.\n\tfilteredServices := make([]gsvc.Service, 0)\n\tfor _, service := range instances.([]gsvc.Service) {\n\t\tif in.Prefix != \"\" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Name != \"\" && service.GetName() != in.Name {\n\t\t\tcontinue\n\t\t}\n\t\tif in.Version != \"\" && service.GetVersion() != in.Version {\n\t\t\tcontinue\n\t\t}\n\t\tif len(in.Metadata) != 0 {\n\t\t\tm1 := gmap.NewStrAnyMapFrom(in.Metadata)\n\t\t\tm2 := gmap.NewStrAnyMapFrom(service.GetMetadata())\n\t\t\tif !m1.IsSubOf(m2) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresultItem := service\n\t\tfilteredServices = append(filteredServices, resultItem)\n\t}\n\treturn filteredServices, nil\n}\n\n// Watch watches specified condition changes.\n// The `key` is the prefix of service key.\nfunc (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {\n\treturn newWatcher(ctx, r.opts.namespace, key, r.conn)\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage zookeeper\n\nimport (\n\t\"encoding/json\"\n)\n\nfunc unmarshal(data []byte) (c *Content, err error) {\n\terr = json.Unmarshal(data, &c)\n\treturn\n}\n\nfunc marshal(c *Content) ([]byte, error) {\n\treturn json.Marshal(c)\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper_registrar.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage zookeeper\n\nimport (\n\t\"context\"\n\t\"path\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-zookeeper/zk\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Register registers `service` to Registry.\n// Note that it returns a new Service if it changes the input Service with custom one.\nfunc (r *Registry) Register(_ context.Context, service gsvc.Service) (gsvc.Service, error) {\n\tvar (\n\t\tdata []byte\n\t\terr  error\n\t)\n\tif err = r.ensureName(r.opts.namespace, []byte(\"\"), 0); err != nil {\n\t\treturn service, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error Creat node which name is %s\",\n\t\t\tr.opts.namespace,\n\t\t)\n\t}\n\tprefix := strings.Trim(strings.ReplaceAll(service.GetPrefix(), \"/\", \"-\"), \"-\")\n\tservicePrefixPath := path.Join(r.opts.namespace, prefix)\n\tif err = r.ensureName(servicePrefixPath, []byte(\"\"), 0); err != nil {\n\t\treturn service, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error Creat node which name is %s\",\n\t\t\tservicePrefixPath,\n\t\t)\n\t}\n\n\tif data, err = marshal(&Content{\n\t\tKey:   service.GetKey(),\n\t\tValue: service.GetValue(),\n\t}); err != nil {\n\t\treturn service, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error with marshal Content to Json string\",\n\t\t)\n\t}\n\tservicePath := path.Join(servicePrefixPath, service.GetName())\n\tif err = r.ensureName(servicePath, data, zk.FlagEphemeral); err != nil {\n\t\treturn service, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error Creat node which name is %s\",\n\t\t\tservicePath,\n\t\t)\n\t}\n\tgo r.reRegister(servicePath, data)\n\treturn service, nil\n}\n\n// Deregister off-lines and removes `service` from the Registry.\nfunc (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {\n\tch := make(chan error, 1)\n\tprefix := strings.Trim(strings.ReplaceAll(service.GetPrefix(), \"/\", \"-\"), \"-\")\n\tservicePath := path.Join(r.opts.namespace, prefix, service.GetName())\n\tgo func() {\n\t\terr := r.conn.Delete(servicePath, -1)\n\t\tch <- err\n\t}()\n\tvar err error\n\tselect {\n\tcase <-ctx.Done():\n\t\terr = ctx.Err()\n\tcase err = <-ch:\n\t}\n\treturn gerror.Wrapf(err,\n\t\t\"Error with deregister service:%s\",\n\t\tservice.GetName(),\n\t)\n}\n\n// ensureName ensure node exists, if not exist, create and set data\nfunc (r *Registry) ensureName(path string, data []byte, flags int32) error {\n\texists, stat, err := r.conn.Exists(path)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err,\n\t\t\t\"Error with check node exist which name is %s\",\n\t\t\tpath,\n\t\t)\n\t}\n\t// ephemeral nodes handling after restart\n\t// fixes a race condition if the server crashes without using CreateProtectedEphemeralSequential()\n\tif flags&zk.FlagEphemeral == zk.FlagEphemeral {\n\t\terr = r.conn.Delete(path, stat.Version)\n\t\tif err != nil && err != zk.ErrNoNode {\n\t\t\treturn gerror.Wrapf(err,\n\t\t\t\t\"Error with delete node which name is %s\",\n\t\t\t\tpath,\n\t\t\t)\n\t\t}\n\t\texists = false\n\t}\n\tif !exists {\n\t\tif len(r.opts.user) > 0 && len(r.opts.password) > 0 {\n\t\t\t_, err = r.conn.Create(path, data, flags, zk.DigestACL(zk.PermAll, r.opts.user, r.opts.password))\n\t\t} else {\n\t\t\t_, err = r.conn.Create(path, data, flags, zk.WorldACL(zk.PermAll))\n\t\t}\n\t\tif err != nil {\n\t\t\treturn gerror.Wrapf(err,\n\t\t\t\t\"Error with create node which name is %s\",\n\t\t\t\tpath,\n\t\t\t)\n\t\t}\n\t}\n\treturn nil\n}\n\n// reRegister re-register data node info when bad connection recovered\nfunc (r *Registry) reRegister(path string, data []byte) {\n\tsessionID := r.conn.SessionID()\n\tticker := time.NewTicker(time.Second)\n\tdefer ticker.Stop()\n\tfor range ticker.C {\n\t\tcur := r.conn.SessionID()\n\t\t// sessionID changed\n\t\tif cur > 0 && sessionID != cur {\n\t\t\t// re-ensureName\n\t\t\tif err := r.ensureName(path, data, zk.FlagEphemeral); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tsessionID = cur\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage zookeeper\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/go-zookeeper/zk\"\n\t\"golang.org/x/sync/singleflight\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nvar _ gsvc.Watcher = (*watcher)(nil)\n\n// ErrWatcherStopped is the certain error for watcher closed.\nvar ErrWatcherStopped = errors.New(\"watcher stopped\")\n\ntype watcher struct {\n\tctx       context.Context\n\tevent     chan zk.Event\n\tconn      *zk.Conn\n\tcancel    context.CancelFunc\n\tprefix    string\n\tnameSpace string\n\tgroup     singleflight.Group\n}\n\nfunc newWatcher(ctx context.Context, nameSpace, prefix string, conn *zk.Conn) (*watcher, error) {\n\tw := &watcher{\n\t\tconn:      conn,\n\t\tevent:     make(chan zk.Event, 1),\n\t\tnameSpace: nameSpace,\n\t\tprefix:    prefix,\n\t}\n\tw.ctx, w.cancel = context.WithCancel(ctx)\n\tgo w.watch(w.ctx)\n\treturn w, nil\n}\n\n// Proceed proceeds watch in blocking way.\n// It returns all complete services that watched by `key` if any change.\nfunc (w *watcher) Proceed() ([]gsvc.Service, error) {\n\tselect {\n\tcase <-w.ctx.Done():\n\t\treturn nil, w.ctx.Err()\n\tcase e := <-w.event:\n\t\tif e.State == zk.StateDisconnected {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\tErrWatcherStopped,\n\t\t\t\t\"watcher stopped\",\n\t\t\t)\n\t\t}\n\t\tif e.Err != nil {\n\t\t\treturn nil, e.Err\n\t\t}\n\t\treturn w.getServicesByPrefix()\n\t}\n}\n\nfunc (w *watcher) getServicesByPrefix() ([]gsvc.Service, error) {\n\tprefix := strings.Trim(strings.ReplaceAll(w.prefix, \"/\", \"-\"), \"-\")\n\tserviceNamePath := path.Join(w.nameSpace, prefix)\n\tinstances, err, _ := w.group.Do(serviceNamePath, func() (any, error) {\n\t\tservicesID, _, err := w.conn.Children(serviceNamePath)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t\"Error with search the children node under %s\",\n\t\t\t\tserviceNamePath,\n\t\t\t)\n\t\t}\n\t\titems := make([]gsvc.Service, 0, len(servicesID))\n\t\tfor _, service := range servicesID {\n\t\t\tservicePath := path.Join(serviceNamePath, service)\n\t\t\tbyteData, _, err := w.conn.Get(servicePath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with node data which name is %s\",\n\t\t\t\t\tservicePath,\n\t\t\t\t)\n\t\t\t}\n\t\t\titem, err := unmarshal(byteData)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with unmarshal node data to Content\",\n\t\t\t\t)\n\t\t\t}\n\t\t\tsvc, err := gsvc.NewServiceWithKV(item.Key, item.Value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error with new service with KV in Content\",\n\t\t\t\t)\n\t\t\t}\n\t\t\titems = append(items, svc)\n\t\t}\n\t\treturn items, nil\n\t})\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(\n\t\t\terr,\n\t\t\t\"Error with group do\",\n\t\t)\n\t}\n\treturn instances.([]gsvc.Service), nil\n}\n\n// Close closes the watcher.\nfunc (w *watcher) Close() error {\n\tw.cancel()\n\treturn nil\n}\n\nfunc (w *watcher) watch(ctx context.Context) {\n\tprefix := strings.Trim(strings.ReplaceAll(w.prefix, \"/\", \"-\"), \"-\")\n\tserviceNamePath := path.Join(w.nameSpace, prefix)\n\tfor {\n\n\t\tif w.conn.State() == zk.StateConnected || w.conn.State() == zk.StateHasSession {\n\t\t\t// each watch action is only valid once\n\t\t\t_, _, ch, err := w.conn.ChildrenW(serviceNamePath)\n\t\t\tif err != nil {\n\t\t\t\tw.event <- zk.Event{Err: err}\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\tw.event <- <-ch\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "contrib/registry/zookeeper/zookeeper_z_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage zookeeper\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// TestRegistry TestRegistryManyService\nfunc TestRegistry(t *testing.T) {\n\tr := New([]string{\"127.0.0.1:2181\"}, WithRootPath(\"/gogf\"))\n\tctx := context.Background()\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-0-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts, err := r.Register(ctx, svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = r.Deregister(ctx, s)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestRegistryMany TestRegistryManyService\nfunc TestRegistryMany(t *testing.T) {\n\tr := New([]string{\"127.0.0.1:2181\"}, WithRootPath(\"/gogf\"))\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-1-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\tsvc1 := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-2-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9001\"),\n\t}\n\tsvc2 := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-3-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9002\"),\n\t}\n\n\ts0, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts2, err := r.Register(context.Background(), svc2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = r.Deregister(context.Background(), s0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = r.Deregister(context.Background(), s1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = r.Deregister(context.Background(), s2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestGetService Test GetService\nfunc TestGetService(t *testing.T) {\n\tr := New([]string{\"127.0.0.1:2181\"}, WithRootPath(\"/gogf\"))\n\tctx := context.Background()\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-4-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\n\ts, err := r.Register(ctx, svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttime.Sleep(time.Second * 1)\n\tserviceInstances, err := r.Search(ctx, gsvc.SearchInput{\n\t\tPrefix:   s.GetPrefix(),\n\t\tName:     svc.Name,\n\t\tVersion:  svc.Version,\n\t\tMetadata: svc.Metadata,\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range serviceInstances {\n\t\tg.Log().Info(ctx, instance)\n\t}\n\n\terr = r.Deregister(ctx, s)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\n// TestWatch Test Watch\nfunc TestWatch(t *testing.T) {\n\tr := New([]string{\"127.0.0.1:2181\"}, WithRootPath(\"/gogf\"))\n\n\tctx := gctx.New()\n\n\tsvc := &gsvc.LocalService{\n\t\tName:      \"goframe-provider-4-tcp\",\n\t\tVersion:   \"test\",\n\t\tMetadata:  map[string]any{\"app\": \"goframe\", gsvc.MDProtocol: \"tcp\"},\n\t\tEndpoints: gsvc.NewEndpoints(\"127.0.0.1:9000\"),\n\t}\n\tt.Log(\"watch\")\n\twatch, err := r.Watch(context.Background(), svc.GetPrefix())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ts1, err := r.Register(context.Background(), svc)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\t// watch svc\n\t// svc register, AddEvent\n\tnext, err := watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output one instance\n\t\tg.Log().Info(ctx, \"Register Proceed service: \", instance)\n\t}\n\n\terr = r.Deregister(context.Background(), s1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// svc deregister, DeleteEvent\n\tnext, err = watch.Proceed()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfor _, instance := range next {\n\t\t// it will output nothing\n\t\tg.Log().Info(ctx, \"Deregister Proceed service: \", instance)\n\t}\n\n\terr = watch.Close()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\t_, err = watch.Proceed()\n\tif err == nil {\n\t\t// if nil, stop failed\n\t\tt.Fatal()\n\t}\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/go.mod",
    "content": "module github.com/gogf/gf/contrib/rpc/grpcx/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/contrib/registry/file/v2 v2.10.0\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/trace v1.38.0\n\tgoogle.golang.org/grpc v1.64.1\n\tgoogle.golang.org/protobuf v1.34.2\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace (\n\tgithub.com/gogf/gf/contrib/registry/file/v2 => ../../registry/file/\n\tgithub.com/gogf/gf/v2 => ../../../\n)\n"
  },
  {
    "path": "contrib/rpc/grpcx/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=\ngoogle.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=\ngoogle.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=\ngoogle.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=\ngoogle.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package grpcx provides grpc service functionalities.\npackage grpcx\n\nimport (\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/balancer\"\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/grpcctx\"\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/resolver\"\n)\n\ntype (\n\tmodCtx      = grpcctx.Ctx\n\tmodBalancer = balancer.Balancer\n\tmodResolver = resolver.Manager\n\tmodClient   struct{}\n\tmodServer   struct{}\n)\n\nconst (\n\tFreePortAddress      = \":0\" // FreePortAddress marks the server listens using random free port.\n\tdefaultListenAddress = \":0\" // Default listening address for grpc server if no address configured.\n)\n\nconst (\n\tdefaultServerName        = `default`\n\tconfigNodeNameGrpcServer = `grpc`\n)\n\nvar (\n\tCtx      = modCtx{}      // Ctx is instance of module Context, which manages the context feature.\n\tBalancer = modBalancer{} // Balancer is instance of module Balancer, which manages the load balancer features.\n\tResolver = modResolver{} // Resolver is instance of module Resolver, which manages the DNS resolving for client.\n\tClient   = modClient{}   // Client is instance of module Client, which manages the client features.\n\tServer   = modServer{}   // Server is instance of module Server, which manages the server feature.\n)\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_grpc_client.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// DefaultGrpcDialOptions returns the default options for creating grpc client connection.\nfunc (c modClient) DefaultGrpcDialOptions() []grpc.DialOption {\n\treturn []grpc.DialOption{\n\t\tBalancer.WithName(gsel.GetBuilder().Name()),\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t}\n}\n\n// NewGrpcClientConn creates and returns a client connection for given service `appId`.\nfunc (c modClient) NewGrpcClientConn(serviceNameOrAddress string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {\n\tautoLoadAndRegisterFileRegistry()\n\n\tvar (\n\t\ttarget            = serviceNameOrAddress\n\t\tgrpcClientOptions = make([]grpc.DialOption, 0)\n\t)\n\tif isServiceName(serviceNameOrAddress) {\n\t\ttarget = fmt.Sprintf(\n\t\t\t`%s://%s`,\n\t\t\tgsvc.Schema, gsvc.NewServiceWithName(serviceNameOrAddress).GetKey(),\n\t\t)\n\t} else {\n\t\taddressParts := gstr.Split(serviceNameOrAddress, gsvc.EndpointHostPortDelimiter)\n\t\tswitch len(addressParts) {\n\t\tcase 2:\n\t\t\tif addressParts[0] == \"\" {\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`invalid address \"%s\" for client, missing host`,\n\t\t\t\t\tserviceNameOrAddress,\n\t\t\t\t)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid address \"%s\" for client`,\n\t\t\t\tserviceNameOrAddress,\n\t\t\t)\n\t\t}\n\t}\n\tgrpcClientOptions = append(grpcClientOptions, c.DefaultGrpcDialOptions()...)\n\tif len(opts) > 0 {\n\t\tgrpcClientOptions = append(grpcClientOptions, opts...)\n\t}\n\tgrpcClientOptions = append(grpcClientOptions, c.ChainUnary(\n\t\tc.UnaryTracing,\n\t\tc.UnaryError,\n\t))\n\tgrpcClientOptions = append(grpcClientOptions, c.ChainStream(\n\t\tc.StreamTracing,\n\t))\n\tconn, err := grpc.NewClient(target, grpcClientOptions...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn conn, nil\n}\n\n// MustNewGrpcClientConn creates and returns a client connection for given service `appId`.\n// It panics if any error occurs.\nfunc (c modClient) MustNewGrpcClientConn(serviceNameOrAddress string, opts ...grpc.DialOption) *grpc.ClientConn {\n\tconn, err := c.NewGrpcClientConn(serviceNameOrAddress, opts...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn conn\n}\n\n// ChainUnary creates a single interceptor out of a chain of many interceptors.\n//\n// Execution is done in left-to-right order, including passing of context.\n// For example ChainUnaryClient(one, two, three) will execute one before two before three.\nfunc (c modClient) ChainUnary(interceptors ...grpc.UnaryClientInterceptor) grpc.DialOption {\n\treturn grpc.WithChainUnaryInterceptor(interceptors...)\n}\n\n// ChainStream creates a single interceptor out of a chain of many interceptors.\n//\n// Execution is done in left-to-right order, including passing of context.\n// For example ChainStreamClient(one, two, three) will execute one before two before three.\nfunc (c modClient) ChainStream(interceptors ...grpc.StreamClientInterceptor) grpc.DialOption {\n\treturn grpc.WithChainStreamInterceptor(interceptors...)\n}\n\n// isServiceName checks and returns whether given input parameter is service name or not.\n// It checks by whether the parameter is address by containing port delimiter character ':'.\n//\n// It does not contain any port number if using service discovery.\nfunc isServiceName(serviceNameOrAddress string) bool {\n\treturn !gstr.Contains(serviceNameOrAddress, gsvc.EndpointHostPortDelimiter)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_grpc_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GrpcServer is the server for GRPC protocol.\ntype GrpcServer struct {\n\tServer    *grpc.Server\n\tconfig    *GrpcServerConfig\n\tlistener  net.Listener\n\tservices  []gsvc.Service\n\twaitGroup sync.WaitGroup\n\tregistrar gsvc.Registrar\n\tserviceMu sync.Mutex\n}\n\n// Service implements gsvc.Service interface.\ntype Service struct {\n\tgsvc.Service\n\tEndpoints gsvc.Endpoints\n}\n\n// New creates and returns a grpc server.\nfunc (s modServer) New(conf ...*GrpcServerConfig) *GrpcServer {\n\tautoLoadAndRegisterFileRegistry()\n\n\tvar (\n\t\tctx    = gctx.GetInitCtx()\n\t\tconfig *GrpcServerConfig\n\t)\n\tif len(conf) > 0 {\n\t\tconfig = conf[0]\n\t} else {\n\t\tconfig = s.NewConfig()\n\t}\n\tif config.Address == \"\" {\n\t\tconfig.Address = defaultListenAddress\n\t}\n\tif !gstr.Contains(config.Address, \":\") {\n\t\tg.Log().Fatal(ctx, \"invalid service address, should contain listening port\")\n\t}\n\tif config.Logger == nil {\n\t\tconfig.Logger = glog.New()\n\t}\n\tgrpcServer := &GrpcServer{\n\t\tconfig:    config,\n\t\tregistrar: gsvc.GetRegistry(),\n\t}\n\tgrpcServer.config.Options = append([]grpc.ServerOption{\n\t\ts.ChainUnary(\n\t\t\ts.UnaryTracing,\n\t\t\tgrpcServer.UnaryLogger,\n\t\t\ts.UnaryRecover,\n\t\t\ts.UnaryAllowNilRes,\n\t\t\ts.UnaryError,\n\t\t),\n\t\ts.ChainStream(\n\t\t\ts.StreamTracing,\n\t\t),\n\t}, grpcServer.config.Options...)\n\tgrpcServer.Server = grpc.NewServer(grpcServer.config.Options...)\n\treturn grpcServer\n}\n\n// Service binds service list to current server.\n// Server will automatically register the service list after it starts.\nfunc (s *GrpcServer) Service(services ...gsvc.Service) {\n\ts.serviceMu.Lock()\n\tdefer s.serviceMu.Unlock()\n\ts.services = append(s.services, services...)\n}\n\n// Run starts the server in blocking way.\nfunc (s *GrpcServer) Run() {\n\tvar (\n\t\terr error\n\t\tctx = gctx.GetInitCtx()\n\t)\n\t// Create listener to bind listening ip and port.\n\ts.listener, err = net.Listen(\"tcp\", s.config.Address)\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\n\t// Start listening.\n\tgo s.doServeAsynchronously(ctx)\n\n\t// Service register.\n\ts.doServiceRegister()\n\ts.Logger().Infof(\n\t\tctx,\n\t\t\"pid[%d]: grpc server started listening on [%s]\",\n\t\tgproc.Pid(), s.GetListenedAddress(),\n\t)\n\ts.doSignalListen()\n}\n\nfunc (s *GrpcServer) doServeAsynchronously(ctx context.Context) {\n\tif err := s.Server.Serve(s.listener); err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n}\n\n// doSignalListen does signal listening and handling for gracefully shutdown.\nfunc (s *GrpcServer) doSignalListen() {\n\tvar ctx = context.Background()\n\tgproc.AddSigHandlerShutdown(func(sig os.Signal) {\n\t\ts.Logger().Infof(ctx, \"signal received: %s, gracefully shutting down\", sig.String())\n\t\t// Deregister services when shutdown signal triggers.\n\t\ts.doServiceDeregister()\n\t\ttime.Sleep(time.Second)\n\t\ts.Stop()\n\t})\n\tgproc.Listen()\n\t// Deregister services when process ends.\n\ts.doServiceDeregister()\n}\n\n// Logger is alias of GetLogger.\nfunc (s *GrpcServer) Logger() *glog.Logger {\n\treturn s.config.Logger\n}\n\n// doServiceRegister registers current service to Registry.\nfunc (s *GrpcServer) doServiceRegister() {\n\tif s.registrar == nil {\n\t\treturn\n\t}\n\ts.serviceMu.Lock()\n\tdefer s.serviceMu.Unlock()\n\tif len(s.services) == 0 {\n\t\ts.services = []gsvc.Service{&gsvc.LocalService{\n\t\t\tName:     s.config.Name,\n\t\t\tMetadata: gsvc.Metadata{},\n\t\t}}\n\t}\n\tvar (\n\t\terr      error\n\t\tctx      = gctx.GetInitCtx()\n\t\tprotocol = `grpc`\n\t)\n\t// Register service list after server starts.\n\tfor i, service := range s.services {\n\t\tservice = &gsvc.LocalService{\n\t\t\tName:      service.GetName(),\n\t\t\tEndpoints: s.calculateListenedEndpoints(ctx),\n\t\t\tMetadata:  service.GetMetadata(),\n\t\t}\n\t\tservice.GetMetadata().Sets(gsvc.Metadata{\n\t\t\tgsvc.MDProtocol: protocol,\n\t\t})\n\t\ts.Logger().Debugf(ctx, `service register: %+v`, service)\n\t\tif len(service.GetEndpoints()) == 0 {\n\t\t\ts.Logger().Warningf(ctx, `no endpoints found to register service, abort service registering`)\n\t\t\treturn\n\t\t}\n\t\tif service, err = s.registrar.Register(ctx, service); err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\t}\n\t\ts.services[i] = service\n\t}\n}\n\n// doServiceDeregister de-registers current service from Registry.\nfunc (s *GrpcServer) doServiceDeregister() {\n\tif s.registrar == nil {\n\t\treturn\n\t}\n\ts.serviceMu.Lock()\n\tdefer s.serviceMu.Unlock()\n\tvar ctx = gctx.GetInitCtx()\n\tfor _, service := range s.services {\n\t\ts.Logger().Debugf(ctx, `service deregister: %+v`, service)\n\t\tif err := s.registrar.Deregister(ctx, service); err != nil {\n\t\t\ts.Logger().Errorf(ctx, `%+v`, err)\n\t\t}\n\t}\n\ts.services = s.services[:0]\n}\n\n// Start starts the server in no-blocking way.\nfunc (s *GrpcServer) Start() {\n\ts.waitGroup.Add(1)\n\tgo s.doStartAsynchronously()\n}\n\nfunc (s *GrpcServer) doStartAsynchronously() {\n\tdefer s.waitGroup.Done()\n\ts.Run()\n}\n\n// Wait works with Start, which blocks current goroutine until the server stops.\nfunc (s *GrpcServer) Wait() {\n\ts.waitGroup.Wait()\n}\n\n// Stop gracefully stops the server.\nfunc (s *GrpcServer) Stop() {\n\ts.doServiceDeregister()\n\ts.Server.GracefulStop()\n}\n\n// GetConfig returns the configuration of current Server.\nfunc (s *GrpcServer) GetConfig() *GrpcServerConfig {\n\treturn s.config\n}\n\n// GetListenedAddress retrieves and returns the address string which are listened by current server.\nfunc (s *GrpcServer) GetListenedAddress() string {\n\tif !gstr.Contains(s.config.Address, FreePortAddress) {\n\t\treturn s.config.Address\n\t}\n\tvar (\n\t\taddress      = s.config.Address\n\t\tlistenedPort = s.GetListenedPort()\n\t)\n\taddress = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort))\n\treturn address\n}\n\n// GetListenedPort retrieves and returns one port which is listened to by current server.\nfunc (s *GrpcServer) GetListenedPort() int {\n\tif ln := s.listener; ln != nil {\n\t\treturn ln.Addr().(*net.TCPAddr).Port\n\t}\n\treturn -1\n}\n\nfunc (s *GrpcServer) calculateListenedEndpoints(ctx context.Context) gsvc.Endpoints {\n\tvar (\n\t\tconfigAddr = s.config.Address\n\t\tendpoints  = make(gsvc.Endpoints, 0)\n\t\taddresses  = s.config.Endpoints\n\t)\n\tif len(addresses) == 0 {\n\t\taddresses = gstr.SplitAndTrim(configAddr, \",\")\n\t}\n\tfor _, address := range addresses {\n\t\tvar (\n\t\t\taddrArray     = gstr.Split(address, \":\")\n\t\t\tlistenedIps   []string\n\t\t\tlistenedPorts []int\n\t\t)\n\t\tif len(addrArray) == 1 {\n\t\t\tconfigItemName := \"address\"\n\t\t\tif len(s.config.Endpoints) != 0 {\n\t\t\t\tconfigItemName = \"endpoint\"\n\t\t\t}\n\t\t\tpanic(gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidConfiguration,\n\t\t\t\t`invalid \"%s\" configuration \"%s\", missing port`,\n\t\t\t\tconfigItemName, address,\n\t\t\t))\n\t\t}\n\t\t// IPs.\n\t\tswitch addrArray[0] {\n\t\tcase \"0.0.0.0\", \"\":\n\t\t\tintranetIps, err := gipv4.GetIntranetIpArray()\n\t\t\tif err != nil {\n\t\t\t\ts.Logger().Errorf(ctx, `error retrieving intranet ip: %+v`, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif len(intranetIps) != 0 {\n\t\t\t\tlistenedIps = intranetIps\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// If no intranet ips found, it uses all ips that can be retrieved,\n\t\t\t// it may include internet ip.\n\t\t\tallIps, err := gipv4.GetIpArray()\n\t\t\tif err != nil {\n\t\t\t\ts.Logger().Errorf(ctx, `error retrieving ip from current node: %+v`, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\ts.Logger().Noticef(\n\t\t\t\tctx,\n\t\t\t\t`no intranet ip found, using internet ip to register service: %v`,\n\t\t\t\tallIps,\n\t\t\t)\n\t\t\tlistenedIps = allIps\n\t\tdefault:\n\t\t\tlistenedIps = []string{addrArray[0]}\n\t\t}\n\t\t// Ports.\n\t\tswitch addrArray[1] {\n\t\tcase \"0\":\n\t\t\tlistenedPorts = []int{s.GetListenedPort()}\n\t\tdefault:\n\t\t\tlistenedPorts = []int{gconv.Int(addrArray[1])}\n\t\t}\n\t\tfor _, ip := range listenedIps {\n\t\t\tfor _, port := range listenedPorts {\n\t\t\t\tendpoints = append(\n\t\t\t\t\tendpoints,\n\t\t\t\t\tgsvc.NewEndpoint(fmt.Sprintf(`%s:%d`, ip, port)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\treturn endpoints\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_grpc_server_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// GrpcServerConfig is the configuration for server.\ntype GrpcServerConfig struct {\n\t// (optional) Name for current service.\n\tName string\n\n\t// (optional) Single address for server listening, use `:0` or `ip:0` to serve random port.\n\tAddress string\n\n\t// (optional) Logger for server.\n\tLogger *glog.Logger\n\n\t// (optional) LogPath specifies the directory for storing logging files.\n\tLogPath string\n\n\t// (optional) LogStdout specifies whether printing logging content to stdout.\n\tLogStdout bool\n\n\t// (optional) ErrorStack specifies whether logging stack information when error.\n\tErrorStack bool\n\n\t// (optional) ErrorLogEnabled enables error logging content to files.\n\tErrorLogEnabled bool\n\n\t// (optional) ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log\n\tErrorLogPattern string\n\n\t// (optional) AccessLogEnabled enables access logging content to file.\n\tAccessLogEnabled bool\n\n\t// (optional) AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log\n\tAccessLogPattern string\n\n\t// (optional) Endpoints are custom endpoints for service register, it uses Address if empty.\n\tEndpoints []string\n\n\t// (optional) GRPC Server options.\n\tOptions []grpc.ServerOption\n}\n\n// NewConfig creates and returns a ServerConfig object with default configurations.\n// Note that, do not define this default configuration to local package variable, as there are\n// some pointer attributes that may be shared in different servers.\nfunc (s modServer) NewConfig() *GrpcServerConfig {\n\tvar (\n\t\terr    error\n\t\tctx    = context.TODO()\n\t\tconfig = &GrpcServerConfig{\n\t\t\tName:             defaultServerName,\n\t\t\tLogger:           glog.New(),\n\t\t\tLogStdout:        true,\n\t\t\tErrorLogEnabled:  true,\n\t\t\tErrorLogPattern:  \"error-{Ymd}.log\",\n\t\t\tAccessLogEnabled: false,\n\t\t\tAccessLogPattern: \"access-{Ymd}.log\",\n\t\t}\n\t)\n\t// Reading configuration file and updating the configured keys.\n\tif g.Cfg().Available(ctx) {\n\t\t// Server attributes configuration.\n\t\tserverConfigMap := g.Cfg().MustGet(ctx, configNodeNameGrpcServer).Map()\n\t\tif len(serverConfigMap) == 0 {\n\t\t\treturn config\n\t\t}\n\t\tif err = gconv.Struct(serverConfigMap, &config); err != nil {\n\t\t\tg.Log().Error(ctx, err)\n\t\t\treturn config\n\t\t}\n\t\t// Server logger configuration checks.\n\t\tserverLoggerConfigMap := g.Cfg().MustGet(\n\t\t\tctx,\n\t\t\tfmt.Sprintf(`%s.logger`, configNodeNameGrpcServer),\n\t\t).Map()\n\t\tif len(serverLoggerConfigMap) == 0 && len(serverConfigMap) > 0 {\n\t\t\tserverLoggerConfigMap = gconv.Map(serverConfigMap[\"logger\"])\n\t\t}\n\t\tif len(serverLoggerConfigMap) > 0 {\n\t\t\tif err = config.Logger.SetConfigWithMap(serverLoggerConfigMap); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t}\n\treturn config\n}\n\n// SetWithMap changes current configuration with map.\n// This is commonly used for changing several configurations of current object.\nfunc (c *GrpcServerConfig) SetWithMap(m g.Map) error {\n\treturn gconv.Struct(m, c)\n}\n\n// MustSetWithMap acts as SetWithMap but panics if error occurs.\nfunc (c *GrpcServerConfig) MustSetWithMap(m g.Map) {\n\terr := c.SetWithMap(m)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_grpc_server_unary.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// UnaryLogger is the default unary interceptor for logging purpose.\nfunc (s *GrpcServer) UnaryLogger(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (any, error) {\n\tvar (\n\t\tstart    = time.Now()\n\t\tres, err = handler(ctx, req)\n\t\tduration = time.Since(start)\n\t)\n\ts.handleAccessLog(ctx, err, duration, info, req, res)\n\ts.handleErrorLog(ctx, err, duration, info, req, res)\n\treturn res, err\n}\n\n// handleAccessLog handles the access logging for server.\nfunc (s *GrpcServer) handleAccessLog(\n\tctx context.Context, err error, duration time.Duration, info *grpc.UnaryServerInfo, req, res any,\n) {\n\tif !s.config.AccessLogEnabled {\n\t\treturn\n\t}\n\tcontent := fmt.Sprintf(\n\t\t\"%s, %.3fms, %+v, %+v\",\n\t\tinfo.FullMethod, float64(duration)/1e6, req, res,\n\t)\n\ts.config.Logger.Stdout(s.config.LogStdout).File(s.config.AccessLogPattern).Path(s.config.LogPath).Print(ctx, content)\n}\n\n// handleErrorLog handles the error logging for server.\nfunc (s *GrpcServer) handleErrorLog(\n\tctx context.Context, err error, duration time.Duration, info *grpc.UnaryServerInfo, req, res any,\n) {\n\t// It does nothing if error logging is custom disabled.\n\tif !s.config.ErrorLogEnabled || err == nil {\n\t\treturn\n\t}\n\tvar (\n\t\tcode          = gerror.Code(err)\n\t\tcodeDetail    = code.Detail()\n\t\tcodeDetailStr string\n\t\tgrpcCode      codes.Code\n\t\tgrpcMessage   string\n\t)\n\tif grpcStatus, ok := status.FromError(err); ok {\n\t\tgrpcCode = grpcStatus.Code()\n\t\tgrpcMessage = grpcStatus.Message()\n\t}\n\tif codeDetail != nil {\n\t\tcodeDetailStr = gstr.Replace(fmt.Sprintf(`%+v`, codeDetail), \"\\n\", \" \")\n\t}\n\tcontent := fmt.Sprintf(\n\t\t`%s, %.3fms, %d, \"%s\", %+v, %+v, %d, \"%s\", \"%s\"`,\n\t\tinfo.FullMethod, float64(duration)/1e6, grpcCode, grpcMessage,\n\t\treq, res, code.Code(), code.Message(), codeDetailStr,\n\t)\n\tif s.config.ErrorStack {\n\t\tif stack := gerror.Stack(err); stack != \"\" {\n\t\t\tcontent += \"\\nStack:\\n\" + stack\n\t\t} else {\n\t\t\tcontent += \", \" + err.Error()\n\t\t}\n\t} else {\n\t\tcontent += \", \" + err.Error()\n\t}\n\ts.config.Logger.Stack(false).\n\t\tStdout(s.config.LogStdout).\n\t\tFile(s.config.ErrorLogPattern).Path(s.config.LogPath).Error(ctx, content)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_interceptor_client.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/tracing\"\n)\n\n// UnaryError handles the error types converting between grpc and gerror.\n// Note that, the minus error code is only used locally which will not be sent to other side.\nfunc (c modClient) UnaryError(ctx context.Context, method string, req, reply any,\n\tcc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {\n\terr := invoker(ctx, method, req, reply, cc, opts...)\n\tif err != nil {\n\t\tgrpcStatus, ok := status.FromError(err)\n\t\tif ok {\n\t\t\tif code := grpcStatus.Code(); code != 0 {\n\t\t\t\treturn gerror.NewCode(gcode.New(int(code), \"\", nil), grpcStatus.Message())\n\t\t\t}\n\t\t\treturn gerror.New(grpcStatus.Message())\n\t\t}\n\t}\n\treturn err\n}\n\n// UnaryTracing is a unary interceptor for adding tracing feature for gRPC client using OpenTelemetry.\nfunc (c modClient) UnaryTracing(\n\tctx context.Context, method string, req, reply any,\n\tcc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {\n\treturn tracing.UnaryClientInterceptor(ctx, method, req, reply, cc, invoker, opts...)\n}\n\n// StreamTracing is a stream interceptor for adding tracing feature for gRPC client using OpenTelemetry.\nfunc (c modClient) StreamTracing(\n\tctx context.Context, desc *grpc.StreamDesc,\n\tcc *grpc.ClientConn, method string, streamer grpc.Streamer,\n\tcallOpts ...grpc.CallOption) (grpc.ClientStream, error) {\n\treturn tracing.StreamClientInterceptor(ctx, desc, cc, method, streamer, callOpts...)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_interceptor_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/tracing\"\n)\n\n// ChainUnary returns a ServerOption that specifies the chained interceptor\n// for unary RPCs. The first interceptor will be the outermost,\n// while the last interceptor will be the innermost wrapper around the real call.\n// All unary interceptors added by this method will be chained.\nfunc (s modServer) ChainUnary(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {\n\treturn grpc.ChainUnaryInterceptor(interceptors...)\n}\n\n// ChainStream returns a ServerOption that specifies the chained interceptor\n// for stream RPCs. The first interceptor will be the outermost,\n// while the last interceptor will be the innermost wrapper around the real call.\n// All stream interceptors added by this method will be chained.\nfunc (s modServer) ChainStream(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {\n\treturn grpc.ChainStreamInterceptor(interceptors...)\n}\n\n// UnaryError is the default unary interceptor for error converting from custom error to grpc error.\nfunc (s modServer) UnaryError(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (any, error) {\n\tres, err := handler(ctx, req)\n\tif err != nil {\n\t\tcode := gerror.Code(err)\n\t\tif code.Code() != -1 {\n\t\t\terr = status.Error(codes.Code(code.Code()), err.Error())\n\t\t}\n\t}\n\treturn res, err\n}\n\n// UnaryRecover is the first interceptor that keep server not down from panics.\nfunc (s modServer) UnaryRecover(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (res any, err error) {\n\tgutil.TryCatch(ctx, func(ctx2 context.Context) {\n\t\tres, err = handler(ctx, req)\n\t}, func(ctx context.Context, exception error) {\n\t\terr = gerror.WrapCode(gcode.New(int(codes.Internal), \"\", nil), exception, \"panic recovered\")\n\t})\n\treturn\n}\n\n// UnaryValidate Common validation unary interpreter.\nfunc (s modServer) UnaryValidate(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (any, error) {\n\t// It does nothing if there's no validation tag in the struct definition.\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.New(int(codes.InvalidArgument), \"\", nil),\n\t\t\tgerror.Current(err).Error(),\n\t\t)\n\t}\n\treturn handler(ctx, req)\n}\n\nfunc (s modServer) UnaryAllowNilRes(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (any, error) {\n\tres, err := handler(ctx, req)\n\tif g.IsNil(res) {\n\t\tres = proto.Message(nil)\n\t}\n\treturn res, err\n}\n\n// UnaryTracing is a unary interceptor for adding tracing feature for gRPC server using OpenTelemetry.\n// The tracing feature is builtin enabled.\nfunc (s modServer) UnaryTracing(\n\tctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,\n) (any, error) {\n\treturn tracing.UnaryServerInterceptor(ctx, req, info, handler)\n}\n\n// StreamTracing is a stream unary interceptor for adding tracing feature for gRPC server using OpenTelemetry.\nfunc (s modServer) StreamTracing(\n\tsrv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler,\n) error {\n\treturn tracing.StreamServerInterceptor(srv, ss, info, handler)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_registry_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\n\t\"github.com/gogf/gf/contrib/registry/file/v2\"\n)\n\n// autoLoadAndRegisterFileRegistry checks and registers ETCD service as default service registry\n// if no registry is registered previously.\nfunc autoLoadAndRegisterFileRegistry() {\n\t// It ignores etcd registry if any registry already registered.\n\tif gsvc.GetRegistry() != nil {\n\t\treturn\n\t}\n\tvar (\n\t\tctx           = gctx.GetInitCtx()\n\t\tdirectoryPath = gfile.Temp(\"gsvc\")\n\t\tfileRegistry  = file.New(directoryPath)\n\t)\n\n\tg.Log().Debugf(\n\t\tctx,\n\t\t`set default registry using file registry as no custom registry set, path: %s`,\n\t\tdirectoryPath,\n\t)\n\tResolver.Register(fileRegistry)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_unit_z_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2\"\n)\n\nfunc Test_Ctx_Basic(t *testing.T) {\n\tctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs(\n\t\t\"k1\", \"v1\",\n\t\t\"k2\", \"v2\",\n\t))\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := grpcx.Ctx.IncomingMap(ctx)\n\t\tt.Assert(m1.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m1.Get(\"k2\"), \"v2\")\n\t\tm2 := grpcx.Ctx.OutgoingMap(ctx)\n\t\tt.Assert(m2.Size(), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := grpcx.Ctx.IncomingToOutgoing(ctx)\n\t\tm1 := grpcx.Ctx.IncomingMap(ctx)\n\t\tt.Assert(m1.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m1.Get(\"k2\"), \"v2\")\n\t\tm2 := grpcx.Ctx.OutgoingMap(ctx)\n\t\tt.Assert(m2.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m2.Get(\"k2\"), \"v2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := grpcx.Ctx.IncomingToOutgoing(ctx, \"k1\")\n\t\tm1 := grpcx.Ctx.IncomingMap(ctx)\n\t\tt.Assert(m1.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m1.Get(\"k2\"), \"v2\")\n\t\tm2 := grpcx.Ctx.OutgoingMap(ctx)\n\t\tt.Assert(m2.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m2.Get(\"k2\"), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := grpcx.Ctx.NewIncoming(ctx)\n\t\tctx = grpcx.Ctx.SetIncoming(ctx, g.Map{\"k1\": \"v1\"})\n\t\tctx = grpcx.Ctx.SetIncoming(ctx, g.Map{\"k2\": \"v2\"})\n\t\tctx = grpcx.Ctx.SetOutgoing(ctx, g.Map{\"k3\": \"v3\"})\n\t\tctx = grpcx.Ctx.SetOutgoing(ctx, g.Map{\"k4\": \"v4\"})\n\t\tm1 := grpcx.Ctx.IncomingMap(ctx)\n\t\tt.Assert(m1.Get(\"k1\"), \"v1\")\n\t\tt.Assert(m1.Get(\"k2\"), \"v2\")\n\t\tm2 := grpcx.Ctx.OutgoingMap(ctx)\n\t\tt.Assert(m2.Get(\"k3\"), \"v3\")\n\t\tt.Assert(m2.Get(\"k4\"), \"v4\")\n\t})\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_unit_z_grpc_server_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2\"\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/testdata/controller\"\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/testdata/protobuf\"\n)\n\nfunc Test_Grpcx_Grpc_Server_Basic(t *testing.T) {\n\tc := grpcx.Server.NewConfig()\n\tc.Name = guid.S()\n\ts := grpcx.Server.New(c)\n\tcontroller.Register(s)\n\ts.Start()\n\ttime.Sleep(time.Millisecond * 100)\n\tdefer s.Stop()\n\n\t// use service discovery.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx    = gctx.New()\n\t\t\tconn   = grpcx.Client.MustNewGrpcClientConn(c.Name)\n\t\t\tclient = protobuf.NewGreeterClient(conn)\n\t\t)\n\t\tres, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: \"World\"})\n\t\tif err != nil {\n\t\t\tg.Log().Error(ctx, err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(res.Message, `Hello World`)\n\t})\n\n\t// use direct address.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx     = gctx.New()\n\t\t\taddress = fmt.Sprintf(`%s:%d`, gipv4.MustGetIntranetIp(), s.GetListenedPort())\n\t\t\tconn    = grpcx.Client.MustNewGrpcClientConn(address)\n\t\t\tclient  = protobuf.NewGreeterClient(conn)\n\t\t)\n\t\tres, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: \"World\"})\n\t\tif err != nil {\n\t\t\tg.Log().Error(ctx, err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(res.Message, `Hello World`)\n\t})\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_unit_z_grpc_server_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Grpcx_Grpc_Server(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := Server.New()\n\t\ts.Start()\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tdefer s.Stop()\n\t\ts.serviceMu.Lock()\n\t\tdefer s.serviceMu.Unlock()\n\t\tt.Assert(len(s.services) != 0, true)\n\t})\n}\n\nfunc Test_Grpcx_Grpc_Server_Address(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := Server.NewConfig()\n\t\tc.Address = \"127.0.0.1:0\"\n\t\ts := Server.New(c)\n\t\ts.Start()\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tdefer s.Stop()\n\n\t\ts.serviceMu.Lock()\n\t\tdefer s.serviceMu.Unlock()\n\t\tt.Assert(len(s.services) != 0, true)\n\t\tt.Assert(gstr.Contains(s.services[0].GetEndpoints().String(), \"127.0.0.1:\"), true)\n\t})\n}\n\nfunc Test_Grpcx_Grpc_Server_Config(t *testing.T) {\n\tcfg := Server.NewConfig()\n\taddr := \"10.0.0.29:80\"\n\tcfg.Endpoints = []string{\n\t\taddr,\n\t}\n\t// cfg set one endpoint\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := Server.New(cfg)\n\t\ts.doServiceRegister()\n\t\tfor _, svc := range s.services {\n\t\t\tt.Assert(svc.GetEndpoints().String(), addr)\n\t\t}\n\t})\n\t// cfg set more endpoints\n\taddr = \"10.0.0.29:80,10.0.0.29:81\"\n\tcfg.Endpoints = []string{\n\t\t\"10.0.0.29:80\",\n\t\t\"10.0.0.29:81\",\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := Server.New(cfg)\n\t\ts.doServiceRegister()\n\t\tfor _, svc := range s.services {\n\t\t\tt.Assert(svc.GetEndpoints().String(), addr)\n\t\t}\n\t})\n}\n\nfunc Test_Grpcx_Grpc_Server_Config_Logger(t *testing.T) {\n\tvar (\n\t\tpwd       = gfile.Pwd()\n\t\tconfigDir = gfile.Join(gdebug.CallerDirectory(), \"testdata\", \"configuration\")\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gfile.Chdir(configDir)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Chdir(pwd)\n\n\t\ts := Server.New()\n\t\ts.Start()\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tdefer s.Stop()\n\n\t\tvar logFilePath = fmt.Sprintf(\"/tmp/log/%s.log\", gtime.Now().Format(\"Y-m-d\"))\n\t\tdefer gfile.RemoveFile(logFilePath)\n\t\tt.Assert(gfile.Exists(logFilePath), true)\n\t\tt.Assert(s.Logger().GetConfig().Prefix, \"TestLogger\")\n\t})\n\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/grpcx_unit_z_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpcx_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2\"\n)\n\nvar ctx = context.Background()\n\n// https://github.com/gogf/gf/issues/3292\nfunc Test_Issue3292(t *testing.T) {\n\tvar (\n\t\t_ = grpcx.Client.MustNewGrpcClientConn(\n\t\t\t\"127.0.0.1:8888\",\n\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t)\n\t)\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/url\", func(r *ghttp.Request) {\n\t\tr.Response.Write(1)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tres, err := client.Get(ctx, \"/url\")\n\t\tt.AssertNil(err)\n\t\tdefer res.Close()\n\n\t\tt.Assert(res.ReadAllString(), \"1\")\n\t})\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/balancer/balancer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package balancer defines APIs for load balancing in gRPC.\npackage balancer\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/balancer\"\n\t\"google.golang.org/grpc/balancer/base\"\n\n\t\"github.com/gogf/gf/v2/net/gsel\"\n)\n\ntype Balancer struct{}\n\nconst (\n\trawSvcKeyInSubConnInfo = `RawService`\n)\n\nvar (\n\tRandom          = gsel.NewBuilderRandom()\n\tWeight          = gsel.NewBuilderWeight()\n\tRoundRobin      = gsel.NewBuilderRoundRobin()\n\tLeastConnection = gsel.NewBuilderLeastConnection()\n)\n\nfunc init() {\n\tb := Balancer{}\n\tb.Register(Random, Weight, RoundRobin, LeastConnection)\n}\n\n// Register registers the given balancer builder with the given name.\nfunc (Balancer) Register(builders ...gsel.Builder) {\n\tfor _, builder := range builders {\n\t\tbalancer.Register(\n\t\t\tbase.NewBalancerBuilder(\n\t\t\t\tbuilder.Name(),\n\t\t\t\t&Builder{builder: builder},\n\t\t\t\tbase.Config{HealthCheck: true},\n\t\t\t),\n\t\t)\n\t}\n}\n\n// WithRandom returns a grpc.DialOption which enables random load balancing.\nfunc (b Balancer) WithRandom() grpc.DialOption {\n\treturn b.WithName(Random.Name())\n}\n\n// WithWeight returns a grpc.DialOption which enables weight load balancing.\nfunc (b Balancer) WithWeight() grpc.DialOption {\n\treturn b.WithName(Weight.Name())\n}\n\n// WithRoundRobin returns a grpc.DialOption which enables round-robin load balancing.\nfunc (b Balancer) WithRoundRobin() grpc.DialOption {\n\treturn b.WithName(RoundRobin.Name())\n}\n\n// WithLeastConnection returns a grpc.DialOption which enables the least connection load balancing.\nfunc (b Balancer) WithLeastConnection() grpc.DialOption {\n\treturn b.WithName(LeastConnection.Name())\n}\n\n// WithName returns a grpc.DialOption which enables the load balancing by name.\nfunc (b Balancer) WithName(name string) grpc.DialOption {\n\treturn grpc.WithDefaultServiceConfig(fmt.Sprintf(\n\t\t`{\"loadBalancingPolicy\": \"%s\"}`,\n\t\tname,\n\t))\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/balancer/balancer_builder.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage balancer\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/balancer\"\n\t\"google.golang.org/grpc/balancer/base\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Builder implements grpc balancer base.PickerBuilder,\n// which returns a picker that will be used by gRPC to pick a SubConn.\ntype Builder struct {\n\tbuilder gsel.Builder\n}\n\n// Build returns a picker that will be used by gRPC to pick a SubConn.\nfunc (b *Builder) Build(info base.PickerBuildInfo) balancer.Picker {\n\tif len(info.ReadySCs) == 0 {\n\t\treturn base.NewErrPicker(balancer.ErrNoSubConnAvailable)\n\t}\n\tvar (\n\t\tctx   = context.Background()\n\t\tnodes = make([]gsel.Node, 0)\n\t)\n\tfor conn, subConnInfo := range info.ReadySCs {\n\t\tsvc, _ := subConnInfo.Address.Attributes.Value(rawSvcKeyInSubConnInfo).(gsvc.Service)\n\t\tif svc == nil && subConnInfo.Address.Addr != \"\" {\n\t\t\t// It might be a direct address without service name, it so creates a default service.\n\t\t\tsvc = &gsvc.LocalService{\n\t\t\t\tName:      subConnInfo.Address.ServerName,\n\t\t\t\tEndpoints: gsvc.NewEndpoints(subConnInfo.Address.Addr),\n\t\t\t}\n\t\t}\n\t\tif svc == nil {\n\t\t\tg.Log().Noticef(ctx, `empty service read from: %+v`, subConnInfo.Address)\n\t\t\tcontinue\n\t\t}\n\t\tnodes = append(nodes, &Node{\n\t\t\tservice: svc,\n\t\t\tconn:    conn,\n\t\t})\n\t}\n\tp := &Picker{\n\t\tselector: b.builder.Build(),\n\t}\n\tif err := p.selector.Update(ctx, nodes); err != nil {\n\t\tpanic(err)\n\t}\n\treturn p\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/balancer/balancer_node.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage balancer\n\nimport (\n\t\"google.golang.org/grpc/balancer\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Node is the node for the balancer.\ntype Node struct {\n\tservice gsvc.Service\n\tconn    balancer.SubConn\n}\n\n// Service returns the service of the node.\nfunc (n *Node) Service() gsvc.Service {\n\treturn n.service\n}\n\n// Address returns the address of the node.\nfunc (n *Node) Address() string {\n\tendpoints := n.service.GetEndpoints()\n\tif len(endpoints) == 0 {\n\t\treturn \"\"\n\t}\n\treturn endpoints[0].String()\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/balancer/balancer_picker.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage balancer\n\nimport (\n\t\"google.golang.org/grpc/balancer\"\n\n\t\"github.com/gogf/gf/v2/net/gsel\"\n)\n\n// Picker implements grpc balancer.Picker,\n// which is used by gRPC to pick a SubConn to send an RPC.\n// Balancer is expected to generate a new picker from its snapshot every time its\n// internal state has changed.\n//\n// The pickers used by gRPC can be updated by ClientConn.UpdateState().\ntype Picker struct {\n\tselector gsel.Selector\n}\n\n// Pick returns the connection to use for this RPC and related information.\n//\n// Pick should not block.  If the balancer needs to do I/O or any blocking\n// or time-consuming work to service this call, it should return\n// ErrNoSubConnAvailable, and the Pick call will be repeated by gRPC when\n// the Picker is updated (using ClientConn.UpdateState).\n//\n// If an error is returned:\n//\n//   - If the error is ErrNoSubConnAvailable, gRPC will block until a new\n//     Picker is provided by the balancer (using ClientConn.UpdateState).\n//\n//   - If the error is a status error (implemented by the grpc/status\n//     package), gRPC will terminate the RPC with the code and message\n//     provided.\n//\n//   - For all other errors, wait for ready RPCs will wait, but non-wait for\n//     ready RPCs will be terminated with this error's Error() string and\n//     status code Unavailable.\nfunc (p *Picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {\n\tnode, done, err := p.selector.Pick(info.Ctx)\n\tif err != nil {\n\t\treturn balancer.PickResult{}, err\n\t}\n\treturn balancer.PickResult{\n\t\tSubConn: node.(*Node).conn,\n\t\tDone: func(di balancer.DoneInfo) {\n\t\t\tif done == nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdone(info.Ctx, gsel.DoneInfo{\n\t\t\t\tErr:           di.Err,\n\t\t\t\tTrailer:       di.Trailer,\n\t\t\t\tBytesSent:     di.BytesSent,\n\t\t\t\tBytesReceived: di.BytesReceived,\n\t\t\t\tServerLoad:    di.ServerLoad,\n\t\t\t})\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/grpcctx/grpcctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package grpcctx provides context feature for GRPC.\npackage grpcctx\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype (\n\tCtx struct{}\n)\n\nfunc (c Ctx) NewIncoming(ctx context.Context, data ...g.Map) context.Context {\n\tif len(data) > 0 {\n\t\tincomingMd := make(metadata.MD)\n\t\tfor key, value := range data[0] {\n\t\t\tincomingMd.Set(key, gconv.String(value))\n\t\t}\n\t\treturn metadata.NewIncomingContext(ctx, incomingMd)\n\t}\n\treturn metadata.NewIncomingContext(ctx, nil)\n}\n\nfunc (c Ctx) NewOutgoing(ctx context.Context, data ...g.Map) context.Context {\n\tif len(data) > 0 {\n\t\toutgoingMd := make(metadata.MD)\n\t\tfor key, value := range data[0] {\n\t\t\toutgoingMd.Set(key, gconv.String(value))\n\t\t}\n\t\treturn metadata.NewOutgoingContext(ctx, outgoingMd)\n\t}\n\treturn metadata.NewOutgoingContext(ctx, nil)\n}\n\nfunc (c Ctx) IncomingToOutgoing(ctx context.Context, keys ...string) context.Context {\n\tincomingMd, _ := metadata.FromIncomingContext(ctx)\n\tif incomingMd == nil {\n\t\treturn ctx\n\t}\n\toutgoingMd, _ := metadata.FromOutgoingContext(ctx)\n\tif outgoingMd == nil {\n\t\toutgoingMd = make(metadata.MD)\n\t}\n\tif len(keys) > 0 {\n\t\tfor _, key := range keys {\n\t\t\toutgoingMd[key] = append(outgoingMd[key], incomingMd.Get(key)...)\n\t\t}\n\t} else {\n\t\tfor key, values := range incomingMd {\n\t\t\toutgoingMd[key] = append(outgoingMd[key], values...)\n\t\t}\n\t}\n\treturn metadata.NewOutgoingContext(ctx, outgoingMd)\n}\n\nfunc (c Ctx) IncomingMap(ctx context.Context) *gmap.Map {\n\tvar (\n\t\tdata          = gmap.New()\n\t\tincomingMd, _ = metadata.FromIncomingContext(ctx)\n\t)\n\tfor key, values := range incomingMd {\n\t\tif len(values) == 1 {\n\t\t\tdata.Set(key, values[0])\n\t\t} else {\n\t\t\tdata.Set(key, values)\n\t\t}\n\t}\n\treturn data\n}\n\nfunc (c Ctx) OutgoingMap(ctx context.Context) *gmap.Map {\n\tvar (\n\t\tdata          = gmap.New()\n\t\toutgoingMd, _ = metadata.FromOutgoingContext(ctx)\n\t)\n\tfor key, values := range outgoingMd {\n\t\tif len(values) == 1 {\n\t\t\tdata.Set(key, values[0])\n\t\t} else {\n\t\t\tdata.Set(key, values)\n\t\t}\n\t}\n\treturn data\n}\n\nfunc (c Ctx) SetIncoming(ctx context.Context, data g.Map) context.Context {\n\tincomingMd, _ := metadata.FromIncomingContext(ctx)\n\tif incomingMd == nil {\n\t\tincomingMd = make(metadata.MD)\n\t}\n\tfor key, value := range data {\n\t\tincomingMd.Set(key, gconv.String(value))\n\t}\n\treturn metadata.NewIncomingContext(ctx, incomingMd)\n}\n\nfunc (c Ctx) SetOutgoing(ctx context.Context, data g.Map) context.Context {\n\toutgoingMd, _ := metadata.FromOutgoingContext(ctx)\n\tif outgoingMd == nil {\n\t\toutgoingMd = make(metadata.MD)\n\t}\n\tfor key, value := range data {\n\t\toutgoingMd.Set(key, gconv.String(value))\n\t}\n\treturn metadata.NewOutgoingContext(ctx, outgoingMd)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/resolver/resolver.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package resolver defines APIs for name resolution in gRPC.\npackage resolver\n\nimport (\n\t\"google.golang.org/grpc/resolver\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\nconst (\n\trawSvcKeyInSubConnInfo = `RawService`\n)\n\nfunc init() {\n\t// It registers default resolver here.\n\t// It uses default builder handling the name resolving for grpc service requests.\n\t// Use `grpc.WithResolver` to custom resolver for client.\n\tresolver.Register(NewBuilder(gsvc.GetRegistry()))\n}\n\n// Register sets the default Registry implements as your own implemented interface.\nfunc Register(registry gsvc.Registry) {\n\tif registry == nil {\n\t\tpanic(gerror.New(`invalid Registry value \"nil\" given`))\n\t}\n\tgsvc.SetRegistry(registry)\n\tresolver.Register(NewBuilder(registry))\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/resolver/resolver_builder.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage resolver\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/resolver\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// Builder is the builder for the etcd discovery resolver.\ntype Builder struct {\n\tdiscovery gsvc.Discovery\n}\n\n// NewBuilder creates and returns a Builder.\nfunc NewBuilder(discovery gsvc.Discovery) *Builder {\n\treturn &Builder{\n\t\tdiscovery: discovery,\n\t}\n}\n\n// Build creates a new etcd discovery resolver.\nfunc (b *Builder) Build(\n\ttarget resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions,\n) (resolver.Resolver, error) {\n\tvar (\n\t\terr         error\n\t\twatcher     gsvc.Watcher\n\t\twatchKey    = target.URL.Path\n\t\tctx, cancel = context.WithCancel(gctx.GetInitCtx())\n\t)\n\tg.Log().Debugf(ctx, `Watch key \"%s\"`, watchKey)\n\tif watcher, err = b.discovery.Watch(ctx, watchKey); err != nil {\n\t\tcancel()\n\t\treturn nil, gerror.Wrap(err, `registry.Watch failed`)\n\t}\n\tr := &Resolver{\n\t\tdiscovery: b.discovery,\n\t\twatcher:   watcher,\n\t\twatchKey:  watchKey,\n\t\tcc:        cc,\n\t\tctx:       ctx,\n\t\tcancel:    cancel,\n\t\tlogger:    g.Log(),\n\t}\n\tgo r.watch()\n\treturn r, nil\n}\n\n// Scheme return scheme of discovery\nfunc (*Builder) Scheme() string {\n\treturn gsvc.Schema\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/resolver/resolver_manager.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage resolver\n\nimport (\n\t\"google.golang.org/grpc/resolver\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Manager for Builder creating.\ntype Manager struct{}\n\n// New creates and returns a Builder.\nfunc (m Manager) New(discovery gsvc.Discovery) resolver.Builder {\n\treturn NewBuilder(discovery)\n}\n\n// Register sets the default Registry implements as your own implemented interface.\nfunc (m Manager) Register(registry gsvc.Registry) {\n\tRegister(registry)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/resolver/resolver_resolver.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/attributes\"\n\t\"google.golang.org/grpc/resolver\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\n// Resolver implements grpc resolver.Resolver,\n// which watches for the updates on the specified target.\n// Updates include address updates and service config updates.\ntype Resolver struct {\n\tdiscovery gsvc.Discovery      // Service discovery.\n\twatcher   gsvc.Watcher        // Service watcher\n\twatchKey  string              // Watched key.\n\tcc        resolver.ClientConn // GRPC client conn.\n\tctx       context.Context\n\tcancel    context.CancelFunc\n\tlogger    *glog.Logger\n}\n\nfunc (r *Resolver) watch() {\n\tvar (\n\t\terr      error\n\t\tservices []gsvc.Service\n\t)\n\t// It updates the resolver state in time.\n\tservices, err = r.discovery.Search(r.ctx, gsvc.SearchInput{\n\t\tPrefix: r.watchKey,\n\t})\n\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\tr.logger.Warningf(r.ctx, `discovery.Search error: %+v`, err)\n\t}\n\tif len(services) > 0 {\n\t\tr.update(services)\n\t}\n\t// Then watch.\n\tfor {\n\t\tselect {\n\t\tcase <-r.ctx.Done():\n\t\t\treturn\n\n\t\tdefault:\n\t\t\tservices, err = r.watcher.Proceed()\n\t\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\tr.logger.Warningf(r.ctx, `watcher.Proceed error: %+v`, err)\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(services) > 0 {\n\t\t\t\tr.update(services)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (r *Resolver) update(services []gsvc.Service) {\n\tvar (\n\t\terr       error\n\t\taddresses = make([]resolver.Address, 0)\n\t)\n\tfor _, service := range services {\n\t\tfor _, endpoint := range service.GetEndpoints() {\n\t\t\taddr := resolver.Address{\n\t\t\t\tAddr:       endpoint.String(),\n\t\t\t\tServerName: service.GetName(),\n\t\t\t\tAttributes: newAttributesFromMetadata(service.GetMetadata()),\n\t\t\t}\n\t\t\taddr.Attributes = addr.Attributes.WithValue(rawSvcKeyInSubConnInfo, service)\n\t\t\taddresses = append(addresses, addr)\n\t\t}\n\t}\n\tif len(addresses) == 0 {\n\t\tr.logger.Noticef(r.ctx, \"empty addresses parsed from: %+v\", services)\n\t\treturn\n\t}\n\tr.logger.Debugf(r.ctx, \"client conn updated with addresses %s\", gjson.MustEncodeString(addresses))\n\tif err = r.cc.UpdateState(resolver.State{Addresses: addresses}); err != nil {\n\t\tr.logger.Errorf(r.ctx, \"UpdateState failed: %+v\", err)\n\t}\n}\n\n// Close closes the resolver.\nfunc (r *Resolver) Close() {\n\tr.logger.Debugf(r.ctx, `resolver closed`)\n\tif err := r.watcher.Close(); err != nil {\n\t\tr.logger.Errorf(r.ctx, `%+v`, err)\n\t}\n\tr.cancel()\n}\n\n// ResolveNow will be called by gRPC to try to resolve the target name\n// again. It's just a hint, resolver can ignore this if it's not necessary.\n//\n// It could be called multiple times concurrently.\nfunc (r *Resolver) ResolveNow(options resolver.ResolveNowOptions) {\n\n}\n\nfunc newAttributesFromMetadata(metadata map[string]any) *attributes.Attributes {\n\tvar a *attributes.Attributes\n\tfor k, v := range metadata {\n\t\tif a == nil {\n\t\t\ta = attributes.New(k, v)\n\t\t} else {\n\t\t\ta = a.WithValue(k, v)\n\t\t}\n\t}\n\treturn a\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/tracing/tracing.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package tracing provide tracing feature for GRPC.\n//\n// Refer to: opentelemetry-go-contrib/instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go\npackage tracing\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/baggage\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\nconst (\n\t// GRPCStatusCodeKey is convention for numeric status code of a gRPC request.\n\tGRPCStatusCodeKey = attribute.Key(\"rpc.grpc.status_code\")\n)\n\nconst (\n\ttracingMaxContentLogSize         = 256 * 1024 // Max log size for request and response body.\n\ttracingInstrumentGrpcClient      = \"github.com/gogf/gf/contrib/rpc/grpcx/v2/krpc.GrpcClient\"\n\ttracingInstrumentGrpcServer      = \"github.com/gogf/gf/contrib/rpc/grpcx/v2/krpc.GrpcServer\"\n\ttracingEventGrpcRequest          = \"grpc.request\"\n\ttracingEventGrpcRequestBaggage   = \"grpc.request.baggage\"\n\ttracingEventGrpcMetadataOutgoing = \"grpc.metadata.outgoing\"\n\ttracingEventGrpcMetadataIncoming = \"grpc.metadata.incoming\"\n\ttracingEventGrpcResponse         = \"grpc.response\"\n)\n\ntype metadataSupplier struct {\n\tmetadata metadata.MD\n}\n\nfunc (s *metadataSupplier) Get(key string) string {\n\tvalues := s.metadata.Get(key)\n\tif len(values) == 0 {\n\t\treturn \"\"\n\t}\n\treturn values[0]\n}\n\nfunc (s *metadataSupplier) Set(key string, value string) {\n\ts.metadata.Set(key, value)\n}\n\nfunc (s *metadataSupplier) Keys() []string {\n\tvar (\n\t\tindex = 0\n\t\tkeys  = make([]string, s.metadata.Len())\n\t)\n\tfor k := range s.metadata {\n\t\tkeys[index] = k\n\t\tindex++\n\t}\n\treturn keys\n}\n\n// Inject injects correlation context and span context into the gRPC\n// metadata object. This function is meant to be used on outgoing\n// requests.\nfunc Inject(ctx context.Context, metadata metadata.MD) {\n\totel.GetTextMapPropagator().Inject(ctx, &metadataSupplier{\n\t\tmetadata: metadata,\n\t})\n}\n\n// Extract returns the correlation context and span context that\n// another service encoded in the gRPC metadata object with Inject.\n// This function is meant to be used on incoming requests.\nfunc Extract(ctx context.Context, metadata metadata.MD) (baggage.Baggage, trace.SpanContext) {\n\tctx = otel.GetTextMapPropagator().Extract(ctx, &metadataSupplier{\n\t\tmetadata: metadata,\n\t})\n\treturn baggage.FromContext(ctx), trace.SpanContextFromContext(ctx)\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/tracing/tracing_interceptor.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// https://github.com/open-telemetry/opentelemetry-go-contrib/blob/master/instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go\n\npackage tracing\n\n// gRPC tracing middleware\n// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/rpc.md\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.7.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"google.golang.org/grpc\"\n\tgrpcCodes \"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/peer\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\ntype messageType attribute.KeyValue\n\n// Event adds an event of the messageType to the span associated with the\n// passed context with id and size (if message is a proto message).\nfunc (m messageType) Event(ctx context.Context, id int, message any) {\n\tspan := trace.SpanFromContext(ctx)\n\tif p, ok := message.(proto.Message); ok {\n\t\tspan.AddEvent(\"message\", trace.WithAttributes(\n\t\t\tattribute.KeyValue(m),\n\t\t\tattribute.Key(\"message.id\").Int(id),\n\t\t\tattribute.Key(\"message.uncompressed_size\").Int(proto.Size(p)),\n\t\t))\n\t} else {\n\t\tspan.AddEvent(\"message\", trace.WithAttributes(\n\t\t\tattribute.KeyValue(m),\n\t\t\tattribute.Key(\"message.id\").Int(id),\n\t\t))\n\t}\n}\n\nvar (\n\tmessageSent     = messageType(attribute.Key(\"message.type\").String(\"SENT\"))\n\tmessageReceived = messageType(attribute.Key(\"message.type\").String(\"RECEIVED\"))\n)\n\ntype streamEventType int\n\ntype streamEvent struct {\n\tType streamEventType\n\tErr  error\n}\n\nconst (\n\tcloseEvent streamEventType = iota\n\treceiveEndEvent\n\terrorEvent\n)\n\n// clientStream  wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and\n// SendMsg method call.\ntype clientStream struct {\n\tgrpc.ClientStream\n\n\tdesc       *grpc.StreamDesc\n\tevents     chan streamEvent\n\teventsDone chan struct{}\n\tfinished   chan error\n\n\treceivedMessageID int\n\tsentMessageID     int\n}\n\nvar _ = proto.Marshal\n\nfunc (w *clientStream) RecvMsg(m any) error {\n\terr := w.ClientStream.RecvMsg(m)\n\n\tif err == nil && !w.desc.ServerStreams {\n\t\tw.sendStreamEvent(receiveEndEvent, nil)\n\t} else if errors.Is(err, io.EOF) {\n\t\tw.sendStreamEvent(receiveEndEvent, nil)\n\t} else if err != nil {\n\t\tw.sendStreamEvent(errorEvent, err)\n\t} else {\n\t\tw.receivedMessageID++\n\t\tmessageReceived.Event(w.Context(), w.receivedMessageID, m)\n\t}\n\n\treturn err\n}\n\nfunc (w *clientStream) SendMsg(m any) error {\n\terr := w.ClientStream.SendMsg(m)\n\n\tw.sentMessageID++\n\tmessageSent.Event(w.Context(), w.sentMessageID, m)\n\n\tif err != nil {\n\t\tw.sendStreamEvent(errorEvent, err)\n\t}\n\n\treturn err\n}\n\nfunc (w *clientStream) Header() (metadata.MD, error) {\n\tmd, err := w.ClientStream.Header()\n\n\tif err != nil {\n\t\tw.sendStreamEvent(errorEvent, err)\n\t}\n\n\treturn md, err\n}\n\nfunc (w *clientStream) CloseSend() error {\n\terr := w.ClientStream.CloseSend()\n\n\tif err != nil {\n\t\tw.sendStreamEvent(errorEvent, err)\n\t} else {\n\t\tw.sendStreamEvent(closeEvent, nil)\n\t}\n\n\treturn err\n}\n\nconst (\n\tclientClosedState byte = 1 << iota\n\treceiveEndedState\n)\n\nfunc wrapClientStream(s grpc.ClientStream, desc *grpc.StreamDesc) *clientStream {\n\tvar (\n\t\tevents     = make(chan streamEvent)\n\t\teventsDone = make(chan struct{})\n\t\tfinished   = make(chan error)\n\t)\n\tgo func() {\n\t\tdefer close(eventsDone)\n\t\t// Both streams have to be closed\n\t\tstate := byte(0)\n\t\tfor event := range events {\n\t\t\tswitch event.Type {\n\t\t\tcase closeEvent:\n\t\t\t\tstate |= clientClosedState\n\t\t\tcase receiveEndEvent:\n\t\t\t\tstate |= receiveEndedState\n\t\t\tcase errorEvent:\n\t\t\t\tfinished <- event.Err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif state == clientClosedState|receiveEndedState {\n\t\t\t\tfinished <- nil\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn &clientStream{\n\t\tClientStream: s,\n\t\tdesc:         desc,\n\t\tevents:       events,\n\t\teventsDone:   eventsDone,\n\t\tfinished:     finished,\n\t}\n}\n\nfunc (w *clientStream) sendStreamEvent(eventType streamEventType, err error) {\n\tselect {\n\tcase <-w.eventsDone:\n\tcase w.events <- streamEvent{Type: eventType, Err: err}:\n\t}\n}\n\n// serverStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and\n// SendMsg method call.\ntype serverStream struct {\n\tgrpc.ServerStream\n\tctx context.Context\n\n\treceivedMessageID int\n\tsentMessageID     int\n}\n\nfunc (w *serverStream) Context() context.Context {\n\treturn w.ctx\n}\n\nfunc (w *serverStream) RecvMsg(m any) error {\n\terr := w.ServerStream.RecvMsg(m)\n\n\tif err == nil {\n\t\tw.receivedMessageID++\n\t\tmessageReceived.Event(w.Context(), w.receivedMessageID, m)\n\t}\n\n\treturn err\n}\n\nfunc (w *serverStream) SendMsg(m any) error {\n\terr := w.ServerStream.SendMsg(m)\n\n\tw.sentMessageID++\n\tmessageSent.Event(w.Context(), w.sentMessageID, m)\n\n\treturn err\n}\n\nfunc wrapServerStream(ctx context.Context, ss grpc.ServerStream) *serverStream {\n\treturn &serverStream{\n\t\tServerStream: ss,\n\t\tctx:          ctx,\n\t}\n}\n\n// spanInfo returns a span name and all appropriate attributes from the gRPC\n// method and peer address.\nfunc spanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) {\n\tattrs := []attribute.KeyValue{attribute.Key(\"rpc.system\").String(\"grpc\")}\n\tname, mAttrs := parseFullMethod(fullMethod)\n\tattrs = append(attrs, mAttrs...)\n\tattrs = append(attrs, peerAttr(peerAddress)...)\n\treturn name, attrs\n}\n\n// peerAttr returns attributes about the peer address.\nfunc peerAttr(addr string) []attribute.KeyValue {\n\thost, port, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn []attribute.KeyValue(nil)\n\t}\n\n\tif host == \"\" {\n\t\thost = \"127.0.0.1\"\n\t}\n\n\treturn []attribute.KeyValue{\n\t\tsemconv.NetPeerIPKey.String(host),\n\t\tsemconv.NetPeerPortKey.String(port),\n\t}\n}\n\n// peerFromCtx returns a peer address from a context, if one exists.\nfunc peerFromCtx(ctx context.Context) string {\n\tp, ok := peer.FromContext(ctx)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\treturn p.Addr.String()\n}\n\n// parseFullMethod returns a span name following the OpenTelemetry semantic\n// conventions as well as all applicable span attribute.KeyValue attributes based\n// on a gRPC's FullMethod.\nfunc parseFullMethod(fullMethod string) (string, []attribute.KeyValue) {\n\tname := strings.TrimLeft(fullMethod, \"/\")\n\tparts := strings.SplitN(name, \"/\", 2)\n\tif len(parts) != 2 {\n\t\t// Invalid format, does not follow `/package.service/method`.\n\t\treturn name, []attribute.KeyValue(nil)\n\t}\n\n\tvar attrs []attribute.KeyValue\n\tif service := parts[0]; service != \"\" {\n\t\tattrs = append(attrs, semconv.RPCServiceKey.String(service))\n\t}\n\tif method := parts[1]; method != \"\" {\n\t\tattrs = append(attrs, semconv.RPCMethodKey.String(method))\n\t}\n\treturn name, attrs\n}\n\n// statusCodeAttr returns status code attribute based on given gRPC code.\nfunc statusCodeAttr(c grpcCodes.Code) attribute.KeyValue {\n\treturn GRPCStatusCodeKey.Int64(int64(c))\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/tracing/tracing_interceptor_client.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage tracing\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"google.golang.org/grpc\"\n\tgrpcCodes \"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/grpcctx\"\n)\n\n// UnaryClientInterceptor returns a grpc.UnaryClientInterceptor suitable\n// for use in a grpc.Dial call.\nfunc UnaryClientInterceptor(ctx context.Context, method string, req, reply any,\n\tcc *grpc.ClientConn, invoker grpc.UnaryInvoker, callOpts ...grpc.CallOption) error {\n\ttracer := otel.GetTracerProvider().Tracer(\n\t\ttracingInstrumentGrpcClient,\n\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t)\n\trequestMetadata, _ := metadata.FromOutgoingContext(ctx)\n\tmetadataCopy := requestMetadata.Copy()\n\tname, attr := spanInfo(method, cc.Target())\n\tvar span trace.Span\n\tctx, span = tracer.Start(\n\t\tctx,\n\t\tname,\n\t\ttrace.WithSpanKind(trace.SpanKindClient),\n\t\ttrace.WithAttributes(attr...),\n\t)\n\tdefer span.End()\n\n\tInject(ctx, metadataCopy)\n\n\tctx = metadata.NewOutgoingContext(ctx, metadataCopy)\n\n\t// If it is now using default trace provider, it then does no complex tracing jobs.\n\tif gtrace.IsUsingDefaultProvider() {\n\t\treturn invoker(ctx, method, req, reply, cc, callOpts...)\n\t}\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\tspan.AddEvent(tracingEventGrpcRequest, trace.WithAttributes(\n\t\tattribute.String(tracingEventGrpcRequestBaggage, gconv.String(gtrace.GetBaggageMap(ctx))),\n\t\tattribute.String(tracingEventGrpcMetadataOutgoing, gconv.String(grpcctx.Ctx{}.OutgoingMap(ctx))),\n\t))\n\n\terr := invoker(ctx, method, req, reply, cc, callOpts...)\n\n\tif err != nil {\n\t\ts, _ := status.FromError(err)\n\t\tspan.SetStatus(codes.Error, s.Message())\n\t\tspan.SetAttributes(statusCodeAttr(s.Code()))\n\t} else {\n\t\tspan.SetAttributes(statusCodeAttr(grpcCodes.OK))\n\t}\n\treturn err\n}\n\n// StreamClientInterceptor returns a grpc.StreamClientInterceptor suitable\n// for use in a grpc.Dial call.\nfunc StreamClientInterceptor(\n\tctx context.Context, desc *grpc.StreamDesc,\n\tcc *grpc.ClientConn, method string, streamer grpc.Streamer,\n\tcallOpts ...grpc.CallOption) (grpc.ClientStream, error) {\n\ttracer := otel.GetTracerProvider().Tracer(\n\t\ttracingInstrumentGrpcClient,\n\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t)\n\trequestMetadata, _ := metadata.FromOutgoingContext(ctx)\n\tmetadataCopy := requestMetadata.Copy()\n\tname, attr := spanInfo(method, cc.Target())\n\n\tvar span trace.Span\n\tctx, span = tracer.Start(\n\t\tctx,\n\t\tname,\n\t\ttrace.WithSpanKind(trace.SpanKindClient),\n\t\ttrace.WithAttributes(attr...),\n\t)\n\n\tInject(ctx, metadataCopy)\n\tctx = metadata.NewOutgoingContext(ctx, metadataCopy)\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\ts, err := streamer(ctx, desc, cc, method, callOpts...)\n\tstream := wrapClientStream(s, desc)\n\tgo func() {\n\t\tif err == nil {\n\t\t\terr = <-stream.finished\n\t\t}\n\n\t\tif err != nil {\n\t\t\ts, _ := status.FromError(err)\n\t\t\tspan.SetStatus(codes.Error, s.Message())\n\t\t\tspan.SetAttributes(statusCodeAttr(s.Code()))\n\t\t} else {\n\t\t\tspan.SetAttributes(statusCodeAttr(grpcCodes.OK))\n\t\t}\n\n\t\tspan.End()\n\t}()\n\n\treturn stream, err\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/tracing/tracing_interceptor_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage tracing\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/baggage\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"google.golang.org/grpc\"\n\tgrpcCodes \"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/grpcctx\"\n)\n\n// UnaryServerInterceptor returns a grpc.UnaryServerInterceptor suitable\n// for usage in a grpc.NewServer call.\nfunc UnaryServerInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\ttracer := otel.GetTracerProvider().Tracer(\n\t\ttracingInstrumentGrpcServer,\n\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t)\n\trequestMetadata, _ := metadata.FromIncomingContext(ctx)\n\tmetadataCopy := requestMetadata.Copy()\n\n\tentries, spanCtx := Extract(ctx, metadataCopy)\n\tctx = baggage.ContextWithBaggage(ctx, entries)\n\tctx = trace.ContextWithRemoteSpanContext(ctx, spanCtx)\n\tname, attr := spanInfo(info.FullMethod, peerFromCtx(ctx))\n\tctx, span := tracer.Start(\n\t\tctx,\n\t\tname,\n\t\ttrace.WithSpanKind(trace.SpanKindServer),\n\t\ttrace.WithAttributes(attr...),\n\t)\n\tdefer span.End()\n\n\t// If it is now using default trace provider, it then does no complex tracing jobs.\n\tif gtrace.IsUsingDefaultProvider() {\n\t\treturn handler(ctx, req)\n\t}\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\tspan.AddEvent(tracingEventGrpcRequest, trace.WithAttributes(\n\t\tattribute.String(tracingEventGrpcRequestBaggage, gconv.String(gtrace.GetBaggageMap(ctx))),\n\t\tattribute.String(tracingEventGrpcMetadataIncoming, gconv.String(grpcctx.Ctx{}.IncomingMap(ctx))),\n\t))\n\n\tres, err := handler(ctx, req)\n\n\tif err != nil {\n\t\ts, _ := status.FromError(err)\n\t\tspan.SetStatus(codes.Error, s.Message())\n\t\tspan.SetAttributes(statusCodeAttr(s.Code()))\n\t} else {\n\t\tspan.SetAttributes(statusCodeAttr(grpcCodes.OK))\n\t}\n\n\treturn res, err\n}\n\n// StreamServerInterceptor returns a grpc.StreamServerInterceptor suitable\n// for use in a grpc.NewServer call.\nfunc StreamServerInterceptor(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\ttracer := otel.GetTracerProvider().Tracer(\n\t\ttracingInstrumentGrpcServer,\n\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t)\n\n\tctx := ss.Context()\n\trequestMetadata, _ := metadata.FromIncomingContext(ctx)\n\tmetadataCopy := requestMetadata.Copy()\n\tentries, spanCtx := Extract(ctx, metadataCopy)\n\tctx = baggage.ContextWithBaggage(ctx, entries)\n\tctx = trace.ContextWithRemoteSpanContext(ctx, spanCtx)\n\tname, attr := spanInfo(info.FullMethod, peerFromCtx(ctx))\n\tctx, span := tracer.Start(\n\t\tctx,\n\t\tname,\n\t\ttrace.WithSpanKind(trace.SpanKindServer),\n\t\ttrace.WithAttributes(attr...),\n\t)\n\tdefer span.End()\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\terr := handler(srv, wrapServerStream(ctx, ss))\n\n\tif err != nil {\n\t\ts, _ := status.FromError(err)\n\t\tspan.SetStatus(codes.Error, s.Message())\n\t\tspan.SetAttributes(statusCodeAttr(s.Code()))\n\t} else {\n\t\tspan.SetAttributes(statusCodeAttr(grpcCodes.OK))\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/internal/utils/utils.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package utils provides utilities for GRPC.\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"unicode/utf8\"\n\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\nvar (\n\tprotoJSONMarshaller = &protojson.MarshalOptions{\n\t\tEmitUnpopulated: true,\n\t}\n)\n\n// MarshalPbMessageToJsonString marshals protobuf message to json string.\nfunc MarshalPbMessageToJsonString(msg proto.Message) string {\n\treturn protoJSONMarshaller.Format(msg)\n}\n\nfunc MarshalMessageToJsonStringForTracing(value any, msgType string, maxBytes int) string {\n\tvar messageContent string\n\tif msg, ok := value.(proto.Message); ok {\n\t\tif proto.Size(msg) <= maxBytes {\n\t\t\tmessageContent = MarshalPbMessageToJsonString(msg)\n\t\t} else {\n\t\t\tmessageContent = fmt.Sprintf(\n\t\t\t\t\"[%s Message Too Large For Tracing, Max: %d bytes]\",\n\t\t\t\tmsgType,\n\t\t\t\tmaxBytes,\n\t\t\t)\n\t\t}\n\t} else {\n\t\tmessageContent = fmt.Sprintf(\"%v\", value)\n\t}\n\n\tif !utf8.ValidString(messageContent) {\n\t\tmessageContent = fmt.Sprintf(\n\t\t\t\"[%s Message Is Invalid UTF-8 Content For Tracing]\",\n\t\t\tmsgType,\n\t\t)\n\t}\n\n\treturn messageContent\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/testdata/configuration/config.yaml",
    "content": "grpc:\n  name:             \"demo\"  # 服务名称\n  address:          \":8000\" # 自定义服务监听地址\n  logPath:          \"./log\" # 日志存储目录路径\n  logStdout:        true    # 日志是否输出到终端\n  errorLogEnabled:  true    # 是否开启错误日志记录\n  accessLogEnabled: true    # 是否开启访问日志记录\n  errorStack:       true    # 当产生错误时，是否记录错误堆栈\n  logger:\n    path:                  \"/tmp/log/\"   # 日志文件路径。默认为空，表示关闭，仅输出到终端\n    file:                  \"{Y-m-d}.log\" # 日志文件格式。默认为\"{Y-m-d}.log\"\n    prefix:                \"TestLogger\"  # 日志内容输出前缀。默认为空\n    level:                 \"all\"         # 日志输出级别\n    stdout:                false         # 日志是否同时输出到终端。默认true"
  },
  {
    "path": "contrib/rpc/grpcx/testdata/controller/helloworld.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage controller\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2\"\n\t\"github.com/gogf/gf/contrib/rpc/grpcx/v2/testdata/protobuf\"\n)\n\ntype Controller struct {\n\tprotobuf.UnimplementedGreeterServer\n}\n\nfunc Register(s *grpcx.GrpcServer) {\n\tprotobuf.RegisterGreeterServer(s.Server, &Controller{})\n}\n\n// SayHello implements helloworld.GreeterServer\nfunc (s *Controller) SayHello(ctx context.Context, in *protobuf.HelloRequest) (*protobuf.HelloReply, error) {\n\treturn &protobuf.HelloReply{Message: \"Hello \" + in.GetName()}, nil\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/testdata/protobuf/helloworld.pb.go",
    "content": "// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.28.1\n// \tprotoc        v3.21.12\n// source: helloworld.proto\n\npackage protobuf\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The request message containing the user's name.\ntype HelloRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n}\n\nfunc (x *HelloRequest) Reset() {\n\t*x = HelloRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_helloworld_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HelloRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HelloRequest) ProtoMessage() {}\n\nfunc (x *HelloRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_helloworld_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.\nfunc (*HelloRequest) Descriptor() ([]byte, []int) {\n\treturn file_helloworld_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *HelloRequest) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\n// The response message containing the greetings\ntype HelloReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tMessage string `protobuf:\"bytes,1,opt,name=message,proto3\" json:\"message,omitempty\"`\n}\n\nfunc (x *HelloReply) Reset() {\n\t*x = HelloReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_helloworld_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HelloReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HelloReply) ProtoMessage() {}\n\nfunc (x *HelloReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_helloworld_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.\nfunc (*HelloReply) Descriptor() ([]byte, []int) {\n\treturn file_helloworld_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *HelloReply) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nvar File_helloworld_proto protoreflect.FileDescriptor\n\nvar file_helloworld_proto_rawDesc = []byte{\n\t0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x22, 0x0a, 0x0c,\n\t0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,\n\t0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,\n\t0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,\n\t0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x45, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65,\n\t0x74, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12,\n\t0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,\n\t0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42,\n\t0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,\n\t0x67, 0x66, 0x2f, 0x67, 0x66, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,\n\t0x6c, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_helloworld_proto_rawDescOnce sync.Once\n\tfile_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc\n)\n\nfunc file_helloworld_proto_rawDescGZIP() []byte {\n\tfile_helloworld_proto_rawDescOnce.Do(func() {\n\t\tfile_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData)\n\t})\n\treturn file_helloworld_proto_rawDescData\n}\n\nvar file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_helloworld_proto_goTypes = []any{\n\t(*HelloRequest)(nil), // 0: protobuf.HelloRequest\n\t(*HelloReply)(nil),   // 1: protobuf.HelloReply\n}\nvar file_helloworld_proto_depIdxs = []int32{\n\t0, // 0: protobuf.Greeter.SayHello:input_type -> protobuf.HelloRequest\n\t1, // 1: protobuf.Greeter.SayHello:output_type -> protobuf.HelloReply\n\t1, // [1:2] is the sub-list for method output_type\n\t0, // [0:1] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_helloworld_proto_init() }\nfunc file_helloworld_proto_init() {\n\tif File_helloworld_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_helloworld_proto_msgTypes[0].Exporter = func(v any, i int) any {\n\t\t\tswitch v := v.(*HelloRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_helloworld_proto_msgTypes[1].Exporter = func(v any, i int) any {\n\t\t\tswitch v := v.(*HelloReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_helloworld_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_helloworld_proto_goTypes,\n\t\tDependencyIndexes: file_helloworld_proto_depIdxs,\n\t\tMessageInfos:      file_helloworld_proto_msgTypes,\n\t}.Build()\n\tFile_helloworld_proto = out.File\n\tfile_helloworld_proto_rawDesc = nil\n\tfile_helloworld_proto_goTypes = nil\n\tfile_helloworld_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/testdata/protobuf/helloworld.proto",
    "content": "// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto\n\nsyntax = \"proto3\";\n\npackage protobuf;\n\noption go_package = \"github.com/gogf/gf/grpc/example/helloworld/protobuf\";\n\n\n// The greeting service definition.\nservice Greeter {\n  // Sends a greeting\n  rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user's name.\nmessage HelloRequest {\n  string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "contrib/rpc/grpcx/testdata/protobuf/helloworld_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.2.0\n// - protoc             v3.21.12\n// source: helloworld.proto\n\npackage protobuf\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\n// GreeterClient is the client API for Greeter service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype GreeterClient interface {\n\t// Sends a greeting\n\tSayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)\n}\n\ntype greeterClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {\n\treturn &greeterClient{cc}\n}\n\nfunc (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {\n\tout := new(HelloReply)\n\terr := c.cc.Invoke(ctx, \"/protobuf.Greeter/SayHello\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// GreeterServer is the server API for Greeter service.\n// All implementations must embed UnimplementedGreeterServer\n// for forward compatibility\ntype GreeterServer interface {\n\t// Sends a greeting\n\tSayHello(context.Context, *HelloRequest) (*HelloReply, error)\n\tmustEmbedUnimplementedGreeterServer()\n}\n\n// UnimplementedGreeterServer must be embedded to have forward compatible implementations.\ntype UnimplementedGreeterServer struct {\n}\n\nfunc (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method SayHello not implemented\")\n}\nfunc (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}\n\n// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to GreeterServer will\n// result in compilation errors.\ntype UnsafeGreeterServer interface {\n\tmustEmbedUnimplementedGreeterServer()\n}\n\nfunc RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {\n\ts.RegisterService(&Greeter_ServiceDesc, srv)\n}\n\nfunc _Greeter_SayHello_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) {\n\tin := new(HelloRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(GreeterServer).SayHello(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/protobuf.Greeter/SayHello\",\n\t}\n\thandler := func(ctx context.Context, req any) (any, error) {\n\t\treturn srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar Greeter_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"protobuf.Greeter\",\n\tHandlerType: (*GreeterServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"SayHello\",\n\t\t\tHandler:    _Greeter_SayHello_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"helloworld.proto\",\n}\n"
  },
  {
    "path": "contrib/sdk/httpclient/go.mod",
    "content": "module github.com/gogf/gf/contrib/sdk/httpclient/v2\n\ngo 1.23.0\n\nrequire github.com/gogf/gf/v2 v2.10.0\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/sdk/httpclient/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/sdk/httpclient/httpclient.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package httpclient provides http client used for SDK.\npackage httpclient\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// Client is a http client for SDK.\ntype Client struct {\n\t*gclient.Client\n\tHandler\n}\n\n// New creates and returns a http client for SDK.\nfunc New(config Config) *Client {\n\tclient := config.Client\n\tif client == nil {\n\t\tclient = gclient.New()\n\t}\n\thandler := config.Handler\n\tif handler == nil {\n\t\thandler = NewDefaultHandler(config.Logger, config.RawDump)\n\t}\n\tif !gstr.HasPrefix(config.URL, \"http\") {\n\t\tconfig.URL = fmt.Sprintf(\"http://%s\", config.URL)\n\t}\n\treturn &Client{\n\t\tClient:  client.Prefix(config.URL),\n\t\tHandler: handler,\n\t}\n}\n\n// Request sends request to service by struct object `req`, and receives response to struct object `res`.\nfunc (c *Client) Request(ctx context.Context, req, res any) error {\n\tvar (\n\t\tmethod = gmeta.Get(req, gtag.Method).String()\n\t\tpath   = gmeta.Get(req, gtag.Path).String()\n\t)\n\tswitch gstr.ToUpper(method) {\n\tcase http.MethodGet:\n\t\treturn c.Get(ctx, path, req, res)\n\n\tdefault:\n\t\tresult, err := c.ContentJson().DoRequest(ctx, method, c.handlePath(path, req), req)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn c.HandleResponse(ctx, result, res)\n\t}\n}\n\n// Get sends a request using GET method.\nfunc (c *Client) Get(ctx context.Context, path string, in, out any) error {\n\t// TODO: Path params will also be built in urlParams, not graceful now.\n\tif urlParams := ghttp.BuildParams(in); urlParams != \"\" && urlParams != \"{}\" {\n\t\tpath += \"?\" + urlParams\n\t}\n\tres, err := c.ContentJson().Get(ctx, c.handlePath(path, in))\n\tif err != nil {\n\t\treturn gerror.Wrap(err, `http request failed`)\n\t}\n\treturn c.HandleResponse(ctx, res, out)\n}\n\nfunc (c *Client) handlePath(path string, in any) string {\n\tif gstr.Contains(path, \"{\") {\n\t\tdata := gconv.MapStrStr(in)\n\t\tpath, _ = gregex.ReplaceStringFuncMatch(`\\{(\\w+)\\}`, path, func(match []string) string {\n\t\t\tif v, ok := data[match[1]]; ok {\n\t\t\t\treturn gurl.Encode(v)\n\t\t\t}\n\t\t\treturn match[1]\n\t\t})\n\t}\n\treturn path\n}\n"
  },
  {
    "path": "contrib/sdk/httpclient/httpclient_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage httpclient\n\nimport (\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\n// Config is the configuration struct for SDK client.\ntype Config struct {\n\tURL     string          `v:\"required\"` // Service address. Eg: user.svc.local, http://user.svc.local\n\tClient  *gclient.Client // Custom underlying client.\n\tHandler Handler         // Custom response handler.\n\tLogger  *glog.Logger    // Custom logger.\n\tRawDump bool            // Whether auto dump request&response in stdout.\n}\n"
  },
  {
    "path": "contrib/sdk/httpclient/httpclient_handler.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage httpclient\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\n// Handler is the interface for http response handling.\ntype Handler interface {\n\t// HandleResponse handles the http response and transforms its body to the specified object.\n\t// The parameter `out` specifies the object that the response body is transformed to.\n\tHandleResponse(ctx context.Context, res *gclient.Response, out any) error\n}\n\n// DefaultHandler handle ghttp.DefaultHandlerResponse of json format.\ntype DefaultHandler struct {\n\tLogger  *glog.Logger\n\tRawDump bool\n}\n\nfunc NewDefaultHandler(logger *glog.Logger, rawRump bool) *DefaultHandler {\n\tif rawRump && logger == nil {\n\t\tlogger = g.Log()\n\t}\n\treturn &DefaultHandler{\n\t\tLogger:  logger,\n\t\tRawDump: rawRump,\n\t}\n}\n\nfunc (h DefaultHandler) HandleResponse(ctx context.Context, res *gclient.Response, out any) error {\n\tdefer res.Close()\n\tif h.RawDump {\n\t\th.Logger.Debugf(ctx, \"raw request&response:\\n%s\", res.Raw())\n\t}\n\tvar (\n\t\tresponseBytes = res.ReadAll()\n\t\tresult        = ghttp.DefaultHandlerResponse{\n\t\t\tData: out,\n\t\t}\n\t)\n\tif !json.Valid(responseBytes) {\n\t\treturn gerror.Newf(`invalid response content: %s`, responseBytes)\n\t}\n\tif err := json.Unmarshal(responseBytes, &result); err != nil {\n\t\treturn gerror.Wrapf(err, `json.Unmarshal failed with content:%s`, responseBytes)\n\t}\n\tif result.Code != gcode.CodeOK.Code() {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.New(result.Code, result.Message, nil),\n\t\t\tresult.Message,\n\t\t)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "contrib/sdk/httpclient/httpclient_z_unit_feature_handler_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage httpclient_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\n\t\"github.com/gogf/gf/contrib/sdk/httpclient/v2\"\n)\n\nfunc Test_HttpClient_With_Default_Handler(t *testing.T) {\n\ttype Req struct {\n\t\tg.Meta `path:\"/get\" method:\"get\"`\n\t}\n\ttype Res struct {\n\t\tUid  int\n\t\tName string\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tres := ghttp.DefaultHandlerResponse{\n\t\t\tData: Res{\n\t\t\t\tUid:  1,\n\t\t\t\tName: \"test\",\n\t\t\t},\n\t\t}\n\t\tr.Response.WriteJson(res)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := httpclient.New(httpclient.Config{\n\t\t\tURL: fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()),\n\t\t})\n\t\tvar (\n\t\t\treq = &Req{}\n\t\t\tres = &Res{}\n\t\t)\n\t\terr := client.Request(gctx.New(), req, res)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(res.Uid, 1)\n\t\tt.AssertEQ(res.Name, \"test\")\n\t})\n}\n\ntype CustomHandler struct{}\n\nfunc (c CustomHandler) HandleResponse(ctx context.Context, res *gclient.Response, out any) error {\n\tdefer res.Close()\n\tif pointer, ok := out.(*string); ok {\n\t\t*pointer = res.ReadAllString()\n\t} else {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"[CustomHandler] expectedType:'*string', but realType:'%T'\", out)\n\t}\n\treturn nil\n}\n\nfunc Test_HttpClient_With_Custom_Handler(t *testing.T) {\n\ttype Req struct {\n\t\tg.Meta `path:\"/get\" method:\"get\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.WriteExit(\"It is a test.\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tclient := httpclient.New(httpclient.Config{\n\t\tURL:     fmt.Sprintf(\"127.0.0.1:%d\", s.GetListenedPort()),\n\t\tHandler: CustomHandler{},\n\t})\n\treq := &Req{}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar res = new(string)\n\t\terr := client.Request(gctx.New(), req, res)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(*res, \"It is a test.\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar res string\n\t\terr := client.Request(gctx.New(), req, res)\n\t\tt.AssertEQ(err, gerror.NewCodef(gcode.CodeInvalidParameter, \"[CustomHandler] expectedType:'*string', but realType:'%T'\", res))\n\t})\n}\n"
  },
  {
    "path": "contrib/trace/otlpgrpc/go.mod",
    "content": "module github.com/gogf/gf/contrib/trace/otlpgrpc/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0\n\tgo.opentelemetry.io/otel/sdk v1.38.0\n\tgoogle.golang.org/grpc v1.75.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/cenkalti/backoff/v5 v5.0.3 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.opentelemetry.io/proto/otlp v1.7.1 // indirect\n\tgolang.org/x/net v0.43.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect\n\tgoogle.golang.org/protobuf v1.36.8 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/trace/otlpgrpc/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=\ngithub.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=\ngo.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=\ngolang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=\ngoogle.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=\ngoogle.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=\ngoogle.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=\ngoogle.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/trace/otlpgrpc/otlpgrpc.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package otlpgrpc provides gtrace.Tracer implementation using OpenTelemetry protocol.\npackage otlpgrpc\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\t\"go.opentelemetry.io/otel/sdk/trace\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.24.0\"\n\t\"google.golang.org/grpc/encoding/gzip\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n)\n\nconst (\n\ttracerHostnameTagKey = \"hostname\"\n)\n\n// Init initializes and registers `otlpgrpc` to global TracerProvider.\n//\n// The output parameter `Shutdown` is used for waiting exported trace spans to be uploaded,\n// which is useful if your program is ending, and you do not want to lose recent spans.\nfunc Init(serviceName, endpoint, traceToken string) (func(ctx context.Context), error) {\n\t// Try retrieving host ip for tracing info.\n\tvar (\n\t\tintranetIPArray, err = gipv4.GetIntranetIpArray()\n\t\thostIP               = \"NoHostIpFound\"\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(intranetIPArray) == 0 {\n\t\tif intranetIPArray, err = gipv4.GetIpArray(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif len(intranetIPArray) > 0 {\n\t\thostIP = intranetIPArray[0]\n\t}\n\n\tctx := context.Background()\n\ttraceExp, err := otlptrace.New(ctx, otlptracegrpc.NewClient(\n\t\totlptracegrpc.WithInsecure(),\n\t\totlptracegrpc.WithEndpoint(endpoint), // Replace the otel Agent Addr with the access point obtained in the prerequisite。\n\t\totlptracegrpc.WithHeaders(map[string]string{\"Authentication\": traceToken}),\n\t\totlptracegrpc.WithCompressor(gzip.Name)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tres, err := resource.New(ctx,\n\t\tresource.WithFromEnv(),\n\t\tresource.WithProcess(),\n\t\tresource.WithTelemetrySDK(),\n\t\tresource.WithHost(),\n\t\tresource.WithAttributes(\n\t\t\t// The name of the service displayed on the traceback end。\n\t\t\tsemconv.ServiceNameKey.String(serviceName),\n\t\t\tsemconv.HostNameKey.String(hostIP),\n\t\t\tattribute.String(tracerHostnameTagKey, hostIP),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttracerProvider := trace.NewTracerProvider(\n\t\t// AlwaysSample is a sampler that samples every trace.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#AlwaysSample\n\t\t// example see: [example/trace/provider/grpc/main.go](../../../../../example/trace/provider/grpc/main.go#L87)\n\t\ttrace.WithSampler(trace.AlwaysSample()),\n\t\t// WithResource returns a trace option that sets the resource to be associated with spans.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithResource\n\t\t// example see: [example/trace/provider/grpc/main.go](../../../../../example/trace/provider/grpc/main.go#L36)\n\t\ttrace.WithResource(res),\n\t\t// WithSpanProcessor returns a trace option that sets the span processor to be used by the trace provider.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithSpanProcessor\n\t\t// example see: [example/trace/provider/grpc/main.go](../../../../../example/trace/provider/grpc/main.go#L99)\n\t\ttrace.WithSpanProcessor(trace.NewBatchSpanProcessor(traceExp)),\n\t)\n\n\t// Set the global propagator to traceContext (not set by default).\n\totel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))\n\totel.SetTracerProvider(tracerProvider)\n\n\treturn func(ctx context.Context) {\n\t\tctx, cancel := context.WithTimeout(ctx, time.Second)\n\t\tdefer cancel()\n\t\tif err = tracerProvider.Shutdown(ctx); err != nil {\n\t\t\tg.Log().Errorf(ctx, \"Shutdown tracerProvider failed err:%+v\", err)\n\t\t} else {\n\t\t\tg.Log().Debug(ctx, \"Shutdown tracerProvider success\")\n\t\t}\n\t}, nil\n}\n"
  },
  {
    "path": "contrib/trace/otlphttp/go.mod",
    "content": "module github.com/gogf/gf/contrib/trace/otlphttp/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/gogf/gf/v2 v2.10.0\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0\n\tgo.opentelemetry.io/otel/sdk v1.38.0\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0 // indirect\n\tgithub.com/cenkalti/backoff/v5 v5.0.3 // indirect\n\tgithub.com/clbanning/mxj/v2 v2.7.0 // indirect\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.3 // indirect\n\tgithub.com/grokify/html-strip-tags-go v0.1.0 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect\n\tgithub.com/magiconair/properties v1.8.10 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.0 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.38.0 // indirect\n\tgo.opentelemetry.io/proto/otlp v1.7.1 // indirect\n\tgolang.org/x/net v0.43.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect\n\tgoogle.golang.org/grpc v1.75.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.8 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/gogf/gf/v2 => ../../../\n"
  },
  {
    "path": "contrib/trace/otlphttp/go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=\ngithub.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=\ngo.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=\ngolang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=\ngoogle.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=\ngoogle.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=\ngoogle.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=\ngoogle.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "contrib/trace/otlphttp/otlphttp.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package otlphttp provides gtrace.Tracer implementation using OpenTelemetry protocol.\npackage otlphttp\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\t\"go.opentelemetry.io/otel/sdk/trace\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.24.0\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n)\n\nconst (\n\ttracerHostnameTagKey = \"hostname\"\n)\n\n// Init initializes and registers `otlphttp` to global TracerProvider.\n//\n// The output parameter `Shutdown` is used for waiting exported trace spans to be uploaded,\n// which is useful if your program is ending, and you do not want to lose recent spans.\nfunc Init(serviceName, endpoint, path string) (func(ctx context.Context), error) {\n\t// Try retrieving host ip for tracing info.\n\tvar (\n\t\tintranetIPArray, err = gipv4.GetIntranetIpArray()\n\t\thostIP               = \"NoHostIpFound\"\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(intranetIPArray) == 0 {\n\t\tif intranetIPArray, err = gipv4.GetIpArray(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif len(intranetIPArray) > 0 {\n\t\thostIP = intranetIPArray[0]\n\t}\n\n\tctx := context.Background()\n\ttraceExp, err := otlptrace.New(ctx, otlptracehttp.NewClient(\n\t\totlptracehttp.WithEndpoint(endpoint),\n\t\totlptracehttp.WithURLPath(path),\n\t\totlptracehttp.WithInsecure(),\n\t\totlptracehttp.WithCompression(1),\n\t))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tres, err := resource.New(ctx,\n\t\tresource.WithFromEnv(),\n\t\tresource.WithProcess(),\n\t\tresource.WithTelemetrySDK(),\n\t\tresource.WithHost(),\n\t\tresource.WithAttributes(\n\t\t\t// The name of the service displayed on the traceback end。\n\t\t\tsemconv.ServiceNameKey.String(serviceName),\n\t\t\tsemconv.HostNameKey.String(hostIP),\n\t\t\tattribute.String(tracerHostnameTagKey, hostIP),\n\t\t),\n\t)\n\n\ttracerProvider := trace.NewTracerProvider(\n\t\t// AlwaysSample is a sampler that samples every trace.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#AlwaysSample\n\t\t// example see: [example/trace/provider/http/main.go](../../../../../example/trace/provider/http/main.go#L84)\n\t\ttrace.WithSampler(trace.AlwaysSample()),\n\t\t// WithResource returns a trace option that sets the resource to be associated with spans.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithResource\n\t\t// example see: [example/trace/provider/http/main.go](../../../../../example/trace/provider/http/main.go#L33)\n\t\ttrace.WithResource(res),\n\t\t// WithSpanProcessor returns a trace option that sets the span processor to be used by the trace provider.\n\t\t// see: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#WithSpanProcessor\n\t\t// example see: [example/trace/provider/http/main.go](../../../../../example/trace/provider/http/main.go#L96)\n\t\ttrace.WithSpanProcessor(trace.NewBatchSpanProcessor(traceExp)),\n\t)\n\n\t// Set the global propagator to traceContext (not set by default).\n\totel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))\n\totel.SetTracerProvider(tracerProvider)\n\n\treturn func(ctx context.Context) {\n\t\tctx, cancel := context.WithTimeout(ctx, time.Second)\n\t\tdefer cancel()\n\t\tif err = tracerProvider.Shutdown(ctx); err != nil {\n\t\t\tg.Log().Errorf(ctx, \"Shutdown tracerProvider failed err:%+v\", err)\n\t\t} else {\n\t\t\tg.Log().Debug(ctx, \"Shutdown tracerProvider success\")\n\t\t}\n\t}, nil\n}\n"
  },
  {
    "path": "crypto/gaes/gaes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gaes provides useful API for AES encryption/decryption algorithms.\npackage gaes\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\t// IVDefaultValue is the default value for IV.\n\tIVDefaultValue = \"I Love Go Frame!\"\n)\n\n// Encrypt is alias of EncryptCBC.\nfunc Encrypt(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {\n\treturn EncryptCBC(plainText, key, iv...)\n}\n\n// Decrypt is alias of DecryptCBC.\nfunc Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {\n\treturn DecryptCBC(cipherText, key, iv...)\n}\n\n// EncryptCBC encrypts `plainText` using CBC mode.\n// Note that the key must be 16/24/32 bit length.\n// The parameter `iv` initialization vector is unnecessary.\nfunc EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\tblockSize := block.BlockSize()\n\tplainText = PKCS7Padding(plainText, blockSize)\n\tivValue := ([]byte)(nil)\n\tif len(iv) > 0 {\n\t\tivValue = iv[0]\n\t} else {\n\t\tivValue = []byte(IVDefaultValue)\n\t}\n\tblockMode := cipher.NewCBCEncrypter(block, ivValue)\n\tcipherText := make([]byte, len(plainText))\n\tblockMode.CryptBlocks(cipherText, plainText)\n\n\treturn cipherText, nil\n}\n\n// DecryptCBC decrypts `cipherText` using CBC mode.\n// Note that the key must be 16/24/32 bit length.\n// The parameter `iv` initialization vector is unnecessary.\nfunc DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\tblockSize := block.BlockSize()\n\tif len(cipherText) < blockSize {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"cipherText too short\")\n\t}\n\tivValue := ([]byte)(nil)\n\tif len(iv) > 0 {\n\t\tivValue = iv[0]\n\t} else {\n\t\tivValue = []byte(IVDefaultValue)\n\t}\n\tif len(cipherText)%blockSize != 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"cipherText is not a multiple of the block size\")\n\t}\n\tblockModel := cipher.NewCBCDecrypter(block, ivValue)\n\tplainText := make([]byte, len(cipherText))\n\tblockModel.CryptBlocks(plainText, cipherText)\n\tplainText, e := PKCS7UnPadding(plainText, blockSize)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\treturn plainText, nil\n}\n\n// PKCS5Padding applies PKCS#5 padding to the source byte slice to match the given block size.\n//\n// If the block size is not provided, it defaults to 8.\nfunc PKCS5Padding(src []byte, blockSize ...int) []byte {\n\tblockSizeTemp := 8\n\tif len(blockSize) > 0 {\n\t\tblockSizeTemp = blockSize[0]\n\t}\n\treturn PKCS7Padding(src, blockSizeTemp)\n}\n\n// PKCS5UnPadding removes PKCS#5 padding from the source byte slice based on the given block size.\n//\n// If the block size is not provided, it defaults to 8.\nfunc PKCS5UnPadding(src []byte, blockSize ...int) ([]byte, error) {\n\tblockSizeTemp := 8\n\tif len(blockSize) > 0 {\n\t\tblockSizeTemp = blockSize[0]\n\t}\n\treturn PKCS7UnPadding(src, blockSizeTemp)\n}\n\n// PKCS7Padding applies PKCS#7 padding to the source byte slice to match the given block size.\nfunc PKCS7Padding(src []byte, blockSize int) []byte {\n\tpadding := blockSize - len(src)%blockSize\n\tpadtext := bytes.Repeat([]byte{byte(padding)}, padding)\n\treturn append(src, padtext...)\n}\n\n// PKCS7UnPadding removes PKCS#7 padding from the source byte slice based on the given block size.\nfunc PKCS7UnPadding(src []byte, blockSize int) ([]byte, error) {\n\tlength := len(src)\n\tif blockSize <= 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, fmt.Sprintf(\"invalid blockSize: %d\", blockSize))\n\t}\n\n\tif length%blockSize != 0 || length == 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid data len\")\n\t}\n\n\tunpadding := int(src[length-1])\n\tif unpadding > blockSize || unpadding == 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid unpadding\")\n\t}\n\n\tpadding := src[length-unpadding:]\n\tfor i := 0; i < unpadding; i++ {\n\t\tif padding[i] != byte(unpadding) {\n\t\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid padding\")\n\t\t}\n\t}\n\n\treturn src[:(length - unpadding)], nil\n}\n\n// EncryptCFB encrypts `plainText` using CFB mode.\n// Note that the key must be 16/24/32 bit length.\n// The parameter `iv` initialization vector is unnecessary.\nfunc EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\tblockSize := block.BlockSize()\n\tplainText, *padding = ZeroPadding(plainText, blockSize)\n\tivValue := ([]byte)(nil)\n\tif len(iv) > 0 {\n\t\tivValue = iv[0]\n\t} else {\n\t\tivValue = []byte(IVDefaultValue)\n\t}\n\tstream := cipher.NewCFBEncrypter(block, ivValue)\n\tcipherText := make([]byte, len(plainText))\n\tstream.XORKeyStream(cipherText, plainText)\n\treturn cipherText, nil\n}\n\n// DecryptCFB decrypts `plainText` using CFB mode.\n// Note that the key must be 16/24/32 bit length.\n// The parameter `iv` initialization vector is unnecessary.\nfunc DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\tif len(cipherText) < aes.BlockSize {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"cipherText too short\")\n\t}\n\tivValue := ([]byte)(nil)\n\tif len(iv) > 0 {\n\t\tivValue = iv[0]\n\t} else {\n\t\tivValue = []byte(IVDefaultValue)\n\t}\n\tstream := cipher.NewCFBDecrypter(block, ivValue)\n\tplainText := make([]byte, len(cipherText))\n\tstream.XORKeyStream(plainText, cipherText)\n\tplainText = ZeroUnPadding(plainText, unPadding)\n\treturn plainText, nil\n}\n\nfunc ZeroPadding(cipherText []byte, blockSize int) ([]byte, int) {\n\tpadding := blockSize - len(cipherText)%blockSize\n\tpadText := bytes.Repeat([]byte{byte(0)}, padding)\n\treturn append(cipherText, padText...), padding\n}\n\nfunc ZeroUnPadding(plaintext []byte, unPadding int) []byte {\n\tlength := len(plaintext)\n\treturn plaintext[:(length - unPadding)]\n}\n"
  },
  {
    "path": "crypto/gaes/gaes_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gaes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gaes\"\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tcontent          = []byte(\"pibigstar\")\n\tcontent_16, _    = gbase64.DecodeString(\"v1jqsGHId/H8onlVHR8Vaw==\")\n\tcontent_24, _    = gbase64.DecodeString(\"0TXOaj5KMoLhNWmJ3lxY1A==\")\n\tcontent_32, _    = gbase64.DecodeString(\"qM/Waw1kkWhrwzek24rCSA==\")\n\tcontent_16_iv, _ = gbase64.DecodeString(\"DqQUXiHgW/XFb6Qs98+hrA==\")\n\tcontent_32_iv, _ = gbase64.DecodeString(\"ZuLgAOii+lrD5KJoQ7yQ8Q==\")\n\t// iv 长度必须等于blockSize，只能为16\n\tiv         = []byte(\"Hello My GoFrame\")\n\tkey_16     = []byte(\"1234567891234567\")\n\tkey_17     = []byte(\"12345678912345670\")\n\tkey_24     = []byte(\"123456789123456789123456\")\n\tkey_32     = []byte(\"12345678912345678912345678912345\")\n\tkeys       = []byte(\"12345678912345678912345678912346\")\n\tkey_err    = []byte(\"1234\")\n\tkey_32_err = []byte(\"1234567891234567891234567891234 \")\n\n\t// cfb模式blockSize补位长度, add by zseeker\n\tpadding_size      = 16 - len(content)\n\tcontent_16_cfb, _ = gbase64.DecodeString(\"oSmget3aBDT1nJnBp8u6kA==\")\n)\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata, err := gaes.Encrypt(content, key_16)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, []byte(content_16))\n\t\tdata, err = gaes.Encrypt(content, key_24)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, []byte(content_24))\n\t\tdata, err = gaes.Encrypt(content, key_32)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, []byte(content_32))\n\t\tdata, err = gaes.Encrypt(content, key_16, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, []byte(content_16_iv))\n\t\tdata, err = gaes.Encrypt(content, key_32, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, []byte(content_32_iv))\n\t})\n}\n\nfunc TestDecrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdecrypt, err := gaes.Decrypt([]byte(content_16), key_16)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\n\t\tdecrypt, err = gaes.Decrypt([]byte(content_24), key_24)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\n\t\tdecrypt, err = gaes.Decrypt([]byte(content_32), key_32)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\n\t\tdecrypt, err = gaes.Decrypt([]byte(content_16_iv), key_16, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\n\t\tdecrypt, err = gaes.Decrypt([]byte(content_32_iv), key_32, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\n\t\tdecrypt, err = gaes.Decrypt([]byte(content_32_iv), keys, iv)\n\t\tt.Assert(err, \"invalid unpadding\")\n\t})\n}\n\nfunc TestEncryptErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// encrypt key error\n\t\t_, err := gaes.Encrypt(content, key_err)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// decrypt key error\n\t\tencrypt, err := gaes.Encrypt(content, key_16)\n\t\t_, err = gaes.Decrypt(encrypt, key_err)\n\t\tt.AssertNE(err, nil)\n\n\t\t// decrypt content too short error\n\t\t_, err = gaes.Decrypt([]byte(\"test\"), key_16)\n\t\tt.AssertNE(err, nil)\n\n\t\t// decrypt content size error\n\t\t_, err = gaes.Decrypt(key_17, key_16)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestPKCS5UnPaddingErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// PKCS5UnPadding blockSize zero\n\t\t_, err := gaes.PKCS5UnPadding(content, 0)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS5UnPadding src len zero\n\t\t_, err = gaes.PKCS5UnPadding([]byte(\"\"), 16)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS5UnPadding src len > blockSize\n\t\t_, err = gaes.PKCS5UnPadding(key_17, 16)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS5UnPadding src len > blockSize\n\t\t_, err = gaes.PKCS5UnPadding(key_32_err, 32)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// PKCS7UnPadding blockSize zero\n\t\t_, err := gaes.PKCS7UnPadding(content, 0)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS7UnPadding src len zero\n\t\t_, err = gaes.PKCS7UnPadding([]byte(\"\"), 16)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS7UnPadding src len > blockSize\n\t\t_, err = gaes.PKCS7UnPadding(key_17, 16)\n\t\tt.AssertNE(err, nil)\n\n\t\t// PKCS7UnPadding src len > blockSize\n\t\t_, err = gaes.PKCS7UnPadding(key_32_err, 32)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptCFB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar padding int = 0\n\t\tdata, err := gaes.EncryptCFB(content, key_16, &padding, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(padding, padding_size)\n\t\tt.Assert(data, []byte(content_16_cfb))\n\t})\n}\n\nfunc TestDecryptCFB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdecrypt, err := gaes.DecryptCFB([]byte(content_16_cfb), key_16, padding_size, iv)\n\t\tt.AssertNil(err)\n\t\tt.Assert(decrypt, content)\n\t})\n}\n"
  },
  {
    "path": "crypto/gcrc32/gcrc32.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcrc32 provides useful API for CRC32 encryption algorithms.\npackage gcrc32\n\nimport (\n\t\"hash/crc32\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encrypt encrypts any type of variable using CRC32 algorithms.\n// It uses gconv package to convert `v` to its bytes type.\nfunc Encrypt(v any) uint32 {\n\treturn crc32.ChecksumIEEE(gconv.Bytes(v))\n}\n"
  },
  {
    "path": "crypto/gcrc32/gcrc32_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gcrc32_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gcrc32\"\n\t\"github.com/gogf/gf/v2/crypto/gmd5\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"pibigstar\"\n\t\tresult := 693191136\n\t\tencrypt1 := gcrc32.Encrypt(s)\n\t\tencrypt2 := gcrc32.Encrypt([]byte(s))\n\t\tt.AssertEQ(int(encrypt1), result)\n\t\tt.AssertEQ(int(encrypt2), result)\n\n\t\tstrmd5, _ := gmd5.Encrypt(s)\n\t\ttest1 := gcrc32.Encrypt(strmd5)\n\t\ttest2 := gcrc32.Encrypt([]byte(strmd5))\n\t\tt.AssertEQ(test2, test1)\n\t})\n}\n"
  },
  {
    "path": "crypto/gdes/gdes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gdes provides useful API for DES encryption/decryption algorithms.\npackage gdes\n\nimport (\n\t\"bytes\"\n\t\"crypto/cipher\"\n\t\"crypto/des\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\tNOPADDING = iota\n\tPKCS5PADDING\n)\n\n// EncryptECB encrypts `plainText` using ECB mode.\nfunc EncryptECB(plainText []byte, key []byte, padding int) ([]byte, error) {\n\ttext, err := Padding(plainText, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcipherText := make([]byte, len(text))\n\tblock, err := des.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\n\tblockSize := block.BlockSize()\n\tfor i, count := 0, len(text)/blockSize; i < count; i++ {\n\t\tbegin, end := i*blockSize, i*blockSize+blockSize\n\t\tblock.Encrypt(cipherText[begin:end], text[begin:end])\n\t}\n\treturn cipherText, nil\n}\n\n// DecryptECB decrypts `cipherText` using ECB mode.\nfunc DecryptECB(cipherText []byte, key []byte, padding int) ([]byte, error) {\n\ttext := make([]byte, len(cipherText))\n\tblock, err := des.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\n\tblockSize := block.BlockSize()\n\tfor i, count := 0, len(text)/blockSize; i < count; i++ {\n\t\tbegin, end := i*blockSize, i*blockSize+blockSize\n\t\tblock.Decrypt(text[begin:end], cipherText[begin:end])\n\t}\n\n\tplainText, err := UnPadding(text, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn plainText, nil\n}\n\n// EncryptECBTriple encrypts `plainText` using TripleDES and ECB mode.\n// The length of the `key` should be either 16 or 24 bytes.\nfunc EncryptECBTriple(plainText []byte, key []byte, padding int) ([]byte, error) {\n\tif len(key) != 16 && len(key) != 24 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"key length error\")\n\t}\n\n\ttext, err := Padding(plainText, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar newKey []byte\n\tif len(key) == 16 {\n\t\tnewKey = append([]byte{}, key...)\n\t\tnewKey = append(newKey, key[:8]...)\n\t} else {\n\t\tnewKey = append([]byte{}, key...)\n\t}\n\n\tblock, err := des.NewTripleDESCipher(newKey)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key \"%s\"`, newKey)\n\t\treturn nil, err\n\t}\n\n\tblockSize := block.BlockSize()\n\tcipherText := make([]byte, len(text))\n\tfor i, count := 0, len(text)/blockSize; i < count; i++ {\n\t\tbegin, end := i*blockSize, i*blockSize+blockSize\n\t\tblock.Encrypt(cipherText[begin:end], text[begin:end])\n\t}\n\treturn cipherText, nil\n}\n\n// DecryptECBTriple decrypts `cipherText` using TripleDES and ECB mode.\n// The length of the `key` should be either 16 or 24 bytes.\nfunc DecryptECBTriple(cipherText []byte, key []byte, padding int) ([]byte, error) {\n\tif len(key) != 16 && len(key) != 24 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"key length error\")\n\t}\n\n\tvar newKey []byte\n\tif len(key) == 16 {\n\t\tnewKey = append([]byte{}, key...)\n\t\tnewKey = append(newKey, key[:8]...)\n\t} else {\n\t\tnewKey = append([]byte{}, key...)\n\t}\n\n\tblock, err := des.NewTripleDESCipher(newKey)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key \"%s\"`, newKey)\n\t\treturn nil, err\n\t}\n\n\tblockSize := block.BlockSize()\n\ttext := make([]byte, len(cipherText))\n\tfor i, count := 0, len(text)/blockSize; i < count; i++ {\n\t\tbegin, end := i*blockSize, i*blockSize+blockSize\n\t\tblock.Decrypt(text[begin:end], cipherText[begin:end])\n\t}\n\n\tplainText, err := UnPadding(text, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn plainText, nil\n}\n\n// EncryptCBC encrypts `plainText` using CBC mode.\nfunc EncryptCBC(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) {\n\tblock, err := des.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\n\tif len(iv) != block.BlockSize() {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid iv length\")\n\t}\n\n\ttext, err := Padding(plainText, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcipherText := make([]byte, len(text))\n\n\tencryptor := cipher.NewCBCEncrypter(block, iv)\n\tencryptor.CryptBlocks(cipherText, text)\n\n\treturn cipherText, nil\n}\n\n// DecryptCBC decrypts `cipherText` using CBC mode.\nfunc DecryptCBC(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) {\n\tblock, err := des.NewCipher(key)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\n\tif len(iv) != block.BlockSize() {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"iv length invalid\")\n\t}\n\n\ttext := make([]byte, len(cipherText))\n\tdecrypter := cipher.NewCBCDecrypter(block, iv)\n\tdecrypter.CryptBlocks(text, cipherText)\n\n\tplainText, err := UnPadding(text, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn plainText, nil\n}\n\n// EncryptCBCTriple encrypts `plainText` using TripleDES and CBC mode.\nfunc EncryptCBCTriple(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) {\n\tif len(key) != 16 && len(key) != 24 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"key length invalid\")\n\t}\n\n\tvar newKey []byte\n\tif len(key) == 16 {\n\t\tnewKey = append([]byte{}, key...)\n\t\tnewKey = append(newKey, key[:8]...)\n\t} else {\n\t\tnewKey = append([]byte{}, key...)\n\t}\n\n\tblock, err := des.NewTripleDESCipher(newKey)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key \"%s\"`, newKey)\n\t\treturn nil, err\n\t}\n\n\tif len(iv) != block.BlockSize() {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid iv length\")\n\t}\n\n\ttext, err := Padding(plainText, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcipherText := make([]byte, len(text))\n\tencrypter := cipher.NewCBCEncrypter(block, iv)\n\tencrypter.CryptBlocks(cipherText, text)\n\n\treturn cipherText, nil\n}\n\n// DecryptCBCTriple decrypts `cipherText` using TripleDES and CBC mode.\nfunc DecryptCBCTriple(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) {\n\tif len(key) != 16 && len(key) != 24 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"key length invalid\")\n\t}\n\n\tvar newKey []byte\n\tif len(key) == 16 {\n\t\tnewKey = append([]byte{}, key...)\n\t\tnewKey = append(newKey, key[:8]...)\n\t} else {\n\t\tnewKey = append([]byte{}, key...)\n\t}\n\n\tblock, err := des.NewTripleDESCipher(newKey)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key \"%s\"`, newKey)\n\t\treturn nil, err\n\t}\n\n\tif len(iv) != block.BlockSize() {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid iv length\")\n\t}\n\n\ttext := make([]byte, len(cipherText))\n\tdecrypter := cipher.NewCBCDecrypter(block, iv)\n\tdecrypter.CryptBlocks(text, cipherText)\n\n\tplainText, err := UnPadding(text, padding)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn plainText, nil\n}\n\nfunc PaddingPKCS5(text []byte, blockSize int) []byte {\n\tpadding := blockSize - len(text)%blockSize\n\tpadText := bytes.Repeat([]byte{byte(padding)}, padding)\n\treturn append(text, padText...)\n}\n\nfunc UnPaddingPKCS5(text []byte) []byte {\n\tlength := len(text)\n\tpadText := int(text[length-1])\n\treturn text[:(length - padText)]\n}\n\nfunc Padding(text []byte, padding int) ([]byte, error) {\n\tswitch padding {\n\tcase NOPADDING:\n\t\tif len(text)%8 != 0 {\n\t\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid text length\")\n\t\t}\n\n\tcase PKCS5PADDING:\n\t\treturn PaddingPKCS5(text, 8), nil\n\n\tdefault:\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type \"%d\"`, padding)\n\t}\n\n\treturn text, nil\n}\n\nfunc UnPadding(text []byte, padding int) ([]byte, error) {\n\tswitch padding {\n\tcase NOPADDING:\n\t\tif len(text)%8 != 0 {\n\t\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid text length\")\n\t\t}\n\n\tcase PKCS5PADDING:\n\t\treturn UnPaddingPKCS5(text), nil\n\n\tdefault:\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type \"%d\"`, padding)\n\t}\n\treturn text, nil\n}\n"
  },
  {
    "path": "crypto/gdes/gdes_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdes_test\n\nimport (\n\t\"encoding/hex\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gdes\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\terrKey     = []byte(\"1111111111111234123456789\")\n\terrIv      = []byte(\"123456789\")\n\terrPadding = 5\n)\n\nfunc TestDesECB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"11111111\")\n\t\ttext := []byte(\"12345678\")\n\t\tpadding := gdes.NOPADDING\n\t\tresult := \"858b176da8b12503\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptECB(text, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptECB(cipherText, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"12345678\")\n\n\t\t// encrypt err test. when throw exception,the err is not equal nil and the string is nil\n\t\terrEncrypt, err := gdes.EncryptECB(text, key, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\terrEncrypt, err = gdes.EncryptECB(text, errKey, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// err decrypt test.\n\t\terrDecrypt, err := gdes.DecryptECB(cipherText, errKey, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t\terrDecrypt, err = gdes.DecryptECB(cipherText, key, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"11111111\")\n\t\ttext := []byte(\"12345678\")\n\t\tpadding := gdes.PKCS5PADDING\n\t\terrPadding := 5\n\t\tresult := \"858b176da8b12503ad6a88b4fa37833d\"\n\t\tcipherText, err := gdes.EncryptECB(text, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptECB(cipherText, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"12345678\")\n\n\t\t// err test\n\t\terrEncrypt, err := gdes.EncryptECB(text, key, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\terrDecrypt, err := gdes.DecryptECB(cipherText, errKey, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t})\n}\n\nfunc Test3DesECB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"1111111111111234\")\n\t\ttext := []byte(\"1234567812345678\")\n\t\tpadding := gdes.NOPADDING\n\t\tresult := \"a23ee24b98c26263a23ee24b98c26263\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptECBTriple(text, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptECBTriple(cipherText, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"1234567812345678\")\n\t\t// err test\n\t\terrEncrypt, err := gdes.EncryptECB(text, key, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"111111111111123412345678\")\n\t\ttext := []byte(\"123456789\")\n\t\tpadding := gdes.PKCS5PADDING\n\t\terrPadding := 5\n\t\tresult := \"37989b1effc07a6d00ff89a7d052e79f\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptECBTriple(text, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptECBTriple(cipherText, key, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"123456789\")\n\t\t// err test, when key is err, but text and padding is right\n\t\terrEncrypt, err := gdes.EncryptECBTriple(text, errKey, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// when padding is err,but key and text is right\n\t\terrEncrypt, err = gdes.EncryptECBTriple(text, key, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// decrypt err test,when key is err\n\t\terrEncrypt, err = gdes.DecryptECBTriple(text, errKey, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t})\n}\n\nfunc TestDesCBC(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"11111111\")\n\t\ttext := []byte(\"1234567812345678\")\n\t\tpadding := gdes.NOPADDING\n\t\tiv := []byte(\"12345678\")\n\t\tresult := \"40826a5800608c87585ca7c9efabee47\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptCBC(text, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptCBC(cipherText, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"1234567812345678\")\n\t\t// encrypt err test.\n\t\terrEncrypt, err := gdes.EncryptCBC(text, errKey, iv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// the iv is err\n\t\terrEncrypt, err = gdes.EncryptCBC(text, key, errIv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// the padding is err\n\t\terrEncrypt, err = gdes.EncryptCBC(text, key, iv, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// decrypt err test. the key is err\n\t\terrDecrypt, err := gdes.DecryptCBC(cipherText, errKey, iv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t\t// the iv is err\n\t\terrDecrypt, err = gdes.DecryptCBC(cipherText, key, errIv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t\t// the padding is err\n\t\terrDecrypt, err = gdes.DecryptCBC(cipherText, key, iv, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"11111111\")\n\t\ttext := []byte(\"12345678\")\n\t\tpadding := gdes.PKCS5PADDING\n\t\tiv := []byte(\"12345678\")\n\t\tresult := \"40826a5800608c87100a25d86ac7c52c\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptCBC(text, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptCBC(cipherText, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"12345678\")\n\t\t// err test\n\t\terrEncrypt, err := gdes.EncryptCBC(text, key, errIv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t})\n}\n\nfunc Test3DesCBC(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"1111111112345678\")\n\t\ttext := []byte(\"1234567812345678\")\n\t\tpadding := gdes.NOPADDING\n\t\tiv := []byte(\"12345678\")\n\t\tresult := \"bfde1394e265d5f738d5cab170c77c88\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptCBCTriple(text, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptCBCTriple(cipherText, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"1234567812345678\")\n\t\t// encrypt err test\n\t\terrEncrypt, err := gdes.EncryptCBCTriple(text, errKey, iv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// the iv is err\n\t\terrEncrypt, err = gdes.EncryptCBCTriple(text, key, errIv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// the padding is err\n\t\terrEncrypt, err = gdes.EncryptCBCTriple(text, key, iv, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, nil)\n\t\t// decrypt err test\n\t\terrDecrypt, err := gdes.DecryptCBCTriple(cipherText, errKey, iv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t\t// the iv is err\n\t\terrDecrypt, err = gdes.DecryptCBCTriple(cipherText, key, errIv, padding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t\t// the padding is err\n\t\terrDecrypt, err = gdes.DecryptCBCTriple(cipherText, key, iv, errPadding)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errDecrypt, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := []byte(\"111111111234567812345678\")\n\t\ttext := []byte(\"12345678\")\n\t\tpadding := gdes.PKCS5PADDING\n\t\tiv := []byte(\"12345678\")\n\t\tresult := \"40826a5800608c87100a25d86ac7c52c\"\n\t\t// encrypt test\n\t\tcipherText, err := gdes.EncryptCBCTriple(text, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(hex.EncodeToString(cipherText), result)\n\t\t// decrypt test\n\t\tclearText, err := gdes.DecryptCBCTriple(cipherText, key, iv, padding)\n\t\tt.AssertEQ(err, nil)\n\t\tt.AssertEQ(string(clearText), \"12345678\")\n\t})\n\n}\n"
  },
  {
    "path": "crypto/gmd5/gmd5.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmd5 provides useful API for MD5 encryption algorithms.\npackage gmd5\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encrypt encrypts any type of variable using MD5 algorithms.\n// It uses gconv package to convert `v` to its bytes type.\nfunc Encrypt(data any) (encrypt string, err error) {\n\treturn EncryptBytes(gconv.Bytes(data))\n}\n\n// MustEncrypt encrypts any type of variable using MD5 algorithms.\n// It uses gconv package to convert `v` to its bytes type.\n// It panics if any error occurs.\nfunc MustEncrypt(data any) string {\n\tresult, err := Encrypt(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// EncryptBytes encrypts `data` using MD5 algorithms.\nfunc EncryptBytes(data []byte) (encrypt string, err error) {\n\th := md5.New()\n\tif _, err = h.Write(data); err != nil {\n\t\terr = gerror.Wrap(err, `hash.Write failed`)\n\t\treturn \"\", err\n\t}\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil)), nil\n}\n\n// MustEncryptBytes encrypts `data` using MD5 algorithms.\n// It panics if any error occurs.\nfunc MustEncryptBytes(data []byte) string {\n\tresult, err := EncryptBytes(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// EncryptString encrypts string `data` using MD5 algorithms.\nfunc EncryptString(data string) (encrypt string, err error) {\n\treturn EncryptBytes([]byte(data))\n}\n\n// MustEncryptString encrypts string `data` using MD5 algorithms.\n// It panics if any error occurs.\nfunc MustEncryptString(data string) string {\n\tresult, err := EncryptString(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// EncryptFile encrypts file content of `path` using MD5 algorithms.\nfunc EncryptFile(path string) (encrypt string, err error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\th := md5.New()\n\t_, err = io.Copy(h, f)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn \"\", err\n\t}\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil)), nil\n}\n\n// MustEncryptFile encrypts file content of `path` using MD5 algorithms.\n// It panics if any error occurs.\nfunc MustEncryptFile(path string) string {\n\tresult, err := EncryptFile(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "crypto/gmd5/gmd5_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gmd5_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gmd5\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\ts = \"pibigstar\"\n\t// online generated MD5 value\n\tresult = \"d175a1ff66aedde64344785f7f7a3df8\"\n)\n\ntype user struct {\n\tname     string\n\tpassword string\n\tage      int\n}\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tencryptString, _ := gmd5.Encrypt(s)\n\t\tt.Assert(encryptString, result)\n\n\t\tresult := \"1427562bb29f88a1161590b76398ab72\"\n\t\tencrypt, _ := gmd5.Encrypt(123456)\n\t\tt.AssertEQ(encrypt, result)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := &user{\n\t\t\tname:     \"派大星\",\n\t\t\tpassword: \"123456\",\n\t\t\tage:      23,\n\t\t}\n\t\tresult := \"70917ebce8bd2f78c736cda63870fb39\"\n\t\tencrypt, _ := gmd5.Encrypt(user)\n\t\tt.AssertEQ(encrypt, result)\n\t})\n}\n\nfunc TestEncryptString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tencryptString, _ := gmd5.EncryptString(s)\n\t\tt.Assert(encryptString, result)\n\t})\n}\n\nfunc TestEncryptFile(t *testing.T) {\n\tpath := \"test.text\"\n\terrorPath := \"err.txt\"\n\tresult := \"e6e6e1cd41895beebff16d5452dfce12\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfile, err := os.Create(path)\n\t\tdefer os.Remove(path)\n\t\tdefer file.Close()\n\t\tt.AssertNil(err)\n\t\t_, _ = file.Write([]byte(\"Hello Go Frame\"))\n\t\tencryptFile, _ := gmd5.EncryptFile(path)\n\t\tt.AssertEQ(encryptFile, result)\n\t\t// when the file is not exist,encrypt will return empty string\n\t\terrEncrypt, _ := gmd5.EncryptFile(errorPath)\n\t\tt.AssertEQ(errEncrypt, \"\")\n\t})\n\n}\n"
  },
  {
    "path": "crypto/grsa/README.md",
    "content": "# GoFrame RSA Package\n\nPackage `grsa` provides useful API for RSA encryption/decryption algorithms within the GoFrame framework.\n\n## Features\n\n- Generating RSA key pairs in PKCS#1 and PKCS#8 formats\n- Encrypting and decrypting data with various key formats\n- Handling Base64 encoded keys\n- Detecting private key types\n- Plaintext size validation\n- **OAEP padding support (recommended for new applications)**\n\n## Security Considerations\n\nThis package provides two padding schemes for RSA encryption:\n\n### 1. PKCS#1 v1.5 (Legacy)\n\nUsed by `Encrypt*`, `DecryptPKCS1*`, `DecryptPKCS8*` functions.\n\n⚠️ **Security Warning**: PKCS#1 v1.5 padding is considered less secure and vulnerable to padding oracle attacks. It is provided for backward compatibility with existing systems.\n\n### 2. OAEP (Recommended)\n\nUsed by `EncryptOAEP*`, `DecryptOAEP*` functions.\n\n✅ **Recommended**: OAEP (Optimal Asymmetric Encryption Padding) provides better security guarantees and should be used for all new applications.\n\n## Quick Start\n\n### Basic Encryption/Decryption (OAEP - Recommended)\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/gogf/gf/v2/crypto/grsa\"\n)\n\nfunc main() {\n    // Generate a default RSA key pair (2048 bits)\n    privateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n    if err != nil {\n        panic(err)\n    }\n\n    // Data to encrypt\n    plainText := []byte(\"Hello, World!\")\n\n    // Encrypt with public key using OAEP (recommended)\n    cipherText, err := grsa.EncryptOAEP(plainText, publicKey)\n    if err != nil {\n        panic(err)\n    }\n\n    // Decrypt with private key using OAEP\n    decryptedText, err := grsa.DecryptOAEP(cipherText, privateKey)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(string(decryptedText)) // Output: Hello, World!\n}\n```\n\n### Legacy Encryption/Decryption (PKCS#1 v1.5)\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/gogf/gf/v2/crypto/grsa\"\n)\n\nfunc main() {\n    // Generate a default RSA key pair (2048 bits)\n    privateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n    if err != nil {\n        panic(err)\n    }\n\n    // Data to encrypt\n    plainText := []byte(\"Hello, World!\")\n\n    // Encrypt with public key (PKCS#1 v1.5 - legacy)\n    cipherText, err := grsa.Encrypt(plainText, publicKey)\n    if err != nil {\n        panic(err)\n    }\n\n    // Decrypt with private key\n    decryptedText, err := grsa.Decrypt(cipherText, privateKey)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(string(decryptedText)) // Output: Hello, World!\n}\n```\n\n### Working with Base64 Encoded Keys\n\n```go\npackage main\n\nimport (\n    \"encoding/base64\"\n    \"fmt\"\n    \"github.com/gogf/gf/v2/crypto/grsa\"\n)\n\nfunc main() {\n    // Generate a key pair\n    privateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n    if err != nil {\n        panic(err)\n    }\n\n    // Encode keys to Base64\n    privateKeyBase64 := base64.StdEncoding.EncodeToString(privateKey)\n    publicKeyBase64 := base64.StdEncoding.EncodeToString(publicKey)\n\n    // Data to encrypt\n    plainText := []byte(\"Hello, Base64 World!\")\n\n    // Encrypt with Base64 encoded public key using OAEP (recommended)\n    cipherTextBase64, err := grsa.EncryptOAEPBase64(plainText, publicKeyBase64)\n    if err != nil {\n        panic(err)\n    }\n\n    // Decrypt with Base64 encoded private key using OAEP\n    decryptedText, err := grsa.DecryptOAEPBase64(cipherTextBase64, privateKeyBase64)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(string(decryptedText)) // Output: Hello, Base64 World!\n}\n```\n\n## Functions\n\n### Key Generation\n\n- `GenerateKeyPair(bits int)`: Generates a new RSA key pair with the given bits in PKCS#1 format\n- `GenerateKeyPairPKCS8(bits int)`: Generates a new RSA key pair with the given bits in PKCS#8 format\n- `GenerateDefaultKeyPair()`: Generates a new RSA key pair with default bits (2048) in PKCS#1 format\n\n### OAEP Encryption/Decryption (Recommended)\n\n- `EncryptOAEP(plainText, publicKey []byte)`: Encrypts data with public key using OAEP padding (SHA-256)\n- `DecryptOAEP(cipherText, privateKey []byte)`: Decrypts data with private key using OAEP padding (SHA-256)\n- `EncryptOAEPBase64(plainText []byte, publicKeyBase64 string)`: Encrypts data with OAEP and returns base64-encoded result\n- `DecryptOAEPBase64(cipherTextBase64, privateKeyBase64 string)`: Decrypts base64-encoded OAEP data\n- `EncryptOAEPWithHash(plainText, publicKey, label []byte, hash hash.Hash)`: Encrypts with custom hash function\n- `DecryptOAEPWithHash(cipherText, privateKey, label []byte, hash hash.Hash)`: Decrypts with custom hash function\n\n### General Encryption/Decryption (Legacy - PKCS#1 v1.5)\n\n- `Encrypt(plainText, publicKey []byte)`: Encrypts data with public key (auto-detect format)\n- `Decrypt(cipherText, privateKey []byte)`: Decrypts data with private key (auto-detect format)\n- `EncryptBase64(plainText []byte, publicKeyBase64 string)`: Encrypts data with base64-encoded public key and returns base64-encoded result\n- `DecryptBase64(cipherTextBase64, privateKeyBase64 string)`: Decrypts base64-encoded data with base64-encoded private key\n\n### PKCS#1 Specific Functions (Legacy)\n\n- `EncryptPKCS1(plainText, publicKey []byte)`: Encrypts data with PKCS#1 format public key\n- `DecryptPKCS1(cipherText, privateKey []byte)`: Decrypts data with PKCS#1 format private key\n- `EncryptPKCS1Base64(plainText []byte, publicKeyBase64 string)`: Encrypts data with PKCS#1 public key and returns base64-encoded result\n- `DecryptPKCS1Base64(cipherTextBase64, privateKeyBase64 string)`: Decrypts base64-encoded data with PKCS#1 private key\n\n### PKIX Specific Functions (Legacy)\n\nPKIX (X.509) is the standard format for public keys, used with PKCS#8 private keys.\n\n- `EncryptPKIX(plainText, publicKey []byte)`: Encrypts data with PKIX format public key\n- `EncryptPKIXBase64(plainText []byte, publicKeyBase64 string)`: Encrypts data with PKIX public key and returns base64-encoded result\n- `DecryptPKCS8(cipherText, privateKey []byte)`: Decrypts data with PKCS#8 format private key\n- `DecryptPKCS8Base64(cipherTextBase64, privateKeyBase64 string)`: Decrypts base64-encoded data with PKCS#8 private key\n\n### Deprecated Functions\n\nThe following functions are deprecated and will be removed in future versions:\n\n- `EncryptPKCS8(plainText, publicKey []byte)`: Use `EncryptPKIX` instead\n- `EncryptPKCS8Base64(plainText []byte, publicKeyBase64 string)`: Use `EncryptPKIXBase64` instead\n\n### Utility Functions\n\n- `GetPrivateKeyType(privateKey []byte)`: Detects the type of private key (PKCS#1 or PKCS#8)\n- `GetPrivateKeyTypeBase64(privateKeyBase64 string)`: Detects the type of base64 encoded private key\n- `ExtractPKCS1PublicKey(privateKey []byte)`: Extracts PKCS#1 public key from PKCS#1 private key\n\n## Key Formats\n\nThe package supports two popular RSA key formats:\n\n1. **PKCS#1**: Traditional RSA key format\n   - Private key PEM header: `-----BEGIN RSA PRIVATE KEY-----`\n   - Public key PEM header: `-----BEGIN RSA PUBLIC KEY-----`\n\n2. **PKCS#8/PKIX**: More modern and flexible key format\n   - Private key PEM header: `-----BEGIN PRIVATE KEY-----`\n   - Public key PEM header: `-----BEGIN PUBLIC KEY-----`\n\nBoth formats are supported for encryption and decryption operations, with auto-detection capabilities for general functions.\n\n### Technical Background: PKCS#8 vs PKIX\n\n**PKCS#8** is a standard for **private keys** only, not public keys. Public keys use the **PKIX (X.509 SubjectPublicKeyInfo)** format.\n\n| Format | Private Key PEM Header | Public Key PEM Header |\n|--------|------------------------|----------------------|\n| PKCS#1 | `RSA PRIVATE KEY` | `RSA PUBLIC KEY` |\n| PKCS#8/PKIX | `PRIVATE KEY` | `PUBLIC KEY` |\n\nWhen we refer to a \"PKCS#8 key pair\", it actually means:\n- **Private key**: PKCS#8 format (RFC 5208)\n- **Public key**: PKIX/SubjectPublicKeyInfo format (RFC 5280, X.509)\n\nThis is why the Go standard library provides `x509.MarshalPKCS8PrivateKey` for private keys but `x509.MarshalPKIXPublicKey` for public keys — there is no `MarshalPKCS8PublicKey` function.\n\nThe deprecated `EncryptPKCS8` function was a misnomer because encryption uses public keys, and public keys are in PKIX format, not PKCS#8. The correct function name is `EncryptPKIX`.\n\n## Plaintext Size Limit\n\nRSA encryption has a size limit based on key size and padding scheme.\n\n### PKCS#1 v1.5 Padding (Legacy)\n\n- **Max plaintext size = key_size_in_bytes - 11**\n- For a 2048-bit key: max 245 bytes\n- For a 4096-bit key: max 501 bytes\n\n### OAEP Padding with SHA-256 (Recommended)\n\n- **Max plaintext size = key_size_in_bytes - 2 × hash_size - 2**\n- For a 2048-bit key with SHA-256: max 190 bytes\n- For a 4096-bit key with SHA-256: max 446 bytes\n\nIf you need to encrypt larger data, consider using hybrid encryption (RSA + AES).\n\n## Error Handling\n\nAll functions return descriptive errors that can be handled using the GoFrame error package (`gerror`). Errors typically include:\n\n- Invalid key format\n- Failed key parsing\n- Plaintext too long\n- Encryption/decryption failures\n\nAlways check for errors in production code to ensure robust handling of edge cases.\n\n## Testing\n\nRun the package tests with:\n\n```bash\ngo test -v\n```\n"
  },
  {
    "path": "crypto/grsa/grsa.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package grsa provides useful API for RSA encryption/decryption algorithms.\n//\n// This package includes functionality for:\n// - Generating RSA key pairs in PKCS#1 and PKCS#8 formats\n// - Encrypting and decrypting data with various key formats\n// - Handling Base64 encoded keys\n// - Detecting private key types\n//\n// # Security Considerations\n//\n// This package provides two padding schemes for RSA encryption:\n//\n// 1. PKCS#1 v1.5 (legacy): Used by Encrypt*, DecryptPKCS1*, DecryptPKCS8* functions.\n// This padding scheme is considered less secure and vulnerable to padding oracle attacks.\n// It is provided for backward compatibility with existing systems.\n//\n// 2. OAEP (recommended): Used by EncryptOAEP*, DecryptOAEP* functions.\n// OAEP (Optimal Asymmetric Encryption Padding) is the recommended padding scheme\n// for new applications as it provides better security guarantees.\n//\n// For new implementations, prefer using OAEP functions (EncryptOAEP, DecryptOAEP, etc.).\npackage grsa\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/pem\"\n\t\"hash\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\t// DefaultRSAKeyBits is the default bit size for RSA key generation\n\tDefaultRSAKeyBits = 2048\n\n\t// KeyTypePKCS1 represents PKCS#1 format private key\n\tKeyTypePKCS1 = \"PKCS#1\"\n\t// KeyTypePKCS8 represents PKCS#8 format private key\n\tKeyTypePKCS8 = \"PKCS#8\"\n\n\t// PEM block types\n\tpemTypeRSAPrivateKey = \"RSA PRIVATE KEY\" // PKCS#1 private key\n\tpemTypePrivateKey    = \"PRIVATE KEY\"     // PKCS#8 private key\n\tpemTypeRSAPublicKey  = \"RSA PUBLIC KEY\"  // PKCS#1 public key\n\tpemTypePublicKey     = \"PUBLIC KEY\"      // PKIX public key\n)\n\n// Encrypt encrypts data with public key using PKCS#1 v1.5 padding (auto-detect format).\n// The publicKey can be either PKCS#1 or PKCS#8 (PKIX) format.\n//\n// Note: RSA encryption has a size limit based on key size.\n// For PKCS#1 v1.5 padding, max plaintext size = key_size_in_bytes - 11.\n// For example, a 2048-bit key can encrypt at most 245 bytes.\n//\n// Security Warning: PKCS#1 v1.5 padding is vulnerable to padding oracle attacks.\n// For new applications, consider using EncryptOAEP instead.\nfunc Encrypt(plainText, publicKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(publicKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid public key\")\n\t}\n\n\t// Try PKCS#8 (PKIX) first\n\tpub, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\t// Try PKCS#1\n\t\tpub, err = x509.ParsePKCS1PublicKey(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse public key\")\n\t\t}\n\t}\n\n\trsaPub, ok := pub.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA public key\")\n\t}\n\n\t// Validate plaintext size for PKCS#1 v1.5 padding\n\tmaxSize := rsaPub.Size() - 11\n\tif len(plainText) > maxSize {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter,\n\t\t\t\"plaintext too long: max %d bytes for this key, got %d bytes\", maxSize, len(plainText))\n\t}\n\n\treturn rsa.EncryptPKCS1v15(rand.Reader, rsaPub, plainText)\n}\n\n// Decrypt decrypts data with private key using PKCS#1 v1.5 padding (auto-detect format).\n// The privateKey can be either PKCS#1 or PKCS#8 format.\n//\n// Security Warning: PKCS#1 v1.5 padding is vulnerable to padding oracle attacks.\n// For new applications, consider using DecryptOAEP instead.\nfunc Decrypt(cipherText, privateKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\t// Try PKCS#8 first\n\tpriv, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tif err != nil {\n\t\t// Try PKCS#1\n\t\tpriv, err = x509.ParsePKCS1PrivateKey(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse private key\")\n\t\t}\n\t}\n\n\trsaPriv, ok := priv.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA private key\")\n\t}\n\n\treturn rsa.DecryptPKCS1v15(rand.Reader, rsaPriv, cipherText)\n}\n\n// EncryptBase64 encrypts data with base64-encoded public key (auto-detect format)\n// and returns base64-encoded result.\nfunc EncryptBase64(plainText []byte, publicKeyBase64 string) (string, error) {\n\tpublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64)\n\tif err != nil {\n\t\treturn \"\", gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode public key\")\n\t}\n\n\tencrypted, err := Encrypt(plainText, publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(encrypted), nil\n}\n\n// DecryptBase64 decrypts base64-encoded data with base64-encoded private key (auto-detect format).\nfunc DecryptBase64(cipherTextBase64, privateKeyBase64 string) ([]byte, error) {\n\tprivateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode private key\")\n\t}\n\n\tcipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode cipher text\")\n\t}\n\n\treturn Decrypt(cipherText, privateKey)\n}\n\n// EncryptPKIX encrypts data with public key in PKIX (X.509) format.\n// PKIX is the standard format for public keys, often referred to as \"PKCS#8 public key\".\n//\n// Note: RSA encryption has a size limit based on key size.\n// For PKCS#1 v1.5 padding, max plaintext size = key_size_in_bytes - 11.\nfunc EncryptPKIX(plainText, publicKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(publicKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid public key\")\n\t}\n\n\tpub, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse PKIX public key\")\n\t}\n\n\trsaPub, ok := pub.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA public key\")\n\t}\n\n\t// Validate plaintext size for PKCS#1 v1.5 padding\n\tmaxSize := rsaPub.Size() - 11\n\tif len(plainText) > maxSize {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter,\n\t\t\t\"plaintext too long: max %d bytes for this key, got %d bytes\", maxSize, len(plainText))\n\t}\n\n\treturn rsa.EncryptPKCS1v15(rand.Reader, rsaPub, plainText)\n}\n\n// EncryptPKCS8 is an alias for EncryptPKIX for backward compatibility.\n//\n// Deprecated: Use EncryptPKIX instead. Public keys use PKIX format, not PKCS#8.\nfunc EncryptPKCS8(plainText, publicKey []byte) ([]byte, error) {\n\treturn EncryptPKIX(plainText, publicKey)\n}\n\n// EncryptPKCS1 encrypts data with public key in PKCS#1 format.\n//\n// Note: RSA encryption has a size limit based on key size.\n// For PKCS#1 v1.5 padding, max plaintext size = key_size_in_bytes - 11.\nfunc EncryptPKCS1(plainText, publicKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(publicKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid public key\")\n\t}\n\n\tpub, err := x509.ParsePKCS1PublicKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse PKCS#1 public key\")\n\t}\n\n\t// Validate plaintext size for PKCS#1 v1.5 padding\n\tmaxSize := pub.Size() - 11\n\tif len(plainText) > maxSize {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter,\n\t\t\t\"plaintext too long: max %d bytes for this key, got %d bytes\", maxSize, len(plainText))\n\t}\n\n\treturn rsa.EncryptPKCS1v15(rand.Reader, pub, plainText)\n}\n\n// DecryptPKCS8 decrypts data with private key by PKCS#8 format.\nfunc DecryptPKCS8(cipherText, privateKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\tpriv, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse PKCS#8 private key\")\n\t}\n\n\trsaPriv, ok := priv.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA private key\")\n\t}\n\n\treturn rsa.DecryptPKCS1v15(rand.Reader, rsaPriv, cipherText)\n}\n\n// DecryptPKCS1 decrypts data with private key by PKCS#1 format.\nfunc DecryptPKCS1(cipherText, privateKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\tpriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse private key\")\n\t}\n\n\treturn rsa.DecryptPKCS1v15(rand.Reader, priv, cipherText)\n}\n\n// EncryptPKIXBase64 encrypts data with PKIX public key and returns base64-encoded result.\nfunc EncryptPKIXBase64(plainText []byte, publicKeyBase64 string) (string, error) {\n\tpublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64)\n\tif err != nil {\n\t\treturn \"\", gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode public key\")\n\t}\n\n\tencrypted, err := EncryptPKIX(plainText, publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(encrypted), nil\n}\n\n// EncryptPKCS8Base64 is an alias for EncryptPKIXBase64 for backward compatibility.\n//\n// Deprecated: Use EncryptPKIXBase64 instead.\nfunc EncryptPKCS8Base64(plainText []byte, publicKeyBase64 string) (string, error) {\n\treturn EncryptPKIXBase64(plainText, publicKeyBase64)\n}\n\n// EncryptPKCS1Base64 encrypts data with PKCS#1 public key and returns base64-encoded result.\nfunc EncryptPKCS1Base64(plainText []byte, publicKeyBase64 string) (string, error) {\n\tpublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64)\n\tif err != nil {\n\t\treturn \"\", gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode public key\")\n\t}\n\n\tencrypted, err := EncryptPKCS1(plainText, publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(encrypted), nil\n}\n\n// DecryptPKCS8Base64 decrypts data with private key by PKCS#8 format and decode base64 input.\nfunc DecryptPKCS8Base64(cipherTextBase64, privateKeyBase64 string) ([]byte, error) {\n\tprivateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode private key\")\n\t}\n\n\tcipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode cipher text\")\n\t}\n\n\treturn DecryptPKCS8(cipherText, privateKey)\n}\n\n// DecryptPKCS1Base64 decrypts base64-encoded data with PKCS#1 private key.\nfunc DecryptPKCS1Base64(cipherTextBase64, privateKeyBase64 string) ([]byte, error) {\n\tprivateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode private key\")\n\t}\n\n\tcipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode cipher text\")\n\t}\n\n\treturn DecryptPKCS1(cipherText, privateKey)\n}\n\n// GetPrivateKeyType detects the type of private key (PKCS#1 or PKCS#8).\n// It attempts to parse the key in both formats to determine the actual type.\nfunc GetPrivateKeyType(privateKey []byte) (string, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\t// Try PKCS#1 first\n\t_, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\tif err == nil {\n\t\treturn KeyTypePKCS1, nil\n\t}\n\n\t// Try PKCS#8\n\tpriv, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tif err == nil {\n\t\tif _, ok := priv.(*rsa.PrivateKey); ok {\n\t\t\treturn KeyTypePKCS8, nil\n\t\t}\n\t\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA private key\")\n\t}\n\n\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, \"unknown private key format\")\n}\n\n// GetPrivateKeyTypeBase64 detects the type of base64 encoded private key (PKCS#1 or PKCS#8).\nfunc GetPrivateKeyTypeBase64(privateKeyBase64 string) (string, error) {\n\tprivateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)\n\tif err != nil {\n\t\treturn \"\", gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode private key\")\n\t}\n\n\treturn GetPrivateKeyType(privateKey)\n}\n\n// GenerateKeyPair generates a new RSA key pair with the given bits.\nfunc GenerateKeyPair(bits int) (privateKey, publicKey []byte, err error) {\n\t// Generate private key\n\tprivKey, err := rsa.GenerateKey(rand.Reader, bits)\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to generate rsa key\")\n\t}\n\n\t// Validate private key\n\terr = privKey.Validate()\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to validate rsa key\")\n\t}\n\n\t// Marshal private key to PKCS#1 format\n\tprivKeyBytes := x509.MarshalPKCS1PrivateKey(privKey)\n\tprivateKey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  pemTypeRSAPrivateKey,\n\t\tBytes: privKeyBytes,\n\t})\n\n\t// Generate PKCS#1 public key\n\tpubKeyBytes := x509.MarshalPKCS1PublicKey(&privKey.PublicKey)\n\tpublicKey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  pemTypeRSAPublicKey,\n\t\tBytes: pubKeyBytes,\n\t})\n\n\treturn privateKey, publicKey, nil\n}\n\n// GenerateKeyPairPKCS8 generates a new RSA key pair with the given bits in PKCS#8 format.\nfunc GenerateKeyPairPKCS8(bits int) (privateKey, publicKey []byte, err error) {\n\t// Generate private key\n\tprivKey, err := rsa.GenerateKey(rand.Reader, bits)\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to generate rsa key\")\n\t}\n\n\t// Validate private key\n\terr = privKey.Validate()\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to validate rsa key\")\n\t}\n\n\t// Marshal private key to PKCS#8 format\n\tprivKeyBytes, err := x509.MarshalPKCS8PrivateKey(privKey)\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to marshal private key to PKCS#8\")\n\t}\n\n\tprivateKey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  pemTypePrivateKey,\n\t\tBytes: privKeyBytes,\n\t})\n\n\t// Generate public key\n\tpubKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)\n\tif err != nil {\n\t\treturn nil, nil, gerror.WrapCode(gcode.CodeInternalError, err, \"failed to marshal public key\")\n\t}\n\n\tpublicKey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  pemTypePublicKey,\n\t\tBytes: pubKeyBytes,\n\t})\n\n\treturn privateKey, publicKey, nil\n}\n\n// GenerateDefaultKeyPair generates a new RSA key pair with default bits (2048).\nfunc GenerateDefaultKeyPair() (privateKey, publicKey []byte, err error) {\n\treturn GenerateKeyPair(DefaultRSAKeyBits)\n}\n\n// ExtractPKCS1PublicKey extracts PKCS#1 public key from private key.\nfunc ExtractPKCS1PublicKey(privateKey []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\tpriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse private key\")\n\t}\n\n\tpubKeyBytes := x509.MarshalPKCS1PublicKey(&priv.PublicKey)\n\treturn pem.EncodeToMemory(&pem.Block{\n\t\tType:  pemTypeRSAPublicKey,\n\t\tBytes: pubKeyBytes,\n\t}), nil\n}\n\n// ============================================================================\n// OAEP Encryption/Decryption Functions (Recommended for new applications)\n// ============================================================================\n\n// EncryptOAEP encrypts data with public key using OAEP padding (auto-detect format).\n// The publicKey can be either PKCS#1 or PKCS#8 (PKIX) format.\n// Uses SHA-256 as the hash function by default.\n//\n// OAEP (Optimal Asymmetric Encryption Padding) is more secure than PKCS#1 v1.5\n// and is recommended for new applications.\n//\n// Note: For OAEP with SHA-256, max plaintext size = key_size_in_bytes - 2*32 - 2.\n// For a 2048-bit key, this is 190 bytes.\nfunc EncryptOAEP(plainText, publicKey []byte) ([]byte, error) {\n\treturn EncryptOAEPWithHash(plainText, publicKey, nil, sha256.New())\n}\n\n// EncryptOAEPWithHash encrypts data with public key using OAEP padding with custom hash.\n// The publicKey can be either PKCS#1 or PKCS#8 (PKIX) format.\n// The label parameter can be nil for most use cases.\n// The hash parameter specifies the hash function to use (e.g., sha256.New()).\nfunc EncryptOAEPWithHash(plainText, publicKey, label []byte, hash hash.Hash) ([]byte, error) {\n\tblock, _ := pem.Decode(publicKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid public key\")\n\t}\n\n\t// Try PKCS#8 (PKIX) first\n\tpub, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\t// Try PKCS#1\n\t\tpub, err = x509.ParsePKCS1PublicKey(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse public key\")\n\t\t}\n\t}\n\n\trsaPub, ok := pub.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA public key\")\n\t}\n\n\t// Validate plaintext size for OAEP padding\n\t// maxSize = keySize - 2*hashSize - 2\n\tmaxSize := rsaPub.Size() - 2*hash.Size() - 2\n\tif len(plainText) > maxSize {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter,\n\t\t\t\"plaintext too long: max %d bytes for this key with OAEP, got %d bytes\", maxSize, len(plainText))\n\t}\n\n\treturn rsa.EncryptOAEP(hash, rand.Reader, rsaPub, plainText, label)\n}\n\n// DecryptOAEP decrypts data with private key using OAEP padding (auto-detect format).\n// The privateKey can be either PKCS#1 or PKCS#8 format.\n// Uses SHA-256 as the hash function by default.\nfunc DecryptOAEP(cipherText, privateKey []byte) ([]byte, error) {\n\treturn DecryptOAEPWithHash(cipherText, privateKey, nil, sha256.New())\n}\n\n// DecryptOAEPWithHash decrypts data with private key using OAEP padding with custom hash.\n// The privateKey can be either PKCS#1 or PKCS#8 format.\n// The label parameter must match the label used during encryption (nil if not used).\n// The hash parameter must match the hash function used during encryption.\nfunc DecryptOAEPWithHash(cipherText, privateKey, label []byte, hash hash.Hash) ([]byte, error) {\n\tblock, _ := pem.Decode(privateKey)\n\tif block == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"invalid private key\")\n\t}\n\n\t// Try PKCS#8 first\n\tpriv, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tif err != nil {\n\t\t// Try PKCS#1\n\t\tpriv, err = x509.ParsePKCS1PrivateKey(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to parse private key\")\n\t\t}\n\t}\n\n\trsaPriv, ok := priv.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"not an RSA private key\")\n\t}\n\n\treturn rsa.DecryptOAEP(hash, rand.Reader, rsaPriv, cipherText, label)\n}\n\n// EncryptOAEPBase64 encrypts data with public key using OAEP padding\n// and returns base64-encoded result.\nfunc EncryptOAEPBase64(plainText []byte, publicKeyBase64 string) (string, error) {\n\tpublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64)\n\tif err != nil {\n\t\treturn \"\", gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode public key\")\n\t}\n\n\tencrypted, err := EncryptOAEP(plainText, publicKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(encrypted), nil\n}\n\n// DecryptOAEPBase64 decrypts base64-encoded data with private key using OAEP padding.\nfunc DecryptOAEPBase64(cipherTextBase64, privateKeyBase64 string) ([]byte, error) {\n\tprivateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode private key\")\n\t}\n\n\tcipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64)\n\tif err != nil {\n\t\treturn nil, gerror.WrapCode(gcode.CodeInvalidParameter, err, \"failed to decode cipher text\")\n\t}\n\n\treturn DecryptOAEP(cipherText, privateKey)\n}\n"
  },
  {
    "path": "crypto/grsa/grsa_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grsa_test\n\nimport (\n\t\"encoding/base64\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/grsa\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestEncryptDecrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Encrypt with public key\n\t\tcipherText, err := grsa.Encrypt(plainText, publicKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt with private key\n\t\tdecryptedText, err := grsa.Decrypt(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestEncryptDecryptBase64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Encode keys to base64\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, Base64 World!\")\n\n\t\t// Encrypt with public key\n\t\tcipherTextBase64, err := grsa.EncryptBase64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherTextBase64, \"\")\n\n\t\t// Decrypt with private key\n\t\tdecryptedText, err := grsa.DecryptBase64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestGenerateKeyPair(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test generating a 2048-bit RSA key pair\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Check if keys are in correct format\n\t\tprivateKeyType, err := grsa.GetPrivateKeyType(privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(privateKeyType, \"PKCS#1\")\n\n\t\t// Test with 1024-bit key for faster test execution only.\n\t\t// Note: 1024-bit keys are NOT secure for production use.\n\t\t// Always use at least 2048-bit keys in production.\n\t\tprivateKey, publicKey, err = grsa.GenerateKeyPair(1024)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\t})\n}\n\nfunc TestGenerateKeyPairPKCS8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test generating a 2048-bit RSA key pair in PKCS#8 format\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Check if keys are in correct format\n\t\tprivateKeyType, err := grsa.GetPrivateKeyType(privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(privateKeyType, \"PKCS#8\")\n\n\t\t// Test with 1024-bit key for faster test execution only.\n\t\t// Note: 1024-bit keys are NOT secure for production use.\n\t\tprivateKey, publicKey, err = grsa.GenerateKeyPairPKCS8(1024)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\t})\n}\n\nfunc TestEncryptAndDecryptPKCS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate both types of key pairs for testing\n\t\tprivateKey1, publicKey1, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, Mixed Formats!\")\n\n\t\t// Test general encrypt/decrypt with PKCS#1 keys\n\t\tcipherText, err := grsa.Encrypt(plainText, publicKey1)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\tdecryptedText, err := grsa.Decrypt(cipherText, privateKey1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\n\t\t// Test general encrypt/decrypt with PKCS#8 keys\n\t\tcipherText8, err := grsa.Encrypt(plainText, publicKey8)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText8, nil)\n\n\t\tdecryptedText8, err := grsa.Decrypt(cipherText8, privateKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText8), string(plainText))\n\t})\n}\n\nfunc TestGetPrivateKeyType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate both PKCS#1 and PKCS#8 key pairs\n\t\t// Note: 1024-bit keys used here for faster test execution only.\n\t\t// NOT secure for production use.\n\t\tprivKey1, _, err := grsa.GenerateKeyPair(1024)\n\t\tt.AssertNil(err)\n\n\t\tprivKey8, _, err := grsa.GenerateKeyPairPKCS8(1024)\n\t\tt.AssertNil(err)\n\n\t\t// Check types\n\t\tkeyType1, err := grsa.GetPrivateKeyType(privKey1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(keyType1, \"PKCS#1\")\n\n\t\tkeyType8, err := grsa.GetPrivateKeyType(privKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(keyType8, \"PKCS#8\")\n\t})\n}\n\nfunc TestEncryptPKCS1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing (PKCS#1 format)\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, PKCS#1 World!\")\n\n\t\t// Encrypt with public key using PKCS#1 format specifically\n\t\tcipherText, err := grsa.EncryptPKCS1(plainText, publicKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt with private key using PKCS#1 format specifically\n\t\tdecryptedText, err := grsa.DecryptPKCS1(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestEncryptPKCS1Base64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Encode keys to base64\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, PKCS#1 Base64 World!\")\n\n\t\t// Encrypt with public key using PKCS#1 format specifically\n\t\tcipherTextBase64, err := grsa.EncryptPKCS1Base64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherTextBase64, \"\")\n\n\t\t// Decrypt with private key using PKCS#1 format specifically\n\t\tdecryptedText, err := grsa.DecryptPKCS1Base64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\n// Helper function to encode to base64\nfunc encodeToBase64(data []byte) string {\n\treturn base64.StdEncoding.EncodeToString(data)\n}\n\nfunc TestEncryptWithInvalidPublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with invalid public key\n\t\t_, err := grsa.Encrypt(plainText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with empty public key\n\t\t_, err = grsa.Encrypt(plainText, []byte{})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with nil public key\n\t\t_, err = grsa.Encrypt(plainText, nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptWithInvalidPrivateKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a valid key pair and encrypt some data\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.Encrypt(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Test decryption with invalid private key\n\t\t_, err = grsa.Decrypt(cipherText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test decryption with empty private key\n\t\t_, err = grsa.Decrypt(cipherText, []byte{})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test decryption with wrong private key\n\t\twrongPrivKey, _, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.Decrypt(cipherText, wrongPrivKey)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify correct decryption still works\n\t\tdecrypted, err := grsa.Decrypt(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestEncryptWithOversizedPlaintext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a 2048-bit key pair\n\t\t_, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\t// For 2048-bit key with PKCS#1 v1.5 padding, max size is 256 - 11 = 245 bytes\n\t\t// Create plaintext that exceeds this limit\n\t\toversizedPlainText := make([]byte, 300)\n\t\tfor i := range oversizedPlainText {\n\t\t\toversizedPlainText[i] = 'A'\n\t\t}\n\n\t\t// Encryption should fail with oversized plaintext\n\t\t_, err = grsa.Encrypt(oversizedPlainText, publicKey)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify that valid size plaintext works\n\t\tvalidPlainText := make([]byte, 200)\n\t\tfor i := range validPlainText {\n\t\t\tvalidPlainText[i] = 'B'\n\t\t}\n\t\t_, err = grsa.Encrypt(validPlainText, publicKey)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestDecryptWithCorruptedCiphertext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.Encrypt(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Corrupt the ciphertext\n\t\tcorruptedCipherText := make([]byte, len(cipherText))\n\t\tcopy(corruptedCipherText, cipherText)\n\t\tcorruptedCipherText[0] ^= 0xFF\n\t\tcorruptedCipherText[len(corruptedCipherText)-1] ^= 0xFF\n\n\t\t// Decryption should fail with corrupted ciphertext\n\t\t_, err = grsa.Decrypt(corruptedCipherText, privateKey)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestGetPrivateKeyTypeWithInvalidKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with invalid key\n\t\t_, err := grsa.GetPrivateKeyType([]byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with empty key\n\t\t_, err = grsa.GetPrivateKeyType([]byte{})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with nil key\n\t\t_, err = grsa.GetPrivateKeyType(nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestBase64FunctionsWithInvalidInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test EncryptBase64 with invalid base64 public key\n\t\t_, err := grsa.EncryptBase64(plainText, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test DecryptBase64 with invalid base64 private key\n\t\t_, err = grsa.DecryptBase64(\"validbase64==\", \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test DecryptBase64 with invalid base64 ciphertext\n\t\tprivateKey, _, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\t_, err = grsa.DecryptBase64(\"not-valid-base64!!!\", privateKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptPKCS8WithPKCS1Key(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#1 key pair\n\t\tprivateKey1, publicKey1, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.EncryptPKCS1(plainText, publicKey1)\n\t\tt.AssertNil(err)\n\n\t\t// DecryptPKCS8 should fail with PKCS#1 private key (no fallback)\n\t\t_, err = grsa.DecryptPKCS8(cipherText, privateKey1)\n\t\tt.AssertNE(err, nil)\n\n\t\t// DecryptPKCS1 should work\n\t\tdecrypted, err := grsa.DecryptPKCS1(cipherText, privateKey1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestEncryptPKIX(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#8 key pair (which uses PKIX public key format)\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, PKIX World!\")\n\n\t\t// Encrypt with PKIX public key\n\t\tcipherText, err := grsa.EncryptPKIX(plainText, publicKey8)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt with PKCS#8 private key\n\t\tdecrypted, err := grsa.DecryptPKCS8(cipherText, privateKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\n\t\t// Test with invalid public key\n\t\t_, err = grsa.EncryptPKIX(plainText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with PKCS#1 public key (should fail for EncryptPKIX)\n\t\t_, publicKey1, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.EncryptPKIX(plainText, publicKey1)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test oversized plaintext\n\t\toversizedPlainText := make([]byte, 300)\n\t\t_, err = grsa.EncryptPKIX(oversizedPlainText, publicKey8)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptPKCS8Alias(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#8 key pair\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, PKCS8 Alias!\")\n\n\t\t// EncryptPKCS8 is an alias for EncryptPKIX\n\t\tcipherText, err := grsa.EncryptPKCS8(plainText, publicKey8)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt should work\n\t\tdecrypted, err := grsa.DecryptPKCS8(cipherText, privateKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestEncryptPKIXBase64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#8 key pair\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivateKeyBase64 := encodeToBase64(privateKey8)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey8)\n\n\t\tplainText := []byte(\"Hello, PKIX Base64!\")\n\n\t\t// Encrypt with PKIX public key\n\t\tcipherTextBase64, err := grsa.EncryptPKIXBase64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherTextBase64, \"\")\n\n\t\t// Decrypt with PKCS#8 private key\n\t\tdecrypted, err := grsa.DecryptPKCS8Base64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\n\t\t// Test with invalid base64 public key\n\t\t_, err = grsa.EncryptPKIXBase64(plainText, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with invalid public key content\n\t\t_, err = grsa.EncryptPKIXBase64(plainText, encodeToBase64([]byte(\"invalid key\")))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptPKCS8Base64Alias(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#8 key pair\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivateKeyBase64 := encodeToBase64(privateKey8)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey8)\n\n\t\tplainText := []byte(\"Hello, PKCS8 Base64 Alias!\")\n\n\t\t// EncryptPKCS8Base64 is an alias for EncryptPKIXBase64\n\t\tcipherTextBase64, err := grsa.EncryptPKCS8Base64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherTextBase64, \"\")\n\n\t\t// Decrypt should work\n\t\tdecrypted, err := grsa.DecryptPKCS8Base64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestDecryptPKCS8Base64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#8 key pair\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivateKeyBase64 := encodeToBase64(privateKey8)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey8)\n\n\t\tplainText := []byte(\"Hello, DecryptPKCS8Base64!\")\n\n\t\t// Encrypt\n\t\tcipherTextBase64, err := grsa.EncryptPKIXBase64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\n\t\t// Decrypt\n\t\tdecrypted, err := grsa.DecryptPKCS8Base64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\n\t\t// Test with invalid base64 private key\n\t\t_, err = grsa.DecryptPKCS8Base64(cipherTextBase64, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with invalid base64 ciphertext\n\t\t_, err = grsa.DecryptPKCS8Base64(\"not-valid-base64!!!\", privateKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestGetPrivateKeyTypeBase64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate both PKCS#1 and PKCS#8 key pairs\n\t\tprivKey1, _, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivKey8, _, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\t// Check types via base64\n\t\tkeyType1, err := grsa.GetPrivateKeyTypeBase64(encodeToBase64(privKey1))\n\t\tt.AssertNil(err)\n\t\tt.Assert(keyType1, \"PKCS#1\")\n\n\t\tkeyType8, err := grsa.GetPrivateKeyTypeBase64(encodeToBase64(privKey8))\n\t\tt.AssertNil(err)\n\t\tt.Assert(keyType8, \"PKCS#8\")\n\n\t\t// Test with invalid base64\n\t\t_, err = grsa.GetPrivateKeyTypeBase64(\"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestExtractPKCS1PublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate PKCS#1 key pair\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\t// Extract public key from private key\n\t\textractedPublicKey, err := grsa.ExtractPKCS1PublicKey(privateKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(extractedPublicKey, nil)\n\n\t\t// The extracted public key should work for encryption\n\t\tplainText := []byte(\"Hello, Extracted Key!\")\n\t\tcipherText, err := grsa.EncryptPKCS1(plainText, extractedPublicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Decrypt with original private key\n\t\tdecrypted, err := grsa.DecryptPKCS1(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\n\t\t// Compare extracted key with original (they should be equivalent)\n\t\tcipherText2, err := grsa.EncryptPKCS1(plainText, publicKey)\n\t\tt.AssertNil(err)\n\t\tdecrypted2, err := grsa.DecryptPKCS1(cipherText2, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted2), string(plainText))\n\n\t\t// Test with invalid private key\n\t\t_, err = grsa.ExtractPKCS1PublicKey([]byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with PKCS#8 private key (should fail)\n\t\tprivateKey8, _, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.ExtractPKCS1PublicKey(privateKey8)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptPKCS1WithInvalidKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.EncryptPKCS1(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Test with invalid private key\n\t\t_, err = grsa.DecryptPKCS1(cipherText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with PKCS#8 private key (should fail for DecryptPKCS1)\n\t\tprivateKey8, _, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.DecryptPKCS1(cipherText, privateKey8)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify correct decryption works\n\t\tdecrypted, err := grsa.DecryptPKCS1(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestDecryptPKCS8WithInvalidKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.EncryptPKIX(plainText, publicKey8)\n\t\tt.AssertNil(err)\n\n\t\t// Test with invalid private key\n\t\t_, err = grsa.DecryptPKCS8(cipherText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify correct decryption works\n\t\tdecrypted, err := grsa.DecryptPKCS8(cipherText, privateKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestEncryptPKCS1WithInvalidKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with invalid public key\n\t\t_, err := grsa.EncryptPKCS1(plainText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with PKCS#8 public key (should fail for EncryptPKCS1)\n\t\t_, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.EncryptPKCS1(plainText, publicKey8)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptPKCS1WithOversizedPlaintext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\t// Create oversized plaintext\n\t\toversizedPlainText := make([]byte, 300)\n\t\t_, err = grsa.EncryptPKCS1(oversizedPlainText, publicKey)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptPKCS1Base64WithInvalidInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with invalid base64 public key\n\t\t_, err := grsa.EncryptPKCS1Base64(plainText, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with invalid public key content\n\t\t_, err = grsa.EncryptPKCS1Base64(plainText, encodeToBase64([]byte(\"invalid key\")))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptPKCS1Base64WithInvalidInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey, publicKey, err := grsa.GenerateKeyPair(2048)\n\t\tt.AssertNil(err)\n\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherTextBase64, err := grsa.EncryptPKCS1Base64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\n\t\t// Test with invalid base64 private key\n\t\t_, err = grsa.DecryptPKCS1Base64(cipherTextBase64, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with invalid base64 ciphertext\n\t\t_, err = grsa.DecryptPKCS1Base64(\"not-valid-base64!!!\", privateKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptWithNonRSAPublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a PEM block that is valid but not an RSA key\n\t\t// This tests the \"not an RSA public key\" error path\n\t\t// We use a valid PEM structure but with invalid content\n\t\tinvalidPEM := []byte(`-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n-----END PUBLIC KEY-----`)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\t_, err := grsa.Encrypt(plainText, invalidPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptWithNonRSAPrivateKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a PEM block that is valid but not an RSA key\n\t\tinvalidPEM := []byte(`-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg\n-----END PRIVATE KEY-----`)\n\n\t\tcipherText := []byte(\"some cipher text\")\n\t\t_, err := grsa.Decrypt(cipherText, invalidPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptBase64WithInvalidPublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with valid base64 but invalid key content\n\t\tinvalidKeyBase64 := encodeToBase64([]byte(\"invalid key\"))\n\t\t_, err := grsa.EncryptBase64(plainText, invalidKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestGetPrivateKeyTypeWithNonRSAKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKCS#8 PEM but with non-RSA content (EC key)\n\t\t// This tests the \"not an RSA private key\" error path in GetPrivateKeyType\n\t\tecPrivateKeyPEM := []byte(`-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVcB/UNPczVP6jE4Z\np7v6qYQXsKQZLJGBJKKnUWuHb6+hRANCAASYn3k2T4VqPt1HVAK5Rc7rMb6lGOzF\nv0MVLfCgPKANNGdBvGPmaSLFIxGMNL0v1C2RRvqqEu/vL3POoaqfMJhw\n-----END PRIVATE KEY-----`)\n\n\t\t_, err := grsa.GetPrivateKeyType(ecPrivateKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptPKCS8WithNonRSAKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKCS#8 PEM but with non-RSA content (EC key)\n\t\tecPrivateKeyPEM := []byte(`-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVcB/UNPczVP6jE4Z\np7v6qYQXsKQZLJGBJKKnUWuHb6+hRANCAASYn3k2T4VqPt1HVAK5Rc7rMb6lGOzF\nv0MVLfCgPKANNGdBvGPmaSLFIxGMNL0v1C2RRvqqEu/vL3POoaqfMJhw\n-----END PRIVATE KEY-----`)\n\n\t\tcipherText := []byte(\"some cipher text\")\n\t\t_, err := grsa.DecryptPKCS8(cipherText, ecPrivateKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptPKIXWithNonRSAKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKIX PEM but with non-RSA content (EC key)\n\t\tecPublicKeyPEM := []byte(`-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmJ95Nk+Faj7dR1QCuUXO6zG+pRjs\nxb9DFS3woDygDTRnQbxj5mkixSMRjDS9L9QtkUb6qhLv7y9zzqGqnzCYcA==\n-----END PUBLIC KEY-----`)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\t_, err := grsa.EncryptPKIX(plainText, ecPublicKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptWithNonRSAPKIXKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKIX PEM but with non-RSA content (EC key)\n\t\t// This tests the \"not an RSA public key\" error path in Encrypt\n\t\tecPublicKeyPEM := []byte(`-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmJ95Nk+Faj7dR1QCuUXO6zG+pRjs\nxb9DFS3woDygDTRnQbxj5mkixSMRjDS9L9QtkUb6qhLv7y9zzqGqnzCYcA==\n-----END PUBLIC KEY-----`)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\t_, err := grsa.Encrypt(plainText, ecPublicKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptWithNonRSAPKCS8Key(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKCS#8 PEM but with non-RSA content (EC key)\n\t\t// This tests the \"not an RSA private key\" error path in Decrypt\n\t\tecPrivateKeyPEM := []byte(`-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVcB/UNPczVP6jE4Z\np7v6qYQXsKQZLJGBJKKnUWuHb6+hRANCAASYn3k2T4VqPt1HVAK5Rc7rMb6lGOzF\nv0MVLfCgPKANNGdBvGPmaSLFIxGMNL0v1C2RRvqqEu/vL3POoaqfMJhw\n-----END PRIVATE KEY-----`)\n\n\t\tcipherText := []byte(\"some cipher text\")\n\t\t_, err := grsa.Decrypt(cipherText, ecPrivateKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// ============================================================================\n// OAEP Encryption/Decryption Tests\n// ============================================================================\n\nfunc TestEncryptDecryptOAEP(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey, nil)\n\t\tt.AssertNE(publicKey, nil)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, OAEP World!\")\n\n\t\t// Encrypt with public key using OAEP\n\t\tcipherText, err := grsa.EncryptOAEP(plainText, publicKey)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt with private key using OAEP\n\t\tdecryptedText, err := grsa.DecryptOAEP(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestEncryptDecryptOAEPWithPKCS8Keys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a PKCS#8 key pair for testing\n\t\tprivateKey8, publicKey8, err := grsa.GenerateKeyPairPKCS8(2048)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(privateKey8, nil)\n\t\tt.AssertNE(publicKey8, nil)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, OAEP PKCS#8 World!\")\n\n\t\t// Encrypt with PKIX public key using OAEP\n\t\tcipherText, err := grsa.EncryptOAEP(plainText, publicKey8)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherText, nil)\n\n\t\t// Decrypt with PKCS#8 private key using OAEP\n\t\tdecryptedText, err := grsa.DecryptOAEP(cipherText, privateKey8)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestEncryptDecryptOAEPBase64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a key pair for testing\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\t// Encode keys to base64\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey)\n\n\t\t// Test data to encrypt\n\t\tplainText := []byte(\"Hello, OAEP Base64 World!\")\n\n\t\t// Encrypt with public key using OAEP\n\t\tcipherTextBase64, err := grsa.EncryptOAEPBase64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(cipherTextBase64, \"\")\n\n\t\t// Decrypt with private key using OAEP\n\t\tdecryptedText, err := grsa.DecryptOAEPBase64(cipherTextBase64, privateKeyBase64)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n\nfunc TestEncryptOAEPWithInvalidPublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with invalid public key\n\t\t_, err := grsa.EncryptOAEP(plainText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with empty public key\n\t\t_, err = grsa.EncryptOAEP(plainText, []byte{})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with nil public key\n\t\t_, err = grsa.EncryptOAEP(plainText, nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptOAEPWithInvalidPrivateKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a valid key pair and encrypt some data\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.EncryptOAEP(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Test decryption with invalid private key\n\t\t_, err = grsa.DecryptOAEP(cipherText, []byte(\"invalid key\"))\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test decryption with empty private key\n\t\t_, err = grsa.DecryptOAEP(cipherText, []byte{})\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test decryption with wrong private key\n\t\twrongPrivKey, _, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\t\t_, err = grsa.DecryptOAEP(cipherText, wrongPrivKey)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify correct decryption still works\n\t\tdecrypted, err := grsa.DecryptOAEP(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decrypted), string(plainText))\n\t})\n}\n\nfunc TestEncryptOAEPWithOversizedPlaintext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Generate a 2048-bit key pair\n\t\t_, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\t// For 2048-bit key with OAEP SHA-256 padding, max size is 256 - 2*32 - 2 = 190 bytes\n\t\t// Create plaintext that exceeds this limit\n\t\toversizedPlainText := make([]byte, 200)\n\t\tfor i := range oversizedPlainText {\n\t\t\toversizedPlainText[i] = 'A'\n\t\t}\n\n\t\t// Encryption should fail with oversized plaintext\n\t\t_, err = grsa.EncryptOAEP(oversizedPlainText, publicKey)\n\t\tt.AssertNE(err, nil)\n\n\t\t// Verify that valid size plaintext works\n\t\tvalidPlainText := make([]byte, 150)\n\t\tfor i := range validPlainText {\n\t\t\tvalidPlainText[i] = 'B'\n\t\t}\n\t\t_, err = grsa.EncryptOAEP(validPlainText, publicKey)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestDecryptOAEPWithCorruptedCiphertext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherText, err := grsa.EncryptOAEP(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\t// Corrupt the ciphertext\n\t\tcorruptedCipherText := make([]byte, len(cipherText))\n\t\tcopy(corruptedCipherText, cipherText)\n\t\tcorruptedCipherText[0] ^= 0xFF\n\t\tcorruptedCipherText[len(corruptedCipherText)-1] ^= 0xFF\n\n\t\t// Decryption should fail with corrupted ciphertext\n\t\t_, err = grsa.DecryptOAEP(corruptedCipherText, privateKey)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptOAEPBase64WithInvalidInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tplainText := []byte(\"Hello, World!\")\n\n\t\t// Test with invalid base64 public key\n\t\t_, err := grsa.EncryptOAEPBase64(plainText, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with valid base64 but invalid key content\n\t\tinvalidKeyBase64 := encodeToBase64([]byte(\"invalid key\"))\n\t\t_, err = grsa.EncryptOAEPBase64(plainText, invalidKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptOAEPBase64WithInvalidInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tprivateKeyBase64 := encodeToBase64(privateKey)\n\t\tpublicKeyBase64 := encodeToBase64(publicKey)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\tcipherTextBase64, err := grsa.EncryptOAEPBase64(plainText, publicKeyBase64)\n\t\tt.AssertNil(err)\n\n\t\t// Test with invalid base64 private key\n\t\t_, err = grsa.DecryptOAEPBase64(cipherTextBase64, \"not-valid-base64!!!\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Test with invalid base64 ciphertext\n\t\t_, err = grsa.DecryptOAEPBase64(\"not-valid-base64!!!\", privateKeyBase64)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptOAEPWithNonRSAPublicKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKIX PEM but with non-RSA content (EC key)\n\t\tecPublicKeyPEM := []byte(`-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmJ95Nk+Faj7dR1QCuUXO6zG+pRjs\nxb9DFS3woDygDTRnQbxj5mkixSMRjDS9L9QtkUb6qhLv7y9zzqGqnzCYcA==\n-----END PUBLIC KEY-----`)\n\n\t\tplainText := []byte(\"Hello, World!\")\n\t\t_, err := grsa.EncryptOAEP(plainText, ecPublicKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestDecryptOAEPWithNonRSAPrivateKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a valid PKCS#8 PEM but with non-RSA content (EC key)\n\t\tecPrivateKeyPEM := []byte(`-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVcB/UNPczVP6jE4Z\np7v6qYQXsKQZLJGBJKKnUWuHb6+hRANCAASYn3k2T4VqPt1HVAK5Rc7rMb6lGOzF\nv0MVLfCgPKANNGdBvGPmaSLFIxGMNL0v1C2RRvqqEu/vL3POoaqfMJhw\n-----END PRIVATE KEY-----`)\n\n\t\tcipherText := []byte(\"some cipher text\")\n\t\t_, err := grsa.DecryptOAEP(cipherText, ecPrivateKeyPEM)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestEncryptOAEPWithHashCustomHash(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// This test verifies that EncryptOAEPWithHash and DecryptOAEPWithHash work correctly\n\t\t// with the default SHA-256 hash (via EncryptOAEP/DecryptOAEP which use sha256.New())\n\t\tprivateKey, publicKey, err := grsa.GenerateDefaultKeyPair()\n\t\tt.AssertNil(err)\n\n\t\tplainText := []byte(\"Hello, Custom Hash World!\")\n\n\t\t// Encrypt and decrypt using the default OAEP functions\n\t\tcipherText, err := grsa.EncryptOAEP(plainText, publicKey)\n\t\tt.AssertNil(err)\n\n\t\tdecryptedText, err := grsa.DecryptOAEP(cipherText, privateKey)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(decryptedText), string(plainText))\n\t})\n}\n"
  },
  {
    "path": "crypto/gsha1/gsha1.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsha1 provides useful API for SHA1 encryption algorithms.\npackage gsha1\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encrypt encrypts any type of variable using SHA1 algorithms.\n// It uses package gconv to convert `v` to its bytes type.\nfunc Encrypt(v any) string {\n\tr := sha1.Sum(gconv.Bytes(v))\n\treturn hex.EncodeToString(r[:])\n}\n\n// EncryptFile encrypts file content of `path` using SHA1 algorithms.\nfunc EncryptFile(path string) (encrypt string, err error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\th := sha1.New()\n\t_, err = io.Copy(h, f)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(h.Sum(nil)), nil\n}\n\n// MustEncryptFile encrypts file content of `path` using SHA1 algorithms.\n// It panics if any error occurs.\nfunc MustEncryptFile(path string) string {\n\tresult, err := EncryptFile(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "crypto/gsha1/gsha1_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gsha1_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gsha1\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype user struct {\n\tname     string\n\tpassword string\n\tage      int\n}\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := &user{\n\t\t\tname:     \"派大星\",\n\t\t\tpassword: \"123456\",\n\t\t\tage:      23,\n\t\t}\n\t\tresult := \"97386736e3ee4adee5ca595c78c12129f6032cad\"\n\t\tencrypt := gsha1.Encrypt(user)\n\t\tt.AssertEQ(encrypt, result)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"5b4c1c2a08ca85ddd031ef8627414f4cb2620b41\"\n\t\ts := gsha1.Encrypt(\"pibigstar\")\n\t\tt.AssertEQ(s, result)\n\t})\n}\n\nfunc TestEncryptFile(t *testing.T) {\n\tpath := \"test.text\"\n\terrPath := \"err.text\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"8b05d3ba24b8d2374b8f5149d9f3fbada14ea984\"\n\t\tfile, err := os.Create(path)\n\t\tdefer os.Remove(path)\n\t\tdefer file.Close()\n\t\tt.AssertNil(err)\n\t\t_, _ = file.Write([]byte(\"Hello Go Frame\"))\n\t\tencryptFile, _ := gsha1.EncryptFile(path)\n\t\tt.AssertEQ(encryptFile, result)\n\t\t// when the file is not exist,encrypt will return empty string\n\t\terrEncrypt, _ := gsha1.EncryptFile(errPath)\n\t\tt.AssertEQ(errEncrypt, \"\")\n\t})\n}\n"
  },
  {
    "path": "crypto/gsha256/gsha256.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsha256 provides useful API for SHA256 encryption algorithms.\npackage gsha256\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encrypt encrypts any type of variable using SHA256 algorithms.\n// It uses package gconv to convert `v` to its bytes type.\nfunc Encrypt(v any) string {\n\tbs := sha256.Sum256(gconv.Bytes(v))\n\treturn hex.EncodeToString(bs[:])\n}\n\n// EncryptFile encrypts file content of `path` using SHA256 algorithms.\nfunc EncryptFile(path string) (encrypt string, err error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\th := sha256.New()\n\t_, err = io.Copy(h, f)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(h.Sum(nil)), nil\n}\n\n// MustEncryptFile encrypts file content of `path` using the SHA256 algorithm.\n// It panics if any error occurs.\nfunc MustEncryptFile(path string) string {\n\tresult, err := EncryptFile(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "crypto/gsha256/gsha256_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gsha256_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gsha256\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype user struct {\n\tname     string\n\tpassword string\n\tage      int\n}\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"b5568f1b35aeb9eb7528336dea6c211a2cdcec1f333d98141b8adf346717907e\"\n\t\ts := gsha256.Encrypt(\"pibigstar\")\n\t\tt.AssertEQ(s, result)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := &user{\n\t\t\tname:     \"派大星\",\n\t\t\tpassword: \"123456\",\n\t\t\tage:      23,\n\t\t}\n\t\tresult := \"8e0293ca8e1860ae258a88429d3c14755712059d9562c825557a927718f574f3\"\n\t\tencrypt := gsha256.Encrypt(user)\n\t\tt.AssertEQ(encrypt, result)\n\t})\n}\n\nfunc TestEncryptFile(t *testing.T) {\n\tpath := \"test.text\"\n\terrPath := \"err.text\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"8fd86e81f66886d4ef7007c2df565f7f61dce2000d8b67ac7163be547c3115ef\"\n\t\tfile, err := os.Create(path)\n\t\tdefer os.Remove(path)\n\t\tdefer file.Close()\n\t\tt.AssertNil(err)\n\t\t_, _ = file.Write([]byte(\"Hello Go Frame\"))\n\t\tencryptFile, err := gsha256.EncryptFile(path)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(encryptFile, result)\n\t\t// when the file is not exist,encrypt will return empty string\n\t\terrEncrypt, err := gsha256.EncryptFile(errPath)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, \"\")\n\t})\n}\n"
  },
  {
    "path": "crypto/gsha512/gsha512.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsha512 provides useful API for SHA512 encryption algorithms.\npackage gsha512\n\nimport (\n\t\"crypto/sha512\"\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encrypt encrypts any type of variable using SHA512 algorithms.\n// It uses package gconv to convert `v` to its bytes type.\nfunc Encrypt(v any) string {\n\tbs := sha512.Sum512(gconv.Bytes(v))\n\treturn hex.EncodeToString(bs[:])\n}\n\n// EncryptFile encrypts file content of `path` using SHA512 algorithms.\nfunc EncryptFile(path string) (encrypt string, err error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\th := sha512.New()\n\t_, err = io.Copy(h, f)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(h.Sum(nil)), nil\n}\n\n// MustEncryptFile encrypts file content of `path` using the SHA512 algorithm.\n// It panics if any error occurs.\nfunc MustEncryptFile(path string) string {\n\tresult, err := EncryptFile(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "crypto/gsha512/gsha512_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gsha512_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/crypto/gsha512\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype user struct {\n\tname     string\n\tpassword string\n\tage      int\n}\n\nfunc TestEncrypt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"c7b81ef31111986759f12df55baf7ea79f9d23557f32656fd271813adc37ab605b793e7c0170180b219a7a66a43a156e04b7563eeab61c4ad04c650b132da269\"\n\t\ts := gsha512.Encrypt(\"pibigstar\")\n\t\tt.AssertEQ(s, result)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := &user{\n\t\t\tname:     \"派大星\",\n\t\t\tpassword: \"123456\",\n\t\t\tage:      23,\n\t\t}\n\t\tresult := \"fe5e3be3c17e593f89f176833a52b130a6f5d367fd4a65b520cfa6818c4c42f2af133457c75c884554817b36e255130b4164da88c3a1740767153d63a06bdaa5\"\n\t\tencrypt := gsha512.Encrypt(user)\n\t\tt.AssertEQ(encrypt, result)\n\t})\n}\n\nfunc TestEncryptFile(t *testing.T) {\n\tpath := gtest.DataPath(\"test.text\")\n\terrPath := gtest.DataPath(\"err.text\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := \"2c6df89b4fda8e4c0baa7dc962380c496f1efe6e5c7ffc3bd33175b2e8f8e394716c8ec2e40c70468dd23bbbdc503db480c57b0051705ef5beaa7aec4a9061d5\"\n\t\t// ensure the testdata directory exists\n\t\tdir := filepath.Dir(path)\n\t\terr := os.MkdirAll(dir, 0o755)\n\t\tt.AssertNil(err)\n\n\t\tfile, err := os.Create(path)\n\t\tt.AssertNil(err)\n\t\tdefer func() { _ = os.Remove(path) }()\n\t\tdefer func() { _ = file.Close() }()\n\t\t_, err = file.Write([]byte(\"Hello Go Frame\"))\n\t\tt.AssertNil(err)\n\t\tencryptFile, err := gsha512.EncryptFile(path)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(encryptFile, result)\n\t\t// When the file does not exist, EncryptFile returns an empty string and a non-nil error.\n\t\terrEncrypt, err := gsha512.EncryptFile(errPath)\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertEQ(errEncrypt, \"\")\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gdb provides ORM features for popular relationship databases.\n//\n// TODO use context.Context as required parameter for all DB operations.\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// DB defines the interfaces for ORM operations.\ntype DB interface {\n\t// ===========================================================================\n\t// Model creation.\n\t// ===========================================================================\n\n\t// Model creates and returns a new ORM model from given schema.\n\t// The parameter `table` can be more than one table names, and also alias name, like:\n\t// 1. Model names:\n\t//    Model(\"user\")\n\t//    Model(\"user u\")\n\t//    Model(\"user, user_detail\")\n\t//    Model(\"user u, user_detail ud\")\n\t// 2. Model name with alias: Model(\"user\", \"u\")\n\t// Also see Core.Model.\n\tModel(tableNameOrStruct ...any) *Model\n\n\t// Raw creates and returns a model based on a raw sql not a table.\n\tRaw(rawSql string, args ...any) *Model\n\n\t// Schema switches to a specified schema.\n\t// Also see Core.Schema.\n\tSchema(schema string) *Schema\n\n\t// With creates and returns an ORM model based on metadata of given object.\n\t// Also see Core.With.\n\tWith(objects ...any) *Model\n\n\t// Open creates a raw connection object for database with given node configuration.\n\t// Note that it is not recommended using the function manually.\n\tOpen(config *ConfigNode) (*sql.DB, error)\n\n\t// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy\n\t// of current DB object and with given context in it.\n\t// Also see Core.Ctx.\n\tCtx(ctx context.Context) DB\n\n\t// Close closes the database and prevents new queries from starting.\n\t// Close then waits for all queries that have started processing on the server\n\t// to finish.\n\t//\n\t// It is rare to Close a DB, as the DB handle is meant to be\n\t// long-lived and shared between many goroutines.\n\tClose(ctx context.Context) error\n\n\t// ===========================================================================\n\t// Query APIs.\n\t// ===========================================================================\n\n\t// Query executes a SQL query that returns rows using given SQL and arguments.\n\t// The args are for any placeholder parameters in the query.\n\tQuery(ctx context.Context, sql string, args ...any) (Result, error)\n\n\t// Exec executes a SQL query that doesn't return rows (e.g., INSERT, UPDATE, DELETE).\n\t// It returns sql.Result for accessing LastInsertId or RowsAffected.\n\tExec(ctx context.Context, sql string, args ...any) (sql.Result, error)\n\n\t// Prepare creates a prepared statement for later queries or executions.\n\t// The execOnMaster parameter determines whether the statement executes on master node.\n\tPrepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error)\n\n\t// ===========================================================================\n\t// Common APIs for CRUD.\n\t// ===========================================================================\n\n\t// Insert inserts one or multiple records into table.\n\t// The data can be a map, struct, or slice of maps/structs.\n\t// The optional batch parameter specifies the batch size for bulk inserts.\n\tInsert(ctx context.Context, table string, data any, batch ...int) (sql.Result, error)\n\n\t// InsertIgnore inserts records but ignores duplicate key errors.\n\t// It works like Insert but adds IGNORE keyword to the SQL statement.\n\tInsertIgnore(ctx context.Context, table string, data any, batch ...int) (sql.Result, error)\n\n\t// InsertAndGetId inserts a record and returns the auto-generated ID.\n\t// It's a convenience method combining Insert with LastInsertId.\n\tInsertAndGetId(ctx context.Context, table string, data any, batch ...int) (int64, error)\n\n\t// Replace inserts or replaces records using REPLACE INTO syntax.\n\t// Existing records with same unique key will be deleted and re-inserted.\n\tReplace(ctx context.Context, table string, data any, batch ...int) (sql.Result, error)\n\n\t// Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax.\n\t// It updates existing records instead of replacing them entirely.\n\tSave(ctx context.Context, table string, data any, batch ...int) (sql.Result, error)\n\n\t// Update updates records in table that match the condition.\n\t// The data can be a map or struct containing the new values.\n\t// The condition specifies the WHERE clause with optional placeholder args.\n\tUpdate(ctx context.Context, table string, data any, condition any, args ...any) (sql.Result, error)\n\n\t// Delete deletes records from table that match the condition.\n\t// The condition specifies the WHERE clause with optional placeholder args.\n\tDelete(ctx context.Context, table string, condition any, args ...any) (sql.Result, error)\n\n\t// ===========================================================================\n\t// Internal APIs for CRUD, which can be overwritten by custom CRUD implements.\n\t// ===========================================================================\n\n\t// DoSelect executes a SELECT query using the given link and returns the result.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoSelect(ctx context.Context, link Link, sql string, args ...any) (result Result, err error)\n\n\t// DoInsert performs the actual INSERT operation with given options.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error)\n\n\t// DoUpdate performs the actual UPDATE operation.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoUpdate(ctx context.Context, link Link, table string, data any, condition string, args ...any) (result sql.Result, err error)\n\n\t// DoDelete performs the actual DELETE operation.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoDelete(ctx context.Context, link Link, table string, condition string, args ...any) (result sql.Result, err error)\n\n\t// DoQuery executes a query that returns rows.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoQuery(ctx context.Context, link Link, sql string, args ...any) (result Result, err error)\n\n\t// DoExec executes a query that doesn't return rows.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoExec(ctx context.Context, link Link, sql string, args ...any) (result sql.Result, err error)\n\n\t// DoFilter processes and filters SQL and args before execution.\n\t// This is an internal method that can be overridden to implement custom SQL filtering.\n\tDoFilter(ctx context.Context, link Link, sql string, args []any) (newSql string, newArgs []any, err error)\n\n\t// DoCommit handles the actual commit operation for transactions.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error)\n\n\t// DoPrepare creates a prepared statement on the given link.\n\t// This is an internal method that can be overridden by custom implementations.\n\tDoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error)\n\n\t// ===========================================================================\n\t// Query APIs for convenience purpose.\n\t// ===========================================================================\n\n\t// GetAll executes a query and returns all rows as Result.\n\t// It's a convenience wrapper around Query.\n\tGetAll(ctx context.Context, sql string, args ...any) (Result, error)\n\n\t// GetOne executes a query and returns the first row as Record.\n\t// It's useful when you expect only one row to be returned.\n\tGetOne(ctx context.Context, sql string, args ...any) (Record, error)\n\n\t// GetValue executes a query and returns the first column of the first row.\n\t// It's useful for queries like SELECT COUNT(*) or getting a single value.\n\tGetValue(ctx context.Context, sql string, args ...any) (Value, error)\n\n\t// GetArray executes a query and returns the first column of all rows.\n\t// It's useful for queries like SELECT id FROM table.\n\tGetArray(ctx context.Context, sql string, args ...any) (Array, error)\n\n\t// GetCount executes a COUNT query and returns the result as an integer.\n\t// It's a convenience method for counting rows.\n\tGetCount(ctx context.Context, sql string, args ...any) (int, error)\n\n\t// GetScan executes a query and scans the result into the given object pointer.\n\t// It automatically maps database columns to struct fields or slice elements.\n\tGetScan(ctx context.Context, objPointer any, sql string, args ...any) error\n\n\t// Union combines multiple SELECT queries using UNION operator.\n\t// It returns a new Model that represents the combined query.\n\tUnion(unions ...*Model) *Model\n\n\t// UnionAll combines multiple SELECT queries using UNION ALL operator.\n\t// Unlike Union, it keeps duplicate rows in the result.\n\tUnionAll(unions ...*Model) *Model\n\n\t// ===========================================================================\n\t// Master/Slave specification support.\n\t// ===========================================================================\n\n\t// Master returns a connection to the master database node.\n\t// The optional schema parameter specifies which database schema to use.\n\tMaster(schema ...string) (*sql.DB, error)\n\n\t// Slave returns a connection to a slave database node.\n\t// The optional schema parameter specifies which database schema to use.\n\tSlave(schema ...string) (*sql.DB, error)\n\n\t// ===========================================================================\n\t// Ping-Pong.\n\t// ===========================================================================\n\n\t// PingMaster checks if the master database node is accessible.\n\t// It returns an error if the connection fails.\n\tPingMaster() error\n\n\t// PingSlave checks if any slave database node is accessible.\n\t// It returns an error if no slave connections are available.\n\tPingSlave() error\n\n\t// ===========================================================================\n\t// Transaction.\n\t// ===========================================================================\n\n\t// Begin starts a new transaction and returns a TX interface.\n\t// The returned TX must be committed or rolled back to release resources.\n\tBegin(ctx context.Context) (TX, error)\n\n\t// BeginWithOptions starts a new transaction with the given options and returns a TX interface.\n\t// The options allow specifying isolation level and read-only mode.\n\t// The returned TX must be committed or rolled back to release resources.\n\tBeginWithOptions(ctx context.Context, opts TxOptions) (TX, error)\n\n\t// Transaction executes a function within a transaction.\n\t// It automatically handles commit/rollback based on whether f returns an error.\n\tTransaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error\n\n\t// TransactionWithOptions executes a function within a transaction with specific options.\n\t// It allows customizing transaction behavior like isolation level and timeout.\n\tTransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error\n\n\t// ===========================================================================\n\t// Configuration methods.\n\t// ===========================================================================\n\n\t// GetCache returns the cache instance used by this database.\n\t// The cache is used for query results caching.\n\tGetCache() *gcache.Cache\n\n\t// SetDebug enables or disables debug mode for SQL logging.\n\t// When enabled, all SQL statements and their execution time are logged.\n\tSetDebug(debug bool)\n\n\t// GetDebug returns whether debug mode is enabled.\n\tGetDebug() bool\n\n\t// GetSchema returns the current database schema name.\n\tGetSchema() string\n\n\t// GetPrefix returns the table name prefix used by this database.\n\tGetPrefix() string\n\n\t// GetGroup returns the configuration group name of this database.\n\tGetGroup() string\n\n\t// SetDryRun enables or disables dry-run mode.\n\t// In dry-run mode, SQL statements are generated but not executed.\n\tSetDryRun(enabled bool)\n\n\t// GetDryRun returns whether dry-run mode is enabled.\n\tGetDryRun() bool\n\n\t// SetLogger sets a custom logger for database operations.\n\t// The logger must implement glog.ILogger interface.\n\tSetLogger(logger glog.ILogger)\n\n\t// GetLogger returns the current logger used by this database.\n\tGetLogger() glog.ILogger\n\n\t// GetConfig returns the configuration node used by this database.\n\tGetConfig() *ConfigNode\n\n\t// SetMaxIdleConnCount sets the maximum number of idle connections in the pool.\n\tSetMaxIdleConnCount(n int)\n\n\t// SetMaxOpenConnCount sets the maximum number of open connections to the database.\n\tSetMaxOpenConnCount(n int)\n\n\t// SetMaxConnLifeTime sets the maximum amount of time a connection may be reused.\n\tSetMaxConnLifeTime(d time.Duration)\n\n\t// SetMaxIdleConnTime sets the maximum amount of time a connection may be idle before being closed.\n\tSetMaxIdleConnTime(d time.Duration)\n\n\t// ===========================================================================\n\t// Utility methods.\n\t// ===========================================================================\n\n\t// Stats returns statistics about the database connection pool.\n\t// It includes information like the number of active and idle connections.\n\tStats(ctx context.Context) []StatsItem\n\n\t// GetCtx returns the context associated with this database instance.\n\tGetCtx() context.Context\n\n\t// GetCore returns the underlying Core instance of this database.\n\tGetCore() *Core\n\n\t// GetChars returns the left and right quote characters used for escaping identifiers.\n\t// For example, in MySQL these are backticks: ` and `.\n\tGetChars() (charLeft string, charRight string)\n\n\t// Tables returns a list of all table names in the specified schema.\n\t// If no schema is specified, it uses the default schema.\n\tTables(ctx context.Context, schema ...string) (tables []string, err error)\n\n\t// TableFields returns detailed information about all fields in the specified table.\n\t// The returned map keys are field names and values contain field metadata.\n\tTableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error)\n\n\t// ConvertValueForField converts a value to the appropriate type for a database field.\n\t// It handles type conversion from Go types to database-specific types.\n\tConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error)\n\n\t// ConvertValueForLocal converts a database value to the appropriate Go type.\n\t// It handles type conversion from database-specific types to Go types.\n\tConvertValueForLocal(ctx context.Context, fieldType string, fieldValue any) (any, error)\n\n\t// GetFormattedDBTypeNameForField returns the formatted database type name and pattern for a field type.\n\tGetFormattedDBTypeNameForField(fieldType string) (typeName, typePattern string)\n\n\t// CheckLocalTypeForField checks if a Go value is compatible with a database field type.\n\t// It returns the appropriate LocalType and any conversion errors.\n\tCheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue any) (LocalType, error)\n\n\t// FormatUpsert formats an upsert (INSERT ... ON DUPLICATE KEY UPDATE) statement.\n\t// It generates the appropriate SQL based on the columns, values, and options provided.\n\tFormatUpsert(columns []string, list List, option DoInsertOption) (string, error)\n\n\t// OrderRandomFunction returns the SQL function for random ordering.\n\t// The implementation is database-specific (e.g., RAND() for MySQL).\n\tOrderRandomFunction() string\n}\n\n// TX defines the interfaces for ORM transaction operations.\ntype TX interface {\n\tLink\n\n\t// Ctx binds a context to current transaction.\n\t// The context is used for operations like timeout control.\n\tCtx(ctx context.Context) TX\n\n\t// Raw creates and returns a model based on a raw SQL.\n\t// The rawSql can contain placeholders ? and corresponding args.\n\tRaw(rawSql string, args ...any) *Model\n\n\t// Model creates and returns a Model from given table name/struct.\n\t// The parameter can be table name as string, or struct/*struct type.\n\tModel(tableNameQueryOrStruct ...any) *Model\n\n\t// With creates and returns a Model from given object.\n\t// It automatically analyzes the object and generates corresponding SQL.\n\tWith(object any) *Model\n\n\t// ===========================================================================\n\t// Nested transaction if necessary.\n\t// ===========================================================================\n\n\t// Begin starts a nested transaction.\n\t// It creates a new savepoint for current transaction.\n\tBegin() error\n\n\t// Commit commits current transaction/savepoint.\n\t// For nested transactions, it releases the current savepoint.\n\tCommit() error\n\n\t// Rollback rolls back current transaction/savepoint.\n\t// For nested transactions, it rolls back to the current savepoint.\n\tRollback() error\n\n\t// Transaction executes given function in a nested transaction.\n\t// It automatically handles commit/rollback based on function's error return.\n\tTransaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error)\n\n\t// TransactionWithOptions executes given function in a nested transaction with options.\n\t// It allows customizing transaction behavior like isolation level.\n\tTransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error\n\n\t// ===========================================================================\n\t// Core method.\n\t// ===========================================================================\n\n\t// Query executes a query that returns rows using given SQL and arguments.\n\t// The args are for any placeholder parameters in the query.\n\tQuery(sql string, args ...any) (result Result, err error)\n\n\t// Exec executes a query that doesn't return rows.\n\t// For example: INSERT, UPDATE, DELETE.\n\tExec(sql string, args ...any) (sql.Result, error)\n\n\t// Prepare creates a prepared statement for later queries or executions.\n\t// Multiple queries or executions may be run concurrently from the statement.\n\tPrepare(sql string) (*Stmt, error)\n\n\t// ===========================================================================\n\t// Query.\n\t// ===========================================================================\n\n\t// GetAll executes a query and returns all rows as Result.\n\t// It's a convenient wrapper for Query.\n\tGetAll(sql string, args ...any) (Result, error)\n\n\t// GetOne executes a query and returns the first row as Record.\n\t// It's useful when you expect only one row to be returned.\n\tGetOne(sql string, args ...any) (Record, error)\n\n\t// GetStruct executes a query and scans the result into given struct.\n\t// The obj should be a pointer to struct.\n\tGetStruct(obj any, sql string, args ...any) error\n\n\t// GetStructs executes a query and scans all results into given struct slice.\n\t// The objPointerSlice should be a pointer to slice of struct.\n\tGetStructs(objPointerSlice any, sql string, args ...any) error\n\n\t// GetScan executes a query and scans the result into given variables.\n\t// The pointer can be type of struct/*struct/[]struct/[]*struct.\n\tGetScan(pointer any, sql string, args ...any) error\n\n\t// GetValue executes a query and returns the first column of first row.\n\t// It's useful for queries like SELECT COUNT(*).\n\tGetValue(sql string, args ...any) (Value, error)\n\n\t// GetCount executes a query that should return a count value.\n\t// It's a convenient wrapper for count queries.\n\tGetCount(sql string, args ...any) (int64, error)\n\n\t// ===========================================================================\n\t// CRUD.\n\t// ===========================================================================\n\n\t// Insert inserts one or multiple records into table.\n\t// The data can be map/struct/*struct/[]map/[]struct/[]*struct.\n\tInsert(table string, data any, batch ...int) (sql.Result, error)\n\n\t// InsertIgnore inserts one or multiple records with IGNORE option.\n\t// It ignores records that would cause duplicate key conflicts.\n\tInsertIgnore(table string, data any, batch ...int) (sql.Result, error)\n\n\t// InsertAndGetId inserts one record and returns its id value.\n\t// It's commonly used with auto-increment primary key.\n\tInsertAndGetId(table string, data any, batch ...int) (int64, error)\n\n\t// Replace inserts or replaces records using REPLACE INTO syntax.\n\t// Existing records with same unique key will be deleted and re-inserted.\n\tReplace(table string, data any, batch ...int) (sql.Result, error)\n\n\t// Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax.\n\t// It updates existing records instead of replacing them entirely.\n\tSave(table string, data any, batch ...int) (sql.Result, error)\n\n\t// Update updates records in table that match given condition.\n\t// The data can be map/struct, and condition supports various formats.\n\tUpdate(table string, data any, condition any, args ...any) (sql.Result, error)\n\n\t// Delete deletes records from table that match given condition.\n\t// The condition supports various formats with optional arguments.\n\tDelete(table string, condition any, args ...any) (sql.Result, error)\n\n\t// ===========================================================================\n\t// Utility methods.\n\t// ===========================================================================\n\n\t// GetCtx returns the context that is bound to current transaction.\n\tGetCtx() context.Context\n\n\t// GetDB returns the underlying DB interface object.\n\tGetDB() DB\n\n\t// GetSqlTX returns the underlying *sql.Tx object.\n\t// Note: be very careful when using this method.\n\tGetSqlTX() *sql.Tx\n\n\t// IsClosed checks if current transaction is closed.\n\t// A transaction is closed after Commit or Rollback.\n\tIsClosed() bool\n\n\t// ===========================================================================\n\t// Save point feature.\n\t// ===========================================================================\n\n\t// SavePoint creates a save point with given name.\n\t// It's used in nested transactions to create rollback points.\n\tSavePoint(point string) error\n\n\t// RollbackTo rolls back transaction to previously created save point.\n\t// If the save point doesn't exist, it returns an error.\n\tRollbackTo(point string) error\n}\n\n// StatsItem defines the stats information for a configuration node.\ntype StatsItem interface {\n\t// Node returns the configuration node info.\n\tNode() ConfigNode\n\n\t// Stats returns the connection stat for current node.\n\tStats() sql.DBStats\n}\n\n// Core is the base struct for database management.\ntype Core struct {\n\tdb            DB                               // DB interface object.\n\tctx           context.Context                  // Context for chaining operation only. Do not set a default value in Core initialization.\n\tgroup         string                           // Configuration group name.\n\tschema        string                           // Custom schema for this object.\n\tdebug         *gtype.Bool                      // Enable debug mode for the database, which can be changed in runtime.\n\tcache         *gcache.Cache                    // Cache manager, SQL result cache only.\n\tlinks         *gmap.KVMap[ConfigNode, *sql.DB] // links caches all created links by node.\n\tlogger        glog.ILogger                     // Logger for logging functionality.\n\tconfig        *ConfigNode                      // Current config node.\n\tlocalTypeMap  *gmap.StrAnyMap                  // Local type map for database field type conversion.\n\tdynamicConfig dynamicConfig                    // Dynamic configurations, which can be changed in runtime.\n\tinnerMemCache *gcache.Cache                    // Internal memory cache for storing temporary data.\n}\n\ntype dynamicConfig struct {\n\tMaxIdleConnCount int\n\tMaxOpenConnCount int\n\tMaxConnLifeTime  time.Duration\n\tMaxIdleConnTime  time.Duration\n}\n\n// DoCommitInput is the input parameters for function DoCommit.\ntype DoCommitInput struct {\n\t// Db is the underlying database connection object.\n\tDb *sql.DB\n\n\t// Tx is the underlying transaction object.\n\tTx *sql.Tx\n\n\t// Stmt is the prepared statement object.\n\tStmt *sql.Stmt\n\n\t// Link is the common database function wrapper interface.\n\tLink Link\n\n\t// Sql is the SQL string to be executed.\n\tSql string\n\n\t// Args is the arguments for SQL placeholders.\n\tArgs []any\n\n\t// Type indicates the type of SQL operation.\n\tType SqlType\n\n\t// TxOptions specifies the transaction options.\n\tTxOptions sql.TxOptions\n\n\t// TxCancelFunc is the context cancel function for transaction.\n\tTxCancelFunc context.CancelFunc\n\n\t// IsTransaction indicates whether current operation is in transaction.\n\tIsTransaction bool\n}\n\n// DoCommitOutput is the output parameters for function DoCommit.\ntype DoCommitOutput struct {\n\t// Result is the result of exec statement.\n\tResult sql.Result\n\n\t// Records is the result of query statement.\n\tRecords []Record\n\n\t// Stmt is the Statement object result for Prepare.\n\tStmt *Stmt\n\n\t// Tx is the transaction object result for Begin.\n\tTx TX\n\n\t// RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row.\n\tRawResult any\n}\n\n// Driver is the interface for integrating sql drivers into package gdb.\ntype Driver interface {\n\t// New creates and returns a database object for specified database server.\n\tNew(core *Core, node *ConfigNode) (DB, error)\n}\n\n// Link is a common database function wrapper interface.\n// Note that, any operation using `Link` will have no SQL logging.\ntype Link interface {\n\tQueryContext(ctx context.Context, sql string, args ...any) (*sql.Rows, error)\n\tExecContext(ctx context.Context, sql string, args ...any) (sql.Result, error)\n\tPrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)\n\tIsOnMaster() bool\n\tIsTransaction() bool\n}\n\n// Sql is the sql recording struct.\ntype Sql struct {\n\tSql           string  // SQL string(may contain reserved char '?').\n\tType          SqlType // SQL operation type.\n\tArgs          []any   // Arguments for this sql.\n\tFormat        string  // Formatted sql which contains arguments in the sql.\n\tError         error   // Execution result.\n\tStart         int64   // Start execution timestamp in milliseconds.\n\tEnd           int64   // End execution timestamp in milliseconds.\n\tGroup         string  // Group is the group name of the configuration that the sql is executed from.\n\tSchema        string  // Schema is the schema name of the configuration that the sql is executed from.\n\tIsTransaction bool    // IsTransaction marks whether this sql is executed in transaction.\n\tRowsAffected  int64   // RowsAffected marks retrieved or affected number with current sql statement.\n}\n\n// DoInsertOption is the input struct for function DoInsert.\ntype DoInsertOption struct {\n\t// OnDuplicateStr is the custom string for `on duplicated` statement.\n\tOnDuplicateStr string\n\n\t// OnDuplicateMap is the custom key-value map from `OnDuplicateEx` function for `on duplicated` statement.\n\tOnDuplicateMap map[string]any\n\n\t// OnConflict is the custom conflict key of upsert clause, if the database needs it.\n\tOnConflict []string\n\n\t// InsertOption is the insert operation in constant value.\n\tInsertOption InsertOption\n\n\t// BatchCount is the batch count for batch inserting.\n\tBatchCount int\n}\n\n// TableField is the struct for table field.\ntype TableField struct {\n\t// Index is for ordering purpose as map is unordered.\n\tIndex int\n\n\t// Name is the field name.\n\tName string\n\n\t// Type is the field type. Eg: 'int(10) unsigned', 'varchar(64)'.\n\tType string\n\n\t// Null is whether the field can be null or not.\n\tNull bool\n\n\t// Key is the index information(empty if it's not an index). Eg: PRI, MUL.\n\tKey string\n\n\t// Default is the default value for the field.\n\tDefault any\n\n\t// Extra is the extra information. Eg: auto_increment.\n\tExtra string\n\n\t// Comment is the field comment.\n\tComment string\n}\n\n// Counter is the type for update count.\ntype Counter struct {\n\t// Field is the field name.\n\tField string\n\n\t// Value is the value.\n\tValue float64\n}\n\ntype (\n\t// Raw is a raw sql that will not be treated as argument but as a direct sql part.\n\tRaw string\n\n\t// Value is the field value type.\n\tValue = *gvar.Var\n\n\t// Array is the field value array type.\n\tArray = gvar.Vars\n\n\t// Record is the row record of the table.\n\tRecord map[string]Value\n\n\t// Result is the row record array.\n\tResult []Record\n\n\t// Map is alias of map[string]any, which is the most common usage map type.\n\tMap = map[string]any\n\n\t// List is type of map array.\n\tList = []Map\n)\n\ntype CatchSQLManager struct {\n\t// SQLArray is the array of sql.\n\tSQLArray *garray.StrArray\n\n\t// DoCommit marks it will be committed to underlying driver or not.\n\tDoCommit bool\n}\n\nconst (\n\tdefaultModelSafe                      = false\n\tdefaultCharset                        = `utf8`\n\tdefaultProtocol                       = `tcp`\n\tunionTypeNormal                       = 0\n\tunionTypeAll                          = 1\n\tdefaultMaxIdleConnCount               = 10               // Max idle connection count in pool.\n\tdefaultMaxOpenConnCount               = 0                // Max open connection count in pool. Default is no limit.\n\tdefaultMaxConnLifeTime                = 30 * time.Second // Max lifetime for per connection in pool in seconds.\n\tcachePrefixTableFields                = `TableFields:`\n\tcachePrefixSelectCache                = `SelectCache:`\n\tcommandEnvKeyForDryRun                = \"gf.gdb.dryrun\"\n\tmodelForDaoSuffix                     = `ForDao`\n\tdbRoleSlave                           = `slave`\n\tctxKeyForDB               gctx.StrKey = `CtxKeyForDB`\n\tctxKeyCatchSQL            gctx.StrKey = `CtxKeyCatchSQL`\n\tctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL`\n\n\tlinkPattern            = `^(\\w+):(.*?):(.*?)@(\\w+?)\\((.+?)\\)/{0,1}([^\\?]*)\\?{0,1}(.*?)$`\n\tlinkPatternDescription = `type:username:password@protocol(host:port)/dbname?param1=value1&...&paramN=valueN`\n)\n\n// Context key types to avoid collisions\ntype ctxKey string\n\nconst (\n\tctxKeyWrappedByGetCtxTimeout ctxKey = \"WrappedByGetCtxTimeout\"\n)\n\ntype ctxTimeoutType int\n\nconst (\n\tctxTimeoutTypeExec ctxTimeoutType = iota\n\tctxTimeoutTypeQuery\n\tctxTimeoutTypePrepare\n\tctxTimeoutTypeTrans\n)\n\ntype SelectType int\n\nconst (\n\tSelectTypeDefault SelectType = iota\n\tSelectTypeCount\n\tSelectTypeValue\n\tSelectTypeArray\n)\n\ntype joinOperator string\n\nconst (\n\tjoinOperatorLeft  joinOperator = \"LEFT\"\n\tjoinOperatorRight joinOperator = \"RIGHT\"\n\tjoinOperatorInner joinOperator = \"INNER\"\n)\n\ntype InsertOption int\n\nconst (\n\tInsertOptionDefault InsertOption = iota\n\tInsertOptionReplace\n\tInsertOptionSave\n\tInsertOptionIgnore\n)\n\nconst (\n\tInsertOperationInsert      = \"INSERT\"\n\tInsertOperationReplace     = \"REPLACE\"\n\tInsertOperationIgnore      = \"INSERT IGNORE\"\n\tInsertOnDuplicateKeyUpdate = \"ON DUPLICATE KEY UPDATE\"\n)\n\ntype SqlType string\n\nconst (\n\tSqlTypeBegin               SqlType = \"DB.Begin\"\n\tSqlTypeTXCommit            SqlType = \"TX.Commit\"\n\tSqlTypeTXRollback          SqlType = \"TX.Rollback\"\n\tSqlTypeExecContext         SqlType = \"DB.ExecContext\"\n\tSqlTypeQueryContext        SqlType = \"DB.QueryContext\"\n\tSqlTypePrepareContext      SqlType = \"DB.PrepareContext\"\n\tSqlTypeStmtExecContext     SqlType = \"DB.Statement.ExecContext\"\n\tSqlTypeStmtQueryContext    SqlType = \"DB.Statement.QueryContext\"\n\tSqlTypeStmtQueryRowContext SqlType = \"DB.Statement.QueryRowContext\"\n)\n\n// LocalType is a type that defines the local storage type of a field value.\n// It is used to specify how the field value should be processed locally.\ntype LocalType string\n\nconst (\n\tLocalTypeUndefined    LocalType = \"\"\n\tLocalTypeString       LocalType = \"string\"\n\tLocalTypeTime         LocalType = \"time\"\n\tLocalTypeDate         LocalType = \"date\"\n\tLocalTypeDatetime     LocalType = \"datetime\"\n\tLocalTypeInt          LocalType = \"int\"\n\tLocalTypeUint         LocalType = \"uint\"\n\tLocalTypeInt32        LocalType = \"int32\"\n\tLocalTypeUint32       LocalType = \"uint32\"\n\tLocalTypeInt64        LocalType = \"int64\"\n\tLocalTypeUint64       LocalType = \"uint64\"\n\tLocalTypeBigInt       LocalType = \"bigint\"\n\tLocalTypeIntSlice     LocalType = \"[]int\"\n\tLocalTypeUintSlice    LocalType = \"[]uint\"\n\tLocalTypeInt32Slice   LocalType = \"[]int32\"\n\tLocalTypeUint32Slice  LocalType = \"[]uint32\"\n\tLocalTypeInt64Slice   LocalType = \"[]int64\"\n\tLocalTypeUint64Slice  LocalType = \"[]uint64\"\n\tLocalTypeStringSlice  LocalType = \"[]string\"\n\tLocalTypeInt64Bytes   LocalType = \"int64-bytes\"\n\tLocalTypeUint64Bytes  LocalType = \"uint64-bytes\"\n\tLocalTypeFloat32      LocalType = \"float32\"\n\tLocalTypeFloat64      LocalType = \"float64\"\n\tLocalTypeFloat32Slice LocalType = \"[]float32\"\n\tLocalTypeFloat64Slice LocalType = \"[]float64\"\n\tLocalTypeBytes        LocalType = \"[]byte\"\n\tLocalTypeBytesSlice   LocalType = \"[][]byte\"\n\tLocalTypeBool         LocalType = \"bool\"\n\tLocalTypeBoolSlice    LocalType = \"[]bool\"\n\tLocalTypeJson         LocalType = \"json\"\n\tLocalTypeJsonb        LocalType = \"jsonb\"\n\tLocalTypeUUID         LocalType = \"uuid.UUID\"\n\tLocalTypeUUIDSlice    LocalType = \"[]uuid.UUID\"\n)\n\nconst (\n\tfieldTypeBinary     = \"binary\"\n\tfieldTypeVarbinary  = \"varbinary\"\n\tfieldTypeBlob       = \"blob\"\n\tfieldTypeTinyblob   = \"tinyblob\"\n\tfieldTypeMediumblob = \"mediumblob\"\n\tfieldTypeLongblob   = \"longblob\"\n\tfieldTypeInt        = \"int\"\n\tfieldTypeTinyint    = \"tinyint\"\n\tfieldTypeSmallInt   = \"small_int\"\n\tfieldTypeSmallint   = \"smallint\"\n\tfieldTypeMediumInt  = \"medium_int\"\n\tfieldTypeMediumint  = \"mediumint\"\n\tfieldTypeSerial     = \"serial\"\n\tfieldTypeBigInt     = \"big_int\"\n\tfieldTypeBigint     = \"bigint\"\n\tfieldTypeBigserial  = \"bigserial\"\n\tfieldTypeInt128     = \"int128\"\n\tfieldTypeInt256     = \"int256\"\n\tfieldTypeUint128    = \"uint128\"\n\tfieldTypeUint256    = \"uint256\"\n\tfieldTypeReal       = \"real\"\n\tfieldTypeFloat      = \"float\"\n\tfieldTypeDouble     = \"double\"\n\tfieldTypeDecimal    = \"decimal\"\n\tfieldTypeMoney      = \"money\"\n\tfieldTypeNumeric    = \"numeric\"\n\tfieldTypeSmallmoney = \"smallmoney\"\n\tfieldTypeBool       = \"bool\"\n\tfieldTypeBit        = \"bit\"\n\tfieldTypeYear       = \"year\"      // YYYY\n\tfieldTypeDate       = \"date\"      // YYYY-MM-DD\n\tfieldTypeTime       = \"time\"      // HH:MM:SS\n\tfieldTypeDatetime   = \"datetime\"  // YYYY-MM-DD HH:MM:SS\n\tfieldTypeTimestamp  = \"timestamp\" // YYYYMMDD HHMMSS\n\tfieldTypeTimestampz = \"timestamptz\"\n\tfieldTypeJson       = \"json\"\n\tfieldTypeJsonb      = \"jsonb\"\n)\n\nvar (\n\t// checker is the checker function for instances map.\n\tchecker = func(v DB) bool { return v == nil }\n\t// instances is the management map for instances.\n\tinstances = gmap.NewKVMapWithChecker[string, DB](checker, true)\n\n\t// driverMap manages all custom registered driver.\n\tdriverMap = map[string]Driver{}\n\n\t// lastOperatorRegPattern is the regular expression pattern for a string\n\t// which has operator at its tail.\n\tlastOperatorRegPattern = `[<>=]+\\s*$`\n\n\t// regularFieldNameRegPattern is the regular expression pattern for a string\n\t// which is a regular field name of table.\n\tregularFieldNameRegPattern = `^[\\w\\.\\-]+$`\n\n\t// regularFieldNameWithCommaRegPattern is the regular expression pattern for one or more strings\n\t// which are regular field names of table, multiple field names joined with char ','.\n\tregularFieldNameWithCommaRegPattern = `^[\\w\\.\\-,\\s]+$`\n\n\t// regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'.\n\t// Note that, although some databases allow char '.' in the field name, but it here does not allow '.'\n\t// in the field name as it conflicts with \"db.table.field\" pattern in SOME situations.\n\tregularFieldNameWithoutDotRegPattern = `^[\\w\\-]+$`\n\n\t// allDryRun sets dry-run feature for all database connections.\n\t// It is commonly used for command options for convenience.\n\tallDryRun = false\n)\n\nfunc init() {\n\t// allDryRun is initialized from environment or command options.\n\tallDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool()\n}\n\n// Register registers custom database driver to gdb.\nfunc Register(name string, driver Driver) error {\n\tdriverMap[name] = newDriverWrapper(driver)\n\treturn nil\n}\n\n// New creates and returns an ORM object with given configuration node.\nfunc New(node ConfigNode) (db DB, err error) {\n\treturn newDBByConfigNode(&node, \"\")\n}\n\n// NewByGroup creates and returns an ORM object with global configurations.\n// The parameter `name` specifies the configuration group name,\n// which is DefaultGroupName in default.\nfunc NewByGroup(group ...string) (db DB, err error) {\n\tgroupName := configs.group\n\tif len(group) > 0 && group[0] != \"\" {\n\t\tgroupName = group[0]\n\t}\n\tconfigs.RLock()\n\tdefer configs.RUnlock()\n\n\tif len(configs.config) < 1 {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeInvalidConfiguration,\n\t\t\t\"database configuration is empty, please set the database configuration before using\",\n\t\t)\n\t}\n\tif _, ok := configs.config[groupName]; ok {\n\t\tvar node *ConfigNode\n\t\tif node, err = getConfigNodeByGroup(groupName, true); err == nil {\n\t\t\treturn newDBByConfigNode(node, groupName)\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn nil, gerror.NewCodef(\n\t\tgcode.CodeInvalidConfiguration,\n\t\t`database configuration node \"%s\" is not found, did you misspell group name \"%s\" or miss the database configuration?`,\n\t\tgroupName, groupName,\n\t)\n}\n\n// linksChecker is the checker function for links map.\nvar linksChecker = func(v *sql.DB) bool { return v == nil }\n\n// newDBByConfigNode creates and returns an ORM object with given configuration node and group name.\n//\n// Very Note:\n// The parameter `node` is used for DB creation, not for underlying connection creation.\n// So all db type configurations in the same group should be the same.\nfunc newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {\n\tif node.Link != \"\" {\n\t\tnode, err = parseConfigNodeLink(node)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tc := &Core{\n\t\tgroup:         group,\n\t\tdebug:         gtype.NewBool(),\n\t\tcache:         gcache.New(),\n\t\tlinks:         gmap.NewKVMapWithChecker[ConfigNode, *sql.DB](linksChecker, true),\n\t\tlogger:        glog.New(),\n\t\tconfig:        node,\n\t\tlocalTypeMap:  gmap.NewStrAnyMap(true),\n\t\tinnerMemCache: gcache.New(),\n\t\tdynamicConfig: dynamicConfig{\n\t\t\tMaxIdleConnCount: node.MaxIdleConnCount,\n\t\t\tMaxOpenConnCount: node.MaxOpenConnCount,\n\t\t\tMaxConnLifeTime:  node.MaxConnLifeTime,\n\t\t\tMaxIdleConnTime:  node.MaxIdleConnTime,\n\t\t},\n\t}\n\tif v, ok := driverMap[node.Type]; ok {\n\t\tif c.db, err = v.New(c, node); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn c.db, nil\n\t}\n\terrorMsg := `cannot find database driver for specified database type \"%s\"`\n\terrorMsg += `, did you misspell type name \"%s\" or forget importing the database driver? `\n\terrorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers`\n\treturn nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type)\n}\n\n// Instance returns an instance for DB operations.\n// The parameter `name` specifies the configuration group name,\n// which is DefaultGroupName in default.\nfunc Instance(name ...string) (db DB, err error) {\n\tgroup := configs.group\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tgroup = name[0]\n\t}\n\tv := instances.GetOrSetFuncLock(group, func() DB {\n\t\tdb, err = NewByGroup(group)\n\t\treturn db\n\t})\n\tif v != nil {\n\t\treturn v, nil\n\t}\n\treturn nil, err\n}\n\n// getConfigNodeByGroup calculates and returns a configuration node of given group. It\n// calculates the value internally using weight algorithm for load balance.\n//\n// The returned node is a clone of configuration node, which is safe for later modification.\n//\n// The parameter `master` specifies whether retrieving a master node, or else a slave node\n// if master-slave nodes are configured.\nfunc getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) {\n\tif list, ok := configs.config[group]; ok {\n\t\t// Separates master and slave configuration nodes array.\n\t\tvar (\n\t\t\tmasterList = make(ConfigGroup, 0)\n\t\t\tslaveList  = make(ConfigGroup, 0)\n\t\t)\n\t\tfor i := 0; i < len(list); i++ {\n\t\t\tif list[i].Role == dbRoleSlave {\n\t\t\t\tslaveList = append(slaveList, list[i])\n\t\t\t} else {\n\t\t\t\tmasterList = append(masterList, list[i])\n\t\t\t}\n\t\t}\n\t\tif len(masterList) < 1 {\n\t\t\treturn nil, gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidConfiguration,\n\t\t\t\t\"at least one master node configuration's need to make sense\",\n\t\t\t)\n\t\t}\n\t\tif len(slaveList) < 1 {\n\t\t\tslaveList = masterList\n\t\t}\n\t\tif master {\n\t\t\treturn getConfigNodeByWeight(masterList), nil\n\t\t} else {\n\t\t\treturn getConfigNodeByWeight(slaveList), nil\n\t\t}\n\t}\n\treturn nil, gerror.NewCodef(\n\t\tgcode.CodeInvalidConfiguration,\n\t\t\"empty database configuration for item name '%s'\",\n\t\tgroup,\n\t)\n}\n\n// getConfigNodeByWeight calculates the configuration weights and randomly returns a node.\n// The returned node is a clone of configuration node, which is safe for later modification.\n//\n// Calculation algorithm brief:\n// 1. If we have 2 nodes, and their weights are both 1, then the weight range is [0, 199];\n// 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1;\n// 3. If the random number is 99, it then chooses and returns node1;.\nfunc getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {\n\tif len(cg) < 2 {\n\t\treturn &cg[0]\n\t}\n\tvar total int\n\tfor i := 0; i < len(cg); i++ {\n\t\ttotal += cg[i].Weight * 100\n\t}\n\t// If total is 0 means all the nodes have no weight attribute configured.\n\t// It then defaults each node's weight attribute to 1.\n\tif total == 0 {\n\t\tfor i := 0; i < len(cg); i++ {\n\t\t\tcg[i].Weight = 1\n\t\t\ttotal += cg[i].Weight * 100\n\t\t}\n\t}\n\t// Exclude the right border value.\n\tvar (\n\t\tminWeight = 0\n\t\tmaxWeight = 0\n\t\trandom    = grand.N(0, total-1)\n\t)\n\tfor i := 0; i < len(cg); i++ {\n\t\tmaxWeight = minWeight + cg[i].Weight*100\n\t\tif random >= minWeight && random < maxWeight {\n\t\t\t// ====================================================\n\t\t\t// Return a COPY of the ConfigNode.\n\t\t\t// ====================================================\n\t\t\tnode := ConfigNode{}\n\t\t\tnode = cg[i]\n\t\t\treturn &node\n\t\t}\n\t\tminWeight = maxWeight\n\t}\n\treturn nil\n}\n\n// getSqlDb retrieves and returns an underlying database connection object.\n// The parameter `master` specifies whether retrieves master node connection if\n// master-slave nodes are configured.\nfunc (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {\n\tvar (\n\t\tnode *ConfigNode\n\t\tctx  = c.db.GetCtx()\n\t)\n\tif c.group != \"\" {\n\t\t// Load balance.\n\t\tconfigs.RLock()\n\t\tdefer configs.RUnlock()\n\t\t// Value COPY for node.\n\t\t// The returned node is a clone of configuration node, which is safe for later modification.\n\t\tnode, err = getConfigNodeByGroup(c.group, master)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\t// Value COPY for node.\n\t\tn := *c.db.GetConfig()\n\t\tnode = &n\n\t}\n\tif node.Charset == \"\" {\n\t\tnode.Charset = defaultCharset\n\t}\n\t// Changes the schema.\n\tnodeSchema := gutil.GetOrDefaultStr(c.schema, schema...)\n\tif nodeSchema != \"\" {\n\t\tnode.Name = nodeSchema\n\t}\n\t// Update the configuration object in internal data.\n\tif err = c.setConfigNodeToCtx(ctx, node); err != nil {\n\t\treturn\n\t}\n\n\t// Cache the underlying connection pool object by node.\n\tvar (\n\t\tinstanceCacheFunc = func() *sql.DB {\n\t\t\tif sqlDb, err = c.db.Open(node); err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif sqlDb == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif c.dynamicConfig.MaxIdleConnCount > 0 {\n\t\t\t\tsqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount)\n\t\t\t} else {\n\t\t\t\tsqlDb.SetMaxIdleConns(defaultMaxIdleConnCount)\n\t\t\t}\n\t\t\tif c.dynamicConfig.MaxOpenConnCount > 0 {\n\t\t\t\tsqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount)\n\t\t\t} else {\n\t\t\t\tsqlDb.SetMaxOpenConns(defaultMaxOpenConnCount)\n\t\t\t}\n\t\t\tif c.dynamicConfig.MaxConnLifeTime > 0 {\n\t\t\t\tsqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime)\n\t\t\t} else {\n\t\t\t\tsqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)\n\t\t\t}\n\t\t\tif c.dynamicConfig.MaxIdleConnTime > 0 {\n\t\t\t\tsqlDb.SetConnMaxIdleTime(c.dynamicConfig.MaxIdleConnTime)\n\t\t\t}\n\t\t\treturn sqlDb\n\t\t}\n\t\t// it here uses NODE VALUE not pointer as the cache key, in case of oracle ORA-12516 error.\n\t\tinstanceValue = c.links.GetOrSetFuncLock(*node, instanceCacheFunc)\n\t)\n\tif instanceValue != nil && sqlDb == nil {\n\t\t// It reads from instance map.\n\t\tsqlDb = instanceValue\n\t}\n\tif node.Debug {\n\t\tc.db.SetDebug(node.Debug)\n\t}\n\tif node.DryRun {\n\t\tc.db.SetDryRun(node.DryRun)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "database/gdb/gdb_converter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// iVal is used for type assert api for Val().\ntype iVal interface {\n\tVal() any\n}\n\nvar (\n\t// converter is the internal type converter for gdb.\n\tconverter = gconv.NewConverter()\n)\n\nfunc init() {\n\tconverter.RegisterAnyConverterFunc(\n\t\tsliceTypeConverterFunc,\n\t\treflect.TypeOf([]string{}),\n\t\treflect.TypeOf([]float32{}),\n\t\treflect.TypeOf([]float64{}),\n\t\treflect.TypeOf([]int{}),\n\t\treflect.TypeOf([]int32{}),\n\t\treflect.TypeOf([]int64{}),\n\t\treflect.TypeOf([]uint{}),\n\t\treflect.TypeOf([]uint32{}),\n\t\treflect.TypeOf([]uint64{}),\n\t)\n}\n\n// GetConverter returns the internal type converter for gdb.\nfunc GetConverter() gconv.Converter {\n\treturn converter\n}\n\nfunc sliceTypeConverterFunc(from any, to reflect.Value) (err error) {\n\tv, ok := from.(iVal)\n\tif !ok {\n\t\treturn nil\n\t}\n\tfromVal := v.Val()\n\tswitch x := fromVal.(type) {\n\tcase []byte:\n\t\tdst := to.Addr().Interface()\n\t\terr = json.Unmarshal(x, dst)\n\tcase string:\n\t\tdst := to.Addr().Interface()\n\t\terr = json.Unmarshal([]byte(x), dst)\n\tdefault:\n\t\tfromType := reflect.TypeOf(fromVal)\n\t\tswitch fromType.Kind() {\n\t\tcase reflect.Slice:\n\t\t\tconvertOption := gconv.ConvertOption{\n\t\t\t\tSliceOption:  gconv.SliceOption{ContinueOnError: true},\n\t\t\t\tMapOption:    gconv.MapOption{ContinueOnError: true},\n\t\t\t\tStructOption: gconv.StructOption{ContinueOnError: true},\n\t\t\t}\n\t\t\tdv, err := converter.ConvertWithTypeName(fromVal, to.Type().String(), convertOption)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tto.Set(reflect.ValueOf(dv))\n\t\tdefault:\n\t\t\terr = gerror.Newf(\n\t\t\t\t`unsupported type converting from type \"%T\" to type \"%T\"`,\n\t\t\t\tfromVal, to,\n\t\t\t)\n\t\t}\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "database/gdb/gdb_core.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// GetCore returns the underlying *Core object.\nfunc (c *Core) GetCore() *Core {\n\treturn c\n}\n\n// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy\n// of current DB object and with given context in it.\n// Note that this returned DB object can be used only once, so do not assign it to\n// a global or package variable for long using.\nfunc (c *Core) Ctx(ctx context.Context) DB {\n\tif ctx == nil {\n\t\treturn c.db\n\t}\n\t// It makes a shallow copy of current db and changes its context for next chaining operation.\n\tvar (\n\t\terr        error\n\t\tnewCore    = &Core{}\n\t\tconfigNode = c.db.GetConfig()\n\t)\n\t*newCore = *c\n\t// It creates a new DB object(NOT NEW CONNECTION), which is commonly a wrapper for object `Core`.\n\tnewCore.db, err = driverMap[configNode.Type].New(newCore, configNode)\n\tif err != nil {\n\t\t// It is really a serious error here.\n\t\t// Do not let it continue.\n\t\tpanic(err)\n\t}\n\tnewCore.ctx = WithDB(ctx, newCore.db)\n\tnewCore.ctx = c.injectInternalCtxData(newCore.ctx)\n\treturn newCore.db\n}\n\n// GetCtx returns the context for current DB.\n// It returns `context.Background()` is there's no context previously set.\nfunc (c *Core) GetCtx() context.Context {\n\tctx := c.ctx\n\tif ctx == nil {\n\t\tctx = context.TODO()\n\t}\n\treturn c.injectInternalCtxData(ctx)\n}\n\n// GetCtxTimeout returns the context and cancel function for specified timeout type.\nfunc (c *Core) GetCtxTimeout(ctx context.Context, timeoutType ctxTimeoutType) (context.Context, context.CancelFunc) {\n\tif ctx == nil {\n\t\tctx = c.db.GetCtx()\n\t} else {\n\t\tctx = context.WithValue(ctx, ctxKeyWrappedByGetCtxTimeout, nil)\n\t}\n\tvar config = c.db.GetConfig()\n\tswitch timeoutType {\n\tcase ctxTimeoutTypeExec:\n\t\tif c.db.GetConfig().ExecTimeout > 0 {\n\t\t\treturn context.WithTimeout(ctx, config.ExecTimeout)\n\t\t}\n\tcase ctxTimeoutTypeQuery:\n\t\tif c.db.GetConfig().QueryTimeout > 0 {\n\t\t\treturn context.WithTimeout(ctx, config.QueryTimeout)\n\t\t}\n\tcase ctxTimeoutTypePrepare:\n\t\tif c.db.GetConfig().PrepareTimeout > 0 {\n\t\t\treturn context.WithTimeout(ctx, config.PrepareTimeout)\n\t\t}\n\tcase ctxTimeoutTypeTrans:\n\t\tif c.db.GetConfig().TranTimeout > 0 {\n\t\t\treturn context.WithTimeout(ctx, config.TranTimeout)\n\t\t}\n\tdefault:\n\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, \"invalid context timeout type: %d\", timeoutType))\n\t}\n\treturn ctx, func() {}\n}\n\n// Close closes the database and prevents new queries from starting.\n// Close then waits for all queries that have started processing on the server\n// to finish.\n//\n// It is rare to Close a DB, as the DB handle is meant to be\n// long-lived and shared between many goroutines.\nfunc (c *Core) Close(ctx context.Context) (err error) {\n\tif err = c.cache.Close(ctx); err != nil {\n\t\treturn err\n\t}\n\tc.links.LockFunc(func(m map[ConfigNode]*sql.DB) {\n\t\tfor k, v := range m {\n\t\t\terr = v.Close()\n\t\t\tif err != nil {\n\t\t\t\terr = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`)\n\t\t\t}\n\t\t\tintlog.Printf(ctx, `close link: %s, err: %v`, gconv.String(k), err)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tdelete(m, k)\n\t\t}\n\t})\n\treturn\n}\n\n// Master creates and returns a connection from master node if master-slave configured.\n// It returns the default connection if master-slave not configured.\nfunc (c *Core) Master(schema ...string) (*sql.DB, error) {\n\tvar (\n\t\tusedSchema   = gutil.GetOrDefaultStr(c.schema, schema...)\n\t\tcharL, charR = c.db.GetChars()\n\t)\n\treturn c.getSqlDb(true, gstr.Trim(usedSchema, charL+charR))\n}\n\n// Slave creates and returns a connection from slave node if master-slave configured.\n// It returns the default connection if master-slave not configured.\nfunc (c *Core) Slave(schema ...string) (*sql.DB, error) {\n\tvar (\n\t\tusedSchema   = gutil.GetOrDefaultStr(c.schema, schema...)\n\t\tcharL, charR = c.db.GetChars()\n\t)\n\treturn c.getSqlDb(false, gstr.Trim(usedSchema, charL+charR))\n}\n\n// GetAll queries and returns data records from database.\nfunc (c *Core) GetAll(ctx context.Context, sql string, args ...any) (Result, error) {\n\treturn c.db.DoSelect(ctx, nil, sql, args...)\n}\n\n// DoSelect queries and returns data records from database.\nfunc (c *Core) DoSelect(ctx context.Context, link Link, sql string, args ...any) (result Result, err error) {\n\treturn c.db.DoQuery(ctx, link, sql, args...)\n}\n\n// GetOne queries and returns one record from database.\nfunc (c *Core) GetOne(ctx context.Context, sql string, args ...any) (Record, error) {\n\tlist, err := c.db.GetAll(ctx, sql, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\treturn list[0], nil\n\t}\n\treturn nil, nil\n}\n\n// GetArray queries and returns data values as slice from database.\n// Note that if there are multiple columns in the result, it returns just one column values randomly.\nfunc (c *Core) GetArray(ctx context.Context, sql string, args ...any) (Array, error) {\n\tall, err := c.db.DoSelect(ctx, nil, sql, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn all.Array(), nil\n}\n\n// doGetStruct queries one record from database and converts it to given struct.\n// The parameter `pointer` should be a pointer to struct.\nfunc (c *Core) doGetStruct(ctx context.Context, pointer any, sql string, args ...any) error {\n\tone, err := c.db.GetOne(ctx, sql, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn one.Struct(pointer)\n}\n\n// doGetStructs queries records from database and converts them to given struct.\n// The parameter `pointer` should be type of struct slice: []struct/[]*struct.\nfunc (c *Core) doGetStructs(ctx context.Context, pointer any, sql string, args ...any) error {\n\tall, err := c.db.GetAll(ctx, sql, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn all.Structs(pointer)\n}\n\n// GetScan queries one or more records from database and converts them to given struct or\n// struct array.\n//\n// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for\n// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally\n// for conversion.\nfunc (c *Core) GetScan(ctx context.Context, pointer any, sql string, args ...any) error {\n\treflectInfo := reflection.OriginTypeAndKind(pointer)\n\tif reflectInfo.InputKind != reflect.Pointer {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"params should be type of pointer, but got: %v\",\n\t\t\treflectInfo.InputKind,\n\t\t)\n\t}\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.Array, reflect.Slice:\n\t\treturn c.db.GetCore().doGetStructs(ctx, pointer, sql, args...)\n\n\tcase reflect.Struct:\n\t\treturn c.db.GetCore().doGetStruct(ctx, pointer, sql, args...)\n\n\tdefault:\n\t}\n\treturn gerror.NewCodef(\n\t\tgcode.CodeInvalidParameter,\n\t\t`in valid parameter type \"%v\", of which element type should be type of struct/slice`,\n\t\treflectInfo.InputType,\n\t)\n}\n\n// GetValue queries and returns the field value from database.\n// The sql should query only one field from database, or else it returns only one\n// field of the result.\nfunc (c *Core) GetValue(ctx context.Context, sql string, args ...any) (Value, error) {\n\tone, err := c.db.GetOne(ctx, sql, args...)\n\tif err != nil {\n\t\treturn gvar.New(nil), err\n\t}\n\tfor _, v := range one {\n\t\treturn v, nil\n\t}\n\treturn gvar.New(nil), nil\n}\n\n// GetCount queries and returns the count from database.\nfunc (c *Core) GetCount(ctx context.Context, sql string, args ...any) (int, error) {\n\t// If the query fields do not contain function \"COUNT\",\n\t// it replaces the sql string and adds the \"COUNT\" function to the fields.\n\tif !gregex.IsMatchString(`(?i)SELECT\\s+COUNT\\(.+\\)\\s+FROM`, sql) {\n\t\tsql, _ = gregex.ReplaceString(`(?i)(SELECT)\\s+(.+)\\s+(FROM)`, `$1 COUNT($2) $3`, sql)\n\t}\n\tvalue, err := c.db.GetValue(ctx, sql, args...)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Int(), nil\n}\n\n// Union does \"(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ...\" statement.\nfunc (c *Core) Union(unions ...*Model) *Model {\n\tvar ctx = c.db.GetCtx()\n\treturn c.doUnion(ctx, unionTypeNormal, unions...)\n}\n\n// UnionAll does \"(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ...\" statement.\nfunc (c *Core) UnionAll(unions ...*Model) *Model {\n\tvar ctx = c.db.GetCtx()\n\treturn c.doUnion(ctx, unionTypeAll, unions...)\n}\n\nfunc (c *Core) doUnion(ctx context.Context, unionType int, unions ...*Model) *Model {\n\tvar (\n\t\tunionTypeStr   string\n\t\tcomposedSqlStr string\n\t\tcomposedArgs   = make([]any, 0)\n\t)\n\tif unionType == unionTypeAll {\n\t\tunionTypeStr = \"UNION ALL\"\n\t} else {\n\t\tunionTypeStr = \"UNION\"\n\t}\n\tfor _, v := range unions {\n\t\tsqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, SelectTypeDefault, false)\n\t\tif composedSqlStr == \"\" {\n\t\t\tcomposedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder)\n\t\t} else {\n\t\t\tcomposedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder)\n\t\t}\n\t\tcomposedArgs = append(composedArgs, holderArgs...)\n\t}\n\treturn c.db.Raw(composedSqlStr, composedArgs...)\n}\n\n// PingMaster pings the master node to check authentication or keeps the connection alive.\nfunc (c *Core) PingMaster() error {\n\tvar ctx = c.db.GetCtx()\n\tif master, err := c.db.Master(); err != nil {\n\t\treturn err\n\t} else {\n\t\tif err = master.PingContext(ctx); err != nil {\n\t\t\terr = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`)\n\t\t}\n\t\treturn err\n\t}\n}\n\n// PingSlave pings the slave node to check authentication or keeps the connection alive.\nfunc (c *Core) PingSlave() error {\n\tvar ctx = c.db.GetCtx()\n\tif slave, err := c.db.Slave(); err != nil {\n\t\treturn err\n\t} else {\n\t\tif err = slave.PingContext(ctx); err != nil {\n\t\t\terr = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`)\n\t\t}\n\t\treturn err\n\t}\n}\n\n// Insert does \"INSERT INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it returns error.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `batch` specifies the batch operation count when given data is slice.\nfunc (c *Core) Insert(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert()\n\t}\n\treturn c.Model(table).Ctx(ctx).Data(data).Insert()\n}\n\n// InsertIgnore does \"INSERT IGNORE INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it ignores the inserting.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `batch` specifies the batch operation count when given data is slice.\nfunc (c *Core) InsertIgnore(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore()\n\t}\n\treturn c.Model(table).Ctx(ctx).Data(data).InsertIgnore()\n}\n\n// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.\nfunc (c *Core) InsertAndGetId(ctx context.Context, table string, data any, batch ...int) (int64, error) {\n\tif len(batch) > 0 {\n\t\treturn c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId()\n\t}\n\treturn c.Model(table).Ctx(ctx).Data(data).InsertAndGetId()\n}\n\n// Replace does \"REPLACE INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it deletes the record\n// and inserts a new one.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// If given data is type of slice, it then does batch replacing, and the optional parameter\n// `batch` specifies the batch operation count.\nfunc (c *Core) Replace(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace()\n\t}\n\treturn c.Model(table).Ctx(ctx).Data(data).Replace()\n}\n\n// Save does \"INSERT INTO ... ON DUPLICATE KEY UPDATE...\" statement for the table.\n// It updates the record if there's primary or unique index in the saving data,\n// or else it inserts a new record into the table.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// If given data is type of slice, it then does batch saving, and the optional parameter\n// `batch` specifies the batch operation count.\nfunc (c *Core) Save(ctx context.Context, table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save()\n\t}\n\treturn c.Model(table).Ctx(ctx).Data(data).Save()\n}\n\nfunc (c *Core) fieldsToSequence(ctx context.Context, table string, fields []string) ([]string, error) {\n\tvar (\n\t\tfieldSet               = gset.NewStrSetFrom(fields)\n\t\tfieldsResultInSequence = make([]string, 0)\n\t\ttableFields, err       = c.db.TableFields(ctx, table)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Sort the fields in order.\n\tvar fieldsOfTableInSequence = make([]string, len(tableFields))\n\tfor _, field := range tableFields {\n\t\tfieldsOfTableInSequence[field.Index] = field.Name\n\t}\n\t// Sort the input fields.\n\tfor _, fieldName := range fieldsOfTableInSequence {\n\t\tif fieldSet.Contains(fieldName) {\n\t\t\tfieldsResultInSequence = append(fieldsResultInSequence, fieldName)\n\t\t}\n\t}\n\treturn fieldsResultInSequence, nil\n}\n\n// DoInsert inserts or updates data for given table.\n// This function is usually used for custom interface definition, you do not need call it manually.\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `option` values are as follows:\n// InsertOptionDefault: just insert, if there's unique/primary key in the data, it returns error;\n// InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;\n// InsertOptionSave:    if there's unique/primary key in the data, it updates it or else inserts a new one;\n// InsertOptionIgnore:  if there's unique/primary key in the data, it ignores the inserting;\nfunc (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) {\n\tvar (\n\t\tkeys           []string // Field names.\n\t\tvalues         []string // Value holder string array, like: (?,?,?)\n\t\tparams         []any    // Values that will be committed to underlying database driver.\n\t\tonDuplicateStr string   // onDuplicateStr is used in \"ON DUPLICATE KEY UPDATE\" statement.\n\t)\n\t// ============================================================================================\n\t// Group the list by fields. Different fields to different list.\n\t// It here uses ListMap to keep sequence for data inserting.\n\t// ============================================================================================\n\tvar (\n\t\tkeyListMap    = gmap.NewListMap()\n\t\ttmpKeyListMap = make(map[string]List)\n\t)\n\tfor _, item := range list {\n\t\tmapLen := len(item)\n\t\tif mapLen == 0 {\n\t\t\tcontinue\n\t\t}\n\t\ttmpKeys := make([]string, 0, mapLen)\n\t\tfor k := range item {\n\t\t\ttmpKeys = append(tmpKeys, k)\n\t\t}\n\t\tif mapLen > 1 {\n\t\t\tsort.Strings(tmpKeys)\n\t\t}\n\t\tkeys = tmpKeys // for fieldsToSequence\n\n\t\ttmpKeysInSequenceStr := gstr.Join(tmpKeys, \",\")\n\t\tif tmpKeyListMapItem, ok := tmpKeyListMap[tmpKeysInSequenceStr]; ok {\n\t\t\ttmpKeyListMap[tmpKeysInSequenceStr] = append(tmpKeyListMapItem, item)\n\t\t} else {\n\t\t\ttmpKeyListMap[tmpKeysInSequenceStr] = List{item}\n\t\t}\n\t}\n\tfor tmpKeysInSequenceStr, itemList := range tmpKeyListMap {\n\t\tkeyListMap.Set(tmpKeysInSequenceStr, itemList)\n\t}\n\tif keyListMap.Size() > 1 {\n\t\tvar (\n\t\t\ttmpResult    sql.Result\n\t\t\tsqlResult    SqlResult\n\t\t\trowsAffected int64\n\t\t)\n\t\tkeyListMap.Iterator(func(key, value any) bool {\n\t\t\ttmpResult, err = c.DoInsert(ctx, link, table, value.(List), option)\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\trowsAffected, err = tmpResult.RowsAffected()\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tsqlResult.Result = tmpResult\n\t\t\tsqlResult.Affected += rowsAffected\n\t\t\treturn true\n\t\t})\n\t\treturn &sqlResult, err\n\t}\n\n\tkeys, err = c.fieldsToSequence(ctx, table, keys)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(keys) == 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"no valid data fields found in table\")\n\t}\n\n\t// Prepare the batch result pointer.\n\tvar (\n\t\tcharL, charR = c.db.GetChars()\n\t\tbatchResult  = new(SqlResult)\n\t\tkeysStr      = charL + strings.Join(keys, charR+\",\"+charL) + charR\n\t\toperation    = GetInsertOperationByOption(option.InsertOption)\n\t)\n\t// Upsert clause only takes effect on Save operation.\n\tif option.InsertOption == InsertOptionSave {\n\t\tonDuplicateStr, err = c.db.FormatUpsert(keys, list, option)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tvar (\n\t\tlistLength   = len(list)\n\t\tvalueHolders = make([]string, 0)\n\t)\n\tfor i := 0; i < listLength; i++ {\n\t\tvalues = values[:0]\n\t\t// Note that the map type is unordered,\n\t\t// so it should use slice+key to retrieve the value.\n\t\tfor _, k := range keys {\n\t\t\tif s, ok := list[i][k].(Raw); ok {\n\t\t\t\tvalues = append(values, gconv.String(s))\n\t\t\t} else {\n\t\t\t\tvalues = append(values, \"?\")\n\t\t\t\tparams = append(params, list[i][k])\n\t\t\t}\n\t\t}\n\t\tvalueHolders = append(valueHolders, \"(\"+gstr.Join(values, \",\")+\")\")\n\t\t// Batch package checks: It meets the batch number, or it is the last element.\n\t\tif len(valueHolders) == option.BatchCount || (i == listLength-1 && len(valueHolders) > 0) {\n\t\t\tvar (\n\t\t\t\tstdSqlResult sql.Result\n\t\t\t\taffectedRows int64\n\t\t\t)\n\t\t\tstdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf(\n\t\t\t\t\"%s INTO %s(%s) VALUES%s %s\",\n\t\t\t\toperation, c.QuotePrefixTableName(table), keysStr,\n\t\t\t\tgstr.Join(valueHolders, \",\"),\n\t\t\t\tonDuplicateStr,\n\t\t\t), params...)\n\t\t\tif err != nil {\n\t\t\t\treturn stdSqlResult, err\n\t\t\t}\n\t\t\tif affectedRows, err = stdSqlResult.RowsAffected(); err != nil {\n\t\t\t\terr = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`)\n\t\t\t\treturn stdSqlResult, err\n\t\t\t} else {\n\t\t\t\tbatchResult.Result = stdSqlResult\n\t\t\t\tbatchResult.Affected += affectedRows\n\t\t\t}\n\t\t\tparams = params[:0]\n\t\t\tvalueHolders = valueHolders[:0]\n\t\t}\n\t}\n\treturn batchResult, nil\n}\n\n// Update does \"UPDATE ... \" statement for the table.\n//\n// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.\n// Eg: \"uid=10000\", \"uid\", 10000, g.Map{\"uid\": 10000, \"name\":\"john\"}\n//\n// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.\n// It is commonly used with parameter `args`.\n// Eg:\n// \"uid=10000\",\n// \"uid\", 10000\n// \"money>? AND name like ?\", 99999, \"vip_%\"\n// \"status IN (?)\", g.Slice{1,2,3}\n// \"age IN(?,?)\", 18, 50\n// User{ Id : 1, UserName : \"john\"}.\nfunc (c *Core) Update(ctx context.Context, table string, data any, condition any, args ...any) (sql.Result, error) {\n\treturn c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update()\n}\n\n// DoUpdate does \"UPDATE ... \" statement for the table.\n// This function is usually used for custom interface definition, you do not need to call it manually.\nfunc (c *Core) DoUpdate(ctx context.Context, link Link, table string, data any, condition string, args ...any) (result sql.Result, err error) {\n\ttable = c.QuotePrefixTableName(table)\n\tvar (\n\t\trv   = reflect.ValueOf(data)\n\t\tkind = rv.Kind()\n\t)\n\tif kind == reflect.Pointer {\n\t\trv = rv.Elem()\n\t\tkind = rv.Kind()\n\t}\n\tvar (\n\t\tparams  []any\n\t\tupdates string\n\t)\n\tswitch kind {\n\tcase reflect.Map, reflect.Struct:\n\t\tvar (\n\t\t\tfields  []string\n\t\t\tdataMap map[string]any\n\t\t)\n\t\tdataMap, err = c.ConvertDataForRecord(ctx, data, table)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Sort the data keys in sequence of table fields.\n\t\tvar (\n\t\t\tdataKeys       = make([]string, 0)\n\t\t\tkeysInSequence = make([]string, 0)\n\t\t)\n\t\tfor k := range dataMap {\n\t\t\tdataKeys = append(dataKeys, k)\n\t\t}\n\t\tkeysInSequence, err = c.fieldsToSequence(ctx, table, dataKeys)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, k := range keysInSequence {\n\t\t\tv := dataMap[k]\n\t\t\tswitch v.(type) {\n\t\t\tcase Counter, *Counter:\n\t\t\t\tvar counter Counter\n\t\t\t\tswitch value := v.(type) {\n\t\t\t\tcase Counter:\n\t\t\t\t\tcounter = value\n\t\t\t\tcase *Counter:\n\t\t\t\t\tcounter = *value\n\t\t\t\t}\n\t\t\t\tif counter.Value == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toperator, columnVal := c.getCounterAlter(counter)\n\t\t\t\tfields = append(fields, fmt.Sprintf(\"%s=%s%s?\", c.QuoteWord(k), c.QuoteWord(counter.Field), operator))\n\t\t\t\tparams = append(params, columnVal)\n\t\t\tdefault:\n\t\t\t\tif s, ok := v.(Raw); ok {\n\t\t\t\t\tfields = append(fields, c.QuoteWord(k)+\"=\"+gconv.String(s))\n\t\t\t\t} else {\n\t\t\t\t\tfields = append(fields, c.QuoteWord(k)+\"=?\")\n\t\t\t\t\tparams = append(params, v)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tupdates = strings.Join(fields, \",\")\n\n\tdefault:\n\t\tupdates = gconv.String(data)\n\t}\n\tif len(updates) == 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeMissingParameter, \"data cannot be empty\")\n\t}\n\tif len(params) > 0 {\n\t\targs = append(params, args...)\n\t}\n\t// If no link passed, it then uses the master link.\n\tif link == nil {\n\t\tif link, err = c.MasterLink(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.db.DoExec(ctx, link, fmt.Sprintf(\n\t\t\"UPDATE %s SET %s%s\",\n\t\ttable, updates, condition,\n\t),\n\t\targs...,\n\t)\n}\n\n// Delete does \"DELETE FROM ... \" statement for the table.\n//\n// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.\n// It is commonly used with parameter `args`.\n// Eg:\n// \"uid=10000\",\n// \"uid\", 10000\n// \"money>? AND name like ?\", 99999, \"vip_%\"\n// \"status IN (?)\", g.Slice{1,2,3}\n// \"age IN(?,?)\", 18, 50\n// User{ Id : 1, UserName : \"john\"}.\nfunc (c *Core) Delete(ctx context.Context, table string, condition any, args ...any) (result sql.Result, err error) {\n\treturn c.Model(table).Ctx(ctx).Where(condition, args...).Delete()\n}\n\n// DoDelete does \"DELETE FROM ... \" statement for the table.\n// This function is usually used for custom interface definition, you do not need call it manually.\nfunc (c *Core) DoDelete(ctx context.Context, link Link, table string, condition string, args ...any) (result sql.Result, err error) {\n\tif link == nil {\n\t\tif link, err = c.MasterLink(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\ttable = c.QuotePrefixTableName(table)\n\treturn c.db.DoExec(ctx, link, fmt.Sprintf(\"DELETE FROM %s%s\", table, condition), args...)\n}\n\n// FilteredLink retrieves and returns filtered `linkInfo` that can be using for\n// logging or tracing purpose.\nfunc (c *Core) FilteredLink() string {\n\treturn fmt.Sprintf(\n\t\t`%s@%s(%s:%s)/%s`,\n\t\tc.config.User, c.config.Protocol, c.config.Host, c.config.Port, c.config.Name,\n\t)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// It just returns the pointer address.\n//\n// Note that this interface implements mainly for workaround for a json infinite loop bug\n// of Golang version < v1.14.\nfunc (c *Core) MarshalJSON() ([]byte, error) {\n\treturn []byte(fmt.Sprintf(`%+v`, c)), nil\n}\n\n// writeSqlToLogger outputs the Sql object to logger.\n// It is enabled only if configuration \"debug\" is true.\nfunc (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {\n\tvar transactionIdStr string\n\tif sql.IsTransaction {\n\t\tif v := ctx.Value(transactionIdForLoggerCtx); v != nil {\n\t\t\ttransactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64))\n\t\t}\n\t}\n\ts := fmt.Sprintf(\n\t\t\"[%3d ms] [%s] [%s] [rows:%-3d] %s%s\",\n\t\tsql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format,\n\t)\n\tif sql.Error != nil {\n\t\ts += \"\\nError: \" + sql.Error.Error()\n\t\tc.logger.Error(ctx, s)\n\t} else {\n\t\tc.logger.Debug(ctx, s)\n\t}\n}\n\n// HasTable determine whether the table name exists in the database.\nfunc (c *Core) HasTable(name string) (bool, error) {\n\ttables, err := c.GetTablesWithCache()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tcharL, charR := c.db.GetChars()\n\tname = gstr.Trim(name, charL+charR)\n\tfor _, table := range tables {\n\t\tif table == name {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// GetInnerMemCache retrieves and returns the inner memory cache object.\nfunc (c *Core) GetInnerMemCache() *gcache.Cache {\n\treturn c.innerMemCache\n}\n\nfunc (c *Core) SetTableFields(ctx context.Context, table string, fields map[string]*TableField, schema ...string) error {\n\tif table == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"table name cannot be empty\")\n\t}\n\tcharL, charR := c.db.GetChars()\n\ttable = gstr.Trim(table, charL+charR)\n\tif gstr.Contains(table, \" \") {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"function TableFields supports only single table operations\",\n\t\t)\n\t}\n\tvar (\n\t\tinnerMemCache = c.GetInnerMemCache()\n\t\t// prefix:group@schema#table\n\t\tcacheKey = genTableFieldsCacheKey(\n\t\t\tc.db.GetGroup(),\n\t\t\tgutil.GetOrDefaultStr(c.db.GetSchema(), schema...),\n\t\t\ttable,\n\t\t)\n\t)\n\treturn innerMemCache.Set(ctx, cacheKey, fields, gcache.DurationNoExpire)\n}\n\n// GetTablesWithCache retrieves and returns the table names of current database with cache.\nfunc (c *Core) GetTablesWithCache() ([]string, error) {\n\tvar (\n\t\tctx           = c.db.GetCtx()\n\t\tcacheKey      = genTableNamesCacheKey(c.db.GetGroup())\n\t\tcacheDuration = gcache.DurationNoExpire\n\t\tinnerMemCache = c.GetInnerMemCache()\n\t)\n\tresult, err := innerMemCache.GetOrSetFuncLock(\n\t\tctx, cacheKey,\n\t\tfunc(ctx context.Context) (any, error) {\n\t\t\ttableList, err := c.db.Tables(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn tableList, nil\n\t\t}, cacheDuration,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result.Strings(), nil\n}\n\n// IsSoftCreatedFieldName checks and returns whether given field name is an automatic-filled created time.\nfunc (c *Core) IsSoftCreatedFieldName(fieldName string) bool {\n\tif fieldName == \"\" {\n\t\treturn false\n\t}\n\tif config := c.db.GetConfig(); config.CreatedAt != \"\" {\n\t\tif utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) {\n\t\t\treturn true\n\t\t}\n\t\treturn gstr.InArray(append([]string{config.CreatedAt}, createdFieldNames...), fieldName)\n\t}\n\tfor _, v := range createdFieldNames {\n\t\tif utils.EqualFoldWithoutChars(fieldName, v) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// FormatSqlBeforeExecuting formats the sql string and its arguments before executing.\n// The internal handleArguments function might be called twice during the SQL procedure,\n// but do not worry about it, it's safe and efficient.\nfunc (c *Core) FormatSqlBeforeExecuting(sql string, args []any) (newSql string, newArgs []any) {\n\treturn handleSliceAndStructArgsForSql(sql, args)\n}\n\n// getCounterAlter\nfunc (c *Core) getCounterAlter(counter Counter) (operator string, columnVal float64) {\n\toperator, columnVal = \"+\", counter.Value\n\tif columnVal < 0 {\n\t\toperator, columnVal = \"-\", -columnVal\n\t}\n\treturn\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Config is the configuration management object.\ntype Config map[string]ConfigGroup\n\n// ConfigGroup is a slice of configuration node for specified named group.\ntype ConfigGroup []ConfigNode\n\n// ConfigNode is configuration for one node.\ntype ConfigNode struct {\n\t// Host specifies the server address, can be either IP address or domain name\n\t// Example: \"127.0.0.1\", \"localhost\"\n\tHost string `json:\"host\"`\n\n\t// Port specifies the server port number\n\t// Default is typically \"3306\" for MySQL\n\tPort string `json:\"port\"`\n\n\t// User specifies the authentication username for database connection\n\tUser string `json:\"user\"`\n\n\t// Pass specifies the authentication password for database connection\n\tPass string `json:\"pass\"`\n\n\t// Name specifies the default database name to be used\n\tName string `json:\"name\"`\n\n\t// Type specifies the database type\n\t// Example: mysql, mariadb, sqlite, mssql, pgsql, oracle, clickhouse, dm.\n\tType string `json:\"type\"`\n\n\t// Link provides custom connection string that combines all configuration in one string\n\t// Optional field\n\tLink string `json:\"link\"`\n\n\t// Extra provides additional configuration options for third-party database drivers\n\t// Optional field\n\tExtra string `json:\"extra\"`\n\n\t// Role specifies the node role in master-slave setup\n\t// Optional field, defaults to \"master\"\n\t// Available values: \"master\", \"slave\"\n\tRole Role `json:\"role\"`\n\n\t// Debug enables debug mode for logging and output\n\t// Optional field\n\tDebug bool `json:\"debug\"`\n\n\t// Prefix specifies the table name prefix\n\t// Optional field\n\tPrefix string `json:\"prefix\"`\n\n\t// DryRun enables simulation mode where SELECT statements are executed\n\t// but INSERT/UPDATE/DELETE statements are not\n\t// Optional field\n\tDryRun bool `json:\"dryRun\"`\n\n\t// Weight specifies the node weight for load balancing calculations\n\t// Optional field, only effective in multi-node setups\n\tWeight int `json:\"weight\"`\n\n\t// Charset specifies the character set for database operations\n\t// Optional field, defaults to \"utf8\"\n\tCharset string `json:\"charset\"`\n\n\t// Protocol specifies the network protocol for database connection\n\t// Optional field, defaults to \"tcp\"\n\t// See net.Dial for available network protocols\n\tProtocol string `json:\"protocol\"`\n\n\t// Timezone sets the time zone for timestamp interpretation and display\n\t// Optional field\n\tTimezone string `json:\"timezone\"`\n\n\t// Namespace specifies the schema namespace for certain databases\n\t// Optional field, e.g., in PostgreSQL, Name is the catalog and Namespace is the schema\n\tNamespace string `json:\"namespace\"`\n\n\t// MaxIdleConnCount specifies the maximum number of idle connections in the pool\n\t// Optional field\n\tMaxIdleConnCount int `json:\"maxIdle\"`\n\n\t// MaxOpenConnCount specifies the maximum number of open connections in the pool\n\t// Optional field\n\tMaxOpenConnCount int `json:\"maxOpen\"`\n\n\t// MaxConnLifeTime specifies the maximum lifetime of a connection\n\t// Optional field\n\tMaxConnLifeTime time.Duration `json:\"maxLifeTime\"`\n\n\t// MaxIdleConnTime specifies the maximum idle time of a connection before being closed\n\t// This is Go 1.15+ feature: sql.DB.SetConnMaxIdleTime\n\t// Optional field\n\tMaxIdleConnTime time.Duration `json:\"maxIdleTime\"`\n\n\t// QueryTimeout specifies the maximum execution time for DQL operations\n\t// Optional field\n\tQueryTimeout time.Duration `json:\"queryTimeout\"`\n\n\t// ExecTimeout specifies the maximum execution time for DML operations\n\t// Optional field\n\tExecTimeout time.Duration `json:\"execTimeout\"`\n\n\t// TranTimeout specifies the maximum execution time for a transaction block\n\t// Optional field\n\tTranTimeout time.Duration `json:\"tranTimeout\"`\n\n\t// PrepareTimeout specifies the maximum execution time for prepare operations\n\t// Optional field\n\tPrepareTimeout time.Duration `json:\"prepareTimeout\"`\n\n\t// CreatedAt specifies the field name for automatic timestamp on record creation\n\t// Optional field\n\tCreatedAt string `json:\"createdAt\"`\n\n\t// UpdatedAt specifies the field name for automatic timestamp on record updates\n\t// Optional field\n\tUpdatedAt string `json:\"updatedAt\"`\n\n\t// DeletedAt specifies the field name for automatic timestamp on record deletion\n\t// Optional field\n\tDeletedAt string `json:\"deletedAt\"`\n\n\t// TimeMaintainDisabled controls whether automatic time maintenance is disabled\n\t// Optional field\n\tTimeMaintainDisabled bool `json:\"timeMaintainDisabled\"`\n}\n\ntype Role string\n\nconst (\n\tRoleMaster Role = \"master\"\n\tRoleSlave  Role = \"slave\"\n)\n\nconst (\n\tDefaultGroupName = \"default\" // Default group name.\n)\n\n// configs specifies internal used configuration object.\nvar configs struct {\n\tsync.RWMutex\n\tconfig Config // All configurations.\n\tgroup  string // Default configuration group.\n}\n\nfunc init() {\n\tconfigs.config = make(Config)\n\tconfigs.group = DefaultGroupName\n}\n\n// SetConfig sets the global configuration for package.\n// It will overwrite the old configuration of package.\nfunc SetConfig(config Config) error {\n\tdefer instances.Clear()\n\tconfigs.Lock()\n\tdefer configs.Unlock()\n\n\tfor k, nodes := range config {\n\t\tfor i, node := range nodes {\n\t\t\tparsedNode, err := parseConfigNode(node)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tnodes[i] = parsedNode\n\t\t}\n\t\tconfig[k] = nodes\n\t}\n\tconfigs.config = config\n\treturn nil\n}\n\n// SetConfigGroup sets the configuration for given group.\nfunc SetConfigGroup(group string, nodes ConfigGroup) error {\n\tdefer instances.Clear()\n\tconfigs.Lock()\n\tdefer configs.Unlock()\n\n\tfor i, node := range nodes {\n\t\tparsedNode, err := parseConfigNode(node)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnodes[i] = parsedNode\n\t}\n\tconfigs.config[group] = nodes\n\treturn nil\n}\n\n// AddConfigNode adds one node configuration to configuration of given group.\nfunc AddConfigNode(group string, node ConfigNode) error {\n\tdefer instances.Clear()\n\tconfigs.Lock()\n\tdefer configs.Unlock()\n\n\tparsedNode, err := parseConfigNode(node)\n\tif err != nil {\n\t\treturn err\n\t}\n\tconfigs.config[group] = append(configs.config[group], parsedNode)\n\treturn nil\n}\n\n// parseConfigNode parses `Link` configuration syntax.\nfunc parseConfigNode(node ConfigNode) (ConfigNode, error) {\n\tif node.Link != \"\" {\n\t\tparsedLinkNode, err := parseConfigNodeLink(&node)\n\t\tif err != nil {\n\t\t\treturn node, err\n\t\t}\n\t\tnode = *parsedLinkNode\n\t}\n\tif node.Link != \"\" && node.Type == \"\" {\n\t\tmatch, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)\n\t\tif len(match) == 3 {\n\t\t\tnode.Type = gstr.Trim(match[1])\n\t\t\tnode.Link = gstr.Trim(match[2])\n\t\t}\n\t}\n\treturn node, nil\n}\n\n// AddDefaultConfigNode adds one node configuration to configuration of default group.\nfunc AddDefaultConfigNode(node ConfigNode) error {\n\treturn AddConfigNode(DefaultGroupName, node)\n}\n\n// AddDefaultConfigGroup adds multiple node configurations to configuration of default group.\n//\n// Deprecated: Use SetDefaultConfigGroup instead.\nfunc AddDefaultConfigGroup(nodes ConfigGroup) error {\n\treturn SetConfigGroup(DefaultGroupName, nodes)\n}\n\n// SetDefaultConfigGroup sets multiple node configurations to configuration of default group.\nfunc SetDefaultConfigGroup(nodes ConfigGroup) error {\n\treturn SetConfigGroup(DefaultGroupName, nodes)\n}\n\n// GetConfig retrieves and returns the configuration of given group.\n//\n// Deprecated: Use GetConfigGroup instead.\nfunc GetConfig(group string) ConfigGroup {\n\tconfigGroup, _ := GetConfigGroup(group)\n\treturn configGroup\n}\n\n// GetConfigGroup retrieves and returns the configuration of given group.\n// It returns an error if the group does not exist, or an empty slice if the group exists but has no nodes.\nfunc GetConfigGroup(group string) (ConfigGroup, error) {\n\tconfigs.RLock()\n\tdefer configs.RUnlock()\n\n\tconfigGroup, exists := configs.config[group]\n\tif !exists {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`configuration group \"%s\" not found`,\n\t\t\tgroup,\n\t\t)\n\t}\n\treturn configGroup, nil\n}\n\n// GetAllConfig retrieves and returns all configurations.\nfunc GetAllConfig() Config {\n\tconfigs.RLock()\n\tdefer configs.RUnlock()\n\treturn configs.config\n}\n\n// SetDefaultGroup sets the group name for default configuration.\nfunc SetDefaultGroup(name string) {\n\tdefer instances.Clear()\n\tconfigs.Lock()\n\tdefer configs.Unlock()\n\tconfigs.group = name\n}\n\n// GetDefaultGroup returns the { name of default configuration.\nfunc GetDefaultGroup() string {\n\tdefer instances.Clear()\n\tconfigs.RLock()\n\tdefer configs.RUnlock()\n\treturn configs.group\n}\n\n// IsConfigured checks and returns whether the database configured.\n// It returns true if any configuration exists.\nfunc IsConfigured() bool {\n\tconfigs.RLock()\n\tdefer configs.RUnlock()\n\treturn len(configs.config) > 0\n}\n\n// SetLogger sets the logger for orm.\nfunc (c *Core) SetLogger(logger glog.ILogger) {\n\tc.logger = logger\n}\n\n// GetLogger returns the (logger) of the orm.\nfunc (c *Core) GetLogger() glog.ILogger {\n\treturn c.logger\n}\n\n// SetMaxIdleConnCount sets the maximum number of connections in the idle\n// connection pool.\n//\n// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,\n// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.\n//\n// If n <= 0, no idle connections are retained.\n//\n// The default max idle connections is currently 2. This may change in\n// a future release.\nfunc (c *Core) SetMaxIdleConnCount(n int) {\n\tc.dynamicConfig.MaxIdleConnCount = n\n}\n\n// SetMaxOpenConnCount sets the maximum number of open connections to the database.\n//\n// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than\n// MaxIdleConns, then MaxIdleConns will be reduced to match the new\n// MaxOpenConns limit.\n//\n// If n <= 0, then there is no limit on the number of open connections.\n// The default is 0 (unlimited).\nfunc (c *Core) SetMaxOpenConnCount(n int) {\n\tc.dynamicConfig.MaxOpenConnCount = n\n}\n\n// SetMaxConnLifeTime sets the maximum amount of time a connection may be reused.\n//\n// Expired connections may be closed lazily before reuse.\n//\n// If d <= 0, connections are not closed due to a connection's age.\nfunc (c *Core) SetMaxConnLifeTime(d time.Duration) {\n\tc.dynamicConfig.MaxConnLifeTime = d\n}\n\n// SetMaxIdleConnTime sets the maximum amount of time a connection may be idle before being closed.\n//\n// Idle connections may be closed lazily before reuse.\n//\n// If d <= 0, connections are not closed due to a connection's idle time.\n// This is Go 1.15+ feature: sql.DB.SetConnMaxIdleTime.\nfunc (c *Core) SetMaxIdleConnTime(d time.Duration) {\n\tc.dynamicConfig.MaxIdleConnTime = d\n}\n\n// GetConfig returns the current used node configuration.\nfunc (c *Core) GetConfig() *ConfigNode {\n\tvar configNode = c.getConfigNodeFromCtx(c.db.GetCtx())\n\tif configNode != nil {\n\t\t// Note:\n\t\t// It so here checks and returns the config from current DB,\n\t\t// if different schemas between current DB and config.Name from context,\n\t\t// for example, in nested transaction scenario, the context is passed all through the logic procedure,\n\t\t// but the config.Name from context may be still the original one from the first transaction object.\n\t\tif c.config.Name == configNode.Name {\n\t\t\treturn configNode\n\t\t}\n\t}\n\treturn c.config\n}\n\n// SetDebug enables/disables the debug mode.\nfunc (c *Core) SetDebug(debug bool) {\n\tc.debug.Set(debug)\n}\n\n// GetDebug returns the debug value.\nfunc (c *Core) GetDebug() bool {\n\treturn c.debug.Val()\n}\n\n// GetCache returns the internal cache object.\nfunc (c *Core) GetCache() *gcache.Cache {\n\treturn c.cache\n}\n\n// GetGroup returns the group string configured.\nfunc (c *Core) GetGroup() string {\n\treturn c.group\n}\n\n// SetDryRun enables/disables the DryRun feature.\nfunc (c *Core) SetDryRun(enabled bool) {\n\tc.config.DryRun = enabled\n}\n\n// GetDryRun returns the DryRun value.\nfunc (c *Core) GetDryRun() bool {\n\treturn c.config.DryRun || allDryRun\n}\n\n// GetPrefix returns the table prefix string configured.\nfunc (c *Core) GetPrefix() string {\n\treturn c.config.Prefix\n}\n\n// GetSchema returns the schema configured.\nfunc (c *Core) GetSchema() string {\n\tschema := c.schema\n\tif schema == \"\" {\n\t\tschema = c.db.GetConfig().Name\n\t}\n\treturn schema\n}\n\nfunc parseConfigNodeLink(node *ConfigNode) (*ConfigNode, error) {\n\tvar (\n\t\tlink  = node.Link\n\t\tmatch []string\n\t)\n\tif link != \"\" {\n\t\t// To be compatible with old configuration,\n\t\t// it checks and converts the link to new configuration.\n\t\tif node.Type != \"\" && !gstr.HasPrefix(link, node.Type+\":\") {\n\t\t\tlink = fmt.Sprintf(\"%s:%s\", node.Type, link)\n\t\t}\n\t\tmatch, _ = gregex.MatchString(linkPattern, link)\n\t\tif len(match) <= 5 {\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid link configuration: %s, shuold be pattern like: %s`,\n\t\t\t\tlink, linkPatternDescription,\n\t\t\t)\n\t\t}\n\t\tnode.Type = match[1]\n\t\tnode.User = match[2]\n\t\tnode.Pass = match[3]\n\t\tnode.Protocol = match[4]\n\t\tarray := gstr.Split(match[5], \":\")\n\t\tif node.Protocol == \"file\" {\n\t\t\tnode.Name = match[5]\n\t\t} else {\n\t\t\tif len(array) == 2 {\n\t\t\t\t// link with port.\n\t\t\t\tnode.Host = array[0]\n\t\t\t\tnode.Port = array[1]\n\t\t\t} else {\n\t\t\t\t// link without port.\n\t\t\t\tnode.Host = array[0]\n\t\t\t}\n\t\t\tnode.Name = match[6]\n\t\t}\n\t\tif len(match) > 6 && match[7] != \"\" {\n\t\t\tnode.Extra = match[7]\n\t\t}\n\t}\n\tif node.Extra != \"\" {\n\t\tif m, _ := gstr.Parse(node.Extra); len(m) > 0 {\n\t\t\t_ = gconv.Struct(m, &node)\n\t\t}\n\t}\n\t// Default value checks.\n\tif node.Charset == \"\" {\n\t\tnode.Charset = defaultCharset\n\t}\n\tif node.Protocol == \"\" {\n\t\tnode.Protocol = defaultProtocol\n\t}\n\treturn node, nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// internalCtxData stores data in ctx for internal usage purpose.\ntype internalCtxData struct {\n\tsync.Mutex\n\t// Used configuration node in current operation.\n\tConfigNode *ConfigNode\n}\n\n// column stores column data in ctx for internal usage purpose.\ntype internalColumnData struct {\n\t// The first column in result response from database server.\n\t// This attribute is used for Value/Count selection statement purpose,\n\t// which is to avoid HOOK handler that might modify the result columns\n\t// that can confuse the Value/Count selection statement logic.\n\tFirstResultColumn string\n}\n\nconst (\n\tinternalCtxDataKeyInCtx    gctx.StrKey = \"InternalCtxData\"\n\tinternalColumnDataKeyInCtx gctx.StrKey = \"InternalColumnData\"\n\n\t// `ignoreResultKeyInCtx` is a mark for some db drivers that do not support `RowsAffected` function,\n\t// for example: `clickhouse`. The `clickhouse` does not support fetching insert/update results,\n\t// but returns errors when execute `RowsAffected`. It here ignores the calling of `RowsAffected`\n\t// to avoid triggering errors, rather than ignoring errors after they are triggered.\n\tignoreResultKeyInCtx gctx.StrKey = \"IgnoreResult\"\n)\n\nfunc (c *Core) injectInternalCtxData(ctx context.Context) context.Context {\n\t// If the internal data is already injected, it does nothing.\n\tif ctx.Value(internalCtxDataKeyInCtx) != nil {\n\t\treturn ctx\n\t}\n\treturn context.WithValue(ctx, internalCtxDataKeyInCtx, &internalCtxData{\n\t\tConfigNode: c.config,\n\t})\n}\n\nfunc (c *Core) setConfigNodeToCtx(ctx context.Context, node *ConfigNode) error {\n\tvalue := ctx.Value(internalCtxDataKeyInCtx)\n\tif value == nil {\n\t\treturn gerror.NewCode(gcode.CodeInternalError, `no internal data found in context`)\n\t}\n\n\tdata := value.(*internalCtxData)\n\tdata.Lock()\n\tdefer data.Unlock()\n\tdata.ConfigNode = node\n\treturn nil\n}\n\nfunc (c *Core) getConfigNodeFromCtx(ctx context.Context) *ConfigNode {\n\tif value := ctx.Value(internalCtxDataKeyInCtx); value != nil {\n\t\tdata := value.(*internalCtxData)\n\t\tdata.Lock()\n\t\tdefer data.Unlock()\n\t\treturn data.ConfigNode\n\t}\n\treturn nil\n}\n\nfunc (c *Core) injectInternalColumn(ctx context.Context) context.Context {\n\treturn context.WithValue(ctx, internalColumnDataKeyInCtx, &internalColumnData{})\n}\n\nfunc (c *Core) getInternalColumnFromCtx(ctx context.Context) *internalColumnData {\n\tif v := ctx.Value(internalColumnDataKeyInCtx); v != nil {\n\t\treturn v.(*internalColumnData)\n\t}\n\treturn nil\n}\n\nfunc (c *Core) InjectIgnoreResult(ctx context.Context) context.Context {\n\tif ctx.Value(ignoreResultKeyInCtx) != nil {\n\t\treturn ctx\n\t}\n\treturn context.WithValue(ctx, ignoreResultKeyInCtx, true)\n}\n\nfunc (c *Core) GetIgnoreResultFromCtx(ctx context.Context) bool {\n\treturn ctx.Value(ignoreResultKeyInCtx) != nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_link.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n)\n\n// dbLink is used to implement interface Link for DB.\ntype dbLink struct {\n\t*sql.DB         // Underlying DB object.\n\tisOnMaster bool // isOnMaster marks whether current link is operated on master node.\n}\n\n// txLink is used to implement interface Link for TX.\ntype txLink struct {\n\t*sql.Tx\n}\n\n// IsTransaction returns if current Link is a transaction.\nfunc (l *dbLink) IsTransaction() bool {\n\treturn false\n}\n\n// IsOnMaster checks and returns whether current link is operated on master node.\nfunc (l *dbLink) IsOnMaster() bool {\n\treturn l.isOnMaster\n}\n\n// IsTransaction returns if current Link is a transaction.\nfunc (l *txLink) IsTransaction() bool {\n\treturn true\n}\n\n// IsOnMaster checks and returns whether current link is operated on master node.\n// Note that, transaction operation is always operated on master node.\nfunc (l *txLink) IsOnMaster() bool {\n\treturn true\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_stats.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\ntype localStatsItem struct {\n\tnode  *ConfigNode\n\tstats sql.DBStats\n}\n\n// Node returns the configuration node info.\nfunc (item *localStatsItem) Node() ConfigNode {\n\treturn *item.node\n}\n\n// Stats returns the connection stat for current node.\nfunc (item *localStatsItem) Stats() sql.DBStats {\n\treturn item.stats\n}\n\n// Stats retrieves and returns the pool stat for all nodes that have been established.\nfunc (c *Core) Stats(ctx context.Context) []StatsItem {\n\tvar items = make([]StatsItem, 0)\n\tc.links.Iterator(func(k ConfigNode, v *sql.DB) bool {\n\t\t// Create a local copy of k to avoid loop variable address re-use issue\n\t\t// In Go, loop variables are re-used with the same memory address across iterations,\n\t\t// directly using &k would cause all localStatsItem instances to share the same address\n\t\tnode := k\n\t\titems = append(items, &localStatsItem{\n\t\t\tnode:  &node,\n\t\t\tstats: v.Stats(),\n\t\t})\n\t\treturn true\n\t})\n\treturn items\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_structure.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql/driver\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// GetFieldTypeStr retrieves and returns the field type string for certain field by name.\nfunc (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string {\n\tfield := c.GetFieldType(ctx, fieldName, table, schema)\n\tif field != nil {\n\t\t// Kinds of data type examples:\n\t\t// year(4)\n\t\t// datetime\n\t\t// varchar(64)\n\t\t// bigint(20)\n\t\t// int(10) unsigned\n\t\ttypeName := gstr.StrTillEx(field.Type, \"(\") // int(10) unsigned -> int\n\t\tif typeName != \"\" {\n\t\t\ttypeName = gstr.Trim(typeName)\n\t\t} else {\n\t\t\ttypeName = field.Type\n\t\t}\n\t\treturn typeName\n\t}\n\treturn \"\"\n}\n\n// GetFieldType retrieves and returns the field type object for certain field by name.\nfunc (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField {\n\tfieldsMap, err := c.db.TableFields(ctx, table, schema)\n\tif err != nil {\n\t\tintlog.Errorf(\n\t\t\tctx,\n\t\t\t`TableFields failed for table \"%s\", schema \"%s\": %+v`,\n\t\t\ttable, schema, err,\n\t\t)\n\t\treturn nil\n\t}\n\tfor tableFieldName, tableField := range fieldsMap {\n\t\tif tableFieldName == fieldName {\n\t\t\treturn tableField\n\t\t}\n\t}\n\treturn nil\n}\n\n// ConvertDataForRecord is a very important function, which does converting for any data that\n// will be inserted into table/collection as a record.\n//\n// The parameter `value` should be type of *map/map/*struct/struct.\n// It supports embedded struct definition for struct.\nfunc (c *Core) ConvertDataForRecord(ctx context.Context, value any, table string) (map[string]any, error) {\n\tvar (\n\t\terr  error\n\t\tdata = MapOrStructToMapDeep(value, true)\n\t)\n\tfor fieldName, fieldValue := range data {\n\t\tvar fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema())\n\t\tdata[fieldName], err = c.db.ConvertValueForField(\n\t\t\tctx,\n\t\t\tfieldType,\n\t\t\tfieldValue,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue)\n\t\t}\n\t}\n\treturn data, nil\n}\n\n// ConvertValueForField converts value to the type of the record field.\n// The parameter `fieldType` is the target record field.\n// The parameter `fieldValue` is the value that to be committed to record field.\nfunc (c *Core) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {\n\tvar (\n\t\terr            error\n\t\tconvertedValue = fieldValue\n\t)\n\tswitch fieldValue.(type) {\n\tcase time.Time, *time.Time, gtime.Time, *gtime.Time:\n\t\tgoto Default\n\t}\n\t// If `value` implements interface `driver.Valuer`, it then uses the interface for value converting.\n\tif valuer, ok := fieldValue.(driver.Valuer); ok {\n\t\tif convertedValue, err = valuer.Value(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn convertedValue, nil\n\t}\nDefault:\n\t// Default value converting.\n\tvar (\n\t\trvValue = reflect.ValueOf(fieldValue)\n\t\trvKind  = rvValue.Kind()\n\t)\n\tfor rvKind == reflect.Pointer {\n\t\trvValue = rvValue.Elem()\n\t\trvKind = rvValue.Kind()\n\t}\n\tswitch rvKind {\n\tcase reflect.Invalid:\n\t\tconvertedValue = nil\n\n\tcase reflect.Slice, reflect.Array, reflect.Map:\n\t\t// It should ignore the bytes type.\n\t\tif _, ok := fieldValue.([]byte); !ok {\n\t\t\t// Convert the value to JSON.\n\t\t\tconvertedValue, err = json.Marshal(fieldValue)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\tcase reflect.Struct:\n\t\tswitch r := fieldValue.(type) {\n\t\t// If the time is zero, it then updates it to nil,\n\t\t// which will insert/update the value to database as \"null\".\n\t\tcase time.Time:\n\t\t\tif r.IsZero() {\n\t\t\t\tconvertedValue = nil\n\t\t\t} else {\n\t\t\t\tswitch fieldType {\n\t\t\t\tcase fieldTypeYear:\n\t\t\t\t\tconvertedValue = r.Format(\"2006\")\n\t\t\t\tcase fieldTypeDate:\n\t\t\t\t\tconvertedValue = r.Format(\"2006-01-02\")\n\t\t\t\tcase fieldTypeTime:\n\t\t\t\t\tconvertedValue = r.Format(\"15:04:05\")\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *time.Time:\n\t\t\tif r == nil {\n\t\t\t\t// Nothing to do.\n\t\t\t} else {\n\t\t\t\tswitch fieldType {\n\t\t\t\tcase fieldTypeYear:\n\t\t\t\t\tconvertedValue = r.Format(\"2006\")\n\t\t\t\tcase fieldTypeDate:\n\t\t\t\t\tconvertedValue = r.Format(\"2006-01-02\")\n\t\t\t\tcase fieldTypeTime:\n\t\t\t\t\tconvertedValue = r.Format(\"15:04:05\")\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase gtime.Time:\n\t\t\tif r.IsZero() {\n\t\t\t\tconvertedValue = nil\n\t\t\t} else {\n\t\t\t\tswitch fieldType {\n\t\t\t\tcase fieldTypeYear:\n\t\t\t\t\tconvertedValue = r.Layout(\"2006\")\n\t\t\t\tcase fieldTypeDate:\n\t\t\t\t\tconvertedValue = r.Layout(\"2006-01-02\")\n\t\t\t\tcase fieldTypeTime:\n\t\t\t\t\tconvertedValue = r.Layout(\"15:04:05\")\n\t\t\t\tdefault:\n\t\t\t\t\tconvertedValue = r.Time\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *gtime.Time:\n\t\t\tif r.IsZero() {\n\t\t\t\tconvertedValue = nil\n\t\t\t} else {\n\t\t\t\tswitch fieldType {\n\t\t\t\tcase fieldTypeYear:\n\t\t\t\t\tconvertedValue = r.Layout(\"2006\")\n\t\t\t\tcase fieldTypeDate:\n\t\t\t\t\tconvertedValue = r.Layout(\"2006-01-02\")\n\t\t\t\tcase fieldTypeTime:\n\t\t\t\t\tconvertedValue = r.Layout(\"15:04:05\")\n\t\t\t\tdefault:\n\t\t\t\t\tconvertedValue = r.Time\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase Counter, *Counter:\n\t\t\t// Nothing to do.\n\n\t\tdefault:\n\t\t\t// If `value` implements interface iNil,\n\t\t\t// check its IsNil() function, if got ture,\n\t\t\t// which will insert/update the value to database as \"null\".\n\t\t\tif v, ok := fieldValue.(iNil); ok && v.IsNil() {\n\t\t\t\tconvertedValue = nil\n\t\t\t} else if s, ok := fieldValue.(iString); ok {\n\t\t\t\t// Use string conversion in default.\n\t\t\t\tconvertedValue = s.String()\n\t\t\t} else {\n\t\t\t\t// Convert the value to JSON.\n\t\t\t\tconvertedValue, err = json.Marshal(fieldValue)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tdefault:\n\t}\n\n\treturn convertedValue, nil\n}\n\n// GetFormattedDBTypeNameForField retrieves and returns the formatted database type name\n// eg. `int(10) unsigned` -> `int`, `varchar(100)` -> `varchar`, etc.\nfunc (c *Core) GetFormattedDBTypeNameForField(fieldType string) (typeName, typePattern string) {\n\tmatch, _ := gregex.MatchString(`(.+?)\\((.+)\\)`, fieldType)\n\tif len(match) == 3 {\n\t\ttypeName = gstr.Trim(match[1])\n\t\ttypePattern = gstr.Trim(match[2])\n\t} else {\n\t\tvar array = gstr.SplitAndTrim(fieldType, \" \")\n\t\tif len(array) > 1 && gstr.Equal(array[0], \"unsigned\") {\n\t\t\ttypeName = array[1]\n\t\t} else if len(array) > 0 {\n\t\t\ttypeName = array[0]\n\t\t}\n\t}\n\ttypeName = strings.ToLower(typeName)\n\treturn\n}\n\n// CheckLocalTypeForField checks and returns corresponding type for given db type.\n// The `fieldType` is retrieved from ColumnTypes of db driver, example:\n// UNSIGNED INT\nfunc (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ any) (LocalType, error) {\n\tvar (\n\t\ttypeName    string\n\t\ttypePattern string\n\t)\n\ttypeName, typePattern = c.GetFormattedDBTypeNameForField(fieldType)\n\tswitch typeName {\n\tcase\n\t\tfieldTypeBinary,\n\t\tfieldTypeVarbinary,\n\t\tfieldTypeBlob,\n\t\tfieldTypeTinyblob,\n\t\tfieldTypeMediumblob,\n\t\tfieldTypeLongblob:\n\t\treturn LocalTypeBytes, nil\n\n\tcase\n\t\tfieldTypeInt,\n\t\tfieldTypeTinyint,\n\t\tfieldTypeSmallInt,\n\t\tfieldTypeSmallint,\n\t\tfieldTypeMediumInt,\n\t\tfieldTypeMediumint,\n\t\tfieldTypeSerial:\n\t\tif gstr.ContainsI(fieldType, \"unsigned\") {\n\t\t\treturn LocalTypeUint, nil\n\t\t}\n\t\treturn LocalTypeInt, nil\n\n\tcase\n\t\tfieldTypeBigInt,\n\t\tfieldTypeBigint,\n\t\tfieldTypeBigserial:\n\t\tif gstr.ContainsI(fieldType, \"unsigned\") {\n\t\t\treturn LocalTypeUint64, nil\n\t\t}\n\t\treturn LocalTypeInt64, nil\n\n\tcase\n\t\tfieldTypeInt128,\n\t\tfieldTypeInt256,\n\t\tfieldTypeUint128,\n\t\tfieldTypeUint256:\n\t\treturn LocalTypeBigInt, nil\n\n\tcase\n\t\tfieldTypeReal:\n\t\treturn LocalTypeFloat32, nil\n\n\tcase\n\t\tfieldTypeDecimal,\n\t\tfieldTypeMoney,\n\t\tfieldTypeNumeric,\n\t\tfieldTypeSmallmoney:\n\t\treturn LocalTypeString, nil\n\tcase\n\t\tfieldTypeFloat,\n\t\tfieldTypeDouble:\n\t\treturn LocalTypeFloat64, nil\n\n\tcase\n\t\tfieldTypeBit:\n\t\t// It is suggested using bit(1) as boolean.\n\t\tif typePattern == \"1\" {\n\t\t\treturn LocalTypeBool, nil\n\t\t}\n\t\tif gstr.ContainsI(fieldType, \"unsigned\") {\n\t\t\treturn LocalTypeUint64Bytes, nil\n\t\t}\n\t\treturn LocalTypeInt64Bytes, nil\n\n\tcase\n\t\tfieldTypeBool:\n\t\treturn LocalTypeBool, nil\n\n\tcase\n\t\tfieldTypeDate:\n\t\treturn LocalTypeDate, nil\n\n\tcase\n\t\tfieldTypeTime:\n\t\treturn LocalTypeTime, nil\n\n\tcase\n\t\tfieldTypeDatetime,\n\t\tfieldTypeTimestamp,\n\t\tfieldTypeTimestampz:\n\t\treturn LocalTypeDatetime, nil\n\n\tcase\n\t\tfieldTypeJson:\n\t\treturn LocalTypeJson, nil\n\n\tcase\n\t\tfieldTypeJsonb:\n\t\treturn LocalTypeJsonb, nil\n\n\tdefault:\n\t\t// Auto-detect field type, using key match.\n\t\tswitch {\n\t\tcase strings.Contains(typeName, \"text\") || strings.Contains(typeName, \"char\") || strings.Contains(typeName, \"character\"):\n\t\t\treturn LocalTypeString, nil\n\n\t\tcase strings.Contains(typeName, \"float\") || strings.Contains(typeName, \"double\") || strings.Contains(typeName, \"numeric\"):\n\t\t\treturn LocalTypeFloat64, nil\n\n\t\tcase strings.Contains(typeName, \"bool\"):\n\t\t\treturn LocalTypeBool, nil\n\n\t\tcase strings.Contains(typeName, \"binary\") || strings.Contains(typeName, \"blob\"):\n\t\t\treturn LocalTypeBytes, nil\n\n\t\tcase strings.Contains(typeName, \"int\"):\n\t\t\tif gstr.ContainsI(fieldType, \"unsigned\") {\n\t\t\t\treturn LocalTypeUint, nil\n\t\t\t}\n\t\t\treturn LocalTypeInt, nil\n\n\t\tcase strings.Contains(typeName, \"time\"):\n\t\t\treturn LocalTypeDatetime, nil\n\n\t\tcase strings.Contains(typeName, \"date\"):\n\t\t\treturn LocalTypeDatetime, nil\n\n\t\tdefault:\n\t\t\treturn LocalTypeString, nil\n\t\t}\n\t}\n}\n\n// ConvertValueForLocal converts value to local Golang type of value according field type name from database.\n// The parameter `fieldType` is in lower case, like:\n// `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc.\nfunc (c *Core) ConvertValueForLocal(\n\tctx context.Context, fieldType string, fieldValue any,\n) (any, error) {\n\t// If there's no type retrieved, it returns the `fieldValue` directly\n\t// to use its original data type, as `fieldValue` is type of any.\n\tif fieldType == \"\" {\n\t\treturn fieldValue, nil\n\t}\n\ttypeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch typeName {\n\tcase LocalTypeBytes:\n\t\tvar typeNameStr = string(typeName)\n\t\tif strings.Contains(typeNameStr, \"binary\") || strings.Contains(typeNameStr, \"blob\") {\n\t\t\treturn fieldValue, nil\n\t\t}\n\t\treturn gconv.Bytes(fieldValue), nil\n\n\tcase LocalTypeInt:\n\t\treturn gconv.Int(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeUint:\n\t\treturn gconv.Uint(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeInt64:\n\t\treturn gconv.Int64(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeUint64:\n\t\treturn gconv.Uint64(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeInt64Bytes:\n\t\treturn gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil\n\n\tcase LocalTypeUint64Bytes:\n\t\treturn gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil\n\n\tcase LocalTypeBigInt:\n\t\tswitch v := fieldValue.(type) {\n\t\tcase big.Int:\n\t\t\treturn v.String(), nil\n\t\tcase *big.Int:\n\t\t\treturn v.String(), nil\n\t\tdefault:\n\t\t\treturn gconv.String(fieldValue), nil\n\t\t}\n\n\tcase LocalTypeFloat32:\n\t\treturn gconv.Float32(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeFloat64:\n\t\treturn gconv.Float64(gconv.String(fieldValue)), nil\n\n\tcase LocalTypeBool:\n\t\ts := gconv.String(fieldValue)\n\t\t// mssql is true|false string.\n\t\tif strings.EqualFold(s, \"true\") {\n\t\t\treturn 1, nil\n\t\t}\n\t\tif strings.EqualFold(s, \"false\") {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturn gconv.Bool(fieldValue), nil\n\n\tcase LocalTypeDate:\n\t\tif t, ok := fieldValue.(time.Time); ok {\n\t\t\treturn gtime.NewFromTime(t).Format(\"Y-m-d\"), nil\n\t\t}\n\t\tt, _ := gtime.StrToTime(gconv.String(fieldValue))\n\t\treturn t.Format(\"Y-m-d\"), nil\n\n\tcase LocalTypeTime:\n\t\tif t, ok := fieldValue.(time.Time); ok {\n\t\t\treturn gtime.NewFromTime(t).Format(\"H:i:s\"), nil\n\t\t}\n\t\tt, _ := gtime.StrToTime(gconv.String(fieldValue))\n\t\treturn t.Format(\"H:i:s\"), nil\n\n\tcase LocalTypeDatetime:\n\t\tif t, ok := fieldValue.(time.Time); ok {\n\t\t\treturn gtime.NewFromTime(t), nil\n\t\t}\n\t\tt, _ := gtime.StrToTime(gconv.String(fieldValue))\n\t\treturn t, nil\n\n\tdefault:\n\t\treturn gconv.String(fieldValue), nil\n\t}\n}\n\n// mappingAndFilterData automatically mappings the map key to table field and removes\n// all key-value pairs that are not the field of given table.\nfunc (c *Core) mappingAndFilterData(ctx context.Context, schema, table string, data map[string]any, filter bool) (map[string]any, error) {\n\tfieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(fieldsMap) == 0 {\n\t\treturn nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table)\n\t}\n\tfieldsKeyMap := make(map[string]any, len(fieldsMap))\n\tfor k := range fieldsMap {\n\t\tfieldsKeyMap[k] = nil\n\t}\n\t// Automatic data key to table field name mapping.\n\tvar foundKey string\n\tfor dataKey, dataValue := range data {\n\t\tif _, ok := fieldsKeyMap[dataKey]; !ok {\n\t\t\tfoundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)\n\t\t\tif foundKey != \"\" {\n\t\t\t\tif _, ok = data[foundKey]; !ok {\n\t\t\t\t\tdata[foundKey] = dataValue\n\t\t\t\t}\n\t\t\t\tdelete(data, dataKey)\n\t\t\t}\n\t\t}\n\t}\n\t// Data filtering.\n\t// It deletes all key-value pairs that has incorrect field name.\n\tif filter {\n\t\tfor dataKey := range data {\n\t\t\tif _, ok := fieldsMap[dataKey]; !ok {\n\t\t\t\tdelete(data, dataKey)\n\t\t\t}\n\t\t}\n\t\tif len(data) == 0 {\n\t\t\treturn nil, gerror.Newf(`input data match no fields in table %s`, table)\n\t\t}\n\t}\n\treturn data, nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_trace.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.18.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n)\n\nconst (\n\ttraceInstrumentName       = \"github.com/gogf/gf/v2/database/gdb\"\n\ttraceAttrDbType           = \"db.type\"\n\ttraceAttrDbHost           = \"db.host\"\n\ttraceAttrDbPort           = \"db.port\"\n\ttraceAttrDbName           = \"db.name\"\n\ttraceAttrDbUser           = \"db.user\"\n\ttraceAttrDbLink           = \"db.link\"\n\ttraceAttrDbGroup          = \"db.group\"\n\ttraceEventDbExecution     = \"db.execution\"\n\ttraceEventDbExecutionCost = \"db.execution.cost\"\n\ttraceEventDbExecutionRows = \"db.execution.rows\"\n\ttraceEventDbExecutionTxID = \"db.execution.txid\"\n\ttraceEventDbExecutionType = \"db.execution.type\"\n)\n\n// addSqlToTracing adds sql information to tracer if it's enabled.\nfunc (c *Core) traceSpanEnd(ctx context.Context, span trace.Span, sql *Sql) {\n\tif gtrace.IsUsingDefaultProvider() || !gtrace.IsTracingInternal() {\n\t\treturn\n\t}\n\tif sql.Error != nil {\n\t\tspan.SetStatus(codes.Error, fmt.Sprintf(`%+v`, sql.Error))\n\t}\n\tlabels := make([]attribute.KeyValue, 0)\n\tlabels = append(labels, gtrace.CommonLabels()...)\n\tlabels = append(labels,\n\t\tattribute.String(traceAttrDbType, c.db.GetConfig().Type),\n\t\tsemconv.DBStatement(sql.Format),\n\t)\n\tif c.db.GetConfig().Host != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbHost, c.db.GetConfig().Host))\n\t}\n\tif c.db.GetConfig().Port != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbPort, c.db.GetConfig().Port))\n\t}\n\tif c.db.GetConfig().Name != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbName, c.db.GetConfig().Name))\n\t}\n\tif c.db.GetConfig().User != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbUser, c.db.GetConfig().User))\n\t}\n\tif filteredLink := c.db.GetCore().FilteredLink(); filteredLink != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbLink, c.db.GetCore().FilteredLink()))\n\t}\n\tif group := c.db.GetGroup(); group != \"\" {\n\t\tlabels = append(labels, attribute.String(traceAttrDbGroup, group))\n\t}\n\tspan.SetAttributes(labels...)\n\tevents := []attribute.KeyValue{\n\t\tattribute.String(traceEventDbExecutionCost, fmt.Sprintf(`%d ms`, sql.End-sql.Start)),\n\t\tattribute.String(traceEventDbExecutionRows, fmt.Sprintf(`%d`, sql.RowsAffected)),\n\t}\n\tif sql.IsTransaction {\n\t\tif v := ctx.Value(transactionIdForLoggerCtx); v != nil {\n\t\t\tevents = append(events, attribute.String(\n\t\t\t\ttraceEventDbExecutionTxID, fmt.Sprintf(`%d`, v.(uint64)),\n\t\t\t))\n\t\t}\n\t}\n\tevents = append(events, attribute.String(traceEventDbExecutionType, string(sql.Type)))\n\tspan.AddEvent(traceEventDbExecution, trace.WithAttributes(events...))\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_transaction.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Propagation defines transaction propagation behavior.\ntype Propagation string\n\nconst (\n\t// PropagationNested starts a nested transaction if already in a transaction,\n\t// or behaves like PropagationRequired if not in a transaction.\n\t//\n\t// It is the default behavior.\n\tPropagationNested Propagation = \"NESTED\"\n\n\t// PropagationRequired starts a new transaction if not in a transaction,\n\t// or uses the existing transaction if already in a transaction.\n\tPropagationRequired Propagation = \"REQUIRED\"\n\n\t// PropagationSupports executes within the existing transaction if present,\n\t// otherwise executes without transaction.\n\tPropagationSupports Propagation = \"SUPPORTS\"\n\n\t// PropagationRequiresNew starts a new transaction, and suspends the current transaction if one exists.\n\tPropagationRequiresNew Propagation = \"REQUIRES_NEW\"\n\n\t// PropagationNotSupported executes non-transactional, suspends any existing transaction.\n\tPropagationNotSupported Propagation = \"NOT_SUPPORTED\"\n\n\t// PropagationMandatory executes in a transaction, fails if no existing transaction.\n\tPropagationMandatory Propagation = \"MANDATORY\"\n\n\t// PropagationNever executes non-transactional, fails if in an existing transaction.\n\tPropagationNever Propagation = \"NEVER\"\n)\n\n// TxOptions defines options for transaction control.\ntype TxOptions struct {\n\t// Propagation specifies the propagation behavior.\n\tPropagation Propagation\n\t// Isolation is the transaction isolation level.\n\t// If zero, the driver or database's default level is used.\n\tIsolation sql.IsolationLevel\n\t// ReadOnly is used to mark the transaction as read-only.\n\tReadOnly bool\n}\n\n// Context key types for transaction to avoid collisions\ntype transactionCtxKey string\n\nconst (\n\ttransactionPointerPrefix                      = \"transaction\"\n\tcontextTransactionKeyPrefix                   = \"TransactionObjectForGroup_\"\n\ttransactionIdForLoggerCtx   transactionCtxKey = \"TransactionId\"\n)\n\nvar transactionIdGenerator = gtype.NewUint64()\n\n// DefaultTxOptions returns the default transaction options.\nfunc DefaultTxOptions() TxOptions {\n\treturn TxOptions{\n\t\t// Note the default propagation type is PropagationNested not PropagationRequired.\n\t\tPropagation: PropagationNested,\n\t}\n}\n\n// Begin starts and returns the transaction object.\n// You should call Commit or Rollback functions of the transaction object\n// if you no longer use the transaction. Commit or Rollback functions will also\n// close the transaction automatically.\nfunc (c *Core) Begin(ctx context.Context) (tx TX, err error) {\n\treturn c.BeginWithOptions(ctx, DefaultTxOptions())\n}\n\n// BeginWithOptions starts and returns the transaction object with given options.\n// The options allow specifying the isolation level and read-only mode.\n// You should call Commit or Rollback functions of the transaction object\n// if you no longer use the transaction. Commit or Rollback functions will also\n// close the transaction automatically.\nfunc (c *Core) BeginWithOptions(ctx context.Context, opts TxOptions) (tx TX, err error) {\n\tif ctx == nil {\n\t\tctx = c.db.GetCtx()\n\t}\n\tctx = c.injectInternalCtxData(ctx)\n\treturn c.doBeginCtx(ctx, sql.TxOptions{\n\t\tIsolation: opts.Isolation,\n\t\tReadOnly:  opts.ReadOnly,\n\t})\n}\n\nfunc (c *Core) doBeginCtx(ctx context.Context, opts sql.TxOptions) (TX, error) {\n\tmaster, err := c.db.Master()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar out DoCommitOutput\n\tout, err = c.db.DoCommit(ctx, DoCommitInput{\n\t\tDb:            master,\n\t\tSql:           \"BEGIN\",\n\t\tType:          SqlTypeBegin,\n\t\tTxOptions:     opts,\n\t\tIsTransaction: true,\n\t})\n\treturn out.Tx, err\n}\n\n// Transaction wraps the transaction logic using function `f`.\n// It rollbacks the transaction and returns the error from function `f` if\n// it returns non-nil error. It commits the transaction and returns nil if\n// function `f` returns nil.\n//\n// Note that, you should not Commit or Rollback the transaction in function `f`\n// as it is automatically handled by this function.\nfunc (c *Core) Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) {\n\treturn c.TransactionWithOptions(ctx, DefaultTxOptions(), f)\n}\n\n// TransactionWithOptions wraps the transaction logic with propagation options using function `f`.\nfunc (c *Core) TransactionWithOptions(\n\tctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error,\n) (err error) {\n\tif ctx == nil {\n\t\tctx = c.db.GetCtx()\n\t}\n\tctx = c.injectInternalCtxData(ctx)\n\n\t// Check current transaction from context\n\tvar (\n\t\tgroup     = c.db.GetGroup()\n\t\tcurrentTx = TXFromCtx(ctx, group)\n\t)\n\tswitch opts.Propagation {\n\tcase PropagationRequired:\n\t\tif currentTx != nil {\n\t\t\treturn f(ctx, currentTx)\n\t\t}\n\t\treturn c.createNewTransaction(ctx, opts, f)\n\n\tcase PropagationSupports:\n\t\tif currentTx == nil {\n\t\t\tcurrentTx = c.newEmptyTX()\n\t\t}\n\t\treturn f(ctx, currentTx)\n\n\tcase PropagationMandatory:\n\t\tif currentTx == nil {\n\t\t\treturn gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\t\"transaction propagation MANDATORY requires an existing transaction\",\n\t\t\t)\n\t\t}\n\t\treturn f(ctx, currentTx)\n\n\tcase PropagationRequiresNew:\n\t\tctx = WithoutTX(ctx, group)\n\t\treturn c.createNewTransaction(ctx, opts, f)\n\n\tcase PropagationNotSupported:\n\t\tctx = WithoutTX(ctx, group)\n\t\treturn f(ctx, c.newEmptyTX())\n\n\tcase PropagationNever:\n\t\tif currentTx != nil {\n\t\t\treturn gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\t\"transaction propagation NEVER cannot run within an existing transaction\",\n\t\t\t)\n\t\t}\n\t\tctx = WithoutTX(ctx, group)\n\t\treturn f(ctx, c.newEmptyTX())\n\n\tcase PropagationNested:\n\t\tif currentTx != nil {\n\t\t\treturn currentTx.Transaction(ctx, f)\n\t\t}\n\t\treturn c.createNewTransaction(ctx, opts, f)\n\n\tdefault:\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"unsupported propagation behavior: %s\",\n\t\t\topts.Propagation,\n\t\t)\n\t}\n}\n\n// createNewTransaction handles creating and managing a new transaction\nfunc (c *Core) createNewTransaction(\n\tctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error,\n) (err error) {\n\t// Begin transaction with options\n\ttx, err := c.doBeginCtx(ctx, sql.TxOptions{\n\t\tIsolation: opts.Isolation,\n\t\tReadOnly:  opts.ReadOnly,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Inject transaction object into context\n\tctx = WithTX(tx.GetCtx(), tx)\n\terr = callTxFunc(tx.Ctx(ctx), f)\n\treturn\n}\n\nfunc callTxFunc(tx TX, f func(ctx context.Context, tx TX) error) (err error) {\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\terr = v\n\t\t\t\t} else {\n\t\t\t\t\terr = gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\tif e := tx.Rollback(); e != nil {\n\t\t\t\terr = e\n\t\t\t}\n\t\t} else {\n\t\t\tif e := tx.Commit(); e != nil {\n\t\t\t\terr = e\n\t\t\t}\n\t\t}\n\t}()\n\terr = f(tx.GetCtx(), tx)\n\treturn\n}\n\n// WithTX injects given transaction object into context and returns a new context.\nfunc WithTX(ctx context.Context, tx TX) context.Context {\n\tif tx == nil {\n\t\treturn ctx\n\t}\n\t// Check repeat injection from given.\n\tgroup := tx.GetDB().GetGroup()\n\tif ctxTx := TXFromCtx(ctx, group); ctxTx != nil && ctxTx.GetDB().GetGroup() == group {\n\t\treturn ctx\n\t}\n\tdbCtx := tx.GetDB().GetCtx()\n\tif ctxTx := TXFromCtx(dbCtx, group); ctxTx != nil && ctxTx.GetDB().GetGroup() == group {\n\t\treturn dbCtx\n\t}\n\t// Inject transaction object and id into context.\n\tctx = context.WithValue(ctx, transactionKeyForContext(group), tx)\n\tctx = context.WithValue(ctx, transactionIdForLoggerCtx, tx.GetCtx().Value(transactionIdForLoggerCtx))\n\treturn ctx\n}\n\n// WithoutTX removed transaction object from context and returns a new context.\nfunc WithoutTX(ctx context.Context, group string) context.Context {\n\tctx = context.WithValue(ctx, transactionKeyForContext(group), nil)\n\tctx = context.WithValue(ctx, transactionIdForLoggerCtx, nil)\n\treturn ctx\n}\n\n// TXFromCtx retrieves and returns transaction object from context.\n// It is usually used in nested transaction feature, and it returns nil if it is not set previously.\nfunc TXFromCtx(ctx context.Context, group string) TX {\n\tif ctx == nil {\n\t\treturn nil\n\t}\n\tv := ctx.Value(transactionKeyForContext(group))\n\tif v != nil {\n\t\ttx := v.(TX)\n\t\tif tx.IsClosed() {\n\t\t\treturn nil\n\t\t}\n\t\t// no underlying sql tx.\n\t\tif tx.GetSqlTX() == nil {\n\t\t\treturn nil\n\t\t}\n\t\ttx = tx.Ctx(ctx)\n\t\treturn tx\n\t}\n\treturn nil\n}\n\n// transactionKeyForContext forms and returns a key for storing transaction object of certain database group into context.\nfunc transactionKeyForContext(group string) transactionCtxKey {\n\treturn transactionCtxKey(contextTransactionKeyPrefix + group)\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_txcore.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// TXCore is the struct for transaction management.\ntype TXCore struct {\n\t// db is the database management interface that implements the DB interface,\n\t// providing access to database operations and configuration.\n\tdb DB\n\t// tx is the underlying SQL transaction object from database/sql package,\n\t// which manages the actual transaction operations.\n\ttx *sql.Tx\n\t// ctx is the context specific to this transaction,\n\t// which can be used for timeout control and cancellation.\n\tctx context.Context\n\t// master is the underlying master database connection pool,\n\t// used for direct database operations when needed.\n\tmaster *sql.DB\n\t// transactionId is a unique identifier for this transaction instance,\n\t// used for tracking and debugging purposes.\n\ttransactionId string\n\t// transactionCount tracks the number of nested transaction begins,\n\t// used for managing transaction nesting depth.\n\ttransactionCount int\n\t// isClosed indicates whether this transaction has been finalized\n\t// through either a commit or rollback operation.\n\tisClosed bool\n\t// cancelFunc is the context cancellation function associated with ctx,\n\t// used to cancel the transaction context when needed.\n\tcancelFunc context.CancelFunc\n}\n\nfunc (c *Core) newEmptyTX() TX {\n\treturn &TXCore{\n\t\tdb: c.db,\n\t}\n}\n\n// transactionKeyForNestedPoint forms and returns the transaction key at current save point.\nfunc (tx *TXCore) transactionKeyForNestedPoint() string {\n\treturn tx.db.GetCore().QuoteWord(\n\t\ttransactionPointerPrefix + gconv.String(tx.transactionCount),\n\t)\n}\n\n// Ctx sets the context for current transaction.\nfunc (tx *TXCore) Ctx(ctx context.Context) TX {\n\ttx.ctx = ctx\n\tif tx.ctx != nil {\n\t\ttx.ctx = tx.db.GetCore().injectInternalCtxData(tx.ctx)\n\t}\n\treturn tx\n}\n\n// GetCtx returns the context for current transaction.\nfunc (tx *TXCore) GetCtx() context.Context {\n\treturn tx.ctx\n}\n\n// GetDB returns the DB for current transaction.\nfunc (tx *TXCore) GetDB() DB {\n\treturn tx.db\n}\n\n// GetSqlTX returns the underlying transaction object for current transaction.\nfunc (tx *TXCore) GetSqlTX() *sql.Tx {\n\treturn tx.tx\n}\n\n// Commit commits current transaction.\n// Note that it releases previous saved transaction point if it's in a nested transaction procedure,\n// or else it commits the hole transaction.\nfunc (tx *TXCore) Commit() error {\n\tif tx.transactionCount > 0 {\n\t\ttx.transactionCount--\n\t\t_, err := tx.Exec(\"RELEASE SAVEPOINT \" + tx.transactionKeyForNestedPoint())\n\t\treturn err\n\t}\n\t_, err := tx.db.DoCommit(tx.ctx, DoCommitInput{\n\t\tTx:            tx.tx,\n\t\tSql:           \"COMMIT\",\n\t\tType:          SqlTypeTXCommit,\n\t\tTxCancelFunc:  tx.cancelFunc,\n\t\tIsTransaction: true,\n\t})\n\tif err == nil {\n\t\ttx.isClosed = true\n\t}\n\treturn err\n}\n\n// Rollback aborts current transaction.\n// Note that it aborts current transaction if it's in a nested transaction procedure,\n// or else it aborts the hole transaction.\nfunc (tx *TXCore) Rollback() error {\n\tif tx.transactionCount > 0 {\n\t\ttx.transactionCount--\n\t\t_, err := tx.Exec(\"ROLLBACK TO SAVEPOINT \" + tx.transactionKeyForNestedPoint())\n\t\treturn err\n\t}\n\t_, err := tx.db.DoCommit(tx.ctx, DoCommitInput{\n\t\tTx:            tx.tx,\n\t\tSql:           \"ROLLBACK\",\n\t\tType:          SqlTypeTXRollback,\n\t\tTxCancelFunc:  tx.cancelFunc,\n\t\tIsTransaction: true,\n\t})\n\tif err == nil {\n\t\ttx.isClosed = true\n\t}\n\treturn err\n}\n\n// IsClosed checks and returns this transaction has already been committed or rolled back.\nfunc (tx *TXCore) IsClosed() bool {\n\treturn tx.isClosed\n}\n\n// Begin starts a nested transaction procedure.\nfunc (tx *TXCore) Begin() error {\n\t_, err := tx.Exec(\"SAVEPOINT \" + tx.transactionKeyForNestedPoint())\n\tif err != nil {\n\t\treturn err\n\t}\n\ttx.transactionCount++\n\treturn nil\n}\n\n// SavePoint performs `SAVEPOINT xxx` SQL statement that saves transaction at current point.\n// The parameter `point` specifies the point name that will be saved to server.\nfunc (tx *TXCore) SavePoint(point string) error {\n\t_, err := tx.Exec(\"SAVEPOINT \" + tx.db.GetCore().QuoteWord(point))\n\treturn err\n}\n\n// RollbackTo performs `ROLLBACK TO SAVEPOINT xxx` SQL statement that rollbacks to specified saved transaction.\n// The parameter `point` specifies the point name that was saved previously.\nfunc (tx *TXCore) RollbackTo(point string) error {\n\t_, err := tx.Exec(\"ROLLBACK TO SAVEPOINT \" + tx.db.GetCore().QuoteWord(point))\n\treturn err\n}\n\n// Transaction wraps the transaction logic using function `f`.\n// It rollbacks the transaction and returns the error from function `f` if\n// it returns non-nil error. It commits the transaction and returns nil if\n// function `f` returns nil.\n//\n// Note that, you should not Commit or Rollback the transaction in function `f`\n// as it is automatically handled by this function.\nfunc (tx *TXCore) Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) {\n\tif ctx != nil {\n\t\ttx.ctx = ctx\n\t}\n\t// Check transaction object from context.\n\tif TXFromCtx(tx.ctx, tx.db.GetGroup()) == nil {\n\t\t// Inject transaction object into context.\n\t\ttx.ctx = WithTX(tx.ctx, tx)\n\t}\n\tif err = tx.Begin(); err != nil {\n\t\treturn err\n\t}\n\terr = callTxFunc(tx, f)\n\treturn\n}\n\n// TransactionWithOptions wraps the transaction logic with propagation options using function `f`.\nfunc (tx *TXCore) TransactionWithOptions(\n\tctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error,\n) (err error) {\n\treturn tx.db.TransactionWithOptions(ctx, opts, f)\n}\n\n// Query does query operation on transaction.\n// See Core.Query.\nfunc (tx *TXCore) Query(sql string, args ...any) (result Result, err error) {\n\treturn tx.db.DoQuery(tx.ctx, &txLink{tx.tx}, sql, args...)\n}\n\n// Exec does none query operation on transaction.\n// See Core.Exec.\nfunc (tx *TXCore) Exec(sql string, args ...any) (sql.Result, error) {\n\treturn tx.db.DoExec(tx.ctx, &txLink{tx.tx}, sql, args...)\n}\n\n// Prepare creates a prepared statement for later queries or executions.\n// Multiple queries or executions may be run concurrently from the\n// returned statement.\n// The caller must call the statement's Close method\n// when the statement is no longer needed.\nfunc (tx *TXCore) Prepare(sql string) (*Stmt, error) {\n\treturn tx.db.DoPrepare(tx.ctx, &txLink{tx.tx}, sql)\n}\n\n// GetAll queries and returns data records from database.\nfunc (tx *TXCore) GetAll(sql string, args ...any) (Result, error) {\n\treturn tx.Query(sql, args...)\n}\n\n// GetOne queries and returns one record from database.\nfunc (tx *TXCore) GetOne(sql string, args ...any) (Record, error) {\n\tlist, err := tx.GetAll(sql, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\treturn list[0], nil\n\t}\n\treturn nil, nil\n}\n\n// GetStruct queries one record from database and converts it to given struct.\n// The parameter `pointer` should be a pointer to struct.\nfunc (tx *TXCore) GetStruct(obj any, sql string, args ...any) error {\n\tone, err := tx.GetOne(sql, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn one.Struct(obj)\n}\n\n// GetStructs queries records from database and converts them to given struct.\n// The parameter `pointer` should be type of struct slice: []struct/[]*struct.\nfunc (tx *TXCore) GetStructs(objPointerSlice any, sql string, args ...any) error {\n\tall, err := tx.GetAll(sql, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn all.Structs(objPointerSlice)\n}\n\n// GetScan queries one or more records from database and converts them to given struct or\n// struct array.\n//\n// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for\n// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally\n// for conversion.\nfunc (tx *TXCore) GetScan(pointer any, sql string, args ...any) error {\n\treflectInfo := reflection.OriginTypeAndKind(pointer)\n\tif reflectInfo.InputKind != reflect.Pointer {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"params should be type of pointer, but got: %v\",\n\t\t\treflectInfo.InputKind,\n\t\t)\n\t}\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.Array, reflect.Slice:\n\t\treturn tx.GetStructs(pointer, sql, args...)\n\n\tcase reflect.Struct:\n\t\treturn tx.GetStruct(pointer, sql, args...)\n\n\tdefault:\n\t}\n\treturn gerror.NewCodef(\n\t\tgcode.CodeInvalidParameter,\n\t\t`in valid parameter type \"%v\", of which element type should be type of struct/slice`,\n\t\treflectInfo.InputType,\n\t)\n}\n\n// GetValue queries and returns the field value from database.\n// The sql should query only one field from database, or else it returns only one\n// field of the result.\nfunc (tx *TXCore) GetValue(sql string, args ...any) (Value, error) {\n\tone, err := tx.GetOne(sql, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, v := range one {\n\t\treturn v, nil\n\t}\n\treturn nil, nil\n}\n\n// GetCount queries and returns the count from database.\nfunc (tx *TXCore) GetCount(sql string, args ...any) (int64, error) {\n\tif !gregex.IsMatchString(`(?i)SELECT\\s+COUNT\\(.+\\)\\s+FROM`, sql) {\n\t\tsql, _ = gregex.ReplaceString(`(?i)(SELECT)\\s+(.+)\\s+(FROM)`, `$1 COUNT($2) $3`, sql)\n\t}\n\tvalue, err := tx.GetValue(sql, args...)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Int64(), nil\n}\n\n// Insert does \"INSERT INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it returns error.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `batch` specifies the batch operation count when given data is slice.\nfunc (tx *TXCore) Insert(table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Insert()\n\t}\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Insert()\n}\n\n// InsertIgnore does \"INSERT IGNORE INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it ignores the inserting.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `batch` specifies the batch operation count when given data is slice.\nfunc (tx *TXCore) InsertIgnore(table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertIgnore()\n\t}\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).InsertIgnore()\n}\n\n// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.\nfunc (tx *TXCore) InsertAndGetId(table string, data any, batch ...int) (int64, error) {\n\tif len(batch) > 0 {\n\t\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertAndGetId()\n\t}\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).InsertAndGetId()\n}\n\n// Replace does \"REPLACE INTO ...\" statement for the table.\n// If there's already one unique record of the data in the table, it deletes the record\n// and inserts a new one.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// If given data is type of slice, it then does batch replacing, and the optional parameter\n// `batch` specifies the batch operation count.\nfunc (tx *TXCore) Replace(table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Replace()\n\t}\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Replace()\n}\n\n// Save does \"INSERT INTO ... ON DUPLICATE KEY UPDATE...\" statement for the table.\n// It updates the record if there's primary or unique index in the saving data,\n// or else it inserts a new record into the table.\n//\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// If given data is type of slice, it then does batch saving, and the optional parameter\n// `batch` specifies the batch operation count.\nfunc (tx *TXCore) Save(table string, data any, batch ...int) (sql.Result, error) {\n\tif len(batch) > 0 {\n\t\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Save()\n\t}\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Save()\n}\n\n// Update does \"UPDATE ... \" statement for the table.\n//\n// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.\n// Eg: \"uid=10000\", \"uid\", 10000, g.Map{\"uid\": 10000, \"name\":\"john\"}\n//\n// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.\n// It is commonly used with parameter `args`.\n// Eg:\n// \"uid=10000\",\n// \"uid\", 10000\n// \"money>? AND name like ?\", 99999, \"vip_%\"\n// \"status IN (?)\", g.Slice{1,2,3}\n// \"age IN(?,?)\", 18, 50\n// User{ Id : 1, UserName : \"john\"}.\nfunc (tx *TXCore) Update(table string, data any, condition any, args ...any) (sql.Result, error) {\n\treturn tx.Model(table).Ctx(tx.ctx).Data(data).Where(condition, args...).Update()\n}\n\n// Delete does \"DELETE FROM ... \" statement for the table.\n//\n// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.\n// It is commonly used with parameter `args`.\n// Eg:\n// \"uid=10000\",\n// \"uid\", 10000\n// \"money>? AND name like ?\", 99999, \"vip_%\"\n// \"status IN (?)\", g.Slice{1,2,3}\n// \"age IN(?,?)\", 18, 50\n// User{ Id : 1, UserName : \"john\"}.\nfunc (tx *TXCore) Delete(table string, condition any, args ...any) (sql.Result, error) {\n\treturn tx.Model(table).Ctx(tx.ctx).Where(condition, args...).Delete()\n}\n\n// QueryContext implements interface function Link.QueryContext.\nfunc (tx *TXCore) QueryContext(ctx context.Context, sql string, args ...any) (*sql.Rows, error) {\n\treturn tx.tx.QueryContext(ctx, sql, args...)\n}\n\n// ExecContext implements interface function Link.ExecContext.\nfunc (tx *TXCore) ExecContext(ctx context.Context, sql string, args ...any) (sql.Result, error) {\n\treturn tx.tx.ExecContext(ctx, sql, args...)\n}\n\n// PrepareContext implements interface function Link.PrepareContext.\nfunc (tx *TXCore) PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error) {\n\treturn tx.tx.PrepareContext(ctx, sql)\n}\n\n// IsOnMaster implements interface function Link.IsOnMaster.\nfunc (tx *TXCore) IsOnMaster() bool {\n\treturn true\n}\n\n// IsTransaction implements interface function Link.IsTransaction.\nfunc (tx *TXCore) IsTransaction() bool {\n\treturn tx != nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_underlying.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// Query commits one query SQL to underlying driver and returns the execution result.\n// It is most commonly used for data querying.\nfunc (c *Core) Query(ctx context.Context, sql string, args ...any) (result Result, err error) {\n\treturn c.db.DoQuery(ctx, nil, sql, args...)\n}\n\n// DoQuery commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\nfunc (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...any) (result Result, err error) {\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t} else if link, err = c.SlaveLink(); err != nil {\n\t\t\t// Or else it creates one from master node.\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it checks and retrieves transaction from context.\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t}\n\t}\n\n\t// Sql filtering.\n\tsql, args = c.FormatSqlBeforeExecuting(sql, args)\n\tsql, args, err = c.db.DoFilter(ctx, link, sql, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// SQL format and retrieve.\n\tif v := ctx.Value(ctxKeyCatchSQL); v != nil {\n\t\tvar (\n\t\t\tmanager      = v.(*CatchSQLManager)\n\t\t\tformattedSql = FormatSqlWithArgs(sql, args)\n\t\t)\n\t\tmanager.SQLArray.Append(formattedSql)\n\t\tif !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\t// Link execution.\n\tvar out DoCommitOutput\n\tout, err = c.db.DoCommit(ctx, DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          SqlTypeQueryContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out.Records, err\n}\n\n// Exec commits one query SQL to underlying driver and returns the execution result.\n// It is most commonly used for data inserting and updating.\nfunc (c *Core) Exec(ctx context.Context, sql string, args ...any) (result sql.Result, err error) {\n\treturn c.db.DoExec(ctx, nil, sql, args...)\n}\n\n// DoExec commits the sql string and its arguments to underlying driver\n// through given link object and returns the execution result.\nfunc (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...any) (result sql.Result, err error) {\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t} else if link, err = c.MasterLink(); err != nil {\n\t\t\t// Or else it creates one from master node.\n\t\t\treturn nil, err\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it tries retrieving transaction object from context.\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t}\n\t}\n\n\t// SQL filtering.\n\tsql, args = c.FormatSqlBeforeExecuting(sql, args)\n\tsql, args, err = c.db.DoFilter(ctx, link, sql, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// SQL format and retrieve.\n\tif v := ctx.Value(ctxKeyCatchSQL); v != nil {\n\t\tvar (\n\t\t\tmanager      = v.(*CatchSQLManager)\n\t\t\tformattedSql = FormatSqlWithArgs(sql, args)\n\t\t)\n\t\tmanager.SQLArray.Append(formattedSql)\n\t\tif !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {\n\t\t\treturn new(SqlResult), nil\n\t\t}\n\t}\n\t// Link execution.\n\tvar out DoCommitOutput\n\tout, err = c.db.DoCommit(ctx, DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tArgs:          args,\n\t\tStmt:          nil,\n\t\tType:          SqlTypeExecContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out.Result, err\n}\n\n// DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver.\n// The parameter `link` specifies the current database connection operation object. You can modify the sql\n// string `sql` and its arguments `args` as you wish before they're committed to driver.\nfunc (c *Core) DoFilter(\n\tctx context.Context, link Link, sql string, args []any,\n) (newSql string, newArgs []any, err error) {\n\treturn sql, args, nil\n}\n\n// DoCommit commits current sql and arguments to underlying sql driver.\nfunc (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) {\n\tvar (\n\t\tsqlTx                *sql.Tx\n\t\tsqlStmt              *sql.Stmt\n\t\tsqlRows              *sql.Rows\n\t\tsqlResult            sql.Result\n\t\tstmtSqlRows          *sql.Rows\n\t\tstmtSqlRow           *sql.Row\n\t\trowsAffected         int64\n\t\tcancelFuncForTimeout context.CancelFunc\n\t\tformattedSql         = FormatSqlWithArgs(in.Sql, in.Args)\n\t\ttimestampMilli1      = gtime.TimestampMilli()\n\t)\n\n\t// Panic recovery to handle panics from underlying database drivers\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif err == nil {\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\terr = v\n\t\t\t\t} else {\n\t\t\t\t\terr = gerror.WrapCodef(gcode.CodeDbOperationError, gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception), FormatSqlWithArgs(in.Sql, in.Args))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Trace span start.\n\ttr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))\n\tctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindClient))\n\tdefer span.End()\n\n\t// Execution by type.\n\tswitch in.Type {\n\tcase SqlTypeBegin:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans)\n\t\tformattedSql = fmt.Sprintf(\n\t\t\t`%s (IosolationLevel: %s, ReadOnly: %t)`,\n\t\t\tformattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly,\n\t\t)\n\t\tif sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil {\n\t\t\ttx := &TXCore{\n\t\t\t\tdb:            c.db,\n\t\t\t\ttx:            sqlTx,\n\t\t\t\tctx:           ctx,\n\t\t\t\tmaster:        in.Db,\n\t\t\t\ttransactionId: guid.S(),\n\t\t\t\tcancelFunc:    cancelFuncForTimeout,\n\t\t\t}\n\t\t\ttx.ctx = context.WithValue(ctx, transactionKeyForContext(tx.db.GetGroup()), tx)\n\t\t\ttx.ctx = context.WithValue(tx.ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1))\n\t\t\tout.Tx = tx\n\t\t\tctx = out.Tx.GetCtx()\n\t\t}\n\t\tout.RawResult = sqlTx\n\n\tcase SqlTypeTXCommit:\n\t\tif in.TxCancelFunc != nil {\n\t\t\tdefer in.TxCancelFunc()\n\t\t}\n\t\terr = in.Tx.Commit()\n\n\tcase SqlTypeTXRollback:\n\t\tif in.TxCancelFunc != nil {\n\t\t\tdefer in.TxCancelFunc()\n\t\t}\n\t\terr = in.Tx.Rollback()\n\n\tcase SqlTypeExecContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)\n\t\tdefer cancelFuncForTimeout()\n\t\tif c.db.GetDryRun() {\n\t\t\tsqlResult = new(SqlResult)\n\t\t} else {\n\t\t\tsqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...)\n\t\t}\n\t\tout.RawResult = sqlResult\n\n\tcase SqlTypeQueryContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)\n\t\tdefer cancelFuncForTimeout()\n\t\tsqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...)\n\t\tout.RawResult = sqlRows\n\n\tcase SqlTypePrepareContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare)\n\t\tdefer cancelFuncForTimeout()\n\t\tsqlStmt, err = in.Link.PrepareContext(ctx, in.Sql)\n\t\tout.RawResult = sqlStmt\n\n\tcase SqlTypeStmtExecContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)\n\t\tdefer cancelFuncForTimeout()\n\t\tif c.db.GetDryRun() {\n\t\t\tsqlResult = new(SqlResult)\n\t\t} else {\n\t\t\tsqlResult, err = in.Stmt.ExecContext(ctx, in.Args...)\n\t\t}\n\t\tout.RawResult = sqlResult\n\n\tcase SqlTypeStmtQueryContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)\n\t\tdefer cancelFuncForTimeout()\n\t\tstmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...)\n\t\tout.RawResult = stmtSqlRows\n\n\tcase SqlTypeStmtQueryRowContext:\n\t\tctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)\n\t\tdefer cancelFuncForTimeout()\n\t\tstmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...)\n\t\tout.RawResult = stmtSqlRow\n\n\tdefault:\n\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType \"%s\"`, in.Type))\n\t}\n\t// Result handling.\n\tswitch {\n\tcase sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx):\n\t\trowsAffected, err = sqlResult.RowsAffected()\n\t\tout.Result = sqlResult\n\n\tcase sqlRows != nil:\n\t\tout.Records, err = c.RowsToResult(ctx, sqlRows)\n\t\trowsAffected = int64(len(out.Records))\n\n\tcase sqlStmt != nil:\n\t\tout.Stmt = &Stmt{\n\t\t\tStmt: sqlStmt,\n\t\t\tcore: c,\n\t\t\tlink: in.Link,\n\t\t\tsql:  in.Sql,\n\t\t}\n\t}\n\tvar (\n\t\ttimestampMilli2 = gtime.TimestampMilli()\n\t\tsqlObj          = &Sql{\n\t\t\tSql:           in.Sql,\n\t\t\tType:          in.Type,\n\t\t\tArgs:          in.Args,\n\t\t\tFormat:        formattedSql,\n\t\t\tError:         err,\n\t\t\tStart:         timestampMilli1,\n\t\t\tEnd:           timestampMilli2,\n\t\t\tGroup:         c.db.GetGroup(),\n\t\t\tSchema:        c.db.GetSchema(),\n\t\t\tRowsAffected:  rowsAffected,\n\t\t\tIsTransaction: in.IsTransaction,\n\t\t}\n\t)\n\n\t// Tracing.\n\tc.traceSpanEnd(ctx, span, sqlObj)\n\n\t// Logging.\n\tif c.db.GetDebug() {\n\t\tc.writeSqlToLogger(ctx, sqlObj)\n\t}\n\tif err != nil && err != sql.ErrNoRows {\n\t\terr = gerror.WrapCode(\n\t\t\tgcode.CodeDbOperationError,\n\t\t\terr,\n\t\t\tFormatSqlWithArgs(in.Sql, in.Args),\n\t\t)\n\t}\n\treturn out, err\n}\n\n// Prepare creates a prepared statement for later queries or executions.\n// Multiple queries or executions may be run concurrently from the\n// returned statement.\n// The caller must call the statement's Close method\n// when the statement is no longer needed.\n//\n// The parameter `execOnMaster` specifies whether executing the sql on master node,\n// or else it executes the sql on slave node if master-slave configured.\nfunc (c *Core) Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) {\n\tvar (\n\t\terr  error\n\t\tlink Link\n\t)\n\tif len(execOnMaster) > 0 && execOnMaster[0] {\n\t\tif link, err = c.MasterLink(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tif link, err = c.SlaveLink(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c.db.DoPrepare(ctx, link, sql)\n}\n\n// DoPrepare calls prepare function on given link object and returns the statement object.\nfunc (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt, err error) {\n\t// Transaction checks.\n\tif link == nil {\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\t// Firstly, check and retrieve transaction link from context.\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t} else {\n\t\t\t// Or else it creates one from master node.\n\t\t\tif link, err = c.MasterLink(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t} else if !link.IsTransaction() {\n\t\t// If current link is not transaction link, it checks and retrieves transaction from context.\n\t\tif tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {\n\t\t\tlink = &txLink{tx.GetSqlTX()}\n\t\t}\n\t}\n\n\tif c.db.GetConfig().PrepareTimeout > 0 {\n\t\t// DO NOT USE cancel function in prepare statement.\n\t\tvar cancelFunc context.CancelFunc\n\t\tctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)\n\t\tdefer cancelFunc()\n\t}\n\n\t// Link execution.\n\tvar out DoCommitOutput\n\tout, err = c.db.DoCommit(ctx, DoCommitInput{\n\t\tLink:          link,\n\t\tSql:           sql,\n\t\tType:          SqlTypePrepareContext,\n\t\tIsTransaction: link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out.Stmt, err\n}\n\n// FormatUpsert formats and returns SQL clause part for upsert statement.\n// In default implements, this function performs upsert statement for MySQL like:\n// `INSERT INTO ... ON DUPLICATE KEY UPDATE x=VALUES(z),m=VALUES(y)...`\nfunc (c *Core) FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) {\n\tvar onDuplicateStr string\n\tif option.OnDuplicateStr != \"\" {\n\t\tonDuplicateStr = option.OnDuplicateStr\n\t} else if len(option.OnDuplicateMap) > 0 {\n\t\tfor k, v := range option.OnDuplicateMap {\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tswitch v.(type) {\n\t\t\tcase Raw, *Raw:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=%s\",\n\t\t\t\t\tc.QuoteWord(k),\n\t\t\t\t\tv,\n\t\t\t\t)\n\t\t\tcase Counter, *Counter:\n\t\t\t\tvar counter Counter\n\t\t\t\tswitch value := v.(type) {\n\t\t\t\tcase Counter:\n\t\t\t\t\tcounter = value\n\t\t\t\tcase *Counter:\n\t\t\t\t\tcounter = *value\n\t\t\t\t}\n\t\t\t\toperator, columnVal := c.getCounterAlter(counter)\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=%s%s%s\",\n\t\t\t\t\tc.QuoteWord(k),\n\t\t\t\t\tc.QuoteWord(counter.Field),\n\t\t\t\t\toperator,\n\t\t\t\t\tgconv.String(columnVal),\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\t\"%s=VALUES(%s)\",\n\t\t\t\t\tc.QuoteWord(k),\n\t\t\t\t\tc.QuoteWord(gconv.String(v)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, column := range columns {\n\t\t\t// If it's `SAVE` operation, do not automatically update the creating time.\n\t\t\tif c.IsSoftCreatedFieldName(column) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(onDuplicateStr) > 0 {\n\t\t\t\tonDuplicateStr += \",\"\n\t\t\t}\n\t\t\tonDuplicateStr += fmt.Sprintf(\n\t\t\t\t\"%s=VALUES(%s)\",\n\t\t\t\tc.QuoteWord(column),\n\t\t\t\tc.QuoteWord(column),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn InsertOnDuplicateKeyUpdate + \" \" + onDuplicateStr, nil\n}\n\n// RowsToResult converts underlying data record type sql.Rows to Result type.\nfunc (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) {\n\tif rows == nil {\n\t\treturn nil, nil\n\t}\n\tdefer func() {\n\t\tif err := rows.Close(); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}()\n\tif !rows.Next() {\n\t\treturn nil, nil\n\t}\n\t// Column names and types.\n\tcolumnTypes, err := rows.ColumnTypes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(columnTypes) > 0 {\n\t\tif internalData := c.getInternalColumnFromCtx(ctx); internalData != nil {\n\t\t\tinternalData.FirstResultColumn = columnTypes[0].Name()\n\t\t}\n\t}\n\tvar (\n\t\tvalues   = make([]any, len(columnTypes))\n\t\tresult   = make(Result, 0)\n\t\tscanArgs = make([]any, len(values))\n\t)\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\tfor {\n\t\tif err = rows.Scan(scanArgs...); err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\trecord := Record{}\n\t\tfor i, value := range values {\n\t\t\tif value == nil {\n\t\t\t\t// DO NOT use `gvar.New(nil)` here as it creates an initialized object\n\t\t\t\t// which will cause struct converting issue.\n\t\t\t\trecord[columnTypes[i].Name()] = nil\n\t\t\t} else {\n\t\t\t\tvar (\n\t\t\t\t\tconvertedValue any\n\t\t\t\t\tcolumnType     = columnTypes[i]\n\t\t\t\t)\n\t\t\t\tif convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\trecord[columnTypes[i].Name()] = gvar.New(convertedValue)\n\t\t\t}\n\t\t}\n\t\tresult = append(result, record)\n\t\tif !rows.Next() {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn result, nil\n}\n\n// OrderRandomFunction returns the SQL function for random ordering.\nfunc (c *Core) OrderRandomFunction() string {\n\treturn \"RAND()\"\n}\n\nfunc (c *Core) columnValueToLocalValue(ctx context.Context, value any, columnType *sql.ColumnType) (any, error) {\n\tvar scanType = columnType.ScanType()\n\tif scanType != nil {\n\t\t// Common basic builtin types.\n\t\tswitch scanType.Kind() {\n\t\tcase\n\t\t\treflect.Bool,\n\t\t\treflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,\n\t\t\treflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,\n\t\t\treflect.Float32, reflect.Float64:\n\t\t\treturn gconv.Convert(gconv.String(value), scanType.String()), nil\n\t\tdefault:\n\t\t}\n\t}\n\t// Other complex types, especially custom types.\n\treturn c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value)\n}\n"
  },
  {
    "path": "database/gdb/gdb_core_utility.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// GetDB returns the underlying DB.\nfunc (c *Core) GetDB() DB {\n\treturn c.db\n}\n\n// GetLink creates and returns the underlying database link object with transaction checks.\n// The parameter `master` specifies whether using the master node if master-slave configured.\nfunc (c *Core) GetLink(ctx context.Context, master bool, schema string) (Link, error) {\n\ttx := TXFromCtx(ctx, c.db.GetGroup())\n\tif tx != nil {\n\t\treturn &txLink{tx.GetSqlTX()}, nil\n\t}\n\tif master {\n\t\tlink, err := c.db.GetCore().MasterLink(schema)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn link, nil\n\t}\n\tlink, err := c.db.GetCore().SlaveLink(schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn link, nil\n}\n\n// MasterLink acts like function Master but with additional `schema` parameter specifying\n// the schema for the connection. It is defined for internal usage.\n// Also see Master.\nfunc (c *Core) MasterLink(schema ...string) (Link, error) {\n\tdb, err := c.db.Master(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &dbLink{\n\t\tDB:         db,\n\t\tisOnMaster: true,\n\t}, nil\n}\n\n// SlaveLink acts like function Slave but with additional `schema` parameter specifying\n// the schema for the connection. It is defined for internal usage.\n// Also see Slave.\nfunc (c *Core) SlaveLink(schema ...string) (Link, error) {\n\tdb, err := c.db.Slave(schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &dbLink{\n\t\tDB:         db,\n\t\tisOnMaster: false,\n\t}, nil\n}\n\n// QuoteWord checks given string `s` a word,\n// if true it quotes `s` with security chars of the database\n// and returns the quoted string; or else it returns `s` without any change.\n//\n// The meaning of a `word` can be considered as a column name.\nfunc (c *Core) QuoteWord(s string) string {\n\ts = gstr.Trim(s)\n\tif s == \"\" {\n\t\treturn s\n\t}\n\tcharLeft, charRight := c.db.GetChars()\n\treturn doQuoteWord(s, charLeft, charRight)\n}\n\n// QuoteString quotes string with quote chars. Strings like:\n// \"user\", \"user u\", \"user,user_detail\", \"user u, user_detail ut\", \"u.id asc\".\n//\n// The meaning of a `string` can be considered as part of a statement string including columns.\nfunc (c *Core) QuoteString(s string) string {\n\tif !gregex.IsMatchString(regularFieldNameWithCommaRegPattern, s) {\n\t\treturn s\n\t}\n\tcharLeft, charRight := c.db.GetChars()\n\treturn doQuoteString(s, charLeft, charRight)\n}\n\n// QuotePrefixTableName adds prefix string and quotes chars for the table.\n// It handles table string like:\n// \"user\", \"user u\",\n// \"user,user_detail\",\n// \"user u, user_detail ut\",\n// \"user as u, user_detail as ut\".\n//\n// Note that, this will automatically checks the table prefix whether already added,\n// if true it does nothing to the table name, or else adds the prefix to the table name.\nfunc (c *Core) QuotePrefixTableName(table string) string {\n\tcharLeft, charRight := c.db.GetChars()\n\treturn doQuoteTableName(table, c.db.GetPrefix(), charLeft, charRight)\n}\n\n// GetChars returns the security char for current database.\n// It does nothing in default.\nfunc (c *Core) GetChars() (charLeft string, charRight string) {\n\treturn \"\", \"\"\n}\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (c *Core) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\treturn\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current\n// schema.\n//\n// The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection\n// as its link to proceed necessary sql query.\n//\n// Note that it returns a map containing the field name and its corresponding fields.\n// As a map is unsorted, the TableField struct has an \"Index\" field marks its sequence in\n// the fields.\n//\n// It's using cache feature to enhance the performance, which is never expired util the\n// process restarts.\nfunc (c *Core) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*TableField, err error) {\n\treturn\n}\n\n// ClearTableFields removes certain cached table fields of current configuration group.\nfunc (c *Core) ClearTableFields(ctx context.Context, table string, schema ...string) (err error) {\n\ttableFieldsCacheKey := genTableFieldsCacheKey(\n\t\tc.db.GetGroup(),\n\t\tgutil.GetOrDefaultStr(c.db.GetSchema(), schema...),\n\t\ttable,\n\t)\n\t_, err = c.innerMemCache.Remove(ctx, tableFieldsCacheKey)\n\treturn\n}\n\n// ClearTableFieldsAll removes all cached table fields of current configuration group.\nfunc (c *Core) ClearTableFieldsAll(ctx context.Context) (err error) {\n\tvar (\n\t\tkeys, _     = c.innerMemCache.KeyStrings(ctx)\n\t\tcachePrefix = cachePrefixTableFields\n\t\tremovedKeys = make([]any, 0)\n\t)\n\tfor _, key := range keys {\n\t\tif gstr.HasPrefix(key, cachePrefix) {\n\t\t\tremovedKeys = append(removedKeys, key)\n\t\t}\n\t}\n\n\tif len(removedKeys) > 0 {\n\t\terr = c.innerMemCache.Removes(ctx, removedKeys)\n\t}\n\treturn\n}\n\n// ClearCache removes cached sql result of certain table.\nfunc (c *Core) ClearCache(ctx context.Context, table string) (err error) {\n\tvar (\n\t\tkeys, _     = c.db.GetCache().KeyStrings(ctx)\n\t\tcachePrefix = fmt.Sprintf(`%s%s@`, cachePrefixSelectCache, table)\n\t\tremovedKeys = make([]any, 0)\n\t)\n\tfor _, key := range keys {\n\t\tif gstr.HasPrefix(key, cachePrefix) {\n\t\t\tremovedKeys = append(removedKeys, key)\n\t\t}\n\t}\n\tif len(removedKeys) > 0 {\n\t\terr = c.db.GetCache().Removes(ctx, removedKeys)\n\t}\n\treturn\n}\n\n// ClearCacheAll removes all cached sql result from cache\nfunc (c *Core) ClearCacheAll(ctx context.Context) (err error) {\n\tif err = c.db.GetCache().Clear(ctx); err != nil {\n\t\treturn err\n\t}\n\tif err = c.GetInnerMemCache().Clear(ctx); err != nil {\n\t\treturn err\n\t}\n\treturn\n}\n\n// HasField determine whether the field exists in the table.\nfunc (c *Core) HasField(ctx context.Context, table, field string, schema ...string) (bool, error) {\n\ttable = c.guessPrimaryTableName(table)\n\ttableFields, err := c.db.TableFields(ctx, table, schema...)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif len(tableFields) == 0 {\n\t\treturn false, gerror.NewCodef(\n\t\t\tgcode.CodeNotFound,\n\t\t\t`empty table fields for table \"%s\"`, table,\n\t\t)\n\t}\n\tfieldsArray := make([]string, len(tableFields))\n\tfor k, v := range tableFields {\n\t\tfieldsArray[v.Index] = k\n\t}\n\tcharLeft, charRight := c.db.GetChars()\n\tfield = gstr.Trim(field, charLeft+charRight)\n\tfor _, f := range fieldsArray {\n\t\tif f == field {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// guessPrimaryTableName parses and returns the primary table name.\nfunc (c *Core) guessPrimaryTableName(tableStr string) string {\n\tif tableStr == \"\" {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tguessedTableName string\n\t\tarray1           = gstr.SplitAndTrim(tableStr, \",\")\n\t\tarray2           = gstr.SplitAndTrim(array1[0], \" \")\n\t\tarray3           = gstr.SplitAndTrim(array2[0], \".\")\n\t)\n\tif len(array3) >= 2 {\n\t\tguessedTableName = array3[1]\n\t} else {\n\t\tguessedTableName = array3[0]\n\t}\n\tcharL, charR := c.db.GetChars()\n\tif charL != \"\" || charR != \"\" {\n\t\tguessedTableName = gstr.Trim(guessedTableName, charL+charR)\n\t}\n\tif !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) {\n\t\treturn \"\"\n\t}\n\treturn guessedTableName\n}\n\n// GetPrimaryKeys retrieves and returns the primary key field names of the specified table.\n// This method extracts primary key information from TableFields.\n// The parameter `schema` is optional, if not specified it uses the default schema.\nfunc (c *Core) GetPrimaryKeys(ctx context.Context, table string, schema ...string) ([]string, error) {\n\ttableFields, err := c.db.TableFields(ctx, table, schema...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar primaryKeys []string\n\tfor _, field := range tableFields {\n\t\tif strings.EqualFold(field.Key, \"pri\") {\n\t\t\tprimaryKeys = append(primaryKeys, field.Name)\n\t\t}\n\t}\n\n\treturn primaryKeys, nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_driver_default.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n)\n\n// DriverDefault is the default driver for mysql database, which does nothing.\ntype DriverDefault struct {\n\t*Core\n}\n\nfunc init() {\n\tif err := Register(\"default\", &DriverDefault{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// New creates and returns a database object for mysql.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *DriverDefault) New(core *Core, node *ConfigNode) (DB, error) {\n\treturn &DriverDefault{\n\t\tCore: core,\n\t}, nil\n}\n\n// Open creates and returns an underlying sql.DB object for mysql.\n// Note that it converts time.Time argument to local timezone in default.\nfunc (d *DriverDefault) Open(config *ConfigNode) (db *sql.DB, err error) {\n\treturn\n}\n\n// PingMaster pings the master node to check authentication or keeps the connection alive.\nfunc (d *DriverDefault) PingMaster() error {\n\treturn nil\n}\n\n// PingSlave pings the slave node to check authentication or keeps the connection alive.\nfunc (d *DriverDefault) PingSlave() error {\n\treturn nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_driver_wrapper.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// DriverWrapper is a driver wrapper for extending features with embedded driver.\ntype DriverWrapper struct {\n\tdriver Driver\n}\n\n// New creates and returns a database object for mysql.\n// It implements the interface of gdb.Driver for extra database driver installation.\nfunc (d *DriverWrapper) New(core *Core, node *ConfigNode) (DB, error) {\n\tdb, err := d.driver.New(core, node)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &DriverWrapperDB{\n\t\tDB: db,\n\t}, nil\n}\n\n// newDriverWrapper creates and returns a driver wrapper.\nfunc newDriverWrapper(driver Driver) Driver {\n\treturn &DriverWrapper{\n\t\tdriver: driver,\n\t}\n}\n"
  },
  {
    "path": "database/gdb/gdb_driver_wrapper_db.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// DriverWrapperDB is a DB wrapper for extending features with embedded DB.\ntype DriverWrapperDB struct {\n\tDB\n}\n\n// Open creates and returns an underlying sql.DB object for pgsql.\n// https://pkg.go.dev/github.com/lib/pq\nfunc (d *DriverWrapperDB) Open(node *ConfigNode) (db *sql.DB, err error) {\n\tvar ctx = d.GetCtx()\n\tintlog.PrintFunc(ctx, func() string {\n\t\treturn fmt.Sprintf(`open new connection:%s`, gjson.MustEncode(node))\n\t})\n\treturn d.DB.Open(node)\n}\n\n// Tables retrieves and returns the tables of current schema.\n// It's mainly used in cli tool chain for automatically generating the models.\nfunc (d *DriverWrapperDB) Tables(ctx context.Context, schema ...string) (tables []string, err error) {\n\tctx = context.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{})\n\treturn d.DB.Tables(ctx, schema...)\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current\n// schema.\n//\n// The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection\n// as its link to proceed necessary sql query.\n//\n// Note that it returns a map containing the field name and its corresponding fields.\n// As a map is unsorted, the TableField struct has an \"Index\" field marks its sequence in\n// the fields.\n//\n// It's using cache feature to enhance the performance, which is never expired util the\n// process restarts.\nfunc (d *DriverWrapperDB) TableFields(\n\tctx context.Context, table string, schema ...string,\n) (fields map[string]*TableField, err error) {\n\tif table == \"\" {\n\t\treturn nil, nil\n\t}\n\tcharL, charR := d.GetChars()\n\ttable = gstr.Trim(table, charL+charR)\n\tif gstr.Contains(table, \" \") {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"function TableFields supports only single table operations\",\n\t\t)\n\t}\n\tvar (\n\t\tinnerMemCache = d.GetCore().GetInnerMemCache()\n\t\t// prefix:group@schema#table\n\t\tcacheKey = genTableFieldsCacheKey(\n\t\t\td.GetGroup(),\n\t\t\tgutil.GetOrDefaultStr(d.GetSchema(), schema...),\n\t\t\ttable,\n\t\t)\n\t\tcacheFunc = func(ctx context.Context) (any, error) {\n\t\t\treturn d.DB.TableFields(\n\t\t\t\tcontext.WithValue(ctx, ctxKeyInternalProducedSQL, struct{}{}),\n\t\t\t\ttable, schema...,\n\t\t\t)\n\t\t}\n\t\tvalue *gvar.Var\n\t)\n\tvalue, err = innerMemCache.GetOrSetFuncLock(\n\t\tctx, cacheKey, cacheFunc, gcache.DurationNoExpire,\n\t)\n\tif err != nil {\n\t\treturn\n\t}\n\tif !value.IsNil() {\n\t\tfields = value.Val().(map[string]*TableField)\n\t}\n\treturn\n}\n\n// DoInsert inserts or updates data for given table.\n// This function is usually used for custom interface definition, you do not need call it manually.\n// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.\n// Eg:\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"})\n//\n// The parameter `option` values are as follows:\n// InsertOptionDefault:  just insert, if there's unique/primary key in the data, it returns error;\n// InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;\n// InsertOptionSave:    if there's unique/primary key in the data, it updates it or else inserts a new one;\n// InsertOptionIgnore:  if there's unique/primary key in the data, it ignores the inserting;\nfunc (d *DriverWrapperDB) DoInsert(\n\tctx context.Context, link Link, table string, list List, option DoInsertOption,\n) (result sql.Result, err error) {\n\tif len(list) == 0 {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidRequest,\n\t\t\t`data list is empty for %s operation`,\n\t\t\tGetInsertOperationByOption(option.InsertOption),\n\t\t)\n\t}\n\n\t// Convert data type before commit it to underlying db driver.\n\tfor i, item := range list {\n\t\tlist[i], err = d.GetCore().ConvertDataForRecord(ctx, item, table)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn d.DB.DoInsert(ctx, link, table, list, option)\n}\n"
  },
  {
    "path": "database/gdb/gdb_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// iString is the type assert api for String.\ntype iString interface {\n\tString() string\n}\n\n// iIterator is the type assert api for Iterator.\ntype iIterator interface {\n\tIterator(f func(key, value any) bool)\n}\n\n// iInterfaces is the type assert api for Interfaces.\ntype iInterfaces interface {\n\tInterfaces() []any\n}\n\n// iNil if the type assert api for IsNil.\ntype iNil interface {\n\tIsNil() bool\n}\n\n// iTableName is the interface for retrieving table name for struct.\ntype iTableName interface {\n\tTableName() string\n}\n\nconst (\n\tOrmTagForStruct       = \"orm\"\n\tOrmTagForTable        = \"table\"\n\tOrmTagForWith         = \"with\"\n\tOrmTagForWithWhere    = \"where\"\n\tOrmTagForWithOrder    = \"order\"\n\tOrmTagForWithUnscoped = \"unscoped\"\n\tOrmTagForDo           = \"do\"\n)\n\nvar (\n\t// quoteWordReg is the regular expression object for a word check.\n\tquoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\\-_]+$`)\n\n\t// structTagPriority tags for struct converting for orm field mapping.\n\tstructTagPriority = append([]string{OrmTagForStruct}, gtag.StructTagPriority...)\n)\n\n// WithDB injects given db object into context and returns a new context.\nfunc WithDB(ctx context.Context, db DB) context.Context {\n\tif db == nil {\n\t\treturn ctx\n\t}\n\tdbCtx := db.GetCtx()\n\tif ctxDb := DBFromCtx(dbCtx); ctxDb != nil {\n\t\treturn dbCtx\n\t}\n\tctx = context.WithValue(ctx, ctxKeyForDB, db)\n\treturn ctx\n}\n\n// DBFromCtx retrieves and returns DB object from context.\nfunc DBFromCtx(ctx context.Context) DB {\n\tif ctx == nil {\n\t\treturn nil\n\t}\n\tv := ctx.Value(ctxKeyForDB)\n\tif v != nil {\n\t\treturn v.(DB)\n\t}\n\treturn nil\n}\n\n// ToSQL formats and returns the last one of sql statements in given closure function\n// WITHOUT TRULY EXECUTING IT.\n// Be caution that, all the following sql statements should use the context object passing by function `f`.\nfunc ToSQL(ctx context.Context, f func(ctx context.Context) error) (sql string, err error) {\n\tvar manager = &CatchSQLManager{\n\t\tSQLArray: garray.NewStrArray(),\n\t\tDoCommit: false,\n\t}\n\tctx = context.WithValue(ctx, ctxKeyCatchSQL, manager)\n\terr = f(ctx)\n\tsql, _ = manager.SQLArray.PopRight()\n\treturn\n}\n\n// CatchSQL catches and returns all sql statements that are EXECUTED in given closure function.\n// Be caution that, all the following sql statements should use the context object passing by function `f`.\nfunc CatchSQL(ctx context.Context, f func(ctx context.Context) error) (sqlArray []string, err error) {\n\tvar manager = &CatchSQLManager{\n\t\tSQLArray: garray.NewStrArray(),\n\t\tDoCommit: true,\n\t}\n\tctx = context.WithValue(ctx, ctxKeyCatchSQL, manager)\n\terr = f(ctx)\n\treturn manager.SQLArray.Slice(), err\n}\n\n// isDoStruct checks and returns whether given type is a DO struct.\nfunc isDoStruct(object any) bool {\n\t// It checks by struct name like \"XxxForDao\", to be compatible with old version.\n\t// TODO remove this compatible codes in future.\n\treflectType := reflect.TypeOf(object)\n\tif gstr.HasSuffix(reflectType.String(), modelForDaoSuffix) {\n\t\treturn true\n\t}\n\t// It checks by struct meta for DO struct in version.\n\tif ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {\n\t\tmatch, _ := gregex.MatchString(\n\t\t\tfmt.Sprintf(`%s\\s*:\\s*([^,]+)`, OrmTagForDo),\n\t\t\tormTag.String(),\n\t\t)\n\t\tif len(match) > 1 {\n\t\t\treturn gconv.Bool(match[1])\n\t\t}\n\t}\n\treturn false\n}\n\n// getTableNameFromOrmTag retrieves and returns the table name from struct object.\nfunc getTableNameFromOrmTag(object any) string {\n\tvar tableName string\n\tvar actualObj = object\n\n\tif rv, ok := object.(reflect.Value); ok {\n\t\t// Check if reflect.Value is valid\n\t\tif rv.IsValid() && rv.CanInterface() {\n\t\t\tactualObj = rv.Interface()\n\t\t} else {\n\t\t\t// If reflect.Value is invalid, we cannot proceed with interface checks\n\t\t\treturn \"\"\n\t\t}\n\t}\n\n\t// Check iTableName interface\n\tif actualObj != nil {\n\t\tif r, ok := actualObj.(iTableName); ok {\n\t\t\treturn r.TableName()\n\t\t}\n\n\t\t// User meta data tag \"orm\".\n\t\tif ormTag := gmeta.Get(actualObj, OrmTagForStruct); !ormTag.IsEmpty() {\n\t\t\tmatch, _ := gregex.MatchString(\n\t\t\t\tfmt.Sprintf(`%s\\s*:\\s*([^,]+)`, OrmTagForTable),\n\t\t\t\tormTag.String(),\n\t\t\t)\n\t\t\tif len(match) > 1 {\n\t\t\t\ttableName = match[1]\n\t\t\t}\n\t\t}\n\n\t\t// Use the struct name of snake case.\n\t\tif tableName == \"\" {\n\t\t\tif t, err := gstructs.StructType(actualObj); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t} else {\n\t\t\t\ttableName = gstr.CaseSnakeFirstUpper(\n\t\t\t\t\tgstr.StrEx(t.String(), \".\"),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tableName\n}\n\n// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\n//\n// The parameter `list` supports types like:\n// []map[string]any\n// []map[string]sub-map\n// []struct\n// []struct:sub-struct\n// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.\n// See gutil.ListItemValues.\nfunc ListItemValues(list any, key any, subKey ...any) (values []any) {\n\treturn gutil.ListItemValues(list, key, subKey...)\n}\n\n// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\n// See gutil.ListItemValuesUnique.\nfunc ListItemValuesUnique(list any, key string, subKey ...any) []any {\n\treturn gutil.ListItemValuesUnique(list, key, subKey...)\n}\n\n// GetInsertOperationByOption returns proper insert option with given parameter `option`.\nfunc GetInsertOperationByOption(option InsertOption) string {\n\tvar operator string\n\tswitch option {\n\tcase InsertOptionReplace:\n\t\toperator = InsertOperationReplace\n\tcase InsertOptionIgnore:\n\t\toperator = InsertOperationIgnore\n\tdefault:\n\t\toperator = InsertOperationInsert\n\t}\n\treturn operator\n}\n\nfunc anyValueToMapBeforeToRecord(value any) map[string]any {\n\tconvertedMap := gconv.Map(value, gconv.MapOption{\n\t\tTags:      structTagPriority,\n\t\tOmitEmpty: true, // To be compatible with old version from v2.6.0.\n\t})\n\tif gutil.OriginValueAndKind(value).OriginKind != reflect.Struct {\n\t\treturn convertedMap\n\t}\n\t// It here converts all struct/map slice attributes to json string.\n\tfor k, v := range convertedMap {\n\t\toriginValueAndKind := gutil.OriginValueAndKind(v)\n\t\tswitch originValueAndKind.OriginKind {\n\t\t// Check map item slice item.\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\tmapItemValue := originValueAndKind.OriginValue\n\t\t\tif mapItemValue.Len() == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Check slice item type struct/map type.\n\t\t\tswitch mapItemValue.Index(0).Kind() {\n\t\t\tcase reflect.Struct, reflect.Map:\n\t\t\t\tmapItemJsonBytes, err := json.Marshal(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// Do not eat any error.\n\t\t\t\t\tintlog.Error(context.TODO(), err)\n\t\t\t\t}\n\t\t\t\tconvertedMap[k] = mapItemJsonBytes\n\t\t\t}\n\t\t}\n\t}\n\treturn convertedMap\n}\n\n// MapOrStructToMapDeep converts `value` to map type recursively(if attribute struct is embedded).\n// The parameter `value` should be type of *map/map/*struct/struct.\n// It supports embedded struct definition for struct.\nfunc MapOrStructToMapDeep(value any, omitempty bool) map[string]any {\n\tm := gconv.Map(value, gconv.MapOption{\n\t\tTags:      structTagPriority,\n\t\tOmitEmpty: omitempty,\n\t})\n\tfor k, v := range m {\n\t\tswitch v.(type) {\n\t\tcase time.Time, *time.Time, gtime.Time, *gtime.Time, gjson.Json, *gjson.Json:\n\t\t\tm[k] = v\n\t\t}\n\t}\n\treturn m\n}\n\n// doQuoteTableName adds prefix string and quote chars for table name. It handles table string like:\n// \"user\", \"user u\", \"user,user_detail\", \"user u, user_detail ut\", \"user as u, user_detail as ut\",\n// \"user.user u\", \"`user`.`user` u\".\n//\n// Note that, this will automatically check the table prefix whether already added, if true it does\n// nothing to the table name, or else adds the prefix to the table name and returns new table name with prefix.\nfunc doQuoteTableName(table, prefix, charLeft, charRight string) string {\n\tvar (\n\t\tindex  int\n\t\tchars  = charLeft + charRight\n\t\tarray1 = gstr.SplitAndTrim(table, \",\")\n\t)\n\tfor k1, v1 := range array1 {\n\t\tarray2 := gstr.SplitAndTrim(v1, \" \")\n\t\t// Trim the security chars.\n\t\tarray2[0] = gstr.Trim(array2[0], chars)\n\t\t// Check whether it has database name.\n\t\tarray3 := gstr.Split(gstr.Trim(array2[0]), \".\")\n\t\tfor k, v := range array3 {\n\t\t\tarray3[k] = gstr.Trim(v, chars)\n\t\t}\n\t\tindex = len(array3) - 1\n\t\t// If the table name already has the prefix, skips the prefix adding.\n\t\tif len(array3[index]) <= len(prefix) || array3[index][:len(prefix)] != prefix {\n\t\t\tarray3[index] = prefix + array3[index]\n\t\t}\n\t\tarray2[0] = gstr.Join(array3, \".\")\n\t\t// Add the security chars.\n\t\tarray2[0] = doQuoteString(array2[0], charLeft, charRight)\n\t\tarray1[k1] = gstr.Join(array2, \" \")\n\t}\n\treturn gstr.Join(array1, \",\")\n}\n\n// doQuoteWord checks given string `s` a word, if true quotes it with `charLeft` and `charRight`\n// and returns the quoted string; or else returns `s` without any change.\nfunc doQuoteWord(s, charLeft, charRight string) string {\n\tif quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {\n\t\treturn charLeft + s + charRight\n\t}\n\treturn s\n}\n\n// doQuoteString quotes string with quote chars.\n// For example, if quote char is '`':\n// \"null\"                             => \"NULL\"\n// \"user\"                             => \"`user`\"\n// \"user u\"                           => \"`user` u\"\n// \"user,user_detail\"                 => \"`user`,`user_detail`\"\n// \"user u, user_detail ut\"           => \"`user` u,`user_detail` ut\"\n// \"user.user u, user.user_detail ut\" => \"`user`.`user` u,`user`.`user_detail` ut\"\n// \"u.id, u.name, u.age\"              => \"`u`.`id`,`u`.`name`,`u`.`age`\"\n// \"u.id asc\"                         => \"`u`.`id` asc\".\nfunc doQuoteString(s, charLeft, charRight string) string {\n\tarray1 := gstr.SplitAndTrim(s, \",\")\n\tfor k1, v1 := range array1 {\n\t\tarray2 := gstr.SplitAndTrim(v1, \" \")\n\t\tarray3 := gstr.Split(gstr.Trim(array2[0]), \".\")\n\t\tif len(array3) == 1 {\n\t\t\tif strings.EqualFold(array3[0], \"NULL\") {\n\t\t\t\tarray3[0] = doQuoteWord(array3[0], \"\", \"\")\n\t\t\t} else {\n\t\t\t\tarray3[0] = doQuoteWord(array3[0], charLeft, charRight)\n\t\t\t}\n\t\t} else if len(array3) >= 2 {\n\t\t\tarray3[0] = doQuoteWord(array3[0], charLeft, charRight)\n\t\t\t// Note:\n\t\t\t// mysql: u.uid\n\t\t\t// mssql double dots: Database..Table\n\t\t\tarray3[len(array3)-1] = doQuoteWord(array3[len(array3)-1], charLeft, charRight)\n\t\t}\n\t\tarray2[0] = gstr.Join(array3, \".\")\n\t\tarray1[k1] = gstr.Join(array2, \" \")\n\t}\n\treturn gstr.Join(array1, \",\")\n}\n\nfunc getFieldsFromStructOrMap(structOrMap any) (fields []any) {\n\tfields = []any{}\n\tif utils.IsStruct(structOrMap) {\n\t\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         structOrMap,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tvar ormTagValue string\n\t\tfor _, structField := range structFields {\n\t\t\tormTagValue = structField.Tag(OrmTagForStruct)\n\t\t\tormTagValue = gstr.Split(gstr.Trim(ormTagValue), \",\")[0]\n\t\t\tif ormTagValue != \"\" && gregex.IsMatchString(regularFieldNameRegPattern, ormTagValue) {\n\t\t\t\tfields = append(fields, ormTagValue)\n\t\t\t} else {\n\t\t\t\tfields = append(fields, structField.Name())\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfields = gconv.Interfaces(gutil.Keys(structOrMap))\n\t}\n\treturn\n}\n\n// GetPrimaryKeyCondition returns a new where condition by primary field name.\n// The optional parameter `where` is like follows:\n// 123                             => primary=123\n// []int{1, 2, 3}                  => primary IN(1,2,3)\n// \"john\"                          => primary='john'\n// []string{\"john\", \"smith\"}       => primary IN('john','smith')\n// g.Map{\"id\": g.Slice{1,2,3}}     => id IN(1,2,3)\n// g.Map{\"id\": 1, \"name\": \"john\"}  => id=1 AND name='john'\n// etc.\n//\n// Note that it returns the given `where` parameter directly if the `primary` is empty\n// or length of `where` > 1.\nfunc GetPrimaryKeyCondition(primary string, where ...any) (newWhereCondition []any) {\n\tif len(where) == 0 {\n\t\treturn nil\n\t}\n\tif primary == \"\" {\n\t\treturn where\n\t}\n\tif len(where) == 1 {\n\t\tvar (\n\t\t\trv   = reflect.ValueOf(where[0])\n\t\t\tkind = rv.Kind()\n\t\t)\n\t\tif kind == reflect.Pointer {\n\t\t\trv = rv.Elem()\n\t\t\tkind = rv.Kind()\n\t\t}\n\t\tswitch kind {\n\t\tcase reflect.Map, reflect.Struct:\n\t\t\t// Ignore the parameter `primary`.\n\t\t\tbreak\n\n\t\tdefault:\n\t\t\treturn []any{map[string]any{\n\t\t\t\tprimary: where[0],\n\t\t\t}}\n\t\t}\n\t}\n\treturn where\n}\n\ntype formatWhereHolderInput struct {\n\tWhereHolder\n\tOmitNil   bool\n\tOmitEmpty bool\n\tSchema    string\n\tTable     string // Table is used for fields mapping and filtering internally.\n}\n\nfunc isKeyValueCanBeOmitEmpty(omitEmpty bool, whereType string, key, value any) bool {\n\tif !omitEmpty {\n\t\treturn false\n\t}\n\t// Eg:\n\t// Where(\"id\", []int{}).All()             -> SELECT xxx FROM xxx WHERE 0=1\n\t// Where(\"name\", \"\").All()                -> SELECT xxx FROM xxx WHERE `name`=''\n\t// OmitEmpty().Where(\"id\", []int{}).All() -> SELECT xxx FROM xxx\n\t// OmitEmpty().Where(\"name\", \"\").All()    -> SELECT xxx FROM xxx\n\t// OmitEmpty().Where(\"1\").All()           -> SELECT xxx FROM xxx WHERE 1\n\tswitch whereType {\n\tcase whereHolderTypeNoArgs:\n\t\treturn false\n\n\tcase whereHolderTypeIn:\n\t\treturn gutil.IsEmpty(value)\n\n\tdefault:\n\t\tif gstr.Count(gconv.String(key), \"?\") == 0 && gutil.IsEmpty(value) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// formatWhereHolder formats where statement and its arguments for `Where` and `Having` statements.\nfunc formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (newWhere string, newArgs []any) {\n\tvar (\n\t\tbuffer      = bytes.NewBuffer(nil)\n\t\treflectInfo = reflection.OriginValueAndKind(in.Where)\n\t)\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.Array, reflect.Slice:\n\t\tnewArgs = formatWhereInterfaces(db, gconv.Interfaces(in.Where), buffer, newArgs)\n\n\tcase reflect.Map:\n\t\tfor key, value := range MapOrStructToMapDeep(in.Where, true) {\n\t\t\tif in.OmitNil && empty.IsNil(value) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif in.OmitEmpty && empty.IsEmpty(value) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tnewArgs = formatWhereKeyValue(formatWhereKeyValueInput{\n\t\t\t\tDb:     db,\n\t\t\t\tBuffer: buffer,\n\t\t\t\tArgs:   newArgs,\n\t\t\t\tKey:    key,\n\t\t\t\tValue:  value,\n\t\t\t\tPrefix: in.Prefix,\n\t\t\t\tType:   in.Type,\n\t\t\t})\n\t\t}\n\n\tcase reflect.Struct:\n\t\t// If the `where` parameter is `DO` struct, it then adds `OmitNil` option for this condition,\n\t\t// which will filter all nil parameters in `where`.\n\t\tif isDoStruct(in.Where) {\n\t\t\tin.OmitNil = true\n\t\t}\n\t\t// If `where` struct implements `iIterator` interface,\n\t\t// it then uses its Iterate function to iterate its key-value pairs.\n\t\t// For example, ListMap and TreeMap are ordered map,\n\t\t// which implement `iIterator` interface and are index-friendly for where conditions.\n\t\tif iterator, ok := in.Where.(iIterator); ok {\n\t\t\titerator.Iterator(func(key, value any) bool {\n\t\t\t\tketStr := gconv.String(key)\n\t\t\t\tif in.OmitNil && empty.IsNil(value) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\tif in.OmitEmpty && empty.IsEmpty(value) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\tnewArgs = formatWhereKeyValue(formatWhereKeyValueInput{\n\t\t\t\t\tDb:        db,\n\t\t\t\t\tBuffer:    buffer,\n\t\t\t\t\tArgs:      newArgs,\n\t\t\t\t\tKey:       ketStr,\n\t\t\t\t\tValue:     value,\n\t\t\t\t\tOmitEmpty: in.OmitEmpty,\n\t\t\t\t\tPrefix:    in.Prefix,\n\t\t\t\t\tType:      in.Type,\n\t\t\t\t})\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tbreak\n\t\t}\n\t\t// Automatically mapping and filtering the struct attribute.\n\t\tvar (\n\t\t\treflectType = reflectInfo.OriginValue.Type()\n\t\t\tstructField reflect.StructField\n\t\t\tdata        = MapOrStructToMapDeep(in.Where, true)\n\t\t)\n\t\t// If `Prefix` is given, it checks and retrieves the table name.\n\t\tif in.Prefix != \"\" {\n\t\t\thasTable, _ := db.GetCore().HasTable(in.Prefix)\n\t\t\tif hasTable {\n\t\t\t\tin.Table = in.Prefix\n\t\t\t} else {\n\t\t\t\tormTagTableName := getTableNameFromOrmTag(in.Where)\n\t\t\t\tif ormTagTableName != \"\" {\n\t\t\t\t\tin.Table = ormTagTableName\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Mapping and filtering fields if `Table` is given.\n\t\tif in.Table != \"\" {\n\t\t\tdata, _ = db.GetCore().mappingAndFilterData(ctx, in.Schema, in.Table, data, true)\n\t\t}\n\t\t// Put the struct attributes in sequence in Where statement.\n\t\tvar ormTagValue string\n\t\tfor i := 0; i < reflectType.NumField(); i++ {\n\t\t\tstructField = reflectType.Field(i)\n\t\t\t// Use tag value from `orm` as field name if specified.\n\t\t\tormTagValue = structField.Tag.Get(OrmTagForStruct)\n\t\t\tormTagValue = gstr.Split(gstr.Trim(ormTagValue), \",\")[0]\n\t\t\tif ormTagValue == \"\" {\n\t\t\t\tormTagValue = structField.Name\n\t\t\t}\n\t\t\tfoundKey, foundValue := gutil.MapPossibleItemByKey(data, ormTagValue)\n\t\t\tif foundKey != \"\" {\n\t\t\t\tif in.OmitNil && empty.IsNil(foundValue) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif in.OmitEmpty && empty.IsEmpty(foundValue) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnewArgs = formatWhereKeyValue(formatWhereKeyValueInput{\n\t\t\t\t\tDb:        db,\n\t\t\t\t\tBuffer:    buffer,\n\t\t\t\t\tArgs:      newArgs,\n\t\t\t\t\tKey:       foundKey,\n\t\t\t\t\tValue:     foundValue,\n\t\t\t\t\tOmitEmpty: in.OmitEmpty,\n\t\t\t\t\tPrefix:    in.Prefix,\n\t\t\t\t\tType:      in.Type,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\t// Where filter.\n\t\tvar omitEmptyCheckValue any\n\t\tif len(in.Args) == 1 {\n\t\t\tomitEmptyCheckValue = in.Args[0]\n\t\t} else {\n\t\t\tomitEmptyCheckValue = in.Args\n\t\t}\n\t\tif isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, in.Where, omitEmptyCheckValue) {\n\t\t\treturn\n\t\t}\n\t\t// Usually a string.\n\t\twhereStr := gstr.Trim(gconv.String(in.Where))\n\t\t// Is `whereStr` a field name which composed as a key-value condition?\n\t\t// Eg:\n\t\t// Where(\"id\", 1)\n\t\t// Where(\"id\", g.Slice{1,2,3})\n\t\tif gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, whereStr) && len(in.Args) == 1 {\n\t\t\tnewArgs = formatWhereKeyValue(formatWhereKeyValueInput{\n\t\t\t\tDb:        db,\n\t\t\t\tBuffer:    buffer,\n\t\t\t\tArgs:      newArgs,\n\t\t\t\tKey:       whereStr,\n\t\t\t\tValue:     in.Args[0],\n\t\t\t\tOmitEmpty: in.OmitEmpty,\n\t\t\t\tPrefix:    in.Prefix,\n\t\t\t\tType:      in.Type,\n\t\t\t})\n\t\t\tin.Args = in.Args[:0]\n\t\t\tbreak\n\t\t}\n\t\t// If the first part is column name, it automatically adds prefix to the column.\n\t\tif in.Prefix != \"\" {\n\t\t\tarray := gstr.Split(whereStr, \" \")\n\t\t\tif ok, _ := db.GetCore().HasField(ctx, in.Table, array[0]); ok {\n\t\t\t\twhereStr = in.Prefix + \".\" + whereStr\n\t\t\t}\n\t\t}\n\t\t// Regular string and parameter place holder handling.\n\t\t// Eg:\n\t\t// Where(\"id in(?) and name=?\", g.Slice{1,2,3}, \"john\")\n\t\tfor i := 0; i < len(in.Args); i++ {\n\t\t\t// ===============================================================\n\t\t\t// Sub query, which is always used along with a string condition.\n\t\t\t// ===============================================================\n\t\t\tif subModel, ok := in.Args[i].(*Model); ok {\n\t\t\t\tindex := -1\n\t\t\t\twhereStr = gstr.ReplaceFunc(whereStr, `?`, func(s string) string {\n\t\t\t\t\tindex++\n\t\t\t\t\tif i+len(newArgs) == index {\n\t\t\t\t\t\tsqlWithHolder, holderArgs := subModel.getHolderAndArgsAsSubModel(ctx)\n\t\t\t\t\t\tin.Args = gutil.SliceInsertAfter(in.Args, i, holderArgs...)\n\t\t\t\t\t\t// Automatically adding the brackets.\n\t\t\t\t\t\treturn \"(\" + sqlWithHolder + \")\"\n\t\t\t\t\t}\n\t\t\t\t\treturn s\n\t\t\t\t})\n\t\t\t\tin.Args = gutil.SliceDelete(in.Args, i)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tbuffer.WriteString(whereStr)\n\t}\n\n\tif buffer.Len() == 0 {\n\t\treturn \"\", in.Args\n\t}\n\tif len(in.Args) > 0 {\n\t\tnewArgs = append(newArgs, in.Args...)\n\t}\n\tnewWhere = buffer.String()\n\tif len(newArgs) > 0 {\n\t\tif gstr.Pos(newWhere, \"?\") == -1 {\n\t\t\tif gregex.IsMatchString(lastOperatorRegPattern, newWhere) {\n\t\t\t\t// Eg: Where/And/Or(\"uid>=\", 1)\n\t\t\t\tnewWhere += \"?\"\n\t\t\t} else if gregex.IsMatchString(regularFieldNameRegPattern, newWhere) {\n\t\t\t\tnewWhere = db.GetCore().QuoteString(newWhere)\n\t\t\t\tif len(newArgs) > 0 {\n\t\t\t\t\tif utils.IsArray(newArgs[0]) {\n\t\t\t\t\t\t// Eg:\n\t\t\t\t\t\t// Where(\"id\", []int{1,2,3})\n\t\t\t\t\t\t// Where(\"user.id\", []int{1,2,3})\n\t\t\t\t\t\tnewWhere += \" IN (?)\"\n\t\t\t\t\t} else if empty.IsNil(newArgs[0]) {\n\t\t\t\t\t\t// Eg:\n\t\t\t\t\t\t// Where(\"id\", nil)\n\t\t\t\t\t\t// Where(\"user.id\", nil)\n\t\t\t\t\t\tnewWhere += \" IS NULL\"\n\t\t\t\t\t\tnewArgs = nil\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Eg:\n\t\t\t\t\t\t// Where/And/Or(\"uid\", 1)\n\t\t\t\t\t\t// Where/And/Or(\"user.uid\", 1)\n\t\t\t\t\t\tnewWhere += \"=?\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn handleSliceAndStructArgsForSql(newWhere, newArgs)\n}\n\n// formatWhereInterfaces formats `where` as []any.\nfunc formatWhereInterfaces(db DB, where []any, buffer *bytes.Buffer, newArgs []any) []any {\n\tif len(where) == 0 {\n\t\treturn newArgs\n\t}\n\tif len(where)%2 != 0 {\n\t\tbuffer.WriteString(gstr.Join(gconv.Strings(where), \"\"))\n\t\treturn newArgs\n\t}\n\tvar str string\n\tfor i := 0; i < len(where); i += 2 {\n\t\tstr = gconv.String(where[i])\n\t\tif buffer.Len() > 0 {\n\t\t\tbuffer.WriteString(\" AND \" + db.GetCore().QuoteWord(str) + \"=?\")\n\t\t} else {\n\t\t\tbuffer.WriteString(db.GetCore().QuoteWord(str) + \"=?\")\n\t\t}\n\t\tif s, ok := where[i+1].(Raw); ok {\n\t\t\tbuffer.WriteString(gconv.String(s))\n\t\t} else {\n\t\t\tnewArgs = append(newArgs, where[i+1])\n\t\t}\n\t}\n\treturn newArgs\n}\n\ntype formatWhereKeyValueInput struct {\n\tDb        DB            // Db is the underlying DB object for current operation.\n\tBuffer    *bytes.Buffer // Buffer is the sql statement string without Args for current operation.\n\tArgs      []any         // Args is the full arguments of current operation.\n\tKey       string        // The field name, eg: \"id\", \"name\", etc.\n\tValue     any           // The field value, can be any types.\n\tType      string        // The value in Where type.\n\tOmitEmpty bool          // Ignores current condition key if `value` is empty.\n\tPrefix    string        // Field prefix, eg: \"user\", \"order\", etc.\n}\n\n// formatWhereKeyValue handles each key-value pair of the parameter map.\nfunc formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []any) {\n\tvar (\n\t\tquotedKey   = in.Db.GetCore().QuoteWord(in.Key)\n\t\tholderCount = gstr.Count(quotedKey, \"?\")\n\t)\n\tif isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, quotedKey, in.Value) {\n\t\treturn in.Args\n\t}\n\tif in.Prefix != \"\" && !gstr.Contains(quotedKey, \".\") {\n\t\tquotedKey = in.Prefix + \".\" + quotedKey\n\t}\n\tif in.Buffer.Len() > 0 {\n\t\tin.Buffer.WriteString(\" AND \")\n\t}\n\t// If the value is type of slice, and there's only one '?' holder in\n\t// the key string, it automatically adds '?' holder chars according to its arguments count\n\t// and converts it to \"IN\" statement.\n\tvar (\n\t\treflectValue = reflect.ValueOf(in.Value)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\t// Check if the value implements iString interface (like uuid.UUID).\n\t// These types should be treated as single values, not arrays.\n\tif reflectKind == reflect.Array {\n\t\tif v, ok := in.Value.(iString); ok {\n\t\t\tin.Value = v.String()\n\t\t\treflectKind = reflect.String\n\t\t}\n\t}\n\tswitch reflectKind {\n\t// Slice argument.\n\tcase reflect.Slice, reflect.Array:\n\t\tif holderCount == 0 {\n\t\t\tin.Buffer.WriteString(quotedKey + \" IN(?)\")\n\t\t\tin.Args = append(in.Args, in.Value)\n\t\t} else {\n\t\t\tif holderCount != reflectValue.Len() {\n\t\t\t\tin.Buffer.WriteString(quotedKey)\n\t\t\t\tin.Args = append(in.Args, in.Value)\n\t\t\t} else {\n\t\t\t\tin.Buffer.WriteString(quotedKey)\n\t\t\t\tin.Args = append(in.Args, gconv.Interfaces(in.Value)...)\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tif in.Value == nil || empty.IsNil(reflectValue) {\n\t\t\tif gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {\n\t\t\t\t// The key is a single field name.\n\t\t\t\tin.Buffer.WriteString(quotedKey + \" IS NULL\")\n\t\t\t} else {\n\t\t\t\t// The key may have operation chars.\n\t\t\t\tin.Buffer.WriteString(quotedKey)\n\t\t\t}\n\t\t} else {\n\t\t\t// It also supports \"LIKE\" statement, which we consider it an operator.\n\t\t\tquotedKey = gstr.Trim(quotedKey)\n\t\t\tif gstr.Pos(quotedKey, \"?\") == -1 {\n\t\t\t\tlike := \" LIKE\"\n\t\t\t\tif len(quotedKey) > len(like) && gstr.Equal(quotedKey[len(quotedKey)-len(like):], like) {\n\t\t\t\t\t// Eg: Where(g.Map{\"name like\": \"john%\"})\n\t\t\t\t\tin.Buffer.WriteString(quotedKey + \" ?\")\n\t\t\t\t} else if gregex.IsMatchString(lastOperatorRegPattern, quotedKey) {\n\t\t\t\t\t// Eg: Where(g.Map{\"age > \": 16})\n\t\t\t\t\tin.Buffer.WriteString(quotedKey + \" ?\")\n\t\t\t\t} else if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {\n\t\t\t\t\t// The key is a regular field name.\n\t\t\t\t\tin.Buffer.WriteString(quotedKey + \"=?\")\n\t\t\t\t} else {\n\t\t\t\t\t// The key is not a regular field name.\n\t\t\t\t\t// Eg: Where(g.Map{\"age > 16\": nil})\n\t\t\t\t\t// Issue: https://github.com/gogf/gf/issues/765\n\t\t\t\t\tif empty.IsEmpty(in.Value) {\n\t\t\t\t\t\tin.Buffer.WriteString(quotedKey)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} else {\n\t\t\t\t\t\tin.Buffer.WriteString(quotedKey + \"=?\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tin.Buffer.WriteString(quotedKey)\n\t\t\t}\n\t\t\tin.Args = append(in.Args, in.Value)\n\t\t}\n\t}\n\treturn in.Args\n}\n\n// handleSliceAndStructArgsForSql is an important function, which handles the sql and all its arguments\n// before committing them to underlying driver.\nfunc handleSliceAndStructArgsForSql(oldSql string, oldArgs []any) (newSql string, newArgs []any) {\n\tnewSql = oldSql\n\tif len(oldArgs) == 0 {\n\t\treturn\n\t}\n\t// insertHolderCount is used to calculate the inserting position for the '?' holder.\n\tinsertHolderCount := 0\n\t// Handles the slice and struct type argument item.\n\tfor index, oldArg := range oldArgs {\n\t\targReflectInfo := reflection.OriginValueAndKind(oldArg)\n\t\tswitch argReflectInfo.OriginKind {\n\t\tcase reflect.Slice, reflect.Array:\n\t\t\t// It does not split the type of []byte.\n\t\t\t// Eg: table.Where(\"name = ?\", []byte(\"john\"))\n\t\t\tif _, ok := oldArg.([]byte); ok {\n\t\t\t\tnewArgs = append(newArgs, oldArg)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// It does not split types that implement fmt.Stringer interface (like uuid.UUID).\n\t\t\t// These types should be converted to string instead of being expanded as arrays.\n\t\t\t// Eg: table.Where(\"uuid = ?\", uuid.UUID{...})\n\t\t\tif v, ok := oldArg.(iString); ok {\n\t\t\t\tnewArgs = append(newArgs, v.String())\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tvalueHolderCount = gstr.Count(newSql, \"?\")\n\t\t\t\targSliceLength   = argReflectInfo.OriginValue.Len()\n\t\t\t)\n\t\t\tif argSliceLength == 0 {\n\t\t\t\t// Empty slice argument, it converts the sql to a false sql.\n\t\t\t\t// Example:\n\t\t\t\t// Query(\"select * from xxx where id in(?)\", g.Slice{}) -> select * from xxx where 0=1\n\t\t\t\t// Where(\"id in(?)\", g.Slice{}) -> WHERE 0=1\n\t\t\t\tif gstr.Contains(newSql, \"?\") {\n\t\t\t\t\twhereKeyWord := \" WHERE \"\n\t\t\t\t\tif p := gstr.PosI(newSql, whereKeyWord); p == -1 {\n\t\t\t\t\t\treturn \"0=1\", []any{}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn gstr.SubStr(newSql, 0, p+len(whereKeyWord)) + \"0=1\", []any{}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Example:\n\t\t\t\t// Query(\"SELECT ?+?\", g.Slice{1,2})\n\t\t\t\t// WHERE(\"id=?\", g.Slice{1,2})\n\t\t\t\tfor i := 0; i < argSliceLength; i++ {\n\t\t\t\t\tnewArgs = append(newArgs, argReflectInfo.OriginValue.Index(i).Interface())\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the '?' holder count equals the length of the slice,\n\t\t\t// it does not implement the arguments splitting logic.\n\t\t\t// Eg: db.Query(\"SELECT ?+?\", g.Slice{1, 2})\n\t\t\tif len(oldArgs) == 1 && valueHolderCount == argSliceLength {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// counter is used to finding the inserting position for the '?' holder.\n\t\t\tvar (\n\t\t\t\tcounter  = 0\n\t\t\t\treplaced = false\n\t\t\t)\n\t\t\tnewSql = gstr.ReplaceFunc(newSql, `?`, func(s string) string {\n\t\t\t\tif replaced {\n\t\t\t\t\treturn s\n\t\t\t\t}\n\t\t\t\tcounter++\n\t\t\t\tif counter == index+insertHolderCount+1 {\n\t\t\t\t\treplaced = true\n\t\t\t\t\tinsertHolderCount += argSliceLength - 1\n\t\t\t\t\treturn \"?\" + strings.Repeat(\",?\", argSliceLength-1)\n\t\t\t\t}\n\t\t\t\treturn s\n\t\t\t})\n\n\t\t\t// Special struct handling.\n\t\tcase reflect.Struct:\n\t\t\tswitch v := oldArg.(type) {\n\t\t\t// The underlying driver supports time.Time/*time.Time types.\n\t\t\tcase time.Time, *time.Time:\n\t\t\t\tnewArgs = append(newArgs, oldArg)\n\t\t\t\tcontinue\n\n\t\t\tcase gtime.Time:\n\t\t\t\tnewArgs = append(newArgs, v.Time)\n\t\t\t\tcontinue\n\n\t\t\tcase *gtime.Time:\n\t\t\t\tnewArgs = append(newArgs, v.Time)\n\t\t\t\tcontinue\n\n\t\t\tdefault:\n\t\t\t\t// It converts the struct to string in default\n\t\t\t\t// if it has implemented the String interface.\n\t\t\t\tif v, ok := oldArg.(iString); ok {\n\t\t\t\t\tnewArgs = append(newArgs, v.String())\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tnewArgs = append(newArgs, oldArg)\n\n\t\tdefault:\n\t\t\tswitch oldArg.(type) {\n\t\t\t// Do not append Raw arg to args but directly into the sql.\n\t\t\tcase Raw, *Raw:\n\t\t\t\tvar counter = 0\n\t\t\t\tnewSql = gstr.ReplaceFunc(newSql, `?`, func(s string) string {\n\t\t\t\t\tcounter++\n\t\t\t\t\tif counter == index+insertHolderCount+1 {\n\t\t\t\t\t\treturn gconv.String(oldArg)\n\t\t\t\t\t}\n\t\t\t\t\treturn s\n\t\t\t\t})\n\t\t\t\tcontinue\n\n\t\t\tdefault:\n\t\t\t}\n\t\t\tnewArgs = append(newArgs, oldArg)\n\t\t}\n\t}\n\treturn\n}\n\n// FormatSqlWithArgs binds the arguments to the sql string and returns a complete\n// sql string, just for debugging.\nfunc FormatSqlWithArgs(sql string, args []any) string {\n\tindex := -1\n\tnewQuery, _ := gregex.ReplaceStringFunc(\n\t\t`(\\?|:v\\d+|\\$\\d+|@p\\d+)`,\n\t\tsql,\n\t\tfunc(s string) string {\n\t\t\tindex++\n\t\t\tif len(args) > index {\n\t\t\t\tif args[index] == nil {\n\t\t\t\t\treturn \"null\"\n\t\t\t\t}\n\t\t\t\t// Parameters of type Raw do not require special treatment\n\t\t\t\tif v, ok := args[index].(Raw); ok {\n\t\t\t\t\treturn gconv.String(v)\n\t\t\t\t}\n\t\t\t\treflectInfo := reflection.OriginValueAndKind(args[index])\n\t\t\t\tif reflectInfo.OriginKind == reflect.Pointer &&\n\t\t\t\t\t(reflectInfo.OriginValue.IsNil() || !reflectInfo.OriginValue.IsValid()) {\n\t\t\t\t\treturn \"null\"\n\t\t\t\t}\n\t\t\t\tswitch reflectInfo.OriginKind {\n\t\t\t\tcase reflect.String, reflect.Map, reflect.Slice, reflect.Array:\n\t\t\t\t\treturn `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`\n\n\t\t\t\tcase reflect.Struct:\n\t\t\t\t\tif t, ok := args[index].(time.Time); ok {\n\t\t\t\t\t\treturn `'` + t.Format(`2006-01-02 15:04:05`) + `'`\n\t\t\t\t\t}\n\t\t\t\t\treturn `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`\n\t\t\t\t}\n\t\t\t\treturn gconv.String(args[index])\n\t\t\t}\n\t\t\treturn s\n\t\t})\n\treturn newQuery\n}\n\n// FormatMultiLineSqlToSingle formats sql template string into one line.\nfunc FormatMultiLineSqlToSingle(sql string) (string, error) {\n\tvar err error\n\t// format sql template string.\n\tsql, err = gregex.ReplaceString(`[\\n\\r\\s]+`, \" \", gstr.Trim(sql))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tsql, err = gregex.ReplaceString(`\\s{2,}`, \" \", gstr.Trim(sql))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn sql, nil\n}\n\n// genTableFieldsCacheKey generates cache key for table fields.\nfunc genTableFieldsCacheKey(group, schema, table string) string {\n\treturn fmt.Sprintf(\n\t\t`%s%s@%s#%s`,\n\t\tcachePrefixTableFields,\n\t\tgroup,\n\t\tschema,\n\t\ttable,\n\t)\n}\n\n// genSelectCacheKey generates cache key for select.\nfunc genSelectCacheKey(table, group, schema, name, sql string, args ...any) string {\n\tif name == \"\" {\n\t\tname = fmt.Sprintf(\n\t\t\t`%s@%s#%s:%d`,\n\t\t\ttable,\n\t\t\tgroup,\n\t\t\tschema,\n\t\t\tghash.BKDR64([]byte(sql+\", @PARAMS:\"+gconv.String(args))),\n\t\t)\n\t}\n\treturn fmt.Sprintf(`%s%s`, cachePrefixSelectCache, name)\n}\n\n// genTableNamesCacheKey generates cache key for table names.\nfunc genTableNamesCacheKey(group string) string {\n\treturn fmt.Sprintf(`Tables:%s`, group)\n}\n\n// genSoftTimeFieldNameTypeCacheKey generates cache key for soft time field name and type.\nfunc genSoftTimeFieldNameTypeCacheKey(schema, table string, candidateFields []string) string {\n\treturn fmt.Sprintf(`getSoftFieldNameAndType:%s#%s#%s`, schema, table, strings.Join(candidateFields, \"_\"))\n}\n"
  },
  {
    "path": "database/gdb/gdb_model.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Model is core struct implementing the DAO for ORM.\ntype Model struct {\n\tdb              DB                // Underlying DB interface.\n\ttx              TX                // Underlying TX interface.\n\trawSql          string            // rawSql is the raw SQL string which marks a raw SQL based Model not a table based Model.\n\tschema          string            // Custom database schema.\n\tlinkType        int               // Mark for operation on master or slave.\n\ttablesInit      string            // Table names when model initialization.\n\ttables          string            // Operation table names, which can be more than one table names and aliases, like: \"user\", \"user u\", \"user u, user_detail ud\".\n\tfields          []any             // Operation fields, multiple fields joined using char ','.\n\tfieldsEx        []any             // Excluded operation fields, it here uses slice instead of string type for quick filtering.\n\twithArray       []any             // Arguments for With feature.\n\twithAll         bool              // Enable model association operations on all objects that have \"with\" tag in the struct.\n\textraArgs       []any             // Extra custom arguments for sql, which are prepended to the arguments before sql committed to underlying driver.\n\twhereBuilder    *WhereBuilder     // Condition builder for where operation.\n\tgroupBy         string            // Used for \"group by\" statement.\n\torderBy         string            // Used for \"order by\" statement.\n\thaving          []any             // Used for \"having...\" statement.\n\tstart           int               // Used for \"select ... start, limit ...\" statement.\n\tlimit           int               // Used for \"select ... start, limit ...\" statement.\n\toption          int               // Option for extra operation features.\n\toffset          int               // Offset statement for some databases grammar.\n\tpartition       string            // Partition table partition name.\n\tdata            any               // Data for operation, which can be type of map/[]map/struct/*struct/string, etc.\n\tbatch           int               // Batch number for batch Insert/Replace/Save operations.\n\tfilter          bool              // Filter data and where key-value pairs according to the fields of the table.\n\tdistinct        string            // Force the query to only return distinct results.\n\tlockInfo        string            // Lock for update or in shared lock.\n\tcacheEnabled    bool              // Enable sql result cache feature, which is mainly for indicating cache duration(especially 0) usage.\n\tcacheOption     CacheOption       // Cache option for query statement.\n\tpageCacheOption []CacheOption     // Cache option for paging query statement.\n\thookHandler     HookHandler       // Hook functions for model hook feature.\n\tunscoped        bool              // Disables soft deleting features when select/delete operations.\n\tsafe            bool              // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.\n\tonDuplicate     any               // onDuplicate is used for on Upsert clause.\n\tonDuplicateEx   any               // onDuplicateEx is used for excluding some columns on Upsert clause.\n\tonConflict      any               // onConflict is used for conflict keys on Upsert clause.\n\ttableAliasMap   map[string]string // Table alias to true table name, usually used in join statements.\n\tsoftTimeOption  SoftTimeOption    // SoftTimeOption is the option to customize soft time feature for Model.\n\tshardingConfig  ShardingConfig    // ShardingConfig for database/table sharding feature.\n\tshardingValue   any               // Sharding value for sharding feature.\n}\n\n// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.\ntype ModelHandler func(m *Model) *Model\n\n// ChunkHandler is a function that is used in function Chunk, which handles given Result and error.\n// It returns true if it wants to continue chunking, or else it returns false to stop chunking.\ntype ChunkHandler func(result Result, err error) bool\n\nconst (\n\tlinkTypeMaster           = 1\n\tlinkTypeSlave            = 2\n\tdefaultField             = \"*\"\n\twhereHolderOperatorWhere = 1\n\twhereHolderOperatorAnd   = 2\n\twhereHolderOperatorOr    = 3\n\twhereHolderTypeDefault   = \"Default\"\n\twhereHolderTypeNoArgs    = \"NoArgs\"\n\twhereHolderTypeIn        = \"In\"\n)\n\n// Model creates and returns a new ORM model from given schema.\n// The parameter `tableNameQueryOrStruct` can be more than one table names, and also alias name, like:\n//  1. Model names:\n//     db.Model(\"user\")\n//     db.Model(\"user u\")\n//     db.Model(\"user, user_detail\")\n//     db.Model(\"user u, user_detail ud\")\n//  2. Model name with alias:\n//     db.Model(\"user\", \"u\")\n//  3. Model name with sub-query:\n//     db.Model(\"? AS a, ? AS b\", subQuery1, subQuery2)\nfunc (c *Core) Model(tableNameQueryOrStruct ...any) *Model {\n\tvar (\n\t\tctx       = c.db.GetCtx()\n\t\ttableStr  string\n\t\ttableName string\n\t\textraArgs []any\n\t)\n\t// Model creation with sub-query.\n\tif len(tableNameQueryOrStruct) > 1 {\n\t\tconditionStr := gconv.String(tableNameQueryOrStruct[0])\n\t\tif gstr.Contains(conditionStr, \"?\") {\n\t\t\twhereHolder := WhereHolder{\n\t\t\t\tWhere: conditionStr,\n\t\t\t\tArgs:  tableNameQueryOrStruct[1:],\n\t\t\t}\n\t\t\ttableStr, extraArgs = formatWhereHolder(ctx, c.db, formatWhereHolderInput{\n\t\t\t\tWhereHolder: whereHolder,\n\t\t\t\tOmitNil:     false,\n\t\t\t\tOmitEmpty:   false,\n\t\t\t\tSchema:      \"\",\n\t\t\t\tTable:       \"\",\n\t\t\t})\n\t\t}\n\t}\n\t// Normal model creation.\n\tif tableStr == \"\" {\n\t\ttableNames := make([]string, len(tableNameQueryOrStruct))\n\t\tfor k, v := range tableNameQueryOrStruct {\n\t\t\tif s, ok := v.(string); ok {\n\t\t\t\ttableNames[k] = s\n\t\t\t} else if tableName = getTableNameFromOrmTag(v); tableName != \"\" {\n\t\t\t\ttableNames[k] = tableName\n\t\t\t}\n\t\t}\n\t\tif len(tableNames) > 1 {\n\t\t\ttableStr = fmt.Sprintf(\n\t\t\t\t`%s AS %s`, c.QuotePrefixTableName(tableNames[0]), c.QuoteWord(tableNames[1]),\n\t\t\t)\n\t\t} else if len(tableNames) == 1 {\n\t\t\ttableStr = c.QuotePrefixTableName(tableNames[0])\n\t\t}\n\t}\n\tm := &Model{\n\t\tdb:            c.db,\n\t\tschema:        c.schema,\n\t\ttablesInit:    tableStr,\n\t\ttables:        tableStr,\n\t\tstart:         -1,\n\t\toffset:        -1,\n\t\tfilter:        true,\n\t\textraArgs:     extraArgs,\n\t\ttableAliasMap: make(map[string]string),\n\t}\n\tm.whereBuilder = m.Builder()\n\tif defaultModelSafe {\n\t\tm.safe = true\n\t}\n\treturn m\n}\n\n// Raw creates and returns a model based on a raw sql not a table.\n// Example:\n//\n//\tdb.Raw(\"SELECT * FROM `user` WHERE `name` = ?\", \"john\").Scan(&result)\nfunc (c *Core) Raw(rawSql string, args ...any) *Model {\n\tmodel := c.Model()\n\tmodel.rawSql = rawSql\n\tmodel.extraArgs = args\n\treturn model\n}\n\n// Raw sets current model as a raw sql model.\n// Example:\n//\n//\tdb.Raw(\"SELECT * FROM `user` WHERE `name` = ?\", \"john\").Scan(&result)\n//\n// See Core.Raw.\nfunc (m *Model) Raw(rawSql string, args ...any) *Model {\n\tmodel := m.db.Raw(rawSql, args...)\n\tmodel.db = m.db\n\tmodel.tx = m.tx\n\treturn model\n}\n\nfunc (tx *TXCore) Raw(rawSql string, args ...any) *Model {\n\treturn tx.Model().Raw(rawSql, args...)\n}\n\n// With creates and returns an ORM model based on metadata of given object.\nfunc (c *Core) With(objects ...any) *Model {\n\treturn c.db.Model().With(objects...)\n}\n\n// Partition sets Partition name.\n// Example:\n// dao.User.Ctx(ctx).Partition（\"p1\",\"p2\",\"p3\").All()\nfunc (m *Model) Partition(partitions ...string) *Model {\n\tmodel := m.getModel()\n\tmodel.partition = gstr.Join(partitions, \",\")\n\treturn model\n}\n\n// Model acts like Core.Model except it operates on transaction.\n// See Core.Model.\nfunc (tx *TXCore) Model(tableNameQueryOrStruct ...any) *Model {\n\tmodel := tx.db.Model(tableNameQueryOrStruct...)\n\tmodel.db = tx.db\n\tmodel.tx = tx\n\treturn model\n}\n\n// With acts like Core.With except it operates on transaction.\n// See Core.With.\nfunc (tx *TXCore) With(object any) *Model {\n\treturn tx.Model().With(object)\n}\n\n// Ctx sets the context for current operation.\nfunc (m *Model) Ctx(ctx context.Context) *Model {\n\tif ctx == nil {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tmodel.db = model.db.Ctx(ctx)\n\tif m.tx != nil {\n\t\tmodel.tx = model.tx.Ctx(ctx)\n\t}\n\treturn model\n}\n\n// GetCtx returns the context for current Model.\n// It returns `context.Background()` is there's no context previously set.\nfunc (m *Model) GetCtx() context.Context {\n\tif m.tx != nil && m.tx.GetCtx() != nil {\n\t\treturn m.tx.GetCtx()\n\t}\n\treturn m.db.GetCtx()\n}\n\n// As sets an alias name for current table.\nfunc (m *Model) As(as string) *Model {\n\tif m.tables != \"\" {\n\t\tmodel := m.getModel()\n\t\tsplit := \" JOIN \"\n\t\tif gstr.ContainsI(model.tables, split) {\n\t\t\t// For join table.\n\t\t\tarray := gstr.Split(model.tables, split)\n\t\t\tarray[len(array)-1], _ = gregex.ReplaceString(`(.+) ON`, fmt.Sprintf(`$1 AS %s ON`, as), array[len(array)-1])\n\t\t\tmodel.tables = gstr.Join(array, split)\n\t\t} else {\n\t\t\t// For base table.\n\t\t\tmodel.tables = gstr.TrimRight(model.tables) + \" AS \" + as\n\t\t}\n\t\treturn model\n\t}\n\treturn m\n}\n\n// DB sets/changes the db object for current operation.\nfunc (m *Model) DB(db DB) *Model {\n\tmodel := m.getModel()\n\tmodel.db = db\n\treturn model\n}\n\n// TX sets/changes the transaction for current operation.\nfunc (m *Model) TX(tx TX) *Model {\n\tmodel := m.getModel()\n\tmodel.db = tx.GetDB()\n\tmodel.tx = tx\n\treturn model\n}\n\n// Schema sets the schema for current operation.\nfunc (m *Model) Schema(schema string) *Model {\n\tmodel := m.getModel()\n\tmodel.schema = schema\n\treturn model\n}\n\n// Clone creates and returns a new model which is a Clone of current model.\n// Note that it uses deep-copy for the Clone.\nfunc (m *Model) Clone() *Model {\n\tnewModel := (*Model)(nil)\n\tif m.tx != nil {\n\t\tnewModel = m.tx.Model(m.tablesInit)\n\t} else {\n\t\tnewModel = m.db.Model(m.tablesInit)\n\t}\n\t// Basic attributes copy.\n\t*newModel = *m\n\t// WhereBuilder copy, note the attribute pointer.\n\tnewModel.whereBuilder = m.whereBuilder.Clone()\n\tnewModel.whereBuilder.model = newModel\n\t// Shallow copy slice attributes.\n\tif n := len(m.fields); n > 0 {\n\t\tnewModel.fields = make([]any, n)\n\t\tcopy(newModel.fields, m.fields)\n\t}\n\tif n := len(m.fieldsEx); n > 0 {\n\t\tnewModel.fieldsEx = make([]any, n)\n\t\tcopy(newModel.fieldsEx, m.fieldsEx)\n\t}\n\tif n := len(m.extraArgs); n > 0 {\n\t\tnewModel.extraArgs = make([]any, n)\n\t\tcopy(newModel.extraArgs, m.extraArgs)\n\t}\n\tif n := len(m.withArray); n > 0 {\n\t\tnewModel.withArray = make([]any, n)\n\t\tcopy(newModel.withArray, m.withArray)\n\t}\n\tif n := len(m.having); n > 0 {\n\t\tnewModel.having = make([]any, n)\n\t\tcopy(newModel.having, m.having)\n\t}\n\treturn newModel\n}\n\n// Master marks the following operation on master node.\nfunc (m *Model) Master() *Model {\n\tmodel := m.getModel()\n\tmodel.linkType = linkTypeMaster\n\treturn model\n}\n\n// Slave marks the following operation on slave node.\n// Note that it makes sense only if there's any slave node configured.\nfunc (m *Model) Slave() *Model {\n\tmodel := m.getModel()\n\tmodel.linkType = linkTypeSlave\n\treturn model\n}\n\n// Safe marks this model safe or unsafe. If safe is true, it clones and returns a new model object\n// whenever the operation done, or else it changes the attribute of current model.\nfunc (m *Model) Safe(safe ...bool) *Model {\n\tif len(safe) > 0 {\n\t\tm.safe = safe[0]\n\t} else {\n\t\tm.safe = true\n\t}\n\treturn m\n}\n\n// Args sets custom arguments for model operation.\nfunc (m *Model) Args(args ...any) *Model {\n\tmodel := m.getModel()\n\tmodel.extraArgs = append(model.extraArgs, args)\n\treturn model\n}\n\n// Handler calls each of `handlers` on current Model and returns a new Model.\n// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.\nfunc (m *Model) Handler(handlers ...ModelHandler) *Model {\n\tmodel := m.getModel()\n\tfor _, handler := range handlers {\n\t\tmodel = handler(model)\n\t}\n\treturn model\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_builder.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n)\n\n// WhereBuilder holds multiple where conditions in a group.\ntype WhereBuilder struct {\n\tmodel       *Model        // A WhereBuilder should be bound to certain Model.\n\twhereHolder []WhereHolder // Condition strings for where operation.\n}\n\n// WhereHolder is the holder for where condition preparing.\ntype WhereHolder struct {\n\tType     string // Type of this holder.\n\tOperator int    // Operator for this holder.\n\tWhere    any    // Where parameter, which can commonly be type of string/map/struct.\n\tArgs     []any  // Arguments for where parameter.\n\tPrefix   string // Field prefix, eg: \"user.\", \"order.\".\n}\n\n// Builder creates and returns a WhereBuilder. Please note that the builder is chain-safe.\nfunc (m *Model) Builder() *WhereBuilder {\n\tb := &WhereBuilder{\n\t\tmodel:       m,\n\t\twhereHolder: make([]WhereHolder, 0),\n\t}\n\treturn b\n}\n\n// getBuilder creates and returns a cloned WhereBuilder of current WhereBuilder\nfunc (b *WhereBuilder) getBuilder() *WhereBuilder {\n\treturn b.Clone()\n}\n\n// Clone clones and returns a WhereBuilder that is a copy of current one.\nfunc (b *WhereBuilder) Clone() *WhereBuilder {\n\tnewBuilder := b.model.Builder()\n\tnewBuilder.whereHolder = make([]WhereHolder, len(b.whereHolder))\n\tcopy(newBuilder.whereHolder, b.whereHolder)\n\treturn newBuilder\n}\n\n// Build builds current WhereBuilder and returns the condition string and parameters.\nfunc (b *WhereBuilder) Build() (conditionWhere string, conditionArgs []any) {\n\tvar (\n\t\tctx                         = b.model.GetCtx()\n\t\tautoPrefix                  = b.model.getAutoPrefix()\n\t\ttableForMappingAndFiltering = b.model.tables\n\t)\n\tif len(b.whereHolder) > 0 {\n\t\tfor _, holder := range b.whereHolder {\n\t\t\tif holder.Prefix == \"\" {\n\t\t\t\tholder.Prefix = autoPrefix\n\t\t\t}\n\t\t\tswitch holder.Operator {\n\t\t\tcase whereHolderOperatorWhere, whereHolderOperatorAnd:\n\t\t\t\tnewWhere, newArgs := formatWhereHolder(ctx, b.model.db, formatWhereHolderInput{\n\t\t\t\t\tWhereHolder: holder,\n\t\t\t\t\tOmitNil:     b.model.option&optionOmitNilWhere > 0,\n\t\t\t\t\tOmitEmpty:   b.model.option&optionOmitEmptyWhere > 0,\n\t\t\t\t\tSchema:      b.model.schema,\n\t\t\t\t\tTable:       tableForMappingAndFiltering,\n\t\t\t\t})\n\t\t\t\tif len(newWhere) > 0 {\n\t\t\t\t\tif len(conditionWhere) == 0 {\n\t\t\t\t\t\tconditionWhere = newWhere\n\t\t\t\t\t} else if conditionWhere[0] == '(' {\n\t\t\t\t\t\tconditionWhere = fmt.Sprintf(`%s AND (%s)`, conditionWhere, newWhere)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconditionWhere = fmt.Sprintf(`(%s) AND (%s)`, conditionWhere, newWhere)\n\t\t\t\t\t}\n\t\t\t\t\tconditionArgs = append(conditionArgs, newArgs...)\n\t\t\t\t}\n\n\t\t\tcase whereHolderOperatorOr:\n\t\t\t\tnewWhere, newArgs := formatWhereHolder(ctx, b.model.db, formatWhereHolderInput{\n\t\t\t\t\tWhereHolder: holder,\n\t\t\t\t\tOmitNil:     b.model.option&optionOmitNilWhere > 0,\n\t\t\t\t\tOmitEmpty:   b.model.option&optionOmitEmptyWhere > 0,\n\t\t\t\t\tSchema:      b.model.schema,\n\t\t\t\t\tTable:       tableForMappingAndFiltering,\n\t\t\t\t})\n\t\t\t\tif len(newWhere) > 0 {\n\t\t\t\t\tif len(conditionWhere) == 0 {\n\t\t\t\t\t\tconditionWhere = newWhere\n\t\t\t\t\t} else if conditionWhere[0] == '(' {\n\t\t\t\t\t\tconditionWhere = fmt.Sprintf(`%s OR (%s)`, conditionWhere, newWhere)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconditionWhere = fmt.Sprintf(`(%s) OR (%s)`, conditionWhere, newWhere)\n\t\t\t\t\t}\n\t\t\t\t\tconditionArgs = append(conditionArgs, newArgs...)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// convertWhereBuilder converts parameter `where` to condition string and parameters if `where` is also a WhereBuilder.\nfunc (b *WhereBuilder) convertWhereBuilder(where any, args []any) (newWhere any, newArgs []any) {\n\tvar builder *WhereBuilder\n\tswitch v := where.(type) {\n\tcase WhereBuilder:\n\t\tbuilder = &v\n\n\tcase *WhereBuilder:\n\t\tbuilder = v\n\t}\n\tif builder != nil {\n\t\tconditionWhere, conditionArgs := builder.Build()\n\t\tif conditionWhere != \"\" && (len(b.whereHolder) == 0 || len(builder.whereHolder) > 1) {\n\t\t\tconditionWhere = \"(\" + conditionWhere + \")\"\n\t\t}\n\t\treturn conditionWhere, conditionArgs\n\t}\n\treturn where, args\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_builder_where.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// doWhereType sets the condition statement for the model. The parameter `where` can be type of\n// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,\n// multiple conditions will be joined into where statement using \"AND\".\nfunc (b *WhereBuilder) doWhereType(whereType string, where any, args ...any) *WhereBuilder {\n\twhere, args = b.convertWhereBuilder(where, args)\n\n\tbuilder := b.getBuilder()\n\tif builder.whereHolder == nil {\n\t\tbuilder.whereHolder = make([]WhereHolder, 0)\n\t}\n\tif whereType == \"\" {\n\t\tif len(args) == 0 {\n\t\t\twhereType = whereHolderTypeNoArgs\n\t\t} else {\n\t\t\twhereType = whereHolderTypeDefault\n\t\t}\n\t}\n\tbuilder.whereHolder = append(builder.whereHolder, WhereHolder{\n\t\tType:     whereType,\n\t\tOperator: whereHolderOperatorWhere,\n\t\tWhere:    where,\n\t\tArgs:     args,\n\t})\n\treturn builder\n}\n\n// doWherefType builds condition string using fmt.Sprintf and arguments.\n// Note that if the number of `args` is more than the placeholder in `format`,\n// the extra `args` will be used as the where condition arguments of the Model.\nfunc (b *WhereBuilder) doWherefType(t string, format string, args ...any) *WhereBuilder {\n\tvar (\n\t\tplaceHolderCount = gstr.Count(format, \"?\")\n\t\tconditionStr     = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...)\n\t)\n\treturn b.doWhereType(t, conditionStr, args[len(args)-placeHolderCount:]...)\n}\n\n// Where sets the condition statement for the builder. The parameter `where` can be type of\n// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,\n// multiple conditions will be joined into where statement using \"AND\".\n// Eg:\n// Where(\"uid=10000\")\n// Where(\"uid\", 10000)\n// Where(\"money>? AND name like ?\", 99999, \"vip_%\")\n// Where(\"uid\", 1).Where(\"name\", \"john\")\n// Where(\"status IN (?)\", g.Slice{1,2,3})\n// Where(\"age IN(?,?)\", 18, 50)\n// Where(User{ Id : 1, UserName : \"john\"}).\nfunc (b *WhereBuilder) Where(where any, args ...any) *WhereBuilder {\n\treturn b.doWhereType(``, where, args...)\n}\n\n// Wheref builds condition string using fmt.Sprintf and arguments.\n// Note that if the number of `args` is more than the placeholder in `format`,\n// the extra `args` will be used as the where condition arguments of the Model.\n// Eg:\n// Wheref(`amount<? and status=%s`, \"paid\", 100)  => WHERE `amount`<100 and status='paid'\n// Wheref(`amount<%d and status=%s`, 100, \"paid\") => WHERE `amount`<100 and status='paid'\nfunc (b *WhereBuilder) Wheref(format string, args ...any) *WhereBuilder {\n\treturn b.doWherefType(``, format, args...)\n}\n\n// WherePri does the same logic as Model.Where except that if the parameter `where`\n// is a single condition like int/string/float/slice, it treats the condition as the primary\n// key value. That is, if primary key is \"id\" and given `where` parameter as \"123\", the\n// WherePri function treats the condition as \"id=123\", but Model.Where treats the condition\n// as string \"123\".\nfunc (b *WhereBuilder) WherePri(where any, args ...any) *WhereBuilder {\n\tif len(args) > 0 {\n\t\treturn b.Where(where, args...)\n\t}\n\tnewWhere := GetPrimaryKeyCondition(b.model.getPrimaryKey(), where)\n\treturn b.Where(newWhere[0], newWhere[1:]...)\n}\n\n// WhereLT builds `column < value` statement.\nfunc (b *WhereBuilder) WhereLT(column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s < ?`, b.model.QuoteWord(column), value)\n}\n\n// WhereLTE builds `column <= value` statement.\nfunc (b *WhereBuilder) WhereLTE(column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s <= ?`, b.model.QuoteWord(column), value)\n}\n\n// WhereGT builds `column > value` statement.\nfunc (b *WhereBuilder) WhereGT(column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s > ?`, b.model.QuoteWord(column), value)\n}\n\n// WhereGTE builds `column >= value` statement.\nfunc (b *WhereBuilder) WhereGTE(column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s >= ?`, b.model.QuoteWord(column), value)\n}\n\n// WhereBetween builds `column BETWEEN min AND max` statement.\nfunc (b *WhereBuilder) WhereBetween(column string, min, max any) *WhereBuilder {\n\treturn b.Wheref(`%s BETWEEN ? AND ?`, b.model.QuoteWord(column), min, max)\n}\n\n// WhereLike builds `column LIKE like` statement.\nfunc (b *WhereBuilder) WhereLike(column string, like string) *WhereBuilder {\n\treturn b.Wheref(`%s LIKE ?`, b.model.QuoteWord(column), like)\n}\n\n// WhereIn builds `column IN (in)` statement.\nfunc (b *WhereBuilder) WhereIn(column string, in any) *WhereBuilder {\n\treturn b.doWherefType(whereHolderTypeIn, `%s IN (?)`, b.model.QuoteWord(column), in)\n}\n\n// WhereNull builds `columns[0] IS NULL AND columns[1] IS NULL ...` statement.\nfunc (b *WhereBuilder) WhereNull(columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.Wheref(`%s IS NULL`, b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n\n// WhereNotBetween builds `column NOT BETWEEN min AND max` statement.\nfunc (b *WhereBuilder) WhereNotBetween(column string, min, max any) *WhereBuilder {\n\treturn b.Wheref(`%s NOT BETWEEN ? AND ?`, b.model.QuoteWord(column), min, max)\n}\n\n// WhereNotLike builds `column NOT LIKE like` statement.\nfunc (b *WhereBuilder) WhereNotLike(column string, like any) *WhereBuilder {\n\treturn b.Wheref(`%s NOT LIKE ?`, b.model.QuoteWord(column), like)\n}\n\n// WhereNot builds `column != value` statement.\nfunc (b *WhereBuilder) WhereNot(column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s != ?`, b.model.QuoteWord(column), value)\n}\n\n// WhereNotIn builds `column NOT IN (in)` statement.\nfunc (b *WhereBuilder) WhereNotIn(column string, in any) *WhereBuilder {\n\treturn b.doWherefType(whereHolderTypeIn, `%s NOT IN (?)`, b.model.QuoteWord(column), in)\n}\n\n// WhereNotNull builds `columns[0] IS NOT NULL AND columns[1] IS NOT NULL ...` statement.\nfunc (b *WhereBuilder) WhereNotNull(columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.Wheref(`%s IS NOT NULL`, b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n\n// WhereExists builds `EXISTS (subQuery)` statement.\nfunc (b *WhereBuilder) WhereExists(subQuery *Model) *WhereBuilder {\n\treturn b.Wheref(`EXISTS (?)`, subQuery)\n}\n\n// WhereNotExists builds `NOT EXISTS (subQuery)` statement.\nfunc (b *WhereBuilder) WhereNotExists(subQuery *Model) *WhereBuilder {\n\treturn b.Wheref(`NOT EXISTS (?)`, subQuery)\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_builder_where_prefix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// WherePrefix performs as Where, but it adds prefix to each field in where statement.\n// Eg:\n// WherePrefix(\"order\", \"status\", \"paid\")                        => WHERE `order`.`status`='paid'\n// WherePrefix(\"order\", struct{Status:\"paid\", \"channel\":\"bank\"}) => WHERE `order`.`status`='paid' AND `order`.`channel`='bank'\nfunc (b *WhereBuilder) WherePrefix(prefix string, where any, args ...any) *WhereBuilder {\n\twhere, args = b.convertWhereBuilder(where, args)\n\n\tbuilder := b.getBuilder()\n\tif builder.whereHolder == nil {\n\t\tbuilder.whereHolder = make([]WhereHolder, 0)\n\t}\n\tbuilder.whereHolder = append(builder.whereHolder, WhereHolder{\n\t\tType:     whereHolderTypeDefault,\n\t\tOperator: whereHolderOperatorWhere,\n\t\tWhere:    where,\n\t\tArgs:     args,\n\t\tPrefix:   prefix,\n\t})\n\treturn builder\n}\n\n// WherePrefixLT builds `prefix.column < value` statement.\nfunc (b *WhereBuilder) WherePrefixLT(prefix string, column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s < ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WherePrefixLTE builds `prefix.column <= value` statement.\nfunc (b *WhereBuilder) WherePrefixLTE(prefix string, column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s <= ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WherePrefixGT builds `prefix.column > value` statement.\nfunc (b *WhereBuilder) WherePrefixGT(prefix string, column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s > ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WherePrefixGTE builds `prefix.column >= value` statement.\nfunc (b *WhereBuilder) WherePrefixGTE(prefix string, column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s >= ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WherePrefixBetween builds `prefix.column BETWEEN min AND max` statement.\nfunc (b *WhereBuilder) WherePrefixBetween(prefix string, column string, min, max any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s BETWEEN ? AND ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), min, max)\n}\n\n// WherePrefixLike builds `prefix.column LIKE like` statement.\nfunc (b *WhereBuilder) WherePrefixLike(prefix string, column string, like any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s LIKE ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), like)\n}\n\n// WherePrefixIn builds `prefix.column IN (in)` statement.\nfunc (b *WhereBuilder) WherePrefixIn(prefix string, column string, in any) *WhereBuilder {\n\treturn b.doWherefType(whereHolderTypeIn, `%s.%s IN (?)`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), in)\n}\n\n// WherePrefixNull builds `prefix.columns[0] IS NULL AND prefix.columns[1] IS NULL ...` statement.\nfunc (b *WhereBuilder) WherePrefixNull(prefix string, columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.Wheref(`%s.%s IS NULL`, b.model.QuoteWord(prefix), b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n\n// WherePrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement.\nfunc (b *WhereBuilder) WherePrefixNotBetween(prefix string, column string, min, max any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s NOT BETWEEN ? AND ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), min, max)\n}\n\n// WherePrefixNotLike builds `prefix.column NOT LIKE like` statement.\nfunc (b *WhereBuilder) WherePrefixNotLike(prefix string, column string, like any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s NOT LIKE ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), like)\n}\n\n// WherePrefixNot builds `prefix.column != value` statement.\nfunc (b *WhereBuilder) WherePrefixNot(prefix string, column string, value any) *WhereBuilder {\n\treturn b.Wheref(`%s.%s != ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WherePrefixNotIn builds `prefix.column NOT IN (in)` statement.\nfunc (b *WhereBuilder) WherePrefixNotIn(prefix string, column string, in any) *WhereBuilder {\n\treturn b.doWherefType(whereHolderTypeIn, `%s.%s NOT IN (?)`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), in)\n}\n\n// WherePrefixNotNull builds `prefix.columns[0] IS NOT NULL AND prefix.columns[1] IS NOT NULL ...` statement.\nfunc (b *WhereBuilder) WherePrefixNotNull(prefix string, columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.Wheref(`%s.%s IS NOT NULL`, b.model.QuoteWord(prefix), b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_builder_whereor.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// WhereOr adds \"OR\" condition to the where statement.\nfunc (b *WhereBuilder) doWhereOrType(t string, where any, args ...any) *WhereBuilder {\n\twhere, args = b.convertWhereBuilder(where, args)\n\n\tbuilder := b.getBuilder()\n\tif builder.whereHolder == nil {\n\t\tbuilder.whereHolder = make([]WhereHolder, 0)\n\t}\n\tbuilder.whereHolder = append(builder.whereHolder, WhereHolder{\n\t\tType:     t,\n\t\tOperator: whereHolderOperatorOr,\n\t\tWhere:    where,\n\t\tArgs:     args,\n\t})\n\treturn builder\n}\n\n// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.\nfunc (b *WhereBuilder) doWhereOrfType(t string, format string, args ...any) *WhereBuilder {\n\tvar (\n\t\tplaceHolderCount = gstr.Count(format, \"?\")\n\t\tconditionStr     = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...)\n\t)\n\treturn b.doWhereOrType(t, conditionStr, args[len(args)-placeHolderCount:]...)\n}\n\n// WhereOr adds \"OR\" condition to the where statement.\nfunc (b *WhereBuilder) WhereOr(where any, args ...any) *WhereBuilder {\n\treturn b.doWhereOrType(``, where, args...)\n}\n\n// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.\n// Eg:\n// WhereOrf(`amount<? and status=%s`, \"paid\", 100)  => WHERE xxx OR `amount`<100 and status='paid'\n// WhereOrf(`amount<%d and status=%s`, 100, \"paid\") => WHERE xxx OR `amount`<100 and status='paid'\nfunc (b *WhereBuilder) WhereOrf(format string, args ...any) *WhereBuilder {\n\treturn b.doWhereOrfType(``, format, args...)\n}\n\n// WhereOrNot builds `column != value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrNot(column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s != ?`, column, value)\n}\n\n// WhereOrLT builds `column < value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrLT(column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s < ?`, column, value)\n}\n\n// WhereOrLTE builds `column <= value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrLTE(column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s <= ?`, column, value)\n}\n\n// WhereOrGT builds `column > value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrGT(column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s > ?`, column, value)\n}\n\n// WhereOrGTE builds `column >= value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrGTE(column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s >= ?`, column, value)\n}\n\n// WhereOrBetween builds `column BETWEEN min AND max` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrBetween(column string, min, max any) *WhereBuilder {\n\treturn b.WhereOrf(`%s BETWEEN ? AND ?`, b.model.QuoteWord(column), min, max)\n}\n\n// WhereOrLike builds `column LIKE 'like'` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrLike(column string, like any) *WhereBuilder {\n\treturn b.WhereOrf(`%s LIKE ?`, b.model.QuoteWord(column), like)\n}\n\n// WhereOrIn builds `column IN (in)` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrIn(column string, in any) *WhereBuilder {\n\treturn b.doWhereOrfType(whereHolderTypeIn, `%s IN (?)`, b.model.QuoteWord(column), in)\n}\n\n// WhereOrNull builds `columns[0] IS NULL OR columns[1] IS NULL ...` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrNull(columns ...string) *WhereBuilder {\n\tvar builder *WhereBuilder\n\tfor _, column := range columns {\n\t\tbuilder = b.WhereOrf(`%s IS NULL`, b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n\n// WhereOrNotBetween builds `column NOT BETWEEN min AND max` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrNotBetween(column string, min, max any) *WhereBuilder {\n\treturn b.WhereOrf(`%s NOT BETWEEN ? AND ?`, b.model.QuoteWord(column), min, max)\n}\n\n// WhereOrNotLike builds `column NOT LIKE like` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrNotLike(column string, like any) *WhereBuilder {\n\treturn b.WhereOrf(`%s NOT LIKE ?`, b.model.QuoteWord(column), like)\n}\n\n// WhereOrNotIn builds `column NOT IN (in)` statement.\nfunc (b *WhereBuilder) WhereOrNotIn(column string, in any) *WhereBuilder {\n\treturn b.doWhereOrfType(whereHolderTypeIn, `%s NOT IN (?)`, b.model.QuoteWord(column), in)\n}\n\n// WhereOrNotNull builds `columns[0] IS NOT NULL OR columns[1] IS NOT NULL ...` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrNotNull(columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.WhereOrf(`%s IS NOT NULL`, b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_builder_whereor_prefix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// WhereOrPrefix performs as WhereOr, but it adds prefix to each field in where statement.\n// Eg:\n// WhereOrPrefix(\"order\", \"status\", \"paid\")                        => WHERE xxx OR (`order`.`status`='paid')\n// WhereOrPrefix(\"order\", struct{Status:\"paid\", \"channel\":\"bank\"}) => WHERE xxx OR (`order`.`status`='paid' AND `order`.`channel`='bank')\nfunc (b *WhereBuilder) WhereOrPrefix(prefix string, where any, args ...any) *WhereBuilder {\n\twhere, args = b.convertWhereBuilder(where, args)\n\n\tbuilder := b.getBuilder()\n\tbuilder.whereHolder = append(builder.whereHolder, WhereHolder{\n\t\tType:     whereHolderTypeDefault,\n\t\tOperator: whereHolderOperatorOr,\n\t\tWhere:    where,\n\t\tArgs:     args,\n\t\tPrefix:   prefix,\n\t})\n\treturn builder\n}\n\n// WhereOrPrefixNot builds `prefix.column != value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixNot(prefix string, column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s != ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WhereOrPrefixLT builds `prefix.column < value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixLT(prefix string, column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s < ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WhereOrPrefixLTE builds `prefix.column <= value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixLTE(prefix string, column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s <= ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WhereOrPrefixGT builds `prefix.column > value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixGT(prefix string, column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s > ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WhereOrPrefixGTE builds `prefix.column >= value` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixGTE(prefix string, column string, value any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s >= ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), value)\n}\n\n// WhereOrPrefixBetween builds `prefix.column BETWEEN min AND max` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixBetween(prefix string, column string, min, max any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s BETWEEN ? AND ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), min, max)\n}\n\n// WhereOrPrefixLike builds `prefix.column LIKE 'like'` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixLike(prefix string, column string, like any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s LIKE ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), like)\n}\n\n// WhereOrPrefixIn builds `prefix.column IN (in)` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixIn(prefix string, column string, in any) *WhereBuilder {\n\treturn b.doWhereOrfType(whereHolderTypeIn, `%s.%s IN (?)`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), in)\n}\n\n// WhereOrPrefixNull builds `prefix.columns[0] IS NULL OR prefix.columns[1] IS NULL ...` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixNull(prefix string, columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.WhereOrf(`%s.%s IS NULL`, b.model.QuoteWord(prefix), b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n\n// WhereOrPrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixNotBetween(prefix string, column string, min, max any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s NOT BETWEEN ? AND ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), min, max)\n}\n\n// WhereOrPrefixNotLike builds `prefix.column NOT LIKE 'like'` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixNotLike(prefix string, column string, like any) *WhereBuilder {\n\treturn b.WhereOrf(`%s.%s NOT LIKE ?`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), like)\n}\n\n// WhereOrPrefixNotIn builds `prefix.column NOT IN (in)` statement.\nfunc (b *WhereBuilder) WhereOrPrefixNotIn(prefix string, column string, in any) *WhereBuilder {\n\treturn b.doWhereOrfType(whereHolderTypeIn, `%s.%s NOT IN (?)`, b.model.QuoteWord(prefix), b.model.QuoteWord(column), in)\n}\n\n// WhereOrPrefixNotNull builds `prefix.columns[0] IS NOT NULL OR prefix.columns[1] IS NOT NULL ...` statement in `OR` conditions.\nfunc (b *WhereBuilder) WhereOrPrefixNotNull(prefix string, columns ...string) *WhereBuilder {\n\tbuilder := b\n\tfor _, column := range columns {\n\t\tbuilder = builder.WhereOrf(`%s.%s IS NOT NULL`, b.model.QuoteWord(prefix), b.model.QuoteWord(column))\n\t}\n\treturn builder\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_cache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// CacheOption is options for model cache control in query.\ntype CacheOption struct {\n\t// Duration is the TTL for the cache.\n\t// If the parameter `Duration` < 0, which means it clear the cache with given `Name`.\n\t// If the parameter `Duration` = 0, which means it never expires.\n\t// If the parameter `Duration` > 0, which means it expires after `Duration`.\n\tDuration time.Duration\n\n\t// Name is an optional unique name for the cache.\n\t// The Name is used to bind a name to the cache, which means you can later control the cache\n\t// like changing the `duration` or clearing the cache with specified Name.\n\tName string\n\n\t// Force caches the query result whatever the result is nil or not.\n\t// It is used to avoid Cache Penetration.\n\tForce bool\n}\n\n// selectCacheItem is the cache item for SELECT statement result.\ntype selectCacheItem struct {\n\tResult            Result // Sql result of SELECT statement.\n\tFirstResultColumn string // The first column name of result, for Value/Count functions.\n}\n\n// Cache sets the cache feature for the model. It caches the result of the sql, which means\n// if there's another same sql request, it just reads and returns the result from cache, it\n// but not committed and executed into the database.\n//\n// Note that, the cache feature is disabled if the model is performing select statement\n// on a transaction.\nfunc (m *Model) Cache(option CacheOption) *Model {\n\tmodel := m.getModel()\n\tmodel.cacheOption = option\n\tmodel.cacheEnabled = true\n\treturn model\n}\n\n// PageCache sets the cache feature for pagination queries. It allows to configure\n// separate cache options for count query and data query in pagination.\n//\n// Note that, the cache feature is disabled if the model is performing select statement\n// on a transaction.\nfunc (m *Model) PageCache(countOption CacheOption, dataOption CacheOption) *Model {\n\tmodel := m.getModel()\n\tmodel.pageCacheOption = []CacheOption{countOption, dataOption}\n\tmodel.cacheEnabled = true\n\treturn model\n}\n\n// checkAndRemoveSelectCache checks and removes the cache in insert/update/delete statement if\n// cache feature is enabled.\nfunc (m *Model) checkAndRemoveSelectCache(ctx context.Context) {\n\tif m.cacheEnabled && m.cacheOption.Duration < 0 && len(m.cacheOption.Name) > 0 {\n\t\tvar cacheKey = m.makeSelectCacheKey(\"\")\n\t\tif _, err := m.db.GetCache().Remove(ctx, cacheKey); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}\n}\n\nfunc (m *Model) getSelectResultFromCache(ctx context.Context, sql string, args ...any) (result Result, err error) {\n\tif !m.cacheEnabled || m.tx != nil {\n\t\treturn\n\t}\n\tvar (\n\t\tcacheItem *selectCacheItem\n\t\tcacheKey  = m.makeSelectCacheKey(sql, args...)\n\t\tcacheObj  = m.db.GetCache()\n\t\tcore      = m.db.GetCore()\n\t)\n\tdefer func() {\n\t\tif cacheItem != nil {\n\t\t\tif internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {\n\t\t\t\tif cacheItem.FirstResultColumn != \"\" {\n\t\t\t\t\tinternalData.FirstResultColumn = cacheItem.FirstResultColumn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\tif v, _ := cacheObj.Get(ctx, cacheKey); !v.IsNil() {\n\t\tif err = v.Scan(&cacheItem); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn cacheItem.Result, nil\n\t}\n\treturn\n}\n\nfunc (m *Model) saveSelectResultToCache(\n\tctx context.Context, selectType SelectType, result Result, sql string, args ...any,\n) (err error) {\n\tif !m.cacheEnabled || m.tx != nil {\n\t\treturn\n\t}\n\tvar (\n\t\tcacheKey = m.makeSelectCacheKey(sql, args...)\n\t\tcacheObj = m.db.GetCache()\n\t)\n\tif m.cacheOption.Duration < 0 {\n\t\tif _, errCache := cacheObj.Remove(ctx, cacheKey); errCache != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, errCache)\n\t\t}\n\t\treturn\n\t}\n\t// Special handler for Value/Count operations result.\n\tif len(result) > 0 {\n\t\tvar core = m.db.GetCore()\n\t\tswitch selectType {\n\t\tcase SelectTypeValue, SelectTypeArray, SelectTypeCount:\n\t\t\tif internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {\n\t\t\t\tif result[0][internalData.FirstResultColumn].IsEmpty() {\n\t\t\t\t\tresult = nil\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t}\n\t}\n\n\t// In case of Cache Penetration.\n\tif result != nil && result.IsEmpty() {\n\t\tif m.cacheOption.Force {\n\t\t\tresult = Result{}\n\t\t} else {\n\t\t\tresult = nil\n\t\t}\n\t}\n\tvar (\n\t\tcore      = m.db.GetCore()\n\t\tcacheItem = &selectCacheItem{\n\t\t\tResult: result,\n\t\t}\n\t)\n\tif internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {\n\t\tcacheItem.FirstResultColumn = internalData.FirstResultColumn\n\t}\n\tif errCache := cacheObj.Set(ctx, cacheKey, cacheItem, m.cacheOption.Duration); errCache != nil {\n\t\tintlog.Errorf(ctx, `%+v`, errCache)\n\t}\n\treturn\n}\n\nfunc (m *Model) makeSelectCacheKey(sql string, args ...any) string {\n\tvar (\n\t\ttable      = m.db.GetCore().guessPrimaryTableName(m.tables)\n\t\tgroup      = m.db.GetGroup()\n\t\tschema     = m.db.GetSchema()\n\t\tcustomName = m.cacheOption.Name\n\t)\n\treturn genSelectCacheKey(\n\t\ttable,\n\t\tgroup,\n\t\tschema,\n\t\tcustomName,\n\t\tsql,\n\t\targs...,\n\t)\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_delete.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Delete does \"DELETE FROM ... \" statement for the model.\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) Delete(where ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(where) > 0 {\n\t\treturn m.Where(where[0], where[1:]...).Delete()\n\t}\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tm.checkAndRemoveSelectCache(ctx)\n\t\t}\n\t}()\n\tvar (\n\t\tconditionWhere, conditionExtra, conditionArgs = m.formatCondition(ctx, false, false)\n\t\tconditionStr                                  = conditionWhere + conditionExtra\n\t\tfieldNameDelete, fieldTypeDelete              = m.softTimeMaintainer().GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldDelete)\n\t)\n\tif m.unscoped {\n\t\tfieldNameDelete = \"\"\n\t}\n\tif !gstr.ContainsI(conditionStr, \" WHERE \") || (fieldNameDelete != \"\" && !gstr.ContainsI(conditionStr, \" AND \")) {\n\t\tintlog.Printf(\n\t\t\tctx,\n\t\t\t`sql condition string \"%s\" has no WHERE for DELETE operation, fieldNameDelete: %s`,\n\t\t\tconditionStr, fieldNameDelete,\n\t\t)\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t\"there should be WHERE condition statement for DELETE operation\",\n\t\t)\n\t}\n\n\t// Soft deleting.\n\tif fieldNameDelete != \"\" {\n\t\tdataHolder, dataValue := m.softTimeMaintainer().GetDeleteData(\n\t\t\tctx, \"\", fieldNameDelete, fieldTypeDelete,\n\t\t)\n\t\tin := &HookUpdateInput{\n\t\t\tinternalParamHookUpdate: internalParamHookUpdate{\n\t\t\t\tinternalParamHook: internalParamHook{\n\t\t\t\t\tlink: m.getLink(true),\n\t\t\t\t},\n\t\t\t\thandler: m.hookHandler.Update,\n\t\t\t},\n\t\t\tModel:     m,\n\t\t\tTable:     m.tables,\n\t\t\tSchema:    m.schema,\n\t\t\tData:      dataHolder,\n\t\t\tCondition: conditionStr,\n\t\t\tArgs:      append([]any{dataValue}, conditionArgs...),\n\t\t}\n\t\treturn in.Next(ctx)\n\t}\n\n\tin := &HookDeleteInput{\n\t\tinternalParamHookDelete: internalParamHookDelete{\n\t\t\tinternalParamHook: internalParamHook{\n\t\t\t\tlink: m.getLink(true),\n\t\t\t},\n\t\t\thandler: m.hookHandler.Delete,\n\t\t},\n\t\tModel:     m,\n\t\tTable:     m.tables,\n\t\tSchema:    m.schema,\n\t\tCondition: conditionStr,\n\t\tArgs:      conditionArgs,\n\t}\n\treturn in.Next(ctx)\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_fields.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Fields appends `fieldNamesOrMapStruct` to the operation fields of the model, multiple fields joined using char ','.\n// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.\n//\n// Example:\n// Fields(\"id\", \"name\", \"age\")\n// Fields([]string{\"id\", \"name\", \"age\"})\n// Fields(map[string]any{\"id\":1, \"name\":\"john\", \"age\":18})\n// Fields(User{Id: 1, Name: \"john\", Age: 18}).\nfunc (m *Model) Fields(fieldNamesOrMapStruct ...any) *Model {\n\tlength := len(fieldNamesOrMapStruct)\n\tif length == 0 {\n\t\treturn m\n\t}\n\tfields := m.filterFieldsFrom(m.tablesInit, fieldNamesOrMapStruct...)\n\tif len(fields) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(fields...)\n}\n\n// FieldsPrefix performs as function Fields but add extra prefix for each field.\nfunc (m *Model) FieldsPrefix(prefixOrAlias string, fieldNamesOrMapStruct ...any) *Model {\n\tfields := m.filterFieldsFrom(\n\t\tm.getTableNameByPrefixOrAlias(prefixOrAlias),\n\t\tfieldNamesOrMapStruct...,\n\t)\n\tif len(fields) == 0 {\n\t\treturn m\n\t}\n\tprefixOrAlias = m.QuoteWord(prefixOrAlias)\n\tfor i, field := range fields {\n\t\tfields[i] = fmt.Sprintf(\"%s.%s\", prefixOrAlias, m.QuoteWord(gconv.String(field)))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(fields...)\n}\n\n// FieldsEx appends `fieldNamesOrMapStruct` to the excluded operation fields of the model,\n// multiple fields joined using char ','.\n// Note that this function supports only single table operations.\n// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.\n//\n// Example:\n// FieldsEx(\"id\", \"name\", \"age\")\n// FieldsEx([]string{\"id\", \"name\", \"age\"})\n// FieldsEx(map[string]any{\"id\":1, \"name\":\"john\", \"age\":18})\n// FieldsEx(User{Id: 1, Name: \"john\", Age: 18}).\nfunc (m *Model) FieldsEx(fieldNamesOrMapStruct ...any) *Model {\n\treturn m.doFieldsEx(m.tablesInit, fieldNamesOrMapStruct...)\n}\n\nfunc (m *Model) doFieldsEx(table string, fieldNamesOrMapStruct ...any) *Model {\n\tlength := len(fieldNamesOrMapStruct)\n\tif length == 0 {\n\t\treturn m\n\t}\n\tfields := m.filterFieldsFrom(table, fieldNamesOrMapStruct...)\n\tif len(fields) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tmodel.fieldsEx = append(model.fieldsEx, fields...)\n\treturn model\n}\n\n// FieldsExPrefix performs as function FieldsEx but add extra prefix for each field.\n// Note that this function must be used together with FieldsPrefix, otherwise it will be invalid.\nfunc (m *Model) FieldsExPrefix(prefixOrAlias string, fieldNamesOrMapStruct ...any) *Model {\n\tfields := m.filterFieldsFrom(\n\t\tm.getTableNameByPrefixOrAlias(prefixOrAlias),\n\t\tfieldNamesOrMapStruct...,\n\t)\n\tif len(fields) == 0 {\n\t\treturn m\n\t}\n\tprefixOrAlias = m.QuoteWord(prefixOrAlias)\n\tfor i, field := range fields {\n\t\tfields[i] = fmt.Sprintf(\"%s.%s\", prefixOrAlias, m.QuoteWord(gconv.String(field)))\n\t}\n\tmodel := m.getModel()\n\tmodel.fieldsEx = append(model.fieldsEx, fields...)\n\treturn model\n}\n\n// FieldCount formats and appends commonly used field `COUNT(column)` to the select fields of model.\nfunc (m *Model) FieldCount(column string, as ...string) *Model {\n\tasStr := \"\"\n\tif len(as) > 0 && as[0] != \"\" {\n\t\tasStr = fmt.Sprintf(` AS %s`, m.QuoteWord(as[0]))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(\n\t\tfmt.Sprintf(`COUNT(%s)%s`, m.QuoteWord(column), asStr),\n\t)\n}\n\n// FieldSum formats and appends commonly used field `SUM(column)` to the select fields of model.\nfunc (m *Model) FieldSum(column string, as ...string) *Model {\n\tasStr := \"\"\n\tif len(as) > 0 && as[0] != \"\" {\n\t\tasStr = fmt.Sprintf(` AS %s`, m.QuoteWord(as[0]))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(\n\t\tfmt.Sprintf(`SUM(%s)%s`, m.QuoteWord(column), asStr),\n\t)\n}\n\n// FieldMin formats and appends commonly used field `MIN(column)` to the select fields of model.\nfunc (m *Model) FieldMin(column string, as ...string) *Model {\n\tasStr := \"\"\n\tif len(as) > 0 && as[0] != \"\" {\n\t\tasStr = fmt.Sprintf(` AS %s`, m.QuoteWord(as[0]))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(\n\t\tfmt.Sprintf(`MIN(%s)%s`, m.QuoteWord(column), asStr),\n\t)\n}\n\n// FieldMax formats and appends commonly used field `MAX(column)` to the select fields of model.\nfunc (m *Model) FieldMax(column string, as ...string) *Model {\n\tasStr := \"\"\n\tif len(as) > 0 && as[0] != \"\" {\n\t\tasStr = fmt.Sprintf(` AS %s`, m.QuoteWord(as[0]))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(\n\t\tfmt.Sprintf(`MAX(%s)%s`, m.QuoteWord(column), asStr),\n\t)\n}\n\n// FieldAvg formats and appends commonly used field `AVG(column)` to the select fields of model.\nfunc (m *Model) FieldAvg(column string, as ...string) *Model {\n\tasStr := \"\"\n\tif len(as) > 0 && as[0] != \"\" {\n\t\tasStr = fmt.Sprintf(` AS %s`, m.QuoteWord(as[0]))\n\t}\n\tmodel := m.getModel()\n\treturn model.appendToFields(\n\t\tfmt.Sprintf(`AVG(%s)%s`, m.QuoteWord(column), asStr),\n\t)\n}\n\n// GetFieldsStr retrieves and returns all fields from the table, joined with char ','.\n// The optional parameter `prefix` specifies the prefix for each field, eg: GetFieldsStr(\"u.\").\nfunc (m *Model) GetFieldsStr(prefix ...string) string {\n\tprefixStr := \"\"\n\tif len(prefix) > 0 {\n\t\tprefixStr = prefix[0]\n\t}\n\ttableFields, err := m.TableFields(m.tablesInit)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif len(tableFields) == 0 {\n\t\tpanic(fmt.Sprintf(`empty table fields for table \"%s\"`, m.tables))\n\t}\n\tfieldsArray := make([]string, len(tableFields))\n\tfor k, v := range tableFields {\n\t\tfieldsArray[v.Index] = k\n\t}\n\tnewFields := \"\"\n\tfor _, k := range fieldsArray {\n\t\tif len(newFields) > 0 {\n\t\t\tnewFields += \",\"\n\t\t}\n\t\tnewFields += prefixStr + k\n\t}\n\tnewFields = m.db.GetCore().QuoteString(newFields)\n\treturn newFields\n}\n\n// GetFieldsExStr retrieves and returns fields which are not in parameter `fields` from the table,\n// joined with char ','.\n// The parameter `fields` specifies the fields that are excluded.\n// The optional parameter `prefix` specifies the prefix for each field, eg: FieldsExStr(\"id\", \"u.\").\nfunc (m *Model) GetFieldsExStr(fields string, prefix ...string) (string, error) {\n\tprefixStr := \"\"\n\tif len(prefix) > 0 {\n\t\tprefixStr = prefix[0]\n\t}\n\ttableFields, err := m.TableFields(m.tablesInit)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(tableFields) == 0 {\n\t\treturn \"\", gerror.Newf(`empty table fields for table \"%s\"`, m.tables)\n\t}\n\tfieldsExSet := gset.NewStrSetFrom(gstr.SplitAndTrim(fields, \",\"))\n\tfieldsArray := make([]string, len(tableFields))\n\tfor k, v := range tableFields {\n\t\tfieldsArray[v.Index] = k\n\t}\n\tnewFields := \"\"\n\tfor _, k := range fieldsArray {\n\t\tif fieldsExSet.Contains(k) {\n\t\t\tcontinue\n\t\t}\n\t\tif len(newFields) > 0 {\n\t\t\tnewFields += \",\"\n\t\t}\n\t\tnewFields += prefixStr + k\n\t}\n\tnewFields = m.db.GetCore().QuoteString(newFields)\n\treturn newFields, nil\n}\n\n// HasField determine whether the field exists in the table.\nfunc (m *Model) HasField(field string) (bool, error) {\n\treturn m.db.GetCore().HasField(m.GetCtx(), m.tablesInit, field)\n}\n\n// getFieldsFrom retrieves, filters and returns fields name from table `table`.\nfunc (m *Model) filterFieldsFrom(table string, fieldNamesOrMapStruct ...any) []any {\n\tlength := len(fieldNamesOrMapStruct)\n\tif length == 0 {\n\t\treturn nil\n\t}\n\tswitch {\n\t// String slice.\n\tcase length >= 2:\n\t\treturn m.mappingAndFilterToTableFields(\n\t\t\ttable, fieldNamesOrMapStruct, true,\n\t\t)\n\n\t// It needs type asserting.\n\tcase length == 1:\n\t\tstructOrMap := fieldNamesOrMapStruct[0]\n\t\tswitch r := structOrMap.(type) {\n\t\tcase string:\n\t\t\treturn m.mappingAndFilterToTableFields(table, []any{r}, false)\n\n\t\tcase []string:\n\t\t\treturn m.mappingAndFilterToTableFields(table, gconv.Interfaces(r), true)\n\n\t\tcase Raw, *Raw:\n\t\t\treturn []any{structOrMap}\n\n\t\tdefault:\n\t\t\treturn m.mappingAndFilterToTableFields(table, getFieldsFromStructOrMap(structOrMap), true)\n\t\t}\n\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc (m *Model) appendToFields(fields ...any) *Model {\n\tif len(fields) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tmodel.fields = append(model.fields, fields...)\n\treturn model\n}\n\nfunc (m *Model) isFieldInFieldsEx(field string) bool {\n\tfor _, v := range m.fieldsEx {\n\t\tif v == field {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_hook.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype (\n\tHookFuncSelect func(ctx context.Context, in *HookSelectInput) (result Result, err error)\n\tHookFuncInsert func(ctx context.Context, in *HookInsertInput) (result sql.Result, err error)\n\tHookFuncUpdate func(ctx context.Context, in *HookUpdateInput) (result sql.Result, err error)\n\tHookFuncDelete func(ctx context.Context, in *HookDeleteInput) (result sql.Result, err error)\n)\n\n// HookHandler manages all supported hook functions for Model.\ntype HookHandler struct {\n\tSelect HookFuncSelect\n\tInsert HookFuncInsert\n\tUpdate HookFuncUpdate\n\tDelete HookFuncDelete\n}\n\n// internalParamHook manages all internal parameters for hook operations.\n// The `internal` obviously means you cannot access these parameters outside this package.\ntype internalParamHook struct {\n\tlink               Link      // Connection object from third party sql driver.\n\thandlerCalled      bool      // Simple mark for custom handler called, in case of recursive calling.\n\tremovedWhere       bool      // Removed mark for condition string that was removed `WHERE` prefix.\n\toriginalTableName  *gvar.Var // The original table name.\n\toriginalSchemaName *gvar.Var // The original schema name.\n}\n\ntype internalParamHookSelect struct {\n\tinternalParamHook\n\thandler HookFuncSelect\n}\n\ntype internalParamHookInsert struct {\n\tinternalParamHook\n\thandler HookFuncInsert\n}\n\ntype internalParamHookUpdate struct {\n\tinternalParamHook\n\thandler HookFuncUpdate\n}\n\ntype internalParamHookDelete struct {\n\tinternalParamHook\n\thandler HookFuncDelete\n}\n\n// HookSelectInput holds the parameters for select hook operation.\n// Note that, COUNT statement will also be hooked by this feature,\n// which is usually not be interesting for upper business hook handler.\ntype HookSelectInput struct {\n\tinternalParamHookSelect\n\tModel      *Model     // Current operation Model.\n\tTable      string     // The table name that to be used. Update this attribute to change target table name.\n\tSchema     string     // The schema name that to be used. Update this attribute to change target schema name.\n\tSql        string     // The sql string that to be committed.\n\tArgs       []any      // The arguments of sql.\n\tSelectType SelectType // The type of this SELECT operation.\n}\n\n// HookInsertInput holds the parameters for insert hook operation.\ntype HookInsertInput struct {\n\tinternalParamHookInsert\n\tModel  *Model         // Current operation Model.\n\tTable  string         // The table name that to be used. Update this attribute to change target table name.\n\tSchema string         // The schema name that to be used. Update this attribute to change target schema name.\n\tData   List           // The data records list to be inserted/saved into table.\n\tOption DoInsertOption // The extra option for data inserting.\n}\n\n// HookUpdateInput holds the parameters for update hook operation.\ntype HookUpdateInput struct {\n\tinternalParamHookUpdate\n\tModel     *Model // Current operation Model.\n\tTable     string // The table name that to be used. Update this attribute to change target table name.\n\tSchema    string // The schema name that to be used. Update this attribute to change target schema name.\n\tData      any    // Data can be type of: map[string]any/string. You can use type assertion on `Data`.\n\tCondition string // The where condition string for updating.\n\tArgs      []any  // The arguments for sql place-holders.\n}\n\n// HookDeleteInput holds the parameters for delete hook operation.\ntype HookDeleteInput struct {\n\tinternalParamHookDelete\n\tModel     *Model // Current operation Model.\n\tTable     string // The table name that to be used. Update this attribute to change target table name.\n\tSchema    string // The schema name that to be used. Update this attribute to change target schema name.\n\tCondition string // The where condition string for deleting.\n\tArgs      []any  // The arguments for sql place-holders.\n}\n\nconst (\n\twhereKeyInCondition = \" WHERE \"\n)\n\n// IsTransaction checks and returns whether current operation is during transaction.\nfunc (h *internalParamHook) IsTransaction() bool {\n\treturn h.link.IsTransaction()\n}\n\n// Next calls the next hook handler.\nfunc (h *HookSelectInput) Next(ctx context.Context) (result Result, err error) {\n\tif h.originalTableName.IsNil() {\n\t\th.originalTableName = gvar.New(h.Table)\n\t}\n\tif h.originalSchemaName.IsNil() {\n\t\th.originalSchemaName = gvar.New(h.Schema)\n\t}\n\n\t// Sharding feature.\n\th.Schema, err = h.Model.getActualSchema(ctx, h.Schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th.Table, err = h.Model.getActualTable(ctx, h.Table)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Custom hook handler call.\n\tif h.handler != nil && !h.handlerCalled {\n\t\th.handlerCalled = true\n\t\treturn h.handler(ctx, h)\n\t}\n\tvar toBeCommittedSql = h.Sql\n\t// Table change.\n\tif h.Table != h.originalTableName.String() {\n\t\ttoBeCommittedSql, err = gregex.ReplaceStringFuncMatch(\n\t\t\t`(?i) FROM ([\\S]+)`,\n\t\t\ttoBeCommittedSql,\n\t\t\tfunc(match []string) string {\n\t\t\t\tcharL, charR := h.Model.db.GetChars()\n\t\t\t\treturn fmt.Sprintf(` FROM %s%s%s`, charL, h.Table, charR)\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\t// Schema change.\n\tif h.Schema != \"\" && h.Schema != h.originalSchemaName.String() {\n\t\th.link, err = h.Model.db.GetCore().SlaveLink(h.Schema)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\th.Model.db.GetCore().schema = h.Schema\n\t\tdefer func() {\n\t\t\th.Model.db.GetCore().schema = h.originalSchemaName.String()\n\t\t}()\n\t}\n\treturn h.Model.db.DoSelect(ctx, h.link, toBeCommittedSql, h.Args...)\n}\n\n// Next calls the next hook handler.\nfunc (h *HookInsertInput) Next(ctx context.Context) (result sql.Result, err error) {\n\tif h.originalTableName.IsNil() {\n\t\th.originalTableName = gvar.New(h.Table)\n\t}\n\tif h.originalSchemaName.IsNil() {\n\t\th.originalSchemaName = gvar.New(h.Schema)\n\t}\n\n\t// Sharding feature.\n\th.Schema, err = h.Model.getActualSchema(ctx, h.Schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th.Table, err = h.Model.getActualTable(ctx, h.Table)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif h.handler != nil && !h.handlerCalled {\n\t\th.handlerCalled = true\n\t\treturn h.handler(ctx, h)\n\t}\n\n\t// No need to handle table change.\n\n\t// Schema change.\n\tif h.Schema != \"\" && h.Schema != h.originalSchemaName.String() {\n\t\th.link, err = h.Model.db.GetCore().MasterLink(h.Schema)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\th.Model.db.GetCore().schema = h.Schema\n\t\tdefer func() {\n\t\t\th.Model.db.GetCore().schema = h.originalSchemaName.String()\n\t\t}()\n\t}\n\treturn h.Model.db.DoInsert(ctx, h.link, h.Table, h.Data, h.Option)\n}\n\n// Next calls the next hook handler.\nfunc (h *HookUpdateInput) Next(ctx context.Context) (result sql.Result, err error) {\n\tif h.originalTableName.IsNil() {\n\t\th.originalTableName = gvar.New(h.Table)\n\t}\n\tif h.originalSchemaName.IsNil() {\n\t\th.originalSchemaName = gvar.New(h.Schema)\n\t}\n\n\t// Sharding feature.\n\th.Schema, err = h.Model.getActualSchema(ctx, h.Schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th.Table, err = h.Model.getActualTable(ctx, h.Table)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif h.handler != nil && !h.handlerCalled {\n\t\th.handlerCalled = true\n\t\tif gstr.HasPrefix(h.Condition, whereKeyInCondition) {\n\t\t\th.removedWhere = true\n\t\t\th.Condition = gstr.TrimLeftStr(h.Condition, whereKeyInCondition)\n\t\t}\n\t\treturn h.handler(ctx, h)\n\t}\n\tif h.removedWhere {\n\t\th.Condition = whereKeyInCondition + h.Condition\n\t}\n\n\t// No need to handle table change.\n\n\t// Schema change.\n\tif h.Schema != \"\" && h.Schema != h.originalSchemaName.String() {\n\t\th.link, err = h.Model.db.GetCore().MasterLink(h.Schema)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\th.Model.db.GetCore().schema = h.Schema\n\t\tdefer func() {\n\t\t\th.Model.db.GetCore().schema = h.originalSchemaName.String()\n\t\t}()\n\t}\n\treturn h.Model.db.DoUpdate(ctx, h.link, h.Table, h.Data, h.Condition, h.Args...)\n}\n\n// Next calls the next hook handler.\nfunc (h *HookDeleteInput) Next(ctx context.Context) (result sql.Result, err error) {\n\tif h.originalTableName.IsNil() {\n\t\th.originalTableName = gvar.New(h.Table)\n\t}\n\tif h.originalSchemaName.IsNil() {\n\t\th.originalSchemaName = gvar.New(h.Schema)\n\t}\n\n\t// Sharding feature.\n\th.Schema, err = h.Model.getActualSchema(ctx, h.Schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th.Table, err = h.Model.getActualTable(ctx, h.Table)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif h.handler != nil && !h.handlerCalled {\n\t\th.handlerCalled = true\n\t\tif gstr.HasPrefix(h.Condition, whereKeyInCondition) {\n\t\t\th.removedWhere = true\n\t\t\th.Condition = gstr.TrimLeftStr(h.Condition, whereKeyInCondition)\n\t\t}\n\t\treturn h.handler(ctx, h)\n\t}\n\tif h.removedWhere {\n\t\th.Condition = whereKeyInCondition + h.Condition\n\t}\n\n\t// No need to handle table change.\n\n\t// Schema change.\n\tif h.Schema != \"\" && h.Schema != h.originalSchemaName.String() {\n\t\th.link, err = h.Model.db.GetCore().MasterLink(h.Schema)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\th.Model.db.GetCore().schema = h.Schema\n\t\tdefer func() {\n\t\t\th.Model.db.GetCore().schema = h.originalSchemaName.String()\n\t\t}()\n\t}\n\treturn h.Model.db.DoDelete(ctx, h.link, h.Table, h.Condition, h.Args...)\n}\n\n// Hook sets the hook functions for current model.\nfunc (m *Model) Hook(hook HookHandler) *Model {\n\tmodel := m.getModel()\n\tmodel.hookHandler = hook\n\treturn model\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_insert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Batch sets the batch operation number for the model.\nfunc (m *Model) Batch(batch int) *Model {\n\tmodel := m.getModel()\n\tmodel.batch = batch\n\treturn model\n}\n\n// Data sets the operation data for the model.\n// The parameter `data` can be type of string/map/gmap/slice/struct/*struct, etc.\n// Note that, it uses shallow value copying for `data` if `data` is type of map/slice\n// to avoid changing it inside function.\n// Eg:\n// Data(\"uid=10000\")\n// Data(\"uid\", 10000)\n// Data(\"uid=? AND name=?\", 10000, \"john\")\n// Data(g.Map{\"uid\": 10000, \"name\":\"john\"})\n// Data(g.Slice{g.Map{\"uid\": 10000, \"name\":\"john\"}, g.Map{\"uid\": 20000, \"name\":\"smith\"}).\nfunc (m *Model) Data(data ...any) *Model {\n\tvar model = m.getModel()\n\tif len(data) > 1 {\n\t\tif s := gconv.String(data[0]); gstr.Contains(s, \"?\") {\n\t\t\tmodel.data = s\n\t\t\tmodel.extraArgs = data[1:]\n\t\t} else {\n\t\t\tnewData := make(map[string]any)\n\t\t\tfor i := 0; i < len(data); i += 2 {\n\t\t\t\tnewData[gconv.String(data[i])] = data[i+1]\n\t\t\t}\n\t\t\tmodel.data = newData\n\t\t}\n\t} else if len(data) == 1 {\n\t\tswitch value := data[0].(type) {\n\t\tcase Result:\n\t\t\tmodel.data = value.List()\n\n\t\tcase Record:\n\t\t\tmodel.data = value.Map()\n\n\t\tcase List:\n\t\t\tlist := make(List, len(value))\n\t\t\tfor k, v := range value {\n\t\t\t\tlist[k] = gutil.MapCopy(v)\n\t\t\t}\n\t\t\tmodel.data = list\n\n\t\tcase Map:\n\t\t\tmodel.data = gutil.MapCopy(value)\n\n\t\tdefault:\n\t\t\treflectInfo := reflection.OriginValueAndKind(value)\n\t\t\tswitch reflectInfo.OriginKind {\n\t\t\tcase reflect.Slice, reflect.Array:\n\t\t\t\tif reflectInfo.OriginValue.Len() > 0 {\n\t\t\t\t\t// If the `data` parameter is a DO struct,\n\t\t\t\t\t// it then adds `OmitNilData` option for this condition,\n\t\t\t\t\t// which will filter all nil parameters in `data`.\n\t\t\t\t\tif isDoStruct(reflectInfo.OriginValue.Index(0).Interface()) {\n\t\t\t\t\t\tmodel = model.OmitNilData()\n\t\t\t\t\t\tmodel.option |= optionOmitNilDataInternal\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlist := make(List, reflectInfo.OriginValue.Len())\n\t\t\t\tfor i := 0; i < reflectInfo.OriginValue.Len(); i++ {\n\t\t\t\t\tlist[i] = anyValueToMapBeforeToRecord(reflectInfo.OriginValue.Index(i).Interface())\n\t\t\t\t}\n\t\t\t\tmodel.data = list\n\n\t\t\tcase reflect.Struct:\n\t\t\t\t// If the `data` parameter is a DO struct,\n\t\t\t\t// it then adds `OmitNilData` option for this condition,\n\t\t\t\t// which will filter all nil parameters in `data`.\n\t\t\t\tif isDoStruct(value) {\n\t\t\t\t\tmodel = model.OmitNilData()\n\t\t\t\t}\n\t\t\t\tif v, ok := data[0].(iInterfaces); ok {\n\t\t\t\t\tvar (\n\t\t\t\t\t\tarray = v.Interfaces()\n\t\t\t\t\t\tlist  = make(List, len(array))\n\t\t\t\t\t)\n\t\t\t\t\tfor i := 0; i < len(array); i++ {\n\t\t\t\t\t\tlist[i] = anyValueToMapBeforeToRecord(array[i])\n\t\t\t\t\t}\n\t\t\t\t\tmodel.data = list\n\t\t\t\t} else {\n\t\t\t\t\tmodel.data = anyValueToMapBeforeToRecord(data[0])\n\t\t\t\t}\n\n\t\t\tcase reflect.Map:\n\t\t\t\tmodel.data = anyValueToMapBeforeToRecord(data[0])\n\n\t\t\tdefault:\n\t\t\t\tmodel.data = data[0]\n\t\t\t}\n\t\t}\n\t}\n\treturn model\n}\n\n// OnConflict sets the primary key or index when columns conflicts occurs.\n// It's not necessary for MySQL driver.\nfunc (m *Model) OnConflict(onConflict ...any) *Model {\n\tif len(onConflict) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tif len(onConflict) > 1 {\n\t\tmodel.onConflict = onConflict\n\t} else if len(onConflict) == 1 {\n\t\tmodel.onConflict = onConflict[0]\n\t}\n\treturn model\n}\n\n// OnDuplicate sets the operations when columns conflicts occurs.\n// In MySQL, this is used for \"ON DUPLICATE KEY UPDATE\" statement.\n// In PgSQL, this is used for \"ON CONFLICT (id) DO UPDATE SET\" statement.\n// The parameter `onDuplicate` can be type of string/Raw/*Raw/map/slice.\n// Example:\n//\n// OnDuplicate(\"nickname, age\")\n// OnDuplicate(\"nickname\", \"age\")\n//\n//\tOnDuplicate(g.Map{\n//\t\t  \"nickname\": gdb.Raw(\"CONCAT('name_', VALUES(`nickname`))\"),\n//\t})\n//\n//\tOnDuplicate(g.Map{\n//\t\t  \"nickname\": \"passport\",\n//\t}).\nfunc (m *Model) OnDuplicate(onDuplicate ...any) *Model {\n\tif len(onDuplicate) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tif len(onDuplicate) > 1 {\n\t\tmodel.onDuplicate = onDuplicate\n\t} else if len(onDuplicate) == 1 {\n\t\tmodel.onDuplicate = onDuplicate[0]\n\t}\n\treturn model\n}\n\n// OnDuplicateEx sets the excluding columns for operations when columns conflict occurs.\n// In MySQL, this is used for \"ON DUPLICATE KEY UPDATE\" statement.\n// In PgSQL, this is used for \"ON CONFLICT (id) DO UPDATE SET\" statement.\n// The parameter `onDuplicateEx` can be type of string/map/slice.\n// Example:\n//\n// OnDuplicateEx(\"passport, password\")\n// OnDuplicateEx(\"passport\", \"password\")\n//\n//\tOnDuplicateEx(g.Map{\n//\t\t  \"passport\": \"\",\n//\t\t  \"password\": \"\",\n//\t}).\nfunc (m *Model) OnDuplicateEx(onDuplicateEx ...any) *Model {\n\tif len(onDuplicateEx) == 0 {\n\t\treturn m\n\t}\n\tmodel := m.getModel()\n\tif len(onDuplicateEx) > 1 {\n\t\tmodel.onDuplicateEx = onDuplicateEx\n\t} else if len(onDuplicateEx) == 1 {\n\t\tmodel.onDuplicateEx = onDuplicateEx[0]\n\t}\n\treturn model\n}\n\n// Insert does \"INSERT INTO ...\" statement for the model.\n// The optional parameter `data` is the same as the parameter of Model.Data function,\n// see Model.Data.\nfunc (m *Model) Insert(data ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(data) > 0 {\n\t\treturn m.Data(data...).Insert()\n\t}\n\treturn m.doInsertWithOption(ctx, InsertOptionDefault)\n}\n\n// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.\nfunc (m *Model) InsertAndGetId(data ...any) (lastInsertId int64, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(data) > 0 {\n\t\treturn m.Data(data...).InsertAndGetId()\n\t}\n\tresult, err := m.doInsertWithOption(ctx, InsertOptionDefault)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn result.LastInsertId()\n}\n\n// InsertIgnore does \"INSERT IGNORE INTO ...\" statement for the model.\n// The optional parameter `data` is the same as the parameter of Model.Data function,\n// see Model.Data.\nfunc (m *Model) InsertIgnore(data ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(data) > 0 {\n\t\treturn m.Data(data...).InsertIgnore()\n\t}\n\treturn m.doInsertWithOption(ctx, InsertOptionIgnore)\n}\n\n// Replace does \"REPLACE INTO ...\" statement for the model.\n// The optional parameter `data` is the same as the parameter of Model.Data function,\n// see Model.Data.\nfunc (m *Model) Replace(data ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(data) > 0 {\n\t\treturn m.Data(data...).Replace()\n\t}\n\treturn m.doInsertWithOption(ctx, InsertOptionReplace)\n}\n\n// Save does \"INSERT INTO ... ON DUPLICATE KEY UPDATE...\" statement for the model.\n// The optional parameter `data` is the same as the parameter of Model.Data function,\n// see Model.Data.\n//\n// It updates the record if there's primary or unique index in the saving data,\n// or else it inserts a new record into the table.\nfunc (m *Model) Save(data ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(data) > 0 {\n\t\treturn m.Data(data...).Save()\n\t}\n\treturn m.doInsertWithOption(ctx, InsertOptionSave)\n}\n\n// doInsertWithOption inserts data with option parameter.\nfunc (m *Model) doInsertWithOption(ctx context.Context, insertOption InsertOption) (result sql.Result, err error) {\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tm.checkAndRemoveSelectCache(ctx)\n\t\t}\n\t}()\n\tif m.data == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeMissingParameter, \"inserting into table with empty data\")\n\t}\n\tvar (\n\t\tlist                             List\n\t\tstm                              = m.softTimeMaintainer()\n\t\tfieldNameCreate, fieldTypeCreate = stm.GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldCreate)\n\t\tfieldNameUpdate, fieldTypeUpdate = stm.GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldUpdate)\n\t\tfieldNameDelete, fieldTypeDelete = stm.GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldDelete)\n\t)\n\t// m.data was already converted to type List/Map by function Data\n\tnewData, err := m.filterDataForInsertOrUpdate(m.data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// It converts any data to List type for inserting.\n\tswitch value := newData.(type) {\n\tcase List:\n\t\tlist = value\n\n\tcase Map:\n\t\tlist = List{value}\n\t}\n\n\tif len(list) < 1 {\n\t\treturn result, gerror.NewCode(gcode.CodeMissingParameter, \"data list cannot be empty\")\n\t}\n\n\t// Automatic handling for creating/updating time.\n\tif fieldNameCreate != \"\" && m.isFieldInFieldsEx(fieldNameCreate) {\n\t\tfieldNameCreate = \"\"\n\t}\n\tif fieldNameUpdate != \"\" && m.isFieldInFieldsEx(fieldNameUpdate) {\n\t\tfieldNameUpdate = \"\"\n\t}\n\tvar isSoftTimeFeatureEnabled = fieldNameCreate != \"\" || fieldNameUpdate != \"\"\n\tif !m.unscoped && isSoftTimeFeatureEnabled {\n\t\tfor k, v := range list {\n\t\t\tif fieldNameCreate != \"\" && empty.IsNil(v[fieldNameCreate]) {\n\t\t\t\tfieldCreateValue := stm.GetFieldValue(ctx, fieldTypeCreate, false)\n\t\t\t\tif fieldCreateValue != nil {\n\t\t\t\t\tv[fieldNameCreate] = fieldCreateValue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif fieldNameUpdate != \"\" && empty.IsNil(v[fieldNameUpdate]) {\n\t\t\t\tfieldUpdateValue := stm.GetFieldValue(ctx, fieldTypeUpdate, false)\n\t\t\t\tif fieldUpdateValue != nil {\n\t\t\t\t\tv[fieldNameUpdate] = fieldUpdateValue\n\t\t\t\t}\n\t\t\t}\n\t\t\t// for timestamp field that should initialize the delete_at field with value, for example 0.\n\t\t\tif fieldNameDelete != \"\" && empty.IsNil(v[fieldNameDelete]) {\n\t\t\t\tfieldDeleteValue := stm.GetFieldValue(ctx, fieldTypeDelete, true)\n\t\t\t\tif fieldDeleteValue != nil {\n\t\t\t\t\tv[fieldNameDelete] = fieldDeleteValue\n\t\t\t\t}\n\t\t\t}\n\t\t\tlist[k] = v\n\t\t}\n\t}\n\t// Format DoInsertOption, especially for \"ON DUPLICATE KEY UPDATE\" statement.\n\tcolumnNames := make([]string, 0, len(list[0]))\n\tfor k := range list[0] {\n\t\tcolumnNames = append(columnNames, k)\n\t}\n\tdoInsertOption, err := m.formatDoInsertOption(insertOption, columnNames)\n\tif err != nil {\n\t\treturn result, err\n\t}\n\n\tin := &HookInsertInput{\n\t\tinternalParamHookInsert: internalParamHookInsert{\n\t\t\tinternalParamHook: internalParamHook{\n\t\t\t\tlink: m.getLink(true),\n\t\t\t},\n\t\t\thandler: m.hookHandler.Insert,\n\t\t},\n\t\tModel:  m,\n\t\tTable:  m.tables,\n\t\tSchema: m.schema,\n\t\tData:   list,\n\t\tOption: doInsertOption,\n\t}\n\treturn in.Next(ctx)\n}\n\nfunc (m *Model) formatDoInsertOption(insertOption InsertOption, columnNames []string) (option DoInsertOption, err error) {\n\toption = DoInsertOption{\n\t\tInsertOption: insertOption,\n\t\tBatchCount:   m.getBatch(),\n\t}\n\tif insertOption != InsertOptionSave {\n\t\treturn\n\t}\n\n\tonConflictKeys, err := m.formatOnConflictKeys(m.onConflict)\n\tif err != nil {\n\t\treturn option, err\n\t}\n\toption.OnConflict = onConflictKeys\n\n\tonDuplicateExKeys, err := m.formatOnDuplicateExKeys(m.onDuplicateEx)\n\tif err != nil {\n\t\treturn option, err\n\t}\n\tonDuplicateExKeySet := gset.NewStrSetFrom(onDuplicateExKeys)\n\tif m.onDuplicate != nil {\n\t\tswitch m.onDuplicate.(type) {\n\t\tcase Raw, *Raw:\n\t\t\toption.OnDuplicateStr = gconv.String(m.onDuplicate)\n\n\t\tdefault:\n\t\t\treflectInfo := reflection.OriginValueAndKind(m.onDuplicate)\n\t\t\tswitch reflectInfo.OriginKind {\n\t\t\tcase reflect.String:\n\t\t\t\toption.OnDuplicateMap = make(map[string]any)\n\t\t\t\tfor _, v := range gstr.SplitAndTrim(reflectInfo.OriginValue.String(), \",\") {\n\t\t\t\t\tif onDuplicateExKeySet.Contains(v) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\toption.OnDuplicateMap[v] = v\n\t\t\t\t}\n\n\t\t\tcase reflect.Map:\n\t\t\t\toption.OnDuplicateMap = make(map[string]any)\n\t\t\t\tfor k, v := range gconv.Map(m.onDuplicate) {\n\t\t\t\t\tif onDuplicateExKeySet.Contains(k) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\toption.OnDuplicateMap[k] = v\n\t\t\t\t}\n\n\t\t\tcase reflect.Slice, reflect.Array:\n\t\t\t\toption.OnDuplicateMap = make(map[string]any)\n\t\t\t\tfor _, v := range gconv.Strings(m.onDuplicate) {\n\t\t\t\t\tif onDuplicateExKeySet.Contains(v) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\toption.OnDuplicateMap[v] = v\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn option, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`unsupported OnDuplicate parameter type \"%s\"`,\n\t\t\t\t\treflect.TypeOf(m.onDuplicate),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t} else if onDuplicateExKeySet.Size() > 0 {\n\t\toption.OnDuplicateMap = make(map[string]any)\n\t\tfor _, v := range columnNames {\n\t\t\tif onDuplicateExKeySet.Contains(v) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toption.OnDuplicateMap[v] = v\n\t\t}\n\t}\n\treturn\n}\n\nfunc (m *Model) formatOnDuplicateExKeys(onDuplicateEx any) ([]string, error) {\n\tif onDuplicateEx == nil {\n\t\treturn nil, nil\n\t}\n\n\treflectInfo := reflection.OriginValueAndKind(onDuplicateEx)\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.String:\n\t\treturn gstr.SplitAndTrim(reflectInfo.OriginValue.String(), \",\"), nil\n\n\tcase reflect.Map:\n\t\treturn gutil.Keys(onDuplicateEx), nil\n\n\tcase reflect.Slice, reflect.Array:\n\t\treturn gconv.Strings(onDuplicateEx), nil\n\n\tdefault:\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`unsupported OnDuplicateEx parameter type \"%s\"`,\n\t\t\treflect.TypeOf(onDuplicateEx),\n\t\t)\n\t}\n}\n\nfunc (m *Model) formatOnConflictKeys(onConflict any) ([]string, error) {\n\tif onConflict == nil {\n\t\treturn nil, nil\n\t}\n\n\treflectInfo := reflection.OriginValueAndKind(onConflict)\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.String:\n\t\treturn gstr.SplitAndTrim(reflectInfo.OriginValue.String(), \",\"), nil\n\n\tcase reflect.Slice, reflect.Array:\n\t\treturn gconv.Strings(onConflict), nil\n\n\tdefault:\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`unsupported onConflict parameter type \"%s\"`,\n\t\t\treflect.TypeOf(onConflict),\n\t\t)\n\t}\n}\n\nfunc (m *Model) getBatch() int {\n\treturn m.batch\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_join.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// LeftJoin does \"LEFT JOIN ... ON ...\" statement on the model.\n// The parameter `table` can be joined table and its joined condition,\n// and also with its alias name.\n//\n// Eg:\n// Model(\"user\").LeftJoin(\"user_detail\", \"user_detail.uid=user.uid\")\n// Model(\"user\", \"u\").LeftJoin(\"user_detail\", \"ud\", \"ud.uid=u.uid\")\n// Model(\"user\", \"u\").LeftJoin(\"SELECT xxx FROM xxx\",\"a\", \"a.uid=u.uid\").\nfunc (m *Model) LeftJoin(tableOrSubQueryAndJoinConditions ...string) *Model {\n\treturn m.doJoin(joinOperatorLeft, tableOrSubQueryAndJoinConditions...)\n}\n\n// RightJoin does \"RIGHT JOIN ... ON ...\" statement on the model.\n// The parameter `table` can be joined table and its joined condition,\n// and also with its alias name.\n//\n// Eg:\n// Model(\"user\").RightJoin(\"user_detail\", \"user_detail.uid=user.uid\")\n// Model(\"user\", \"u\").RightJoin(\"user_detail\", \"ud\", \"ud.uid=u.uid\")\n// Model(\"user\", \"u\").RightJoin(\"SELECT xxx FROM xxx\",\"a\", \"a.uid=u.uid\").\nfunc (m *Model) RightJoin(tableOrSubQueryAndJoinConditions ...string) *Model {\n\treturn m.doJoin(joinOperatorRight, tableOrSubQueryAndJoinConditions...)\n}\n\n// InnerJoin does \"INNER JOIN ... ON ...\" statement on the model.\n// The parameter `table` can be joined table and its joined condition,\n// and also with its alias name。\n//\n// Eg:\n// Model(\"user\").InnerJoin(\"user_detail\", \"user_detail.uid=user.uid\")\n// Model(\"user\", \"u\").InnerJoin(\"user_detail\", \"ud\", \"ud.uid=u.uid\")\n// Model(\"user\", \"u\").InnerJoin(\"SELECT xxx FROM xxx\",\"a\", \"a.uid=u.uid\").\nfunc (m *Model) InnerJoin(tableOrSubQueryAndJoinConditions ...string) *Model {\n\treturn m.doJoin(joinOperatorInner, tableOrSubQueryAndJoinConditions...)\n}\n\n// LeftJoinOnField performs as LeftJoin, but it joins both tables with the `same field name`.\n//\n// Eg:\n// Model(\"order\").LeftJoinOnField(\"user\", \"user_id\")\n// Model(\"order\").LeftJoinOnField(\"product\", \"product_id\").\nfunc (m *Model) LeftJoinOnField(table, field string) *Model {\n\treturn m.doJoin(joinOperatorLeft, table, fmt.Sprintf(\n\t\t`%s.%s=%s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(field),\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(field),\n\t))\n}\n\n// RightJoinOnField performs as RightJoin, but it joins both tables with the `same field name`.\n//\n// Eg:\n// Model(\"order\").InnerJoinOnField(\"user\", \"user_id\")\n// Model(\"order\").InnerJoinOnField(\"product\", \"product_id\").\nfunc (m *Model) RightJoinOnField(table, field string) *Model {\n\treturn m.doJoin(joinOperatorRight, table, fmt.Sprintf(\n\t\t`%s.%s=%s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(field),\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(field),\n\t))\n}\n\n// InnerJoinOnField performs as InnerJoin, but it joins both tables with the `same field name`.\n//\n// Eg:\n// Model(\"order\").InnerJoinOnField(\"user\", \"user_id\")\n// Model(\"order\").InnerJoinOnField(\"product\", \"product_id\").\nfunc (m *Model) InnerJoinOnField(table, field string) *Model {\n\treturn m.doJoin(joinOperatorInner, table, fmt.Sprintf(\n\t\t`%s.%s=%s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(field),\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(field),\n\t))\n}\n\n// LeftJoinOnFields performs as LeftJoin. It specifies different fields and comparison operator.\n//\n// Eg:\n// Model(\"user\").LeftJoinOnFields(\"order\", \"id\", \"=\", \"user_id\")\n// Model(\"user\").LeftJoinOnFields(\"order\", \"id\", \">\", \"user_id\")\n// Model(\"user\").LeftJoinOnFields(\"order\", \"id\", \"<\", \"user_id\")\nfunc (m *Model) LeftJoinOnFields(table, firstField, operator, secondField string) *Model {\n\treturn m.doJoin(joinOperatorLeft, table, fmt.Sprintf(\n\t\t`%s.%s %s %s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(firstField),\n\t\toperator,\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(secondField),\n\t))\n}\n\n// RightJoinOnFields performs as RightJoin. It specifies different fields and comparison operator.\n//\n// Eg:\n// Model(\"user\").RightJoinOnFields(\"order\", \"id\", \"=\", \"user_id\")\n// Model(\"user\").RightJoinOnFields(\"order\", \"id\", \">\", \"user_id\")\n// Model(\"user\").RightJoinOnFields(\"order\", \"id\", \"<\", \"user_id\")\nfunc (m *Model) RightJoinOnFields(table, firstField, operator, secondField string) *Model {\n\treturn m.doJoin(joinOperatorRight, table, fmt.Sprintf(\n\t\t`%s.%s %s %s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(firstField),\n\t\toperator,\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(secondField),\n\t))\n}\n\n// InnerJoinOnFields performs as InnerJoin. It specifies different fields and comparison operator.\n//\n// Eg:\n// Model(\"user\").InnerJoinOnFields(\"order\", \"id\", \"=\", \"user_id\")\n// Model(\"user\").InnerJoinOnFields(\"order\", \"id\", \">\", \"user_id\")\n// Model(\"user\").InnerJoinOnFields(\"order\", \"id\", \"<\", \"user_id\")\nfunc (m *Model) InnerJoinOnFields(table, firstField, operator, secondField string) *Model {\n\treturn m.doJoin(joinOperatorInner, table, fmt.Sprintf(\n\t\t`%s.%s %s %s.%s`,\n\t\tm.tablesInit,\n\t\tm.db.GetCore().QuoteWord(firstField),\n\t\toperator,\n\t\tm.db.GetCore().QuoteWord(table),\n\t\tm.db.GetCore().QuoteWord(secondField),\n\t))\n}\n\n// doJoin does \"LEFT/RIGHT/INNER JOIN ... ON ...\" statement on the model.\n// The parameter `tableOrSubQueryAndJoinConditions` can be joined table and its joined condition,\n// and also with its alias name.\n//\n// Eg:\n// Model(\"user\").InnerJoin(\"user_detail\", \"user_detail.uid=user.uid\")\n// Model(\"user\", \"u\").InnerJoin(\"user_detail\", \"ud\", \"ud.uid=u.uid\")\n// Model(\"user\", \"u\").InnerJoin(\"user_detail\", \"ud\", \"ud.uid>u.uid\")\n// Model(\"user\", \"u\").InnerJoin(\"SELECT xxx FROM xxx\",\"a\", \"a.uid=u.uid\")\n// Related issues:\n// https://github.com/gogf/gf/issues/1024\nfunc (m *Model) doJoin(operator joinOperator, tableOrSubQueryAndJoinConditions ...string) *Model {\n\tvar (\n\t\tmodel   = m.getModel()\n\t\tjoinStr = \"\"\n\t\ttable   string\n\t\talias   string\n\t)\n\t// Check the first parameter table or sub-query.\n\tif len(tableOrSubQueryAndJoinConditions) > 0 {\n\t\tif isSubQuery(tableOrSubQueryAndJoinConditions[0]) {\n\t\t\tjoinStr = gstr.Trim(tableOrSubQueryAndJoinConditions[0])\n\t\t\tif joinStr[0] != '(' {\n\t\t\t\tjoinStr = \"(\" + joinStr + \")\"\n\t\t\t}\n\t\t} else {\n\t\t\ttable = tableOrSubQueryAndJoinConditions[0]\n\t\t\tjoinStr = m.db.GetCore().QuotePrefixTableName(table)\n\t\t}\n\t}\n\t// Generate join condition statement string.\n\tconditionLength := len(tableOrSubQueryAndJoinConditions)\n\tswitch {\n\tcase conditionLength > 2:\n\t\talias = tableOrSubQueryAndJoinConditions[1]\n\t\tmodel.tables += fmt.Sprintf(\n\t\t\t\" %s JOIN %s AS %s ON (%s)\",\n\t\t\toperator, joinStr,\n\t\t\tm.db.GetCore().QuoteWord(alias),\n\t\t\ttableOrSubQueryAndJoinConditions[2],\n\t\t)\n\t\tm.tableAliasMap[alias] = table\n\n\tcase conditionLength == 2:\n\t\tmodel.tables += fmt.Sprintf(\n\t\t\t\" %s JOIN %s ON (%s)\",\n\t\t\toperator, joinStr, tableOrSubQueryAndJoinConditions[1],\n\t\t)\n\n\tcase conditionLength == 1:\n\t\tmodel.tables += fmt.Sprintf(\n\t\t\t\" %s JOIN %s\", operator, joinStr,\n\t\t)\n\t}\n\treturn model\n}\n\n// getTableNameByPrefixOrAlias checks and returns the table name if `prefixOrAlias` is an alias of a table,\n// it or else returns the `prefixOrAlias` directly.\nfunc (m *Model) getTableNameByPrefixOrAlias(prefixOrAlias string) string {\n\tvalue, ok := m.tableAliasMap[prefixOrAlias]\n\tif ok {\n\t\treturn value\n\t}\n\treturn prefixOrAlias\n}\n\n// isSubQuery checks and returns whether given string a sub-query sql string.\nfunc isSubQuery(s string) bool {\n\ts = gstr.TrimLeft(s, \"()\")\n\tif p := gstr.Pos(s, \" \"); p != -1 {\n\t\tif gstr.Equal(s[:p], \"select\") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_lock.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// Lock clause constants for different databases.\n// These constants provide type-safe and IDE-friendly access to various lock syntaxes.\nconst (\n\t// Common lock clauses (supported by most databases)\n\tLockForUpdate           = \"FOR UPDATE\"\n\tLockForUpdateSkipLocked = \"FOR UPDATE SKIP LOCKED\"\n\n\t// MySQL lock clauses\n\tLockInShareMode     = \"LOCK IN SHARE MODE\" // MySQL legacy syntax\n\tLockForShare        = \"FOR SHARE\"          // MySQL 8.0+ and PostgreSQL\n\tLockForUpdateNowait = \"FOR UPDATE NOWAIT\"  // MySQL 8.0+ and Oracle\n\n\t// PostgreSQL specific lock clauses\n\tLockForNoKeyUpdate           = \"FOR NO KEY UPDATE\"\n\tLockForKeyShare              = \"FOR KEY SHARE\"\n\tLockForShareNowait           = \"FOR SHARE NOWAIT\"\n\tLockForShareSkipLocked       = \"FOR SHARE SKIP LOCKED\"\n\tLockForNoKeyUpdateNowait     = \"FOR NO KEY UPDATE NOWAIT\"\n\tLockForNoKeyUpdateSkipLocked = \"FOR NO KEY UPDATE SKIP LOCKED\"\n\tLockForKeyShareNowait        = \"FOR KEY SHARE NOWAIT\"\n\tLockForKeyShareSkipLocked    = \"FOR KEY SHARE SKIP LOCKED\"\n\n\t// Oracle specific lock clauses\n\tLockForUpdateWait5  = \"FOR UPDATE WAIT 5\"\n\tLockForUpdateWait10 = \"FOR UPDATE WAIT 10\"\n\tLockForUpdateWait30 = \"FOR UPDATE WAIT 30\"\n\n\t// SQL Server lock hints (use with WITH clause)\n\tLockWithUpdLock         = \"WITH (UPDLOCK)\"\n\tLockWithHoldLock        = \"WITH (HOLDLOCK)\"\n\tLockWithXLock           = \"WITH (XLOCK)\"\n\tLockWithTabLock         = \"WITH (TABLOCK)\"\n\tLockWithNoLock          = \"WITH (NOLOCK)\"\n\tLockWithUpdLockHoldLock = \"WITH (UPDLOCK, HOLDLOCK)\"\n)\n\n// Lock sets a custom lock clause for the current operation.\n// This is a generic method that allows you to specify any lock syntax supported by your database.\n// You can use predefined constants or custom strings.\n//\n// Database-specific lock syntax support:\n//\n// PostgreSQL (most comprehensive):\n//   - \"FOR UPDATE\"                    - Exclusive lock, blocks all access\n//   - \"FOR NO KEY UPDATE\"            - Weaker exclusive lock, doesn't block FOR KEY SHARE\n//   - \"FOR SHARE\"                    - Shared lock, allows reads but blocks writes\n//   - \"FOR KEY SHARE\"                - Weakest lock, only locks key values\n//   - All above can be combined with:\n//   - \"NOWAIT\"                     - Return immediately if lock cannot be acquired\n//   - \"SKIP LOCKED\"               - Skip locked rows instead of waiting\n//\n// MySQL:\n//   - \"FOR UPDATE\"                    - Exclusive lock (all versions)\n//   - \"LOCK IN SHARE MODE\"           - Shared lock (legacy syntax)\n//   - \"FOR SHARE\"                    - Shared lock (MySQL 8.0+)\n//   - \"FOR UPDATE NOWAIT\"            - MySQL 8.0+ only\n//   - \"FOR UPDATE SKIP LOCKED\"       - MySQL 8.0+ only\n//\n// Oracle:\n//   - \"FOR UPDATE\"                    - Exclusive lock\n//   - \"FOR UPDATE NOWAIT\"            - Exclusive lock, no wait\n//   - \"FOR UPDATE SKIP LOCKED\"       - Exclusive lock, skip locked rows\n//   - \"FOR UPDATE WAIT n\"            - Exclusive lock, wait n seconds\n//   - \"FOR UPDATE OF column_list\"    - Lock specific columns\n//\n// SQL Server (uses WITH hints):\n//   - \"WITH (UPDLOCK)\"               - Update lock\n//   - \"WITH (HOLDLOCK)\"              - Hold lock until transaction end\n//   - \"WITH (XLOCK)\"                 - Exclusive lock\n//   - \"WITH (TABLOCK)\"               - Table lock\n//   - \"WITH (NOLOCK)\"                - No lock (dirty read)\n//   - \"WITH (UPDLOCK, HOLDLOCK)\"     - Combined update and hold lock\n//\n// SQLite:\n//   - Limited locking support, database-level locks only\n//   - No row-level lock syntax supported\n//\n// Usage examples:\n//\n//\tdb.Model(\"users\").Lock(\"FOR UPDATE NOWAIT\").Where(\"id\", 1).One()\n//\tdb.Model(\"users\").Lock(\"FOR SHARE SKIP LOCKED\").Where(\"status\", \"active\").All()\n//\tdb.Model(\"users\").Lock(\"WITH (UPDLOCK)\").Where(\"id\", 1).One() // SQL Server\n//\tdb.Model(\"users\").Lock(\"FOR UPDATE OF name, email\").Where(\"id\", 1).One() // Oracle\n//\tdb.Model(\"users\").Lock(\"FOR UPDATE WAIT 15\").Where(\"id\", 1).One() // Oracle custom wait\n//\n// Or use predefined constants for better IDE support:\n//\n//\tdb.Model(\"users\").Lock(gdb.LockForUpdateNowait).Where(\"id\", 1).One()\n//\tdb.Model(\"users\").Lock(gdb.LockForShareSkipLocked).Where(\"status\", \"active\").All()\nfunc (m *Model) Lock(lockClause string) *Model {\n\tmodel := m.getModel()\n\tmodel.lockInfo = lockClause\n\treturn model\n}\n\n// LockUpdate sets the lock for update for current operation.\n// This is equivalent to Lock(\"FOR UPDATE\").\nfunc (m *Model) LockUpdate() *Model {\n\tmodel := m.getModel()\n\tmodel.lockInfo = LockForUpdate\n\treturn model\n}\n\n// LockUpdateSkipLocked sets the lock for update with skip locked behavior for current operation.\n// It skips the locked rows.\n// This is equivalent to Lock(\"FOR UPDATE SKIP LOCKED\").\n// Note: Supported by PostgreSQL, Oracle, and MySQL 8.0+.\nfunc (m *Model) LockUpdateSkipLocked() *Model {\n\tmodel := m.getModel()\n\tmodel.lockInfo = LockForUpdateSkipLocked\n\treturn model\n}\n\n// LockShared sets the lock in share mode for current operation.\n// This is equivalent to Lock(\"LOCK IN SHARE MODE\") for MySQL or Lock(\"FOR SHARE\") for PostgreSQL.\n// Note: For maximum compatibility, this uses MySQL's legacy syntax.\nfunc (m *Model) LockShared() *Model {\n\tmodel := m.getModel()\n\tmodel.lockInfo = LockInShareMode\n\treturn model\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_option.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nconst (\n\toptionOmitNil             = optionOmitNilWhere | optionOmitNilData\n\toptionOmitEmpty           = optionOmitEmptyWhere | optionOmitEmptyData\n\toptionOmitNilDataInternal = optionOmitNilData | optionOmitNilDataList // this option is used internally only for ForDao feature.\n\toptionOmitEmptyWhere      = 1 << iota                                 // 8\n\toptionOmitEmptyData                                                   // 16\n\toptionOmitNilWhere                                                    // 32\n\toptionOmitNilData                                                     // 64\n\toptionOmitNilDataList                                                 // 128\n)\n\n// OmitEmpty sets optionOmitEmpty option for the model, which automatically filers\n// the data and where parameters for `empty` values.\nfunc (m *Model) OmitEmpty() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitEmpty\n\treturn model\n}\n\n// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers\n// the Where/Having parameters for `empty` values.\n//\n// Eg:\n//\n//\tWhere(\"id\", []int{}).All()             -> SELECT xxx FROM xxx WHERE 0=1\n//\tWhere(\"name\", \"\").All()                -> SELECT xxx FROM xxx WHERE `name`=''\n//\tOmitEmpty().Where(\"id\", []int{}).All() -> SELECT xxx FROM xxx\n//\tOmitEmpty().(\"name\", \"\").All()         -> SELECT xxx FROM xxx.\nfunc (m *Model) OmitEmptyWhere() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitEmptyWhere\n\treturn model\n}\n\n// OmitEmptyData sets optionOmitEmptyData option for the model, which automatically filers\n// the Data parameters for `empty` values.\nfunc (m *Model) OmitEmptyData() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitEmptyData\n\treturn model\n}\n\n// OmitNil sets optionOmitNil option for the model, which automatically filers\n// the data and where parameters for `nil` values.\nfunc (m *Model) OmitNil() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitNil\n\treturn model\n}\n\n// OmitNilWhere sets optionOmitNilWhere option for the model, which automatically filers\n// the Where/Having parameters for `nil` values.\nfunc (m *Model) OmitNilWhere() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitNilWhere\n\treturn model\n}\n\n// OmitNilData sets optionOmitNilData option for the model, which automatically filers\n// the Data parameters for `nil` values.\nfunc (m *Model) OmitNilData() *Model {\n\tmodel := m.getModel()\n\tmodel.option = model.option | optionOmitNilData\n\treturn model\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_order_group.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Order sets the \"ORDER BY\" statement for the model.\n//\n// Example:\n// Order(\"id desc\")\n// Order(\"id\", \"desc\")\n// Order(\"id desc,name asc\")\n// Order(\"id desc\", \"name asc\")\n// Order(\"id desc\").Order(\"name asc\")\n// Order(gdb.Raw(\"field(id, 3,1,2)\")).\nfunc (m *Model) Order(orderBy ...any) *Model {\n\tif len(orderBy) == 0 {\n\t\treturn m\n\t}\n\tvar (\n\t\tcore  = m.db.GetCore()\n\t\tmodel = m.getModel()\n\t)\n\tfor _, v := range orderBy {\n\t\tif model.orderBy != \"\" {\n\t\t\tmodel.orderBy += \",\"\n\t\t}\n\t\tswitch v.(type) {\n\t\tcase Raw, *Raw:\n\t\t\tmodel.orderBy += gconv.String(v)\n\t\tdefault:\n\t\t\torderByStr := gconv.String(v)\n\t\t\tif gstr.Contains(orderByStr, \" \") {\n\t\t\t\tmodel.orderBy += core.QuoteString(orderByStr)\n\t\t\t} else {\n\t\t\t\tif gstr.Equal(orderByStr, \"ASC\") || gstr.Equal(orderByStr, \"DESC\") {\n\t\t\t\t\tmodel.orderBy = gstr.TrimRight(model.orderBy, \",\")\n\t\t\t\t\tmodel.orderBy += \" \" + orderByStr\n\t\t\t\t} else {\n\t\t\t\t\tmodel.orderBy += core.QuoteWord(orderByStr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn model\n}\n\n// OrderAsc sets the \"ORDER BY xxx ASC\" statement for the model.\nfunc (m *Model) OrderAsc(column string) *Model {\n\tif len(column) == 0 {\n\t\treturn m\n\t}\n\treturn m.Order(column + \" ASC\")\n}\n\n// OrderDesc sets the \"ORDER BY xxx DESC\" statement for the model.\nfunc (m *Model) OrderDesc(column string) *Model {\n\tif len(column) == 0 {\n\t\treturn m\n\t}\n\treturn m.Order(column + \" DESC\")\n}\n\n// OrderRandom sets the \"ORDER BY RANDOM()\" statement for the model.\nfunc (m *Model) OrderRandom() *Model {\n\tmodel := m.getModel()\n\tmodel.orderBy = m.db.OrderRandomFunction()\n\treturn model\n}\n\n// Group sets the \"GROUP BY\" statement for the model.\nfunc (m *Model) Group(groupBy ...string) *Model {\n\tif len(groupBy) == 0 {\n\t\treturn m\n\t}\n\tvar (\n\t\tcore  = m.db.GetCore()\n\t\tmodel = m.getModel()\n\t)\n\n\tif model.groupBy != \"\" {\n\t\tmodel.groupBy += \",\"\n\t}\n\tmodel.groupBy += core.QuoteString(strings.Join(groupBy, \",\"))\n\treturn model\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_select.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// All does \"SELECT FROM ...\" statement for the model.\n// It retrieves the records from table and returns the result as slice type.\n// It returns nil if there's no record retrieved with the given conditions from table.\n//\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) All(where ...any) (Result, error) {\n\tvar ctx = m.GetCtx()\n\treturn m.doGetAll(ctx, SelectTypeDefault, false, where...)\n}\n\n// AllAndCount retrieves all records and the total count of records from the model.\n// If useFieldForCount is true, it will use the fields specified in the model for counting;\n// otherwise, it will use a constant value of 1 for counting.\n// It returns the result as a slice of records, the total count of records, and an error if any.\n// The where parameter is an optional list of conditions to use when retrieving records.\n//\n// Example:\n//\n//\tvar model Model\n//\tvar result Result\n//\tvar count int\n//\twhere := []any{\"name = ?\", \"John\"}\n//\tresult, count, err := model.AllAndCount(true)\n//\tif err != nil {\n//\t    // Handle error.\n//\t}\n//\tfmt.Println(result, count)\nfunc (m *Model) AllAndCount(useFieldForCount bool) (result Result, totalCount int, err error) {\n\t// Clone the model for counting\n\tcountModel := m.Clone()\n\n\t// Decide how to build the COUNT() expression:\n\t// - If caller explicitly wants to use the single field expression for counting,\n\t//   honor it (e.g. Fields(\"DISTINCT col\") with useFieldForCount = true).\n\t// - Otherwise, clear fields to let Count() use its default COUNT(1),\n\t//   avoiding invalid COUNT(field1, field2, ...) with multiple fields,\n\t//   or incorrect COUNT(DISTINCT 1) when Distinct() is set.\n\tif useFieldForCount && len(m.fields) == 1 {\n\t\tcountModel.fields = m.fields\n\t} else {\n\t\tcountModel.fields = nil\n\t}\n\tif len(m.pageCacheOption) > 0 {\n\t\tcountModel = countModel.Cache(m.pageCacheOption[0])\n\t}\n\n\t// Get the total count of records\n\ttotalCount, err = countModel.Count()\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// If the total count is 0, there are no records to retrieve, so return early\n\tif totalCount == 0 {\n\t\treturn\n\t}\n\n\tresultModel := m.Clone()\n\tif len(m.pageCacheOption) > 1 {\n\t\tresultModel = resultModel.Cache(m.pageCacheOption[1])\n\t}\n\n\t// Retrieve all records\n\tresult, err = resultModel.doGetAll(m.GetCtx(), SelectTypeDefault, false)\n\treturn\n}\n\n// Chunk iterates the query result with given `size` and `handler` function.\nfunc (m *Model) Chunk(size int, handler ChunkHandler) {\n\tpage := m.start\n\tif page <= 0 {\n\t\tpage = 1\n\t}\n\tmodel := m\n\tfor {\n\t\tmodel = model.Page(page, size)\n\t\tdata, err := model.All()\n\t\tif err != nil {\n\t\t\thandler(nil, err)\n\t\t\tbreak\n\t\t}\n\t\tif len(data) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tif !handler(data, err) {\n\t\t\tbreak\n\t\t}\n\t\tif len(data) < size {\n\t\t\tbreak\n\t\t}\n\t\tpage++\n\t}\n}\n\n// One retrieves one record from table and returns the result as map type.\n// It returns nil if there's no record retrieved with the given conditions from table.\n//\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) One(where ...any) (Record, error) {\n\tvar ctx = m.GetCtx()\n\tif len(where) > 0 {\n\t\treturn m.Where(where[0], where[1:]...).One()\n\t}\n\tall, err := m.doGetAll(ctx, SelectTypeDefault, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(all) > 0 {\n\t\treturn all[0], nil\n\t}\n\treturn nil, nil\n}\n\n// Array queries and returns data values as slice from database.\n// Note that if there are multiple columns in the result, it returns just one column values randomly.\n//\n// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields\n// and fieldsAndWhere[1:] is treated as where condition fields.\n// Also see Model.Fields and Model.Where functions.\nfunc (m *Model) Array(fieldsAndWhere ...any) (Array, error) {\n\tif len(fieldsAndWhere) > 0 {\n\t\tif len(fieldsAndWhere) > 2 {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array()\n\t\t} else if len(fieldsAndWhere) == 2 {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Array()\n\t\t} else {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Array()\n\t\t}\n\t}\n\n\tvar (\n\t\tfield string\n\t\tcore  = m.db.GetCore()\n\t\tctx   = core.injectInternalColumn(m.GetCtx())\n\t)\n\tall, err := m.doGetAll(ctx, SelectTypeArray, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(all) > 0 {\n\t\tinternalData := core.getInternalColumnFromCtx(ctx)\n\t\tif internalData == nil {\n\t\t\treturn nil, gerror.NewCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\t`query count error: the internal context data is missing. there's internal issue should be fixed`,\n\t\t\t)\n\t\t}\n\t\t// If FirstResultColumn present, it returns the value of the first record of the first field.\n\t\t// It means it use no cache mechanism, while cache mechanism makes `internalData` missing.\n\t\tfield = internalData.FirstResultColumn\n\t\tif field == \"\" {\n\t\t\t// Fields number check.\n\t\t\tvar recordFields = m.getRecordFields(all[0])\n\t\t\tif len(recordFields) == 1 {\n\t\t\t\tfield = recordFields[0]\n\t\t\t} else {\n\t\t\t\t// it returns error if there are multiple fields in the result record.\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`invalid fields for \"Array\" operation, result fields number \"%d\"%s, but expect one`,\n\t\t\t\t\tlen(recordFields),\n\t\t\t\t\tgjson.MustEncodeString(recordFields),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\treturn all.Array(field), nil\n}\n\n// Struct retrieves one record from table and converts it into given struct.\n// The parameter `pointer` should be type of *struct/**struct. If type **struct is given,\n// it can create the struct internally during converting.\n//\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\n//\n// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has\n// default value and there's no record retrieved with the given conditions from table.\n//\n// Example:\n// user := new(User)\n// err  := db.Model(\"user\").Where(\"id\", 1).Scan(user)\n//\n// user := (*User)(nil)\n// err  := db.Model(\"user\").Where(\"id\", 1).Scan(&user).\nfunc (m *Model) doStruct(pointer any, where ...any) error {\n\tmodel := m\n\t// Auto selecting fields by struct attributes.\n\tif len(model.fieldsEx) == 0 && len(model.fields) == 0 {\n\t\tif v, ok := pointer.(reflect.Value); ok {\n\t\t\tmodel = m.Fields(v.Interface())\n\t\t} else {\n\t\t\tmodel = m.Fields(pointer)\n\t\t}\n\t}\n\tone, err := model.One(where...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err = one.Struct(pointer); err != nil {\n\t\treturn err\n\t}\n\treturn model.doWithScanStruct(pointer)\n}\n\n// Structs retrieves records from table and converts them into given struct slice.\n// The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct\n// slice internally during converting.\n//\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\n//\n// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has\n// default value and there's no record retrieved with the given conditions from table.\n//\n// Example:\n// users := ([]User)(nil)\n// err   := db.Model(\"user\").Scan(&users)\n//\n// users := ([]*User)(nil)\n// err   := db.Model(\"user\").Scan(&users).\nfunc (m *Model) doStructs(pointer any, where ...any) error {\n\tmodel := m\n\t// Auto selecting fields by struct attributes.\n\tif len(model.fieldsEx) == 0 && len(model.fields) == 0 {\n\t\tif v, ok := pointer.(reflect.Value); ok {\n\t\t\tmodel = m.Fields(\n\t\t\t\treflect.New(\n\t\t\t\t\tv.Type().Elem(),\n\t\t\t\t).Interface(),\n\t\t\t)\n\t\t} else {\n\t\t\tmodel = m.Fields(\n\t\t\t\treflect.New(\n\t\t\t\t\treflect.ValueOf(pointer).Elem().Type().Elem(),\n\t\t\t\t).Interface(),\n\t\t\t)\n\t\t}\n\t}\n\tall, err := model.All(where...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err = all.Structs(pointer); err != nil {\n\t\treturn err\n\t}\n\treturn model.doWithScanStructs(pointer)\n}\n\n// Scan automatically calls Struct or Structs function according to the type of parameter `pointer`.\n// It calls function doStruct if `pointer` is type of *struct/**struct.\n// It calls function doStructs if `pointer` is type of *[]struct/*[]*struct.\n//\n// The optional parameter `where` is the same as the parameter of Model.Where function,  see Model.Where.\n//\n// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has\n// default value and there's no record retrieved with the given conditions from table.\n//\n// Example:\n// user := new(User)\n// err  := db.Model(\"user\").Where(\"id\", 1).Scan(user)\n//\n// user := (*User)(nil)\n// err  := db.Model(\"user\").Where(\"id\", 1).Scan(&user)\n//\n// users := ([]User)(nil)\n// err   := db.Model(\"user\").Scan(&users)\n//\n// users := ([]*User)(nil)\n// err   := db.Model(\"user\").Scan(&users).\nfunc (m *Model) Scan(pointer any, where ...any) error {\n\treflectInfo := reflection.OriginTypeAndKind(pointer)\n\tif reflectInfo.InputKind != reflect.Pointer {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`the parameter \"pointer\" for function Scan should type of pointer`,\n\t\t)\n\t}\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\treturn m.doStructs(pointer, where...)\n\n\tcase reflect.Struct, reflect.Invalid:\n\t\treturn m.doStruct(pointer, where...)\n\n\tdefault:\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`element of parameter \"pointer\" for function Scan should type of struct/*struct/[]struct/[]*struct`,\n\t\t)\n\t}\n}\n\n// ScanAndCount scans a single record or record array that matches the given conditions and counts the total number\n// of records that match those conditions.\n//\n// If `useFieldForCount` is true, it will use the fields specified in the model for counting;\n// The `pointer` parameter is a pointer to a struct that the scanned data will be stored in.\n// The `totalCount` parameter is a pointer to an integer that will be set to the total number of records that match the given conditions.\n// The where parameter is an optional list of conditions to use when retrieving records.\n//\n// Example:\n//\n//\tvar count int\n//\tuser := new(User)\n//\terr  := db.Model(\"user\").Where(\"id\", 1).ScanAndCount(user,&count,true)\n//\tfmt.Println(user, count)\n//\n// Example Join:\n//\n//\ttype User struct {\n//\t\tId       int\n//\t\tPassport string\n//\t\tName     string\n//\t\tAge      int\n//\t}\n//\tvar users []User\n//\tvar count int\n//\tdb.Model(table).As(\"u1\").\n//\t\tLeftJoin(tableName2, \"u2\", \"u2.id=u1.id\").\n//\t\tFields(\"u1.passport,u1.id,u2.name,u2.age\").\n//\t\tWhere(\"u1.id<2\").\n//\t\tScanAndCount(&users, &count, false)\nfunc (m *Model) ScanAndCount(pointer any, totalCount *int, useFieldForCount bool) (err error) {\n\t// support Fields with *, example: .Fields(\"a.*, b.name\"). Count sql is select count(1) from xxx\n\tcountModel := m.Clone()\n\t// Decide how to build the COUNT() expression:\n\t// - If caller explicitly wants to use the single field expression for counting,\n\t//   honor it (e.g. Fields(\"DISTINCT col\") with useFieldForCount = true).\n\t// - Otherwise, clear fields to let Count() use its default COUNT(1),\n\t//   avoiding invalid COUNT(field1, field2, ...) with multiple fields,\n\t//   or incorrect COUNT(DISTINCT 1) when Distinct() is set.\n\tif useFieldForCount && len(m.fields) == 1 {\n\t\tcountModel.fields = m.fields\n\t} else {\n\t\tcountModel.fields = nil\n\t}\n\tif len(m.pageCacheOption) > 0 {\n\t\tcountModel = countModel.Cache(m.pageCacheOption[0])\n\t}\n\t// Get the total count of records\n\t*totalCount, err = countModel.Count()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// If the total count is 0, there are no records to retrieve, so return early\n\tif *totalCount == 0 {\n\t\treturn\n\t}\n\tscanModel := m.Clone()\n\tif len(m.pageCacheOption) > 1 {\n\t\tscanModel = scanModel.Cache(m.pageCacheOption[1])\n\t}\n\terr = scanModel.Scan(pointer)\n\treturn\n}\n\n// ScanList converts `r` to struct slice which contains other complex struct attributes.\n// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.\n//\n// See Result.ScanList.\nfunc (m *Model) ScanList(structSlicePointer any, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {\n\tvar result Result\n\tout, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(m.fields) > 0 || len(m.fieldsEx) != 0 {\n\t\t// There are custom fields.\n\t\tresult, err = m.All()\n\t} else {\n\t\t// Filter fields using temporary created struct using reflect.New.\n\t\tresult, err = m.Fields(reflect.New(out.BindToAttrType).Interface()).All()\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar (\n\t\trelationAttrName string\n\t\trelationFields   string\n\t)\n\tswitch len(relationAttrNameAndFields) {\n\tcase 2:\n\t\trelationAttrName = relationAttrNameAndFields[0]\n\t\trelationFields = relationAttrNameAndFields[1]\n\tcase 1:\n\t\trelationFields = relationAttrNameAndFields[0]\n\t}\n\treturn doScanList(doScanListInput{\n\t\tModel:              m,\n\t\tResult:             result,\n\t\tStructSlicePointer: structSlicePointer,\n\t\tStructSliceValue:   out.SliceReflectValue,\n\t\tBindToAttrName:     bindToAttrName,\n\t\tRelationAttrName:   relationAttrName,\n\t\tRelationFields:     relationFields,\n\t})\n}\n\n// Value retrieves a specified record value from table and returns the result as interface type.\n// It returns nil if there's no record found with the given conditions from table.\n//\n// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields\n// and fieldsAndWhere[1:] is treated as where condition fields.\n// Also see Model.Fields and Model.Where functions.\nfunc (m *Model) Value(fieldsAndWhere ...any) (Value, error) {\n\tvar (\n\t\tcore = m.db.GetCore()\n\t\tctx  = core.injectInternalColumn(m.GetCtx())\n\t)\n\tif len(fieldsAndWhere) > 0 {\n\t\tif len(fieldsAndWhere) > 2 {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Value()\n\t\t} else if len(fieldsAndWhere) == 2 {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Value()\n\t\t} else {\n\t\t\treturn m.Fields(gconv.String(fieldsAndWhere[0])).Value()\n\t\t}\n\t}\n\tvar (\n\t\tsqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(ctx, SelectTypeValue, true)\n\t\tall, err                  = m.doGetAllBySql(ctx, SelectTypeValue, sqlWithHolder, holderArgs...)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(all) > 0 {\n\t\tinternalData := core.getInternalColumnFromCtx(ctx)\n\t\tif internalData == nil {\n\t\t\treturn nil, gerror.NewCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\t`query count error: the internal context data is missing. there's internal issue should be fixed`,\n\t\t\t)\n\t\t}\n\t\t// If FirstResultColumn present, it returns the value of the first record of the first field.\n\t\t// It means it use no cache mechanism, while cache mechanism makes `internalData` missing.\n\t\tif v, ok := all[0][internalData.FirstResultColumn]; ok {\n\t\t\treturn v, nil\n\t\t}\n\t\t// Fields number check.\n\t\tvar recordFields = m.getRecordFields(all[0])\n\t\tif len(recordFields) == 1 {\n\t\t\tfor _, v := range all[0] {\n\t\t\t\treturn v, nil\n\t\t\t}\n\t\t}\n\t\t// it returns error if there are multiple fields in the result record.\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid fields for \"Value\" operation, result fields number \"%d\"%s, but expect one`,\n\t\t\tlen(recordFields),\n\t\t\tgjson.MustEncodeString(recordFields),\n\t\t)\n\t}\n\treturn nil, nil\n}\n\nfunc (m *Model) getRecordFields(record Record) []string {\n\tif len(record) == 0 {\n\t\treturn nil\n\t}\n\tvar fields = make([]string, 0)\n\tfor k := range record {\n\t\tfields = append(fields, k)\n\t}\n\treturn fields\n}\n\n// Count does \"SELECT COUNT(x) FROM ...\" statement for the model.\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) Count(where ...any) (int, error) {\n\tvar (\n\t\tcore = m.db.GetCore()\n\t\tctx  = core.injectInternalColumn(m.GetCtx())\n\t)\n\tif len(where) > 0 {\n\t\treturn m.Where(where[0], where[1:]...).Count()\n\t}\n\tvar (\n\t\tsqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(ctx, SelectTypeCount, false)\n\t\tall, err                  = m.doGetAllBySql(ctx, SelectTypeCount, sqlWithHolder, holderArgs...)\n\t)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif len(all) > 0 {\n\t\tinternalData := core.getInternalColumnFromCtx(ctx)\n\t\tif internalData == nil {\n\t\t\treturn 0, gerror.NewCode(\n\t\t\t\tgcode.CodeInternalError,\n\t\t\t\t`query count error: the internal context data is missing. there's internal issue should be fixed`,\n\t\t\t)\n\t\t}\n\t\t// If FirstResultColumn present, it returns the value of the first record of the first field.\n\t\t// It means it use no cache mechanism, while cache mechanism makes `internalData` missing.\n\t\tif v, ok := all[0][internalData.FirstResultColumn]; ok {\n\t\t\treturn v.Int(), nil\n\t\t}\n\t\t// Fields number check.\n\t\tvar recordFields = m.getRecordFields(all[0])\n\t\tif len(recordFields) == 1 {\n\t\t\tfor _, v := range all[0] {\n\t\t\t\treturn v.Int(), nil\n\t\t\t}\n\t\t}\n\t\t// it returns error if there are multiple fields in the result record.\n\t\treturn 0, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid fields for \"Count\" operation, result fields number \"%d\"%s, but expect one`,\n\t\t\tlen(recordFields),\n\t\t\tgjson.MustEncodeString(recordFields),\n\t\t)\n\t}\n\treturn 0, nil\n}\n\n// Exist does \"SELECT 1 FROM ... LIMIT 1\" statement for the model.\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) Exist(where ...any) (bool, error) {\n\tif len(where) > 0 {\n\t\treturn m.Where(where[0], where[1:]...).Exist()\n\t}\n\tone, err := m.Fields(Raw(\"1\")).One()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tfor _, val := range one {\n\t\tif val.Bool() {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// CountColumn does \"SELECT COUNT(x) FROM ...\" statement for the model.\nfunc (m *Model) CountColumn(column string) (int, error) {\n\tif len(column) == 0 {\n\t\treturn 0, nil\n\t}\n\treturn m.Fields(column).Count()\n}\n\n// Min does \"SELECT MIN(x) FROM ...\" statement for the model.\nfunc (m *Model) Min(column string) (float64, error) {\n\tif len(column) == 0 {\n\t\treturn 0, nil\n\t}\n\tvalue, err := m.Fields(fmt.Sprintf(`MIN(%s)`, m.QuoteWord(column))).Value()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Float64(), err\n}\n\n// Max does \"SELECT MAX(x) FROM ...\" statement for the model.\nfunc (m *Model) Max(column string) (float64, error) {\n\tif len(column) == 0 {\n\t\treturn 0, nil\n\t}\n\tvalue, err := m.Fields(fmt.Sprintf(`MAX(%s)`, m.QuoteWord(column))).Value()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Float64(), err\n}\n\n// Avg does \"SELECT AVG(x) FROM ...\" statement for the model.\nfunc (m *Model) Avg(column string) (float64, error) {\n\tif len(column) == 0 {\n\t\treturn 0, nil\n\t}\n\tvalue, err := m.Fields(fmt.Sprintf(`AVG(%s)`, m.QuoteWord(column))).Value()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Float64(), err\n}\n\n// Sum does \"SELECT SUM(x) FROM ...\" statement for the model.\nfunc (m *Model) Sum(column string) (float64, error) {\n\tif len(column) == 0 {\n\t\treturn 0, nil\n\t}\n\tvalue, err := m.Fields(fmt.Sprintf(`SUM(%s)`, m.QuoteWord(column))).Value()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn value.Float64(), err\n}\n\n// Union does \"(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ...\" statement for the model.\nfunc (m *Model) Union(unions ...*Model) *Model {\n\treturn m.db.Union(unions...)\n}\n\n// UnionAll does \"(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ...\" statement for the model.\nfunc (m *Model) UnionAll(unions ...*Model) *Model {\n\treturn m.db.UnionAll(unions...)\n}\n\n// Limit sets the \"LIMIT\" statement for the model.\n// The parameter `limit` can be either one or two number, if passed two number is passed,\n// it then sets \"LIMIT limit[0],limit[1]\" statement for the model, or else it sets \"LIMIT limit[0]\"\n// statement.\n// Note: Negative values are treated as zero.\nfunc (m *Model) Limit(limit ...int) *Model {\n\tmodel := m.getModel()\n\tswitch len(limit) {\n\tcase 1:\n\t\tif limit[0] < 0 {\n\t\t\tlimit[0] = 0\n\t\t}\n\t\tmodel.limit = limit[0]\n\tcase 2:\n\t\tif limit[0] < 0 {\n\t\t\tlimit[0] = 0\n\t\t}\n\t\tif limit[1] < 0 {\n\t\t\tlimit[1] = 0\n\t\t}\n\t\tmodel.start = limit[0]\n\t\tmodel.limit = limit[1]\n\t}\n\treturn model\n}\n\n// Offset sets the \"OFFSET\" statement for the model.\n// It only makes sense for some databases like SQLServer, PostgreSQL, etc.\n// Note: Negative values are treated as zero.\nfunc (m *Model) Offset(offset int) *Model {\n\tmodel := m.getModel()\n\tif offset < 0 {\n\t\toffset = 0\n\t}\n\tmodel.offset = offset\n\treturn model\n}\n\n// Distinct forces the query to only return distinct results.\nfunc (m *Model) Distinct() *Model {\n\tmodel := m.getModel()\n\tmodel.distinct = \"DISTINCT \"\n\treturn model\n}\n\n// Page sets the paging number for the model.\n// The parameter `page` is started from 1 for paging.\n// Note that, it differs that the Limit function starts from 0 for \"LIMIT\" statement.\n// Note: Negative limit values are treated as zero.\nfunc (m *Model) Page(page, limit int) *Model {\n\tmodel := m.getModel()\n\tif page <= 0 {\n\t\tpage = 1\n\t}\n\tif limit < 0 {\n\t\tlimit = 0\n\t}\n\tmodel.start = (page - 1) * limit\n\tmodel.limit = limit\n\treturn model\n}\n\n// Having sets the having statement for the model.\n// The parameters of this function usage are as the same as function Where.\n// See Where.\nfunc (m *Model) Having(having any, args ...any) *Model {\n\tmodel := m.getModel()\n\tmodel.having = []any{\n\t\thaving, args,\n\t}\n\treturn model\n}\n\n// doGetAll does \"SELECT FROM ...\" statement for the model.\n// It retrieves the records from table and returns the result as slice type.\n// It returns nil if there's no record retrieved with the given conditions from table.\n//\n// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.\n// The optional parameter `where` is the same as the parameter of Model.Where function,\n// see Model.Where.\nfunc (m *Model) doGetAll(ctx context.Context, selectType SelectType, limit1 bool, where ...any) (Result, error) {\n\tif len(where) > 0 {\n\t\treturn m.Where(where[0], where[1:]...).All()\n\t}\n\tsqlWithHolder, holderArgs := m.getFormattedSqlAndArgs(ctx, selectType, limit1)\n\treturn m.doGetAllBySql(ctx, selectType, sqlWithHolder, holderArgs...)\n}\n\n// doGetAllBySql does the select statement on the database.\nfunc (m *Model) doGetAllBySql(\n\tctx context.Context, selectType SelectType, sql string, args ...any,\n) (result Result, err error) {\n\tif result, err = m.getSelectResultFromCache(ctx, sql, args...); err != nil || result != nil {\n\t\treturn\n\t}\n\n\tin := &HookSelectInput{\n\t\tinternalParamHookSelect: internalParamHookSelect{\n\t\t\tinternalParamHook: internalParamHook{\n\t\t\t\tlink: m.getLink(false),\n\t\t\t},\n\t\t\thandler: m.hookHandler.Select,\n\t\t},\n\t\tModel:      m,\n\t\tTable:      m.tables,\n\t\tSchema:     m.schema,\n\t\tSql:        sql,\n\t\tArgs:       m.mergeArguments(args),\n\t\tSelectType: selectType,\n\t}\n\tif result, err = in.Next(ctx); err != nil {\n\t\treturn\n\t}\n\n\terr = m.saveSelectResultToCache(ctx, selectType, result, sql, args...)\n\treturn\n}\n\nfunc (m *Model) getFormattedSqlAndArgs(\n\tctx context.Context, selectType SelectType, limit1 bool,\n) (sqlWithHolder string, holderArgs []any) {\n\tswitch selectType {\n\tcase SelectTypeCount:\n\t\tqueryFields := \"COUNT(1)\"\n\t\tif len(m.fields) > 0 {\n\t\t\t// DO NOT quote the m.fields here, in case of fields like:\n\t\t\t// DISTINCT t.user_id uid\n\t\t\tqueryFields = fmt.Sprintf(`COUNT(%s%s)`, m.distinct, m.getFieldsAsStr())\n\t\t}\n\t\t// Raw SQL Model.\n\t\tif m.rawSql != \"\" {\n\t\t\tconditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, false, true)\n\t\t\tsqlWithHolder = fmt.Sprintf(\n\t\t\t\t\"SELECT %s FROM (%s%s) AS T\",\n\t\t\t\tqueryFields, m.rawSql, conditionWhere+conditionExtra,\n\t\t\t)\n\t\t\treturn sqlWithHolder, conditionArgs\n\t\t}\n\t\tconditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, false, true)\n\t\tsqlWithHolder = fmt.Sprintf(\"SELECT %s FROM %s%s\", queryFields, m.tables, conditionWhere+conditionExtra)\n\t\tif len(m.groupBy) > 0 {\n\t\t\tsqlWithHolder = fmt.Sprintf(\"SELECT COUNT(1) FROM (%s) count_alias\", sqlWithHolder)\n\t\t}\n\t\treturn sqlWithHolder, conditionArgs\n\n\tdefault:\n\t\tconditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, limit1, false)\n\t\t// Raw SQL Model, especially for UNION/UNION ALL featured SQL.\n\t\tif m.rawSql != \"\" {\n\t\t\tsqlWithHolder = fmt.Sprintf(\n\t\t\t\t\"%s%s\",\n\t\t\t\tm.rawSql,\n\t\t\t\tconditionWhere+conditionExtra,\n\t\t\t)\n\t\t\treturn sqlWithHolder, conditionArgs\n\t\t}\n\t\t// DO NOT quote the m.fields where, in case of fields like:\n\t\t// DISTINCT t.user_id uid\n\t\tsqlWithHolder = fmt.Sprintf(\n\t\t\t\"SELECT %s%s FROM %s%s\",\n\t\t\tm.distinct, m.getFieldsFiltered(), m.tables, conditionWhere+conditionExtra,\n\t\t)\n\t\treturn sqlWithHolder, conditionArgs\n\t}\n}\n\nfunc (m *Model) getHolderAndArgsAsSubModel(ctx context.Context) (holder string, args []any) {\n\tholder, args = m.getFormattedSqlAndArgs(\n\t\tctx, SelectTypeDefault, false,\n\t)\n\targs = m.mergeArguments(args)\n\treturn\n}\n\nfunc (m *Model) getAutoPrefix() string {\n\tautoPrefix := \"\"\n\tif gstr.Contains(m.tables, \" JOIN \") {\n\t\tautoPrefix = m.QuoteWord(\n\t\t\tm.db.GetCore().guessPrimaryTableName(m.tablesInit),\n\t\t)\n\t}\n\treturn autoPrefix\n}\n\nfunc (m *Model) getFieldsAsStr() string {\n\tvar (\n\t\tfieldsStr string\n\t)\n\tfor _, v := range m.fields {\n\t\tfield := gconv.String(v)\n\t\tswitch {\n\t\tcase gstr.ContainsAny(field, \"()\"):\n\t\tcase gstr.ContainsAny(field, \". \"):\n\t\tdefault:\n\t\t\tswitch v.(type) {\n\t\t\tcase Raw, *Raw:\n\t\t\tdefault:\n\t\t\t\tfield = m.QuoteWord(field)\n\t\t\t}\n\t\t}\n\t\tif fieldsStr != \"\" {\n\t\t\tfieldsStr += \",\"\n\t\t}\n\t\tfieldsStr += field\n\t}\n\treturn fieldsStr\n}\n\n// getFieldsFiltered checks the fields and fieldsEx attributes, filters and returns the fields that will\n// really be committed to underlying database driver.\nfunc (m *Model) getFieldsFiltered() string {\n\tif len(m.fieldsEx) == 0 && len(m.fields) == 0 {\n\t\treturn defaultField\n\t}\n\tif len(m.fieldsEx) == 0 && len(m.fields) > 0 {\n\t\treturn m.getFieldsAsStr()\n\t}\n\tvar (\n\t\tfieldsArray []string\n\t\tfieldsExSet = gset.NewStrSetFrom(gconv.Strings(m.fieldsEx))\n\t)\n\tif len(m.fields) > 0 {\n\t\t// Filter custom fields with fieldEx.\n\t\tfieldsArray = make([]string, 0, 8)\n\t\tfor _, v := range m.fields {\n\t\t\tfield := gconv.String(v)\n\t\t\tfieldsArray = append(fieldsArray, field[gstr.PosR(field, \"-\")+1:])\n\t\t}\n\t} else {\n\t\tif gstr.Contains(m.tables, \" \") {\n\t\t\tpanic(\"function FieldsEx supports only single table operations\")\n\t\t}\n\t\t// Filter table fields with fieldEx.\n\t\ttableFields, err := m.TableFields(m.tablesInit)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tif len(tableFields) == 0 {\n\t\t\tpanic(fmt.Sprintf(`empty table fields for table \"%s\"`, m.tables))\n\t\t}\n\t\tfieldsArray = make([]string, len(tableFields))\n\t\tfor k, v := range tableFields {\n\t\t\tfieldsArray[v.Index] = k\n\t\t}\n\t}\n\tnewFields := \"\"\n\tfor _, k := range fieldsArray {\n\t\tif fieldsExSet.Contains(k) {\n\t\t\tcontinue\n\t\t}\n\t\tif len(newFields) > 0 {\n\t\t\tnewFields += \",\"\n\t\t}\n\t\tnewFields += m.QuoteWord(k)\n\t}\n\treturn newFields\n}\n\n// formatCondition formats where arguments of the model and returns a new condition sql and its arguments.\n// Note that this function does not change any attribute value of the `m`.\n//\n// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.\nfunc (m *Model) formatCondition(\n\tctx context.Context, limit1 bool, isCountStatement bool,\n) (conditionWhere string, conditionExtra string, conditionArgs []any) {\n\tvar autoPrefix = m.getAutoPrefix()\n\t// GROUP BY.\n\tif m.groupBy != \"\" {\n\t\tconditionExtra += \" GROUP BY \" + m.groupBy\n\t}\n\t// WHERE\n\tconditionWhere, conditionArgs = m.whereBuilder.Build()\n\tsoftDeletingCondition := m.softTimeMaintainer().GetDeleteCondition(ctx)\n\tif m.rawSql != \"\" && conditionWhere != \"\" {\n\t\tif gstr.ContainsI(m.rawSql, \" WHERE \") {\n\t\t\tconditionWhere = \" AND \" + conditionWhere\n\t\t} else {\n\t\t\tconditionWhere = \" WHERE \" + conditionWhere\n\t\t}\n\t} else if !m.unscoped && softDeletingCondition != \"\" {\n\t\tif conditionWhere == \"\" {\n\t\t\tconditionWhere = fmt.Sprintf(` WHERE %s`, softDeletingCondition)\n\t\t} else {\n\t\t\tconditionWhere = fmt.Sprintf(` WHERE (%s) AND %s`, conditionWhere, softDeletingCondition)\n\t\t}\n\t} else {\n\t\tif conditionWhere != \"\" {\n\t\t\tconditionWhere = \" WHERE \" + conditionWhere\n\t\t}\n\t}\n\t// HAVING.\n\tif len(m.having) > 0 {\n\t\thavingHolder := WhereHolder{\n\t\t\tWhere:  m.having[0],\n\t\t\tArgs:   gconv.Interfaces(m.having[1]),\n\t\t\tPrefix: autoPrefix,\n\t\t}\n\t\thavingStr, havingArgs := formatWhereHolder(ctx, m.db, formatWhereHolderInput{\n\t\t\tWhereHolder: havingHolder,\n\t\t\tOmitNil:     m.option&optionOmitNilWhere > 0,\n\t\t\tOmitEmpty:   m.option&optionOmitEmptyWhere > 0,\n\t\t\tSchema:      m.schema,\n\t\t\tTable:       m.tables,\n\t\t})\n\t\tif len(havingStr) > 0 {\n\t\t\tconditionExtra += \" HAVING \" + havingStr\n\t\t\tconditionArgs = append(conditionArgs, havingArgs...)\n\t\t}\n\t}\n\t// ORDER BY.\n\tif !isCountStatement { // The count statement of sqlserver cannot contain the order by statement\n\t\tif m.orderBy != \"\" {\n\t\t\tconditionExtra += \" ORDER BY \" + m.orderBy\n\t\t}\n\t}\n\t// LIMIT.\n\tif !isCountStatement {\n\t\tif m.limit != 0 {\n\t\t\tif m.start >= 0 {\n\t\t\t\tconditionExtra += fmt.Sprintf(\" LIMIT %d,%d\", m.start, m.limit)\n\t\t\t} else {\n\t\t\t\tconditionExtra += fmt.Sprintf(\" LIMIT %d\", m.limit)\n\t\t\t}\n\t\t} else if limit1 {\n\t\t\tconditionExtra += \" LIMIT 1\"\n\t\t}\n\n\t\tif m.offset >= 0 {\n\t\t\tconditionExtra += fmt.Sprintf(\" OFFSET %d\", m.offset)\n\t\t}\n\t}\n\n\tif m.lockInfo != \"\" {\n\t\tconditionExtra += \" \" + m.lockInfo\n\t}\n\treturn\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_sharding.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ShardingConfig defines the configuration for database/table sharding.\ntype ShardingConfig struct {\n\t// Table sharding configuration\n\tTable ShardingTableConfig\n\t// Schema sharding configuration\n\tSchema ShardingSchemaConfig\n}\n\n// ShardingSchemaConfig defines the configuration for database sharding.\ntype ShardingSchemaConfig struct {\n\t// Enable schema sharding\n\tEnable bool\n\t// Schema rule prefix, e.g., \"db_\"\n\tPrefix string\n\t// ShardingRule defines how to route data to different database nodes\n\tRule ShardingRule\n}\n\n// ShardingTableConfig defines the configuration for table sharding\ntype ShardingTableConfig struct {\n\t// Enable table sharding\n\tEnable bool\n\t// Table rule prefix, e.g., \"user_\"\n\tPrefix string\n\t// ShardingRule defines how to route data to different tables\n\tRule ShardingRule\n}\n\n// ShardingRule defines the interface for sharding rules\ntype ShardingRule interface {\n\t// SchemaName returns the target schema name based on sharding value.\n\tSchemaName(ctx context.Context, config ShardingSchemaConfig, value any) (string, error)\n\t// TableName returns the target table name based on sharding value.\n\tTableName(ctx context.Context, config ShardingTableConfig, value any) (string, error)\n}\n\n// DefaultShardingRule implements a simple modulo-based sharding rule\ntype DefaultShardingRule struct {\n\t// Number of schema count.\n\tSchemaCount int\n\t// Number of tables per schema.\n\tTableCount int\n}\n\n// Sharding creates a sharding model with given sharding configuration.\nfunc (m *Model) Sharding(config ShardingConfig) *Model {\n\tmodel := m.getModel()\n\tmodel.shardingConfig = config\n\treturn model\n}\n\n// ShardingValue sets the sharding value for routing\nfunc (m *Model) ShardingValue(value any) *Model {\n\tmodel := m.getModel()\n\tmodel.shardingValue = value\n\treturn model\n}\n\n// getActualSchema returns the actual schema based on sharding configuration.\n// TODO it does not support schemas in different database config node.\nfunc (m *Model) getActualSchema(ctx context.Context, defaultSchema string) (string, error) {\n\tif !m.shardingConfig.Schema.Enable {\n\t\treturn defaultSchema, nil\n\t}\n\tif m.shardingValue == nil {\n\t\treturn defaultSchema, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"sharding value is required when sharding feature enabled\",\n\t\t)\n\t}\n\tif m.shardingConfig.Schema.Rule == nil {\n\t\treturn defaultSchema, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"sharding rule is required when sharding feature enabled\",\n\t\t)\n\t}\n\treturn m.shardingConfig.Schema.Rule.SchemaName(ctx, m.shardingConfig.Schema, m.shardingValue)\n}\n\n// getActualTable returns the actual table name based on sharding configuration\nfunc (m *Model) getActualTable(ctx context.Context, defaultTable string) (string, error) {\n\tif !m.shardingConfig.Table.Enable {\n\t\treturn defaultTable, nil\n\t}\n\tif m.shardingValue == nil {\n\t\treturn defaultTable, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"sharding value is required when sharding feature enabled\",\n\t\t)\n\t}\n\tif m.shardingConfig.Table.Rule == nil {\n\t\treturn defaultTable, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"sharding rule is required when sharding feature enabled\",\n\t\t)\n\t}\n\treturn m.shardingConfig.Table.Rule.TableName(ctx, m.shardingConfig.Table, m.shardingValue)\n}\n\n// SchemaName implements the default database sharding strategy\nfunc (r *DefaultShardingRule) SchemaName(ctx context.Context, config ShardingSchemaConfig, value any) (string, error) {\n\tif r.SchemaCount == 0 {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"schema count should not be 0 using DefaultShardingRule when schema sharding enabled\",\n\t\t)\n\t}\n\thashValue, err := getHashValue(value)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tnodeIndex := hashValue % uint64(r.SchemaCount)\n\treturn fmt.Sprintf(\"%s%d\", config.Prefix, nodeIndex), nil\n}\n\n// TableName implements the default table sharding strategy\nfunc (r *DefaultShardingRule) TableName(ctx context.Context, config ShardingTableConfig, value any) (string, error) {\n\tif r.TableCount == 0 {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter, \"table count should not be 0 using DefaultShardingRule when table sharding enabled\",\n\t\t)\n\t}\n\thashValue, err := getHashValue(value)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ttableIndex := hashValue % uint64(r.TableCount)\n\treturn fmt.Sprintf(\"%s%d\", config.Prefix, tableIndex), nil\n}\n\n// getHashValue converts sharding value to uint64 hash\nfunc getHashValue(value any) (uint64, error) {\n\tvar rv = reflect.ValueOf(value)\n\tswitch rv.Kind() {\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,\n\t\treflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,\n\t\treflect.Float32, reflect.Float64:\n\t\treturn gconv.Uint64(value), nil\n\tdefault:\n\t\th := fnv.New64a()\n\t\t_, err := h.Write(gconv.Bytes(value))\n\t\tif err != nil {\n\t\t\treturn 0, gerror.WrapCode(gcode.CodeInternalError, err)\n\t\t}\n\t\treturn h.Sum64(), nil\n\t}\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_soft_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SoftTimeType custom defines the soft time field type.\ntype SoftTimeType int\n\nconst (\n\tSoftTimeTypeAuto           SoftTimeType = 0 // (Default)Auto detect the field type by table field type.\n\tSoftTimeTypeTime           SoftTimeType = 1 // Using datetime as the field value.\n\tSoftTimeTypeTimestamp      SoftTimeType = 2 // In unix seconds.\n\tSoftTimeTypeTimestampMilli SoftTimeType = 3 // In unix milliseconds.\n\tSoftTimeTypeTimestampMicro SoftTimeType = 4 // In unix microseconds.\n\tSoftTimeTypeTimestampNano  SoftTimeType = 5 // In unix nanoseconds.\n)\n\n// SoftTimeOption is the option to customize soft time feature for Model.\ntype SoftTimeOption struct {\n\tSoftTimeType SoftTimeType // The value type for soft time field.\n}\n\ntype softTimeMaintainer struct {\n\t*Model\n}\n\n// SoftTimeFieldType represents different soft time field purposes.\ntype SoftTimeFieldType int\n\nconst (\n\tSoftTimeFieldCreate SoftTimeFieldType = iota\n\tSoftTimeFieldUpdate\n\tSoftTimeFieldDelete\n)\n\ntype iSoftTimeMaintainer interface {\n\t// GetFieldInfo returns field name and type for specified field purpose.\n\tGetFieldInfo(ctx context.Context, schema, table string, fieldPurpose SoftTimeFieldType) (fieldName string, localType LocalType)\n\n\t// GetFieldValue generates value for create/update/delete operations.\n\tGetFieldValue(ctx context.Context, localType LocalType, isDeleted bool) any\n\n\t// GetDeleteCondition returns WHERE condition for soft delete query.\n\tGetDeleteCondition(ctx context.Context) string\n\n\t// GetDeleteData returns UPDATE statement data for soft delete.\n\tGetDeleteData(ctx context.Context, prefix, fieldName string, localType LocalType) (holder string, value any)\n}\n\n// getSoftFieldNameAndTypeCacheItem is the internal struct for storing create/update/delete fields.\ntype getSoftFieldNameAndTypeCacheItem struct {\n\tFieldName string\n\tFieldType LocalType\n}\n\nvar (\n\t// Default field names of table for automatic-filled for record creating.\n\tcreatedFieldNames = []string{\"created_at\", \"create_at\"}\n\t// Default field names of table for automatic-filled for record updating.\n\tupdatedFieldNames = []string{\"updated_at\", \"update_at\"}\n\t// Default field names of table for automatic-filled for record deleting.\n\tdeletedFieldNames = []string{\"deleted_at\", \"delete_at\"}\n)\n\n// SoftTime sets the SoftTimeOption to customize soft time feature for Model.\nfunc (m *Model) SoftTime(option SoftTimeOption) *Model {\n\tmodel := m.getModel()\n\tmodel.softTimeOption = option\n\treturn model\n}\n\n// Unscoped disables the soft time feature for insert, update and delete operations.\nfunc (m *Model) Unscoped() *Model {\n\tmodel := m.getModel()\n\tmodel.unscoped = true\n\treturn model\n}\n\nfunc (m *Model) softTimeMaintainer() iSoftTimeMaintainer {\n\treturn &softTimeMaintainer{\n\t\tm,\n\t}\n}\n\n// GetFieldInfo returns field name and type for specified field purpose.\n// It checks the key with or without cases or chars '-'/'_'/'.'/' '.\nfunc (m *softTimeMaintainer) GetFieldInfo(\n\tctx context.Context, schema, table string, fieldPurpose SoftTimeFieldType,\n) (fieldName string, localType LocalType) {\n\t// Check if feature is disabled\n\tif m.db.GetConfig().TimeMaintainDisabled {\n\t\treturn \"\", LocalTypeUndefined\n\t}\n\n\t// Determine table name\n\ttableName := table\n\tif tableName == \"\" {\n\t\ttableName = m.tablesInit\n\t}\n\n\t// Get config and field candidates\n\tconfig := m.db.GetConfig()\n\tvar (\n\t\tconfigField   string\n\t\tdefaultFields []string\n\t)\n\n\tswitch fieldPurpose {\n\tcase SoftTimeFieldCreate:\n\t\tconfigField = config.CreatedAt\n\t\tdefaultFields = createdFieldNames\n\tcase SoftTimeFieldUpdate:\n\t\tconfigField = config.UpdatedAt\n\t\tdefaultFields = updatedFieldNames\n\tcase SoftTimeFieldDelete:\n\t\tconfigField = config.DeletedAt\n\t\tdefaultFields = deletedFieldNames\n\t}\n\n\t// Use config field if specified, otherwise use defaults\n\tif configField != \"\" {\n\t\treturn m.getSoftFieldNameAndType(ctx, schema, tableName, []string{configField})\n\t}\n\treturn m.getSoftFieldNameAndType(ctx, schema, tableName, defaultFields)\n}\n\n// getSoftFieldNameAndType retrieves and returns the field name of the table for possible key.\nfunc (m *softTimeMaintainer) getSoftFieldNameAndType(\n\tctx context.Context, schema, table string, candidateFields []string,\n) (fieldName string, fieldType LocalType) {\n\t// Build cache key\n\tcacheKey := genSoftTimeFieldNameTypeCacheKey(schema, table, candidateFields)\n\n\t// Try to get from cache\n\tcache := m.db.GetCore().GetInnerMemCache()\n\tresult, err := cache.GetOrSetFunc(ctx, cacheKey, func(ctx context.Context) (any, error) {\n\t\t// Get table fields\n\t\tfieldsMap, err := m.TableFields(table, schema)\n\t\tif err != nil || len(fieldsMap) == 0 {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Search for matching field\n\t\tfor _, field := range candidateFields {\n\t\t\tif name := searchFieldNameFromMap(fieldsMap, field); name != \"\" {\n\t\t\t\tfType, _ := m.db.CheckLocalTypeForField(ctx, fieldsMap[name].Type, nil)\n\t\t\t\treturn getSoftFieldNameAndTypeCacheItem{\n\t\t\t\t\tFieldName: name,\n\t\t\t\t\tFieldType: fType,\n\t\t\t\t}, nil\n\t\t\t}\n\t\t}\n\t\treturn nil, nil\n\t}, gcache.DurationNoExpire)\n\n\tif err != nil || result == nil {\n\t\treturn \"\", LocalTypeUndefined\n\t}\n\n\titem := result.Val().(getSoftFieldNameAndTypeCacheItem)\n\treturn item.FieldName, item.FieldType\n}\n\nfunc searchFieldNameFromMap(fieldsMap map[string]*TableField, key string) string {\n\tif len(fieldsMap) == 0 {\n\t\treturn \"\"\n\t}\n\t_, ok := fieldsMap[key]\n\tif ok {\n\t\treturn key\n\t}\n\tkey = utils.RemoveSymbols(key)\n\tfor k := range fieldsMap {\n\t\tif strings.EqualFold(utils.RemoveSymbols(k), key) {\n\t\t\treturn k\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetDeleteCondition returns WHERE condition for soft delete query.\n// It supports multiple tables string like:\n// \"user u, user_detail ud\"\n// \"user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)\"\n// \"user LEFT JOIN user_detail ON(user_detail.uid=user.uid)\"\n// \"user u LEFT JOIN user_detail ud ON(ud.uid=u.uid) LEFT JOIN user_stats us ON(us.uid=u.uid)\".\nfunc (m *softTimeMaintainer) GetDeleteCondition(ctx context.Context) string {\n\tif m.unscoped {\n\t\treturn \"\"\n\t}\n\tconditionArray := garray.NewStrArray()\n\tif gstr.Contains(m.tables, \" JOIN \") {\n\t\t// Base table.\n\t\ttableMatch, _ := gregex.MatchString(`(.+?) [A-Z]+ JOIN`, m.tables)\n\t\tconditionArray.Append(m.getConditionOfTableStringForSoftDeleting(ctx, tableMatch[1]))\n\t\t// Multiple joined tables, exclude the sub query sql which contains char '(' and ')'.\n\t\ttableMatches, _ := gregex.MatchAllString(`JOIN ([^()]+?) ON`, m.tables)\n\t\tfor _, match := range tableMatches {\n\t\t\tconditionArray.Append(m.getConditionOfTableStringForSoftDeleting(ctx, match[1]))\n\t\t}\n\t}\n\tif conditionArray.Len() == 0 && gstr.Contains(m.tables, \",\") {\n\t\t// Multiple base tables.\n\t\tfor _, s := range gstr.SplitAndTrim(m.tables, \",\") {\n\t\t\tconditionArray.Append(m.getConditionOfTableStringForSoftDeleting(ctx, s))\n\t\t}\n\t}\n\tconditionArray.FilterEmpty()\n\tif conditionArray.Len() > 0 {\n\t\treturn conditionArray.Join(\" AND \")\n\t}\n\t// Only one table.\n\tfieldName, fieldType := m.GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldDelete)\n\tif fieldName != \"\" {\n\t\treturn m.buildDeleteCondition(ctx, \"\", fieldName, fieldType)\n\t}\n\treturn \"\"\n}\n\n// getConditionOfTableStringForSoftDeleting does something as its name describes.\n// Examples for `s`:\n// - `test`.`demo` as b\n// - `test`.`demo` b\n// - `demo`\n// - demo\nfunc (m *softTimeMaintainer) getConditionOfTableStringForSoftDeleting(ctx context.Context, s string) string {\n\tvar (\n\t\ttable  string\n\t\tschema string\n\t\tarray1 = gstr.SplitAndTrim(s, \" \")\n\t\tarray2 = gstr.SplitAndTrim(array1[0], \".\")\n\t)\n\tif len(array2) >= 2 {\n\t\ttable = array2[1]\n\t\tschema = array2[0]\n\t} else {\n\t\ttable = array2[0]\n\t}\n\tfieldName, fieldType := m.GetFieldInfo(ctx, schema, table, SoftTimeFieldDelete)\n\tif fieldName == \"\" {\n\t\treturn \"\"\n\t}\n\tif len(array1) >= 3 {\n\t\treturn m.buildDeleteCondition(ctx, array1[2], fieldName, fieldType)\n\t}\n\tif len(array1) >= 2 {\n\t\treturn m.buildDeleteCondition(ctx, array1[1], fieldName, fieldType)\n\t}\n\treturn m.buildDeleteCondition(ctx, table, fieldName, fieldType)\n}\n\n// GetDeleteData returns UPDATE statement data for soft delete.\nfunc (m *softTimeMaintainer) GetDeleteData(\n\tctx context.Context, prefix, fieldName string, fieldType LocalType,\n) (holder string, value any) {\n\tcore := m.db.GetCore()\n\tquotedName := core.QuoteWord(fieldName)\n\n\tif prefix != \"\" {\n\t\tquotedName = fmt.Sprintf(`%s.%s`, core.QuoteWord(prefix), quotedName)\n\t}\n\n\tholder = fmt.Sprintf(`%s=?`, quotedName)\n\tvalue = m.GetFieldValue(ctx, fieldType, false)\n\treturn\n}\n\n// buildDeleteCondition builds WHERE condition for soft delete filtering.\nfunc (m *softTimeMaintainer) buildDeleteCondition(\n\tctx context.Context, prefix, fieldName string, fieldType LocalType,\n) string {\n\tcore := m.db.GetCore()\n\tquotedName := core.QuoteWord(fieldName)\n\n\tif prefix != \"\" {\n\t\tquotedName = fmt.Sprintf(`%s.%s`, core.QuoteWord(prefix), quotedName)\n\t}\n\tswitch m.softTimeOption.SoftTimeType {\n\tcase SoftTimeTypeAuto:\n\t\tswitch fieldType {\n\t\tcase LocalTypeDate, LocalTypeTime, LocalTypeDatetime:\n\t\t\treturn fmt.Sprintf(`%s IS NULL`, quotedName)\n\t\tcase LocalTypeInt, LocalTypeUint, LocalTypeInt64, LocalTypeUint64, LocalTypeBool:\n\t\t\treturn fmt.Sprintf(`%s=0`, quotedName)\n\t\tdefault:\n\t\t\tintlog.Errorf(ctx, `invalid field type \"%s\" for soft delete condition: prefix=%s, field=%s`, fieldType, prefix, fieldName)\n\t\t\treturn \"\"\n\t\t}\n\n\tcase SoftTimeTypeTime:\n\t\treturn fmt.Sprintf(`%s IS NULL`, quotedName)\n\n\tdefault:\n\t\treturn fmt.Sprintf(`%s=0`, quotedName)\n\t}\n}\n\n// GetFieldValue generates value for create/update/delete operations.\nfunc (m *softTimeMaintainer) GetFieldValue(\n\tctx context.Context, fieldType LocalType, isDeleted bool,\n) any {\n\t// For deleted field, return \"empty\" value\n\tif isDeleted {\n\t\treturn m.getEmptyValue(fieldType)\n\t}\n\n\t// For create/update/delete, return current time value\n\tswitch m.softTimeOption.SoftTimeType {\n\tcase SoftTimeTypeAuto:\n\t\treturn m.getAutoValue(ctx, fieldType)\n\tdefault:\n\t\tswitch fieldType {\n\t\tcase LocalTypeBool:\n\t\t\treturn 1\n\t\tdefault:\n\t\t\treturn m.getTimestampValue()\n\t\t}\n\t}\n}\n\n// getTimestampValue returns timestamp value for soft time.\nfunc (m *softTimeMaintainer) getTimestampValue() any {\n\tswitch m.softTimeOption.SoftTimeType {\n\tcase SoftTimeTypeTime:\n\t\treturn gtime.Now()\n\tcase SoftTimeTypeTimestamp:\n\t\treturn gtime.Timestamp()\n\tcase SoftTimeTypeTimestampMilli:\n\t\treturn gtime.TimestampMilli()\n\tcase SoftTimeTypeTimestampMicro:\n\t\treturn gtime.TimestampMicro()\n\tcase SoftTimeTypeTimestampNano:\n\t\treturn gtime.TimestampNano()\n\tdefault:\n\t\tpanic(gerror.NewCodef(\n\t\t\tgcode.CodeInternalPanic,\n\t\t\t`unrecognized SoftTimeType \"%d\"`, m.softTimeOption.SoftTimeType,\n\t\t))\n\t}\n}\n\n// getEmptyValue returns \"empty\" value for deleted field.\nfunc (m *softTimeMaintainer) getEmptyValue(fieldType LocalType) any {\n\tswitch fieldType {\n\tcase LocalTypeDate, LocalTypeTime, LocalTypeDatetime:\n\t\treturn nil\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// getAutoValue returns auto-detected value based on field type.\nfunc (m *softTimeMaintainer) getAutoValue(ctx context.Context, fieldType LocalType) any {\n\tswitch fieldType {\n\tcase LocalTypeDate, LocalTypeTime, LocalTypeDatetime:\n\t\treturn gtime.Now()\n\tcase LocalTypeInt, LocalTypeUint, LocalTypeInt64, LocalTypeUint64:\n\t\treturn gtime.Timestamp()\n\tcase LocalTypeBool:\n\t\treturn 1\n\tdefault:\n\t\tintlog.Errorf(ctx, `invalid field type \"%s\" for soft time auto value`, fieldType)\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_transaction.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n)\n\n// Transaction wraps the transaction logic using function `f`.\n// It rollbacks the transaction and returns the error from function `f` if\n// it returns non-nil error. It commits the transaction and returns nil if\n// function `f` returns nil.\n//\n// Note that, you should not Commit or Rollback the transaction in function `f`\n// as it is automatically handled by this function.\nfunc (m *Model) Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) {\n\tif ctx == nil {\n\t\tctx = m.GetCtx()\n\t}\n\tif m.tx != nil {\n\t\treturn m.tx.Transaction(ctx, f)\n\t}\n\treturn m.db.Transaction(ctx, f)\n}\n\n// TransactionWithOptions executes transaction with options.\n// The parameter `opts` specifies the transaction options.\n// The parameter `f` specifies the function that will be called within the transaction.\n// If f returns error, the transaction will be rolled back, or else the transaction will be committed.\nfunc (m *Model) TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) (err error) {\n\tif ctx == nil {\n\t\tctx = m.GetCtx()\n\t}\n\tif m.tx != nil {\n\t\treturn m.tx.Transaction(ctx, f)\n\t}\n\treturn m.db.TransactionWithOptions(ctx, opts, f)\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_update.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Update does \"UPDATE ... \" statement for the model.\n//\n// If the optional parameter `dataAndWhere` is given, the dataAndWhere[0] is the updated data field,\n// and dataAndWhere[1:] is treated as where condition fields.\n// Also see Model.Data and Model.Where functions.\nfunc (m *Model) Update(dataAndWhere ...any) (result sql.Result, err error) {\n\tvar ctx = m.GetCtx()\n\tif len(dataAndWhere) > 0 {\n\t\tif len(dataAndWhere) > 2 {\n\t\t\treturn m.Data(dataAndWhere[0]).Where(dataAndWhere[1], dataAndWhere[2:]...).Update()\n\t\t} else if len(dataAndWhere) == 2 {\n\t\t\treturn m.Data(dataAndWhere[0]).Where(dataAndWhere[1]).Update()\n\t\t} else {\n\t\t\treturn m.Data(dataAndWhere[0]).Update()\n\t\t}\n\t}\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tm.checkAndRemoveSelectCache(ctx)\n\t\t}\n\t}()\n\tif m.data == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeMissingParameter, \"updating table with empty data\")\n\t}\n\tvar (\n\t\tnewData                                       any\n\t\tstm                                           = m.softTimeMaintainer()\n\t\treflectInfo                                   = reflection.OriginTypeAndKind(m.data)\n\t\tconditionWhere, conditionExtra, conditionArgs = m.formatCondition(ctx, false, false)\n\t\tconditionStr                                  = conditionWhere + conditionExtra\n\t\tfieldNameUpdate, fieldTypeUpdate              = stm.GetFieldInfo(ctx, \"\", m.tablesInit, SoftTimeFieldUpdate)\n\t)\n\tif fieldNameUpdate != \"\" && (m.unscoped || m.isFieldInFieldsEx(fieldNameUpdate)) {\n\t\tfieldNameUpdate = \"\"\n\t}\n\n\tnewData, err = m.filterDataForInsertOrUpdate(m.data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch reflectInfo.OriginKind {\n\tcase reflect.Map, reflect.Struct:\n\t\tvar dataMap = anyValueToMapBeforeToRecord(newData)\n\t\t// Automatically update the record updating time.\n\t\tif fieldNameUpdate != \"\" && empty.IsNil(dataMap[fieldNameUpdate]) {\n\t\t\tdataValue := stm.GetFieldValue(ctx, fieldTypeUpdate, false)\n\t\t\tdataMap[fieldNameUpdate] = dataValue\n\t\t}\n\t\tnewData = dataMap\n\n\tdefault:\n\t\tvar updateStr = gconv.String(newData)\n\t\t// Automatically update the record updating time.\n\t\tif fieldNameUpdate != \"\" && !gstr.Contains(updateStr, fieldNameUpdate) {\n\t\t\tdataValue := stm.GetFieldValue(ctx, fieldTypeUpdate, false)\n\t\t\tupdateStr += fmt.Sprintf(`,%s=?`, fieldNameUpdate)\n\t\t\tconditionArgs = append([]any{dataValue}, conditionArgs...)\n\t\t}\n\t\tnewData = updateStr\n\t}\n\n\tif !gstr.ContainsI(conditionStr, \" WHERE \") {\n\t\tintlog.Printf(\n\t\t\tctx,\n\t\t\t`sql condition string \"%s\" has no WHERE for UPDATE operation, fieldNameUpdate: %s`,\n\t\t\tconditionStr, fieldNameUpdate,\n\t\t)\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t\"there should be WHERE condition statement for UPDATE operation\",\n\t\t)\n\t}\n\n\tin := &HookUpdateInput{\n\t\tinternalParamHookUpdate: internalParamHookUpdate{\n\t\t\tinternalParamHook: internalParamHook{\n\t\t\t\tlink: m.getLink(true),\n\t\t\t},\n\t\t\thandler: m.hookHandler.Update,\n\t\t},\n\t\tModel:     m,\n\t\tTable:     m.tables,\n\t\tSchema:    m.schema,\n\t\tData:      newData,\n\t\tCondition: conditionStr,\n\t\tArgs:      m.mergeArguments(conditionArgs),\n\t}\n\treturn in.Next(ctx)\n}\n\n// UpdateAndGetAffected performs update statement and returns the affected rows number.\nfunc (m *Model) UpdateAndGetAffected(dataAndWhere ...any) (affected int64, err error) {\n\tresult, err := m.Update(dataAndWhere...)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn result.RowsAffected()\n}\n\n// Increment increments a column's value by a given amount.\n// The parameter `amount` can be type of float or integer.\nfunc (m *Model) Increment(column string, amount any) (sql.Result, error) {\n\treturn m.getModel().Data(column, &Counter{\n\t\tField: column,\n\t\tValue: gconv.Float64(amount),\n\t}).Update()\n}\n\n// Decrement decrements a column's value by a given amount.\n// The parameter `amount` can be type of float or integer.\nfunc (m *Model) Decrement(column string, amount any) (sql.Result, error) {\n\treturn m.getModel().Data(column, &Counter{\n\t\tField: column,\n\t\tValue: -gconv.Float64(amount),\n\t}).Update()\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_utility.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// QuoteWord checks given string `s` a word,\n// if true it quotes `s` with security chars of the database\n// and returns the quoted string; or else it returns `s` without any change.\n//\n// The meaning of a `word` can be considered as a column name.\nfunc (m *Model) QuoteWord(s string) string {\n\treturn m.db.GetCore().QuoteWord(s)\n}\n\n// TableFields retrieves and returns the fields' information of specified table of current\n// schema.\n//\n// Also see DriverMysql.TableFields.\nfunc (m *Model) TableFields(tableStr string, schema ...string) (fields map[string]*TableField, err error) {\n\tvar (\n\t\tctx        = m.GetCtx()\n\t\tusedTable  = m.db.GetCore().guessPrimaryTableName(tableStr)\n\t\tusedSchema = gutil.GetOrDefaultStr(m.schema, schema...)\n\t)\n\t// Sharding feature.\n\tusedSchema, err = m.getActualSchema(ctx, usedSchema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tusedTable, err = m.getActualTable(ctx, usedTable)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn m.db.TableFields(ctx, usedTable, usedSchema)\n}\n\n// getModel creates and returns a cloned model of current model if `safe` is true, or else it returns\n// the current model.\nfunc (m *Model) getModel() *Model {\n\tif !m.safe {\n\t\treturn m\n\t} else {\n\t\treturn m.Clone()\n\t}\n}\n\n// mappingAndFilterToTableFields mappings and changes given field name to really table field name.\n// Eg:\n// ID        -> id\n// NICK_Name -> nickname.\nfunc (m *Model) mappingAndFilterToTableFields(table string, fields []any, filter bool) []any {\n\tvar fieldsTable = table\n\tif fieldsTable != \"\" {\n\t\thasTable, _ := m.db.GetCore().HasTable(fieldsTable)\n\t\tif !hasTable {\n\t\t\tif fieldsTable != m.tablesInit {\n\t\t\t\t// Table/alias unknown (e.g., FieldsPrefix called before LeftJoin), skip filtering.\n\t\t\t\treturn fields\n\t\t\t}\n\t\t\t// HasTable cache miss for main table, fallback to use main table for field mapping.\n\t\t\tfieldsTable = m.tablesInit\n\t\t}\n\t}\n\tif fieldsTable == \"\" {\n\t\tfieldsTable = m.tablesInit\n\t}\n\n\tfieldsMap, _ := m.TableFields(fieldsTable)\n\tif len(fieldsMap) == 0 {\n\t\treturn fields\n\t}\n\tvar outputFieldsArray = make([]any, 0)\n\tfieldsKeyMap := make(map[string]any, len(fieldsMap))\n\tfor k := range fieldsMap {\n\t\tfieldsKeyMap[k] = nil\n\t}\n\tfor _, field := range fields {\n\t\tvar (\n\t\t\tfieldStr         = gconv.String(field)\n\t\t\tinputFieldsArray []string\n\t\t)\n\t\t// Skip empty string fields.\n\t\tif fieldStr == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tswitch {\n\t\tcase gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, fieldStr):\n\t\t\tinputFieldsArray = append(inputFieldsArray, fieldStr)\n\n\t\tcase gregex.IsMatchString(regularFieldNameWithCommaRegPattern, fieldStr):\n\t\t\tinputFieldsArray = gstr.SplitAndTrim(fieldStr, \",\")\n\n\t\tdefault:\n\t\t\t// Example:\n\t\t\t// user.id, user.name\n\t\t\t// replace(concat_ws(',',lpad(s.id, 6, '0'),s.name),',','') `code`\n\t\t\toutputFieldsArray = append(outputFieldsArray, field)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, inputField := range inputFieldsArray {\n\t\t\tif !gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, inputField) {\n\t\t\t\toutputFieldsArray = append(outputFieldsArray, inputField)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif _, ok := fieldsKeyMap[inputField]; !ok {\n\t\t\t\t// Example:\n\t\t\t\t// id, name\n\t\t\t\tif foundKey, _ := gutil.MapPossibleItemByKey(fieldsKeyMap, inputField); foundKey != \"\" {\n\t\t\t\t\toutputFieldsArray = append(outputFieldsArray, foundKey)\n\t\t\t\t} else if !filter {\n\t\t\t\t\toutputFieldsArray = append(outputFieldsArray, inputField)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\toutputFieldsArray = append(outputFieldsArray, inputField)\n\t\t\t}\n\t\t}\n\t}\n\treturn outputFieldsArray\n}\n\n// filterDataForInsertOrUpdate does filter feature with data for inserting/updating operations.\n// Note that, it does not filter list item, which is also type of map, for \"omit empty\" feature.\nfunc (m *Model) filterDataForInsertOrUpdate(data any) (any, error) {\n\tvar err error\n\tswitch value := data.(type) {\n\tcase List:\n\t\tvar omitEmpty bool\n\t\tif m.option&optionOmitNilDataList > 0 {\n\t\t\tomitEmpty = true\n\t\t}\n\t\tfor k, item := range value {\n\t\t\tvalue[k], err = m.doMappingAndFilterForInsertOrUpdateDataMap(item, omitEmpty)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\treturn value, nil\n\n\tcase Map:\n\t\treturn m.doMappingAndFilterForInsertOrUpdateDataMap(value, true)\n\n\tdefault:\n\t\treturn data, nil\n\t}\n}\n\n// doMappingAndFilterForInsertOrUpdateDataMap does the filter features for map.\n// Note that, it does not filter list item, which is also type of map, for \"omit empty\" feature.\nfunc (m *Model) doMappingAndFilterForInsertOrUpdateDataMap(data Map, allowOmitEmpty bool) (Map, error) {\n\tvar (\n\t\terr    error\n\t\tctx    = m.GetCtx()\n\t\tcore   = m.db.GetCore()\n\t\tschema = m.schema\n\t\ttable  = m.tablesInit\n\t)\n\t// Sharding feature.\n\tschema, err = m.getActualSchema(ctx, schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttable, err = m.getActualTable(ctx, table)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdata, err = core.mappingAndFilterData(\n\t\tctx, schema, table, data, m.filter,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Remove key-value pairs of which the value is nil.\n\tif allowOmitEmpty && m.option&optionOmitNilData > 0 {\n\t\ttempMap := make(Map, len(data))\n\t\tfor k, v := range data {\n\t\t\tif empty.IsNil(v) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttempMap[k] = v\n\t\t}\n\t\tdata = tempMap\n\t}\n\n\t// Remove key-value pairs of which the value is empty.\n\tif allowOmitEmpty && m.option&optionOmitEmptyData > 0 {\n\t\ttempMap := make(Map, len(data))\n\t\tfor k, v := range data {\n\t\t\tif empty.IsEmpty(v) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Special type filtering.\n\t\t\tswitch r := v.(type) {\n\t\t\tcase time.Time:\n\t\t\t\tif r.IsZero() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase *time.Time:\n\t\t\t\tif r.IsZero() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase gtime.Time:\n\t\t\t\tif r.IsZero() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase *gtime.Time:\n\t\t\t\tif r.IsZero() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\ttempMap[k] = v\n\t\t}\n\t\tdata = tempMap\n\t}\n\n\tif len(m.fields) > 0 {\n\t\t// Keep specified fields.\n\t\tvar (\n\t\t\tfieldSet     = gset.NewStrSetFrom(gconv.Strings(m.fields))\n\t\t\tcharL, charR = m.db.GetChars()\n\t\t\tchars        = charL + charR\n\t\t)\n\t\tfieldSet.Walk(func(item string) string {\n\t\t\treturn gstr.Trim(item, chars)\n\t\t})\n\t\tfor k := range data {\n\t\t\tk = gstr.Trim(k, chars)\n\t\t\tif !fieldSet.Contains(k) {\n\t\t\t\tdelete(data, k)\n\t\t\t}\n\t\t}\n\t} else if len(m.fieldsEx) > 0 {\n\t\t// Filter specified fields.\n\t\tfor _, v := range m.fieldsEx {\n\t\t\tdelete(data, gconv.String(v))\n\t\t}\n\t}\n\treturn data, nil\n}\n\n// getLink returns the underlying database link object with configured `linkType` attribute.\n// The parameter `master` specifies whether using the master node if master-slave configured.\nfunc (m *Model) getLink(master bool) Link {\n\tif m.tx != nil {\n\t\tif sqlTx := m.tx.GetSqlTX(); sqlTx != nil {\n\t\t\treturn &txLink{sqlTx}\n\t\t}\n\t}\n\tlinkType := m.linkType\n\tif linkType == 0 {\n\t\tif master {\n\t\t\tlinkType = linkTypeMaster\n\t\t} else {\n\t\t\tlinkType = linkTypeSlave\n\t\t}\n\t}\n\tswitch linkType {\n\tcase linkTypeMaster:\n\t\tlink, err := m.db.GetCore().MasterLink(m.schema)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn link\n\tcase linkTypeSlave:\n\t\tlink, err := m.db.GetCore().SlaveLink(m.schema)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn link\n\t}\n\treturn nil\n}\n\n// getPrimaryKey retrieves and returns the primary key name of the model table.\n// It parses m.tables to retrieve the primary table name, supporting m.tables like:\n// \"user\", \"user u\", \"user as u, user_detail as ud\".\nfunc (m *Model) getPrimaryKey() string {\n\ttable := gstr.SplitAndTrim(m.tablesInit, \" \")[0]\n\ttableFields, err := m.TableFields(table)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tfor name, field := range tableFields {\n\t\tif gstr.ContainsI(field.Key, \"pri\") {\n\t\t\treturn name\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// mergeArguments creates and returns new arguments by merging `m.extraArgs` and given `args`.\nfunc (m *Model) mergeArguments(args []any) []any {\n\tif len(m.extraArgs) > 0 {\n\t\tnewArgs := make([]any, len(m.extraArgs)+len(args))\n\t\tcopy(newArgs, m.extraArgs)\n\t\tcopy(newArgs[len(m.extraArgs):], args)\n\t\treturn newArgs\n\t}\n\treturn args\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_where.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://githum.com/gogf/gf.\n\npackage gdb\n\n// callWhereBuilder creates and returns a new Model, and sets its WhereBuilder if current Model is safe.\n// It sets the WhereBuilder and returns current Model directly if it is not safe.\nfunc (m *Model) callWhereBuilder(builder *WhereBuilder) *Model {\n\tmodel := m.getModel()\n\tmodel.whereBuilder = builder\n\treturn model\n}\n\n// Where sets the condition statement for the builder. The parameter `where` can be type of\n// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,\n// multiple conditions will be joined into where statement using \"AND\".\n// See WhereBuilder.Where.\nfunc (m *Model) Where(where any, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.Where(where, args...))\n}\n\n// Wheref builds condition string using fmt.Sprintf and arguments.\n// Note that if the number of `args` is more than the placeholder in `format`,\n// the extra `args` will be used as the where condition arguments of the Model.\n// See WhereBuilder.Wheref.\nfunc (m *Model) Wheref(format string, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.Wheref(format, args...))\n}\n\n// WherePri does the same logic as Model.Where except that if the parameter `where`\n// is a single condition like int/string/float/slice, it treats the condition as the primary\n// key value. That is, if primary key is \"id\" and given `where` parameter as \"123\", the\n// WherePri function treats the condition as \"id=123\", but Model.Where treats the condition\n// as string \"123\".\n// See WhereBuilder.WherePri.\nfunc (m *Model) WherePri(where any, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePri(where, args...))\n}\n\n// WhereLT builds `column < value` statement.\n// See WhereBuilder.WhereLT.\nfunc (m *Model) WhereLT(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereLT(column, value))\n}\n\n// WhereLTE builds `column <= value` statement.\n// See WhereBuilder.WhereLTE.\nfunc (m *Model) WhereLTE(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereLTE(column, value))\n}\n\n// WhereGT builds `column > value` statement.\n// See WhereBuilder.WhereGT.\nfunc (m *Model) WhereGT(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereGT(column, value))\n}\n\n// WhereGTE builds `column >= value` statement.\n// See WhereBuilder.WhereGTE.\nfunc (m *Model) WhereGTE(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereGTE(column, value))\n}\n\n// WhereBetween builds `column BETWEEN min AND max` statement.\n// See WhereBuilder.WhereBetween.\nfunc (m *Model) WhereBetween(column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereBetween(column, min, max))\n}\n\n// WhereLike builds `column LIKE like` statement.\n// See WhereBuilder.WhereLike.\nfunc (m *Model) WhereLike(column string, like string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereLike(column, like))\n}\n\n// WhereIn builds `column IN (in)` statement.\n// See WhereBuilder.WhereIn.\nfunc (m *Model) WhereIn(column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereIn(column, in))\n}\n\n// WhereNull builds `columns[0] IS NULL AND columns[1] IS NULL ...` statement.\n// See WhereBuilder.WhereNull.\nfunc (m *Model) WhereNull(columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNull(columns...))\n}\n\n// WhereNotBetween builds `column NOT BETWEEN min AND max` statement.\n// See WhereBuilder.WhereNotBetween.\nfunc (m *Model) WhereNotBetween(column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNotBetween(column, min, max))\n}\n\n// WhereNotLike builds `column NOT LIKE like` statement.\n// See WhereBuilder.WhereNotLike.\nfunc (m *Model) WhereNotLike(column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNotLike(column, like))\n}\n\n// WhereNot builds `column != value` statement.\n// See WhereBuilder.WhereNot.\nfunc (m *Model) WhereNot(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNot(column, value))\n}\n\n// WhereNotIn builds `column NOT IN (in)` statement.\n// See WhereBuilder.WhereNotIn.\nfunc (m *Model) WhereNotIn(column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNotIn(column, in))\n}\n\n// WhereNotNull builds `columns[0] IS NOT NULL AND columns[1] IS NOT NULL ...` statement.\n// See WhereBuilder.WhereNotNull.\nfunc (m *Model) WhereNotNull(columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNotNull(columns...))\n}\n\n// WhereExists builds `EXISTS (subQuery)` statement.\nfunc (m *Model) WhereExists(subQuery *Model) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereExists(subQuery))\n}\n\n// WhereNotExists builds `NOT EXISTS (subQuery)` statement.\nfunc (m *Model) WhereNotExists(subQuery *Model) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereNotExists(subQuery))\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_where_prefix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// WherePrefix performs as Where, but it adds prefix to each field in where statement.\n// See WhereBuilder.WherePrefix.\nfunc (m *Model) WherePrefix(prefix string, where any, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefix(prefix, where, args...))\n}\n\n// WherePrefixLT builds `prefix.column < value` statement.\n// See WhereBuilder.WherePrefixLT.\nfunc (m *Model) WherePrefixLT(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixLT(prefix, column, value))\n}\n\n// WherePrefixLTE builds `prefix.column <= value` statement.\n// See WhereBuilder.WherePrefixLTE.\nfunc (m *Model) WherePrefixLTE(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixLTE(prefix, column, value))\n}\n\n// WherePrefixGT builds `prefix.column > value` statement.\n// See WhereBuilder.WherePrefixGT.\nfunc (m *Model) WherePrefixGT(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixGT(prefix, column, value))\n}\n\n// WherePrefixGTE builds `prefix.column >= value` statement.\n// See WhereBuilder.WherePrefixGTE.\nfunc (m *Model) WherePrefixGTE(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixGTE(prefix, column, value))\n}\n\n// WherePrefixBetween builds `prefix.column BETWEEN min AND max` statement.\n// See WhereBuilder.WherePrefixBetween.\nfunc (m *Model) WherePrefixBetween(prefix string, column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixBetween(prefix, column, min, max))\n}\n\n// WherePrefixLike builds `prefix.column LIKE like` statement.\n// See WhereBuilder.WherePrefixLike.\nfunc (m *Model) WherePrefixLike(prefix string, column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixLike(prefix, column, like))\n}\n\n// WherePrefixIn builds `prefix.column IN (in)` statement.\n// See WhereBuilder.WherePrefixIn.\nfunc (m *Model) WherePrefixIn(prefix string, column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixIn(prefix, column, in))\n}\n\n// WherePrefixNull builds `prefix.columns[0] IS NULL AND prefix.columns[1] IS NULL ...` statement.\n// See WhereBuilder.WherePrefixNull.\nfunc (m *Model) WherePrefixNull(prefix string, columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNull(prefix, columns...))\n}\n\n// WherePrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement.\n// See WhereBuilder.WherePrefixNotBetween.\nfunc (m *Model) WherePrefixNotBetween(prefix string, column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNotBetween(prefix, column, min, max))\n}\n\n// WherePrefixNotLike builds `prefix.column NOT LIKE like` statement.\n// See WhereBuilder.WherePrefixNotLike.\nfunc (m *Model) WherePrefixNotLike(prefix string, column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNotLike(prefix, column, like))\n}\n\n// WherePrefixNot builds `prefix.column != value` statement.\n// See WhereBuilder.WherePrefixNot.\nfunc (m *Model) WherePrefixNot(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNot(prefix, column, value))\n}\n\n// WherePrefixNotIn builds `prefix.column NOT IN (in)` statement.\n// See WhereBuilder.WherePrefixNotIn.\nfunc (m *Model) WherePrefixNotIn(prefix string, column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNotIn(prefix, column, in))\n}\n\n// WherePrefixNotNull builds `prefix.columns[0] IS NOT NULL AND prefix.columns[1] IS NOT NULL ...` statement.\n// See WhereBuilder.WherePrefixNotNull.\nfunc (m *Model) WherePrefixNotNull(prefix string, columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WherePrefixNotNull(prefix, columns...))\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_whereor.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// WhereOr adds \"OR\" condition to the where statement.\n// See WhereBuilder.WhereOr.\nfunc (m *Model) WhereOr(where any, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOr(where, args...))\n}\n\n// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.\n// See WhereBuilder.WhereOrf.\nfunc (m *Model) WhereOrf(format string, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrf(format, args...))\n}\n\n// WhereOrLT builds `column < value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrLT.\nfunc (m *Model) WhereOrLT(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrLT(column, value))\n}\n\n// WhereOrLTE builds `column <= value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrLTE.\nfunc (m *Model) WhereOrLTE(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrLTE(column, value))\n}\n\n// WhereOrGT builds `column > value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrGT.\nfunc (m *Model) WhereOrGT(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrGT(column, value))\n}\n\n// WhereOrGTE builds `column >= value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrGTE.\nfunc (m *Model) WhereOrGTE(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrGTE(column, value))\n}\n\n// WhereOrBetween builds `column BETWEEN min AND max` statement in `OR` conditions.\n// See WhereBuilder.WhereOrBetween.\nfunc (m *Model) WhereOrBetween(column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrBetween(column, min, max))\n}\n\n// WhereOrLike builds `column LIKE like` statement in `OR` conditions.\n// See WhereBuilder.WhereOrLike.\nfunc (m *Model) WhereOrLike(column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrLike(column, like))\n}\n\n// WhereOrIn builds `column IN (in)` statement in `OR` conditions.\n// See WhereBuilder.WhereOrIn.\nfunc (m *Model) WhereOrIn(column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrIn(column, in))\n}\n\n// WhereOrNull builds `columns[0] IS NULL OR columns[1] IS NULL ...` statement in `OR` conditions.\n// See WhereBuilder.WhereOrNull.\nfunc (m *Model) WhereOrNull(columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNull(columns...))\n}\n\n// WhereOrNotBetween builds `column NOT BETWEEN min AND max` statement in `OR` conditions.\n// See WhereBuilder.WhereOrNotBetween.\nfunc (m *Model) WhereOrNotBetween(column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNotBetween(column, min, max))\n}\n\n// WhereOrNotLike builds `column NOT LIKE 'like'` statement in `OR` conditions.\n// See WhereBuilder.WhereOrNotLike.\nfunc (m *Model) WhereOrNotLike(column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNotLike(column, like))\n}\n\n// WhereOrNot builds `column != value` statement.\n// See WhereBuilder.WhereOrNot.\nfunc (m *Model) WhereOrNot(column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNot(column, value))\n}\n\n// WhereOrNotIn builds `column NOT IN (in)` statement.\n// See WhereBuilder.WhereOrNotIn.\nfunc (m *Model) WhereOrNotIn(column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNotIn(column, in))\n}\n\n// WhereOrNotNull builds `columns[0] IS NOT NULL OR columns[1] IS NOT NULL ...` statement in `OR` conditions.\n// See WhereBuilder.WhereOrNotNull.\nfunc (m *Model) WhereOrNotNull(columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrNotNull(columns...))\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_whereor_prefix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// WhereOrPrefix performs as WhereOr, but it adds prefix to each field in where statement.\n// See WhereBuilder.WhereOrPrefix.\nfunc (m *Model) WhereOrPrefix(prefix string, where any, args ...any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefix(prefix, where, args...))\n}\n\n// WhereOrPrefixLT builds `prefix.column < value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixLT.\nfunc (m *Model) WhereOrPrefixLT(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixLT(prefix, column, value))\n}\n\n// WhereOrPrefixLTE builds `prefix.column <= value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixLTE.\nfunc (m *Model) WhereOrPrefixLTE(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixLTE(prefix, column, value))\n}\n\n// WhereOrPrefixGT builds `prefix.column > value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixGT.\nfunc (m *Model) WhereOrPrefixGT(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixGT(prefix, column, value))\n}\n\n// WhereOrPrefixGTE builds `prefix.column >= value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixGTE.\nfunc (m *Model) WhereOrPrefixGTE(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixGTE(prefix, column, value))\n}\n\n// WhereOrPrefixBetween builds `prefix.column BETWEEN min AND max` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixBetween.\nfunc (m *Model) WhereOrPrefixBetween(prefix string, column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixBetween(prefix, column, min, max))\n}\n\n// WhereOrPrefixLike builds `prefix.column LIKE like` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixLike.\nfunc (m *Model) WhereOrPrefixLike(prefix string, column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixLike(prefix, column, like))\n}\n\n// WhereOrPrefixIn builds `prefix.column IN (in)` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixIn.\nfunc (m *Model) WhereOrPrefixIn(prefix string, column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixIn(prefix, column, in))\n}\n\n// WhereOrPrefixNull builds `prefix.columns[0] IS NULL OR prefix.columns[1] IS NULL ...` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixNull.\nfunc (m *Model) WhereOrPrefixNull(prefix string, columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNull(prefix, columns...))\n}\n\n// WhereOrPrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixNotBetween.\nfunc (m *Model) WhereOrPrefixNotBetween(prefix string, column string, min, max any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNotBetween(prefix, column, min, max))\n}\n\n// WhereOrPrefixNotLike builds `prefix.column NOT LIKE like` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixNotLike.\nfunc (m *Model) WhereOrPrefixNotLike(prefix string, column string, like any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNotLike(prefix, column, like))\n}\n\n// WhereOrPrefixNotIn builds `prefix.column NOT IN (in)` statement.\n// See WhereBuilder.WhereOrPrefixNotIn.\nfunc (m *Model) WhereOrPrefixNotIn(prefix string, column string, in any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNotIn(prefix, column, in))\n}\n\n// WhereOrPrefixNotNull builds `prefix.columns[0] IS NOT NULL OR prefix.columns[1] IS NOT NULL ...` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixNotNull.\nfunc (m *Model) WhereOrPrefixNotNull(prefix string, columns ...string) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNotNull(prefix, columns...))\n}\n\n// WhereOrPrefixNot builds `prefix.column != value` statement in `OR` conditions.\n// See WhereBuilder.WhereOrPrefixNot.\nfunc (m *Model) WhereOrPrefixNot(prefix string, column string, value any) *Model {\n\treturn m.callWhereBuilder(m.whereBuilder.WhereOrPrefixNot(prefix, column, value))\n}\n"
  },
  {
    "path": "database/gdb/gdb_model_with.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// With creates and returns an ORM model based on metadata of given object.\n// It also enables model association operations feature on given `object`.\n// It can be called multiple times to add one or more objects to model and enable\n// their mode association operations feature.\n// For example, if given struct definition:\n//\n//\ttype User struct {\n//\t\t gmeta.Meta `orm:\"table:user\"`\n//\t\t Id         int           `json:\"id\"`\n//\t\t Name       string        `json:\"name\"`\n//\t\t UserDetail *UserDetail   `orm:\"with:uid=id\"`\n//\t\t UserScores []*UserScores `orm:\"with:uid=id\"`\n//\t}\n//\n// We can enable model association operations on attribute `UserDetail` and `UserScores` by:\n//\n//\tdb.With(User{}.UserDetail).With(User{}.UserScores).Scan(xxx)\n//\n// Or:\n//\n//\tdb.With(UserDetail{}).With(UserScores{}).Scan(xxx)\n//\n// Or:\n//\n//\tdb.With(UserDetail{}, UserScores{}).Scan(xxx)\nfunc (m *Model) With(objects ...any) *Model {\n\tmodel := m.getModel()\n\tfor _, object := range objects {\n\t\tif m.tables == \"\" {\n\t\t\tm.tablesInit = m.db.GetCore().QuotePrefixTableName(\n\t\t\t\tgetTableNameFromOrmTag(object),\n\t\t\t)\n\t\t\tm.tables = m.tablesInit\n\t\t\treturn model\n\t\t}\n\t\tmodel.withArray = append(model.withArray, object)\n\t}\n\treturn model\n}\n\n// WithAll enables model association operations on all objects that have \"with\" tag in the struct.\nfunc (m *Model) WithAll() *Model {\n\tmodel := m.getModel()\n\tmodel.withAll = true\n\treturn model\n}\n\n// doWithScanStruct handles model association operations feature for single struct.\nfunc (m *Model) doWithScanStruct(pointer any) error {\n\tif len(m.withArray) == 0 && !m.withAll {\n\t\treturn nil\n\t}\n\tvar (\n\t\terr                 error\n\t\tallowedTypeStrArray = make([]string, 0)\n\t)\n\tcurrentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\tPointer:          pointer,\n\t\tPriorityTagArray: nil,\n\t\tRecursiveOption:  gstructs.RecursiveOptionEmbeddedNoTag,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\t// It checks the with array and automatically calls the ScanList to complete association querying.\n\tif !m.withAll {\n\t\tfor _, field := range currentStructFieldMap {\n\t\t\tfor _, withItem := range m.withArray {\n\t\t\t\twithItemReflectValueType, err := gstructs.StructType(withItem)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tvar (\n\t\t\t\t\tfieldTypeStr                = gstr.TrimAll(field.Type().String(), \"*[]\")\n\t\t\t\t\twithItemReflectValueTypeStr = gstr.TrimAll(withItemReflectValueType.String(), \"*[]\")\n\t\t\t\t)\n\t\t\t\t// It does select operation if the field type is in the specified \"with\" type array.\n\t\t\t\tif gstr.Compare(fieldTypeStr, withItemReflectValueTypeStr) == 0 {\n\t\t\t\t\tallowedTypeStrArray = append(allowedTypeStrArray, fieldTypeStr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor _, field := range currentStructFieldMap {\n\t\tvar (\n\t\t\tfieldTypeStr    = gstr.TrimAll(field.Type().String(), \"*[]\")\n\t\t\tparsedTagOutput = m.parseWithTagInFieldStruct(field)\n\t\t)\n\t\tif parsedTagOutput.With == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\t// It just handlers \"with\" type attribute struct, so it ignores other struct types.\n\t\tif !m.withAll && !gstr.InArray(allowedTypeStrArray, fieldTypeStr) {\n\t\t\tcontinue\n\t\t}\n\t\tarray := gstr.SplitAndTrim(parsedTagOutput.With, \"=\")\n\t\tif len(array) == 1 {\n\t\t\t// It also supports using only one column name\n\t\t\t// if both tables associates using the same column name.\n\t\t\tarray = append(array, parsedTagOutput.With)\n\t\t}\n\t\tvar (\n\t\t\tmodel              *Model\n\t\t\tfieldKeys          []string\n\t\t\trelatedSourceName  = array[0]\n\t\t\trelatedTargetName  = array[1]\n\t\t\trelatedTargetValue any\n\t\t)\n\t\t// Find the value of related attribute from `pointer`.\n\t\tfor attributeName, attributeValue := range currentStructFieldMap {\n\t\t\tif utils.EqualFoldWithoutChars(attributeName, relatedTargetName) {\n\t\t\t\trelatedTargetValue = attributeValue.Value.Interface()\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif relatedTargetValue == nil {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot find the target related value of name \"%s\" in with tag \"%s\" for attribute \"%s.%s\"`,\n\t\t\t\trelatedTargetName, parsedTagOutput.With, reflect.TypeOf(pointer).Elem(), field.Name(),\n\t\t\t)\n\t\t}\n\t\tbindToReflectValue := field.Value\n\t\tif bindToReflectValue.Kind() != reflect.Pointer && bindToReflectValue.CanAddr() {\n\t\t\tbindToReflectValue = bindToReflectValue.Addr()\n\t\t}\n\n\t\tif structFields, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         field.Value,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t} else {\n\t\t\tfieldKeys = make([]string, len(structFields))\n\t\t\tfor i, field := range structFields {\n\t\t\t\tfieldKeys[i] = field.Name()\n\t\t\t}\n\t\t}\n\t\t// Recursively with feature checks.\n\t\tmodel = m.db.With(field.Value).Hook(m.hookHandler)\n\t\tif m.withAll {\n\t\t\tmodel = model.WithAll()\n\t\t} else {\n\t\t\tmodel = model.With(m.withArray...)\n\t\t}\n\t\tif parsedTagOutput.Where != \"\" {\n\t\t\tmodel = model.Where(parsedTagOutput.Where)\n\t\t}\n\t\tif parsedTagOutput.Order != \"\" {\n\t\t\tmodel = model.Order(parsedTagOutput.Order)\n\t\t}\n\t\tif parsedTagOutput.Unscoped == \"true\" {\n\t\t\tmodel = model.Unscoped()\n\t\t}\n\t\t// With cache feature.\n\t\tif m.cacheEnabled && m.cacheOption.Name == \"\" {\n\t\t\tmodel = model.Cache(m.cacheOption)\n\t\t}\n\t\terr = model.Fields(fieldKeys).\n\t\t\tWhere(relatedSourceName, relatedTargetValue).\n\t\t\tScan(bindToReflectValue)\n\t\t// It ignores sql.ErrNoRows in with feature.\n\t\tif err != nil && err != sql.ErrNoRows {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// doWithScanStructs handles model association operations feature for struct slice.\n// Also see doWithScanStruct.\nfunc (m *Model) doWithScanStructs(pointer any) error {\n\tif len(m.withArray) == 0 && !m.withAll {\n\t\treturn nil\n\t}\n\tif v, ok := pointer.(reflect.Value); ok {\n\t\tpointer = v.Interface()\n\t}\n\n\tvar (\n\t\terr                 error\n\t\tallowedTypeStrArray = make([]string, 0)\n\t)\n\tcurrentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\tPointer:          pointer,\n\t\tPriorityTagArray: nil,\n\t\tRecursiveOption:  gstructs.RecursiveOptionEmbeddedNoTag,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\t// It checks the with array and automatically calls the ScanList to complete association querying.\n\tif !m.withAll {\n\t\tfor _, field := range currentStructFieldMap {\n\t\t\tfor _, withItem := range m.withArray {\n\t\t\t\twithItemReflectValueType, err := gstructs.StructType(withItem)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tvar (\n\t\t\t\t\tfieldTypeStr                = gstr.TrimAll(field.Type().String(), \"*[]\")\n\t\t\t\t\twithItemReflectValueTypeStr = gstr.TrimAll(withItemReflectValueType.String(), \"*[]\")\n\t\t\t\t)\n\t\t\t\t// It does select operation if the field type is in the specified with type array.\n\t\t\t\tif gstr.Compare(fieldTypeStr, withItemReflectValueTypeStr) == 0 {\n\t\t\t\t\tallowedTypeStrArray = append(allowedTypeStrArray, fieldTypeStr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor fieldName, field := range currentStructFieldMap {\n\t\tvar (\n\t\t\tfieldTypeStr    = gstr.TrimAll(field.Type().String(), \"*[]\")\n\t\t\tparsedTagOutput = m.parseWithTagInFieldStruct(field)\n\t\t)\n\t\tif parsedTagOutput.With == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif !m.withAll && !gstr.InArray(allowedTypeStrArray, fieldTypeStr) {\n\t\t\tcontinue\n\t\t}\n\t\tarray := gstr.SplitAndTrim(parsedTagOutput.With, \"=\")\n\t\tif len(array) == 1 {\n\t\t\t// It supports using only one column name\n\t\t\t// if both tables associates using the same column name.\n\t\t\tarray = append(array, parsedTagOutput.With)\n\t\t}\n\t\tvar (\n\t\t\tmodel              *Model\n\t\t\tfieldKeys          []string\n\t\t\trelatedSourceName  = array[0]\n\t\t\trelatedTargetName  = array[1]\n\t\t\trelatedTargetValue any\n\t\t)\n\t\t// Find the value slice of related attribute from `pointer`.\n\t\tfor attributeName := range currentStructFieldMap {\n\t\t\tif utils.EqualFoldWithoutChars(attributeName, relatedTargetName) {\n\t\t\t\trelatedTargetValue = ListItemValuesUnique(pointer, attributeName)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif relatedTargetValue == nil {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot find the related value for attribute name \"%s\" of with tag \"%s\"`,\n\t\t\t\trelatedTargetName, parsedTagOutput.With,\n\t\t\t)\n\t\t}\n\t\t// If related value is empty, it does nothing but just returns.\n\t\tif gutil.IsEmpty(relatedTargetValue) {\n\t\t\treturn nil\n\t\t}\n\t\tif structFields, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         field.Value,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t} else {\n\t\t\tfieldKeys = make([]string, len(structFields))\n\t\t\tfor i, field := range structFields {\n\t\t\t\tfieldKeys[i] = field.Name()\n\t\t\t}\n\t\t}\n\t\t// Recursively with feature checks.\n\t\tmodel = m.db.With(field.Value).Hook(m.hookHandler)\n\t\tif m.withAll {\n\t\t\tmodel = model.WithAll()\n\t\t} else {\n\t\t\tmodel = model.With(m.withArray...)\n\t\t}\n\t\tif parsedTagOutput.Where != \"\" {\n\t\t\tmodel = model.Where(parsedTagOutput.Where)\n\t\t}\n\t\tif parsedTagOutput.Order != \"\" {\n\t\t\tmodel = model.Order(parsedTagOutput.Order)\n\t\t}\n\t\tif parsedTagOutput.Unscoped == \"true\" {\n\t\t\tmodel = model.Unscoped()\n\t\t}\n\t\t// With cache feature.\n\t\tif m.cacheEnabled && m.cacheOption.Name == \"\" {\n\t\t\tmodel = model.Cache(m.cacheOption)\n\t\t}\n\t\terr = model.Fields(fieldKeys).\n\t\t\tWhere(relatedSourceName, relatedTargetValue).\n\t\t\tScanList(pointer, fieldName, parsedTagOutput.With)\n\t\t// It ignores sql.ErrNoRows in with feature.\n\t\tif err != nil && err != sql.ErrNoRows {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\ntype parseWithTagInFieldStructOutput struct {\n\tWith     string\n\tWhere    string\n\tOrder    string\n\tUnscoped string\n}\n\nfunc (m *Model) parseWithTagInFieldStruct(field gstructs.Field) (output parseWithTagInFieldStructOutput) {\n\tvar (\n\t\tormTag = field.Tag(OrmTagForStruct)\n\t\tdata   = make(map[string]string)\n\t\tarray  []string\n\t\tkey    string\n\t)\n\tfor _, v := range gstr.SplitAndTrim(ormTag, \",\") {\n\t\tarray = gstr.Split(v, \":\")\n\t\tif len(array) == 2 {\n\t\t\tkey = array[0]\n\t\t\tdata[key] = gstr.Trim(array[1])\n\t\t} else {\n\t\t\tif key == OrmTagForWithOrder {\n\t\t\t\t// supporting multiple order fields\n\t\t\t\tdata[key] += \",\" + gstr.Trim(v)\n\t\t\t} else {\n\t\t\t\tdata[key] += \" \" + gstr.Trim(v)\n\t\t\t}\n\t\t}\n\t}\n\toutput.With = data[OrmTagForWith]\n\toutput.Where = data[OrmTagForWithWhere]\n\toutput.Order = data[OrmTagForWithOrder]\n\toutput.Unscoped = data[OrmTagForWithUnscoped]\n\treturn\n}\n"
  },
  {
    "path": "database/gdb/gdb_panic_recovery_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// mockPanicStmt simulates a prepared statement that panics during execution\ntype mockPanicStmt struct {\n\tpanicMessage string\n}\n\nfunc (m *mockPanicStmt) ExecContext(ctx context.Context, args ...any) (sql.Result, error) {\n\tif m.panicMessage != \"\" {\n\t\tpanic(m.panicMessage)\n\t}\n\tpanic(\"math/big: buffer too small to fit value\")\n}\n\nfunc (m *mockPanicStmt) QueryContext(ctx context.Context, args ...any) (*sql.Rows, error) {\n\tif m.panicMessage != \"\" {\n\t\tpanic(m.panicMessage)\n\t}\n\tpanic(\"math/big: buffer too small to fit value\")\n}\n\nfunc (m *mockPanicStmt) QueryRowContext(ctx context.Context, args ...any) *sql.Row {\n\tif m.panicMessage != \"\" {\n\t\tpanic(m.panicMessage)\n\t}\n\tpanic(\"math/big: buffer too small to fit value\")\n}\n\nfunc (m *mockPanicStmt) Close() error {\n\treturn nil\n}\n\n// Test_PanicRecoveryErrorWrapping tests that the panic recovery properly wraps errors\n// with correct error codes and messages\nfunc Test_PanicRecoveryErrorWrapping(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test creating an error from a string panic value\n\t\tdefer func() {\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\tvar err error\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\terr = v\n\t\t\t\t} else {\n\t\t\t\t\terr = gerror.WrapCodef(gcode.CodeDbOperationError, gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception), \"test SQL\")\n\t\t\t\t}\n\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t\tt.Assert(strings.Contains(err.Error(), \"buffer too small\"), true)\n\t\t\t\tt.Assert(strings.Contains(err.Error(), \"test SQL\"), true)\n\t\t\t}\n\t\t}()\n\n\t\t// Simulate the panic that would occur in database operations\n\t\tpanic(\"math/big: buffer too small to fit value\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test creating an error from an error panic value with stack\n\t\tdefer func() {\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\tvar err error\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\terr = v\n\t\t\t\t} else {\n\t\t\t\t\terr = gerror.WrapCodef(gcode.CodeDbOperationError, gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception), \"test SQL\")\n\t\t\t\t}\n\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t\t// Since gerror has stack, it should preserve the original error\n\t\t\t\tt.Assert(strings.Contains(err.Error(), \"custom database error\"), true)\n\t\t\t}\n\t\t}()\n\n\t\t// Simulate a panic with a custom error that has stack\n\t\tcustomErr := gerror.New(\"custom database error\")\n\t\tpanic(customErr)\n\t})\n}\n\n// Test_DoCommit_StmtPanicRecovery simulates the scenario from the issue where\n// statement execution causes a panic during DoCommit operations\nfunc Test_DoCommit_StmtPanicRecovery(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// We'll test the panic recovery by triggering it in the defer function\n\t\t// Since we can't easily mock sql.Stmt, we'll test the panic recovery mechanism directly\n\n\t\ttestPanicRecovery := func(panicValue any, sqlText string) (err error) {\n\t\t\tdefer func() {\n\t\t\t\tif exception := recover(); exception != nil {\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\t\t\terr = v\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\terr = gerror.WrapCodef(gcode.CodeDbOperationError, gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception), FormatSqlWithArgs(sqlText, []any{123}))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\t// Simulate the panic that would occur in database operations\n\t\t\tpanic(panicValue)\n\t\t}\n\n\t\t// Test different panic scenarios\n\t\ttestCases := []struct {\n\t\t\tname       string\n\t\t\tpanicValue any\n\t\t\tsqlText    string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:       \"String panic from math/big\",\n\t\t\t\tpanicValue: \"math/big: buffer too small to fit value\",\n\t\t\t\tsqlText:    \"INSERT INTO test VALUES (?)\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"Custom error panic\",\n\t\t\t\tpanicValue: gerror.New(\"clickhouse driver panic\"),\n\t\t\t\tsqlText:    \"SELECT * FROM test WHERE id = ?\",\n\t\t\t},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Log(\"Testing:\", tc.name)\n\n\t\t\t// Test the panic recovery mechanism\n\t\t\terr := testPanicRecovery(tc.panicValue, tc.sqlText)\n\n\t\t\t// After our fix, these should return errors instead of panicking\n\t\t\tt.AssertNE(err, nil)\n\n\t\t\t// Verify the error contains information about the panic\n\t\t\terrorMsg := err.Error()\n\n\t\t\tif tc.name == \"String panic from math/big\" {\n\t\t\t\tt.Assert(strings.Contains(errorMsg, \"buffer too small\"), true)\n\t\t\t\tt.Assert(strings.Contains(errorMsg, \"INSERT INTO test VALUES\"), true)\n\t\t\t} else {\n\t\t\t\tt.Assert(strings.Contains(errorMsg, \"clickhouse driver panic\"), true)\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// SqlResult is execution result for sql operations.\n// It also supports batch operation result for rowsAffected.\ntype SqlResult struct {\n\tResult   sql.Result\n\tAffected int64\n}\n\n// MustGetAffected returns the affected rows count, if any error occurs, it panics.\nfunc (r *SqlResult) MustGetAffected() int64 {\n\trows, err := r.RowsAffected()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `sql.Result.RowsAffected failed`)\n\t\tpanic(err)\n\t}\n\treturn rows\n}\n\n// MustGetInsertId returns the last insert id, if any error occurs, it panics.\nfunc (r *SqlResult) MustGetInsertId() int64 {\n\tid, err := r.LastInsertId()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `sql.Result.LastInsertId failed`)\n\t\tpanic(err)\n\t}\n\treturn id\n}\n\n// RowsAffected returns the number of rows affected by an\n// update, insert, or delete. Not every database or database\n// driver may support this.\n// Also, See sql.Result.\nfunc (r *SqlResult) RowsAffected() (int64, error) {\n\tif r.Affected > 0 {\n\t\treturn r.Affected, nil\n\t}\n\tif r.Result == nil {\n\t\treturn 0, nil\n\t}\n\treturn r.Result.RowsAffected()\n}\n\n// LastInsertId returns the integer generated by the database\n// in response to a command. Typically, this will be from an\n// \"auto increment\" column when inserting a new row. Not all\n// databases support this feature, and the syntax of such\n// statements varies.\n// Also, See sql.Result.\nfunc (r *SqlResult) LastInsertId() (int64, error) {\n\tif r.Result == nil {\n\t\treturn 0, nil\n\t}\n\treturn r.Result.LastInsertId()\n}\n"
  },
  {
    "path": "database/gdb/gdb_schema.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\n// Schema is a schema object from which it can then create a Model.\ntype Schema struct {\n\tDB\n}\n\n// Schema creates and returns a schema.\nfunc (c *Core) Schema(schema string) *Schema {\n\t// Do not change the schema of the original db,\n\t// it here creates a new db and changes its schema.\n\tdb, err := NewByGroup(c.GetGroup())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tcore := db.GetCore()\n\t// Different schema share some same objects.\n\tcore.logger = c.logger\n\tcore.cache = c.cache\n\tcore.schema = schema\n\treturn &Schema{\n\t\tDB: db,\n\t}\n}\n"
  },
  {
    "path": "database/gdb/gdb_statement.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\n// Stmt is a prepared statement.\n// A Stmt is safe for concurrent use by multiple goroutines.\n//\n// If a Stmt is prepared on a Tx or Conn, it will be bound to a single\n// underlying connection forever. If the Tx or Conn closes, the Stmt will\n// become unusable and all operations will return an error.\n// If a Stmt is prepared on a DB, it will remain usable for the lifetime of the\n// DB. When the Stmt needs to execute on a new underlying connection, it will\n// prepare itself on the new connection automatically.\ntype Stmt struct {\n\t*sql.Stmt\n\tcore *Core\n\tlink Link\n\tsql  string\n}\n\n// ExecContext executes a prepared statement with the given arguments and\n// returns a Result summarizing the effect of the statement.\nfunc (s *Stmt) ExecContext(ctx context.Context, args ...any) (sql.Result, error) {\n\tout, err := s.core.db.DoCommit(ctx, DoCommitInput{\n\t\tStmt:          s.Stmt,\n\t\tLink:          s.link,\n\t\tSql:           s.sql,\n\t\tArgs:          args,\n\t\tType:          SqlTypeStmtExecContext,\n\t\tIsTransaction: s.link.IsTransaction(),\n\t})\n\treturn out.Result, err\n}\n\n// QueryContext executes a prepared query statement with the given arguments\n// and returns the query results as a *Rows.\nfunc (s *Stmt) QueryContext(ctx context.Context, args ...any) (*sql.Rows, error) {\n\tout, err := s.core.db.DoCommit(ctx, DoCommitInput{\n\t\tStmt:          s.Stmt,\n\t\tLink:          s.link,\n\t\tSql:           s.sql,\n\t\tArgs:          args,\n\t\tType:          SqlTypeStmtQueryContext,\n\t\tIsTransaction: s.link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif out.RawResult != nil {\n\t\treturn out.RawResult.(*sql.Rows), err\n\t}\n\treturn nil, nil\n}\n\n// QueryRowContext executes a prepared query statement with the given arguments.\n// If an error occurs during the execution of the statement, that error will\n// be returned by a call to Scan on the returned *Row, which is always non-nil.\n// If the query selects no rows, the *Row's Scan will return ErrNoRows.\n// Otherwise, the *Row's Scan scans the first selected row and discards\n// the rest.\nfunc (s *Stmt) QueryRowContext(ctx context.Context, args ...any) *sql.Row {\n\tout, err := s.core.db.DoCommit(ctx, DoCommitInput{\n\t\tStmt:          s.Stmt,\n\t\tLink:          s.link,\n\t\tSql:           s.sql,\n\t\tArgs:          args,\n\t\tType:          SqlTypeStmtQueryContext,\n\t\tIsTransaction: s.link.IsTransaction(),\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif out.RawResult != nil {\n\t\treturn out.RawResult.(*sql.Row)\n\t}\n\treturn nil\n}\n\n// Exec executes a prepared statement with the given arguments and\n// returns a Result summarizing the effect of the statement.\nfunc (s *Stmt) Exec(args ...any) (sql.Result, error) {\n\treturn s.ExecContext(context.Background(), args...)\n}\n\n// Query executes a prepared query statement with the given arguments\n// and returns the query results as a *Rows.\nfunc (s *Stmt) Query(args ...any) (*sql.Rows, error) {\n\treturn s.QueryContext(context.Background(), args...)\n}\n\n// QueryRow executes a prepared query statement with the given arguments.\n// If an error occurs during the execution of the statement, that error will\n// be returned by a call to Scan on the returned *Row, which is always non-nil.\n// If the query selects no rows, the *Row's Scan will return ErrNoRows.\n// Otherwise, the *Row's Scan scans the first selected row and discards\n// the rest.\n//\n// Example usage:\n//\n//\tvar name string\n//\terr := nameByUseridStmt.QueryRow(id).Scan(&name)\nfunc (s *Stmt) QueryRow(args ...any) *sql.Row {\n\treturn s.QueryRowContext(context.Background(), args...)\n}\n\n// Close closes the statement.\nfunc (s *Stmt) Close() error {\n\treturn s.Stmt.Close()\n}\n"
  },
  {
    "path": "database/gdb/gdb_type_record.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Json converts `r` to JSON format content.\nfunc (r Record) Json() string {\n\tcontent, _ := gjson.New(r.Map()).ToJsonString()\n\treturn content\n}\n\n// Xml converts `r` to XML format content.\nfunc (r Record) Xml(rootTag ...string) string {\n\tcontent, _ := gjson.New(r.Map()).ToXmlString(rootTag...)\n\treturn content\n}\n\n// Map converts `r` to map[string]any.\nfunc (r Record) Map() Map {\n\tm := make(map[string]any)\n\tfor k, v := range r {\n\t\tm[k] = v.Val()\n\t}\n\treturn m\n}\n\n// GMap converts `r` to a gmap.\nfunc (r Record) GMap() *gmap.StrAnyMap {\n\treturn gmap.NewStrAnyMapFrom(r.Map())\n}\n\n// Struct converts `r` to a struct.\n// Note that the parameter `pointer` should be type of *struct/**struct.\n//\n// Note that it returns sql.ErrNoRows if `r` is empty.\nfunc (r Record) Struct(pointer any) error {\n\t// If the record is empty, it returns error.\n\tif r.IsEmpty() {\n\t\tif !empty.IsNil(pointer, true) {\n\t\t\treturn sql.ErrNoRows\n\t\t}\n\t\treturn nil\n\t}\n\treturn converter.Struct(r, pointer, gconv.StructOption{\n\t\tPriorityTag:     OrmTagForStruct,\n\t\tContinueOnError: true,\n\t})\n}\n\n// IsEmpty checks and returns whether `r` is empty.\nfunc (r Record) IsEmpty() bool {\n\treturn len(r) == 0\n}\n"
  },
  {
    "path": "database/gdb/gdb_type_result.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// IsEmpty checks and returns whether `r` is empty.\nfunc (r Result) IsEmpty() bool {\n\treturn r == nil || r.Len() == 0\n}\n\n// Len returns the length of result list.\nfunc (r Result) Len() int {\n\treturn len(r)\n}\n\n// Size is alias of function Len.\nfunc (r Result) Size() int {\n\treturn r.Len()\n}\n\n// Chunk splits a Result into multiple Results,\n// the size of each array is determined by `size`.\n// The last chunk may contain less than size elements.\nfunc (r Result) Chunk(size int) []Result {\n\tif size < 1 {\n\t\treturn nil\n\t}\n\tlength := len(r)\n\tchunks := int(math.Ceil(float64(length) / float64(size)))\n\tvar n []Result\n\tfor i, end := 0, 0; chunks > 0; chunks-- {\n\t\tend = (i + 1) * size\n\t\tif end > length {\n\t\t\tend = length\n\t\t}\n\t\tn = append(n, r[i*size:end])\n\t\ti++\n\t}\n\treturn n\n}\n\n// Json converts `r` to JSON format content.\nfunc (r Result) Json() string {\n\tcontent, _ := gjson.New(r.List()).ToJsonString()\n\treturn content\n}\n\n// Xml converts `r` to XML format content.\nfunc (r Result) Xml(rootTag ...string) string {\n\tcontent, _ := gjson.New(r.List()).ToXmlString(rootTag...)\n\treturn content\n}\n\n// List converts `r` to a List.\nfunc (r Result) List() List {\n\tlist := make(List, len(r))\n\tfor k, v := range r {\n\t\tlist[k] = v.Map()\n\t}\n\treturn list\n}\n\n// Array retrieves and returns specified column values as slice.\n// The parameter `field` is optional is the column field is only one.\n// The default `field` is the first field name of the first item in `Result` if parameter `field` is not given.\nfunc (r Result) Array(field ...string) Array {\n\tarray := make(Array, len(r))\n\tif len(r) == 0 {\n\t\treturn array\n\t}\n\tkey := \"\"\n\tif len(field) > 0 && field[0] != \"\" {\n\t\tkey = field[0]\n\t} else {\n\t\tfor k := range r[0] {\n\t\t\tkey = k\n\t\t\tbreak\n\t\t}\n\t}\n\tfor k, v := range r {\n\t\tarray[k] = v[key]\n\t}\n\treturn array\n}\n\n// MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`.\n// Note that the item value may be type of slice.\nfunc (r Result) MapKeyValue(key string) map[string]Value {\n\tvar (\n\t\ts              string\n\t\tm              = make(map[string]Value)\n\t\ttempMap        = make(map[string][]any)\n\t\thasMultiValues bool\n\t)\n\tfor _, item := range r {\n\t\tif k, ok := item[key]; ok {\n\t\t\ts = k.String()\n\t\t\ttempMap[s] = append(tempMap[s], item)\n\t\t\tif len(tempMap[s]) > 1 {\n\t\t\t\thasMultiValues = true\n\t\t\t}\n\t\t}\n\t}\n\tfor k, v := range tempMap {\n\t\tif hasMultiValues {\n\t\t\tm[k] = gvar.New(v)\n\t\t} else {\n\t\t\tm[k] = gvar.New(v[0])\n\t\t}\n\t}\n\treturn m\n}\n\n// MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`.\nfunc (r Result) MapKeyStr(key string) map[string]Map {\n\tm := make(map[string]Map)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.String()] = item.Map()\n\t\t}\n\t}\n\treturn m\n}\n\n// MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`.\nfunc (r Result) MapKeyInt(key string) map[int]Map {\n\tm := make(map[int]Map)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.Int()] = item.Map()\n\t\t}\n\t}\n\treturn m\n}\n\n// MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`.\nfunc (r Result) MapKeyUint(key string) map[uint]Map {\n\tm := make(map[uint]Map)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.Uint()] = item.Map()\n\t\t}\n\t}\n\treturn m\n}\n\n// RecordKeyStr converts `r` to a map[string]Record of which key is specified by `key`.\nfunc (r Result) RecordKeyStr(key string) map[string]Record {\n\tm := make(map[string]Record)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.String()] = item\n\t\t}\n\t}\n\treturn m\n}\n\n// RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`.\nfunc (r Result) RecordKeyInt(key string) map[int]Record {\n\tm := make(map[int]Record)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.Int()] = item\n\t\t}\n\t}\n\treturn m\n}\n\n// RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`.\nfunc (r Result) RecordKeyUint(key string) map[uint]Record {\n\tm := make(map[uint]Record)\n\tfor _, item := range r {\n\t\tif v, ok := item[key]; ok {\n\t\t\tm[v.Uint()] = item\n\t\t}\n\t}\n\treturn m\n}\n\n// Structs converts `r` to struct slice.\n// Note that the parameter `pointer` should be type of *[]struct/*[]*struct.\nfunc (r Result) Structs(pointer any) (err error) {\n\t// If the result is empty and the target pointer is not empty, it returns error.\n\tif r.IsEmpty() {\n\t\tif !empty.IsEmpty(pointer, true) {\n\t\t\treturn sql.ErrNoRows\n\t\t}\n\t\treturn nil\n\t}\n\tvar (\n\t\tsliceOption  = gconv.SliceOption{ContinueOnError: true}\n\t\tstructOption = gconv.StructOption{\n\t\t\tPriorityTag:     OrmTagForStruct,\n\t\t\tContinueOnError: true,\n\t\t}\n\t)\n\treturn converter.Structs(r, pointer, gconv.StructsOption{\n\t\tSliceOption:  sliceOption,\n\t\tStructOption: structOption,\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_type_result_scanlist.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// ScanList converts `r` to struct slice which contains other complex struct attributes.\n// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.\n//\n// Usage example 1: Normal attribute struct relation:\n//\n//\ttype EntityUser struct {\n//\t\t   Uid  int\n//\t\t   Name string\n//\t}\n//\n//\ttype EntityUserDetail struct {\n//\t\t   Uid     int\n//\t\t   Address string\n//\t}\n//\n//\ttype EntityUserScores struct {\n//\t\t   Id     int\n//\t\t   Uid    int\n//\t\t   Score  int\n//\t\t   Course string\n//\t}\n//\n//\ttype Entity struct {\n//\t    User       *EntityUser\n//\t\t   UserDetail *EntityUserDetail\n//\t\t   UserScores []*EntityUserScores\n//\t}\n//\n// var users []*Entity\n// ScanList(&users, \"User\")\n// ScanList(&users, \"User\", \"uid\")\n// ScanList(&users, \"UserDetail\", \"User\", \"uid:Uid\")\n// ScanList(&users, \"UserScores\", \"User\", \"uid:Uid\")\n// ScanList(&users, \"UserScores\", \"User\", \"uid\")\n//\n// Usage example 2: Embedded attribute struct relation:\n//\n//\ttype EntityUser struct {\n//\t\t   Uid  int\n//\t\t   Name string\n//\t}\n//\n//\ttype EntityUserDetail struct {\n//\t\t   Uid     int\n//\t\t   Address string\n//\t}\n//\n//\ttype EntityUserScores struct {\n//\t\t   Id    int\n//\t\t   Uid   int\n//\t\t   Score int\n//\t}\n//\n//\ttype Entity struct {\n//\t\t   EntityUser\n//\t\t   UserDetail EntityUserDetail\n//\t\t   UserScores []EntityUserScores\n//\t}\n//\n// var users []*Entity\n// ScanList(&users)\n// ScanList(&users, \"UserDetail\", \"uid\")\n// ScanList(&users, \"UserScores\", \"uid\")\n//\n// The parameters \"User/UserDetail/UserScores\" in the example codes specify the target attribute struct\n// that current result will be bound to.\n//\n// The \"uid\" in the example codes is the table field name of the result, and the \"Uid\" is the relational\n// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute\n// name \"Uid\" of \"User\" of entity \"Entity\". It automatically calculates the HasOne/HasMany relationship with\n// given `relation` parameter.\n//\n// See the example or unit testing cases for clear understanding for this function.\nfunc (r Result) ScanList(structSlicePointer any, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {\n\tout, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar (\n\t\trelationAttrName string\n\t\trelationFields   string\n\t)\n\tswitch len(relationAttrNameAndFields) {\n\tcase 2:\n\t\trelationAttrName = relationAttrNameAndFields[0]\n\t\trelationFields = relationAttrNameAndFields[1]\n\tcase 1:\n\t\trelationFields = relationAttrNameAndFields[0]\n\t}\n\treturn doScanList(doScanListInput{\n\t\tModel:              nil,\n\t\tResult:             r,\n\t\tStructSlicePointer: structSlicePointer,\n\t\tStructSliceValue:   out.SliceReflectValue,\n\t\tBindToAttrName:     bindToAttrName,\n\t\tRelationAttrName:   relationAttrName,\n\t\tRelationFields:     relationFields,\n\t})\n}\n\ntype checkGetSliceElementInfoForScanListOutput struct {\n\tSliceReflectValue reflect.Value\n\tBindToAttrType    reflect.Type\n}\n\nfunc checkGetSliceElementInfoForScanList(structSlicePointer any, bindToAttrName string) (out *checkGetSliceElementInfoForScanListOutput, err error) {\n\t// Necessary checks for parameters.\n\tif structSlicePointer == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, `structSlicePointer cannot be nil`)\n\t}\n\tif bindToAttrName == \"\" {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)\n\t}\n\tvar (\n\t\treflectType  reflect.Type\n\t\treflectValue = reflect.ValueOf(structSlicePointer)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tif reflectKind == reflect.Interface {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tif reflectKind != reflect.Pointer {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"structSlicePointer should be type of *[]struct/*[]*struct, but got: %s\",\n\t\t\treflect.TypeOf(structSlicePointer).String(),\n\t\t)\n\t}\n\tout = &checkGetSliceElementInfoForScanListOutput{\n\t\tSliceReflectValue: reflectValue.Elem(),\n\t}\n\t// Find the element struct type of the slice.\n\treflectType = reflectValue.Type().Elem().Elem()\n\treflectKind = reflectType.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\treflectType = reflectType.Elem()\n\t\treflectKind = reflectType.Kind()\n\t}\n\tif reflectKind != reflect.Struct {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"structSlicePointer should be type of *[]struct/*[]*struct, but got: %s\",\n\t\t\treflect.TypeOf(structSlicePointer).String(),\n\t\t)\n\t\treturn\n\t}\n\t// Find the target field by given name.\n\tstructField, ok := reflectType.FieldByName(bindToAttrName)\n\tif !ok {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`field \"%s\" not found in element of \"%s\"`,\n\t\t\tbindToAttrName,\n\t\t\treflect.TypeOf(structSlicePointer).String(),\n\t\t)\n\t}\n\t// Find the attribute struct type for ORM fields filtering.\n\treflectType = structField.Type\n\treflectKind = reflectType.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\treflectType = reflectType.Elem()\n\t\treflectKind = reflectType.Kind()\n\t}\n\tif reflectKind == reflect.Slice || reflectKind == reflect.Array {\n\t\treflectType = reflectType.Elem()\n\t\t// reflectKind = reflectType.Kind()\n\t}\n\tout.BindToAttrType = reflectType\n\treturn\n}\n\ntype doScanListInput struct {\n\tModel              *Model\n\tResult             Result\n\tStructSlicePointer any\n\tStructSliceValue   reflect.Value\n\tBindToAttrName     string\n\tRelationAttrName   string\n\tRelationFields     string\n}\n\n// doScanList converts `result` to struct slice which contains other complex struct attributes recursively.\n// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively,\n// but it needs the Model for database accessing.\n// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.\nfunc doScanList(in doScanListInput) (err error) {\n\tif in.Result.IsEmpty() {\n\t\treturn nil\n\t}\n\tif in.BindToAttrName == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)\n\t}\n\n\tlength := len(in.Result)\n\tif length == 0 {\n\t\t// The pointed slice is not empty.\n\t\tif in.StructSliceValue.Len() > 0 {\n\t\t\t// It here checks if it has struct item, which is already initialized.\n\t\t\t// It then returns error to warn the developer its empty and no conversion.\n\t\t\tif v := in.StructSliceValue.Index(0); v.Kind() != reflect.Pointer {\n\t\t\t\treturn sql.ErrNoRows\n\t\t\t}\n\t\t}\n\t\t// Do nothing for empty struct slice.\n\t\treturn nil\n\t}\n\tvar (\n\t\tarrayValue    reflect.Value // Like: []*Entity\n\t\tarrayItemType reflect.Type  // Like: *Entity\n\t\treflectType   = reflect.TypeOf(in.StructSlicePointer)\n\t)\n\tif in.StructSliceValue.Len() > 0 {\n\t\tarrayValue = in.StructSliceValue\n\t} else {\n\t\tarrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)\n\t}\n\n\t// Slice element item.\n\tarrayItemType = arrayValue.Index(0).Type()\n\n\t// Relation variables.\n\tvar (\n\t\trelationDataMap         map[string]Value\n\t\trelationFromFieldName   string // Eg: relationKV: id:uid  -> id\n\t\trelationBindToFieldName string // Eg: relationKV: id:uid  -> uid\n\t)\n\tif len(in.RelationFields) > 0 {\n\t\t// The relation key string of table field name and attribute name\n\t\t// can be joined with char '=' or ':'.\n\t\tarray := gstr.SplitAndTrim(in.RelationFields, \"=\")\n\t\tif len(array) == 1 {\n\t\t\t// Compatible with old splitting char ':'.\n\t\t\tarray = gstr.SplitAndTrim(in.RelationFields, \":\")\n\t\t}\n\t\tif len(array) == 1 {\n\t\t\t// The relation names are the same.\n\t\t\tarray = []string{in.RelationFields, in.RelationFields}\n\t\t}\n\t\tif len(array) == 2 {\n\t\t\t// Defined table field to relation attribute name.\n\t\t\t// Like:\n\t\t\t// uid:Uid\n\t\t\t// uid:UserId\n\t\t\trelationFromFieldName = array[0]\n\t\t\trelationBindToFieldName = array[1]\n\t\t\tif key, _ := gutil.MapPossibleItemByKey(in.Result[0].Map(), relationFromFieldName); key == \"\" {\n\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`cannot find possible related table field name \"%s\" from given relation fields \"%s\"`,\n\t\t\t\t\trelationFromFieldName,\n\t\t\t\t\tin.RelationFields,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\trelationFromFieldName = key\n\t\t\t}\n\t\t} else {\n\t\t\treturn gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`parameter relationKV should be format of \"ResultFieldName:BindToAttrName\"`,\n\t\t\t)\n\t\t}\n\t\tif relationFromFieldName != \"\" {\n\t\t\t// Note that the value might be type of slice.\n\t\t\trelationDataMap = in.Result.MapKeyValue(relationFromFieldName)\n\t\t}\n\t\tif len(relationDataMap) == 0 {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot find the relation data map, maybe invalid relation fields given \"%v\"`,\n\t\t\t\tin.RelationFields,\n\t\t\t)\n\t\t}\n\t}\n\t// Bind to target attribute.\n\tvar (\n\t\tok              bool\n\t\tbindToAttrValue reflect.Value\n\t\tbindToAttrKind  reflect.Kind\n\t\tbindToAttrType  reflect.Type\n\t\tbindToAttrField reflect.StructField\n\t)\n\tif arrayItemType.Kind() == reflect.Pointer {\n\t\tif bindToAttrField, ok = arrayItemType.Elem().FieldByName(in.BindToAttrName); !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid parameter bindToAttrName: cannot find attribute with name \"%s\" from slice element`,\n\t\t\t\tin.BindToAttrName,\n\t\t\t)\n\t\t}\n\t} else {\n\t\tif bindToAttrField, ok = arrayItemType.FieldByName(in.BindToAttrName); !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid parameter bindToAttrName: cannot find attribute with name \"%s\" from slice element`,\n\t\t\t\tin.BindToAttrName,\n\t\t\t)\n\t\t}\n\t}\n\tbindToAttrType = bindToAttrField.Type\n\tbindToAttrKind = bindToAttrType.Kind()\n\n\t// Bind to relation conditions.\n\tvar (\n\t\trelationFromAttrValue          reflect.Value\n\t\trelationFromAttrField          reflect.Value\n\t\trelationBindToFieldNameChecked bool\n\t)\n\tfor i := 0; i < arrayValue.Len(); i++ {\n\t\tarrayElemValue := arrayValue.Index(i)\n\t\t// The FieldByName should be called on non-pointer reflect.Value.\n\t\tif arrayElemValue.Kind() == reflect.Pointer {\n\t\t\t// Like: []*Entity\n\t\t\tarrayElemValue = arrayElemValue.Elem()\n\t\t\tif !arrayElemValue.IsValid() {\n\t\t\t\t// The element is nil, then create one and set it to the slice.\n\t\t\t\t// The \"reflect.New(itemType.Elem())\" creates a new element and returns the address of it.\n\t\t\t\t// For example:\n\t\t\t\t// reflect.New(itemType.Elem())        => *Entity\n\t\t\t\t// reflect.New(itemType.Elem()).Elem() => Entity\n\t\t\t\tarrayElemValue = reflect.New(arrayItemType.Elem()).Elem()\n\t\t\t\tarrayValue.Index(i).Set(arrayElemValue.Addr())\n\t\t\t}\n\t\t\t// } else {\n\t\t\t// Like: []Entity\n\t\t}\n\t\tbindToAttrValue = arrayElemValue.FieldByName(in.BindToAttrName)\n\t\tif in.RelationAttrName != \"\" {\n\t\t\t// Attribute value of current slice element.\n\t\t\trelationFromAttrValue = arrayElemValue.FieldByName(in.RelationAttrName)\n\t\t\tif relationFromAttrValue.Kind() == reflect.Pointer {\n\t\t\t\trelationFromAttrValue = relationFromAttrValue.Elem()\n\t\t\t}\n\t\t} else {\n\t\t\t// Current slice element.\n\t\t\trelationFromAttrValue = arrayElemValue\n\t\t}\n\t\tif len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, in.RelationFields)\n\t\t}\n\t\t// Check and find possible bind to attribute name.\n\t\tif in.RelationFields != \"\" && !relationBindToFieldNameChecked {\n\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\tif !relationFromAttrField.IsValid() {\n\t\t\t\tfieldMap, _ := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\t\t\t\tPointer:         relationFromAttrValue,\n\t\t\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t\t\t})\n\t\t\t\tif key, _ := gutil.MapPossibleItemByKey(gconv.Map(fieldMap), relationBindToFieldName); key == \"\" {\n\t\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t\t`cannot find possible related attribute name \"%s\" from given relation fields \"%s\"`,\n\t\t\t\t\t\trelationBindToFieldName,\n\t\t\t\t\t\tin.RelationFields,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\trelationBindToFieldName = key\n\t\t\t\t}\n\t\t\t}\n\t\t\trelationBindToFieldNameChecked = true\n\t\t}\n\t\tswitch bindToAttrKind {\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\tresults := make(Result, 0)\n\t\t\t\t\tfor _, v := range relationDataMap[gconv.String(relationFromAttrField.Interface())].Slice() {\n\t\t\t\t\t\tresults = append(results, v.(Record))\n\t\t\t\t\t}\n\t\t\t\t\tif err = results.Structs(bindToAttrValue.Addr()); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t// Recursively Scan.\n\t\t\t\t\tif in.Model != nil {\n\t\t\t\t\t\tif err = in.Model.doWithScanStructs(bindToAttrValue.Addr()); err != nil {\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, in.RelationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`relationKey should not be empty as field \"%s\" is slice`,\n\t\t\t\t\tin.BindToAttrName,\n\t\t\t\t)\n\t\t\t}\n\n\t\tcase reflect.Pointer:\n\t\t\tvar element reflect.Value\n\t\t\tif bindToAttrValue.IsNil() {\n\t\t\t\telement = reflect.New(bindToAttrType.Elem()).Elem()\n\t\t\t} else {\n\t\t\t\telement = bindToAttrValue.Elem()\n\t\t\t}\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\tv := relationDataMap[gconv.String(relationFromAttrField.Interface())]\n\t\t\t\t\tif v == nil {\n\t\t\t\t\t\t// There's no relational data.\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif v.IsSlice() {\n\t\t\t\t\t\tif err = v.Slice()[0].(Record).Struct(element); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err = v.Val().(Record).Struct(element); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, in.RelationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif i >= len(in.Result) {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tv := in.Result[i]\n\t\t\t\tif v == nil {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err = v.Struct(element); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Recursively Scan.\n\t\t\tif in.Model != nil {\n\t\t\t\tif err = in.Model.doWithScanStruct(element); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tbindToAttrValue.Set(element.Addr())\n\n\t\tcase reflect.Struct:\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\trelationDataItem := relationDataMap[gconv.String(relationFromAttrField.Interface())]\n\t\t\t\t\tif relationDataItem == nil {\n\t\t\t\t\t\t// There's no relational data.\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif relationDataItem.IsSlice() {\n\t\t\t\t\t\tif err = relationDataItem.Slice()[0].(Record).Struct(bindToAttrValue); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err = relationDataItem.Val().(Record).Struct(bindToAttrValue); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, in.RelationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif i >= len(in.Result) {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trelationDataItem := in.Result[i]\n\t\t\t\tif relationDataItem == nil {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err = relationDataItem.Struct(bindToAttrValue); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Recursively Scan.\n\t\t\tif in.Model != nil {\n\t\t\t\tif err = in.Model.doWithScanStruct(bindToAttrValue); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())\n\t\t}\n\t}\n\treflect.ValueOf(in.StructSlicePointer).Elem().Set(arrayValue)\n\treturn nil\n}\n"
  },
  {
    "path": "database/gdb/gdb_z_core_config_external_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GetAllConfig(t *testing.T) {\n\t// Test case 1: Empty configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config to empty\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 0)\n\t})\n\n\t// Test case 2: Single configuration group with one node\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\ttestNode := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"test_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"test_group\", testNode)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"test_group\"]), 1)\n\t\tt.Assert(result[\"test_group\"][0].Host, \"127.0.0.1\")\n\t\tt.Assert(result[\"test_group\"][0].Port, \"3306\")\n\t\tt.Assert(result[\"test_group\"][0].User, \"root\")\n\t\tt.Assert(result[\"test_group\"][0].Pass, \"123456\")\n\t\tt.Assert(result[\"test_group\"][0].Name, \"test_db\")\n\t\tt.Assert(result[\"test_group\"][0].Type, \"mysql\")\n\t})\n\n\t// Test case 3: Multiple configuration groups with multiple nodes\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\t// Add first group with two nodes\n\t\ttestNode1 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"master_db\",\n\t\t\tType: \"mysql\",\n\t\t\tRole: \"master\",\n\t\t}\n\t\ttestNode2 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.2\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"slave_db\",\n\t\t\tType: \"mysql\",\n\t\t\tRole: \"slave\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"mysql_cluster\", testNode1)\n\t\tt.AssertNil(err)\n\t\terr = gdb.AddConfigNode(\"mysql_cluster\", testNode2)\n\t\tt.AssertNil(err)\n\n\t\t// Add second group with one node\n\t\ttestNode3 := gdb.ConfigNode{\n\t\t\tHost: \"localhost\",\n\t\t\tPort: \"5432\",\n\t\t\tUser: \"postgres\",\n\t\t\tPass: \"password\",\n\t\t\tName: \"pg_db\",\n\t\t\tType: \"pgsql\",\n\t\t}\n\n\t\terr = gdb.AddConfigNode(\"postgres_db\", testNode3)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 2)\n\n\t\t// Check mysql_cluster group\n\t\tt.Assert(len(result[\"mysql_cluster\"]), 2)\n\t\tt.Assert(result[\"mysql_cluster\"][0].Host, \"127.0.0.1\")\n\t\tt.Assert(result[\"mysql_cluster\"][0].Role, \"master\")\n\t\tt.Assert(result[\"mysql_cluster\"][1].Host, \"127.0.0.2\")\n\t\tt.Assert(result[\"mysql_cluster\"][1].Role, \"slave\")\n\n\t\t// Check postgres_db group\n\t\tt.Assert(len(result[\"postgres_db\"]), 1)\n\t\tt.Assert(result[\"postgres_db\"][0].Host, \"localhost\")\n\t\tt.Assert(result[\"postgres_db\"][0].Port, \"5432\")\n\t\tt.Assert(result[\"postgres_db\"][0].Type, \"pgsql\")\n\t})\n\n\t// Test case 4: Configuration with Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\ttestNode := gdb.ConfigNode{\n\t\t\tLink: \"mysql:root:123456@tcp(127.0.0.1:3306)/test_db?charset=utf8\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"link_test\", testNode)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"link_test\"]), 1)\n\n\t\t// Check parsed values from link\n\t\tnode := result[\"link_test\"][0]\n\t\tt.Assert(node.Type, \"mysql\")\n\t\tt.Assert(node.User, \"root\")\n\t\tt.Assert(node.Pass, \"123456\")\n\t\tt.Assert(node.Host, \"127.0.0.1\")\n\t\tt.Assert(node.Port, \"3306\")\n\t\tt.Assert(node.Name, \"test_db\")\n\t\tt.Assert(node.Charset, \"utf8\")\n\t\tt.Assert(node.Protocol, \"tcp\")\n\t})\n\n\t// Test case 5: Default group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\ttestNode := gdb.ConfigNode{\n\t\t\tHost: \"localhost\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"user\",\n\t\t\tPass: \"pass\",\n\t\t\tName: \"default_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddDefaultConfigNode(testNode)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 1)\n\t\tt.Assert(result[\"default\"][0].Host, \"localhost\")\n\t\tt.Assert(result[\"default\"][0].Name, \"default_db\")\n\t})\n\n\t// Test case 6: SetConfig with multiple groups\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\ttestConfig := gdb.Config{\n\t\t\t\"group1\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tHost: \"host1\",\n\t\t\t\t\tPort: \"3306\",\n\t\t\t\t\tUser: \"user1\",\n\t\t\t\t\tPass: \"pass1\",\n\t\t\t\t\tName: \"db1\",\n\t\t\t\t\tType: \"mysql\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"group2\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tHost: \"host2\",\n\t\t\t\t\tPort: \"5432\",\n\t\t\t\t\tUser: \"user2\",\n\t\t\t\t\tPass: \"pass2\",\n\t\t\t\t\tName: \"db2\",\n\t\t\t\t\tType: \"pgsql\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHost: \"host3\",\n\t\t\t\t\tPort: \"5432\",\n\t\t\t\t\tUser: \"user3\",\n\t\t\t\t\tPass: \"pass3\",\n\t\t\t\t\tName: \"db3\",\n\t\t\t\t\tType: \"pgsql\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfig(testConfig)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(len(result[\"group1\"]), 1)\n\t\tt.Assert(len(result[\"group2\"]), 2)\n\n\t\tt.Assert(result[\"group1\"][0].Host, \"host1\")\n\t\tt.Assert(result[\"group1\"][0].Type, \"mysql\")\n\n\t\tt.Assert(result[\"group2\"][0].Host, \"host2\")\n\t\tt.Assert(result[\"group2\"][0].Type, \"pgsql\")\n\t\tt.Assert(result[\"group2\"][1].Host, \"host3\")\n\t\tt.Assert(result[\"group2\"][1].Type, \"pgsql\")\n\t})\n\n\t// Test case 7: Test return value is a copy (not reference)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\ttestNode := gdb.ConfigNode{\n\t\t\tHost: \"original_host\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"original_user\",\n\t\t\tPass: \"original_pass\",\n\t\t\tName: \"original_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"test_copy\", testNode)\n\t\tt.AssertNil(err)\n\n\t\t// Get config and modify it\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\n\t\t// Verify original values\n\t\tt.Assert(result[\"test_copy\"][0].Host, \"original_host\")\n\n\t\t// Note: GetAllConfig returns the internal config directly (not a copy)\n\t\t// This is by design for performance reasons\n\t\t// So modifying the returned config would affect the internal state\n\t\t// This test just verifies the current behavior\n\t})\n}\n\nfunc Test_SetConfig(t *testing.T) {\n\t// Test case 1: Normal configuration setting\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\ttestConfig := gdb.Config{\n\t\t\t\"group1\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\t\tPort: \"3306\",\n\t\t\t\t\tUser: \"root\",\n\t\t\t\t\tPass: \"123456\",\n\t\t\t\t\tName: \"test_db\",\n\t\t\t\t\tType: \"mysql\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"group2\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tHost: \"192.168.1.100\",\n\t\t\t\t\tPort: \"5432\",\n\t\t\t\t\tUser: \"postgres\",\n\t\t\t\t\tPass: \"password\",\n\t\t\t\t\tName: \"pg_db\",\n\t\t\t\t\tType: \"pgsql\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfig(testConfig)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[\"group1\"][0].Host, \"127.0.0.1\")\n\t\tt.Assert(result[\"group2\"][0].Type, \"pgsql\")\n\t})\n\n\t// Test case 2: Empty configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\ttestConfig := gdb.Config{}\n\t\terr := gdb.SetConfig(testConfig)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 0)\n\t})\n\n\t// Test case 3: Configuration with Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\ttestConfig := gdb.Config{\n\t\t\t\"mysql_link\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tLink: \"mysql:root:123456@tcp(127.0.0.1:3306)/test_db?charset=utf8\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfig(testConfig)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tnode := result[\"mysql_link\"][0]\n\t\tt.Assert(node.Type, \"mysql\")\n\t\tt.Assert(node.User, \"root\")\n\t\tt.Assert(node.Host, \"127.0.0.1\")\n\t\tt.Assert(node.Port, \"3306\")\n\t\tt.Assert(node.Name, \"test_db\")\n\t})\n\n\t// Test case 4: Configuration with invalid Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\ttestConfig := gdb.Config{\n\t\t\t\"invalid_link\": gdb.ConfigGroup{\n\t\t\t\t{\n\t\t\t\t\tLink: \"invalid_link_format\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfig(testConfig)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_SetConfigGroup(t *testing.T) {\n\t// Test case 1: Set new group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db1\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"master\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.2\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db2\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"slave\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfigGroup(\"test_group\", nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"test_group\"]), 2)\n\t\tt.Assert(result[\"test_group\"][0].Role, \"master\")\n\t\tt.Assert(result[\"test_group\"][1].Role, \"slave\")\n\t})\n\n\t// Test case 2: Overwrite existing group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\t// First set\n\t\tnodes1 := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"old_host\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"old_user\",\n\t\t\t\tName: \"old_db\",\n\t\t\t\tType: \"mysql\",\n\t\t\t},\n\t\t}\n\t\terr := gdb.SetConfigGroup(\"test_group\", nodes1)\n\t\tt.AssertNil(err)\n\n\t\t// Overwrite with new config\n\t\tnodes2 := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"new_host\",\n\t\t\t\tPort: \"5432\",\n\t\t\t\tUser: \"new_user\",\n\t\t\t\tName: \"new_db\",\n\t\t\t\tType: \"pgsql\",\n\t\t\t},\n\t\t}\n\t\terr = gdb.SetConfigGroup(\"test_group\", nodes2)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"test_group\"]), 1)\n\t\tt.Assert(result[\"test_group\"][0].Host, \"new_host\")\n\t\tt.Assert(result[\"test_group\"][0].Type, \"pgsql\")\n\t})\n\n\t// Test case 3: Empty group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{}\n\t\terr := gdb.SetConfigGroup(\"empty_group\", nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"empty_group\"]), 0)\n\t})\n\n\t// Test case 4: Configuration with invalid Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tLink: \"invalid_link\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfigGroup(\"invalid_group\", nodes)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_AddConfigNode(t *testing.T) {\n\t// Test case 1: Add node to new group\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"test_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"new_group\", node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"new_group\"]), 1)\n\t\tt.Assert(result[\"new_group\"][0].Host, \"127.0.0.1\")\n\t})\n\n\t// Test case 2: Add node to existing group\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\t// Add first node\n\t\tnode1 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"db1\",\n\t\t\tType: \"mysql\",\n\t\t}\n\t\terr := gdb.AddConfigNode(\"existing_group\", node1)\n\t\tt.AssertNil(err)\n\n\t\t// Add second node to same group\n\t\tnode2 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.2\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"db2\",\n\t\t\tType: \"mysql\",\n\t\t}\n\t\terr = gdb.AddConfigNode(\"existing_group\", node2)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"existing_group\"]), 2)\n\t\tt.Assert(result[\"existing_group\"][0].Name, \"db1\")\n\t\tt.Assert(result[\"existing_group\"][1].Name, \"db2\")\n\t})\n\n\t// Test case 3: Add node with Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tLink: \"mysql:root:password@tcp(192.168.1.100:3306)/mydb?charset=utf8mb4\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"link_group\", node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"link_group\"]), 1)\n\t\tt.Assert(result[\"link_group\"][0].Type, \"mysql\")\n\t\tt.Assert(result[\"link_group\"][0].Host, \"192.168.1.100\")\n\t\tt.Assert(result[\"link_group\"][0].Port, \"3306\")\n\t\tt.Assert(result[\"link_group\"][0].Name, \"mydb\")\n\t})\n\n\t// Test case 4: Add node with invalid Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tLink: \"invalid_link_format\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"invalid_group\", node)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_AddDefaultConfigNode(t *testing.T) {\n\t// Test case 1: Add node to default group\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost: \"localhost\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"root\",\n\t\t\tName: \"default_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddDefaultConfigNode(node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 1)\n\t\tt.Assert(result[\"default\"][0].Host, \"localhost\")\n\t\tt.Assert(result[\"default\"][0].Name, \"default_db\")\n\t})\n\n\t// Test case 2: Add multiple nodes to default group\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode1 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"db1\",\n\t\t\tType: \"mysql\",\n\t\t\tRole: \"master\",\n\t\t}\n\t\terr := gdb.AddDefaultConfigNode(node1)\n\t\tt.AssertNil(err)\n\n\t\tnode2 := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.2\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"db2\",\n\t\t\tType: \"mysql\",\n\t\t\tRole: \"slave\",\n\t\t}\n\t\terr = gdb.AddDefaultConfigNode(node2)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 2)\n\t\tt.Assert(result[\"default\"][0].Role, \"master\")\n\t\tt.Assert(result[\"default\"][1].Role, \"slave\")\n\t})\n\n\t// Test case 3: Add node with Link syntax to default group\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tLink: \"pgsql:postgres:password@tcp(localhost:5432)/testdb\",\n\t\t}\n\n\t\terr := gdb.AddDefaultConfigNode(node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 1)\n\t\tt.Assert(result[\"default\"][0].Type, \"pgsql\")\n\t\tt.Assert(result[\"default\"][0].User, \"postgres\")\n\t\tt.Assert(result[\"default\"][0].Host, \"localhost\")\n\t\tt.Assert(result[\"default\"][0].Port, \"5432\")\n\t\tt.Assert(result[\"default\"][0].Name, \"testdb\")\n\t})\n}\n\nfunc Test_AddDefaultConfigGroup(t *testing.T) {\n\t// Test case 1: Add multiple nodes to default group (deprecated function)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db1\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"master\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.2\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db2\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"slave\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.AddDefaultConfigGroup(nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 2)\n\t\tt.Assert(result[\"default\"][0].Role, \"master\")\n\t\tt.Assert(result[\"default\"][1].Role, \"slave\")\n\t})\n\n\t// Test case 2: Overwrite existing default group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\t// First set\n\t\tnode1 := gdb.ConfigNode{\n\t\t\tHost: \"old_host\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"old_user\",\n\t\t\tName: \"old_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\t\terr := gdb.AddDefaultConfigNode(node1)\n\t\tt.AssertNil(err)\n\n\t\t// Overwrite with new group config\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"new_host\",\n\t\t\t\tPort: \"5432\",\n\t\t\t\tUser: \"new_user\",\n\t\t\t\tName: \"new_db\",\n\t\t\t\tType: \"pgsql\",\n\t\t\t},\n\t\t}\n\t\terr = gdb.AddDefaultConfigGroup(nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 1)\n\t\tt.Assert(result[\"default\"][0].Host, \"new_host\")\n\t\tt.Assert(result[\"default\"][0].Type, \"pgsql\")\n\t})\n}\n\nfunc Test_SetDefaultConfigGroup(t *testing.T) {\n\t// Test case 1: Set default group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"192.168.1.10\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"admin\",\n\t\t\t\tPass: \"admin123\",\n\t\t\t\tName: \"main_db\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"master\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tHost: \"192.168.1.11\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"admin\",\n\t\t\t\tPass: \"admin123\",\n\t\t\t\tName: \"backup_db\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"slave\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetDefaultConfigGroup(nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 2)\n\t\tt.Assert(result[\"default\"][0].Host, \"192.168.1.10\")\n\t\tt.Assert(result[\"default\"][0].Role, \"master\")\n\t\tt.Assert(result[\"default\"][1].Host, \"192.168.1.11\")\n\t\tt.Assert(result[\"default\"][1].Role, \"slave\")\n\t})\n\n\t// Test case 2: Empty default group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config and add some initial data\n\t\tgdb.SetConfig(make(gdb.Config))\n\t\terr := gdb.AddDefaultConfigNode(gdb.ConfigNode{\n\t\t\tHost: \"temp_host\",\n\t\t\tName: \"temp_db\",\n\t\t\tType: \"mysql\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Set empty group\n\t\tnodes := gdb.ConfigGroup{}\n\t\terr = gdb.SetDefaultConfigGroup(nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 0)\n\t})\n\n\t// Test case 3: Configuration with Link syntax\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tLink: \"mysql:root:123456@tcp(localhost:3306)/test_db1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tLink: \"pgsql:postgres:password@tcp(localhost:5432)/test_db2\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetDefaultConfigGroup(nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"default\"]), 2)\n\t\tt.Assert(result[\"default\"][0].Type, \"mysql\")\n\t\tt.Assert(result[\"default\"][0].Name, \"test_db1\")\n\t\tt.Assert(result[\"default\"][1].Type, \"pgsql\")\n\t\tt.Assert(result[\"default\"][1].Name, \"test_db2\")\n\t})\n}\n\nfunc Test_GetConfig(t *testing.T) {\n\t// Test case 1: Get existing group configuration (deprecated function)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"test_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"test_group\", node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetConfig(\"test_group\")\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[0].Host, \"127.0.0.1\")\n\t\tt.Assert(result[0].Type, \"mysql\")\n\t})\n\n\t// Test case 2: Get non-existing group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tresult := gdb.GetConfig(\"non_existing_group\")\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_GetConfigGroup(t *testing.T) {\n\t// Test case 1: Get existing group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnodes := gdb.ConfigGroup{\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db1\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"master\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tHost: \"127.0.0.2\",\n\t\t\t\tPort: \"3306\",\n\t\t\t\tUser: \"root\",\n\t\t\t\tPass: \"123456\",\n\t\t\t\tName: \"db2\",\n\t\t\t\tType: \"mysql\",\n\t\t\t\tRole: \"slave\",\n\t\t\t},\n\t\t}\n\n\t\terr := gdb.SetConfigGroup(\"test_group\", nodes)\n\t\tt.AssertNil(err)\n\n\t\tresult, err := gdb.GetConfigGroup(\"test_group\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 2)\n\t\tt.Assert(result[0].Host, \"127.0.0.1\")\n\t\tt.Assert(result[0].Role, \"master\")\n\t\tt.Assert(result[1].Host, \"127.0.0.2\")\n\t\tt.Assert(result[1].Role, \"slave\")\n\t})\n\n\t// Test case 2: Get non-existing group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tresult, err := gdb.GetConfigGroup(\"non_existing_group\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\n\t// Test case 3: Get empty group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\terr := gdb.SetConfigGroup(\"empty_group\", gdb.ConfigGroup{})\n\t\tt.AssertNil(err)\n\n\t\tresult, err := gdb.GetConfigGroup(\"empty_group\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 0)\n\t})\n}\n\nfunc Test_SetDefaultGroup(t *testing.T) {\n\t// Test case 1: Set default group name\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original group and restore after test\n\t\toriginalGroup := gdb.GetDefaultGroup()\n\t\tdefer func() {\n\t\t\tgdb.SetDefaultGroup(originalGroup)\n\t\t}()\n\n\t\tgdb.SetDefaultGroup(\"custom_default\")\n\t\tresult := gdb.GetDefaultGroup()\n\t\tt.Assert(result, \"custom_default\")\n\t})\n\n\t// Test case 2: Set empty default group name\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original group and restore after test\n\t\toriginalGroup := gdb.GetDefaultGroup()\n\t\tdefer func() {\n\t\t\tgdb.SetDefaultGroup(originalGroup)\n\t\t}()\n\n\t\tgdb.SetDefaultGroup(\"\")\n\t\tresult := gdb.GetDefaultGroup()\n\t\tt.Assert(result, \"\")\n\t})\n\n\t// Test case 3: Multiple calls to SetDefaultGroup\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original group and restore after test\n\t\toriginalGroup := gdb.GetDefaultGroup()\n\t\tdefer func() {\n\t\t\tgdb.SetDefaultGroup(originalGroup)\n\t\t}()\n\n\t\tgdb.SetDefaultGroup(\"first_group\")\n\t\tresult1 := gdb.GetDefaultGroup()\n\t\tt.Assert(result1, \"first_group\")\n\n\t\tgdb.SetDefaultGroup(\"second_group\")\n\t\tresult2 := gdb.GetDefaultGroup()\n\t\tt.Assert(result2, \"second_group\")\n\t})\n}\n\nfunc Test_GetDefaultGroup(t *testing.T) {\n\t// Test case 1: Get default group name\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original group and restore after test\n\t\toriginalGroup := gdb.GetDefaultGroup()\n\t\tdefer func() {\n\t\t\tgdb.SetDefaultGroup(originalGroup)\n\t\t}()\n\n\t\t// Test with default value\n\t\tresult := gdb.GetDefaultGroup()\n\t\tt.Assert(result, \"default\")\n\t})\n\n\t// Test case 2: Get custom default group name\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original group and restore after test\n\t\toriginalGroup := gdb.GetDefaultGroup()\n\t\tdefer func() {\n\t\t\tgdb.SetDefaultGroup(originalGroup)\n\t\t}()\n\n\t\tgdb.SetDefaultGroup(\"my_custom_group\")\n\t\tresult := gdb.GetDefaultGroup()\n\t\tt.Assert(result, \"my_custom_group\")\n\t})\n}\n\nfunc Test_IsConfigured(t *testing.T) {\n\t// Test case 1: No configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config to empty\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tresult := gdb.IsConfigured()\n\t\tt.Assert(result, false)\n\t})\n\n\t// Test case 2: Has configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\tnode := gdb.ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"test_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"test_group\", node)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.IsConfigured()\n\t\tt.Assert(result, true)\n\t})\n\n\t// Test case 3: Has empty group configuration\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\terr := gdb.SetConfigGroup(\"empty_group\", gdb.ConfigGroup{})\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.IsConfigured()\n\t\tt.Assert(result, true)\n\t})\n}\n\nfunc Test_ConfigNode_ConnectionPoolSettings(t *testing.T) {\n\t// Test connection pool configuration fields\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := gdb.GetAllConfig()\n\t\tdefer func() {\n\t\t\tgdb.SetConfig(originalConfig)\n\t\t}()\n\n\t\t// Reset config\n\t\tgdb.SetConfig(make(gdb.Config))\n\n\t\ttestNode := gdb.ConfigNode{\n\t\t\tHost:             \"127.0.0.1\",\n\t\t\tPort:             \"3306\",\n\t\t\tUser:             \"root\",\n\t\t\tPass:             \"123456\",\n\t\t\tName:             \"test_db\",\n\t\t\tType:             \"mysql\",\n\t\t\tMaxIdleConnCount: 10,\n\t\t\tMaxOpenConnCount: 100,\n\t\t\tMaxConnLifeTime:  30 * time.Second,\n\t\t\tMaxIdleConnTime:  10 * time.Second,\n\t\t}\n\n\t\terr := gdb.AddConfigNode(\"pool_test\", testNode)\n\t\tt.AssertNil(err)\n\n\t\tresult := gdb.GetAllConfig()\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(result[\"pool_test\"][0].MaxIdleConnCount, 10)\n\t\tt.Assert(result[\"pool_test\"][0].MaxOpenConnCount, 100)\n\t\tt.Assert(result[\"pool_test\"][0].MaxConnLifeTime, 30*time.Second)\n\t\tt.Assert(result[\"pool_test\"][0].MaxIdleConnTime, 10*time.Second)\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_z_core_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Core_SetDebug_GetDebug(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := configs.config\n\t\tdefer func() {\n\t\t\tconfigs.config = originalConfig\n\t\t}()\n\n\t\t// Create a test configuration\n\t\tconfigs.config = make(Config)\n\t\ttestNode := ConfigNode{\n\t\t\tHost: \"127.0.0.1\",\n\t\t\tPort: \"3306\",\n\t\t\tUser: \"root\",\n\t\t\tPass: \"123456\",\n\t\t\tName: \"test_db\",\n\t\t\tType: \"mysql\",\n\t\t}\n\t\terr := AddConfigNode(\"test_group\", testNode)\n\t\tt.AssertNil(err)\n\n\t\t// Create Core instance\n\t\tnode, err := GetConfigGroup(\"test_group\")\n\t\tt.AssertNil(err)\n\t\tcore := &Core{\n\t\t\tgroup:  \"test_group\",\n\t\t\tconfig: &node[0],\n\t\t\tdebug:  gtype.NewBool(false),\n\t\t}\n\n\t\t// Test default value\n\t\tresult := core.GetDebug()\n\t\tt.Assert(result, false)\n\n\t\t// Test setting debug to true\n\t\tcore.SetDebug(true)\n\t\tresult = core.GetDebug()\n\t\tt.Assert(result, true)\n\n\t\t// Test setting debug to false\n\t\tcore.SetDebug(false)\n\t\tresult = core.GetDebug()\n\t\tt.Assert(result, false)\n\t})\n}\n\nfunc Test_Core_SetDryRun_GetDryRun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := configs.config\n\t\tdefer func() {\n\t\t\tconfigs.config = originalConfig\n\t\t}()\n\n\t\t// Create a test configuration\n\t\tconfigs.config = make(Config)\n\t\ttestNode := ConfigNode{\n\t\t\tHost:   \"127.0.0.1\",\n\t\t\tPort:   \"3306\",\n\t\t\tUser:   \"root\",\n\t\t\tPass:   \"123456\",\n\t\t\tName:   \"test_db\",\n\t\t\tType:   \"mysql\",\n\t\t\tDryRun: false,\n\t\t}\n\t\terr := AddConfigNode(\"test_group\", testNode)\n\t\tt.AssertNil(err)\n\n\t\t// Create Core instance\n\t\tnode, err := GetConfigGroup(\"test_group\")\n\t\tt.AssertNil(err)\n\t\tcore := &Core{\n\t\t\tgroup:  \"test_group\",\n\t\t\tconfig: &node[0],\n\t\t}\n\n\t\t// Test default value\n\t\tresult := core.GetDryRun()\n\t\tt.Assert(result, false)\n\n\t\t// Test setting dry run to true\n\t\tcore.SetDryRun(true)\n\t\tresult = core.GetDryRun()\n\t\tt.Assert(result, true)\n\n\t\t// Test setting dry run to false\n\t\tcore.SetDryRun(false)\n\t\tresult = core.GetDryRun()\n\t\tt.Assert(result, false)\n\t})\n}\n\nfunc Test_Core_SetLogger_GetLogger(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create Core instance\n\t\tcore := &Core{}\n\n\t\t// Test setting custom logger\n\t\tcustomLogger := glog.New()\n\t\tcore.SetLogger(customLogger)\n\t\tresult := core.GetLogger()\n\t\tt.Assert(result, customLogger)\n\n\t\t// Test setting nil logger\n\t\tcore.SetLogger(nil)\n\t\tresult = core.GetLogger()\n\t\tt.Assert(result, nil)\n\t})\n}\n\nfunc Test_Core_SetMaxConnections(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create Core instance\n\t\tcore := &Core{}\n\n\t\t// Test SetMaxIdleConnCount\n\t\tcore.SetMaxIdleConnCount(10)\n\t\tt.Assert(core.dynamicConfig.MaxIdleConnCount, 10)\n\n\t\t// Test SetMaxOpenConnCount\n\t\tcore.SetMaxOpenConnCount(20)\n\t\tt.Assert(core.dynamicConfig.MaxOpenConnCount, 20)\n\n\t\t// Test SetMaxConnLifeTime\n\t\ttestDuration := time.Hour\n\t\tcore.SetMaxConnLifeTime(testDuration)\n\t\tt.Assert(core.dynamicConfig.MaxConnLifeTime, testDuration)\n\n\t\t// Test SetMaxIdleConnTime\n\t\tidleTimeDuration := 30 * time.Minute\n\t\tcore.SetMaxIdleConnTime(idleTimeDuration)\n\t\tt.Assert(core.dynamicConfig.MaxIdleConnTime, idleTimeDuration)\n\t})\n}\n\nfunc Test_Core_GetCache(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create Core instance\n\t\tcore := &Core{}\n\n\t\tcache := core.GetCache()\n\t\t// Cache might be nil if not initialized, so we just test that the call doesn't panic\n\t\t_ = cache\n\t})\n}\n\nfunc Test_Core_GetGroup(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create Core instance\n\t\tcore := &Core{\n\t\t\tgroup: \"test_group\",\n\t\t}\n\n\t\tgroup := core.GetGroup()\n\t\tt.Assert(group, \"test_group\")\n\t})\n}\n\nfunc Test_Core_GetPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save original config and restore after test\n\t\toriginalConfig := configs.config\n\t\tdefer func() {\n\t\t\tconfigs.config = originalConfig\n\t\t}()\n\n\t\t// Create a test configuration\n\t\tconfigs.config = make(Config)\n\t\ttestNode := ConfigNode{\n\t\t\tHost:   \"127.0.0.1\",\n\t\t\tPort:   \"3306\",\n\t\t\tUser:   \"root\",\n\t\t\tPass:   \"123456\",\n\t\t\tName:   \"test_db\",\n\t\t\tType:   \"mysql\",\n\t\t\tPrefix: \"gf_\",\n\t\t}\n\t\terr := AddConfigNode(\"test_group\", testNode)\n\t\tt.AssertNil(err)\n\n\t\t// Create Core instance\n\t\tnode, err := GetConfigGroup(\"test_group\")\n\t\tt.AssertNil(err)\n\t\tcore := &Core{\n\t\t\tgroup:  \"test_group\",\n\t\t\tconfig: &node[0],\n\t\t}\n\n\t\tprefix := core.GetPrefix()\n\t\tt.Assert(prefix, \"gf_\")\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb_test\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\n// ExampleDB_Transaction demonstrates the usage of transaction in gdb.\nfunc ExampleDB_Transaction() {\n\tg.DB().Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {\n\t\t// user\n\t\tresult, err := tx.Insert(\"user\", g.Map{\n\t\t\t\"passport\": \"john\",\n\t\t\t\"password\": \"12345678\",\n\t\t\t\"nickname\": \"JohnGuo\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// user_detail\n\t\tid, err := result.LastInsertId()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = tx.Insert(\"user_detail\", g.Map{\n\t\t\t\"uid\":       id,\n\t\t\t\"site\":      \"https://johng.cn\",\n\t\t\t\"true_name\": \"GuoQiang\",\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_z_mysql_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nfunc Test_GetConverter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := GetConverter()\n\t\ts, err := c.String(1)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(s, \"1\")\n\t})\n}\n\nfunc Test_HookSelect_Regex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr              error\n\t\t\ttoBeCommittedSql = `select * from \"user\" where 1=1`\n\t\t)\n\t\ttoBeCommittedSql, err = gregex.ReplaceStringFuncMatch(\n\t\t\t`(?i) FROM ([\\S]+)`,\n\t\t\ttoBeCommittedSql,\n\t\t\tfunc(match []string) string {\n\n\t\t\t\treturn fmt.Sprintf(` FROM \"%s\"`, \"user_1\")\n\t\t\t},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(toBeCommittedSql, `select * FROM \"user_1\" where 1=1`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr              error\n\t\t\ttoBeCommittedSql = `select * from user`\n\t\t)\n\t\ttoBeCommittedSql, err = gregex.ReplaceStringFuncMatch(\n\t\t\t`(?i) FROM ([\\S]+)`,\n\t\t\ttoBeCommittedSql,\n\t\t\tfunc(match []string) string {\n\t\t\t\treturn fmt.Sprintf(` FROM %s`, \"user_1\")\n\t\t\t},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(toBeCommittedSql, `select * FROM user_1`)\n\t})\n}\n\nfunc Test_parseConfigNodeLink_WithType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)/khaos_oss?loc=Local&parseTime=true&charset=latin`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, `khaos_oss`)\n\t\tt.Assert(newNode.Extra, `loc=Local&parseTime=true&charset=latin`)\n\t\tt.Assert(newNode.Charset, `latin`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)/khaos_oss?`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, `khaos_oss`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)/khaos_oss`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, `khaos_oss`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\t// empty database preselect.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)/?loc=Local&parseTime=true&charset=latin`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, ``)\n\t\tt.Assert(newNode.Extra, `loc=Local&parseTime=true&charset=latin`)\n\t\tt.Assert(newNode.Charset, `latin`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)?loc=Local&parseTime=true&charset=latin`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, ``)\n\t\tt.Assert(newNode.Extra, `loc=Local&parseTime=true&charset=latin`)\n\t\tt.Assert(newNode.Charset, `latin`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)/`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, ``)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@tcp(9.135.69.119:3306)`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, ``)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\t// udp.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `mysql:root:CxzhD*624:27jh@udp(9.135.69.119:3306)`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, `9.135.69.119`)\n\t\tt.Assert(newNode.Port, `3306`)\n\t\tt.Assert(newNode.Name, ``)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `udp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `sqlite:root:CxzhD*624:27jh@file(/var/data/db.sqlite3)?local=Local&parseTime=true`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `sqlite`)\n\t\tt.Assert(newNode.User, `root`)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:27jh`)\n\t\tt.Assert(newNode.Host, ``)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `/var/data/db.sqlite3`)\n\t\tt.Assert(newNode.Extra, `local=Local&parseTime=true`)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `file`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `sqlite::CxzhD*624:2@7jh@file(/var/data/db.sqlite3)`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `sqlite`)\n\t\tt.Assert(newNode.User, ``)\n\t\tt.Assert(newNode.Pass, `CxzhD*624:2@7jh`)\n\t\tt.Assert(newNode.Host, ``)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `/var/data/db.sqlite3`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `file`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `sqlite::@file(/var/data/db.sqlite3)`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `sqlite`)\n\t\tt.Assert(newNode.User, ``)\n\t\tt.Assert(newNode.Pass, ``)\n\t\tt.Assert(newNode.Host, ``)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `/var/data/db.sqlite3`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `file`)\n\t})\n\t// #3146\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: `pgsql:BASIC$xxxx:123456@tcp(xxxx.hologres.aliyuncs.com:80)/xxx`,\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `pgsql`)\n\t\tt.Assert(newNode.User, `BASIC$xxxx`)\n\t\tt.Assert(newNode.Pass, `123456`)\n\t\tt.Assert(newNode.Host, `xxxx.hologres.aliyuncs.com`)\n\t\tt.Assert(newNode.Port, `80`)\n\t\tt.Assert(newNode.Name, `xxx`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, defaultCharset)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\t// https://github.com/gogf/gf/issues/3755\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: \"mysql:user:pwd@tcp(rdsid.mysql.rds.aliyuncs.com)/dbname?charset=utf8&loc=Local\",\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `user`)\n\t\tt.Assert(newNode.Pass, `pwd`)\n\t\tt.Assert(newNode.Host, `rdsid.mysql.rds.aliyuncs.com`)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `dbname`)\n\t\tt.Assert(newNode.Extra, `charset=utf8&loc=Local`)\n\t\tt.Assert(newNode.Charset, `utf8`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\t// https://github.com/gogf/gf/issues/3862\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: \"mysql:username:password@unix(/tmp/mysql.sock)/dbname\",\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `username`)\n\t\tt.Assert(newNode.Pass, `password`)\n\t\tt.Assert(newNode.Host, `/tmp/mysql.sock`)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `dbname`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, `utf8`)\n\t\tt.Assert(newNode.Protocol, `unix`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tType: \"mysql\",\n\t\t\tLink: \"username:password@unix(/tmp/mysql.sock)/dbname\",\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `mysql`)\n\t\tt.Assert(newNode.User, `username`)\n\t\tt.Assert(newNode.Pass, `password`)\n\t\tt.Assert(newNode.Host, `/tmp/mysql.sock`)\n\t\tt.Assert(newNode.Port, ``)\n\t\tt.Assert(newNode.Name, `dbname`)\n\t\tt.Assert(newNode.Extra, ``)\n\t\tt.Assert(newNode.Charset, `utf8`)\n\t\tt.Assert(newNode.Protocol, `unix`)\n\t})\n\t// https://github.com/gogf/gf/issues/4059\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tLink: \"tidb:2hcmRccccxxx9Fizz.root:wP3xxxxPIDc@tcp(xxxx.tidbcloud.com:4000)/db_name?tls=true\",\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `tidb`)\n\t\tt.Assert(newNode.User, `2hcmRccccxxx9Fizz.root`)\n\t\tt.Assert(newNode.Pass, `wP3xxxxPIDc`)\n\t\tt.Assert(newNode.Host, `xxxx.tidbcloud.com`)\n\t\tt.Assert(newNode.Port, `4000`)\n\t\tt.Assert(newNode.Name, `db_name`)\n\t\tt.Assert(newNode.Extra, `tls=true`)\n\t\tt.Assert(newNode.Charset, `utf8`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnode := &ConfigNode{\n\t\t\tType: \"tidb\",\n\t\t\tLink: \"2hcmRccccxxx9Fizz.root:wP3xxxxPIDc@tcp(xxxx.tidbcloud.com:4000)/db_name?tls=true\",\n\t\t}\n\t\tnewNode, err := parseConfigNodeLink(node)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newNode.Type, `tidb`)\n\t\tt.Assert(newNode.User, `2hcmRccccxxx9Fizz.root`)\n\t\tt.Assert(newNode.Pass, `wP3xxxxPIDc`)\n\t\tt.Assert(newNode.Host, `xxxx.tidbcloud.com`)\n\t\tt.Assert(newNode.Port, `4000`)\n\t\tt.Assert(newNode.Name, `db_name`)\n\t\tt.Assert(newNode.Extra, `tls=true`)\n\t\tt.Assert(newNode.Charset, `utf8`)\n\t\tt.Assert(newNode.Protocol, `tcp`)\n\t})\n}\n\nfunc Test_Func_doQuoteWord(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := map[string]string{\n\t\t\t\"user\":                   \"`user`\",\n\t\t\t\"user u\":                 \"user u\",\n\t\t\t\"user_detail\":            \"`user_detail`\",\n\t\t\t\"user,user_detail\":       \"user,user_detail\",\n\t\t\t\"user u, user_detail ut\": \"user u, user_detail ut\",\n\t\t\t\"u.id asc\":               \"u.id asc\",\n\t\t\t\"u.id asc, ut.uid desc\":  \"u.id asc, ut.uid desc\",\n\t\t}\n\t\tfor k, v := range array {\n\t\t\tt.Assert(doQuoteWord(k, \"`\", \"`\"), v)\n\t\t}\n\t})\n}\n\nfunc Test_Func_doQuoteString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := map[string]string{\n\t\t\t\"user\":                             \"`user`\",\n\t\t\t\"user u\":                           \"`user` u\",\n\t\t\t\"user,user_detail\":                 \"`user`,`user_detail`\",\n\t\t\t\"user u, user_detail ut\":           \"`user` u,`user_detail` ut\",\n\t\t\t\"u.id, u.name, u.age\":              \"`u`.`id`,`u`.`name`,`u`.`age`\",\n\t\t\t\"u.id asc\":                         \"`u`.`id` asc\",\n\t\t\t\"u.id asc, ut.uid desc\":            \"`u`.`id` asc,`ut`.`uid` desc\",\n\t\t\t\"user.user u, user.user_detail ut\": \"`user`.`user` u,`user`.`user_detail` ut\",\n\t\t\t// mssql global schema access with double dots.\n\t\t\t\"user..user u, user.user_detail ut\": \"`user`..`user` u,`user`.`user_detail` ut\",\n\t\t}\n\t\tfor k, v := range array {\n\t\t\tt.Assert(doQuoteString(k, \"`\", \"`\"), v)\n\t\t}\n\t})\n}\n\nfunc Test_Func_addTablePrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := \"\"\n\t\tarray := map[string]string{\n\t\t\t\"user\":                         \"`user`\",\n\t\t\t\"user u\":                       \"`user` u\",\n\t\t\t\"user as u\":                    \"`user` as u\",\n\t\t\t\"user,user_detail\":             \"`user`,`user_detail`\",\n\t\t\t\"user u, user_detail ut\":       \"`user` u,`user_detail` ut\",\n\t\t\t\"`user`.user_detail\":           \"`user`.`user_detail`\",\n\t\t\t\"`user`.`user_detail`\":         \"`user`.`user_detail`\",\n\t\t\t\"user as u, user_detail as ut\": \"`user` as u,`user_detail` as ut\",\n\t\t\t\"UserCenter.user as u, UserCenter.user_detail as ut\": \"`UserCenter`.`user` as u,`UserCenter`.`user_detail` as ut\",\n\t\t\t// mssql global schema access with double dots.\n\t\t\t\"UserCenter..user as u, user_detail as ut\": \"`UserCenter`..`user` as u,`user_detail` as ut\",\n\t\t}\n\t\tfor k, v := range array {\n\t\t\tt.Assert(doQuoteTableName(k, prefix, \"`\", \"`\"), v)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := \"gf_\"\n\t\tarray := map[string]string{\n\t\t\t\"user\":                         \"`gf_user`\",\n\t\t\t\"user u\":                       \"`gf_user` u\",\n\t\t\t\"user as u\":                    \"`gf_user` as u\",\n\t\t\t\"user,user_detail\":             \"`gf_user`,`gf_user_detail`\",\n\t\t\t\"user u, user_detail ut\":       \"`gf_user` u,`gf_user_detail` ut\",\n\t\t\t\"`user`.user_detail\":           \"`user`.`gf_user_detail`\",\n\t\t\t\"`user`.`user_detail`\":         \"`user`.`gf_user_detail`\",\n\t\t\t\"user as u, user_detail as ut\": \"`gf_user` as u,`gf_user_detail` as ut\",\n\t\t\t\"UserCenter.user as u, UserCenter.user_detail as ut\": \"`UserCenter`.`gf_user` as u,`UserCenter`.`gf_user_detail` as ut\",\n\t\t\t// mssql global schema access with double dots.\n\t\t\t\"UserCenter..user as u, user_detail as ut\": \"`UserCenter`..`gf_user` as u,`gf_user_detail` as ut\",\n\t\t}\n\t\tfor k, v := range array {\n\t\t\tt.Assert(doQuoteTableName(k, prefix, \"`\", \"`\"), v)\n\t\t}\n\t})\n}\n\nfunc Test_isSubQuery(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(isSubQuery(\"user\"), false)\n\t\tt.Assert(isSubQuery(\"user.uid\"), false)\n\t\tt.Assert(isSubQuery(\"u, user.uid\"), false)\n\t\tt.Assert(isSubQuery(\"select 1\"), true)\n\t})\n}\n"
  },
  {
    "path": "database/gdb/gdb_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// Test_Issue4699 tests negative values for Limit/Page/Offset should be treated as zero.\n// See https://github.com/gogf/gf/issues/4699\nfunc Test_Issue4699(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a base model for testing\n\t\tm := &Model{}\n\n\t\t// Test Limit with single negative parameter\n\t\tm1 := m.Limit(-1)\n\t\tt.AssertEQ(m1.limit, 0)\n\n\t\t// Test Limit with two parameters (start, limit) where both are negative\n\t\tm2 := m.Limit(-10, -5)\n\t\tt.AssertEQ(m2.start, 0)\n\t\tt.AssertEQ(m2.limit, 0)\n\n\t\t// Test Limit with mixed parameters (negative start, positive limit)\n\t\tm3 := m.Limit(-10, 5)\n\t\tt.AssertEQ(m3.start, 0)\n\t\tt.AssertEQ(m3.limit, 5)\n\n\t\t// Test Page with negative limit\n\t\tm4 := m.Page(1, -10)\n\t\tt.AssertEQ(m4.start, 0)\n\t\tt.AssertEQ(m4.limit, 0)\n\n\t\t// Test Page with negative limit on page 2\n\t\tm5 := m.Page(2, -10)\n\t\tt.AssertEQ(m5.start, 0) // (2-1) * 0 = 0\n\t\tt.AssertEQ(m5.limit, 0)\n\n\t\t// Test Offset with negative value\n\t\tm6 := m.Offset(-5)\n\t\tt.AssertEQ(m6.offset, 0)\n\n\t\t// Test Offset with positive value (sanity check)\n\t\tm7 := m.Offset(10)\n\t\tt.AssertEQ(m7.offset, 10)\n\t})\n}\n"
  },
  {
    "path": "database/gdb/testdata/issue1380.sql",
    "content": "CREATE TABLE `jfy_gift`  (\n`id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT,\n`gift_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品名称',\n`at_least_recharge_count` int(0) UNSIGNED NOT NULL DEFAULT 1 COMMENT '最少兑换数量',\n`comments` json NOT NULL COMMENT '礼品留言',\n`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品详情',\n`cost_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '成本价',\n`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '封面',\n`covers` json NOT NULL COMMENT '礼品图片库',\n`description` varchar(62) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '礼品备注',\n`express_type` json NOT NULL COMMENT '配送方式',\n`gift_type` int(0) NOT NULL COMMENT '礼品类型：1：实物；2：虚拟；3：优惠券；4：积分券',\n`has_props` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否有多个属性',\n`is_limit_sell` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否限购',\n`limit_customer_tags` json NOT NULL COMMENT '语序购买的会员标签',\n`limit_sell_custom` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启允许购买的会员标签',\n`limit_sell_cycle` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '限购周期',\n`limit_sell_cycle_count` int(0) NOT NULL COMMENT '限购期内允许购买的数量',\n`limit_sell_type` tinyint(0) NOT NULL COMMENT '限购类型',\n`market_price` decimal(10, 2) NOT NULL COMMENT '市场价',\n`out_sn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内部编码',\n`props` json NOT NULL COMMENT '规格',\n`skus` json NOT NULL COMMENT 'SKU',\n`score_price` decimal(10, 2) NOT NULL COMMENT '兑换所需积分',\n`stock` int(0) NOT NULL COMMENT '库存',\n`create_at` datetime(0) NOT NULL COMMENT '创建日期',\n`store_id` int(0) NOT NULL COMMENT '所属商城',\n`status` int(0) UNSIGNED NULL DEFAULT 1 COMMENT '1：下架；20：审核中；30：复审中；99：上架',\n`view_count` int(0) NOT NULL DEFAULT 0 COMMENT '访问量',\n`sell_count` int(0) NULL DEFAULT 0 COMMENT '销量',\nPRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n\nINSERT INTO `jfy_gift` VALUES (17, 'GIFT', 1, '[{\\\"name\\\": \\\"身份证\\\", \\\"field\\\": \\\"idcard\\\", \\\"required\\\": false}, {\\\"name\\\": \\\"留言2\\\", \\\"field\\\": \\\"text\\\", \\\"required\\\": false}]', '<p>礼品详情</p>', 0.00, '', '{\\\"list\\\": [{\\\"uid\\\": \\\"vc-upload-1629292486099-3\\\", \\\"url\\\": \\\"https://cdn.taobao.com/sULsYiwaOPjsKGoBXwKtuewPzACpBDfQ.jpg\\\", \\\"name\\\": \\\"O1CN01OH6PIP1Oc5ot06U17_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}, {\\\"uid\\\": \\\"vc-upload-1629292486099-4\\\", \\\"url\\\": \\\"https://cdn.taobao.com/lqLHDcrFTgNvlWyXfLYZwmsrODzIBtFH.jpg\\\", \\\"name\\\": \\\"O1CN018hBckI1Oc5ouc8ppl_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}, {\\\"uid\\\": \\\"vc-upload-1629292486099-5\\\", \\\"url\\\": \\\"https://cdn.taobao.com/pvqyutXckICmHhbPBQtrVLHuMlXuGxUg.jpg\\\", \\\"name\\\": \\\"O1CN0185Ubp91Oc5osQTTcc_!!922361725.jpg\\\", \\\"status\\\": \\\"done\\\"}]}', '支持个性定制的父亲节老师长辈的专属礼物', '[\\\"快递包邮\\\", \\\"同城配送\\\"]', 1, 0, 0, '[]', 0, 'day', 0, 1, 0.00, '259402', '[{\\\"name\\\": \\\"颜色\\\", \\\"values\\\": [\\\"红色\\\", \\\"蓝色\\\"]}]', '[{\\\"name\\\": \\\"red\\\", \\\"stock\\\": 10, \\\"gift_id\\\": 1, \\\"cost_price\\\": 80, \\\"score_price\\\": 188, \\\"market_price\\\": 388}, {\\\"name\\\": \\\"blue\\\", \\\"stock\\\": 100, \\\"gift_id\\\": 2, \\\"cost_price\\\": 81, \\\"score_price\\\": 200, \\\"market_price\\\": 288}]', 10.00, 0, '2021-08-18 21:26:13', 100004, 99, 0, 0);\n"
  },
  {
    "path": "database/gdb/testdata/issue1401.sql",
    "content": "-- ----------------------------\n-- Table structure for parcel_items\n-- ----------------------------\nDROP TABLE IF EXISTS `parcel_items`;\nCREATE TABLE `parcel_items`  (\n    `id` int(11) NOT NULL,\n    `parcel_id` int(11) NULL DEFAULT NULL,\n    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcel_items\n-- ----------------------------\nINSERT INTO `parcel_items` VALUES (1, 1, '新品');\nINSERT INTO `parcel_items` VALUES (2, 3, '新品2');\n\n-- ----------------------------\n-- Table structure for parcels\n-- ----------------------------\nDROP TABLE IF EXISTS `parcels`;\nCREATE TABLE `parcels`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcels\n-- ----------------------------\nINSERT INTO `parcels` VALUES (1);\nINSERT INTO `parcels` VALUES (2);\nINSERT INTO `parcels` VALUES (3);"
  },
  {
    "path": "database/gdb/testdata/issue1412.sql",
    "content": "-- ----------------------------\n-- Table structure for items\n-- ----------------------------\nCREATE TABLE `items`  (\n    `id` int(11) NOT NULL,\n    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of items\n-- ----------------------------\nINSERT INTO `items` VALUES (1, '金秋产品1');\nINSERT INTO `items` VALUES (2, '金秋产品2');\n\n-- ----------------------------\n-- Table structure for parcels\n-- ----------------------------\nCREATE TABLE `parcels`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `item_id` int(11) NULL DEFAULT NULL,\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of parcels\n-- ----------------------------\nINSERT INTO `parcels` VALUES (1, 1);\nINSERT INTO `parcels` VALUES (2, 2);\nINSERT INTO `parcels` VALUES (3, 0);"
  },
  {
    "path": "database/gdb/testdata/reservedwords_table_tpl.sql",
    "content": "CREATE TABLE %s (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `key` varchar(45) DEFAULT NULL,\n  `category_id` int(10) unsigned NOT NULL,\n  `user_id` int(10) unsigned NOT NULL,\n  `title` varchar(255) NOT NULL,\n  `content` mediumtext NOT NULL,\n  `sort` int(10) unsigned DEFAULT '0',\n  `brief` varchar(255) DEFAULT NULL,\n  `thumb` varchar(255) DEFAULT NULL,\n  `tags` varchar(900) DEFAULT NULL,\n  `referer` varchar(255) DEFAULT NULL,\n  `status` smallint(5) unsigned DEFAULT '0',\n  `view_count` int(10) unsigned DEFAULT '0',\n  `zan_count` int(10) unsigned DEFAULT NULL,\n  `cai_count` int(10) unsigned DEFAULT NULL,\n  `created_at` datetime DEFAULT NULL,\n  `updated_at` datetime DEFAULT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;"
  },
  {
    "path": "database/gdb/testdata/with_multiple_depends.sql",
    "content": "\nCREATE TABLE `table_a`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_a` VALUES (1, 'table_a_test1');\nINSERT INTO `table_a` VALUES (2, 'table_a_test2');\n\nCREATE TABLE `table_b`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_a_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_b` VALUES (10, 1, 'table_b_test1');\nINSERT INTO `table_b` VALUES (20, 2, 'table_b_test2');\nINSERT INTO `table_b` VALUES (30, 1, 'table_b_test3');\nINSERT INTO `table_b` VALUES (40, 2, 'table_b_test4');\n\nCREATE TABLE `table_c`  (\n    `id` int(11) NOT NULL AUTO_INCREMENT,\n    `table_b_id` int(11) NOT NULL,\n    `alias` varchar(255) NULL DEFAULT '',\n    PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB;\n\nINSERT INTO `table_c` VALUES (100, 10, 'table_c_test1');\nINSERT INTO `table_c` VALUES (200, 10, 'table_c_test2');\nINSERT INTO `table_c` VALUES (300, 20, 'table_c_test3');\nINSERT INTO `table_c` VALUES (400, 30, 'table_c_test4');"
  },
  {
    "path": "database/gredis/gredis.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gredis provides convenient client for redis server.\n//\n// Redis Client.\n//\n// Redis Commands Official: https://redis.io/commands\n//\n// Redis Chinese Documentation: http://redisdoc.com/\npackage gredis\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// AdapterFunc is the function creating redis adapter.\ntype AdapterFunc func(config *Config) Adapter\n\nvar (\n\t// defaultAdapterFunc is the default adapter function creating redis adapter.\n\tdefaultAdapterFunc AdapterFunc = func(config *Config) Adapter {\n\t\treturn nil\n\t}\n)\n\n// New creates and returns a redis client.\n// It creates a default redis adapter of go-redis.\nfunc New(config ...*Config) (*Redis, error) {\n\tvar (\n\t\tusedConfig  *Config\n\t\tusedAdapter Adapter\n\t)\n\tif len(config) > 0 && config[0] != nil {\n\t\t// Redis client with go redis implements adapter from given configuration.\n\t\tusedConfig = config[0]\n\t\tusedAdapter = defaultAdapterFunc(config[0])\n\t} else if configFromGlobal, ok := GetConfig(); ok {\n\t\t// Redis client with go redis implements adapter from package configuration.\n\t\tusedConfig = configFromGlobal\n\t\tusedAdapter = defaultAdapterFunc(configFromGlobal)\n\t}\n\tif usedConfig == nil {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeInvalidConfiguration,\n\t\t\t`no configuration found for creating Redis client`,\n\t\t)\n\t}\n\tif usedAdapter == nil {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeNecessaryPackageNotImport,\n\t\t\terrorNilAdapter,\n\t\t)\n\t}\n\tredis := &Redis{\n\t\tconfig:       usedConfig,\n\t\tlocalAdapter: usedAdapter,\n\t}\n\treturn redis.initGroup(), nil\n}\n\n// NewWithAdapter creates and returns a redis client with given adapter.\nfunc NewWithAdapter(adapter Adapter) (*Redis, error) {\n\tif adapter == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `adapter cannot be nil`)\n\t}\n\tredis := &Redis{localAdapter: adapter}\n\treturn redis.initGroup(), nil\n}\n\n// RegisterAdapterFunc registers default function creating redis adapter.\nfunc RegisterAdapterFunc(adapterFunc AdapterFunc) {\n\tdefaultAdapterFunc = adapterFunc\n}\n"
  },
  {
    "path": "database/gredis/gredis_adapter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// Adapter is an interface for universal redis operations.\ntype Adapter interface {\n\tAdapterGroup\n\tAdapterOperation\n}\n\n// AdapterGroup is an interface managing group operations for redis.\ntype AdapterGroup interface {\n\tGroupGeneric() IGroupGeneric\n\tGroupHash() IGroupHash\n\tGroupList() IGroupList\n\tGroupPubSub() IGroupPubSub\n\tGroupScript() IGroupScript\n\tGroupSet() IGroupSet\n\tGroupSortedSet() IGroupSortedSet\n\tGroupString() IGroupString\n}\n\n// RedisRawClient is a type alias for any, representing the raw underlying redis client.\n// Implementations should return their concrete client type as this interface.\ntype RedisRawClient any\n\n// AdapterOperation is the core operation functions for redis.\n// These functions can be easily overwritten by custom implements.\ntype AdapterOperation interface {\n\t// Do send a command to the server and returns the received reply.\n\t// It uses json.Marshal for struct/slice/map type values before committing them to redis.\n\tDo(ctx context.Context, command string, args ...any) (*gvar.Var, error)\n\n\t// Conn retrieves and returns a connection object for continuous operations.\n\t// Note that you should call Close function manually if you do not use this connection any further.\n\tConn(ctx context.Context) (conn Conn, err error)\n\n\t// Close closes current redis client, closes its connection pool and releases all its related resources.\n\tClose(ctx context.Context) (err error)\n\n\t// Client returns the underlying redis client instance.\n\t// This method provides access to the raw redis client for advanced operations\n\t// that are not covered by the standard redis adapter interface.\n\tClient() RedisRawClient\n}\n\n// Conn is an interface of a connection from universal redis client.\ntype Conn interface {\n\tConnCommand\n\n\t// Do send a command to the server and returns the received reply.\n\t// It uses json.Marshal for struct/slice/map type values before committing them to redis.\n\tDo(ctx context.Context, command string, args ...any) (result *gvar.Var, err error)\n\n\t// Close puts the connection back to connection pool.\n\tClose(ctx context.Context) (err error)\n}\n\n// ConnCommand is an interface managing some operations bound to certain connection.\ntype ConnCommand interface {\n\t// Subscribe subscribes the client to the specified channels.\n\t// https://redis.io/commands/subscribe/\n\tSubscribe(ctx context.Context, channel string, channels ...string) ([]*Subscription, error)\n\n\t// PSubscribe subscribes the client to the given patterns.\n\t//\n\t// Supported glob-style patterns:\n\t// - h?llo subscribes to hello, hallo and hxllo\n\t// - h*llo subscribes to hllo and heeeello\n\t// - h[ae]llo subscribes to hello and hallo, but not hillo\n\t//\n\t// Use \\ to escape special characters if you want to match them verbatim.\n\t//\n\t// https://redis.io/commands/psubscribe/\n\tPSubscribe(ctx context.Context, pattern string, patterns ...string) ([]*Subscription, error)\n\n\t// ReceiveMessage receives a single message of subscription from the Redis server.\n\tReceiveMessage(ctx context.Context) (*Message, error)\n\n\t// Receive receives a single reply as gvar.Var from the Redis server.\n\tReceive(ctx context.Context) (result *gvar.Var, err error)\n}\n"
  },
  {
    "path": "database/gredis/gredis_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Config is redis configuration.\ntype Config struct {\n\t// Address It supports single and cluster redis server. Multiple addresses joined with char ','. Eg: 192.168.1.1:6379, 192.168.1.2:6379.\n\tAddress         string        `json:\"address\"`\n\tDb              int           `json:\"db\"`              // Redis db.\n\tUser            string        `json:\"user\"`            // Username for AUTH.\n\tPass            string        `json:\"pass\"`            // Password for AUTH.\n\tSentinelUser    string        `json:\"sentinel_user\"`   // Username for sentinel AUTH.\n\tSentinelPass    string        `json:\"sentinel_pass\"`   // Password for sentinel AUTH.\n\tMinIdle         int           `json:\"minIdle\"`         // Minimum number of connections allowed to be idle (default is 0)\n\tMaxIdle         int           `json:\"maxIdle\"`         // Maximum number of connections allowed to be idle (default is 10)\n\tMaxActive       int           `json:\"maxActive\"`       // Maximum number of connections limit (default is 0 means no limit).\n\tMaxConnLifetime time.Duration `json:\"maxConnLifetime\"` // Maximum lifetime of the connection (default is 30 seconds, not allowed to be set to 0)\n\tIdleTimeout     time.Duration `json:\"idleTimeout\"`     // Maximum idle time for connection (default is 10 seconds, not allowed to be set to 0)\n\tWaitTimeout     time.Duration `json:\"waitTimeout\"`     // Timed out duration waiting to get a connection from the connection pool.\n\tDialTimeout     time.Duration `json:\"dialTimeout\"`     // Dial connection timeout for TCP.\n\tReadTimeout     time.Duration `json:\"readTimeout\"`     // Read timeout for TCP. DO NOT set it if not necessary.\n\tWriteTimeout    time.Duration `json:\"writeTimeout\"`    // Write timeout for TCP.\n\tMasterName      string        `json:\"masterName\"`      // Used in Redis Sentinel mode.\n\tTLS             bool          `json:\"tls\"`             // Specifies whether TLS should be used when connecting to the server.\n\tTLSSkipVerify   bool          `json:\"tlsSkipVerify\"`   // Disables server name verification when connecting over TLS.\n\tTLSConfig       *tls.Config   `json:\"-\"`               // TLS Config to use. When set TLS will be negotiated.\n\tSlaveOnly       bool          `json:\"slaveOnly\"`       // Route all commands to slave read-only nodes.\n\tCluster         bool          `json:\"cluster\"`         // Specifies whether cluster mode be used.\n\tProtocol        int           `json:\"protocol\"`        // Specifies the RESP version (Protocol 2 or 3.)\n}\n\nconst (\n\tDefaultGroupName = \"default\" // Default configuration group name.\n)\n\nvar (\n\t// configChecker checks whether the *Config is nil.\n\tconfigChecker = func(v *Config) bool { return v == nil }\n\t// Configuration groups.\n\tlocalConfigMap = gmap.NewKVMapWithChecker[string, *Config](configChecker, true)\n)\n\n// SetConfig sets the global configuration for specified group.\n// If `name` is not passed, it sets configuration for the default group name.\nfunc SetConfig(config *Config, name ...string) {\n\tgroup := DefaultGroupName\n\tif len(name) > 0 {\n\t\tgroup = name[0]\n\t}\n\tlocalConfigMap.Set(group, config)\n\n\tintlog.Printf(context.TODO(), `SetConfig for group \"%s\": %+v`, group, config)\n}\n\n// SetConfigByMap sets the global configuration for specified group with map.\n// If `name` is not passed, it sets configuration for the default group name.\nfunc SetConfigByMap(m map[string]any, name ...string) error {\n\tgroup := DefaultGroupName\n\tif len(name) > 0 {\n\t\tgroup = name[0]\n\t}\n\tconfig, err := ConfigFromMap(m)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlocalConfigMap.Set(group, config)\n\treturn nil\n}\n\n// ConfigFromMap parses and returns config from given map.\nfunc ConfigFromMap(m map[string]any) (config *Config, err error) {\n\tconfig = &Config{}\n\tif err = gconv.Scan(m, config); err != nil {\n\t\terr = gerror.NewCodef(gcode.CodeInvalidConfiguration, `invalid redis configuration: %#v`, m)\n\t}\n\tif config.DialTimeout < time.Second {\n\t\tconfig.DialTimeout = config.DialTimeout * time.Second\n\t}\n\tif config.WaitTimeout < time.Second {\n\t\tconfig.WaitTimeout = config.WaitTimeout * time.Second\n\t}\n\tif config.WriteTimeout < time.Second {\n\t\tconfig.WriteTimeout = config.WriteTimeout * time.Second\n\t}\n\tif config.ReadTimeout < time.Second {\n\t\tconfig.ReadTimeout = config.ReadTimeout * time.Second\n\t}\n\tif config.IdleTimeout < time.Second {\n\t\tconfig.IdleTimeout = config.IdleTimeout * time.Second\n\t}\n\tif config.MaxConnLifetime < time.Second {\n\t\tconfig.MaxConnLifetime = config.MaxConnLifetime * time.Second\n\t}\n\tif config.Protocol != 2 && config.Protocol != 3 {\n\t\tconfig.Protocol = 3\n\t}\n\treturn\n}\n\n// GetConfig returns the global configuration with specified group name.\n// If `name` is not passed, it returns configuration of the default group name.\nfunc GetConfig(name ...string) (config *Config, ok bool) {\n\tgroup := DefaultGroupName\n\tif len(name) > 0 {\n\t\tgroup = name[0]\n\t}\n\tif v := localConfigMap.Get(group); v != nil {\n\t\treturn v, true\n\t}\n\treturn &Config{}, false\n}\n\n// RemoveConfig removes the global configuration with specified group.\n// If `name` is not passed, it removes configuration of the default group name.\nfunc RemoveConfig(name ...string) {\n\tgroup := DefaultGroupName\n\tif len(name) > 0 {\n\t\tgroup = name[0]\n\t}\n\tlocalConfigMap.Remove(group)\n\n\tintlog.Printf(context.TODO(), `RemoveConfig: %s`, group)\n}\n\n// ClearConfig removes all configurations of redis.\nfunc ClearConfig() {\n\tlocalConfigMap.Clear()\n}\n"
  },
  {
    "path": "database/gredis/gredis_instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\nvar (\n\t// checker is the checker function for instances map.\n\tchecker        = func(v *Redis) bool { return v == nil }\n\tlocalInstances = gmap.NewKVMapWithChecker[string, *Redis](checker, true)\n)\n\n// Instance returns an instance of redis client with specified group.\n// The `name` param is unnecessary, if `name` is not passed,\n// it returns a redis instance with default configuration group.\nfunc Instance(name ...string) *Redis {\n\tgroup := DefaultGroupName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tgroup = name[0]\n\t}\n\treturn localInstances.GetOrSetFuncLock(group, func() *Redis {\n\t\tif config, ok := GetConfig(group); ok {\n\t\t\tr, err := New(config)\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn r\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Redis client.\ntype Redis struct {\n\tconfig *Config\n\tlocalAdapter\n\tlocalGroup\n}\n\ntype (\n\tlocalGroup struct {\n\t\tlocalGroupGeneric\n\t\tlocalGroupHash\n\t\tlocalGroupList\n\t\tlocalGroupPubSub\n\t\tlocalGroupScript\n\t\tlocalGroupSet\n\t\tlocalGroupSortedSet\n\t\tlocalGroupString\n\t}\n\tlocalAdapter        = Adapter\n\tlocalGroupGeneric   = IGroupGeneric\n\tlocalGroupHash      = IGroupHash\n\tlocalGroupList      = IGroupList\n\tlocalGroupPubSub    = IGroupPubSub\n\tlocalGroupScript    = IGroupScript\n\tlocalGroupSet       = IGroupSet\n\tlocalGroupSortedSet = IGroupSortedSet\n\tlocalGroupString    = IGroupString\n)\n\nconst (\n\terrorNilRedis = `the Redis object is nil`\n)\n\nconst errorNilAdapter = `redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis`\n\n// initGroup initializes the group object of redis.\nfunc (r *Redis) initGroup() *Redis {\n\tr.localGroup = localGroup{\n\t\tlocalGroupGeneric:   r.GroupGeneric(),\n\t\tlocalGroupHash:      r.GroupHash(),\n\t\tlocalGroupList:      r.GroupList(),\n\t\tlocalGroupPubSub:    r.GroupPubSub(),\n\t\tlocalGroupScript:    r.GroupScript(),\n\t\tlocalGroupSet:       r.GroupSet(),\n\t\tlocalGroupSortedSet: r.GroupSortedSet(),\n\t\tlocalGroupString:    r.GroupString(),\n\t}\n\treturn r\n}\n\n// SetAdapter changes the underlying adapter with custom adapter for current redis client.\nfunc (r *Redis) SetAdapter(adapter Adapter) {\n\tif r == nil {\n\t\tpanic(gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis))\n\t}\n\tr.localAdapter = adapter\n}\n\n// GetAdapter returns the adapter that is set in current redis client.\nfunc (r *Redis) GetAdapter() Adapter {\n\tif r == nil {\n\t\treturn nil\n\t}\n\treturn r.localAdapter\n}\n\n// Conn retrieves and returns a connection object for continuous operations.\n// Note that you should call Close function manually if you do not use this connection any further.\nfunc (r *Redis) Conn(ctx context.Context) (Conn, error) {\n\tif r == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis)\n\t}\n\tif r.localAdapter == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeNecessaryPackageNotImport, errorNilAdapter)\n\t}\n\treturn r.localAdapter.Conn(ctx)\n}\n\n// Do send a command to the server and returns the received reply.\n// It uses json.Marshal for struct/slice/map type values before committing them to redis.\nfunc (r *Redis) Do(ctx context.Context, command string, args ...any) (*gvar.Var, error) {\n\tif r == nil {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis)\n\t}\n\tif r.localAdapter == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeMissingConfiguration, errorNilAdapter)\n\t}\n\treturn r.localAdapter.Do(ctx, command, args...)\n}\n\n// MustConn performs as function Conn, but it panics if any error occurs internally.\nfunc (r *Redis) MustConn(ctx context.Context) Conn {\n\tc, err := r.Conn(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn c\n}\n\n// MustDo performs as function Do, but it panics if any error occurs internally.\nfunc (r *Redis) MustDo(ctx context.Context, command string, args ...any) *gvar.Var {\n\tv, err := r.Do(ctx, command, args...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Close closes current redis client, closes its connection pool and releases all its related resources.\nfunc (r *Redis) Close(ctx context.Context) error {\n\tif r == nil || r.localAdapter == nil {\n\t\treturn nil\n\t}\n\treturn r.localAdapter.Close(ctx)\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_generic.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupGeneric manages generic redis operations.\n// Implements see redis.GroupGeneric.\ntype IGroupGeneric interface {\n\tCopy(ctx context.Context, source, destination string, option ...CopyOption) (int64, error)\n\tExists(ctx context.Context, keys ...string) (int64, error)\n\tType(ctx context.Context, key string) (string, error)\n\tUnlink(ctx context.Context, keys ...string) (int64, error)\n\tRename(ctx context.Context, key, newKey string) error\n\tRenameNX(ctx context.Context, key, newKey string) (int64, error)\n\tMove(ctx context.Context, key string, db int) (int64, error)\n\tDel(ctx context.Context, keys ...string) (int64, error)\n\tRandomKey(ctx context.Context) (string, error)\n\tDBSize(ctx context.Context) (int64, error)\n\tKeys(ctx context.Context, pattern string) ([]string, error)\n\tScan(ctx context.Context, cursor uint64, option ...ScanOption) (uint64, []string, error)\n\tFlushDB(ctx context.Context, option ...FlushOp) error\n\tFlushAll(ctx context.Context, option ...FlushOp) error\n\tExpire(ctx context.Context, key string, seconds int64, option ...ExpireOption) (int64, error)\n\tExpireAt(ctx context.Context, key string, time time.Time, option ...ExpireOption) (int64, error)\n\tExpireTime(ctx context.Context, key string) (*gvar.Var, error)\n\tTTL(ctx context.Context, key string) (int64, error)\n\tPersist(ctx context.Context, key string) (int64, error)\n\tPExpire(ctx context.Context, key string, milliseconds int64, option ...ExpireOption) (int64, error)\n\tPExpireAt(ctx context.Context, key string, time time.Time, option ...ExpireOption) (int64, error)\n\tPExpireTime(ctx context.Context, key string) (*gvar.Var, error)\n\tPTTL(ctx context.Context, key string) (int64, error)\n}\n\n// CopyOption provides options for function Copy.\ntype CopyOption struct {\n\tDB      int  // DB option allows specifying an alternative logical database index for the destination key.\n\tREPLACE bool // REPLACE option removes the destination key before copying the value to it.\n}\n\ntype FlushOp string\n\nconst (\n\tFlushAsync FlushOp = \"ASYNC\" // ASYNC: flushes the databases asynchronously\n\tFlushSync  FlushOp = \"SYNC\"  // SYNC: flushes the databases synchronously\n)\n\n// ExpireOption provides options for function Expire.\ntype ExpireOption struct {\n\tNX bool // NX -- Set expiry only when the key has no expiry\n\tXX bool // XX -- Set expiry only when the key has an existing expiry\n\tGT bool // GT -- Set expiry only when the new expiry is greater than current one\n\tLT bool // LT -- Set expiry only when the new expiry is less than current one\n}\n\n// ScanOption provides options for function Scan.\ntype ScanOption struct {\n\tMatch string // Match -- Specifies a glob-style pattern for filtering keys.\n\tCount int    // Count -- Suggests the number of keys to return per scan.\n\tType  string // Type -- Filters keys by their data type. Valid types are \"string\", \"list\", \"set\", \"zset\", \"hash\", and \"stream\".\n}\n\n// doScanOption is the internal representation of ScanOption.\ntype doScanOption struct {\n\tMatch *string\n\tCount *int\n\tType  *string\n}\n\n// ToUsedOption converts fields in ScanOption with zero values to nil. Only fields with values are retained.\nfunc (scanOpt *ScanOption) ToUsedOption() doScanOption {\n\tvar usedOption doScanOption\n\n\tif scanOpt.Match != \"\" {\n\t\tusedOption.Match = &scanOpt.Match\n\t}\n\tif scanOpt.Count != 0 {\n\t\tusedOption.Count = &scanOpt.Count\n\t}\n\tif scanOpt.Type != \"\" {\n\t\tusedOption.Type = &scanOpt.Type\n\t}\n\n\treturn usedOption\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_hash.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupHash manages redis hash operations.\n// Implements see redis.GroupHash.\ntype IGroupHash interface {\n\tHSet(ctx context.Context, key string, fields map[string]any) (int64, error)\n\tHSetNX(ctx context.Context, key, field string, value any) (int64, error)\n\tHGet(ctx context.Context, key, field string) (*gvar.Var, error)\n\tHStrLen(ctx context.Context, key, field string) (int64, error)\n\tHExists(ctx context.Context, key, field string) (int64, error)\n\tHDel(ctx context.Context, key string, fields ...string) (int64, error)\n\tHLen(ctx context.Context, key string) (int64, error)\n\tHIncrBy(ctx context.Context, key, field string, increment int64) (int64, error)\n\tHIncrByFloat(ctx context.Context, key, field string, increment float64) (float64, error)\n\tHMSet(ctx context.Context, key string, fields map[string]any) error\n\tHMGet(ctx context.Context, key string, fields ...string) (gvar.Vars, error)\n\tHKeys(ctx context.Context, key string) ([]string, error)\n\tHVals(ctx context.Context, key string) (gvar.Vars, error)\n\tHGetAll(ctx context.Context, key string) (*gvar.Var, error)\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupList manages redis list operations.\n// Implements see redis.GroupList.\ntype IGroupList interface {\n\tLPush(ctx context.Context, key string, values ...any) (int64, error)\n\tLPushX(ctx context.Context, key string, element any, elements ...any) (int64, error)\n\tRPush(ctx context.Context, key string, values ...any) (int64, error)\n\tRPushX(ctx context.Context, key string, value any) (int64, error)\n\tLPop(ctx context.Context, key string, count ...int) (*gvar.Var, error)\n\tRPop(ctx context.Context, key string, count ...int) (*gvar.Var, error)\n\tLRem(ctx context.Context, key string, count int64, value any) (int64, error)\n\tLLen(ctx context.Context, key string) (int64, error)\n\tLIndex(ctx context.Context, key string, index int64) (*gvar.Var, error)\n\tLInsert(ctx context.Context, key string, op LInsertOp, pivot, value any) (int64, error)\n\tLSet(ctx context.Context, key string, index int64, value any) (*gvar.Var, error)\n\tLRange(ctx context.Context, key string, start, stop int64) (gvar.Vars, error)\n\tLTrim(ctx context.Context, key string, start, stop int64) error\n\tBLPop(ctx context.Context, timeout int64, keys ...string) (gvar.Vars, error)\n\tBRPop(ctx context.Context, timeout int64, keys ...string) (gvar.Vars, error)\n\tRPopLPush(ctx context.Context, source, destination string) (*gvar.Var, error)\n\tBRPopLPush(ctx context.Context, source, destination string, timeout int64) (*gvar.Var, error)\n}\n\n// LInsertOp defines the operation name for function LInsert.\ntype LInsertOp string\n\nconst (\n\tLInsertBefore LInsertOp = \"BEFORE\"\n\tLInsertAfter  LInsertOp = \"AFTER\"\n)\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_pubsub.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// IGroupPubSub manages redis pub/sub operations.\n// Implements see redis.GroupPubSub.\ntype IGroupPubSub interface {\n\tPublish(ctx context.Context, channel string, message any) (int64, error)\n\tSubscribe(ctx context.Context, channel string, channels ...string) (Conn, []*Subscription, error)\n\tPSubscribe(ctx context.Context, pattern string, patterns ...string) (Conn, []*Subscription, error)\n}\n\n// Message received as result of a PUBLISH command issued by another client.\ntype Message struct {\n\tChannel      string\n\tPattern      string\n\tPayload      string\n\tPayloadSlice []string\n}\n\n// Subscription received after a successful subscription to channel.\ntype Subscription struct {\n\tKind    string // Can be \"subscribe\", \"unsubscribe\", \"psubscribe\" or \"punsubscribe\".\n\tChannel string // Channel name we have subscribed to.\n\tCount   int    // Number of channels we are currently subscribed to.\n}\n\n// String converts current object to a readable string.\nfunc (m *Subscription) String() string {\n\treturn fmt.Sprintf(\"%s: %s\", m.Kind, m.Channel)\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_script.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupScript manages redis script operations.\n// Implements see redis.GroupScript.\ntype IGroupScript interface {\n\tEval(ctx context.Context, script string, numKeys int64, keys []string, args []any) (*gvar.Var, error)\n\tEvalSha(ctx context.Context, sha1 string, numKeys int64, keys []string, args []any) (*gvar.Var, error)\n\tScriptLoad(ctx context.Context, script string) (string, error)\n\tScriptExists(ctx context.Context, sha1 string, sha1s ...string) (map[string]bool, error)\n\tScriptFlush(ctx context.Context, option ...ScriptFlushOption) error\n\tScriptKill(ctx context.Context) error\n}\n\n// ScriptFlushOption provides options for function ScriptFlush.\ntype ScriptFlushOption struct {\n\tSYNC  bool // SYNC  flushes the cache synchronously.\n\tASYNC bool // ASYNC flushes the cache asynchronously.\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupSet manages redis set operations.\n// Implements see redis.GroupSet.\ntype IGroupSet interface {\n\tSAdd(ctx context.Context, key string, member any, members ...any) (int64, error)\n\tSIsMember(ctx context.Context, key string, member any) (int64, error)\n\tSPop(ctx context.Context, key string, count ...int) (*gvar.Var, error)\n\tSRandMember(ctx context.Context, key string, count ...int) (*gvar.Var, error)\n\tSRem(ctx context.Context, key string, member any, members ...any) (int64, error)\n\tSMove(ctx context.Context, source, destination string, member any) (int64, error)\n\tSCard(ctx context.Context, key string) (int64, error)\n\tSMembers(ctx context.Context, key string) (gvar.Vars, error)\n\tSMIsMember(ctx context.Context, key, member any, members ...any) ([]int, error)\n\tSInter(ctx context.Context, key string, keys ...string) (gvar.Vars, error)\n\tSInterStore(ctx context.Context, destination string, key string, keys ...string) (int64, error)\n\tSUnion(ctx context.Context, key string, keys ...string) (gvar.Vars, error)\n\tSUnionStore(ctx context.Context, destination, key string, keys ...string) (int64, error)\n\tSDiff(ctx context.Context, key string, keys ...string) (gvar.Vars, error)\n\tSDiffStore(ctx context.Context, destination string, key string, keys ...string) (int64, error)\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_sorted_set.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupSortedSet manages redis sorted set operations.\n// Implements see redis.GroupSortedSet.\ntype IGroupSortedSet interface {\n\tZAdd(ctx context.Context, key string, option *ZAddOption, member ZAddMember, members ...ZAddMember) (*gvar.Var, error)\n\tZScore(ctx context.Context, key string, member any) (float64, error)\n\tZIncrBy(ctx context.Context, key string, increment float64, member any) (float64, error)\n\tZCard(ctx context.Context, key string) (int64, error)\n\tZCount(ctx context.Context, key string, min, max string) (int64, error)\n\tZRange(ctx context.Context, key string, start, stop int64, option ...ZRangeOption) (gvar.Vars, error)\n\tZRevRange(ctx context.Context, key string, start, stop int64, option ...ZRevRangeOption) (*gvar.Var, error)\n\tZRank(ctx context.Context, key string, member any) (int64, error)\n\tZRevRank(ctx context.Context, key string, member any) (int64, error)\n\tZRem(ctx context.Context, key string, member any, members ...any) (int64, error)\n\tZRemRangeByRank(ctx context.Context, key string, start, stop int64) (int64, error)\n\tZRemRangeByScore(ctx context.Context, key string, min, max string) (int64, error)\n\tZRemRangeByLex(ctx context.Context, key string, min, max string) (int64, error)\n\tZLexCount(ctx context.Context, key, min, max string) (int64, error)\n}\n\n// ZAddOption provides options for function ZAdd.\ntype ZAddOption struct {\n\tXX bool // Only update elements that already exist. Don't add new elements.\n\tNX bool // Only add new elements. Don't update already existing elements.\n\t// Only update existing elements if the new score is less than the current score.\n\t// This flag doesn't prevent adding new elements.\n\tLT bool\n\n\t// Only update existing elements if the new score is greater than the current score.\n\t// This flag doesn't prevent adding new elements.\n\tGT bool\n\n\t// Modify the return value from the number of new elements added, to the total number of elements changed (CH is an abbreviation of changed).\n\t// Changed elements are new elements added and elements already existing for which the score was updated.\n\t// So elements specified in the command line having the same score as they had in the past are not counted.\n\t// Note: normally the return value of ZAdd only counts the number of new elements added.\n\tCH bool\n\n\t// When this option is specified ZAdd acts like ZIncrBy. Only one score-element pair can be specified in this mode.\n\tINCR bool\n}\n\n// ZAddMember is element struct for set.\ntype ZAddMember struct {\n\tScore  float64\n\tMember any\n}\n\n// ZRangeOption provides extra option for ZRange function.\ntype ZRangeOption struct {\n\tByScore bool\n\tByLex   bool\n\t// The optional REV argument reverses the ordering, so elements are ordered from highest to lowest score,\n\t// and score ties are resolved by reverse lexicographical ordering.\n\tRev   bool\n\tLimit *ZRangeOptionLimit\n\t// The optional WithScores argument supplements the command's reply with the scores of elements returned.\n\tWithScores bool\n}\n\n// ZRangeOptionLimit provides LIMIT argument for ZRange function.\n// The optional LIMIT argument can be used to obtain a sub-range from the matching elements\n// (similar to SELECT LIMIT offset, count in SQL). A negative `Count` returns all elements from the `Offset`.\ntype ZRangeOptionLimit struct {\n\tOffset *int\n\tCount  *int\n}\n\n// ZRevRangeOption provides options for function ZRevRange.\ntype ZRevRangeOption struct {\n\tWithScores bool\n}\n"
  },
  {
    "path": "database/gredis/gredis_redis_group_string.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gredis\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// IGroupString manages redis string operations.\n// Implements see redis.GroupString.\ntype IGroupString interface {\n\tSet(ctx context.Context, key string, value any, option ...SetOption) (*gvar.Var, error)\n\tSetNX(ctx context.Context, key string, value any) (bool, error)\n\tSetEX(ctx context.Context, key string, value any, ttlInSeconds int64) error\n\tGet(ctx context.Context, key string) (*gvar.Var, error)\n\tGetDel(ctx context.Context, key string) (*gvar.Var, error)\n\tGetEX(ctx context.Context, key string, option ...GetEXOption) (*gvar.Var, error)\n\tGetSet(ctx context.Context, key string, value any) (*gvar.Var, error)\n\tStrLen(ctx context.Context, key string) (int64, error)\n\tAppend(ctx context.Context, key string, value string) (int64, error)\n\tSetRange(ctx context.Context, key string, offset int64, value string) (int64, error)\n\tGetRange(ctx context.Context, key string, start, end int64) (string, error)\n\tIncr(ctx context.Context, key string) (int64, error)\n\tIncrBy(ctx context.Context, key string, increment int64) (int64, error)\n\tIncrByFloat(ctx context.Context, key string, increment float64) (float64, error)\n\tDecr(ctx context.Context, key string) (int64, error)\n\tDecrBy(ctx context.Context, key string, decrement int64) (int64, error)\n\tMSet(ctx context.Context, keyValueMap map[string]any) error\n\tMSetNX(ctx context.Context, keyValueMap map[string]any) (bool, error)\n\tMGet(ctx context.Context, keys ...string) (map[string]*gvar.Var, error)\n}\n\n// TTLOption provides extra option for TTL related functions.\ntype TTLOption struct {\n\tEX      *int64 // EX seconds -- Set the specified expire time, in seconds.\n\tPX      *int64 // PX milliseconds -- Set the specified expire time, in milliseconds.\n\tEXAT    *int64 // EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.\n\tPXAT    *int64 // PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.\n\tKeepTTL bool   // Retain the time to live associated with the key.\n}\n\n// SetOption provides extra option for Set function.\ntype SetOption struct {\n\tTTLOption\n\tNX bool // Only set the key if it does not already exist.\n\tXX bool // Only set the key if it already exists.\n\n\t// Return the old string stored at key, or nil if key did not exist.\n\t// An error is returned and SET aborted if the value stored at key is not a string.\n\tGet bool\n}\n\n// GetEXOption provides extra option for GetEx function.\ntype GetEXOption struct {\n\tTTLOption\n\tPersist bool // Persist -- Remove the time to live associated with the key.\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gdebug contains facilities for programs to debug themselves while they are running.\npackage gdebug\n"
  },
  {
    "path": "debug/gdebug/gdebug_caller.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nconst (\n\tmaxCallerDepth = 1000\n\tstackFilterKey = \"/debug/gdebug/gdebug\"\n)\n\nvar (\n\tgoRootForFilter  = runtime.GOROOT() // goRootForFilter is used for stack filtering purpose.\n\tbinaryVersion    = \"\"               // The version of current running binary(uint64 hex).\n\tbinaryVersionMd5 = \"\"               // The version of current running binary(MD5).\n\tselfPath         = \"\"               // Current running binary absolute path.\n)\n\nfunc init() {\n\tif goRootForFilter != \"\" {\n\t\tgoRootForFilter = strings.ReplaceAll(goRootForFilter, \"\\\\\", \"/\")\n\t}\n\t// Initialize internal package variable: selfPath.\n\tselfPath, _ = exec.LookPath(os.Args[0])\n\tif selfPath != \"\" {\n\t\tselfPath, _ = filepath.Abs(selfPath)\n\t}\n\tif selfPath == \"\" {\n\t\tselfPath, _ = filepath.Abs(os.Args[0])\n\t}\n}\n\n// Caller returns the function name and the absolute file path along with its line\n// number of the caller.\nfunc Caller(skip ...int) (function string, path string, line int) {\n\treturn CallerWithFilter(nil, skip...)\n}\n\n// CallerWithFilter returns the function name and the absolute file path along with\n// its line number of the caller.\n//\n// The parameter `filters` is used to filter the path of the caller.\nfunc CallerWithFilter(filters []string, skip ...int) (function string, path string, line int) {\n\tvar (\n\t\tnumber = 0\n\t\tok     = true\n\t)\n\tif len(skip) > 0 {\n\t\tnumber = skip[0]\n\t}\n\tpc, file, line, start := callerFromIndex(filters)\n\tif start != -1 {\n\t\tfor i := start + number; i < maxCallerDepth; i++ {\n\t\t\tif i != start {\n\t\t\t\tpc, file, line, ok = runtime.Caller(i)\n\t\t\t}\n\t\t\tif ok {\n\t\t\t\tif filterFileByFilters(file, filters) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfunction = \"\"\n\t\t\t\tif fn := runtime.FuncForPC(pc); fn == nil {\n\t\t\t\t\tfunction = \"unknown\"\n\t\t\t\t} else {\n\t\t\t\t\tfunction = fn.Name()\n\t\t\t\t}\n\t\t\t\treturn function, file, line\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\", \"\", -1\n}\n\n// callerFromIndex returns the caller position and according information exclusive of the\n// debug package.\n//\n// VERY NOTE THAT, the returned index value should be `index - 1` as the caller's start point.\nfunc callerFromIndex(filters []string) (pc uintptr, file string, line int, index int) {\n\tvar ok bool\n\tfor index = 0; index < maxCallerDepth; index++ {\n\t\tif pc, file, line, ok = runtime.Caller(index); ok {\n\t\t\tif filterFileByFilters(file, filters) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif index > 0 {\n\t\t\t\tindex--\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\treturn 0, \"\", -1, -1\n}\n\nfunc filterFileByFilters(file string, filters []string) (filtered bool) {\n\t// Filter empty file.\n\tif file == \"\" {\n\t\treturn true\n\t}\n\t// Filter gdebug package callings.\n\tif strings.Contains(file, stackFilterKey) {\n\t\treturn true\n\t}\n\tfor _, filter := range filters {\n\t\tif filter != \"\" && strings.Contains(file, filter) {\n\t\t\treturn true\n\t\t}\n\t}\n\t// GOROOT filter.\n\tif goRootForFilter != \"\" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter {\n\t\t// https://github.com/gogf/gf/issues/2047\n\t\tfileSeparator := file[len(goRootForFilter)]\n\t\tif fileSeparator == filepath.Separator || fileSeparator == '\\\\' || fileSeparator == '/' {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// CallerPackage returns the package name of the caller.\nfunc CallerPackage() string {\n\tfunction, _, _ := Caller()\n\t// it defines a new internal function to retrieve the package name from caller function name,\n\t// which is for unit testing purpose for core logic of this function.\n\treturn getPackageFromCallerFunction(function)\n}\n\nfunc getPackageFromCallerFunction(function string) string {\n\tindexSplit := strings.LastIndexByte(function, '/')\n\tif indexSplit == -1 {\n\t\treturn function[:strings.IndexByte(function, '.')]\n\t}\n\tvar (\n\t\tleftPart  = function[:indexSplit+1]\n\t\trightPart = function[indexSplit+1:]\n\t\tindexDot  = strings.IndexByte(rightPart, '.')\n\t)\n\tif indexDot >= 0 {\n\t\trightPart = rightPart[:indexDot]\n\t}\n\treturn leftPart + rightPart\n}\n\n// CallerFunction returns the function name of the caller.\nfunc CallerFunction() string {\n\tfunction, _, _ := Caller()\n\tfunction = function[strings.LastIndexByte(function, '/')+1:]\n\tfunction = function[strings.IndexByte(function, '.')+1:]\n\treturn function\n}\n\n// CallerFilePath returns the file path of the caller.\nfunc CallerFilePath() string {\n\t_, path, _ := Caller()\n\treturn path\n}\n\n// CallerDirectory returns the directory of the caller.\nfunc CallerDirectory() string {\n\t_, path, _ := Caller()\n\treturn filepath.Dir(path)\n}\n\n// CallerFileLine returns the file path along with the line number of the caller.\nfunc CallerFileLine() string {\n\t_, path, line := Caller()\n\treturn fmt.Sprintf(`%s:%d`, path, line)\n}\n\n// CallerFileLineShort returns the file name along with the line number of the caller.\nfunc CallerFileLineShort() string {\n\t_, path, line := Caller()\n\treturn fmt.Sprintf(`%s:%d`, filepath.Base(path), line)\n}\n\n// FuncPath returns the complete function path of given `f`.\nfunc FuncPath(f any) string {\n\treturn runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()\n}\n\n// FuncName returns the function name of given `f`.\nfunc FuncName(f any) string {\n\tpath := FuncPath(f)\n\tif path == \"\" {\n\t\treturn \"\"\n\t}\n\tindex := strings.LastIndexByte(path, '/')\n\tif index < 0 {\n\t\tindex = strings.LastIndexByte(path, '\\\\')\n\t}\n\treturn path[index+1:]\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_grid.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug\n\nimport (\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n)\n\n// gridRegex is the regular expression object for parsing goroutine id from stack information.\nvar gridRegex = regexp.MustCompile(`^\\w+\\s+(\\d+)\\s+`)\n\n// GoroutineID retrieves and returns the current goroutine id from stack information.\n// Be very aware that, it is with low performance as it uses runtime.Stack function.\n// It is commonly used for debugging purpose.\nfunc GoroutineID() int {\n\tbuf := make([]byte, 26)\n\truntime.Stack(buf, false)\n\tmatch := gridRegex.FindSubmatch(buf)\n\tid, _ := strconv.Atoi(string(match[1]))\n\treturn id\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_stack.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"runtime\"\n)\n\n// PrintStack prints to standard error the stack trace returned by runtime.Stack.\nfunc PrintStack(skip ...int) {\n\tfmt.Print(Stack(skip...))\n}\n\n// Stack returns a formatted stack trace of the goroutine that calls it.\n// It calls runtime.Stack with a large enough buffer to capture the entire trace.\nfunc Stack(skip ...int) string {\n\treturn StackWithFilter(nil, skip...)\n}\n\n// StackWithFilter returns a formatted stack trace of the goroutine that calls it.\n// It calls runtime.Stack with a large enough buffer to capture the entire trace.\n//\n// The parameter `filter` is used to filter the path of the caller.\nfunc StackWithFilter(filters []string, skip ...int) string {\n\treturn StackWithFilters(filters, skip...)\n}\n\n// StackWithFilters returns a formatted stack trace of the goroutine that calls it.\n// It calls runtime.Stack with a large enough buffer to capture the entire trace.\n//\n// The parameter `filters` is a slice of strings, which are used to filter the path of the\n// caller.\n//\n// TODO Improve the performance using debug.Stack.\nfunc StackWithFilters(filters []string, skip ...int) string {\n\tnumber := 0\n\tif len(skip) > 0 {\n\t\tnumber = skip[0]\n\t}\n\tvar (\n\t\tname                  string\n\t\tspace                 = \"  \"\n\t\tindex                 = 1\n\t\tbuffer                = bytes.NewBuffer(nil)\n\t\tok                    = true\n\t\tpc, file, line, start = callerFromIndex(filters)\n\t)\n\tfor i := start + number; i < maxCallerDepth; i++ {\n\t\tif i != start {\n\t\t\tpc, file, line, ok = runtime.Caller(i)\n\t\t}\n\t\tif ok {\n\t\t\tif filterFileByFilters(file, filters) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif fn := runtime.FuncForPC(pc); fn == nil {\n\t\t\t\tname = \"unknown\"\n\t\t\t} else {\n\t\t\t\tname = fn.Name()\n\t\t\t}\n\t\t\tif index > 9 {\n\t\t\t\tspace = \" \"\n\t\t\t}\n\t\t\tfmt.Fprintf(buffer, \"%d.%s%s\\n    %s:%d\\n\", index, space, name, file, line)\n\t\t\tindex++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn buffer.String()\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_version.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// BinVersion returns the version of current running binary.\n// It uses ghash.BKDRHash+BASE36 algorithm to calculate the unique version of the binary.\nfunc BinVersion() string {\n\tif binaryVersion == \"\" {\n\t\tbinaryContent, _ := os.ReadFile(selfPath)\n\t\tbinaryVersion = strconv.FormatInt(\n\t\t\tint64(ghash.BKDR(binaryContent)),\n\t\t\t36,\n\t\t)\n\t}\n\treturn binaryVersion\n}\n\n// BinVersionMd5 returns the version of current running binary.\n// It uses MD5 algorithm to calculate the unique version of the binary.\nfunc BinVersionMd5() string {\n\tif binaryVersionMd5 == \"\" {\n\t\tbinaryVersionMd5, _ = md5File(selfPath)\n\t}\n\treturn binaryVersionMd5\n}\n\n// md5File encrypts file content of `path` using MD5 algorithms.\nfunc md5File(path string) (encrypt string, err error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\th := md5.New()\n\t_, err = io.Copy(h, f)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn \"\", err\n\t}\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil)), nil\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gdebug\n\nimport (\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"testing\"\n)\n\nfunc Benchmark_BinVersion(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBinVersion()\n\t}\n}\n\nfunc Benchmark_BinVersionMd5(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBinVersionMd5()\n\t}\n}\n\nfunc Benchmark_RuntimeCaller(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\truntime.Caller(0)\n\t}\n}\n\nfunc Benchmark_RuntimeFuncForPC(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\truntime.FuncForPC(11010101)\n\t}\n}\n\nfunc Benchmark_callerFromIndex(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tcallerFromIndex(nil)\n\t}\n}\n\nfunc Benchmark_Stack(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStack()\n\t}\n}\n\nfunc Benchmark_StackOfStdlib(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tdebug.Stack()\n\t}\n}\n\nfunc Benchmark_StackWithFilter(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStackWithFilter([]string{\"test\"})\n\t}\n}\n\nfunc Benchmark_Caller(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCaller()\n\t}\n}\n\nfunc Benchmark_CallerWithFilter(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerWithFilter([]string{\"test\"})\n\t}\n}\n\nfunc Benchmark_CallerFilePath(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerFilePath()\n\t}\n}\n\nfunc Benchmark_CallerDirectory(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerDirectory()\n\t}\n}\n\nfunc Benchmark_CallerFileLine(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerFileLine()\n\t}\n}\n\nfunc Benchmark_CallerFileLineShort(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerFileLineShort()\n\t}\n}\n\nfunc Benchmark_CallerFunction(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerFunction()\n\t}\n}\n\nfunc Benchmark_CallerPackage(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tCallerPackage()\n\t}\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug\n\nimport (\n\t\"testing\"\n)\n\nfunc Test_getPackageFromCallerFunction(t *testing.T) {\n\tdataMap := map[string]string{\n\t\t\"github.com/gogf/gf/v2/test/a\":       \"github.com/gogf/gf/v2/test/a\",\n\t\t\"github.com/gogf/gf/v2/test/a.C\":     \"github.com/gogf/gf/v2/test/a\",\n\t\t\"github.com/gogf/gf/v2/test/aa.C\":    \"github.com/gogf/gf/v2/test/aa\",\n\t\t\"github.com/gogf/gf/v2/test/gtest.C\": \"github.com/gogf/gf/v2/test/gtest\",\n\t}\n\tfor functionName, packageName := range dataMap {\n\t\tif result := getPackageFromCallerFunction(functionName); result != packageName {\n\t\t\tt.Logf(`%s != %s`, result, packageName)\n\t\t\tt.Fail()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "debug/gdebug/gdebug_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gdebug_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_CallerPackage(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gdebug.CallerPackage(), \"github.com/gogf/gf/v2/test/gtest\")\n\t})\n}\n\nfunc Test_CallerFunction(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gdebug.CallerFunction(), \"C\")\n\t})\n}\n\nfunc Test_CallerFilePath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(gdebug.CallerFilePath(), \"gtest_util.go\"), true)\n\t})\n}\n\nfunc Test_CallerDirectory(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(gdebug.CallerDirectory(), \"gtest\"), true)\n\t})\n}\n\nfunc Test_CallerFileLine(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfmt.Println(gdebug.CallerFileLine())\n\t\tt.Assert(gstr.Contains(gdebug.CallerFileLine(), \"gtest_util.go:36\"), true)\n\t})\n}\n\nfunc Test_CallerFileLineShort(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(gdebug.CallerFileLineShort(), \"gtest_util.go:36\"), true)\n\t})\n}\n\nfunc Test_FuncPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gdebug.FuncPath(Test_FuncPath), \"github.com/gogf/gf/v2/debug/gdebug_test.Test_FuncPath\")\n\t})\n}\n\nfunc Test_FuncName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gdebug.FuncName(Test_FuncName), \"gdebug_test.Test_FuncName\")\n\t})\n}\n\nfunc Test_PrintStack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgdebug.PrintStack()\n\t})\n}\n\nfunc Test_GoroutineId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(gdebug.GoroutineID(), 0)\n\t})\n}\n\nfunc Test_Stack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(gdebug.Stack(), \"gtest_util.go:36\"), true)\n\t})\n}\n\nfunc Test_StackWithFilter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(gdebug.StackWithFilter([]string{\"github.com\"}), \"gtest_util.go:36\"), true)\n\t})\n}\n\nfunc Test_BinVersion(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(len(gdebug.BinVersion()), 0)\n\t})\n}\n\nfunc Test_BinVersionMd5(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(len(gdebug.BinVersionMd5()), 0)\n\t})\n}\n"
  },
  {
    "path": "encoding/gbase64/gbase64.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gbase64 provides useful API for BASE64 encoding/decoding algorithm.\npackage gbase64\n\nimport (\n\t\"encoding/base64\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Encode encodes bytes with BASE64 algorithm.\nfunc Encode(src []byte) []byte {\n\tdst := make([]byte, base64.StdEncoding.EncodedLen(len(src)))\n\tbase64.StdEncoding.Encode(dst, src)\n\treturn dst\n}\n\n// EncodeString encodes string with BASE64 algorithm.\nfunc EncodeString(src string) string {\n\treturn EncodeToString([]byte(src))\n}\n\n// EncodeToString encodes bytes to string with BASE64 algorithm.\nfunc EncodeToString(src []byte) string {\n\treturn string(Encode(src))\n}\n\n// EncodeFile encodes file content of `path` using BASE64 algorithms.\nfunc EncodeFile(path string) ([]byte, error) {\n\tcontent, err := os.ReadFile(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.ReadFile failed for filename \"%s\"`, path)\n\t\treturn nil, err\n\t}\n\treturn Encode(content), nil\n}\n\n// MustEncodeFile encodes file content of `path` using BASE64 algorithms.\n// It panics if any error occurs.\nfunc MustEncodeFile(path string) []byte {\n\tresult, err := EncodeFile(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// EncodeFileToString encodes file content of `path` to string using BASE64 algorithms.\nfunc EncodeFileToString(path string) (string, error) {\n\tcontent, err := EncodeFile(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(content), nil\n}\n\n// MustEncodeFileToString encodes file content of `path` to string using BASE64 algorithms.\n// It panics if any error occurs.\nfunc MustEncodeFileToString(path string) string {\n\tresult, err := EncodeFileToString(path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// Decode decodes bytes with BASE64 algorithm.\nfunc Decode(data []byte) ([]byte, error) {\n\tvar (\n\t\tsrc    = make([]byte, base64.StdEncoding.DecodedLen(len(data)))\n\t\tn, err = base64.StdEncoding.Decode(src, data)\n\t)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `base64.StdEncoding.Decode failed`)\n\t}\n\treturn src[:n], err\n}\n\n// MustDecode decodes bytes with BASE64 algorithm.\n// It panics if any error occurs.\nfunc MustDecode(data []byte) []byte {\n\tresult, err := Decode(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// DecodeString decodes string with BASE64 algorithm.\nfunc DecodeString(data string) ([]byte, error) {\n\treturn Decode([]byte(data))\n}\n\n// MustDecodeString decodes string with BASE64 algorithm.\n// It panics if any error occurs.\nfunc MustDecodeString(data string) []byte {\n\tresult, err := DecodeString(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// DecodeToString decodes string with BASE64 algorithm.\nfunc DecodeToString(data string) (string, error) {\n\tb, err := DecodeString(data)\n\treturn string(b), err\n}\n\n// MustDecodeToString decodes string with BASE64 algorithm.\n// It panics if any error occurs.\nfunc MustDecodeToString(data string) string {\n\tresult, err := DecodeToString(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "encoding/gbase64/gbase64_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbase64_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype testPair struct {\n\tdecoded, encoded string\n}\n\nvar pairs = []testPair{\n\t// RFC 3548 examples\n\t{\"\\x14\\xfb\\x9c\\x03\\xd9\\x7e\", \"FPucA9l+\"},\n\t{\"\\x14\\xfb\\x9c\\x03\\xd9\", \"FPucA9k=\"},\n\t{\"\\x14\\xfb\\x9c\\x03\", \"FPucAw==\"},\n\n\t// RFC 4648 examples\n\t{\"\", \"\"},\n\t{\"f\", \"Zg==\"},\n\t{\"fo\", \"Zm8=\"},\n\t{\"foo\", \"Zm9v\"},\n\t{\"foob\", \"Zm9vYg==\"},\n\t{\"fooba\", \"Zm9vYmE=\"},\n\t{\"foobar\", \"Zm9vYmFy\"},\n\n\t// Wikipedia examples\n\t{\"sure.\", \"c3VyZS4=\"},\n\t{\"sure\", \"c3VyZQ==\"},\n\t{\"sur\", \"c3Vy\"},\n\t{\"su\", \"c3U=\"},\n\t{\"leasure.\", \"bGVhc3VyZS4=\"},\n\t{\"easure.\", \"ZWFzdXJlLg==\"},\n\t{\"asure.\", \"YXN1cmUu\"},\n\t{\"sure.\", \"c3VyZS4=\"},\n}\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k := range pairs {\n\t\t\t// Encode\n\t\t\tt.Assert(gbase64.Encode([]byte(pairs[k].decoded)), []byte(pairs[k].encoded))\n\t\t\tt.Assert(gbase64.EncodeToString([]byte(pairs[k].decoded)), pairs[k].encoded)\n\t\t\tt.Assert(gbase64.EncodeString(pairs[k].decoded), pairs[k].encoded)\n\n\t\t\t// Decode\n\t\t\tr1, _ := gbase64.Decode([]byte(pairs[k].encoded))\n\t\t\tt.Assert(r1, []byte(pairs[k].decoded))\n\n\t\t\tr2, _ := gbase64.DecodeString(pairs[k].encoded)\n\t\t\tt.Assert(r2, []byte(pairs[k].decoded))\n\n\t\t\tr3, _ := gbase64.DecodeToString(pairs[k].encoded)\n\t\t\tt.Assert(r3, pairs[k].decoded)\n\t\t}\n\t})\n}\n\nfunc Test_File(t *testing.T) {\n\tpath := gtest.DataPath(\"test\")\n\texpect := \"dGVzdA==\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gbase64.EncodeFile(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts, err := gbase64.EncodeFileToString(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, expect)\n\t})\n}\n\nfunc Test_File_Error(t *testing.T) {\n\tpath := \"none-exist-file\"\n\texpect := \"\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gbase64.EncodeFile(path)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(string(b), expect)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts, err := gbase64.EncodeFileToString(path)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(s, expect)\n\t})\n}\n"
  },
  {
    "path": "encoding/gbase64/testdata/test",
    "content": "test"
  },
  {
    "path": "encoding/gbinary/gbinary.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gbinary provides useful API for handling binary/bytes data.\n//\n// Note that package gbinary encodes the data using LittleEndian in default.\npackage gbinary\n\nfunc Encode(values ...any) []byte {\n\treturn LeEncode(values...)\n}\n\nfunc EncodeByLength(length int, values ...any) []byte {\n\treturn LeEncodeByLength(length, values...)\n}\n\nfunc Decode(b []byte, values ...any) error {\n\treturn LeDecode(b, values...)\n}\n\nfunc EncodeString(s string) []byte {\n\treturn LeEncodeString(s)\n}\n\nfunc DecodeToString(b []byte) string {\n\treturn LeDecodeToString(b)\n}\n\nfunc EncodeBool(b bool) []byte {\n\treturn LeEncodeBool(b)\n}\n\nfunc EncodeInt(i int) []byte {\n\treturn LeEncodeInt(i)\n}\n\nfunc EncodeUint(i uint) []byte {\n\treturn LeEncodeUint(i)\n}\n\nfunc EncodeInt8(i int8) []byte {\n\treturn LeEncodeInt8(i)\n}\n\nfunc EncodeUint8(i uint8) []byte {\n\treturn LeEncodeUint8(i)\n}\n\nfunc EncodeInt16(i int16) []byte {\n\treturn LeEncodeInt16(i)\n}\n\nfunc EncodeUint16(i uint16) []byte {\n\treturn LeEncodeUint16(i)\n}\n\nfunc EncodeInt32(i int32) []byte {\n\treturn LeEncodeInt32(i)\n}\n\nfunc EncodeUint32(i uint32) []byte {\n\treturn LeEncodeUint32(i)\n}\n\nfunc EncodeInt64(i int64) []byte {\n\treturn LeEncodeInt64(i)\n}\n\nfunc EncodeUint64(i uint64) []byte {\n\treturn LeEncodeUint64(i)\n}\n\nfunc EncodeFloat32(f float32) []byte {\n\treturn LeEncodeFloat32(f)\n}\n\nfunc EncodeFloat64(f float64) []byte {\n\treturn LeEncodeFloat64(f)\n}\n\nfunc DecodeToInt(b []byte) int {\n\treturn LeDecodeToInt(b)\n}\n\nfunc DecodeToUint(b []byte) uint {\n\treturn LeDecodeToUint(b)\n}\n\nfunc DecodeToBool(b []byte) bool {\n\treturn LeDecodeToBool(b)\n}\n\nfunc DecodeToInt8(b []byte) int8 {\n\treturn LeDecodeToInt8(b)\n}\n\nfunc DecodeToUint8(b []byte) uint8 {\n\treturn LeDecodeToUint8(b)\n}\n\nfunc DecodeToInt16(b []byte) int16 {\n\treturn LeDecodeToInt16(b)\n}\n\nfunc DecodeToUint16(b []byte) uint16 {\n\treturn LeDecodeToUint16(b)\n}\n\nfunc DecodeToInt32(b []byte) int32 {\n\treturn LeDecodeToInt32(b)\n}\n\nfunc DecodeToUint32(b []byte) uint32 {\n\treturn LeDecodeToUint32(b)\n}\n\nfunc DecodeToInt64(b []byte) int64 {\n\treturn LeDecodeToInt64(b)\n}\n\nfunc DecodeToUint64(b []byte) uint64 {\n\treturn LeDecodeToUint64(b)\n}\n\nfunc DecodeToFloat32(b []byte) float32 {\n\treturn LeDecodeToFloat32(b)\n}\n\nfunc DecodeToFloat64(b []byte) float64 {\n\treturn LeDecodeToFloat64(b)\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_be.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// BeEncode encodes one or multiple `values` into bytes using BigEndian.\n// It uses type asserting checking the type of each value of `values` and internally\n// calls corresponding converting function do the bytes converting.\n//\n// It supports common variable type asserting, and finally it uses fmt.Sprintf converting\n// value to string and then to bytes.\nfunc BeEncode(values ...any) []byte {\n\tbuf := new(bytes.Buffer)\n\tfor i := 0; i < len(values); i++ {\n\t\tif values[i] == nil {\n\t\t\treturn buf.Bytes()\n\t\t}\n\n\t\tswitch value := values[i].(type) {\n\t\tcase int:\n\t\t\tbuf.Write(BeEncodeInt(value))\n\t\tcase int8:\n\t\t\tbuf.Write(BeEncodeInt8(value))\n\t\tcase int16:\n\t\t\tbuf.Write(BeEncodeInt16(value))\n\t\tcase int32:\n\t\t\tbuf.Write(BeEncodeInt32(value))\n\t\tcase int64:\n\t\t\tbuf.Write(BeEncodeInt64(value))\n\t\tcase uint:\n\t\t\tbuf.Write(BeEncodeUint(value))\n\t\tcase uint8:\n\t\t\tbuf.Write(BeEncodeUint8(value))\n\t\tcase uint16:\n\t\t\tbuf.Write(BeEncodeUint16(value))\n\t\tcase uint32:\n\t\t\tbuf.Write(BeEncodeUint32(value))\n\t\tcase uint64:\n\t\t\tbuf.Write(BeEncodeUint64(value))\n\t\tcase bool:\n\t\t\tbuf.Write(BeEncodeBool(value))\n\t\tcase string:\n\t\t\tbuf.Write(BeEncodeString(value))\n\t\tcase []byte:\n\t\t\tbuf.Write(value)\n\t\tcase float32:\n\t\t\tbuf.Write(BeEncodeFloat32(value))\n\t\tcase float64:\n\t\t\tbuf.Write(BeEncodeFloat64(value))\n\t\tdefault:\n\t\t\tif err := binary.Write(buf, binary.BigEndian, value); err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\tbuf.Write(BeEncodeString(fmt.Sprintf(\"%v\", value)))\n\t\t\t}\n\t\t}\n\t}\n\treturn buf.Bytes()\n}\n\nfunc BeEncodeByLength(length int, values ...any) []byte {\n\tb := BeEncode(values...)\n\tif len(b) < length {\n\t\tb = append(b, make([]byte, length-len(b))...)\n\t} else if len(b) > length {\n\t\tb = b[0:length]\n\t}\n\treturn b\n}\n\nfunc BeDecode(b []byte, values ...any) error {\n\tvar (\n\t\terr error\n\t\tbuf = bytes.NewBuffer(b)\n\t)\n\tfor i := 0; i < len(values); i++ {\n\t\tif err = binary.Read(buf, binary.BigEndian, values[i]); err != nil {\n\t\t\terr = gerror.Wrap(err, `binary.Read failed`)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc BeEncodeString(s string) []byte {\n\treturn []byte(s)\n}\n\nfunc BeDecodeToString(b []byte) string {\n\treturn string(b)\n}\n\nfunc BeEncodeBool(b bool) []byte {\n\tif b {\n\t\treturn []byte{1}\n\t} else {\n\t\treturn []byte{0}\n\t}\n}\n\nfunc BeEncodeInt(i int) []byte {\n\tif i <= math.MaxInt8 {\n\t\treturn BeEncodeInt8(int8(i))\n\t} else if i <= math.MaxInt16 {\n\t\treturn BeEncodeInt16(int16(i))\n\t} else if i <= math.MaxInt32 {\n\t\treturn BeEncodeInt32(int32(i))\n\t} else {\n\t\treturn BeEncodeInt64(int64(i))\n\t}\n}\n\nfunc BeEncodeUint(i uint) []byte {\n\tif i <= math.MaxUint8 {\n\t\treturn BeEncodeUint8(uint8(i))\n\t} else if i <= math.MaxUint16 {\n\t\treturn BeEncodeUint16(uint16(i))\n\t} else if i <= math.MaxUint32 {\n\t\treturn BeEncodeUint32(uint32(i))\n\t} else {\n\t\treturn BeEncodeUint64(uint64(i))\n\t}\n}\n\nfunc BeEncodeInt8(i int8) []byte {\n\treturn []byte{byte(i)}\n}\n\nfunc BeEncodeUint8(i uint8) []byte {\n\treturn []byte{i}\n}\n\nfunc BeEncodeInt16(i int16) []byte {\n\tb := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(b, uint16(i))\n\treturn b\n}\n\nfunc BeEncodeUint16(i uint16) []byte {\n\tb := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(b, i)\n\treturn b\n}\n\nfunc BeEncodeInt32(i int32) []byte {\n\tb := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(b, uint32(i))\n\treturn b\n}\n\nfunc BeEncodeUint32(i uint32) []byte {\n\tb := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(b, i)\n\treturn b\n}\n\nfunc BeEncodeInt64(i int64) []byte {\n\tb := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(b, uint64(i))\n\treturn b\n}\n\nfunc BeEncodeUint64(i uint64) []byte {\n\tb := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(b, i)\n\treturn b\n}\n\nfunc BeEncodeFloat32(f float32) []byte {\n\tbits := math.Float32bits(f)\n\tb := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(b, bits)\n\treturn b\n}\n\nfunc BeEncodeFloat64(f float64) []byte {\n\tbits := math.Float64bits(f)\n\tb := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(b, bits)\n\treturn b\n}\n\nfunc BeDecodeToInt(b []byte) int {\n\tif len(b) < 2 {\n\t\treturn int(BeDecodeToUint8(b))\n\t} else if len(b) < 3 {\n\t\treturn int(BeDecodeToUint16(b))\n\t} else if len(b) < 5 {\n\t\treturn int(BeDecodeToUint32(b))\n\t} else {\n\t\treturn int(BeDecodeToUint64(b))\n\t}\n}\n\nfunc BeDecodeToUint(b []byte) uint {\n\tif len(b) < 2 {\n\t\treturn uint(BeDecodeToUint8(b))\n\t} else if len(b) < 3 {\n\t\treturn uint(BeDecodeToUint16(b))\n\t} else if len(b) < 5 {\n\t\treturn uint(BeDecodeToUint32(b))\n\t} else {\n\t\treturn uint(BeDecodeToUint64(b))\n\t}\n}\n\nfunc BeDecodeToBool(b []byte) bool {\n\tif len(b) == 0 {\n\t\treturn false\n\t}\n\tif bytes.Equal(b, make([]byte, len(b))) {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc BeDecodeToInt8(b []byte) int8 {\n\tif len(b) == 0 {\n\t\tpanic(`empty slice given`)\n\t}\n\treturn int8(b[0])\n}\n\nfunc BeDecodeToUint8(b []byte) uint8 {\n\tif len(b) == 0 {\n\t\tpanic(`empty slice given`)\n\t}\n\treturn b[0]\n}\n\nfunc BeDecodeToInt16(b []byte) int16 {\n\treturn int16(binary.BigEndian.Uint16(BeFillUpSize(b, 2)))\n}\n\nfunc BeDecodeToUint16(b []byte) uint16 {\n\treturn binary.BigEndian.Uint16(BeFillUpSize(b, 2))\n}\n\nfunc BeDecodeToInt32(b []byte) int32 {\n\treturn int32(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))\n}\n\nfunc BeDecodeToUint32(b []byte) uint32 {\n\treturn binary.BigEndian.Uint32(BeFillUpSize(b, 4))\n}\n\nfunc BeDecodeToInt64(b []byte) int64 {\n\treturn int64(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))\n}\n\nfunc BeDecodeToUint64(b []byte) uint64 {\n\treturn binary.BigEndian.Uint64(BeFillUpSize(b, 8))\n}\n\nfunc BeDecodeToFloat32(b []byte) float32 {\n\treturn math.Float32frombits(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))\n}\n\nfunc BeDecodeToFloat64(b []byte) float64 {\n\treturn math.Float64frombits(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))\n}\n\n// BeFillUpSize fills up the bytes `b` to given length `l` using big BigEndian.\n//\n// Note that it creates a new bytes slice by copying the original one to avoid changing\n// the original parameter bytes.\nfunc BeFillUpSize(b []byte, l int) []byte {\n\tif len(b) >= l {\n\t\treturn b[:l]\n\t}\n\tc := make([]byte, l)\n\tcopy(c[l-len(b):], b)\n\treturn c\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_bit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary\n\n// NOTE: THIS IS AN EXPERIMENTAL FEATURE!\n\n// Bit Binary bit (0 | 1)\ntype Bit int8\n\n// EncodeBits does encode bits return bits Default coding\nfunc EncodeBits(bits []Bit, i int, l int) []Bit {\n\treturn EncodeBitsWithUint(bits, uint(i), l)\n}\n\n// EncodeBitsWithUint . Merge ui bitwise into the bits array and occupy the length bits\n// (Note: binary 0 | 1 digits are stored in the uis array)\nfunc EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bit {\n\ta := make([]Bit, l)\n\tfor i := l - 1; i >= 0; i-- {\n\t\ta[i] = Bit(ui & 1)\n\t\tui >>= 1\n\t}\n\tif bits != nil {\n\t\treturn append(bits, a...)\n\t}\n\treturn a\n}\n\n// EncodeBitsToBytes . does encode bits to bytes\n// Convert bits to [] byte, encode from left to right, and add less than 1 byte from 0 to the end.\nfunc EncodeBitsToBytes(bits []Bit) []byte {\n\tif len(bits)%8 != 0 {\n\t\tfor i := 0; i < len(bits)%8; i++ {\n\t\t\tbits = append(bits, 0)\n\t\t}\n\t}\n\tb := make([]byte, 0)\n\tfor i := 0; i < len(bits); i += 8 {\n\t\tb = append(b, byte(DecodeBitsToUint(bits[i:i+8])))\n\t}\n\treturn b\n}\n\n// DecodeBits .does decode bits to int\n// Resolve to int\nfunc DecodeBits(bits []Bit) int {\n\tv := 0\n\tfor _, i := range bits {\n\t\tv = v<<1 | int(i)\n\t}\n\treturn v\n}\n\n// DecodeBitsToUint .Resolve to uint\nfunc DecodeBitsToUint(bits []Bit) uint {\n\tv := uint(0)\n\tfor _, i := range bits {\n\t\tv = v<<1 | uint(i)\n\t}\n\treturn v\n}\n\n// DecodeBytesToBits .Parsing [] byte into character array [] uint8\nfunc DecodeBytesToBits(bs []byte) []Bit {\n\tbits := make([]Bit, 0)\n\tfor _, b := range bs {\n\t\tbits = EncodeBitsWithUint(bits, uint(b), 8)\n\t}\n\treturn bits\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary\n"
  },
  {
    "path": "encoding/gbinary/gbinary_le.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// LeEncode encodes one or multiple `values` into bytes using LittleEndian.\n// It uses type asserting checking the type of each value of `values` and internally\n// calls corresponding converting function do the bytes converting.\n//\n// It supports common variable type asserting, and finally it uses fmt.Sprintf converting\n// value to string and then to bytes.\nfunc LeEncode(values ...any) []byte {\n\tbuf := new(bytes.Buffer)\n\tfor i := 0; i < len(values); i++ {\n\t\tif values[i] == nil {\n\t\t\treturn buf.Bytes()\n\t\t}\n\t\tswitch value := values[i].(type) {\n\t\tcase int:\n\t\t\tbuf.Write(LeEncodeInt(value))\n\t\tcase int8:\n\t\t\tbuf.Write(LeEncodeInt8(value))\n\t\tcase int16:\n\t\t\tbuf.Write(LeEncodeInt16(value))\n\t\tcase int32:\n\t\t\tbuf.Write(LeEncodeInt32(value))\n\t\tcase int64:\n\t\t\tbuf.Write(LeEncodeInt64(value))\n\t\tcase uint:\n\t\t\tbuf.Write(LeEncodeUint(value))\n\t\tcase uint8:\n\t\t\tbuf.Write(LeEncodeUint8(value))\n\t\tcase uint16:\n\t\t\tbuf.Write(LeEncodeUint16(value))\n\t\tcase uint32:\n\t\t\tbuf.Write(LeEncodeUint32(value))\n\t\tcase uint64:\n\t\t\tbuf.Write(LeEncodeUint64(value))\n\t\tcase bool:\n\t\t\tbuf.Write(LeEncodeBool(value))\n\t\tcase string:\n\t\t\tbuf.Write(LeEncodeString(value))\n\t\tcase []byte:\n\t\t\tbuf.Write(value)\n\t\tcase float32:\n\t\t\tbuf.Write(LeEncodeFloat32(value))\n\t\tcase float64:\n\t\t\tbuf.Write(LeEncodeFloat64(value))\n\n\t\tdefault:\n\t\t\tif err := binary.Write(buf, binary.LittleEndian, value); err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\tbuf.Write(LeEncodeString(fmt.Sprintf(\"%v\", value)))\n\t\t\t}\n\t\t}\n\t}\n\treturn buf.Bytes()\n}\n\nfunc LeEncodeByLength(length int, values ...any) []byte {\n\tb := LeEncode(values...)\n\tif len(b) < length {\n\t\tb = append(b, make([]byte, length-len(b))...)\n\t} else if len(b) > length {\n\t\tb = b[0:length]\n\t}\n\treturn b\n}\n\nfunc LeDecode(b []byte, values ...any) error {\n\tvar (\n\t\terr error\n\t\tbuf = bytes.NewBuffer(b)\n\t)\n\tfor i := 0; i < len(values); i++ {\n\t\tif err = binary.Read(buf, binary.LittleEndian, values[i]); err != nil {\n\t\t\terr = gerror.Wrap(err, `binary.Read failed`)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc LeEncodeString(s string) []byte {\n\treturn []byte(s)\n}\n\nfunc LeDecodeToString(b []byte) string {\n\treturn string(b)\n}\n\nfunc LeEncodeBool(b bool) []byte {\n\tif b {\n\t\treturn []byte{1}\n\t} else {\n\t\treturn []byte{0}\n\t}\n}\n\nfunc LeEncodeInt(i int) []byte {\n\tif i <= math.MaxInt8 {\n\t\treturn EncodeInt8(int8(i))\n\t} else if i <= math.MaxInt16 {\n\t\treturn EncodeInt16(int16(i))\n\t} else if i <= math.MaxInt32 {\n\t\treturn EncodeInt32(int32(i))\n\t} else {\n\t\treturn EncodeInt64(int64(i))\n\t}\n}\n\nfunc LeEncodeUint(i uint) []byte {\n\tif i <= math.MaxUint8 {\n\t\treturn EncodeUint8(uint8(i))\n\t} else if i <= math.MaxUint16 {\n\t\treturn EncodeUint16(uint16(i))\n\t} else if i <= math.MaxUint32 {\n\t\treturn EncodeUint32(uint32(i))\n\t} else {\n\t\treturn EncodeUint64(uint64(i))\n\t}\n}\n\nfunc LeEncodeInt8(i int8) []byte {\n\treturn []byte{byte(i)}\n}\n\nfunc LeEncodeUint8(i uint8) []byte {\n\treturn []byte{i}\n}\n\nfunc LeEncodeInt16(i int16) []byte {\n\tb := make([]byte, 2)\n\tbinary.LittleEndian.PutUint16(b, uint16(i))\n\treturn b\n}\n\nfunc LeEncodeUint16(i uint16) []byte {\n\tb := make([]byte, 2)\n\tbinary.LittleEndian.PutUint16(b, i)\n\treturn b\n}\n\nfunc LeEncodeInt32(i int32) []byte {\n\tb := make([]byte, 4)\n\tbinary.LittleEndian.PutUint32(b, uint32(i))\n\treturn b\n}\n\nfunc LeEncodeUint32(i uint32) []byte {\n\tb := make([]byte, 4)\n\tbinary.LittleEndian.PutUint32(b, i)\n\treturn b\n}\n\nfunc LeEncodeInt64(i int64) []byte {\n\tb := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(b, uint64(i))\n\treturn b\n}\n\nfunc LeEncodeUint64(i uint64) []byte {\n\tb := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(b, i)\n\treturn b\n}\n\nfunc LeEncodeFloat32(f float32) []byte {\n\tbits := math.Float32bits(f)\n\tb := make([]byte, 4)\n\tbinary.LittleEndian.PutUint32(b, bits)\n\treturn b\n}\n\nfunc LeEncodeFloat64(f float64) []byte {\n\tbits := math.Float64bits(f)\n\tb := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(b, bits)\n\treturn b\n}\n\nfunc LeDecodeToInt(b []byte) int {\n\tif len(b) < 2 {\n\t\treturn int(LeDecodeToUint8(b))\n\t} else if len(b) < 3 {\n\t\treturn int(LeDecodeToUint16(b))\n\t} else if len(b) < 5 {\n\t\treturn int(LeDecodeToUint32(b))\n\t} else {\n\t\treturn int(LeDecodeToUint64(b))\n\t}\n}\n\nfunc LeDecodeToUint(b []byte) uint {\n\tif len(b) < 2 {\n\t\treturn uint(LeDecodeToUint8(b))\n\t} else if len(b) < 3 {\n\t\treturn uint(LeDecodeToUint16(b))\n\t} else if len(b) < 5 {\n\t\treturn uint(LeDecodeToUint32(b))\n\t} else {\n\t\treturn uint(LeDecodeToUint64(b))\n\t}\n}\n\nfunc LeDecodeToBool(b []byte) bool {\n\tif len(b) == 0 {\n\t\treturn false\n\t}\n\tif bytes.Equal(b, make([]byte, len(b))) {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc LeDecodeToInt8(b []byte) int8 {\n\tif len(b) == 0 {\n\t\tpanic(`empty slice given`)\n\t}\n\treturn int8(b[0])\n}\n\nfunc LeDecodeToUint8(b []byte) uint8 {\n\tif len(b) == 0 {\n\t\tpanic(`empty slice given`)\n\t}\n\treturn b[0]\n}\n\nfunc LeDecodeToInt16(b []byte) int16 {\n\treturn int16(binary.LittleEndian.Uint16(LeFillUpSize(b, 2)))\n}\n\nfunc LeDecodeToUint16(b []byte) uint16 {\n\treturn binary.LittleEndian.Uint16(LeFillUpSize(b, 2))\n}\n\nfunc LeDecodeToInt32(b []byte) int32 {\n\treturn int32(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))\n}\n\nfunc LeDecodeToUint32(b []byte) uint32 {\n\treturn binary.LittleEndian.Uint32(LeFillUpSize(b, 4))\n}\n\nfunc LeDecodeToInt64(b []byte) int64 {\n\treturn int64(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))\n}\n\nfunc LeDecodeToUint64(b []byte) uint64 {\n\treturn binary.LittleEndian.Uint64(LeFillUpSize(b, 8))\n}\n\nfunc LeDecodeToFloat32(b []byte) float32 {\n\treturn math.Float32frombits(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))\n}\n\nfunc LeDecodeToFloat64(b []byte) float64 {\n\treturn math.Float64frombits(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))\n}\n\n// LeFillUpSize fills up the bytes `b` to given length `l` using LittleEndian.\n//\n// Note that it creates a new bytes slice by copying the original one to avoid changing\n// the original parameter bytes.\nfunc LeFillUpSize(b []byte, l int) []byte {\n\tif len(b) >= l {\n\t\treturn b[:l]\n\t}\n\tc := make([]byte, l)\n\tcopy(c, b)\n\treturn c\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_z_unit_be_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_BeEncodeAndBeDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range testData {\n\t\t\tve := gbinary.BeEncode(v)\n\t\t\tve1 := gbinary.BeEncodeByLength(len(ve), v)\n\n\t\t\t//t.Logf(\"%s:%v, encoded:%v\\n\", k, v, ve)\n\t\t\tswitch v.(type) {\n\t\t\tcase int:\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt(ve1), v)\n\t\t\tcase int8:\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt8(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt8(ve1), v)\n\t\t\tcase int16:\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt16(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt16(ve1), v)\n\t\t\tcase int32:\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt32(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt32(ve1), v)\n\t\t\tcase int64:\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt64(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToInt64(ve1), v)\n\t\t\tcase uint:\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint(ve1), v)\n\t\t\tcase uint8:\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint8(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint8(ve1), v)\n\t\t\tcase uint16:\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint16(ve1), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint16(ve), v)\n\t\t\tcase uint32:\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint32(ve1), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint32(ve), v)\n\t\t\tcase uint64:\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint64(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToUint64(ve1), v)\n\t\t\tcase bool:\n\t\t\t\tt.Assert(gbinary.BeDecodeToBool(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToBool(ve1), v)\n\t\t\tcase string:\n\t\t\t\tt.Assert(gbinary.BeDecodeToString(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToString(ve1), v)\n\t\t\tcase float32:\n\t\t\t\tt.Assert(gbinary.BeDecodeToFloat32(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToFloat32(ve1), v)\n\t\t\tcase float64:\n\t\t\t\tt.Assert(gbinary.BeDecodeToFloat64(ve), v)\n\t\t\t\tt.Assert(gbinary.BeDecodeToFloat64(ve1), v)\n\t\t\tdefault:\n\t\t\t\tif v == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tres := make([]byte, len(ve))\n\t\t\t\terr := gbinary.BeDecode(ve, res)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"test data: %s, %v, error:%v\", k, v, err)\n\t\t\t\t}\n\t\t\t\tt.Assert(res, v)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_BeEncodeStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{\"wenzi1\", 999, \"www.baidu.com\"}\n\t\tve := gbinary.BeEncode(user)\n\t\ts := gbinary.BeDecodeToString(ve)\n\t\tt.Assert(string(s), s)\n\t})\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_z_unit_le_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_LeEncodeAndLeDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range testData {\n\t\t\tve := gbinary.LeEncode(v)\n\t\t\tve1 := gbinary.LeEncodeByLength(len(ve), v)\n\n\t\t\t//t.Logf(\"%s:%v, encoded:%v\\n\", k, v, ve)\n\t\t\tswitch v.(type) {\n\t\t\tcase int:\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt(ve1), v)\n\t\t\tcase int8:\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt8(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt8(ve1), v)\n\t\t\tcase int16:\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt16(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt16(ve1), v)\n\t\t\tcase int32:\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt32(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt32(ve1), v)\n\t\t\tcase int64:\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt64(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToInt64(ve1), v)\n\t\t\tcase uint:\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint(ve1), v)\n\t\t\tcase uint8:\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint8(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint8(ve1), v)\n\t\t\tcase uint16:\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint16(ve1), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint16(ve), v)\n\t\t\tcase uint32:\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint32(ve1), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint32(ve), v)\n\t\t\tcase uint64:\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint64(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToUint64(ve1), v)\n\t\t\tcase bool:\n\t\t\t\tt.Assert(gbinary.LeDecodeToBool(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToBool(ve1), v)\n\t\t\tcase string:\n\t\t\t\tt.Assert(gbinary.LeDecodeToString(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToString(ve1), v)\n\t\t\tcase float32:\n\t\t\t\tt.Assert(gbinary.LeDecodeToFloat32(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToFloat32(ve1), v)\n\t\t\tcase float64:\n\t\t\t\tt.Assert(gbinary.LeDecodeToFloat64(ve), v)\n\t\t\t\tt.Assert(gbinary.LeDecodeToFloat64(ve1), v)\n\t\t\tdefault:\n\t\t\t\tif v == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tres := make([]byte, len(ve))\n\t\t\t\terr := gbinary.LeDecode(ve, res)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"test data: %s, %v, error:%v\", k, v, err)\n\t\t\t\t}\n\t\t\t\tt.Assert(res, v)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_LeEncodeStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{\"wenzi1\", 999, \"www.baidu.com\"}\n\t\tve := gbinary.LeEncode(user)\n\t\ts := gbinary.LeDecodeToString(ve)\n\t\tt.Assert(s, s)\n\t})\n}\n"
  },
  {
    "path": "encoding/gbinary/gbinary_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbinary_test\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype User struct {\n\tName string\n\tAge  int\n\tUrl  string\n}\n\nvar testData = map[string]any{\n\t//\"nil\":         nil,\n\t\"int\":         int(123),\n\t\"int8\":        int8(-99),\n\t\"int8.max\":    math.MaxInt8,\n\t\"int16\":       int16(123),\n\t\"int16.max\":   math.MaxInt16,\n\t\"int32\":       int32(-199),\n\t\"int32.max\":   math.MaxInt32,\n\t\"int64\":       int64(123),\n\t\"uint\":        uint(123),\n\t\"uint8\":       uint8(123),\n\t\"uint8.max\":   math.MaxUint8,\n\t\"uint16\":      uint16(9999),\n\t\"uint16.max\":  math.MaxUint16,\n\t\"uint32\":      uint32(123),\n\t\"uint64\":      uint64(123),\n\t\"bool.true\":   true,\n\t\"bool.false\":  false,\n\t\"string\":      \"hehe haha\",\n\t\"byte\":        []byte(\"hehe haha\"),\n\t\"float32\":     float32(123.456),\n\t\"float32.max\": math.MaxFloat32,\n\t\"float64\":     float64(123.456),\n}\n\nvar testBitData = []int{0, 99, 122, 129, 222, 999, 22322}\n\nfunc Test_EncodeAndDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor k, v := range testData {\n\t\t\tve := gbinary.Encode(v)\n\t\t\tve1 := gbinary.EncodeByLength(len(ve), v)\n\n\t\t\t//t.Logf(\"%s:%v, encoded:%v\\n\", k, v, ve)\n\t\t\tswitch v.(type) {\n\t\t\tcase int:\n\t\t\t\tt.Assert(gbinary.DecodeToInt(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToInt(ve1), v)\n\t\t\tcase int8:\n\t\t\t\tt.Assert(gbinary.DecodeToInt8(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToInt8(ve1), v)\n\t\t\tcase int16:\n\t\t\t\tt.Assert(gbinary.DecodeToInt16(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToInt16(ve1), v)\n\t\t\tcase int32:\n\t\t\t\tt.Assert(gbinary.DecodeToInt32(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToInt32(ve1), v)\n\t\t\tcase int64:\n\t\t\t\tt.Assert(gbinary.DecodeToInt64(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToInt64(ve1), v)\n\t\t\tcase uint:\n\t\t\t\tt.Assert(gbinary.DecodeToUint(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToUint(ve1), v)\n\t\t\tcase uint8:\n\t\t\t\tt.Assert(gbinary.DecodeToUint8(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToUint8(ve1), v)\n\t\t\tcase uint16:\n\t\t\t\tt.Assert(gbinary.DecodeToUint16(ve1), v)\n\t\t\t\tt.Assert(gbinary.DecodeToUint16(ve), v)\n\t\t\tcase uint32:\n\t\t\t\tt.Assert(gbinary.DecodeToUint32(ve1), v)\n\t\t\t\tt.Assert(gbinary.DecodeToUint32(ve), v)\n\t\t\tcase uint64:\n\t\t\t\tt.Assert(gbinary.DecodeToUint64(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToUint64(ve1), v)\n\t\t\tcase bool:\n\t\t\t\tt.Assert(gbinary.DecodeToBool(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToBool(ve1), v)\n\t\t\tcase string:\n\t\t\t\tt.Assert(gbinary.DecodeToString(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToString(ve1), v)\n\t\t\tcase float32:\n\t\t\t\tt.Assert(gbinary.DecodeToFloat32(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToFloat32(ve1), v)\n\t\t\tcase float64:\n\t\t\t\tt.Assert(gbinary.DecodeToFloat64(ve), v)\n\t\t\t\tt.Assert(gbinary.DecodeToFloat64(ve1), v)\n\t\t\tdefault:\n\t\t\t\tif v == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tres := make([]byte, len(ve))\n\t\t\t\terr := gbinary.Decode(ve, res)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Errorf(\"test data: %s, %v, error:%v\", k, v, err)\n\t\t\t\t}\n\t\t\t\tt.Assert(res, v)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_EncodeStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{\"wenzi1\", 999, \"www.baidu.com\"}\n\t\tve := gbinary.Encode(user)\n\t\ts := gbinary.DecodeToString(ve)\n\t\tt.Assert(s, s)\n\t})\n}\n\nfunc Test_Bits(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := range testBitData {\n\t\t\tbits := make([]gbinary.Bit, 0)\n\t\t\tres := gbinary.EncodeBits(bits, testBitData[i], 64)\n\n\t\t\tt.Assert(gbinary.DecodeBits(res), testBitData[i])\n\t\t\tt.Assert(gbinary.DecodeBitsToUint(res), uint(testBitData[i]))\n\n\t\t\tt.Assert(gbinary.DecodeBytesToBits(gbinary.EncodeBitsToBytes(res)), res)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "encoding/gcharset/gcharset.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcharset implements character-set conversion functionality.\n//\n// Supported Character Set:\n//\n// Chinese : GBK/GB18030/GB2312/Big5\n//\n// Japanese: EUCJP/ISO2022JP/ShiftJIS\n//\n// Korean  : EUCKR\n//\n// Unicode : UTF-8/UTF-16/UTF-16BE/UTF-16LE\n//\n// Other   : macintosh/IBM*/Windows*/ISO-*\npackage gcharset\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\n\t\"golang.org/x/text/encoding\"\n\t\"golang.org/x/text/encoding/ianaindex\"\n\t\"golang.org/x/text/transform\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// Alias for charsets.\nvar charsetAlias = map[string]string{\n\t\"HZGB2312\": \"HZ-GB-2312\",\n\t\"hzgb2312\": \"HZ-GB-2312\",\n\t\"GB2312\":   \"HZ-GB-2312\",\n\t\"gb2312\":   \"HZ-GB-2312\",\n}\n\n// Supported returns whether charset `charset` is supported.\nfunc Supported(charset string) bool {\n\treturn getEncoding(charset) != nil\n}\n\n// Convert converts `src` charset encoding from `srcCharset` to `dstCharset`,\n// and returns the converted string.\n// It returns `src` as `dst` if it fails converting.\nfunc Convert(dstCharset string, srcCharset string, src string) (dst string, err error) {\n\tif dstCharset == srcCharset {\n\t\treturn src, nil\n\t}\n\tdst = src\n\t// Converting `src` to UTF-8.\n\tif srcCharset != \"UTF-8\" {\n\t\tif e := getEncoding(srcCharset); e != nil {\n\t\t\ttmp, err := io.ReadAll(\n\t\t\t\ttransform.NewReader(bytes.NewReader([]byte(src)), e.NewDecoder()),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", gerror.Wrapf(err, `convert string \"%s\" to utf8 failed`, srcCharset)\n\t\t\t}\n\t\t\tsrc = string(tmp)\n\t\t} else {\n\t\t\treturn dst, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported srcCharset \"%s\"`, srcCharset)\n\t\t}\n\t}\n\t// Do the converting from UTF-8 to `dstCharset`.\n\tif dstCharset != \"UTF-8\" {\n\t\tif e := getEncoding(dstCharset); e != nil {\n\t\t\ttmp, err := io.ReadAll(\n\t\t\t\ttransform.NewReader(bytes.NewReader([]byte(src)), e.NewEncoder()),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", gerror.Wrapf(err, `convert string from utf8 to \"%s\" failed`, dstCharset)\n\t\t\t}\n\t\t\tdst = string(tmp)\n\t\t} else {\n\t\t\treturn dst, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported dstCharset \"%s\"`, dstCharset)\n\t\t}\n\t} else {\n\t\tdst = src\n\t}\n\treturn dst, nil\n}\n\n// ToUTF8 converts `src` charset encoding from `srcCharset` to UTF-8 ,\n// and returns the converted string.\nfunc ToUTF8(srcCharset string, src string) (dst string, err error) {\n\treturn Convert(\"UTF-8\", srcCharset, src)\n}\n\n// UTF8To converts `src` charset encoding from UTF-8 to `dstCharset`,\n// and returns the converted string.\nfunc UTF8To(dstCharset string, src string) (dst string, err error) {\n\treturn Convert(dstCharset, \"UTF-8\", src)\n}\n\n// getEncoding returns the encoding.Encoding interface object for `charset`.\n// It returns nil if `charset` is not supported.\nfunc getEncoding(charset string) encoding.Encoding {\n\tif c, ok := charsetAlias[charset]; ok {\n\t\tcharset = c\n\t}\n\tenc, err := ianaindex.MIB.Encoding(charset)\n\tif err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t}\n\treturn enc\n}\n"
  },
  {
    "path": "encoding/gcharset/gcharset_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcharset_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcharset\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar testData = []struct {\n\tutf8, other, otherEncoding string\n}{\n\t{\"Résumé\", \"Résumé\", \"utf-8\"},\n\t//{\"Résumé\", \"R\\xe9sum\\xe9\", \"latin-1\"},\n\t{\"これは漢字です。\", \"S0\\x8c0o0\\\"oW[g0Y0\\x020\", \"UTF-16LE\"},\n\t{\"これは漢字です。\", \"0S0\\x8c0oo\\\"[W0g0Y0\\x02\", \"UTF-16BE\"},\n\t{\"これは漢字です。\", \"\\xfe\\xff0S0\\x8c0oo\\\"[W0g0Y0\\x02\", \"UTF-16\"},\n\t{\"𝄢𝄞𝄪𝄫\", \"\\xfe\\xff\\xd8\\x34\\xdd\\x22\\xd8\\x34\\xdd\\x1e\\xd8\\x34\\xdd\\x2a\\xd8\\x34\\xdd\\x2b\", \"UTF-16\"},\n\t//{\"Hello, world\", \"Hello, world\", \"ASCII\"},\n\t{\"Gdańsk\", \"Gda\\xf1sk\", \"ISO-8859-2\"},\n\t{\"Ââ Čč Đđ Ŋŋ Õõ Šš Žž Åå Ää\", \"\\xc2\\xe2 \\xc8\\xe8 \\xa9\\xb9 \\xaf\\xbf \\xd5\\xf5 \\xaa\\xba \\xac\\xbc \\xc5\\xe5 \\xc4\\xe4\", \"ISO-8859-10\"},\n\t//{\"สำหรับ\", \"\\xca\\xd3\\xcb\\xc3\\u047a\", \"ISO-8859-11\"},\n\t{\"latviešu\", \"latvie\\xf0u\", \"ISO-8859-13\"},\n\t{\"Seònaid\", \"Se\\xf2naid\", \"ISO-8859-14\"},\n\t{\"€1 is cheap\", \"\\xa41 is cheap\", \"ISO-8859-15\"},\n\t{\"românește\", \"rom\\xe2ne\\xbate\", \"ISO-8859-16\"},\n\t{\"nutraĵo\", \"nutra\\xbco\", \"ISO-8859-3\"},\n\t{\"Kalâdlit\", \"Kal\\xe2dlit\", \"ISO-8859-4\"},\n\t{\"русский\", \"\\xe0\\xe3\\xe1\\xe1\\xda\\xd8\\xd9\", \"ISO-8859-5\"},\n\t{\"ελληνικά\", \"\\xe5\\xeb\\xeb\\xe7\\xed\\xe9\\xea\\xdc\", \"ISO-8859-7\"},\n\t{\"Kağan\", \"Ka\\xf0an\", \"ISO-8859-9\"},\n\t{\"Résumé\", \"R\\x8esum\\x8e\", \"macintosh\"},\n\t{\"Gdańsk\", \"Gda\\xf1sk\", \"windows-1250\"},\n\t{\"русский\", \"\\xf0\\xf3\\xf1\\xf1\\xea\\xe8\\xe9\", \"windows-1251\"},\n\t{\"Résumé\", \"R\\xe9sum\\xe9\", \"windows-1252\"},\n\t{\"ελληνικά\", \"\\xe5\\xeb\\xeb\\xe7\\xed\\xe9\\xea\\xdc\", \"windows-1253\"},\n\t{\"Kağan\", \"Ka\\xf0an\", \"windows-1254\"},\n\t{\"עִבְרִית\", \"\\xf2\\xc4\\xe1\\xc0\\xf8\\xc4\\xe9\\xfa\", \"windows-1255\"},\n\t{\"العربية\", \"\\xc7\\xe1\\xda\\xd1\\xc8\\xed\\xc9\", \"windows-1256\"},\n\t{\"latviešu\", \"latvie\\xf0u\", \"windows-1257\"},\n\t{\"Việt\", \"Vi\\xea\\xf2t\", \"windows-1258\"},\n\t{\"สำหรับ\", \"\\xca\\xd3\\xcb\\xc3\\u047a\", \"windows-874\"},\n\t{\"русский\", \"\\xd2\\xd5\\xd3\\xd3\\xcb\\xc9\\xca\", \"KOI8-R\"},\n\t{\"українська\", \"\\xd5\\xcb\\xd2\\xc1\\xa7\\xce\\xd3\\xd8\\xcb\\xc1\", \"KOI8-U\"},\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb1`\\xa5\\u03b0\\xea\\xa6r\\xbc\\u0437\\u01e6r\\xc5\\xe9\\xaa\\xed\", \"big5\"},\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\", \"gbk\"},\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\", \"gb18030\"},\n\t{\"花间一壶酒，独酌无相亲。\", \"~{;(<dR;:x>F#,6@WCN^O`GW!#\", \"GB2312\"},\n\t{\"花间一壶酒，独酌无相亲。\", \"~{;(<dR;:x>F#,6@WCN^O`GW!#\", \"HZGB2312\"},\n\t{\"עִבְרִית\", \"\\x81\\x30\\xfb\\x30\\x81\\x30\\xf6\\x34\\x81\\x30\\xf9\\x33\\x81\\x30\\xf6\\x30\\x81\\x30\\xfb\\x36\\x81\\x30\\xf6\\x34\\x81\\x30\\xfa\\x31\\x81\\x30\\xfb\\x38\", \"gb18030\"},\n\t{\"㧯\", \"\\x82\\x31\\x89\\x38\", \"gb18030\"},\n\t{\"㧯\", \"㧯\", \"UTF-8\"},\n\t//{\"これは漢字です。\", \"\\x82\\xb1\\x82\\xea\\x82\\xcd\\x8a\\xbf\\x8e\\x9a\\x82\\xc5\\x82\\xb7\\x81B\", \"SJIS\"},\n\t{\"これは漢字です。\", \"\\xa4\\xb3\\xa4\\xec\\xa4\\u03f4\\xc1\\xbb\\xfa\\xa4\\u01e4\\xb9\\xa1\\xa3\", \"EUC-JP\"},\n}\n\nfunc TestDecode(t *testing.T) {\n\tfor _, data := range testData {\n\t\tstr := \"\"\n\t\tstr, err := gcharset.Convert(\"UTF-8\", data.otherEncoding, data.other)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Could not create decoder for %v\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif str != data.utf8 {\n\t\t\tt.Errorf(\"Unexpected value: %#v (expected %#v) %v\", str, data.utf8, data.otherEncoding)\n\t\t}\n\t}\n}\n\nfunc TestUTF8To(t *testing.T) {\n\tfor _, data := range testData {\n\t\tstr := \"\"\n\t\tstr, err := gcharset.UTF8To(data.otherEncoding, data.utf8)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Could not create decoder for %v\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif str != data.other {\n\t\t\tt.Errorf(\"Unexpected value: %#v (expected %#v) %v\", str, data.other, data.otherEncoding)\n\t\t}\n\t}\n}\n\nfunc TestToUTF8(t *testing.T) {\n\tfor _, data := range testData {\n\t\tstr := \"\"\n\t\tstr, err := gcharset.ToUTF8(data.otherEncoding, data.other)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Could not create decoder for %v\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif str != data.utf8 {\n\t\t\tt.Errorf(\"Unexpected value: %#v (expected %#v)\", str, data.utf8)\n\t\t}\n\t}\n}\n\nfunc TestEncode(t *testing.T) {\n\tfor _, data := range testData {\n\t\tstr := \"\"\n\t\tstr, err := gcharset.Convert(data.otherEncoding, \"UTF-8\", data.utf8)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Could not create decoder for %v\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif str != data.other {\n\t\t\tt.Errorf(\"Unexpected value: %#v (expected %#v)\", str, data.other)\n\t\t}\n\t}\n}\n\nfunc TestConvert(t *testing.T) {\n\tsrcCharset := \"big5\"\n\tsrc := \"Hello \\xb1`\\xa5\\u03b0\\xea\\xa6r\\xbc\\u0437\\u01e6r\\xc5\\xe9\\xaa\\xed\"\n\tdstCharset := \"gbk\"\n\tdst := \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\"\n\n\tstr, err := gcharset.Convert(dstCharset, srcCharset, src)\n\tif err != nil {\n\t\tt.Errorf(\"convert error. %v\", err)\n\t\treturn\n\t}\n\n\tif str != dst {\n\t\tt.Errorf(\"unexpected value:%#v (expected %#v)\", str, dst)\n\t}\n}\n\nfunc TestConvertErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrcCharset := \"big5\"\n\t\tdstCharset := \"gbk\"\n\t\tsrc := \"Hello \\xb1`\\xa5\\u03b0\\xea\\xa6r\\xbc\\u0437\\u01e6r\\xc5\\xe9\\xaa\\xed\"\n\n\t\ts1, e1 := gcharset.Convert(srcCharset, srcCharset, src)\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(s1, src)\n\n\t\ts2, e2 := gcharset.Convert(dstCharset, \"no this charset\", src)\n\t\tt.AssertNE(e2, nil)\n\t\tt.Assert(s2, src)\n\n\t\ts3, e3 := gcharset.Convert(\"no this charset\", srcCharset, src)\n\t\tt.AssertNE(e3, nil)\n\t\tt.Assert(s3, src)\n\t})\n}\n\nfunc TestSupported(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gcharset.Supported(\"UTF-8\"), true)\n\t\tt.Assert(gcharset.Supported(\"UTF-80\"), false)\n\t})\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcompress provides kinds of compression algorithms for binary/bytes data.\npackage gcompress\n"
  },
  {
    "path": "encoding/gcompress/gcompress_gzip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcompress\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// Gzip compresses `data` using gzip algorithm.\n// The optional parameter `level` specifies the compression level from\n// 1 to 9 which means from none to the best compression.\n//\n// Note that it returns error if given `level` is invalid.\nfunc Gzip(data []byte, level ...int) ([]byte, error) {\n\tvar (\n\t\twriter *gzip.Writer\n\t\tbuf    bytes.Buffer\n\t\terr    error\n\t)\n\tif len(level) > 0 {\n\t\twriter, err = gzip.NewWriterLevel(&buf, level[0])\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `gzip.NewWriterLevel failed for level \"%d\"`, level[0])\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\twriter = gzip.NewWriter(&buf)\n\t}\n\tif _, err = writer.Write(data); err != nil {\n\t\terr = gerror.Wrap(err, `writer.Write failed`)\n\t\treturn nil, err\n\t}\n\tif err = writer.Close(); err != nil {\n\t\terr = gerror.Wrap(err, `writer.Close failed`)\n\t\treturn nil, err\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// GzipFile compresses the file `src` to `dst` using gzip algorithm.\nfunc GzipFile(srcFilePath, dstFilePath string, level ...int) (err error) {\n\tdstFile, err := gfile.Create(dstFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dstFile.Close()\n\n\treturn GzipPathWriter(srcFilePath, dstFile, level...)\n}\n\n// GzipPathWriter compresses `filePath` to `writer` using gzip compressing algorithm.\n//\n// Note that the parameter `path` can be either a directory or a file.\nfunc GzipPathWriter(filePath string, writer io.Writer, level ...int) error {\n\tvar (\n\t\tgzipWriter *gzip.Writer\n\t\terr        error\n\t)\n\tsrcFile, err := gfile.Open(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer srcFile.Close()\n\n\tif len(level) > 0 {\n\t\tgzipWriter, err = gzip.NewWriterLevel(writer, level[0])\n\t\tif err != nil {\n\t\t\treturn gerror.Wrap(err, `gzip.NewWriterLevel failed`)\n\t\t}\n\t} else {\n\t\tgzipWriter = gzip.NewWriter(writer)\n\t}\n\tdefer gzipWriter.Close()\n\n\tif _, err = io.Copy(gzipWriter, srcFile); err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// UnGzip decompresses `data` with gzip algorithm.\nfunc UnGzip(data []byte) ([]byte, error) {\n\tvar buf bytes.Buffer\n\treader, err := gzip.NewReader(bytes.NewReader(data))\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `gzip.NewReader failed`)\n\t\treturn nil, err\n\t}\n\tif _, err = io.Copy(&buf, reader); err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn nil, err\n\t}\n\tif err = reader.Close(); err != nil {\n\t\terr = gerror.Wrap(err, `reader.Close failed`)\n\t\treturn buf.Bytes(), err\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// UnGzipFile decompresses srcFilePath `src` to `dst` using gzip algorithm.\nfunc UnGzipFile(srcFilePath, dstFilePath string) error {\n\tsrcFile, err := gfile.Open(srcFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer srcFile.Close()\n\tdstFile, err := gfile.Create(dstFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dstFile.Close()\n\n\treader, err := gzip.NewReader(srcFile)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `gzip.NewReader failed`)\n\t\treturn err\n\t}\n\tdefer reader.Close()\n\n\tif _, err = io.Copy(dstFile, reader); err != nil {\n\t\terr = gerror.Wrap(err, `io.Copy failed`)\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress_z_unit_gzip_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcompress_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Gzip_UnGzip(t *testing.T) {\n\tvar (\n\t\tsrc  = \"Hello World!!\"\n\t\tgzip = []byte{\n\t\t\t0x1f, 0x8b, 0x08, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00, 0xff,\n\t\t\t0xf2, 0x48, 0xcd, 0xc9, 0xc9,\n\t\t\t0x57, 0x08, 0xcf, 0x2f, 0xca,\n\t\t\t0x49, 0x51, 0x54, 0x04, 0x04,\n\t\t\t0x00, 0x00, 0xff, 0xff, 0x9d,\n\t\t\t0x24, 0xa8, 0xd1, 0x0d, 0x00,\n\t\t\t0x00, 0x00,\n\t\t}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarr := []byte(src)\n\t\tdata, _ := gcompress.Gzip(arr)\n\t\tt.Assert(data, gzip)\n\n\t\tdata, _ = gcompress.UnGzip(gzip)\n\t\tt.Assert(data, arr)\n\n\t\tdata, _ = gcompress.UnGzip(gzip[1:])\n\t\tt.Assert(data, nil)\n\t})\n}\n\nfunc Test_Gzip_UnGzip_File(t *testing.T) {\n\tvar (\n\t\tsrcPath  = gtest.DataPath(\"gzip\", \"file.txt\")\n\t\tdstPath1 = gfile.Temp(gtime.TimestampNanoStr(), \"gzip.zip\")\n\t\tdstPath2 = gfile.Temp(gtime.TimestampNanoStr(), \"file.txt\")\n\t)\n\n\t// Compress.\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gcompress.GzipFile(srcPath, dstPath1, 9)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath1)\n\t\tt.Assert(gfile.Exists(dstPath1), true)\n\n\t\t// Decompress.\n\t\terr = gcompress.UnGzipFile(dstPath1, dstPath2)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dstPath2)\n\t\tt.Assert(gfile.Exists(dstPath2), true)\n\n\t\tt.Assert(gfile.GetContents(srcPath), gfile.GetContents(dstPath2))\n\t})\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress_z_unit_zip_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcompress_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ZipPath(t *testing.T) {\n\t// file\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrcPath := gtest.DataPath(\"zip\", \"path1\", \"1.txt\")\n\t\tdstPath := gtest.DataPath(\"zip\", \"zip.zip\")\n\n\t\tt.Assert(gfile.Exists(dstPath), false)\n\t\tt.Assert(gcompress.ZipPath(srcPath, dstPath), nil)\n\t\tt.Assert(gfile.Exists(dstPath), true)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// unzip to temporary dir.\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.Assert(gfile.Mkdir(tempDirPath), nil)\n\t\tt.Assert(gcompress.UnZipFile(dstPath, tempDirPath), nil)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"1.txt\")),\n\t\t\tgfile.GetContents(srcPath),\n\t\t)\n\t})\n\t// multiple files\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath1 = gtest.DataPath(\"zip\", \"path1\", \"1.txt\")\n\t\t\tsrcPath2 = gtest.DataPath(\"zip\", \"path2\", \"2.txt\")\n\t\t\tdstPath  = gfile.Temp(gtime.TimestampNanoStr(), \"zip.zip\")\n\t\t)\n\t\tif p := gfile.Dir(dstPath); !gfile.Exists(p) {\n\t\t\tt.Assert(gfile.Mkdir(p), nil)\n\t\t}\n\n\t\tt.Assert(gfile.Exists(dstPath), false)\n\t\terr := gcompress.ZipPath(srcPath1+\",\"+srcPath2, dstPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(dstPath), true)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// unzip to another temporary dir.\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.Assert(gfile.Mkdir(tempDirPath), nil)\n\t\terr = gcompress.UnZipFile(dstPath, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"1.txt\")),\n\t\t\tgfile.GetContents(srcPath1),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"2.txt\")),\n\t\t\tgfile.GetContents(srcPath2),\n\t\t)\n\t})\n\t// one dir and one file.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath1 = gtest.DataPath(\"zip\", \"path1\")\n\t\t\tsrcPath2 = gtest.DataPath(\"zip\", \"path2\", \"2.txt\")\n\t\t\tdstPath  = gfile.Temp(gtime.TimestampNanoStr(), \"zip.zip\")\n\t\t)\n\t\tif p := gfile.Dir(dstPath); !gfile.Exists(p) {\n\t\t\tt.Assert(gfile.Mkdir(p), nil)\n\t\t}\n\n\t\tt.Assert(gfile.Exists(dstPath), false)\n\t\terr := gcompress.ZipPath(srcPath1+\",\"+srcPath2, dstPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(dstPath), true)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\t// unzip to another temporary dir.\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.Assert(gfile.Mkdir(tempDirPath), nil)\n\t\terr = gcompress.UnZipFile(dstPath, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path1\", \"1.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath1, \"1.txt\")),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"2.txt\")),\n\t\t\tgfile.GetContents(srcPath2),\n\t\t)\n\t})\n\t// directory.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrcPath := gtest.DataPath(\"zip\")\n\t\tdstPath := gtest.DataPath(\"zip\", \"zip.zip\")\n\n\t\tpwd := gfile.Pwd()\n\t\terr := gfile.Chdir(srcPath)\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(dstPath), false)\n\t\terr = gcompress.ZipPath(srcPath, dstPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(dstPath), true)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(tempDirPath)\n\t\tt.AssertNil(err)\n\n\t\terr = gcompress.UnZipFile(dstPath, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"zip\", \"path1\", \"1.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path1\", \"1.txt\")),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"zip\", \"path2\", \"2.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path2\", \"2.txt\")),\n\t\t)\n\t})\n\t// multiple directory paths joined using char ','.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath  = gtest.DataPath(\"zip\")\n\t\t\tsrcPath1 = gtest.DataPath(\"zip\", \"path1\")\n\t\t\tsrcPath2 = gtest.DataPath(\"zip\", \"path2\")\n\t\t\tdstPath  = gtest.DataPath(\"zip\", \"zip.zip\")\n\t\t)\n\t\tpwd := gfile.Pwd()\n\t\terr := gfile.Chdir(srcPath)\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.Exists(dstPath), false)\n\t\terr = gcompress.ZipPath(srcPath1+\", \"+srcPath2, dstPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(dstPath), true)\n\t\tdefer gfile.Remove(dstPath)\n\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(tempDirPath)\n\t\tt.AssertNil(err)\n\n\t\tzipContent := gfile.GetBytes(dstPath)\n\t\tt.AssertGT(len(zipContent), 0)\n\t\terr = gcompress.UnZipContent(zipContent, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path1\", \"1.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path1\", \"1.txt\")),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path2\", \"2.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path2\", \"2.txt\")),\n\t\t)\n\t})\n}\n\nfunc Test_ZipPathWriter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath  = gtest.DataPath(\"zip\")\n\t\t\tsrcPath1 = gtest.DataPath(\"zip\", \"path1\")\n\t\t\tsrcPath2 = gtest.DataPath(\"zip\", \"path2\")\n\t\t)\n\t\tpwd := gfile.Pwd()\n\t\terr := gfile.Chdir(srcPath)\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.AssertNil(err)\n\n\t\twriter := bytes.NewBuffer(nil)\n\t\tt.Assert(writer.Len(), 0)\n\t\terr = gcompress.ZipPathWriter(srcPath1+\", \"+srcPath2, writer)\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(writer.Len(), 0)\n\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(tempDirPath)\n\t\tt.AssertNil(err)\n\n\t\tzipContent := writer.Bytes()\n\t\tt.AssertGT(len(zipContent), 0)\n\t\terr = gcompress.UnZipContent(zipContent, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path1\", \"1.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path1\", \"1.txt\")),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path2\", \"2.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path2\", \"2.txt\")),\n\t\t)\n\t})\n}\n\nfunc Test_ZipPathContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath  = gtest.DataPath(\"zip\")\n\t\t\tsrcPath1 = gtest.DataPath(\"zip\", \"path1\")\n\t\t\tsrcPath2 = gtest.DataPath(\"zip\", \"path2\")\n\t\t)\n\t\tpwd := gfile.Pwd()\n\t\terr := gfile.Chdir(srcPath)\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.AssertNil(err)\n\n\t\ttempDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(tempDirPath)\n\t\tt.AssertNil(err)\n\n\t\tzipContent, err := gcompress.ZipPathContent(srcPath1 + \", \" + srcPath2)\n\t\tt.AssertGT(len(zipContent), 0)\n\t\terr = gcompress.UnZipContent(zipContent, tempDirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tempDirPath)\n\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path1\", \"1.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path1\", \"1.txt\")),\n\t\t)\n\t\tt.Assert(\n\t\t\tgfile.GetContents(gfile.Join(tempDirPath, \"path2\", \"2.txt\")),\n\t\t\tgfile.GetContents(gfile.Join(srcPath, \"path2\", \"2.txt\")),\n\t\t)\n\t})\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress_z_unit_zlib_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcompress_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Zlib_UnZlib(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := \"hello, world\\n\"\n\t\tdst := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207, 47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}\n\t\tdata, _ := gcompress.Zlib([]byte(src))\n\t\tt.Assert(data, dst)\n\n\t\tdata, _ = gcompress.UnZlib(dst)\n\t\tt.Assert(data, []byte(src))\n\n\t\tdata, _ = gcompress.Zlib(nil)\n\t\tt.Assert(data, nil)\n\t\tdata, _ = gcompress.UnZlib(nil)\n\t\tt.Assert(data, nil)\n\n\t\tdata, _ = gcompress.UnZlib(dst[1:])\n\t\tt.Assert(data, nil)\n\t})\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress_zip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcompress\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// ZipPath compresses `fileOrFolderPaths` to `dstFilePath` using zip compressing algorithm.\n//\n// The parameter `paths` can be either a directory or a file, which\n// supports multiple paths join with ','.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\nfunc ZipPath(fileOrFolderPaths, dstFilePath string, prefix ...string) error {\n\twriter, err := os.Create(dstFilePath)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Create failed for name \"%s\"`, dstFilePath)\n\t\treturn err\n\t}\n\tdefer writer.Close()\n\tzipWriter := zip.NewWriter(writer)\n\tdefer zipWriter.Close()\n\tfor _, path := range strings.Split(fileOrFolderPaths, \",\") {\n\t\tpath = strings.TrimSpace(path)\n\t\tif err = doZipPathWriter(path, gfile.RealPath(dstFilePath), zipWriter, prefix...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ZipPathWriter compresses `fileOrFolderPaths` to `writer` using zip compressing algorithm.\n//\n// Note that the parameter `fileOrFolderPaths` can be either a directory or a file, which\n// supports multiple paths join with ','.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\nfunc ZipPathWriter(fileOrFolderPaths string, writer io.Writer, prefix ...string) error {\n\tzipWriter := zip.NewWriter(writer)\n\tdefer zipWriter.Close()\n\tfor _, path := range strings.Split(fileOrFolderPaths, \",\") {\n\t\tpath = strings.TrimSpace(path)\n\t\tif err := doZipPathWriter(path, \"\", zipWriter, prefix...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ZipPathContent compresses `fileOrFolderPaths` to []byte using zip compressing algorithm.\n//\n// Note that the parameter `fileOrFolderPaths` can be either a directory or a file, which\n// supports multiple paths join with ','.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\nfunc ZipPathContent(fileOrFolderPaths string, prefix ...string) ([]byte, error) {\n\tvar (\n\t\terr    error\n\t\tbuffer = bytes.NewBuffer(nil)\n\t)\n\tif err = ZipPathWriter(fileOrFolderPaths, buffer, prefix...); err != nil {\n\t\treturn nil, err\n\t}\n\treturn buffer.Bytes(), nil\n}\n\n// doZipPathWriter compresses given `fileOrFolderPaths` and writes the content to `zipWriter`.\n//\n// The parameter `fileOrFolderPath` can be either a single file or folder path.\n// The parameter `exclude` specifies the exclusive file path that is not compressed to `zipWriter`,\n// commonly the destination zip file path.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\nfunc doZipPathWriter(fileOrFolderPath string, exclude string, zipWriter *zip.Writer, prefix ...string) error {\n\tvar (\n\t\terr   error\n\t\tfiles []string\n\t)\n\tfileOrFolderPath, err = gfile.Search(fileOrFolderPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif gfile.IsDir(fileOrFolderPath) {\n\t\tfiles, err = gfile.ScanDir(fileOrFolderPath, \"*\", true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tfiles = []string{fileOrFolderPath}\n\t}\n\theaderPrefix := \"\"\n\tif len(prefix) > 0 && prefix[0] != \"\" {\n\t\theaderPrefix = prefix[0]\n\t}\n\theaderPrefix = strings.TrimRight(headerPrefix, \"\\\\/\")\n\tif gfile.IsDir(fileOrFolderPath) {\n\t\tif len(headerPrefix) > 0 {\n\t\t\theaderPrefix += \"/\"\n\t\t} else {\n\t\t\theaderPrefix = gfile.Basename(fileOrFolderPath)\n\t\t}\n\t}\n\theaderPrefix = strings.ReplaceAll(headerPrefix, \"//\", \"/\")\n\tfor _, file := range files {\n\t\tif exclude == file {\n\t\t\tintlog.Printf(context.TODO(), `exclude file path: %s`, file)\n\t\t\tcontinue\n\t\t}\n\t\tdir := gfile.Dir(file[len(fileOrFolderPath):])\n\t\tif dir == \".\" {\n\t\t\tdir = \"\"\n\t\t}\n\t\tif err = zipFile(file, headerPrefix+dir, zipWriter); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// UnZipFile decompresses `archive` to `dstFolderPath` using zip compressing algorithm.\n//\n// The parameter `dstFolderPath` should be a directory.\n// The optional parameter `zippedPrefix` specifies the unzipped path of `zippedFilePath`,\n// which can be used to specify part of the archive file to unzip.\nfunc UnZipFile(zippedFilePath, dstFolderPath string, zippedPrefix ...string) error {\n\treaderCloser, err := zip.OpenReader(zippedFilePath)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `zip.OpenReader failed for name \"%s\"`, dstFolderPath)\n\t\treturn err\n\t}\n\tdefer readerCloser.Close()\n\treturn unZipFileWithReader(&readerCloser.Reader, dstFolderPath, zippedPrefix...)\n}\n\n// UnZipContent decompresses `zippedContent` to `dstFolderPath` using zip compressing algorithm.\n//\n// The parameter `dstFolderPath` should be a directory.\n// The parameter `zippedPrefix` specifies the unzipped path of `zippedContent`,\n// which can be used to specify part of the archive file to unzip.\nfunc UnZipContent(zippedContent []byte, dstFolderPath string, zippedPrefix ...string) error {\n\treader, err := zip.NewReader(bytes.NewReader(zippedContent), int64(len(zippedContent)))\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `zip.NewReader failed`)\n\t\treturn err\n\t}\n\treturn unZipFileWithReader(reader, dstFolderPath, zippedPrefix...)\n}\n\nfunc unZipFileWithReader(reader *zip.Reader, dstFolderPath string, zippedPrefix ...string) error {\n\tprefix := \"\"\n\tif len(zippedPrefix) > 0 {\n\t\tprefix = gstr.Replace(zippedPrefix[0], `\\`, `/`)\n\t}\n\tif err := os.MkdirAll(dstFolderPath, 0755); err != nil {\n\t\treturn err\n\t}\n\tvar (\n\t\tname    string\n\t\tdstPath string\n\t\tdstDir  string\n\t)\n\tfor _, file := range reader.File {\n\t\tname = gstr.Replace(file.Name, `\\`, `/`)\n\t\tname = gstr.Trim(name, \"/\")\n\t\tif prefix != \"\" {\n\t\t\tif !strings.HasPrefix(name, prefix) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tname = name[len(prefix):]\n\t\t}\n\t\tdstPath = filepath.Join(dstFolderPath, name)\n\t\tif file.FileInfo().IsDir() {\n\t\t\t_ = os.MkdirAll(dstPath, file.Mode())\n\t\t\tcontinue\n\t\t}\n\t\tdstDir = filepath.Dir(dstPath)\n\t\tif len(dstDir) > 0 {\n\t\t\tif _, err := os.Stat(dstDir); os.IsNotExist(err) {\n\t\t\t\tif err = os.MkdirAll(dstDir, 0755); err != nil {\n\t\t\t\t\terr = gerror.Wrapf(err, `os.MkdirAll failed for path \"%s\"`, dstDir)\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfileReader, err := file.Open()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `file.Open failed`)\n\t\t\treturn err\n\t\t}\n\t\t// The fileReader is closed in function doCopyForUnZipFileWithReader.\n\t\tif err = doCopyForUnZipFileWithReader(file, fileReader, dstPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc doCopyForUnZipFileWithReader(file *zip.File, fileReader io.ReadCloser, dstPath string) error {\n\tdefer fileReader.Close()\n\ttargetFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.OpenFile failed for name \"%s\"`, dstPath)\n\t\treturn err\n\t}\n\tdefer targetFile.Close()\n\n\tif _, err = io.Copy(targetFile, fileReader); err != nil {\n\t\terr = gerror.Wrapf(err, `io.Copy failed from \"%s\" to \"%s\"`, file.Name, dstPath)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// zipFile compresses the file of given `filePath` and writes the content to `zw`.\n// The parameter `prefix` indicates the path prefix for zip file.\nfunc zipFile(filePath string, prefix string, zw *zip.Writer) error {\n\tfile, err := os.Open(filePath)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, filePath)\n\t\treturn err\n\t}\n\tdefer file.Close()\n\n\tinfo, err := file.Stat()\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `file.Stat failed for name \"%s\"`, filePath)\n\t\treturn err\n\t}\n\n\theader, err := createFileHeader(info, prefix)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif info.IsDir() {\n\t\theader.Name += \"/\"\n\t} else {\n\t\theader.Method = zip.Deflate\n\t}\n\n\twriter, err := zw.CreateHeader(header)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `zip.Writer.CreateHeader failed for header \"%#v\"`, header)\n\t\treturn err\n\t}\n\tif !info.IsDir() {\n\t\tif _, err = io.Copy(writer, file); err != nil {\n\t\t\terr = gerror.Wrapf(err, `io.Copy failed from \"%s\" to \"%s\"`, filePath, header.Name)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {\n\theader, err := zip.FileInfoHeader(info)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `zip.FileInfoHeader failed for info \"%#v\"`, info)\n\t\treturn nil, err\n\t}\n\n\tif len(prefix) > 0 {\n\t\tprefix = strings.ReplaceAll(prefix, `\\`, `/`)\n\t\tprefix = strings.TrimRight(prefix, `/`)\n\t\theader.Name = prefix + `/` + header.Name\n\t}\n\treturn header, nil\n}\n"
  },
  {
    "path": "encoding/gcompress/gcompress_zlib.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcompress provides kinds of compression algorithms for binary/bytes data.\npackage gcompress\n\nimport (\n\t\"bytes\"\n\t\"compress/zlib\"\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Zlib compresses `data` with zlib algorithm.\nfunc Zlib(data []byte) ([]byte, error) {\n\tif len(data) < 13 {\n\t\treturn data, nil\n\t}\n\tvar (\n\t\terr    error\n\t\tin     bytes.Buffer\n\t\twriter = zlib.NewWriter(&in)\n\t)\n\n\tif _, err = writer.Write(data); err != nil {\n\t\terr = gerror.Wrapf(err, `zlib.Writer.Write failed`)\n\t\treturn nil, err\n\t}\n\tif err = writer.Close(); err != nil {\n\t\terr = gerror.Wrapf(err, `zlib.Writer.Close failed`)\n\t\treturn in.Bytes(), err\n\t}\n\treturn in.Bytes(), nil\n}\n\n// UnZlib decompresses `data` with zlib algorithm.\nfunc UnZlib(data []byte) ([]byte, error) {\n\tif len(data) < 13 {\n\t\treturn data, nil\n\t}\n\tvar (\n\t\tout             bytes.Buffer\n\t\tbytesReader     = bytes.NewReader(data)\n\t\tzlibReader, err = zlib.NewReader(bytesReader)\n\t)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `zlib.NewReader failed`)\n\t\treturn nil, err\n\t}\n\tif _, err = io.Copy(&out, zlibReader); err != nil {\n\t\terr = gerror.Wrapf(err, `io.Copy failed`)\n\t\treturn nil, err\n\t}\n\treturn out.Bytes(), nil\n}\n"
  },
  {
    "path": "encoding/gcompress/testdata/gzip/file.txt",
    "content": "This is a test file for gzip compression."
  },
  {
    "path": "encoding/gcompress/testdata/zip/path1/1.txt",
    "content": "This is a test file for zip compression purpose."
  },
  {
    "path": "encoding/gcompress/testdata/zip/path2/2.txt",
    "content": "This is another test file for zip compression purpose."
  },
  {
    "path": "encoding/ghash/ghash.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package ghash provides some classic hash functions(uint32/uint64) in go.\npackage ghash\n"
  },
  {
    "path": "encoding/ghash/ghash_ap.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// AP implements the classic AP hash algorithm for 32 bits.\nfunc AP(str []byte) uint32 {\n\tvar hash uint32\n\tfor i := 0; i < len(str); i++ {\n\t\tif (i & 1) == 0 {\n\t\t\thash ^= (hash << 7) ^ uint32(str[i]) ^ (hash >> 3)\n\t\t} else {\n\t\t\thash ^= ^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1\n\t\t}\n\t}\n\treturn hash\n}\n\n// AP64 implements the classic AP hash algorithm for 64 bits.\nfunc AP64(str []byte) uint64 {\n\tvar hash uint64\n\tfor i := 0; i < len(str); i++ {\n\t\tif (i & 1) == 0 {\n\t\t\thash ^= (hash << 7) ^ uint64(str[i]) ^ (hash >> 3)\n\t\t} else {\n\t\t\thash ^= ^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1\n\t\t}\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_bkdr.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// BKDR implements the classic BKDR hash algorithm for 32 bits.\nfunc BKDR(str []byte) uint32 {\n\tvar (\n\t\tseed uint32 = 131 // 31 131 1313 13131 131313 etc..\n\t\thash uint32 = 0\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = hash*seed + uint32(str[i])\n\t}\n\treturn hash\n}\n\n// BKDR64 implements the classic BKDR hash algorithm for 64 bits.\nfunc BKDR64(str []byte) uint64 {\n\tvar (\n\t\tseed uint64 = 131 // 31 131 1313 13131 131313 etc..\n\t\thash uint64 = 0\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = hash*seed + uint64(str[i])\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_djb.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// DJB implements the classic DJB hash algorithm for 32 bits.\nfunc DJB(str []byte) uint32 {\n\tvar hash uint32 = 5381\n\tfor i := 0; i < len(str); i++ {\n\t\thash += (hash << 5) + uint32(str[i])\n\t}\n\treturn hash\n}\n\n// DJB64 implements the classic DJB hash algorithm for 64 bits.\nfunc DJB64(str []byte) uint64 {\n\tvar hash uint64 = 5381\n\tfor i := 0; i < len(str); i++ {\n\t\thash += (hash << 5) + uint64(str[i])\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_elf.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// ELF implements the classic ELF hash algorithm for 32 bits.\nfunc ELF(str []byte) uint32 {\n\tvar (\n\t\thash uint32\n\t\tx    uint32\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = (hash << 4) + uint32(str[i])\n\t\tif x = hash & 0xF0000000; x != 0 {\n\t\t\thash ^= x >> 24\n\t\t\thash &= ^x + 1\n\t\t}\n\t}\n\treturn hash\n}\n\n// ELF64 implements the classic ELF hash algorithm for 64 bits.\nfunc ELF64(str []byte) uint64 {\n\tvar (\n\t\thash uint64\n\t\tx    uint64\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = (hash << 4) + uint64(str[i])\n\t\tif x = hash & 0xF000000000000000; x != 0 {\n\t\t\thash ^= x >> 24\n\t\t\thash &= ^x + 1\n\t\t}\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_jshash.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// JS implements the classic JS hash algorithm for 32 bits.\nfunc JS(str []byte) uint32 {\n\tvar hash uint32 = 1315423911\n\tfor i := 0; i < len(str); i++ {\n\t\thash ^= (hash << 5) + uint32(str[i]) + (hash >> 2)\n\t}\n\treturn hash\n}\n\n// JS64 implements the classic JS hash algorithm for 64 bits.\nfunc JS64(str []byte) uint64 {\n\tvar hash uint64 = 1315423911\n\tfor i := 0; i < len(str); i++ {\n\t\thash ^= (hash << 5) + uint64(str[i]) + (hash >> 2)\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_pjw.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// PJW implements the classic PJW hash algorithm for 32 bits.\nfunc PJW(str []byte) uint32 {\n\tvar (\n\t\tBitsInUnsignedInt uint32 = 32 // 4 * 8\n\t\tThreeQuarters            = (BitsInUnsignedInt * 3) / 4\n\t\tOneEighth                = BitsInUnsignedInt / 8\n\t\tHighBits          uint32 = (0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth)\n\t\thash              uint32\n\t\ttest              uint32\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = (hash << OneEighth) + uint32(str[i])\n\t\tif test = hash & HighBits; test != 0 {\n\t\t\thash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)\n\t\t}\n\t}\n\treturn hash\n}\n\n// PJW64 implements the classic PJW hash algorithm for 64 bits.\nfunc PJW64(str []byte) uint64 {\n\tvar (\n\t\tBitsInUnsignedInt uint64 = 32 // 4 * 8\n\t\tThreeQuarters            = (BitsInUnsignedInt * 3) / 4\n\t\tOneEighth                = BitsInUnsignedInt / 8\n\t\tHighBits          uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnsignedInt - OneEighth)\n\t\thash              uint64\n\t\ttest              uint64\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = (hash << OneEighth) + uint64(str[i])\n\t\tif test = hash & HighBits; test != 0 {\n\t\t\thash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)\n\t\t}\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_rs.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// RS implements the classic RS hash algorithm for 32 bits.\nfunc RS(str []byte) uint32 {\n\tvar (\n\t\tb    uint32 = 378551\n\t\ta    uint32 = 63689\n\t\thash uint32 = 0\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = hash*a + uint32(str[i])\n\t\ta *= b\n\t}\n\treturn hash\n}\n\n// RS64 implements the classic RS hash algorithm for 64 bits.\nfunc RS64(str []byte) uint64 {\n\tvar (\n\t\tb    uint64 = 378551\n\t\ta    uint64 = 63689\n\t\thash uint64 = 0\n\t)\n\tfor i := 0; i < len(str); i++ {\n\t\thash = hash*a + uint64(str[i])\n\t\ta *= b\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_sdbm.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash\n\n// SDBM implements the classic SDBM hash algorithm for 32 bits.\nfunc SDBM(str []byte) uint32 {\n\tvar hash uint32\n\tfor i := 0; i < len(str); i++ {\n\t\t// equivalent to: hash = 65599*hash + uint32(str[i]);\n\t\thash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash\n\t}\n\treturn hash\n}\n\n// SDBM64 implements the classic SDBM hash algorithm for 64 bits.\nfunc SDBM64(str []byte) uint64 {\n\tvar hash uint64\n\tfor i := 0; i < len(str); i++ {\n\t\t// equivalent to: hash = 65599*hash + uint32(str[i])\n\t\thash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage ghash_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n)\n\nvar (\n\tstr = []byte(\"This is the test string for hash.\")\n)\n\nfunc Benchmark_BKDR(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.BKDR(str)\n\t}\n}\n\nfunc Benchmark_BKDR64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.BKDR64(str)\n\t}\n}\n\nfunc Benchmark_SDBM(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.SDBM(str)\n\t}\n}\n\nfunc Benchmark_SDBM64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.SDBM64(str)\n\t}\n}\n\nfunc Benchmark_RS(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.RS(str)\n\t}\n}\n\nfunc Benchmark_RS64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.RS64(str)\n\t}\n}\n\nfunc Benchmark_JS(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.JS(str)\n\t}\n}\n\nfunc Benchmark_JS64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.JS64(str)\n\t}\n}\n\nfunc Benchmark_PJW(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.PJW(str)\n\t}\n}\n\nfunc Benchmark_PJW64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.PJW64(str)\n\t}\n}\n\nfunc Benchmark_ELF(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.ELF(str)\n\t}\n}\n\nfunc Benchmark_ELF64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.ELF64(str)\n\t}\n}\n\nfunc Benchmark_DJB(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.DJB(str)\n\t}\n}\n\nfunc Benchmark_DJB64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.DJB64(str)\n\t}\n}\n\nfunc Benchmark_AP(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.AP(str)\n\t}\n}\n\nfunc Benchmark_AP64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tghash.AP64(str)\n\t}\n}\n"
  },
  {
    "path": "encoding/ghash/ghash_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghash_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tstrBasic = []byte(\"This is the test string for hash.\")\n)\n\nfunc Test_BKDR(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(200645773)\n\t\tj := ghash.BKDR(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(4214762819217104013)\n\t\tj := ghash.BKDR64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_SDBM(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(1069170245)\n\t\tj := ghash.SDBM(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(9881052176572890693)\n\t\tj := ghash.SDBM64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_RS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(1944033799)\n\t\tj := ghash.RS(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(13439708950444349959)\n\t\tj := ghash.RS64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_JS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(498688898)\n\t\tj := ghash.JS(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(13410163655098759877)\n\t\tj := ghash.JS64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_PJW(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(7244206)\n\t\tj := ghash.PJW(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(31150)\n\t\tj := ghash.PJW64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_ELF(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(7244206)\n\t\tj := ghash.ELF(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(31150)\n\t\tj := ghash.ELF64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_DJB(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(959862602)\n\t\tj := ghash.DJB(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(2519720351310960458)\n\t\tj := ghash.DJB64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n\nfunc Test_AP(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint32(3998202516)\n\t\tj := ghash.AP(strBasic)\n\t\tt.Assert(j, x)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tx := uint64(2531023058543352243)\n\t\tj := ghash.AP64(strBasic)\n\t\tt.Assert(j, x)\n\t})\n}\n"
  },
  {
    "path": "encoding/ghtml/ghtml.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package ghtml provides useful API for HTML content handling.\npackage ghtml\n\nimport (\n\t\"html\"\n\t\"reflect\"\n\t\"strings\"\n\n\tstrip \"github.com/grokify/html-strip-tags-go\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// StripTags strips HTML tags from content, and returns only text.\n// Referer: http://php.net/manual/zh/function.strip-tags.php\nfunc StripTags(s string) string {\n\treturn strip.StripTags(s)\n}\n\n// Entities encodes all HTML chars for content.\n// Referer: http://php.net/manual/zh/function.htmlentities.php\nfunc Entities(s string) string {\n\treturn html.EscapeString(s)\n}\n\n// EntitiesDecode decodes all HTML chars for content.\n// Referer: http://php.net/manual/zh/function.html-entity-decode.php\nfunc EntitiesDecode(s string) string {\n\treturn html.UnescapeString(s)\n}\n\n// SpecialChars encodes some special chars for content, these special chars are:\n// \"&\", \"<\", \">\", `\"`, \"'\".\n// Referer: http://php.net/manual/zh/function.htmlspecialchars.php\nfunc SpecialChars(s string) string {\n\treturn strings.NewReplacer(\n\t\t\"&\", \"&amp;\",\n\t\t\"<\", \"&lt;\",\n\t\t\">\", \"&gt;\",\n\t\t`\"`, \"&#34;\",\n\t\t\"'\", \"&#39;\",\n\t).Replace(s)\n}\n\n// SpecialCharsDecode decodes some special chars for content, these special chars are:\n// \"&\", \"<\", \">\", `\"`, \"'\".\n// Referer: http://php.net/manual/zh/function.htmlspecialchars-decode.php\nfunc SpecialCharsDecode(s string) string {\n\treturn strings.NewReplacer(\n\t\t\"&amp;\", \"&\",\n\t\t\"&lt;\", \"<\",\n\t\t\"&gt;\", \">\",\n\t\t\"&#34;\", `\"`,\n\t\t\"&#39;\", \"'\",\n\t).Replace(s)\n}\n\n// SpecialCharsMapOrStruct automatically encodes string values/attributes for map/struct.\n//\n// Note that, if operation on struct, the given parameter `mapOrStruct` should be type of pointer to struct.\n//\n// For example:\n// var m = map{}\n// var s = struct{}{}\n// OK: SpecialCharsMapOrStruct(m)\n// OK: SpecialCharsMapOrStruct(&s)\n// Error: SpecialCharsMapOrStruct(s)\nfunc SpecialCharsMapOrStruct(mapOrStruct any) error {\n\tvar (\n\t\treflectValue = reflect.ValueOf(mapOrStruct)\n\t\treflectKind  = reflectValue.Kind()\n\t\toriginalKind = reflectKind\n\t)\n\tfor reflectValue.IsValid() && (reflectKind == reflect.Pointer || reflectKind == reflect.Interface) {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\tvar (\n\t\t\tmapKeys  = reflectValue.MapKeys()\n\t\t\tmapValue reflect.Value\n\t\t)\n\t\tfor _, key := range mapKeys {\n\t\t\tmapValue = reflectValue.MapIndex(key)\n\t\t\tswitch mapValue.Kind() {\n\t\t\tcase reflect.String:\n\t\t\t\treflectValue.SetMapIndex(key, reflect.ValueOf(SpecialChars(mapValue.String())))\n\t\t\tcase reflect.Interface:\n\t\t\t\tif mapValue.Elem().Kind() == reflect.String {\n\t\t\t\t\treflectValue.SetMapIndex(\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\treflect.ValueOf(SpecialChars(mapValue.Elem().String())),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\n\tcase reflect.Struct:\n\t\tif originalKind != reflect.Pointer {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid input parameter type \"%s\", should be type of pointer to struct`,\n\t\t\t\treflect.TypeOf(mapOrStruct).String(),\n\t\t\t)\n\t\t}\n\t\tvar fieldValue reflect.Value\n\t\tfor i := 0; i < reflectValue.NumField(); i++ {\n\t\t\tfieldValue = reflectValue.Field(i)\n\t\t\tswitch fieldValue.Kind() {\n\t\t\tcase reflect.String:\n\t\t\t\tfieldValue.Set(\n\t\t\t\t\treflect.ValueOf(\n\t\t\t\t\t\tSpecialChars(fieldValue.String()),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid input parameter type \"%s\"`,\n\t\t\treflect.TypeOf(mapOrStruct).String(),\n\t\t)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "encoding/ghtml/ghtml_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghtml_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghtml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_StripTags(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := `<p>Test paragraph.</p><!-- Comment -->  <a href=\"#fragment\">Other text</a>`\n\t\tdst := `Test paragraph.  Other text`\n\t\tt.Assert(ghtml.StripTags(src), dst)\n\t})\n}\n\nfunc Test_Entities(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := `A 'quote' \"is\" <b>bold</b>`\n\t\tdst := `A &#39;quote&#39; &#34;is&#34; &lt;b&gt;bold&lt;/b&gt;`\n\t\tt.Assert(ghtml.Entities(src), dst)\n\t\tt.Assert(ghtml.EntitiesDecode(dst), src)\n\t})\n}\n\nfunc Test_SpecialChars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := `A 'quote' \"is\" <b>bold</b>`\n\t\tdst := `A &#39;quote&#39; &#34;is&#34; &lt;b&gt;bold&lt;/b&gt;`\n\t\tt.Assert(ghtml.SpecialChars(src), dst)\n\t\tt.Assert(ghtml.SpecialCharsDecode(dst), src)\n\t})\n}\n\nfunc Test_SpecialCharsMapOrStruct_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := g.Map{\n\t\t\t\"Title\":   \"<h1>T</h1>\",\n\t\t\t\"Content\": \"<div>C</div>\",\n\t\t}\n\t\terr := ghtml.SpecialCharsMapOrStruct(a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a[\"Title\"], `&lt;h1&gt;T&lt;/h1&gt;`)\n\t\tt.Assert(a[\"Content\"], `&lt;div&gt;C&lt;/div&gt;`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := g.MapStrStr{\n\t\t\t\"Title\":   \"<h1>T</h1>\",\n\t\t\t\"Content\": \"<div>C</div>\",\n\t\t}\n\t\terr := ghtml.SpecialCharsMapOrStruct(a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a[\"Title\"], `&lt;h1&gt;T&lt;/h1&gt;`)\n\t\tt.Assert(a[\"Content\"], `&lt;div&gt;C&lt;/div&gt;`)\n\t})\n}\n\nfunc Test_SpecialCharsMapOrStruct_Struct(t *testing.T) {\n\ttype A struct {\n\t\tTitle   string\n\t\tContent string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &A{\n\t\t\tTitle:   \"<h1>T</h1>\",\n\t\t\tContent: \"<div>C</div>\",\n\t\t}\n\t\terr := ghtml.SpecialCharsMapOrStruct(a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.Title, `&lt;h1&gt;T&lt;/h1&gt;`)\n\t\tt.Assert(a.Content, `&lt;div&gt;C&lt;/div&gt;`)\n\t})\n\n\t// should error\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := A{\n\t\t\tTitle:   \"<h1>T</h1>\",\n\t\t\tContent: \"<div>C</div>\",\n\t\t}\n\t\terr := ghtml.SpecialCharsMapOrStruct(a)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "encoding/gini/gini.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gini provides accessing and converting for INI content.\npackage gini\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Decode converts INI format to map.\nfunc Decode(data []byte) (res map[string]any, err error) {\n\tres = make(map[string]any)\n\tvar (\n\t\tfieldMap    = make(map[string]any)\n\t\tbytesReader = bytes.NewReader(data)\n\t\tbufioReader = bufio.NewReader(bytesReader)\n\t\tsection     string\n\t\tlastSection string\n\t\thaveSection bool\n\t\tline        string\n\t)\n\n\tfor {\n\t\tline, err = bufioReader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\terr = gerror.Wrapf(err, `bufioReader.ReadString failed`)\n\t\t\treturn nil, err\n\t\t}\n\t\tif line = strings.TrimSpace(line); len(line) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif line[0] == ';' || line[0] == '#' {\n\t\t\tcontinue\n\t\t}\n\t\tvar (\n\t\t\tsectionBeginPos = strings.Index(line, \"[\")\n\t\t\tsectionEndPos   = strings.Index(line, \"]\")\n\t\t)\n\t\tif sectionBeginPos >= 0 && sectionEndPos >= 2 {\n\t\t\tsection = line[sectionBeginPos+1 : sectionEndPos]\n\t\t\tif lastSection == \"\" {\n\t\t\t\tlastSection = section\n\t\t\t} else if lastSection != section {\n\t\t\t\tlastSection = section\n\t\t\t\tfieldMap = make(map[string]any)\n\t\t\t}\n\t\t\thaveSection = true\n\t\t} else if !haveSection {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(line, \"=\") && haveSection {\n\t\t\tvalues := strings.Split(line, \"=\")\n\t\t\tfieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], \"=\"))\n\t\t\tres[section] = fieldMap\n\t\t}\n\t}\n\n\tif !haveSection {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"failed to parse INI file, section not found\")\n\t}\n\treturn res, nil\n}\n\n// Encode converts map to INI format.\nfunc Encode(data map[string]any) (res []byte, err error) {\n\tvar (\n\t\tn  int\n\t\tw  = new(bytes.Buffer)\n\t\tm  map[string]any\n\t\tok bool\n\t)\n\tfor section, item := range data {\n\t\t// Section key-value pairs.\n\t\tif m, ok = item.(map[string]any); ok {\n\t\t\tn, err = fmt.Fprintf(w, \"[%s]\\n\", section)\n\t\t\tif err != nil || n == 0 {\n\t\t\t\treturn nil, gerror.Wrapf(err, \"w.WriteString failed\")\n\t\t\t}\n\t\t\tfor k, v := range m {\n\t\t\t\tif n, err = fmt.Fprintf(w, \"%s=%v\\n\", k, v); err != nil || n == 0 {\n\t\t\t\t\treturn nil, gerror.Wrapf(err, \"w.WriteString failed\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\t// Simple key-value pairs.\n\t\tfor k, v := range data {\n\t\t\tif n, err = fmt.Fprintf(w, \"%s=%v\\n\", k, v); err != nil || n == 0 {\n\t\t\t\treturn nil, gerror.Wrapf(err, \"w.WriteString failed\")\n\t\t\t}\n\t\t}\n\t\tbreak\n\t}\n\tres = make([]byte, w.Len())\n\tif n, err = w.Read(res); err != nil || n == 0 {\n\t\treturn nil, gerror.Wrapf(err, \"w.Read failed\")\n\t}\n\treturn res, nil\n}\n\n// ToJson convert INI format to JSON.\nfunc ToJson(data []byte) (res []byte, err error) {\n\tiniMap, err := Decode(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn json.Marshal(iniMap)\n}\n"
  },
  {
    "path": "encoding/gini/gini_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gini_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gini\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar iniContent = `\n\n;注释\naa=bb\n[addr] \n#注释\nip = 127.0.0.1\nport=9001\nenable=true\ncommand=/bin/echo \"gf=GoFrame\"\n\n\t[DBINFO]\n\ttype=mysql\n\tuser=root\n\tpassword=password\n[键]\n呵呵=值\n\n`\n\nfunc TestDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tres, err := gini.Decode([]byte(iniContent))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t\tt.Assert(res[\"addr\"].(map[string]any)[\"ip\"], \"127.0.0.1\")\n\t\tt.Assert(res[\"addr\"].(map[string]any)[\"port\"], \"9001\")\n\t\tt.Assert(res[\"addr\"].(map[string]any)[\"command\"], `/bin/echo \"gf=GoFrame\"`)\n\t\tt.Assert(res[\"DBINFO\"].(map[string]any)[\"user\"], \"root\")\n\t\tt.Assert(res[\"DBINFO\"].(map[string]any)[\"type\"], \"mysql\")\n\t\tt.Assert(res[\"键\"].(map[string]any)[\"呵呵\"], \"值\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrContent := `\n\t\ta = b\n`\n\t\t_, err := gini.Decode([]byte(errContent))\n\t\tif err == nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t})\n}\n\nfunc TestEncode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tiniMap, err := gini.Decode([]byte(iniContent))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tiniStr, err := gini.Encode(iniMap)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tres, err := gini.Decode(iniStr)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(res[\"addr\"].(map[string]any)[\"ip\"], \"127.0.0.1\")\n\t\tt.Assert(res[\"addr\"].(map[string]any)[\"port\"], \"9001\")\n\t\tt.Assert(res[\"DBINFO\"].(map[string]any)[\"user\"], \"root\")\n\t\tt.Assert(res[\"DBINFO\"].(map[string]any)[\"type\"], \"mysql\")\n\n\t})\n}\n\nfunc TestToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tjsonStr, err := gini.ToJson([]byte(iniContent))\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tjson, err := gjson.LoadContent(jsonStr)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tiniMap, err := gini.Decode([]byte(iniContent))\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(iniMap[\"addr\"].(map[string]any)[\"ip\"], json.Get(\"addr.ip\").String())\n\t\tt.Assert(iniMap[\"addr\"].(map[string]any)[\"port\"], json.Get(\"addr.port\").String())\n\t\tt.Assert(iniMap[\"DBINFO\"].(map[string]any)[\"user\"], json.Get(\"DBINFO.user\").String())\n\t\tt.Assert(iniMap[\"DBINFO\"].(map[string]any)[\"type\"], json.Get(\"DBINFO.type\").String())\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gjson provides convenient API for JSON/XML/INI/YAML/TOML data handling.\npackage gjson\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype ContentType = string\n\nconst (\n\tContentTypeJSON       ContentType = `json`\n\tContentTypeJs         ContentType = `js`\n\tContentTypeXML        ContentType = `xml`\n\tContentTypeIni        ContentType = `ini`\n\tContentTypeYaml       ContentType = `yaml`\n\tContentTypeYml        ContentType = `yml`\n\tContentTypeToml       ContentType = `toml`\n\tContentTypeProperties ContentType = `properties`\n)\n\nconst (\n\t// Separator char for hierarchical data access.\n\tdefaultSplitChar = '.'\n)\n\n// Json is the customized JSON struct.\ntype Json struct {\n\tmu rwmutex.RWMutex\n\n\t// Pointer for hierarchical data access, it's the root of data in default.\n\tp *any\n\n\t// Char separator('.' in default).\n\tc byte\n\n\t// Violence Check(false in default),\n\t// which is used to access data when the hierarchical data key contains separator char.\n\tvc bool\n}\n\n// Options for Json object creating/loading.\ntype Options struct {\n\t// Mark this object is for in concurrent-safe usage. This is especially for Json object creating.\n\tSafe bool\n\n\t// Custom priority tags for decoding, eg: \"json,yaml,MyTag\".\n\t// This is specially for struct parsing into Json object.\n\tTags string\n\n\t// Type specifies the data content type, eg: json, xml, yaml, toml, ini.\n\tType ContentType\n\n\t// StrNumber causes the Decoder to unmarshal a number into an any as a string instead of as a float64.\n\t// This is specially for json content parsing into Json object.\n\tStrNumber bool\n}\n\n// iInterfaces is used for type assert api for Interfaces().\ntype iInterfaces interface {\n\tInterfaces() []any\n}\n\n// iMapStrAny is the interface support for converting struct parameter to map.\ntype iMapStrAny interface {\n\tMapStrAny() map[string]any\n}\n\n// iVal is the interface for underlying any retrieving.\ntype iVal interface {\n\tVal() any\n}\n\n// setValue sets `value` to `j` by `pattern`.\n// Note:\n// 1. If value is nil and removed is true, means deleting this value;\n// 2. It's quite complicated in hierarchical data search, node creating and data assignment;\nfunc (j *Json) setValue(pattern string, value any, removed bool) error {\n\tvar (\n\t\terr    error\n\t\tarray  = strings.Split(pattern, string(j.c))\n\t\tlength = len(array)\n\t)\n\tif value, err = j.convertValue(value); err != nil {\n\t\treturn err\n\t}\n\t// Initialization checks.\n\tif *j.p == nil {\n\t\tif gstr.IsNumeric(array[0]) {\n\t\t\t*j.p = make([]any, 0)\n\t\t} else {\n\t\t\t*j.p = make(map[string]any)\n\t\t}\n\t}\n\tvar (\n\t\tpparent *any = nil // Parent pointer.\n\t\tpointer      = j.p // Current pointer.\n\t)\n\tj.mu.Lock()\n\tdefer j.mu.Unlock()\n\tfor i := 0; i < length; i++ {\n\t\tswitch (*pointer).(type) {\n\t\tcase map[string]any:\n\t\t\tif i == length-1 {\n\t\t\t\tif removed && value == nil {\n\t\t\t\t\t// Delete item from map.\n\t\t\t\t\tdelete((*pointer).(map[string]any), array[i])\n\t\t\t\t} else {\n\t\t\t\t\tif (*pointer).(map[string]any) == nil {\n\t\t\t\t\t\t*pointer = map[string]any{}\n\t\t\t\t\t}\n\t\t\t\t\t(*pointer).(map[string]any)[array[i]] = value\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If the key does not exit in the map.\n\t\t\t\tif v, ok := (*pointer).(map[string]any)[array[i]]; !ok {\n\t\t\t\t\tif removed && value == nil {\n\t\t\t\t\t\tgoto done\n\t\t\t\t\t}\n\t\t\t\t\t// Creating new node.\n\t\t\t\t\tif gstr.IsNumeric(array[i+1]) {\n\t\t\t\t\t\t// Creating array node.\n\t\t\t\t\t\tn, _ := strconv.Atoi(array[i+1])\n\t\t\t\t\t\tvar v any = make([]any, n+1)\n\t\t\t\t\t\tpparent = j.setPointerWithValue(pointer, array[i], v)\n\t\t\t\t\t\tpointer = &v\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Creating map node.\n\t\t\t\t\t\tvar v any = make(map[string]any)\n\t\t\t\t\t\tpparent = j.setPointerWithValue(pointer, array[i], v)\n\t\t\t\t\t\tpointer = &v\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpparent = pointer\n\t\t\t\t\tpointer = &v\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase []any:\n\t\t\t// A string key.\n\t\t\tif !gstr.IsNumeric(array[i]) {\n\t\t\t\tif i == length-1 {\n\t\t\t\t\t*pointer = map[string]any{array[i]: value}\n\t\t\t\t} else {\n\t\t\t\t\tvar v any = make(map[string]any)\n\t\t\t\t\t*pointer = v\n\t\t\t\t\tpparent = pointer\n\t\t\t\t\tpointer = &v\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Numeric index.\n\t\t\tvalueNum, err := strconv.Atoi(array[i])\n\t\t\tif err != nil {\n\t\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.Atoi failed for string \"%s\"`, array[i])\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif i == length-1 {\n\t\t\t\t// Leaf node.\n\t\t\t\tif len((*pointer).([]any)) > valueNum {\n\t\t\t\t\tif removed && value == nil {\n\t\t\t\t\t\t// Deleting element.\n\t\t\t\t\t\tif pparent == nil {\n\t\t\t\t\t\t\t*pointer = append((*pointer).([]any)[:valueNum], (*pointer).([]any)[valueNum+1:]...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tj.setPointerWithValue(pparent, array[i-1], append((*pointer).([]any)[:valueNum], (*pointer).([]any)[valueNum+1:]...))\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t(*pointer).([]any)[valueNum] = value\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif removed && value == nil {\n\t\t\t\t\t\tgoto done\n\t\t\t\t\t}\n\t\t\t\t\tif pparent == nil {\n\t\t\t\t\t\t// It is the root node.\n\t\t\t\t\t\tj.setPointerWithValue(pointer, array[i], value)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// It is not the root node.\n\t\t\t\t\t\ts := make([]any, valueNum+1)\n\t\t\t\t\t\tcopy(s, (*pointer).([]any))\n\t\t\t\t\t\ts[valueNum] = value\n\t\t\t\t\t\tj.setPointerWithValue(pparent, array[i-1], s)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Branch node.\n\t\t\t\tif gstr.IsNumeric(array[i+1]) {\n\t\t\t\t\tn, _ := strconv.Atoi(array[i+1])\n\t\t\t\t\tpSlice := (*pointer).([]any)\n\t\t\t\t\tif len(pSlice) > valueNum {\n\t\t\t\t\t\titem := pSlice[valueNum]\n\t\t\t\t\t\tif s, ok := item.([]any); ok {\n\t\t\t\t\t\t\tfor i := 0; i < n-len(s); i++ {\n\t\t\t\t\t\t\t\ts = append(s, nil)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpparent = pointer\n\t\t\t\t\t\t\tpointer = &pSlice[valueNum]\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif removed && value == nil {\n\t\t\t\t\t\t\t\tgoto done\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvar v any = make([]any, n+1)\n\t\t\t\t\t\t\tpparent = j.setPointerWithValue(pointer, array[i], v)\n\t\t\t\t\t\t\tpointer = &v\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif removed && value == nil {\n\t\t\t\t\t\t\tgoto done\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar v any = make([]any, n+1)\n\t\t\t\t\t\tpparent = j.setPointerWithValue(pointer, array[i], v)\n\t\t\t\t\t\tpointer = &v\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpSlice := (*pointer).([]any)\n\t\t\t\t\tif len(pSlice) > valueNum {\n\t\t\t\t\t\tpparent = pointer\n\t\t\t\t\t\tpointer = &(*pointer).([]any)[valueNum]\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts := make([]any, valueNum+1)\n\t\t\t\t\t\tcopy(s, pSlice)\n\t\t\t\t\t\ts[valueNum] = make(map[string]any)\n\t\t\t\t\t\tif pparent != nil {\n\t\t\t\t\t\t\t// i > 0\n\t\t\t\t\t\t\tj.setPointerWithValue(pparent, array[i-1], s)\n\t\t\t\t\t\t\tpparent = pointer\n\t\t\t\t\t\t\tpointer = &s[valueNum]\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// i = 0\n\t\t\t\t\t\t\tvar v any = s\n\t\t\t\t\t\t\t*pointer = v\n\t\t\t\t\t\t\tpparent = pointer\n\t\t\t\t\t\t\tpointer = &s[valueNum]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// If the variable pointed to by the `pointer` is not of a reference type,\n\t\t// then it modifies the variable via its the parent, ie: pparent.\n\t\tdefault:\n\t\t\tif removed && value == nil {\n\t\t\t\tgoto done\n\t\t\t}\n\t\t\tif gstr.IsNumeric(array[i]) {\n\t\t\t\tn, _ := strconv.Atoi(array[i])\n\t\t\t\ts := make([]any, n+1)\n\t\t\t\tif i == length-1 {\n\t\t\t\t\ts[n] = value\n\t\t\t\t}\n\t\t\t\tif pparent != nil {\n\t\t\t\t\tpparent = j.setPointerWithValue(pparent, array[i-1], s)\n\t\t\t\t} else {\n\t\t\t\t\t*pointer = s\n\t\t\t\t\tpparent = pointer\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar v1, v2 any\n\t\t\t\tif i == length-1 {\n\t\t\t\t\tv1 = map[string]any{\n\t\t\t\t\t\tarray[i]: value,\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tv1 = map[string]any{\n\t\t\t\t\t\tarray[i]: nil,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif pparent != nil {\n\t\t\t\t\tpparent = j.setPointerWithValue(pparent, array[i-1], v1)\n\t\t\t\t} else {\n\t\t\t\t\t*pointer = v1\n\t\t\t\t\tpparent = pointer\n\t\t\t\t}\n\t\t\t\tv2 = v1.(map[string]any)[array[i]]\n\t\t\t\tpointer = &v2\n\t\t\t}\n\t\t}\n\t}\ndone:\n\treturn nil\n}\n\n// convertValue converts `value` to map[string]any or []any,\n// which can be supported for hierarchical data access.\nfunc (j *Json) convertValue(value any) (convertedValue any, err error) {\n\tif value == nil {\n\t\treturn\n\t}\n\n\tswitch value.(type) {\n\tcase map[string]any:\n\t\treturn value, nil\n\n\tcase []any:\n\t\treturn value, nil\n\n\tdefault:\n\t\tvar (\n\t\t\treflectInfo = reflection.OriginValueAndKind(value)\n\t\t)\n\t\tswitch reflectInfo.OriginKind {\n\t\tcase reflect.Array:\n\t\t\treturn gconv.Interfaces(value), nil\n\n\t\tcase reflect.Slice:\n\t\t\treturn gconv.Interfaces(value), nil\n\n\t\tcase reflect.Map:\n\t\t\treturn gconv.Map(value), nil\n\n\t\tcase reflect.Struct:\n\t\t\tif v, ok := value.(iMapStrAny); ok {\n\t\t\t\tconvertedValue = v.MapStrAny()\n\t\t\t}\n\t\t\tif utils.IsNil(convertedValue) {\n\t\t\t\tif v, ok := value.(iInterfaces); ok {\n\t\t\t\t\tconvertedValue = v.Interfaces()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif utils.IsNil(convertedValue) {\n\t\t\t\tconvertedValue = gconv.Map(value)\n\t\t\t}\n\t\t\tif utils.IsNil(convertedValue) {\n\t\t\t\terr = gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type \"%s\"`, reflect.TypeOf(value))\n\t\t\t}\n\t\t\treturn\n\n\t\tdefault:\n\t\t\treturn value, nil\n\t\t}\n\t}\n}\n\n// setPointerWithValue sets `key`:`value` to `pointer`, the `key` may be a map key or slice index.\n// It returns the pointer to the new value set.\nfunc (j *Json) setPointerWithValue(pointer *any, key string, value any) *any {\n\tswitch (*pointer).(type) {\n\tcase map[string]any:\n\t\t(*pointer).(map[string]any)[key] = value\n\t\treturn &value\n\tcase []any:\n\t\tn, _ := strconv.Atoi(key)\n\t\tif len((*pointer).([]any)) > n {\n\t\t\t(*pointer).([]any)[n] = value\n\t\t\treturn &(*pointer).([]any)[n]\n\t\t} else {\n\t\t\ts := make([]any, n+1)\n\t\t\tcopy(s, (*pointer).([]any))\n\t\t\ts[n] = value\n\t\t\t*pointer = s\n\t\t\treturn &s[n]\n\t\t}\n\tdefault:\n\t\t*pointer = value\n\t}\n\treturn pointer\n}\n\n// getPointerByPattern returns a pointer to the value by specified `pattern`.\nfunc (j *Json) getPointerByPattern(pattern string) *any {\n\tif j.p == nil {\n\t\treturn nil\n\t}\n\tif j.vc {\n\t\treturn j.getPointerByPatternWithViolenceCheck(pattern)\n\t} else {\n\t\treturn j.getPointerByPatternWithoutViolenceCheck(pattern)\n\t}\n}\n\n// getPointerByPatternWithViolenceCheck returns a pointer to the value of specified `pattern` with violence check.\nfunc (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *any {\n\tif !j.vc {\n\t\treturn j.getPointerByPatternWithoutViolenceCheck(pattern)\n\t}\n\n\t// It returns nil if pattern is empty.\n\tif pattern == \"\" {\n\t\treturn nil\n\t}\n\t// It returns all if pattern is \".\".\n\tif pattern == \".\" {\n\t\treturn j.p\n\t}\n\n\tvar (\n\t\tindex   = len(pattern)\n\t\tstart   = 0\n\t\tlength  = 0\n\t\tpointer = j.p\n\t)\n\tif index == 0 {\n\t\treturn pointer\n\t}\n\tfor {\n\t\tif r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {\n\t\t\tif length += index - start; start > 0 {\n\t\t\t\tlength += 1\n\t\t\t}\n\t\t\tstart = index + 1\n\t\t\tindex = len(pattern)\n\t\t\tif length == len(pattern) {\n\t\t\t\treturn r\n\t\t\t} else {\n\t\t\t\tpointer = r\n\t\t\t}\n\t\t} else {\n\t\t\t// Get the position for next separator char.\n\t\t\tindex = strings.LastIndexByte(pattern[start:index], j.c)\n\t\t\tif index != -1 && length > 0 {\n\t\t\t\tindex += length + 1\n\t\t\t}\n\t\t}\n\t\tif start >= index {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn nil\n}\n\n// getPointerByPatternWithoutViolenceCheck returns a pointer to the value of specified `pattern`, with no violence check.\nfunc (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *any {\n\tif j.vc {\n\t\treturn j.getPointerByPatternWithViolenceCheck(pattern)\n\t}\n\n\t// It returns nil if pattern is empty.\n\tif pattern == \"\" {\n\t\treturn nil\n\t}\n\t// It returns all if pattern is \".\".\n\tif pattern == \".\" {\n\t\treturn j.p\n\t}\n\n\tpointer := j.p\n\tif len(pattern) == 0 {\n\t\treturn pointer\n\t}\n\tarray := strings.Split(pattern, string(j.c))\n\tfor k, v := range array {\n\t\tif r := j.checkPatternByPointer(v, pointer); r != nil {\n\t\t\tif k == len(array)-1 {\n\t\t\t\treturn r\n\t\t\t} else {\n\t\t\t\tpointer = r\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn nil\n}\n\n// checkPatternByPointer checks whether there's value by `key` in specified `pointer`.\n// It returns a pointer to the value.\nfunc (j *Json) checkPatternByPointer(key string, pointer *any) *any {\n\tswitch (*pointer).(type) {\n\tcase map[string]any:\n\t\tif v, ok := (*pointer).(map[string]any)[key]; ok {\n\t\t\treturn &v\n\t\t}\n\tcase []any:\n\t\tif gstr.IsNumeric(key) {\n\t\t\tn, err := strconv.Atoi(key)\n\t\t\tif err == nil && len((*pointer).([]any)) > n {\n\t\t\t\treturn &(*pointer).([]any)[n]\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Interface returns the json value.\nfunc (j *Json) Interface() any {\n\tif j == nil {\n\t\treturn nil\n\t}\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\tif j.p == nil {\n\t\treturn nil\n\t}\n\treturn *(j.p)\n}\n\n// Var returns the json value as *gvar.Var.\nfunc (j *Json) Var() *gvar.Var {\n\treturn gvar.New(j.Interface())\n}\n\n// IsNil checks whether the value pointed by `j` is nil.\nfunc (j *Json) IsNil() bool {\n\tif j == nil {\n\t\treturn true\n\t}\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn j.p == nil || *(j.p) == nil\n}\n\n// Get retrieves and returns value by specified `pattern`.\n// It returns all values of current Json object if `pattern` is given \".\".\n// It returns nil if no value found by `pattern`.\n//\n// We can also access slice item by its index number in `pattern` like:\n// \"list.10\", \"array.0.name\", \"array.0.1.id\".\n//\n// It returns a default value specified by `def` if value for `pattern` is not found.\nfunc (j *Json) Get(pattern string, def ...any) *gvar.Var {\n\tif j == nil {\n\t\treturn nil\n\t}\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\n\t// It returns nil if pattern is empty.\n\tif pattern == \"\" {\n\t\treturn nil\n\t}\n\n\tresult := j.getPointerByPattern(pattern)\n\tif result != nil {\n\t\treturn gvar.New(*result)\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetJson gets the value by specified `pattern`,\n// and converts it to an un-concurrent-safe Json object.\nfunc (j *Json) GetJson(pattern string, def ...any) *Json {\n\treturn New(j.Get(pattern, def...).Val())\n}\n\n// GetJsons gets the value by specified `pattern`,\n// and converts it to a slice of un-concurrent-safe Json object.\nfunc (j *Json) GetJsons(pattern string, def ...any) []*Json {\n\tarray := j.Get(pattern, def...).Array()\n\tif len(array) > 0 {\n\t\tjsonSlice := make([]*Json, len(array))\n\t\tfor i := 0; i < len(array); i++ {\n\t\t\tjsonSlice[i] = New(array[i])\n\t\t}\n\t\treturn jsonSlice\n\t}\n\treturn nil\n}\n\n// GetJsonMap gets the value by specified `pattern`,\n// and converts it to a map of un-concurrent-safe Json object.\nfunc (j *Json) GetJsonMap(pattern string, def ...any) map[string]*Json {\n\tm := j.Get(pattern, def...).Map()\n\tif len(m) > 0 {\n\t\tjsonMap := make(map[string]*Json, len(m))\n\t\tfor k, v := range m {\n\t\t\tjsonMap[k] = New(v)\n\t\t}\n\t\treturn jsonMap\n\t}\n\treturn nil\n}\n\n// Set sets value with specified `pattern`.\n// It supports hierarchical data access by char separator, which is '.' in default.\nfunc (j *Json) Set(pattern string, value any) error {\n\treturn j.setValue(pattern, value, false)\n}\n\n// MustSet performs as Set, but it panics if any error occurs.\nfunc (j *Json) MustSet(pattern string, value any) {\n\tif err := j.Set(pattern, value); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Remove deletes value with specified `pattern`.\n// It supports hierarchical data access by char separator, which is '.' in default.\nfunc (j *Json) Remove(pattern string) error {\n\treturn j.setValue(pattern, nil, true)\n}\n\n// MustRemove performs as Remove, but it panics if any error occurs.\nfunc (j *Json) MustRemove(pattern string) {\n\tif err := j.Remove(pattern); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Contains checks whether the value by specified `pattern` exist.\nfunc (j *Json) Contains(pattern string) bool {\n\treturn j.Get(pattern) != nil\n}\n\n// Len returns the length/size of the value by specified `pattern`.\n// The target value by `pattern` should be type of slice or map.\n// It returns -1 if the target value is not found, or its type is invalid.\nfunc (j *Json) Len(pattern string) int {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\tp := j.getPointerByPattern(pattern)\n\tif p != nil {\n\t\tswitch (*p).(type) {\n\t\tcase map[string]any:\n\t\t\treturn len((*p).(map[string]any))\n\t\tcase []any:\n\t\t\treturn len((*p).([]any))\n\t\tdefault:\n\t\t\treturn -1\n\t\t}\n\t}\n\treturn -1\n}\n\n// Append appends value to the value by specified `pattern`.\n// The target value by `pattern` should be type of slice.\nfunc (j *Json) Append(pattern string, value any) error {\n\tp := j.getPointerByPattern(pattern)\n\tif p == nil || *p == nil {\n\t\tif pattern == \".\" {\n\t\t\treturn j.Set(\"0\", value)\n\t\t}\n\t\treturn j.Set(fmt.Sprintf(\"%s.0\", pattern), value)\n\t}\n\tswitch (*p).(type) {\n\tcase []any:\n\t\tif pattern == \".\" {\n\t\t\treturn j.Set(fmt.Sprintf(\"%d\", len((*p).([]any))), value)\n\t\t}\n\t\treturn j.Set(fmt.Sprintf(\"%s.%d\", pattern, len((*p).([]any))), value)\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"invalid variable type of %s\", pattern)\n}\n\n// MustAppend performs as Append, but it panics if any error occurs.\nfunc (j *Json) MustAppend(pattern string, value any) {\n\tif err := j.Append(pattern, value); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Map converts current Json object to map[string]any.\n// It returns nil if fails.\nfunc (j *Json) Map() map[string]any {\n\treturn j.Var().Map()\n}\n\n// Array converts current Json object to []any.\n// It returns nil if fails.\nfunc (j *Json) Array() []any {\n\treturn j.Var().Array()\n}\n\n// Scan automatically calls Struct or Structs function according to the type of parameter\n// `pointer` to implement the converting.\nfunc (j *Json) Scan(pointer any, mapping ...map[string]string) error {\n\treturn j.Var().Scan(pointer, mapping...)\n}\n\n// Dump prints current Json object with more manually readable.\nfunc (j *Json) Dump() {\n\tif j == nil {\n\t\treturn\n\t}\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\tif j.p == nil {\n\t\treturn\n\t}\n\tgutil.Dump(*j.p)\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\n// SetSplitChar sets the separator char for hierarchical data access.\nfunc (j *Json) SetSplitChar(char byte) {\n\tj.mu.Lock()\n\tj.c = char\n\tj.mu.Unlock()\n}\n\n// SetViolenceCheck enables/disables violence check for hierarchical data access.\nfunc (j *Json) SetViolenceCheck(enabled bool) {\n\tj.mu.Lock()\n\tj.vc = enabled\n\tj.mu.Unlock()\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api_encoding.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"github.com/gogf/gf/v2/encoding/gini\"\n\t\"github.com/gogf/gf/v2/encoding/gproperties\"\n\t\"github.com/gogf/gf/v2/encoding/gtoml\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/encoding/gyaml\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// ========================================================================\n// JSON\n// ========================================================================\n\nfunc (j *Json) ToJson() ([]byte, error) {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn Encode(*(j.p))\n}\n\nfunc (j *Json) ToJsonString() (string, error) {\n\tb, e := j.ToJson()\n\treturn string(b), e\n}\n\nfunc (j *Json) ToJsonIndent() ([]byte, error) {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn json.MarshalIndent(*(j.p), \"\", \"\\t\")\n}\n\nfunc (j *Json) ToJsonIndentString() (string, error) {\n\tb, e := j.ToJsonIndent()\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToJson() []byte {\n\tresult, err := j.ToJson()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToJsonString() string {\n\treturn string(j.MustToJson())\n}\n\nfunc (j *Json) MustToJsonIndent() []byte {\n\tresult, err := j.ToJsonIndent()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToJsonIndentString() string {\n\treturn string(j.MustToJsonIndent())\n}\n\n// ========================================================================\n// XML\n// ========================================================================\n\nfunc (j *Json) ToXml(rootTag ...string) ([]byte, error) {\n\treturn gxml.Encode(j.Var().Map(), rootTag...)\n}\n\nfunc (j *Json) ToXmlString(rootTag ...string) (string, error) {\n\tb, e := j.ToXml(rootTag...)\n\treturn string(b), e\n}\n\nfunc (j *Json) ToXmlIndent(rootTag ...string) ([]byte, error) {\n\treturn gxml.EncodeWithIndent(j.Var().Map(), rootTag...)\n}\n\nfunc (j *Json) ToXmlIndentString(rootTag ...string) (string, error) {\n\tb, e := j.ToXmlIndent(rootTag...)\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToXml(rootTag ...string) []byte {\n\tresult, err := j.ToXml(rootTag...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToXmlString(rootTag ...string) string {\n\treturn string(j.MustToXml(rootTag...))\n}\n\nfunc (j *Json) MustToXmlIndent(rootTag ...string) []byte {\n\tresult, err := j.ToXmlIndent(rootTag...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToXmlIndentString(rootTag ...string) string {\n\treturn string(j.MustToXmlIndent(rootTag...))\n}\n\n// ========================================================================\n// YAML\n// ========================================================================\n\nfunc (j *Json) ToYaml() ([]byte, error) {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn gyaml.Encode(*(j.p))\n}\n\nfunc (j *Json) ToYamlIndent(indent string) ([]byte, error) {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn gyaml.EncodeIndent(*(j.p), indent)\n}\n\nfunc (j *Json) ToYamlString() (string, error) {\n\tb, e := j.ToYaml()\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToYaml() []byte {\n\tresult, err := j.ToYaml()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToYamlString() string {\n\treturn string(j.MustToYaml())\n}\n\n// ========================================================================\n// TOML\n// ========================================================================\n\nfunc (j *Json) ToToml() ([]byte, error) {\n\tj.mu.RLock()\n\tdefer j.mu.RUnlock()\n\treturn gtoml.Encode(*(j.p))\n}\n\nfunc (j *Json) ToTomlString() (string, error) {\n\tb, e := j.ToToml()\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToToml() []byte {\n\tresult, err := j.ToToml()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\nfunc (j *Json) MustToTomlString() string {\n\treturn string(j.MustToToml())\n}\n\n// ========================================================================\n// INI\n// ========================================================================\n\n// ToIni json to ini\nfunc (j *Json) ToIni() ([]byte, error) {\n\treturn gini.Encode(j.Map())\n}\n\n// ToIniString ini to string\nfunc (j *Json) ToIniString() (string, error) {\n\tb, e := j.ToIni()\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToIni() []byte {\n\tresult, err := j.ToIni()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// MustToIniString .\nfunc (j *Json) MustToIniString() string {\n\treturn string(j.MustToIni())\n}\n\n// ========================================================================\n// properties\n// ========================================================================\n// Toproperties json to properties\nfunc (j *Json) ToProperties() ([]byte, error) {\n\treturn gproperties.Encode(j.Map())\n}\n\n// ToPropertiesString properties to string\nfunc (j *Json) ToPropertiesString() (string, error) {\n\tb, e := j.ToProperties()\n\treturn string(b), e\n}\n\nfunc (j *Json) MustToProperties() []byte {\n\tresult, err := j.ToProperties()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n\n// MustToPropertiesString\nfunc (j *Json) MustToPropertiesString() string {\n\treturn string(j.MustToProperties())\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api_new_load.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// New creates a Json object with any variable type of `data`, but `data` should be a map\n// or slice for data access reason, or it will make no sense.\n//\n// The parameter `safe` specifies whether using this Json object in concurrent-safe context,\n// which is false in default.\nfunc New(data any, safe ...bool) *Json {\n\treturn NewWithTag(data, string(ContentTypeJSON), safe...)\n}\n\n// NewWithTag creates a Json object with any variable type of `data`, but `data` should be a map\n// or slice for data access reason, or it will make no sense.\n//\n// The parameter `tags` specifies priority tags for struct conversion to map, multiple tags joined\n// with char ','.\n//\n// The parameter `safe` specifies whether using this Json object in concurrent-safe context, which\n// is false in default.\nfunc NewWithTag(data any, tags string, safe ...bool) *Json {\n\toption := Options{\n\t\tTags: tags,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn NewWithOptions(data, option)\n}\n\n// NewWithOptions creates a Json object with any variable type of `data`, but `data` should be a map\n// or slice for data access reason, or it will make no sense.\nfunc NewWithOptions(data any, options Options) *Json {\n\tvar j *Json\n\tswitch result := data.(type) {\n\tcase []byte:\n\t\tif r, err := loadContentWithOptions(result, options); err == nil {\n\t\t\tj = r\n\t\t\tbreak\n\t\t}\n\t\tj = &Json{\n\t\t\tp:  &data,\n\t\t\tc:  byte(defaultSplitChar),\n\t\t\tvc: false,\n\t\t}\n\tcase string:\n\t\tif r, err := loadContentWithOptions([]byte(result), options); err == nil {\n\t\t\tj = r\n\t\t\tbreak\n\t\t}\n\t\tj = &Json{\n\t\t\tp:  &data,\n\t\t\tc:  byte(defaultSplitChar),\n\t\t\tvc: false,\n\t\t}\n\tdefault:\n\t\tvar (\n\t\t\tpointedData any\n\t\t\treflectInfo = reflection.OriginValueAndKind(data)\n\t\t)\n\t\tswitch reflectInfo.OriginKind {\n\t\tcase reflect.Slice, reflect.Array:\n\t\t\tpointedData = gconv.Interfaces(data)\n\n\t\tcase reflect.Map:\n\t\t\tpointedData = gconv.Map(data, gconv.MapOption{\n\t\t\t\tDeep:            true,\n\t\t\t\tOmitEmpty:       false,\n\t\t\t\tTags:            []string{options.Tags},\n\t\t\t\tContinueOnError: true,\n\t\t\t})\n\n\t\tcase reflect.Struct:\n\t\t\tif v, ok := data.(iVal); ok {\n\t\t\t\treturn NewWithOptions(v.Val(), options)\n\t\t\t}\n\t\t\tpointedData = gconv.Map(data, gconv.MapOption{\n\t\t\t\tDeep:            true,\n\t\t\t\tOmitEmpty:       false,\n\t\t\t\tTags:            []string{options.Tags},\n\t\t\t\tContinueOnError: true,\n\t\t\t})\n\n\t\tdefault:\n\t\t\tpointedData = data\n\t\t}\n\t\tj = &Json{\n\t\t\tp:  &pointedData,\n\t\t\tc:  byte(defaultSplitChar),\n\t\t\tvc: false,\n\t\t}\n\t}\n\tj.mu = rwmutex.Create(options.Safe)\n\treturn j\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api_new_load_content.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/gogf/gf/v2/encoding/gini\"\n\t\"github.com/gogf/gf/v2/encoding/gproperties\"\n\t\"github.com/gogf/gf/v2/encoding/gtoml\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/encoding/gyaml\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// LoadWithOptions creates a Json object from given JSON format content and options.\nfunc LoadWithOptions(data []byte, options Options) (*Json, error) {\n\treturn loadContentWithOptions(data, options)\n}\n\n// LoadJson creates a Json object from given JSON format content.\nfunc LoadJson(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeJSON,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadXml creates a Json object from given XML format content.\nfunc LoadXml(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeXML,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadIni creates a Json object from given INI format content.\nfunc LoadIni(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeIni,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadYaml creates a Json object from given YAML format content.\nfunc LoadYaml(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeYaml,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadToml creates a Json object from given TOML format content.\nfunc LoadToml(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeToml,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadProperties creates a Json object from given TOML format content.\nfunc LoadProperties(data []byte, safe ...bool) (*Json, error) {\n\tvar option = Options{\n\t\tType: ContentTypeProperties,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toption.Safe = true\n\t}\n\treturn loadContentWithOptions(data, option)\n}\n\n// LoadContent creates a Json object from given content, it checks the data type of `content`\n// automatically, supporting data content type as follows:\n// JSON, XML, INI, YAML and TOML.\nfunc LoadContent(data []byte, safe ...bool) (*Json, error) {\n\treturn LoadContentType(\"\", data, safe...)\n}\n\n// LoadContentType creates a Json object from given type and content,\n// supporting data content type as follows:\n// JSON, XML, INI, YAML and TOML.\nfunc LoadContentType(dataType ContentType, data []byte, safe ...bool) (*Json, error) {\n\tif len(data) == 0 {\n\t\treturn New(nil, safe...), nil\n\t}\n\tvar options = Options{\n\t\tType:      dataType,\n\t\tStrNumber: true,\n\t}\n\tif len(safe) > 0 && safe[0] {\n\t\toptions.Safe = true\n\t}\n\treturn loadContentWithOptions(data, options)\n}\n\n// IsValidDataType checks and returns whether given `dataType` a valid data type for loading.\nfunc IsValidDataType(dataType ContentType) bool {\n\tif dataType == \"\" {\n\t\treturn false\n\t}\n\tif dataType[0] == '.' {\n\t\tdataType = dataType[1:]\n\t}\n\tswitch dataType {\n\tcase\n\t\tContentTypeJSON,\n\t\tContentTypeJs,\n\t\tContentTypeXML,\n\t\tContentTypeYaml,\n\t\tContentTypeYml,\n\t\tContentTypeToml,\n\t\tContentTypeIni,\n\t\tContentTypeProperties:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc trimBOM(data []byte) []byte {\n\tif len(data) < 3 {\n\t\treturn data\n\t}\n\tif data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {\n\t\tdata = data[3:]\n\t}\n\treturn data\n}\n\n// loadContentWithOptions creates a Json object from given content.\n// It supports data content type as follows:\n// JSON, XML, INI, YAML and TOML.\nfunc loadContentWithOptions(data []byte, options Options) (*Json, error) {\n\tvar (\n\t\terr    error\n\t\tresult any\n\t)\n\tdata = trimBOM(data)\n\tif len(data) == 0 {\n\t\treturn NewWithOptions(nil, options), nil\n\t}\n\tvar (\n\t\tcheckType   ContentType\n\t\tdecodedData any\n\t)\n\tif options.Type != \"\" {\n\t\tcheckType = gstr.TrimLeft(options.Type, \".\")\n\t} else {\n\t\tcheckType, err = checkDataType(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tswitch checkType {\n\tcase ContentTypeJSON, ContentTypeJs:\n\t\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\t\tif options.StrNumber {\n\t\t\tdecoder.UseNumber()\n\t\t}\n\t\tif err = decoder.Decode(&result); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tswitch result.(type) {\n\t\tcase string, []byte:\n\t\t\treturn nil, gerror.Newf(`json decoding failed for content: %s`, data)\n\t\t}\n\t\treturn NewWithOptions(result, options), nil\n\n\tcase ContentTypeXML:\n\t\tdecodedData, err = gxml.Decode(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewWithOptions(decodedData, options), nil\n\n\tcase ContentTypeYaml, ContentTypeYml:\n\t\tdecodedData, err = gyaml.Decode(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewWithOptions(decodedData, options), nil\n\n\tcase ContentTypeToml:\n\t\tdecodedData, err = gtoml.Decode(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewWithOptions(decodedData, options), nil\n\n\tcase ContentTypeIni:\n\t\tdecodedData, err = gini.Decode(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewWithOptions(decodedData, options), nil\n\n\tcase ContentTypeProperties:\n\t\tdecodedData, err = gproperties.Decode(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewWithOptions(decodedData, options), nil\n\n\tdefault:\n\t}\n\t// ignore some duplicated types, like js and yml,\n\t// which are not necessary shown in error message.\n\tallSupportedTypes := []string{\n\t\tContentTypeJSON,\n\t\tContentTypeXML,\n\t\tContentTypeYaml,\n\t\tContentTypeToml,\n\t\tContentTypeIni,\n\t\tContentTypeProperties,\n\t}\n\treturn nil, gerror.NewCodef(\n\t\tgcode.CodeInvalidParameter,\n\t\t`unsupported type \"%s\" for loading, all supported types: %s`,\n\t\toptions.Type, gstr.Join(allSupportedTypes, \", \"),\n\t)\n}\n\n// checkDataType automatically checks and returns the data type for `content`.\n// Note that it uses regular expression for loose checking, you can use LoadXXX/LoadContentType\n// functions to load the content for certain content type.\n// TODO it is not graceful here automatic judging the data type.\n// TODO it might be removed in the future, which lets the user explicitly specify the data type not automatic checking.\nfunc checkDataType(data []byte) (ContentType, error) {\n\tswitch {\n\tcase json.Valid(data):\n\t\treturn ContentTypeJSON, nil\n\n\tcase isXMLContent(data):\n\t\treturn ContentTypeXML, nil\n\n\tcase isYamlContent(data):\n\t\treturn ContentTypeYaml, nil\n\n\tcase isTomlContent(data):\n\t\treturn ContentTypeToml, nil\n\n\tcase isIniContent(data):\n\t\t// Must contain \"[xxx]\" section.\n\t\treturn ContentTypeIni, nil\n\n\tcase isPropertyContent(data):\n\t\treturn ContentTypeProperties, nil\n\n\tdefault:\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeOperationFailed,\n\t\t\t`unable auto check the data format type`,\n\t\t)\n\t}\n}\n\n// isXMLContent checks whether given content is XML format.\n// XML format is easy to be identified using regular expression.\nfunc isXMLContent(data []byte) bool {\n\treturn gregex.IsMatch(`^\\s*<.+>[\\S\\s]+<.+>\\s*$`, data)\n}\n\n// isYamlContent checks whether given content is YAML format.\nfunc isYamlContent(data []byte) bool {\n\t// x = y\n\t// \"x.x\" = \"y\"\n\ttomlFormat1 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\"\"\"[\\s\\S]+\"\"\"`, data)\n\tif tomlFormat1 {\n\t\treturn false\n\t}\n\t// \"x.x\" = '''\n\t// y\n\t// '''\n\ttomlFormat2 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*'''[\\s\\S]+'''`, data)\n\tif tomlFormat2 {\n\t\treturn false\n\t}\n\n\t// content starts with:\n\t// x : \"y\"\n\tyamlFormat1 := gregex.IsMatch(`^[\\n\\r]*[\\w\\-\\s\\t]+\\s*:\\s+\".+\"`, data)\n\n\t// content starts with:\n\t// x : y\n\tyamlFormat2 := gregex.IsMatch(`^[\\n\\r]*[\\w\\-\\s\\t]+\\s*:\\s+\\w+`, data)\n\n\t// line starts with:\n\t// x : \"y\"\n\tyamlFormat3 := gregex.IsMatch(`[\\n\\r]+[\\w\\-\\s\\t]+\\s*:\\s+\".+\"`, data)\n\n\t// line starts with:\n\t// x : y\n\tyamlFormat4 := gregex.IsMatch(`[\\n\\r]+[\\w\\-\\s\\t]+\\s*:\\s+\\w+`, data)\n\n\t// content starts with:\n\t// \"x\" : \"y\"\n\tyamlFormat5 := gregex.IsMatch(`^[\\n\\r]*\".+\":\\s+\".+\"`, data)\n\n\t// line starts with:\n\t// \"x\" : y\n\tyamlFormat6 := gregex.IsMatch(`[\\n\\r]+\".+\":\\s+\\w+`, data)\n\n\treturn yamlFormat1 || yamlFormat2 || yamlFormat3 || yamlFormat4 || yamlFormat5 || yamlFormat6\n}\n\n// isTomlContent checks whether given content is TOML format.\nfunc isTomlContent(data []byte) bool {\n\t// content starts with:\n\t// ; comment line\n\tcontentStartsWithSemicolonComment := gregex.IsMatch(`^[\\s\\t\\n\\r]*;.+`, data)\n\tif contentStartsWithSemicolonComment {\n\t\treturn false\n\t}\n\t// line starts with:\n\t// ; comment line\n\tlineStartsWithSemicolonComment := gregex.IsMatch(`[\\s\\t\\n\\r]+;.+`, data)\n\tif lineStartsWithSemicolonComment {\n\t\treturn false\n\t}\n\n\t// line starts with, this should not be toml format:\n\t// key.with.dot = value\n\tkeyWithDot := gregex.IsMatch(`[\\n\\r]+[\\s\\t\\w\\-]+\\.[\\s\\t\\w\\-]+\\s*=\\s*.+`, data)\n\tif keyWithDot {\n\t\treturn false\n\t}\n\n\t// line starts with:\n\t// key = value\n\t// key = \"value\"\n\t// \"key\" = \"value\"\n\t// \"key\" = value\n\ttomlFormat1 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\".+\"`, data)\n\ttomlFormat2 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\\w+`, data)\n\treturn tomlFormat1 || tomlFormat2\n}\n\n// isIniContent checks whether given content is INI format.\nfunc isIniContent(data []byte) bool {\n\t// no section like: [section], but ini format must have sections.\n\thasBrackets := gregex.IsMatch(`\\[[\\w\\.]+\\]`, data)\n\tif !hasBrackets {\n\t\treturn false\n\t}\n\tiniFormat1 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\".+\"`, data)\n\tiniFormat2 := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\\w+`, data)\n\treturn iniFormat1 || iniFormat2\n}\n\n// isPropertyContent checks whether given content is Properties format.\nfunc isPropertyContent(data []byte) bool {\n\t// line starts with:\n\t// key = value\n\t// \"key\" = value\n\tpropertyFormat := gregex.IsMatch(`[\\n\\r]*[\\s\\t\\w\\-\\.\"]+\\s*=\\s*\\w+`, data)\n\treturn propertyFormat\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_api_new_load_path.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport \"github.com/gogf/gf/v2/os/gfile\"\n\n// Load loads content from specified file `path`, and creates a Json object from its content.\n//\n// Deprecated: use LoadPath instead.\nfunc Load(path string, safe ...bool) (*Json, error) {\n\tvar isSafe bool\n\tif len(safe) > 0 {\n\t\tisSafe = safe[0]\n\t}\n\treturn LoadPath(path, Options{\n\t\tSafe: isSafe,\n\t})\n}\n\n// LoadPath loads content from specified file `path`, and creates a Json object from its content.\nfunc LoadPath(path string, options Options) (*Json, error) {\n\tif p, err := gfile.Search(path); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\tpath = p\n\t}\n\tif options.Type == \"\" {\n\t\toptions.Type = gfile.Ext(path)\n\t}\n\treturn loadContentWithOptions(gfile.GetBytes(path), options)\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_implements.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (j Json) MarshalJSON() ([]byte, error) {\n\treturn j.ToJson()\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (j *Json) UnmarshalJSON(b []byte) error {\n\tr, err := loadContentWithOptions(b, Options{\n\t\tType:      ContentTypeJSON,\n\t\tStrNumber: true,\n\t})\n\tif r != nil {\n\t\t// Value copy.\n\t\t*j = *r\n\t}\n\treturn err\n}\n\n// UnmarshalValue is an interface implement which sets any type of value for Json.\nfunc (j *Json) UnmarshalValue(value any) error {\n\tif r := NewWithOptions(value, Options{\n\t\tStrNumber: true,\n\t}); r != nil {\n\t\t// Value copy.\n\t\t*j = *r\n\t}\n\treturn nil\n}\n\n// MapStrAny implements interface function MapStrAny().\nfunc (j *Json) MapStrAny() map[string]any {\n\tif j == nil {\n\t\treturn nil\n\t}\n\treturn j.Map()\n}\n\n// Interfaces implements interface function Interfaces().\nfunc (j *Json) Interfaces() []any {\n\tif j == nil {\n\t\treturn nil\n\t}\n\treturn j.Array()\n}\n\n// String returns current Json object as string.\nfunc (j *Json) String() string {\n\tif j.IsNil() {\n\t\treturn \"\"\n\t}\n\treturn j.MustToJsonString()\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_stdlib_json_util.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Valid checks whether `data` is a valid JSON data type.\n// The parameter `data` specifies the json format data, which can be either\n// bytes or string type.\nfunc Valid(data any) bool {\n\treturn json.Valid(gconv.Bytes(data))\n}\n\n// Marshal is alias of Encode in order to fit the habit of json.Marshal/Unmarshal functions.\nfunc Marshal(v any) (marshaledBytes []byte, err error) {\n\treturn Encode(v)\n}\n\n// MarshalIndent is alias of json.MarshalIndent in order to fit the habit of json.MarshalIndent function.\nfunc MarshalIndent(v any, prefix, indent string) (marshaledBytes []byte, err error) {\n\treturn json.MarshalIndent(v, prefix, indent)\n}\n\n// Unmarshal is alias of DecodeTo in order to fit the habit of json.Marshal/Unmarshal functions.\nfunc Unmarshal(data []byte, v any) (err error) {\n\treturn DecodeTo(data, v)\n}\n\n// Encode encodes any golang variable `value` to JSON bytes.\nfunc Encode(value any) ([]byte, error) {\n\treturn json.Marshal(value)\n}\n\n// MustEncode performs as Encode, but it panics if any error occurs.\nfunc MustEncode(value any) []byte {\n\tb, err := Encode(value)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn b\n}\n\n// EncodeString encodes any golang variable `value` to JSON string.\nfunc EncodeString(value any) (string, error) {\n\tb, err := json.Marshal(value)\n\treturn string(b), err\n}\n\n// MustEncodeString encodes any golang variable `value` to JSON string.\n// It panics if any error occurs.\nfunc MustEncodeString(value any) string {\n\treturn string(MustEncode(value))\n}\n\n// Decode decodes json format `data` to golang variable.\n// The parameter `data` can be either bytes or string type.\nfunc Decode(data any, options ...Options) (any, error) {\n\tvar value any\n\tif err := DecodeTo(gconv.Bytes(data), &value, options...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn value, nil\n\t}\n}\n\n// DecodeTo decodes json format `data` to specified golang variable `v`.\n// The parameter `data` can be either bytes or string type.\n// The parameter `v` should be a pointer type.\nfunc DecodeTo(data any, v any, options ...Options) (err error) {\n\tdecoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data)))\n\tif len(options) > 0 {\n\t\t// The StrNumber option is for certain situations, not for all.\n\t\t// For example, it causes converting issue for other data formats, for example: yaml.\n\t\tif options[0].StrNumber {\n\t\t\tdecoder.UseNumber()\n\t\t}\n\t}\n\tif err = decoder.Decode(v); err != nil {\n\t\terr = gerror.Wrap(err, `json Decode failed`)\n\t}\n\treturn\n}\n\n// DecodeToJson codes json format `data` to a Json object.\n// The parameter `data` can be either bytes or string type.\nfunc DecodeToJson(data any, options ...Options) (*Json, error) {\n\tif v, err := Decode(gconv.Bytes(data), options...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\tif len(options) > 0 {\n\t\t\treturn New(v, options[0].Safe), nil\n\t\t}\n\t\treturn New(v), nil\n\t}\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\tjson2 \"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nvar (\n\tjsonStr1 = `{\"name\":\"john\",\"slice\":[1,2,3]}`\n\tjsonStr2 = `{\"CallbackCommand\":\"Group.CallbackAfterSendMsg\",\"From_Account\":\"61934946\",\"GroupId\":\"@TGS#2FLGX67FD\",\"MsgBody\":[{\"MsgContent\":{\"Text\":\"是的\"},\"MsgType\":\"TIMTextElem\"}],\"MsgSeq\":23,\"MsgTime\":1567032819,\"Operator_Account\":\"61934946\",\"Random\":2804799576,\"Type\":\"Public\"}`\n\tjsonObj1 = gjson.New(jsonStr1)\n\tjsonObj2 = gjson.New(jsonStr2)\n)\n\nfunc Benchmark_Validate_Simple_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgjson.Valid(jsonStr1)\n\t}\n}\n\nfunc Benchmark_Validate_Complicated_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgjson.Valid(jsonStr2)\n\t}\n}\n\nfunc Benchmark_Get_Simple_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjsonObj1.Get(\"name\")\n\t}\n}\n\nfunc Benchmark_Get_Complicated_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjsonObj2.Get(\"GroupId\")\n\t}\n}\n\nfunc Benchmark_Stdlib_Json_Unmarshal_Simple_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvar m map[string]any\n\t\tjson2.Unmarshal([]byte(jsonStr1), &m)\n\t}\n}\n\nfunc Benchmark_Stdlib_Json_Unmarshal_Complicated_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvar m map[string]any\n\t\tjson2.Unmarshal([]byte(jsonStr2), &m)\n\t}\n}\n\nfunc Benchmark_New_Simple_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgjson.New(jsonStr1)\n\t}\n}\n\nfunc Benchmark_New_Complicated_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgjson.New(jsonStr2)\n\t}\n}\n\nfunc Benchmark_Remove_Simple_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjsonObj1.Remove(\"name\")\n\t}\n}\n\nfunc Benchmark_Remove_Complicated_Json(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tjsonObj2.Remove(\"GroupId\")\n\t}\n}\n\nfunc Benchmark_New_Nil_And_Set_Simple(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tp := gjson.New(nil)\n\t\tp.Set(\"k\", \"v\")\n\t}\n}\n\nfunc Benchmark_New_Nil_And_Set_Multiple_Level(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tp := gjson.New(nil)\n\t\tp.Set(\"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\", []int{1, 2, 3})\n\t}\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_conversion_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nfunc ExampleJson_data() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }`\n\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tfmt.Println(\"JSON:\")\n\t\tfmt.Println(j.MustToJsonString())\n\t\tfmt.Println(\"======================\")\n\n\t\tfmt.Println(\"XML:\")\n\t\tfmt.Println(j.MustToXmlString())\n\t\tfmt.Println(\"======================\")\n\n\t\tfmt.Println(\"YAML:\")\n\t\tfmt.Println(j.MustToYamlString())\n\t\tfmt.Println(\"======================\")\n\n\t\tfmt.Println(\"TOML:\")\n\t\tfmt.Println(j.MustToTomlString())\n\t}\n\n\t// Output:\n\t// JSON:\n\t// {\"users\":{\"array\":[\"John\",\"Ming\"],\"count\":1}}\n\t// ======================\n\t// XML:\n\t// <users><array>John</array><array>Ming</array><count>1</count></users>\n\t// ======================\n\t// YAML:\n\t// users:\n\t//     array:\n\t//         - John\n\t//         - Ming\n\t//     count: 1\n\t//\n\t// ======================\n\t// TOML:\n\t// [users]\n\t//   array = [\"John\", \"Ming\"]\n\t//   count = 1.0\n}\n\nfunc ExampleJson_Get_data() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\ttype Users struct {\n\t\t\tCount int\n\t\t\tArray []string\n\t\t}\n\t\tusers := new(Users)\n\t\tif err := j.Get(\"users\").Scan(users); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Printf(`%+v`, users)\n\t}\n\n\t// Output:\n\t// &{Count:1 Array:[John Ming]}\n}\n\nfunc ExampleJson_Scan_data() {\n\tdata :=\n\t\t`\n\t{\n        \"count\" : 1,\n        \"array\" : [\"John\", \"Ming\"]\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\ttype Users struct {\n\t\t\tCount int\n\t\t\tArray []string\n\t\t}\n\t\tusers := new(Users)\n\t\tif err := j.Var().Scan(users); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Printf(`%+v`, users)\n\t}\n\n\t// Output:\n\t// &{Count:1 Array:[John Ming]}\n}\n\nfunc ExampleValid() {\n\tdata1 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tdata2 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]`)\n\tfmt.Println(gjson.Valid(data1))\n\tfmt.Println(gjson.Valid(data2))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleMarshal() {\n\tdata := map[string]any{\n\t\t\"name\":  \"john\",\n\t\t\"score\": 100,\n\t}\n\n\tjsonData, _ := gjson.Marshal(data)\n\tfmt.Println(string(jsonData))\n\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"Guo Qiang\",\n\t\tAge:  18,\n\t}\n\n\tinfoData, _ := gjson.Marshal(info)\n\tfmt.Println(string(infoData))\n\n\t// Output:\n\t// {\"name\":\"john\",\"score\":100}\n\t// {\"Name\":\"Guo Qiang\",\"Age\":18}\n}\n\nfunc ExampleMarshalIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tinfoData, _ := gjson.MarshalIndent(info, \"\", \"\\t\")\n\tfmt.Println(string(infoData))\n\n\t// Output:\n\t// {\n\t//\t\"Name\": \"John\",\n\t//\t\"Age\": 18\n\t// }\n}\n\nfunc ExampleUnmarshal() {\n\ttype BaseInfo struct {\n\t\tName  string\n\t\tScore int\n\t}\n\n\tvar info BaseInfo\n\n\tjsonContent := \"{\\\"name\\\":\\\"john\\\",\\\"score\\\":100}\"\n\tgjson.Unmarshal([]byte(jsonContent), &info)\n\tfmt.Printf(\"%+v\", info)\n\n\t// Output:\n\t// {Name:john Score:100}\n}\n\nfunc ExampleEncode() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tinfoData, _ := gjson.Encode(info)\n\tfmt.Println(string(infoData))\n\n\t// Output:\n\t// {\"Name\":\"John\",\"Age\":18}\n}\n\nfunc ExampleMustEncode() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tinfoData := gjson.MustEncode(info)\n\tfmt.Println(string(infoData))\n\n\t// Output:\n\t// {\"Name\":\"John\",\"Age\":18}\n}\n\nfunc ExampleEncodeString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tinfoData, _ := gjson.EncodeString(info)\n\tfmt.Println(infoData)\n\n\t// Output:\n\t// {\"Name\":\"John\",\"Age\":18}\n}\n\nfunc ExampleMustEncodeString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tinfoData := gjson.MustEncodeString(info)\n\tfmt.Println(infoData)\n\n\t// Output:\n\t// {\"Name\":\"John\",\"Age\":18}\n}\n\nfunc ExampleDecode() {\n\tjsonContent := `{\"name\":\"john\",\"score\":100}`\n\tinfo, _ := gjson.Decode([]byte(jsonContent))\n\tfmt.Println(info)\n\n\t// Output:\n\t// map[name:john score:100]\n}\n\nfunc ExampleDecodeTo() {\n\ttype BaseInfo struct {\n\t\tName  string\n\t\tScore int\n\t}\n\n\tvar info BaseInfo\n\n\tjsonContent := \"{\\\"name\\\":\\\"john\\\",\\\"score\\\":100}\"\n\tgjson.DecodeTo([]byte(jsonContent), &info)\n\tfmt.Printf(\"%+v\", info)\n\n\t// Output:\n\t// {Name:john Score:100}\n}\n\nfunc ExampleDecodeToJson() {\n\tjsonContent := `{\"name\":\"john\",\"score\":100}\"`\n\tj, _ := gjson.DecodeToJson([]byte(jsonContent))\n\tfmt.Println(j.Map())\n\n\t// May Output:\n\t// map[name:john score:100]\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_dataset_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nfunc ExampleJson_Set_j() {\n\tj := gjson.New(nil)\n\tj.Set(\"name\", \"John\")\n\tj.Set(\"score\", 99.5)\n\tfmt.Printf(\n\t\t\"Name: %s, Score: %v\\n\",\n\t\tj.Get(\"name\").String(),\n\t\tj.Get(\"score\").Float32(),\n\t)\n\tfmt.Println(j.MustToJsonString())\n\n\t// Output:\n\t// Name: John, Score: 99.5\n\t// {\"name\":\"John\",\"score\":99.5}\n}\n\nfunc ExampleJson_Set_sprintf() {\n\tj := gjson.New(nil)\n\tfor i := 0; i < 5; i++ {\n\t\tj.Set(fmt.Sprintf(`%d.id`, i), i)\n\t\tj.Set(fmt.Sprintf(`%d.name`, i), fmt.Sprintf(`student-%d`, i))\n\t}\n\tfmt.Println(j.MustToJsonString())\n\n\t// Output:\n\t// [{\"id\":0,\"name\":\"student-0\"},{\"id\":1,\"name\":\"student-1\"},{\"id\":2,\"name\":\"student-2\"},{\"id\":3,\"name\":\"student-3\"},{\"id\":4,\"name\":\"student-4\"}]\n}\n\nfunc ExampleJson_Set_data() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 2,\n            \"list\"  : [\n                {\"name\" : \"Ming\", \"score\" : 60},\n                {\"name\" : \"John\", \"score\" : 59}\n            ]\n        }\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tj.Set(\"users.list.1.score\", 100)\n\t\tfmt.Println(\"John Score:\", j.Get(\"users.list.1.score\").Float32())\n\t\tfmt.Println(j.MustToJsonString())\n\t}\n\t// Output:\n\t// John Score: 100\n\t// {\"users\":{\"count\":2,\"list\":[{\"name\":\"Ming\",\"score\":60},{\"name\":\"John\",\"score\":100}]}}\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_load_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc ExampleLoad() {\n\tjsonFilePath := gtest.DataPath(\"json\", \"data1.json\")\n\tj, _ := gjson.Load(jsonFilePath)\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\tnotExistFilePath := gtest.DataPath(\"json\", \"data2.json\")\n\tj2, _ := gjson.Load(notExistFilePath)\n\tfmt.Println(j2.Get(\"name\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadJson() {\n\tjsonContent := []byte(`{\"name\":\"john\", \"score\":\"100\"}`)\n\tj, _ := gjson.LoadJson(jsonContent)\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadXml() {\n\txmlContent := []byte(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<base>\n\t<name>john</name>\n\t<score>100</score>\n</base>\n`)\n\tj, _ := gjson.LoadXml(xmlContent)\n\tfmt.Println(j.Get(\"base.name\"))\n\tfmt.Println(j.Get(\"base.score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadIni() {\n\tiniContent := []byte(`\n[base]\nname = john\nscore = 100\n`)\n\tj, _ := gjson.LoadIni(iniContent)\n\tfmt.Println(j.Get(\"base.name\"))\n\tfmt.Println(j.Get(\"base.score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadYaml() {\n\tyamlContent := []byte(`\nbase:\n  name: john\n  score: 100\n`)\n\n\tj, _ := gjson.LoadYaml(yamlContent)\n\tfmt.Println(j.Get(\"base.name\"))\n\tfmt.Println(j.Get(\"base.score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadToml() {\n\ttomlContent := []byte(`\n[base]\n  name = \"john\"\n  score = 100\n`)\n\n\tj, _ := gjson.LoadToml(tomlContent)\n\tfmt.Println(j.Get(\"base.name\"))\n\tfmt.Println(j.Get(\"base.score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadContent() {\n\tjsonContent := []byte(`{\"name\":\"john\", \"score\":\"100\"}`)\n\n\tj, _ := gjson.LoadContent(jsonContent)\n\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadContent_jsonContent() {\n\tjsonContent := `{\"name\":\"john\", \"score\":\"100\"}`\n\n\tcontent := make([]byte, 3, len(jsonContent)+3)\n\tcontent[0] = 0xEF\n\tcontent[1] = 0xBB\n\tcontent[2] = 0xBF\n\tcontent = append(content, jsonContent...)\n\n\tj, _ := gjson.LoadContent(content)\n\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadContent_xml_content() {\n\txmlContent := []byte(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<base>\n\t<name>john</name>\n\t<score>100</score>\n</base>\n`)\n\n\tx, _ := gjson.LoadContent(xmlContent)\n\n\tfmt.Println(x.Get(\"base.name\"))\n\tfmt.Println(x.Get(\"base.score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleLoadContentType() {\n\tvar (\n\t\tjsonContent = []byte(`{\"name\":\"john\", \"score\":\"100\"}`)\n\t\txmlContent  = []byte(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<base>\n\t<name>john</name>\n\t<score>100</score>\n</base>\n`)\n\t)\n\n\tj, _ := gjson.LoadContentType(\"json\", jsonContent)\n\tx, _ := gjson.LoadContentType(\"xml\", xmlContent)\n\tj1, _ := gjson.LoadContentType(\"json\", []byte(\"\"))\n\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\tfmt.Println(x.Get(\"base.name\"))\n\tfmt.Println(x.Get(\"base.score\"))\n\tfmt.Println(j1.Get(\"\"))\n\n\t// Output:\n\t// john\n\t// 100\n\t// john\n\t// 100\n}\n\nfunc ExampleIsValidDataType() {\n\tfmt.Println(gjson.IsValidDataType(\"json\"))\n\tfmt.Println(gjson.IsValidDataType(\"yml\"))\n\tfmt.Println(gjson.IsValidDataType(\"js\"))\n\tfmt.Println(gjson.IsValidDataType(\"mp4\"))\n\tfmt.Println(gjson.IsValidDataType(\"xsl\"))\n\tfmt.Println(gjson.IsValidDataType(\"txt\"))\n\tfmt.Println(gjson.IsValidDataType(\"\"))\n\tfmt.Println(gjson.IsValidDataType(\".json\"))\n\tfmt.Println(gjson.IsValidDataType(\".properties\"))\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// false\n\t// false\n\t// false\n\t// false\n\t// true\n\t// true\n}\n\nfunc ExampleLoad_jsonFilePath() {\n\tjsonFilePath := gtest.DataPath(\"xml\", \"data1.xml\")\n\tj, _ := gjson.Load(jsonFilePath)\n\tfmt.Println(j.Get(\"doc.name\"))\n\tfmt.Println(j.Get(\"doc.score\"))\n}\n\nfunc ExampleLoadProperties() {\n\tjsonFilePath := gtest.DataPath(\"properties\", \"data1.properties\")\n\tj, _ := gjson.Load(jsonFilePath)\n\tfmt.Println(j.Get(\"pr.name\"))\n\tfmt.Println(j.Get(\"pr.score\"))\n\tfmt.Println(j.Get(\"pr.sex\"))\n\n\t// Output:\n\t// john\n\t// 100\n\t// 0\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_new_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nfunc ExampleNew() {\n\tjsonContent := `{\"name\":\"john\", \"score\":\"100\"}`\n\tj := gjson.New(jsonContent)\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleNewWithTag() {\n\ttype Me struct {\n\t\tName  string `tag:\"name\"`\n\t\tScore int    `tag:\"score\"`\n\t\tTitle string\n\t}\n\tme := Me{\n\t\tName:  \"john\",\n\t\tScore: 100,\n\t\tTitle: \"engineer\",\n\t}\n\tj := gjson.NewWithTag(me, \"tag\", true)\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\tfmt.Println(j.Get(\"Title\"))\n\n\t// Output:\n\t// john\n\t// 100\n\t// engineer\n}\n\nfunc ExampleNewWithOptions() {\n\ttype Me struct {\n\t\tName  string `tag:\"name\"`\n\t\tScore int    `tag:\"score\"`\n\t\tTitle string\n\t}\n\tme := Me{\n\t\tName:  \"john\",\n\t\tScore: 100,\n\t\tTitle: \"engineer\",\n\t}\n\n\tj := gjson.NewWithOptions(me, gjson.Options{\n\t\tTags: \"tag\",\n\t})\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\tfmt.Println(j.Get(\"Title\"))\n\n\t// Output:\n\t// john\n\t// 100\n\t// engineer\n}\n\nfunc ExampleNewWithOptions_jsonContent() {\n\tjsonContent := `{\"name\":\"john\", \"score\":\"100\"}`\n\n\tcontent := make([]byte, 3, len(jsonContent)+3)\n\tcontent[0] = 0xEF\n\tcontent[1] = 0xBB\n\tcontent[2] = 0xBF\n\tcontent = append(content, jsonContent...)\n\n\tj := gjson.NewWithOptions(content, gjson.Options{\n\t\tTags: \"tag\",\n\t})\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleNew_xmlContent() {\n\txmlContent := `<?xml version=\"1.0\" encoding=\"UTF-8\"?><doc><name>john</name><score>100</score></doc>`\n\tj := gjson.New(xmlContent)\n\t// Note that there's root node in the XML content.\n\tfmt.Println(j.Get(\"doc.name\"))\n\tfmt.Println(j.Get(\"doc.score\"))\n\t// Output:\n\t// john\n\t// 100\n}\n\nfunc ExampleNew_me() {\n\ttype Me struct {\n\t\tName  string `json:\"name\"`\n\t\tScore int    `json:\"score\"`\n\t}\n\tme := Me{\n\t\tName:  \"john\",\n\t\tScore: 100,\n\t}\n\tj := gjson.New(me)\n\tfmt.Println(j.Get(\"name\"))\n\tfmt.Println(j.Get(\"score\"))\n\t// Output:\n\t// john\n\t// 100\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_pattern_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nfunc ExampleJson_get_data() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 2,\n            \"list\"  : [\n                {\"name\" : \"Ming\",  \"score\" : 60},\n                {\"name\" : \"John\", \"score\" : 99.5}\n            ]\n        }\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tfmt.Println(\"John Score:\", j.Get(\"users.list.1.score\").Float32())\n\t}\n\t// Output:\n\t// John Score: 99.5\n}\n\nfunc ExampleJson_SetViolenceCheck_data() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 100\n        },\n        \"users.count\" : 101\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tj.SetViolenceCheck(true)\n\t\tfmt.Println(\"Users Count:\", j.Get(\"users.count\").Int())\n\t}\n\t// Output:\n\t// Users Count: 101\n}\n\nfunc ExampleJson_Get_jsonContent() {\n\tjsonContent := []byte(`{\"map\":{\"key\":\"value\"}, \"slice\":[59,90]}`)\n\tj, _ := gjson.LoadJson(jsonContent)\n\tm := j.Get(\"map\").Map()\n\tfmt.Println(m)\n\n\t// Change the key-value pair.\n\tm[\"key\"] = \"john\"\n\n\t// It changes the underlying key-value pair.\n\tfmt.Println(j.Get(\"map\").Map())\n\n\ts := j.Get(\"slice\").Array()\n\tfmt.Println(s)\n\n\t// Change the value of specified index.\n\ts[0] = 100\n\n\t// It changes the underlying slice.\n\tfmt.Println(j.Get(\"slice\").Array())\n\n\t// output:\n\t// map[key:value]\n\t// map[key:john]\n\t// [59 90]\n\t// [100 90]\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_example_test.go",
    "content": "package gjson_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n)\n\nfunc ExampleJson_SetSplitChar() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 2,\n            \"list\"  : [\n                {\"name\" : \"Ming\",  \"score\" : 60},\n                {\"name\" : \"John\", \"score\" : 99.5}\n            ]\n        }\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tj.SetSplitChar('#')\n\t\tfmt.Println(\"John Score:\", j.Get(\"users#list#1#score\").Float32())\n\t}\n\t// Output:\n\t// John Score: 99.5\n}\n\nfunc ExampleJson_SetViolenceCheck() {\n\tdata :=\n\t\t`{\n        \"users\" : {\n            \"count\" : 100\n        },\n        \"users.count\" : 101\n    }`\n\tif j, err := gjson.DecodeToJson(data); err != nil {\n\t\tfmt.Println(err)\n\t} else {\n\t\tj.SetViolenceCheck(false)\n\t\tfmt.Println(\"Users Count:\", j.Get(\"users.count\"))\n\t\tj.SetViolenceCheck(true)\n\t\tfmt.Println(\"Users Count:\", j.Get(\"users.count\"))\n\t}\n\t// Output:\n\t// Users Count: 100\n\t// Users Count: 101\n}\n\n// ========================================================================\n// JSON\n// ========================================================================\nfunc ExampleJson_ToJson() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonBytes, _ := j.ToJson()\n\tfmt.Println(string(jsonBytes))\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_ToJsonString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonStr, _ := j.ToJsonString()\n\tfmt.Println(jsonStr)\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_ToJsonIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonBytes, _ := j.ToJsonIndent()\n\tfmt.Println(string(jsonBytes))\n\n\t// Output:\n\t// {\n\t//\t\"Age\": 18,\n\t//\t\"Name\": \"John\"\n\t// }\n}\n\nfunc ExampleJson_ToJsonIndentString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonStr, _ := j.ToJsonIndentString()\n\tfmt.Println(jsonStr)\n\n\t// Output:\n\t// {\n\t//\t\"Age\": 18,\n\t//\t\"Name\": \"John\"\n\t// }\n}\n\nfunc ExampleJson_MustToJson() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonBytes := j.MustToJson()\n\tfmt.Println(string(jsonBytes))\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_MustToJsonString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonStr := j.MustToJsonString()\n\tfmt.Println(jsonStr)\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_MustToJsonIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonBytes := j.MustToJsonIndent()\n\tfmt.Println(string(jsonBytes))\n\n\t// Output:\n\t// {\n\t//\t\"Age\": 18,\n\t//\t\"Name\": \"John\"\n\t// }\n}\n\nfunc ExampleJson_MustToJsonIndentString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonStr := j.MustToJsonIndentString()\n\tfmt.Println(jsonStr)\n\n\t// Output:\n\t// {\n\t//\t\"Age\": 18,\n\t//\t\"Name\": \"John\"\n\t// }\n}\n\n// ========================================================================\n// XML\n// ========================================================================\nfunc ExampleJson_ToXml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlBytes, _ := j.ToXml()\n\tfmt.Println(string(xmlBytes))\n\n\t// Output:\n\t// <doc><Age>18</Age><Name>John</Name></doc>\n}\n\nfunc ExampleJson_ToXmlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlStr, _ := j.ToXmlString()\n\tfmt.Println(string(xmlStr))\n\n\t// Output:\n\t// <doc><Age>18</Age><Name>John</Name></doc>\n}\n\nfunc ExampleJson_ToXmlIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlBytes, _ := j.ToXmlIndent()\n\tfmt.Println(string(xmlBytes))\n\n\t// Output:\n\t// <doc>\n\t//\t<Age>18</Age>\n\t//\t<Name>John</Name>\n\t// </doc>\n}\n\nfunc ExampleJson_ToXmlIndentString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlStr, _ := j.ToXmlIndentString()\n\tfmt.Println(string(xmlStr))\n\n\t// Output:\n\t// <doc>\n\t//\t<Age>18</Age>\n\t//\t<Name>John</Name>\n\t// </doc>\n}\n\nfunc ExampleJson_MustToXml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlBytes := j.MustToXml()\n\tfmt.Println(string(xmlBytes))\n\n\t// Output:\n\t// <doc><Age>18</Age><Name>John</Name></doc>\n}\n\nfunc ExampleJson_MustToXmlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlStr := j.MustToXmlString()\n\tfmt.Println(string(xmlStr))\n\n\t// Output:\n\t// <doc><Age>18</Age><Name>John</Name></doc>\n}\n\nfunc ExampleJson_MustToXmlIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlBytes := j.MustToXmlIndent()\n\tfmt.Println(string(xmlBytes))\n\n\t// Output:\n\t// <doc>\n\t//\t<Age>18</Age>\n\t//\t<Name>John</Name>\n\t// </doc>\n}\n\nfunc ExampleJson_MustToXmlIndentString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\txmlStr := j.MustToXmlIndentString()\n\tfmt.Println(string(xmlStr))\n\n\t// Output:\n\t// <doc>\n\t//\t<Age>18</Age>\n\t//\t<Name>John</Name>\n\t// </doc>\n}\n\n// ========================================================================\n// YAML\n// ========================================================================\nfunc ExampleJson_ToYaml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tYamlBytes, _ := j.ToYaml()\n\tfmt.Println(string(YamlBytes))\n\n\t// Output:\n\t// Age: 18\n\t// Name: John\n}\n\nfunc ExampleJson_ToYamlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tYamlStr, _ := j.ToYamlString()\n\tfmt.Println(string(YamlStr))\n\n\t// Output:\n\t// Age: 18\n\t// Name: John\n}\n\nfunc ExampleJson_ToYamlIndent() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tYamlBytes, _ := j.ToYamlIndent(\"\")\n\tfmt.Println(string(YamlBytes))\n\n\t// Output:\n\t// Age: 18\n\t// Name: John\n}\n\nfunc ExampleJson_MustToYaml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tYamlBytes := j.MustToYaml()\n\tfmt.Println(string(YamlBytes))\n\n\t// Output:\n\t// Age: 18\n\t// Name: John\n}\n\nfunc ExampleJson_MustToYamlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tYamlStr := j.MustToYamlString()\n\tfmt.Println(string(YamlStr))\n\n\t// Output:\n\t// Age: 18\n\t// Name: John\n}\n\n// ========================================================================\n// TOML\n// ========================================================================\nfunc ExampleJson_ToToml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tTomlBytes, _ := j.ToToml()\n\tfmt.Println(string(TomlBytes))\n\n\t// Output:\n\t// Age = 18\n\t// Name = \"John\"\n}\n\nfunc ExampleJson_ToTomlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tTomlStr, _ := j.ToTomlString()\n\tfmt.Println(string(TomlStr))\n\n\t// Output:\n\t// Age = 18\n\t// Name = \"John\"\n}\n\nfunc ExampleJson_MustToToml() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tTomlBytes := j.MustToToml()\n\tfmt.Println(string(TomlBytes))\n\n\t// Output:\n\t// Age = 18\n\t// Name = \"John\"\n}\n\nfunc ExampleJson_MustToTomlString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tTomlStr := j.MustToTomlString()\n\tfmt.Println(string(TomlStr))\n\n\t// Output:\n\t// Age = 18\n\t// Name = \"John\"\n}\n\n// ========================================================================\n// INI\n// ========================================================================\nfunc ExampleJson_ToIni() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tIniBytes, _ := j.ToIni()\n\tfmt.Println(string(IniBytes))\n\n\t// May Output:\n\t// Name=John\n\t// Age=18\n}\n\nfunc ExampleJson_ToIniString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tIniStr, _ := j.ToIniString()\n\tfmt.Println(string(IniStr))\n\n\t// Output:\n\t// Name=John\n}\n\nfunc ExampleJson_MustToIni() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tIniBytes := j.MustToIni()\n\tfmt.Println(string(IniBytes))\n\n\t// Output:\n\t// Name=John\n}\n\nfunc ExampleJson_MustToIniString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tIniStr := j.MustToIniString()\n\tfmt.Println(string(IniStr))\n\n\t// Output:\n\t// Name=John\n}\n\n// ========================================================================\n// Properties\n// ========================================================================\nfunc ExampleJson_ToProperties() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tpr, _ := j.ToProperties()\n\tfmt.Println(string(pr))\n\n\t// May Output:\n\t// name = John\n\t// age = 18\n}\n\nfunc ExampleJson_ToPropertiesString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tpr, _ := j.ToPropertiesString()\n\tfmt.Println(pr)\n\n\t// Output:\n\t// name = John\n}\n\nfunc ExampleJson_MustToProperties() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tpr := j.MustToProperties()\n\tfmt.Println(string(pr))\n\n\t// Output:\n\t// name = John\n}\n\nfunc ExampleJson_MustToPropertiesString() {\n\ttype BaseInfo struct {\n\t\tName string\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t}\n\n\tj := gjson.New(info)\n\tpr := j.MustToPropertiesString()\n\tfmt.Println(pr)\n\n\t// Output:\n\t// name = John\n}\n\nfunc ExampleJson_MarshalJSON() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tjsonBytes, _ := j.MarshalJSON()\n\tfmt.Println(string(jsonBytes))\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_UnmarshalJSON() {\n\tjsonStr := `{\"Age\":18,\"Name\":\"John\"}`\n\n\tj := gjson.New(\"\")\n\tj.UnmarshalJSON([]byte(jsonStr))\n\tfmt.Println(j.Map())\n\n\t// Output:\n\t// map[Age:18 Name:John]\n}\n\nfunc ExampleJson_UnmarshalValue_yamlContent() {\n\tyamlContent :=\n\t\t`base:\n  name: john\n  score: 100`\n\n\tj := gjson.New(\"\")\n\tj.UnmarshalValue([]byte(yamlContent))\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"base\":{\"name\":\"john\",\"score\":100}}\n}\n\nfunc ExampleJson_UnmarshalValue_xmlStr() {\n\txmlStr := `<?xml version=\"1.0\" encoding=\"UTF-8\"?><doc><name>john</name><score>100</score></doc>`\n\n\tj := gjson.New(\"\")\n\tj.UnmarshalValue([]byte(xmlStr))\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"doc\":{\"name\":\"john\",\"score\":\"100\"}}\n}\n\nfunc ExampleJson_MapStrAny() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tfmt.Println(j.MapStrAny())\n\n\t// Output:\n\t// map[Age:18 Name:John]\n}\n\nfunc ExampleJson_Interfaces() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfoList := []BaseInfo{\n\t\t{\n\t\t\tName: \"John\",\n\t\t\tAge:  18,\n\t\t},\n\t\t{\n\t\t\tName: \"Tom\",\n\t\t\tAge:  20,\n\t\t},\n\t}\n\n\tj := gjson.New(infoList)\n\tfmt.Println(j.Interfaces())\n\n\t// Output:\n\t// [{John 18} {Tom 20}]\n}\n\nfunc ExampleJson_Interface() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tfmt.Println(j.Interface())\n\n\tvar nilJ *gjson.Json = nil\n\tfmt.Println(nilJ.Interface())\n\n\t// Output:\n\t// map[Age:18 Name:John]\n\t// <nil>\n}\n\nfunc ExampleJson_Var() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tfmt.Println(j.Var().String())\n\tfmt.Println(j.Var().Map())\n\n\t// Output:\n\t// {\"Age\":18,\"Name\":\"John\"}\n\t// map[Age:18 Name:John]\n}\n\nfunc ExampleJson_IsNil() {\n\tdata1 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tdata2 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]`)\n\n\tj1, _ := gjson.LoadContent(data1)\n\tfmt.Println(j1.IsNil())\n\n\tj2, _ := gjson.LoadContent(data2)\n\tfmt.Println(j2.IsNil())\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleJson_Get() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n\t\t\"count\" : 1,\n\t\t\"array\" : [\"John\", \"Ming\"]\n\t}\n}\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\tfmt.Println(j.Get(\".\"))\n\tfmt.Println(j.Get(\"users\"))\n\tfmt.Println(j.Get(\"users.count\"))\n\tfmt.Println(j.Get(\"users.array\"))\n\n\tvar nilJ *gjson.Json = nil\n\tfmt.Println(nilJ.Get(\".\"))\n\n\t// Output:\n\t// {\"users\":{\"array\":[\"John\",\"Ming\"],\"count\":1}}\n\t// {\"array\":[\"John\",\"Ming\"],\"count\":1}\n\t// 1\n\t// [\"John\",\"Ming\"]\n}\n\nfunc ExampleJson_GetJson() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tfmt.Println(j.GetJson(\"users.array\").Array())\n\n\t// Output:\n\t// [John Ming]\n}\n\nfunc ExampleJson_GetJsons() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 3,\n            \"array\" : [{\"Age\":18,\"Name\":\"John\"}, {\"Age\":20,\"Name\":\"Tom\"}]\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tjsons := j.GetJsons(\"users.array\")\n\tfor _, json := range jsons {\n\t\tfmt.Println(json.Interface())\n\t}\n\n\t// Output:\n\t// map[Age:18 Name:John]\n\t// map[Age:20 Name:Tom]\n}\n\nfunc ExampleJson_GetJsonMap() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n\t\t\t\"array\" : {\n\t\t\t\t\"info\" : {\"Age\":18,\"Name\":\"John\"},\n\t\t\t\t\"addr\" : {\"City\":\"Chengdu\",\"Company\":\"Tencent\"}\n\t\t\t}\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tjsonMap := j.GetJsonMap(\"users.array\")\n\n\tfor _, json := range jsonMap {\n\t\tfmt.Println(json.Interface())\n\t}\n\n\t// May Output:\n\t// map[City:Chengdu Company:Tencent]\n\t// map[Age:18 Name:John]\n}\n\nfunc ExampleJson_Set() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tj.Set(\"Addr\", \"ChengDu\")\n\tj.Set(\"Friends.0\", \"Tom\")\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"Addr\":\"ChengDu\",\"Age\":18,\"Friends\":[\"Tom\"],\"Name\":\"John\"}\n}\n\nfunc ExampleJson_MustSet() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tj.MustSet(\"Addr\", \"ChengDu\")\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"Addr\":\"ChengDu\",\"Age\":18,\"Name\":\"John\"}\n}\n\nfunc ExampleJson_Remove() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tj.Remove(\"Age\")\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"Name\":\"John\"}\n}\n\nfunc ExampleJson_MustRemove() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tj.MustRemove(\"Age\")\n\tfmt.Println(j.Var().String())\n\n\t// Output:\n\t// {\"Name\":\"John\"}\n}\n\nfunc ExampleJson_Contains() {\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{\n\t\tName: \"John\",\n\t\tAge:  18,\n\t}\n\n\tj := gjson.New(info)\n\tfmt.Println(j.Contains(\"Age\"))\n\tfmt.Println(j.Contains(\"Addr\"))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleJson_Len() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n\t\t\t\"nameArray\" : [\"Join\", \"Tom\"],\n\t\t\t\"infoMap\" : {\n\t\t\t\t\"name\" : \"Join\",\n\t\t\t\t\"age\" : 18,\n\t\t\t\t\"addr\" : \"ChengDu\"\n\t\t\t}\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tfmt.Println(j.Len(\"users.nameArray\"))\n\tfmt.Println(j.Len(\"users.infoMap\"))\n\n\t// Output:\n\t// 2\n\t// 3\n}\n\nfunc ExampleJson_Append() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tj.Append(\"users.array\", \"Lily\")\n\n\tfmt.Println(j.Get(\"users.array\").Array())\n\n\t// Output:\n\t// [John Ming Lily]\n}\n\nfunc ExampleJson_MustAppend() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tj.MustAppend(\"users.array\", \"Lily\")\n\n\tfmt.Println(j.Get(\"users.array\").Array())\n\n\t// Output:\n\t// [John Ming Lily]\n}\n\nfunc ExampleJson_Map() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n            \"info\" : {\n\t\t\t\t\"name\" : \"John\",\n\t\t\t\t\"age\" : 18,\n\t\t\t\t\"addr\" : \"ChengDu\"\n\t\t\t}\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tfmt.Println(j.Get(\"users.info\").Map())\n\n\t// Output:\n\t// map[addr:ChengDu age:18 name:John]\n}\n\nfunc ExampleJson_Array() {\n\tdata := []byte(`\n{\n\t\"users\" : {\n            \"count\" : 1,\n            \"array\" : [\"John\", \"Ming\"]\n        }\n    }\n`)\n\n\tj, _ := gjson.LoadContent(data)\n\n\tfmt.Println(j.Get(\"users.array\"))\n\n\t// Output:\n\t// [\"John\",\"Ming\"]\n}\n\nfunc ExampleJson_Scan() {\n\tdata := []byte(`{\"name\":\"john\",\"age\":\"18\"}`)\n\n\ttype BaseInfo struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\tinfo := BaseInfo{}\n\n\tj, _ := gjson.LoadContent(data)\n\tj.Scan(&info)\n\n\tfmt.Println(info)\n\n\t// May Output:\n\t// {john 18}\n}\n\nfunc ExampleJson_Dump() {\n\tdata := []byte(`{\"name\":\"john\",\"age\":\"18\"}`)\n\n\tj, _ := gjson.LoadContent(data)\n\tj.Dump()\n\n\t// May Output:\n\t// {\n\t//\t\"name\": \"john\",\n\t//\t\"age\":  \"18\",\n\t// }\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_feature_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_ToJson(t *testing.T) {\n\ttype ModifyFieldInfoType struct {\n\t\tId  int64  `json:\"id\"`\n\t\tNew string `json:\"new\"`\n\t}\n\ttype ModifyFieldInfosType struct {\n\t\tDuration ModifyFieldInfoType `json:\"duration\"`\n\t\tOMLevel  ModifyFieldInfoType `json:\"om_level\"`\n\t}\n\n\ttype MediaRequestModifyInfo struct {\n\t\tModify ModifyFieldInfosType `json:\"modifyFieldInfos\"`\n\t\tField  ModifyFieldInfosType `json:\"fieldInfos\"`\n\t\tFeedID string               `json:\"feed_id\"`\n\t\tVid    string               `json:\"id\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tjsonContent := `{\"dataSetId\":2001,\"fieldInfos\":{\"duration\":{\"id\":80079,\"value\":\"59\"},\"om_level\":{\"id\":2409,\"value\":\"4\"}},\"id\":\"g0936lt1u0f\",\"modifyFieldInfos\":{\"om_level\":{\"id\":2409,\"new\":\"4\",\"old\":\"\"}},\"timeStamp\":1584599734}`\n\t\tvar info MediaRequestModifyInfo\n\t\terr := gjson.DecodeTo(jsonContent, &info)\n\t\tt.AssertNil(err)\n\t\tcontent := gjson.New(info).MustToJsonString()\n\t\tt.Assert(gstr.Contains(content, `\"feed_id\":\"\"`), true)\n\t\tt.Assert(gstr.Contains(content, `\"fieldInfos\":{`), true)\n\t\tt.Assert(gstr.Contains(content, `\"id\":80079`), true)\n\t\tt.Assert(gstr.Contains(content, `\"om_level\":{`), true)\n\t\tt.Assert(gstr.Contains(content, `\"id\":2409,`), true)\n\t\tt.Assert(gstr.Contains(content, `\"id\":\"g0936lt1u0f\"`), true)\n\t\tt.Assert(gstr.Contains(content, `\"new\":\"4\"`), true)\n\t})\n}\n\nfunc Test_MapAttributeConvert(t *testing.T) {\n\tvar data = []byte(`\n{\n   \"title\": {\"l1\":\"标签1\",\"l2\":\"标签2\"}\n}\n`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tgtest.AssertNil(err)\n\n\t\ttx := struct {\n\t\t\tTitle map[string]any\n\t\t}{}\n\n\t\terr = j.Var().Scan(&tx)\n\t\tgtest.AssertNil(err)\n\t\tt.Assert(tx.Title, g.Map{\n\t\t\t\"l1\": \"标签1\", \"l2\": \"标签2\",\n\t\t})\n\n\t\tj.Dump()\n\n\t\tvar nilJ *gjson.Json = nil\n\t\tnilJ.Dump()\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tgtest.AssertNil(err)\n\n\t\ttx := struct {\n\t\t\tTitle map[string]string\n\t\t}{}\n\n\t\terr = j.Var().Scan(&tx)\n\t\tgtest.AssertNil(err)\n\t\tt.Assert(tx.Title, g.Map{\n\t\t\t\"l1\": \"标签1\", \"l2\": \"标签2\",\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_feature_load_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Load_JSON1(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]`)\n\t\t_, err := gjson.LoadContentType(\"json\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"test.json\"\n\t\tgfile.PutBytes(path, data)\n\t\tdefer gfile.Remove(path)\n\t\tj, err := gjson.Load(path, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n}\n\nfunc Test_Load_JSON2(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789000000000000, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789000000000000\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n}\n\nfunc Test_Load_XML(t *testing.T) {\n\tdata := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"doc.n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"doc.m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"doc.m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"doc.a\").Slice(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"doc.a.1\").Int(), 2)\n\t})\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadXml(data, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"doc.n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"doc.m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"doc.m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"doc.a\").Slice(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"doc.a.1\").Int(), 2)\n\t})\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n><doc>`)\n\t\t_, err := gjson.LoadContentType(\"xml\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"test.xml\"\n\t\tgfile.PutBytes(path, data)\n\t\tdefer gfile.Remove(path)\n\t\tj, err := gjson.Load(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"doc.n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"doc.m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"doc.m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"doc.a\").Array(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"doc.a.1\").Int(), 2)\n\t})\n\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\txml := []byte(`\n<?xml version=\"1.0\"?>\n\n\t<Output type=\"o\">\n\t<itotalSize>0</itotalSize>\n\t<ipageSize>1</ipageSize>\n\t<ipageIndex>2</ipageIndex>\n\t<itotalRecords>GF框架</itotalRecords>\n\t<nworkOrderDtos/>\n\t<nworkOrderFrontXML/>\n\t</Output>\n`)\n\t\tj, err := gjson.LoadContent(xml)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Output.ipageIndex\"), \"2\")\n\t\tt.Assert(j.Get(\"Output.itotalRecords\"), \"GF框架\")\n\t})\n}\n\nfunc Test_Load_YAML1(t *testing.T) {\n\tdata := []byte(`\na:\n- 1\n- 2\n- 3\nm:\n k: v\n\"n\": 123456789\n    `)\n\t// YAML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\t// YAML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadYaml(data, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\t// YAML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"test.yaml\"\n\t\tgfile.PutBytes(path, data)\n\t\tdefer gfile.Remove(path)\n\t\tj, err := gjson.Load(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n}\n\nfunc Test_Load_YAML2(t *testing.T) {\n\tdata := []byte(\"i : 123456789\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"i\"), \"123456789\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(\"i # 123456789\")\n\t\t_, err := gjson.LoadContentType(\"yaml\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Load_TOML1(t *testing.T) {\n\tdata := []byte(`\na = [\"1\", \"2\", \"3\"]\nn = 123456789\n\n[m]\n  k = \"v\"\n`)\n\t// TOML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\t// TOML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadToml(data, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\t// TOML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"test.toml\"\n\t\tgfile.PutBytes(path, data)\n\t\tdefer gfile.Remove(path)\n\t\tj, err := gjson.Load(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{\"1\", \"2\", \"3\"})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n}\n\nfunc Test_Load_TOML2(t *testing.T) {\n\tdata := []byte(\"i=123456789\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"i\"), \"123456789\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(\"i : 123456789\")\n\t\t_, err := gjson.LoadContentType(\"toml\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Load_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tt.Assert(j.Interface(), nil)\n\t\t_, err := gjson.Decode(nil)\n\t\tt.AssertNE(err, nil)\n\t\t_, err = gjson.DecodeToJson(nil)\n\t\tt.AssertNE(err, nil)\n\t\tj, err = gjson.LoadContent(nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Interface(), nil)\n\n\t\tj, err = gjson.LoadContent([]byte(`{\"name\": \"gf\"}`))\n\t\tt.AssertNil(err)\n\n\t\tj, err = gjson.LoadContent([]byte(`{\"name\": \"gf\"\"\"}`))\n\t\tt.AssertNE(err, nil)\n\n\t\tj = gjson.New(&g.Map{\"name\": \"gf\"})\n\t\tt.Assert(j.Get(\"name\").String(), \"gf\")\n\n\t})\n}\n\nfunc Test_Load_Ini(t *testing.T) {\n\tvar data = []byte(`\n\n;注释\n\n[addr]\nip = 127.0.0.1\nport=9001\nenable=true\n\n\t[DBINFO]\n\ttype=mysql\n\tuser=root\n\tpassword=password\n\n`)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(j.Get(\"addr.ip\").String(), \"127.0.0.1\")\n\t\tt.Assert(j.Get(\"addr.port\").String(), \"9001\")\n\t\tt.Assert(j.Get(\"addr.enable\").String(), \"true\")\n\t\tt.Assert(j.Get(\"DBINFO.type\").String(), \"mysql\")\n\t\tt.Assert(j.Get(\"DBINFO.user\").String(), \"root\")\n\t\tt.Assert(j.Get(\"DBINFO.password\").String(), \"password\")\n\n\t\t_, err = j.ToIni()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadIni(data, true)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(j.Get(\"addr.ip\").String(), \"127.0.0.1\")\n\t\tt.Assert(j.Get(\"addr.port\").String(), \"9001\")\n\t\tt.Assert(j.Get(\"addr.enable\").String(), \"true\")\n\t\tt.Assert(j.Get(\"DBINFO.type\").String(), \"mysql\")\n\t\tt.Assert(j.Get(\"DBINFO.user\").String(), \"root\")\n\t\tt.Assert(j.Get(\"DBINFO.password\").String(), \"password\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(\"i : 123456789\")\n\t\t_, err := gjson.LoadContentType(\"ini\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Load_YamlWithV3(t *testing.T) {\n\tcontent := []byte(`\n# CLI tool, only in development environment.\n# https://goframe.org/pages/viewpage.action?pageId=3673173\ngfcli:\n  gen:\n    dao:\n    - path            : \"../../pkg/oss/oss/internal\"\n      group           : \"oss\"\n      stdTime         : true\n      descriptionTag  : true\n      noJsonTag       : true\n      noModelComment  : true\n      overwriteDao    : true\n      modelFileForDao : \"model_dao.go\"\n      tablesEx        : |\n        bpmn_info,\n        dlocker,\n        dlocker_detail,\n        message_table,\n        monitor_data,\n        resource_param_info,\n        version_info,\n        version_topology_info,\n        work_flow,\n        work_flow_step_info,\n        work_flow_undo_step_info\n\n    - path            : \"../../pkg/oss/workflow/internal\"\n      group           : \"workflow\"\n      stdTime         : true\n      descriptionTag  : true\n      noJsonTag       : true\n      noModelComment  : true\n      overwriteDao    : true\n      modelFileForDao : \"model_dao.go\"\n`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gjson.LoadContent(content)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Load_Properties(t *testing.T) {\n\tvar data = []byte(`\n\n#注释\n\n\naddr.ip = 127.0.0.1\naddr.port=9001\naddr.enable=true\nDBINFO.type=mysql\nDBINFO.user=root\nDBINFO.password=password\n\n`)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(j.Get(\"addr.ip\").String(), \"127.0.0.1\")\n\t\tt.Assert(j.Get(\"addr.port\").String(), \"9001\")\n\t\tt.Assert(j.Get(\"addr.enable\").String(), \"true\")\n\t\tt.Assert(j.Get(\"DBINFO.type\").String(), \"mysql\")\n\t\tt.Assert(j.Get(\"DBINFO.user\").String(), \"root\")\n\t\tt.Assert(j.Get(\"DBINFO.password\").String(), \"password\")\n\n\t\t_, err = j.ToProperties()\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadProperties(data, true)\n\t\tif err != nil {\n\t\t\tgtest.Fatal(err)\n\t\t}\n\n\t\tt.Assert(j.Get(\"addr.ip\").String(), \"127.0.0.1\")\n\t\tt.Assert(j.Get(\"addr.port\").String(), \"9001\")\n\t\tt.Assert(j.Get(\"addr.enable\").String(), \"true\")\n\t\tt.Assert(j.Get(\"DBINFO.type\").String(), \"mysql\")\n\t\tt.Assert(j.Get(\"DBINFO.user\").String(), \"root\")\n\t\tt.Assert(j.Get(\"DBINFO.password\").String(), \"password\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrData := []byte(\"i\\\\u1 : 123456789\")\n\t\t_, err := gjson.LoadContentType(\"properties\", errData, true)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Load_YAML_For_I18n(t *testing.T) {\n\tvar data = []byte(gtest.DataContent(\"yaml\", \"i18n-issue.yaml\"))\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.LoadContent(data)\n\t\tt.AssertNil(err)\n\t\tj.SetViolenceCheck(true)\n\t\tt.Assert(j.Get(\"resourceUsage.workflow\").String(), \"workflow\")\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_feature_new_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_NewWithTag(t *testing.T) {\n\ttype User struct {\n\t\tAge  int    `xml:\"age-xml\"  json:\"age-json\"`\n\t\tName string `xml:\"name-xml\" json:\"name-json\"`\n\t\tAddr string `xml:\"addr-xml\" json:\"addr-json\"`\n\t}\n\tdata := User{\n\t\tAge:  18,\n\t\tName: \"john\",\n\t\tAddr: \"chengdu\",\n\t}\n\t// JSON\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(data)\n\t\tt.AssertNE(j, nil)\n\t\tt.Assert(j.Get(\"age-xml\"), nil)\n\t\tt.Assert(j.Get(\"age-json\"), data.Age)\n\t\tt.Assert(j.Get(\"name-xml\"), nil)\n\t\tt.Assert(j.Get(\"name-json\"), data.Name)\n\t\tt.Assert(j.Get(\"addr-xml\"), nil)\n\t\tt.Assert(j.Get(\"addr-json\"), data.Addr)\n\t})\n\t// XML\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.NewWithTag(data, \"xml\")\n\t\tt.AssertNE(j, nil)\n\t\tt.Assert(j.Get(\"age-xml\"), data.Age)\n\t\tt.Assert(j.Get(\"age-json\"), nil)\n\t\tt.Assert(j.Get(\"name-xml\"), data.Name)\n\t\tt.Assert(j.Get(\"name-json\"), nil)\n\t\tt.Assert(j.Get(\"addr-xml\"), data.Addr)\n\t\tt.Assert(j.Get(\"addr-json\"), nil)\n\t})\n}\n\nfunc Test_New_CustomStruct(t *testing.T) {\n\ttype Base struct {\n\t\tId int\n\t}\n\ttype User struct {\n\t\tBase\n\t\tName string\n\t}\n\tuser := new(User)\n\tuser.Id = 1\n\tuser.Name = \"john\"\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(user)\n\t\tt.AssertNE(j, nil)\n\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s == `{\"Id\":1,\"Name\":\"john\"}` || s == `{\"Name\":\"john\",\"Id\":1}`, true)\n\t})\n}\n\nfunc Test_New_HierarchicalStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Me struct {\n\t\t\tName     string `json:\"name\"`\n\t\t\tScore    int    `json:\"score\"`\n\t\t\tChildren []Me   `json:\"children\"`\n\t\t}\n\t\tme := Me{\n\t\t\tName:  \"john\",\n\t\t\tScore: 100,\n\t\t\tChildren: []Me{\n\t\t\t\t{\n\t\t\t\t\tName:  \"Bean\",\n\t\t\t\t\tScore: 99,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"Sam\",\n\t\t\t\t\tScore: 98,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tj := gjson.New(me)\n\t\tt.Assert(j.Remove(\"children.0.score\"), nil)\n\t\tt.Assert(j.Remove(\"children.1.score\"), nil)\n\t\tt.Assert(j.MustToJsonString(), `{\"children\":[{\"children\":null,\"name\":\"Bean\"},{\"children\":null,\"name\":\"Sam\"}],\"name\":\"john\",\"score\":100}`)\n\t})\n}\n\nfunc Test_NewWithOptions(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"[9223372036854775807, 9223372036854775806]\")\n\t\tarray := gjson.New(data).Var().Array()\n\t\tt.Assert(array, []uint64{9223372036854776000, 9223372036854776000})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"[9223372036854775807, 9223372036854775806]\")\n\t\tarray := gjson.NewWithOptions(data, gjson.Options{StrNumber: true}).Var().Array()\n\t\tt.Assert(array, []uint64{9223372036854775807, 9223372036854775806})\n\t})\n}\n\nfunc Test_LoadContentType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"value = 79937385836643329\")\n\t\tj, err := gjson.LoadContentType(\"toml\", data)\n\t\tt.AssertNil(err)\n\t\tvalue := j.Get(\"value\").Int64()\n\t\tt.Assert(value, 79937385836643329)\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_feature_set_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Set1(t *testing.T) {\n\te := []byte(`{\"k1\":{\"k11\":[1,2,3]},\"k2\":\"v2\"}`)\n\tp := gjson.New(map[string]string{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t})\n\tp.Set(\"k1.k11\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, []byte(`{\"k1\":{\"k11\":[1,2,3]},\"k2\":\"v2\"}`)) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\te := `[[null,1]]`\n\t\tp := gjson.New([]string{\"a\"})\n\t\tp.Set(\"0.1\", 1)\n\t\ts := p.MustToJsonString()\n\t\tt.Assert(s, e)\n\t})\n}\n\nfunc Test_Set3(t *testing.T) {\n\te := []byte(`{\"kv\":{\"k1\":\"v1\"}}`)\n\tp := gjson.New([]string{\"a\"})\n\tp.Set(\"kv\", map[string]string{\n\t\t\"k1\": \"v1\",\n\t})\n\tif c, err := p.ToJson(); err == nil {\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set4(t *testing.T) {\n\te := []byte(`[\"a\",[{\"k1\":\"v1\"}]]`)\n\tp := gjson.New([]string{\"a\"})\n\tp.Set(\"1.0\", map[string]string{\n\t\t\"k1\": \"v1\",\n\t})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set5(t *testing.T) {\n\te := []byte(`[[[[[[[[[[[[[[[[[[[[[1,2,3]]]]]]]]]]]]]]]]]]]]]`)\n\tp := gjson.New([]string{\"a\"})\n\tp.Set(\"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set6(t *testing.T) {\n\te := []byte(`[\"a\",[1,2,3]]`)\n\tp := gjson.New([]string{\"a\"})\n\tp.Set(\"1\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set7(t *testing.T) {\n\te := []byte(`{\"0\":[null,[1,2,3]],\"k1\":\"v1\",\"k2\":\"v2\"}`)\n\tp := gjson.New(map[string]string{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t})\n\tp.Set(\"0.1\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set8(t *testing.T) {\n\te := []byte(`{\"0\":[[[[[[null,[1,2,3]]]]]]],\"k1\":\"v1\",\"k2\":\"v2\"}`)\n\tp := gjson.New(map[string]string{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t})\n\tp.Set(\"0.0.0.0.0.0.1\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set9(t *testing.T) {\n\te := []byte(`{\"k1\":[null,[1,2,3]],\"k2\":\"v2\"}`)\n\tp := gjson.New(map[string]string{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t})\n\tp.Set(\"k1.1\", []int{1, 2, 3})\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set10(t *testing.T) {\n\te := []byte(`{\"a\":{\"b\":{\"c\":1}}}`)\n\tp := gjson.New(nil)\n\tp.Set(\"a.b.c\", 1)\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set11(t *testing.T) {\n\te := []byte(`{\"a\":{\"b\":{}}}`)\n\tp, _ := gjson.LoadContent([]byte(`{\"a\":{\"b\":{\"c\":1}}}`))\n\tp.Remove(\"a.b.c\")\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set12(t *testing.T) {\n\te := []byte(`[0,1]`)\n\tp := gjson.New(nil)\n\tp.Set(\"0\", 0)\n\tp.Set(\"1\", 1)\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set13(t *testing.T) {\n\te := []byte(`{\"array\":[0,1]}`)\n\tp := gjson.New(nil)\n\tp.Set(\"array.0\", 0)\n\tp.Set(\"array.1\", 1)\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set14(t *testing.T) {\n\te := []byte(`{\"f\":{\"a\":1}}`)\n\tp := gjson.New(nil)\n\tp.Set(\"f\", \"m\")\n\tp.Set(\"f.a\", 1)\n\tif c, err := p.ToJson(); err == nil {\n\n\t\tif !bytes.Equal(c, e) {\n\t\t\tt.Error(\"expect:\", string(e))\n\t\t}\n\t} else {\n\t\tt.Error(err)\n\t}\n}\n\nfunc Test_Set15(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"root.0.k1\", \"v1\"), nil)\n\t\tt.Assert(j.Set(\"root.1.k2\", \"v2\"), nil)\n\t\tt.Assert(j.Set(\"k\", \"v\"), nil)\n\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tgstr.Contains(s, `\"root\":[{\"k1\":\"v1\"},{\"k2\":\"v2\"}`) ||\n\t\t\t\tgstr.Contains(s, `\"root\":[{\"k2\":\"v2\"},{\"k1\":\"v1\"}`),\n\t\t\ttrue,\n\t\t)\n\t\tt.Assert(\n\t\t\tgstr.Contains(s, `{\"k\":\"v\"`) ||\n\t\t\t\tgstr.Contains(s, `\"k\":\"v\"}`),\n\t\t\ttrue,\n\t\t)\n\t})\n}\n\nfunc Test_Set16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"processors.0.set.0value\", \"1\"), nil)\n\t\tt.Assert(j.Set(\"processors.0.set.0field\", \"2\"), nil)\n\t\tt.Assert(j.Set(\"description\", \"3\"), nil)\n\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tgstr.Contains(s, `\"processors\":[{\"set\":{\"0field\":\"2\",\"0value\":\"1\"}}]`) ||\n\t\t\t\tgstr.Contains(s, `\"processors\":[{\"set\":{\"0value\":\"1\",\"0field\":\"2\"}}]`),\n\t\t\ttrue,\n\t\t)\n\t\tt.Assert(\n\t\t\tgstr.Contains(s, `{\"description\":\"3\"`) || gstr.Contains(s, `\"description\":\"3\"}`),\n\t\t\ttrue,\n\t\t)\n\t})\n}\n\nfunc Test_Set17(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"0.k1\", \"v1\"), nil)\n\t\tt.Assert(j.Set(\"1.k2\", \"v2\"), nil)\n\t\t// overwrite the previous slice.\n\t\tt.Assert(j.Set(\"k\", \"v\"), nil)\n\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, `{\"k\":\"v\"}`)\n\t})\n}\n\nfunc Test_Set18(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"0.1.k1\", \"v1\"), nil)\n\t\tt.Assert(j.Set(\"0.2.k2\", \"v2\"), nil)\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, `[[null,{\"k1\":\"v1\"},{\"k2\":\"v2\"}]]`)\n\t})\n}\n\nfunc Test_Set19(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"0.1.1.k1\", \"v1\"), nil)\n\t\tt.Assert(j.Set(\"0.2.1.k2\", \"v2\"), nil)\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, `[[null,[null,{\"k1\":\"v1\"}],[null,{\"k2\":\"v2\"}]]]`)\n\t})\n}\n\nfunc Test_Set20(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\n\t\tt.Assert(j.Set(\"k1\", \"v1\"), nil)\n\t\tt.Assert(j.Set(\"k2\", g.Slice{1, 2, 3}), nil)\n\t\tt.Assert(j.Set(\"k2.1\", 20), nil)\n\t\tt.Assert(j.Set(\"k2.2\", g.Map{\"k3\": \"v3\"}), nil)\n\t\ts, err := j.ToJsonString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.InArray(\n\t\t\tg.SliceStr{\n\t\t\t\t`{\"k1\":\"v1\",\"k2\":[1,20,{\"k3\":\"v3\"}]}`,\n\t\t\t\t`{\"k2\":[1,20,{\"k3\":\"v3\"}],\"k1\":\"v1\"}`,\n\t\t\t},\n\t\t\ts,\n\t\t), true)\n\t})\n}\n\nfunc Test_Set_GArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tarr := garray.New().Append(\"test\")\n\t\tt.AssertNil(j.Set(\"arr\", arr))\n\t\tt.Assert(j.Get(\"arr\").Array(), g.Slice{\"test\"})\n\t})\n}\n\nfunc Test_Set_WithEmptyStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(&struct{}{})\n\t\tt.AssertNil(j.Set(\"aa\", \"123\"))\n\t\tt.Assert(j.MustToJsonString(), `{\"aa\":\"123\"}`)\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_feature_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GetScan(t *testing.T) {\n\ttype User struct {\n\t\tName  string\n\t\tScore float64\n\t}\n\tj := gjson.New(`[{\"name\":\"john\", \"score\":\"100\"},{\"name\":\"smith\", \"score\":\"60\"}]`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := j.Get(\"1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, &User{\n\t\t\tName:  \"smith\",\n\t\t\tScore: 60,\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := j.Get(\".\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users, []User{\n\t\t\t{\n\t\t\t\tName:  \"john\",\n\t\t\t\tScore: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"smith\",\n\t\t\t\tScore: 60,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc Test_GetScanDeep(t *testing.T) {\n\ttype User struct {\n\t\tName  string\n\t\tScore float64\n\t}\n\tj := gjson.New(`[{\"name\":\"john\", \"score\":\"100\"},{\"name\":\"smith\", \"score\":\"60\"}]`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar user *User\n\t\terr := j.Get(\"1\").Scan(&user)\n\t\tt.AssertNil(err)\n\t\tt.Assert(user, &User{\n\t\t\tName:  \"smith\",\n\t\t\tScore: 60,\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := j.Get(\".\").Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users, []User{\n\t\t\t{\n\t\t\t\tName:  \"john\",\n\t\t\t\tScore: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"smith\",\n\t\t\t\tScore: 60,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc Test_Scan1(t *testing.T) {\n\ttype User struct {\n\t\tName  string\n\t\tScore float64\n\t}\n\tj := gjson.New(`[{\"name\":\"john\", \"score\":\"100\"},{\"name\":\"smith\", \"score\":\"60\"}]`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := j.Var().Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users, []User{\n\t\t\t{\n\t\t\t\tName:  \"john\",\n\t\t\t\tScore: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"smith\",\n\t\t\t\tScore: 60,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc Test_Scan2(t *testing.T) {\n\ttype User struct {\n\t\tName  string\n\t\tScore float64\n\t}\n\tj := gjson.New(`[{\"name\":\"john\", \"score\":\"100\"},{\"name\":\"smith\", \"score\":\"60\"}]`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar users []User\n\t\terr := j.Var().Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.Assert(users, []User{\n\t\t\t{\n\t\t\t\tName:  \"john\",\n\t\t\t\tScore: 100,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"smith\",\n\t\t\t\tScore: 60,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc Test_Struct1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype BaseInfoItem struct {\n\t\t\tIdCardNumber        string `db:\"id_card_number\" json:\"idCardNumber\" field:\"id_card_number\"`\n\t\t\tIsHouseholder       bool   `db:\"is_householder\" json:\"isHouseholder\" field:\"is_householder\"`\n\t\t\tHouseholderRelation string `db:\"householder_relation\" json:\"householderRelation\" field:\"householder_relation\"`\n\t\t\tUserName            string `db:\"user_name\" json:\"userName\" field:\"user_name\"`\n\t\t\tUserSex             string `db:\"user_sex\" json:\"userSex\" field:\"user_sex\"`\n\t\t\tUserAge             int    `db:\"user_age\" json:\"userAge\" field:\"user_age\"`\n\t\t\tUserNation          string `db:\"user_nation\" json:\"userNation\" field:\"user_nation\"`\n\t\t}\n\n\t\ttype UserCollectionAddReq struct {\n\t\t\tBaseInfo []BaseInfoItem `db:\"_\" json:\"baseInfo\" field:\"_\"`\n\t\t}\n\t\tjsonContent := []byte(`{\n\t\"baseInfo\": [{\n\t\t\"idCardNumber\": \"520101199412141111\",\n\t\t\"isHouseholder\": true,\n\t\t\"householderRelation\": \"户主\",\n\t\t\"userName\": \"李四\",\n\t\t\"userSex\": \"男\",\n\t\t\"userAge\": 32,\n\t\t\"userNation\": \"苗族\",\n\t\t\"userPhone\": \"13084183323\",\n\t\t\"liveAddress\": {},\n\t\t\"occupationInfo\": [{\n\t\t\t\"occupationType\": \"经商\",\n\t\t\t\"occupationBusinessInfo\": [{\n\t\t\t\t\"occupationClass\": \"制造业\",\n\t\t\t\t\"businessLicenseNumber\": \"32020000012300\",\n\t\t\t\t\"businessName\": \"土灶柴火鸡\",\n\t\t\t\t\"spouseName\": \"\",\n\t\t\t\t\"spouseIdCardNumber\": \"\",\n\t\t\t\t\"businessLicensePhotoId\": 125,\n\t\t\t\t\"businessPlace\": \"租赁房产\",\n\t\t\t\t\"hasGoodsInsurance\": true,\n\t\t\t\t\"businessScopeStr\": \"柴火鸡;烧烤\",\n\t\t\t\t\"businessAddress\": {},\n\t\t\t\t\"businessPerformAbility\": {\n\t\t\t\t\t\"businessType\": \"服务业\",\n\t\t\t\t\t\"businessLife\": 5,\n\t\t\t\t\t\"salesRevenue\": 8000,\n\t\t\t\t\t\"familyEquity\": 6000\n\t\t\t\t}\n\t\t\t}],\n\t\t\t\"occupationWorkInfo\": {\n\t\t\t\t\"occupationClass\": \"\",\n\t\t\t\t\"companyName\": \"\",\n\t\t\t\t\"companyType\": \"\",\n\t\t\t\t\"workYearNum\": 0,\n\t\t\t\t\"spouseName\": \"\",\n\t\t\t\t\"spouseIdCardNumber\": \"\",\n\t\t\t\t\"spousePhone\": \"\",\n\t\t\t\t\"spouseEducation\": \"\",\n\t\t\t\t\"spouseCompanyName\": \"\",\n\t\t\t\t\"workLevel\": \"\",\n\t\t\t\t\"workAddress\": {},\n\t\t\t\t\"workPerformAbility\": {\n\t\t\t\t\t\"familyAnnualIncome\": 0,\n\t\t\t\t\t\"familyEquity\": 0,\n\t\t\t\t\t\"workCooperationState\": \"\",\n\t\t\t\t\t\"workMoneyCooperationState\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"occupationAgricultureInfo\": []\n\t\t}],\n\t\t\"assetsInfo\": [],\n\t\t\"expenditureInfo\": [],\n\t\t\"incomeInfo\": [],\n\t\t\"liabilityInfo\": []\n\t}]\n}\n`)\n\t\tdata := new(UserCollectionAddReq)\n\t\tj, err := gjson.LoadJson(jsonContent, true)\n\t\tt.AssertNil(err)\n\t\terr = j.Scan(data)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Item struct {\n\t\t\tTitle string `json:\"title\"`\n\t\t\tKey   string `json:\"key\"`\n\t\t}\n\n\t\ttype M struct {\n\t\t\tId    string         `json:\"id\"`\n\t\t\tMe    map[string]any `json:\"me\"`\n\t\t\tTxt   string         `json:\"txt\"`\n\t\t\tItems []*Item        `json:\"items\"`\n\t\t}\n\n\t\ttxt := []byte(`\n{\n\t\"id\":\"88888\",\n\t\"me\":{\"name\":\"mikey\",\"day\":\"20009\"},\n\t\"txt\":\"hello\",\n\t\"items\":null\n}\n`)\n\n\t\tj, err := gjson.LoadContent(txt)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"me.name\").String(), \"mikey\")\n\t\tt.Assert(j.Get(\"items\").String(), \"\")\n\t\tt.Assert(j.Get(\"items\").Bool(), false)\n\t\tt.Assert(j.Get(\"items\").Array(), nil)\n\t\tm := new(M)\n\t\terr = j.Scan(m)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(m.Me, nil)\n\t\tt.Assert(m.Me[\"day\"], \"20009\")\n\t\tt.Assert(m.Items, nil)\n\t})\n}\n\nfunc Test_Struct_Complicated(t *testing.T) {\n\ttype CertInfo struct {\n\t\tUserRealName        string `json:\"userRealname,omitempty\"`\n\t\tIdentType           string `json:\"identType,omitempty\"`\n\t\tIdentNo             string `json:\"identNo,omitempty\"`\n\t\tCompanyName         string `json:\"companyName,omitempty\"`\n\t\tWebsite             string `json:\"website,omitempty\"`\n\t\tRegisterNo          string `json:\"registerNo,omitempty\"`\n\t\tAreaCode            string `json:\"areaCode,omitempty\"`\n\t\tAddress             string `json:\"address,omitempty\"`\n\t\tCommunityCreditCode string `json:\"communityCreditCode,omitempty\"`\n\t\tPhoneNumber         string `json:\"phoneNumber,omitempty\"`\n\t\tAreaName            string `json:\"areaName,omitempty\"`\n\t\tPhoneAreaCode       string `json:\"phoneAreaCode,omitempty\"`\n\t\tOperateRange        string `json:\"operateRange,omitempty\"`\n\t\tEmail               string `json:\"email,omitempty\"`\n\t\tLegalPersonName     string `json:\"legalPersonName,omitempty\"`\n\t\tOrgCode             string `json:\"orgCode,omitempty\"`\n\t\tBusinessLicense     string `json:\"businessLicense,omitempty\"`\n\t\tFilePath1           string `json:\"filePath1,omitempty\"`\n\t\tMobileNo            string `json:\"mobileNo,omitempty\"`\n\t\tCardName            string `json:\"cardName,omitempty\"`\n\t\tBankMobileNo        string `json:\"bankMobileNo,omitempty\"`\n\t\tBankCode            string `json:\"bankCode,omitempty\"`\n\t\tBankCard            string `json:\"bankCard,omitempty\"`\n\t}\n\n\ttype CertList struct {\n\t\tStatusCode uint     `json:\"statusCode,string\"`\n\t\tSrcType    uint     `json:\"srcType,string\"`\n\t\tCertID     string   `json:\"certId\"`\n\t\tCardType   string   `json:\"cardType,omitempty\"`\n\t\tCertInfo   CertInfo `json:\"certInfo\"`\n\t}\n\n\ttype Response struct {\n\t\tUserLevel uint       `json:\"userLevel,string,omitempty\"`\n\t\tCertList  []CertList `json:\"certList\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tjsonContent := []byte(`\n{\n\"certList\":[\n{\"certId\":\"2023313\",\"certInfo\":\"{\\\"address\\\":\\\"xxxxxxx\\\",\\\"phoneNumber\\\":\\\"15084890\\\",\\\"companyName\\\":\\\"dddd\\\",\\\"communityCreditCode\\\":\\\"91110111MBE1G2B\\\",\\\"operateRange\\\":\\\"fff\\\",\\\"registerNo\\\":\\\"91110111MA00G2B\\\",\\\"legalPersonName\\\":\\\"rrr\\\"}\",\"srcType\":\"1\",\"statusCode\":\"2\"},\n{\"certId\":\"2023314\",\"certInfo\":\"{\\\"identNo\\\":\\\"342224196507051\\\",\\\"userRealname\\\":\\\"xxxx\\\",\\\"identType\\\":\\\"01\\\"}\",\"srcType\":\"8\",\"statusCode\":\"0\"},\n{\"certId\":\"2023322\",\"certInfo\":\"{\\\"businessLicense\\\":\\\"91110111MA00BE1G\\\",\\\"companyName\\\":\\\"sssss\\\",\\\"communityCreditCode\\\":\\\"91110111MA00BE1\\\"}\",\"srcType\":\"2\",\"statusCode\":\"0\"}\n]\n}\n`)\n\t\tj, err := gjson.LoadContent(jsonContent)\n\t\tt.AssertNil(err)\n\t\tvar response = new(Response)\n\t\terr = j.Scan(response)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(response.CertList), 3)\n\t\tt.Assert(response.CertList[0].CertID, 2023313)\n\t\tt.Assert(response.CertList[1].CertID, 2023314)\n\t\tt.Assert(response.CertList[2].CertID, 2023322)\n\t\tt.Assert(response.CertList[0].CertInfo.PhoneNumber, \"15084890\")\n\t\tt.Assert(response.CertList[1].CertInfo.IdentNo, \"342224196507051\")\n\t\tt.Assert(response.CertList[2].CertInfo.BusinessLicense, \"91110111MA00BE1G\")\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_implements_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestJson_UnmarshalJSON(t *testing.T) {\n\t// Json Array\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdata = []byte(`[\"a\", \"b\", \"c\"]`)\n\t\t\tj    = gjson.New(nil)\n\t\t\terr  = json.UnmarshalUseNumber(data, j)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\".\").String(), `[\"a\",\"b\",\"c\"]`)\n\t\tt.Assert(j.Get(\"2\").String(), `c`)\n\t})\n\t// Json Array Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdata = []byte(`[{\"a\":1}, {\"b\":2}, {\"c\":3}]`)\n\t\t\tj    = gjson.New(nil)\n\t\t\terr  = json.UnmarshalUseNumber(data, j)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\".\").String(), `[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tt.Assert(j.Get(\"2.c\").String(), `3`)\n\t})\n\t// Json Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdata = []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\t\t\tj    = gjson.New(nil)\n\t\t\terr  = json.UnmarshalUseNumber(data, j)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Array(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n\n}\n\nfunc TestJson_UnmarshalValue(t *testing.T) {\n\ttype V struct {\n\t\tName string\n\t\tJson *gjson.Json\n\t}\n\t// Json Map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"json\": []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`),\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Json.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(v.Json.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(v.Json.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(v.Json.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(v.Json.Get(\"a.1\").Int(), 2)\n\t})\n\t// Json Array.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"json\": `[\"a\", \"b\", \"c\"]`,\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Json.Get(\".\").String(), `[\"a\",\"b\",\"c\"]`)\n\t\tt.Assert(v.Json.Get(\"2\").String(), `c`)\n\t})\n\t// Json Array Map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"json\": `[{\"a\":1},{\"b\":2},{\"c\":3}]`,\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Json.Get(\".\").String(), `[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tt.Assert(v.Json.Get(\"2.c\").String(), `3`)\n\t})\n\t// Map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v *V\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"name\": \"john\",\n\t\t\t\"json\": g.Map{\n\t\t\t\t\"n\": 123456789,\n\t\t\t\t\"m\": g.Map{\"k\": \"v\"},\n\t\t\t\t\"a\": g.Slice{1, 2, 3},\n\t\t\t},\n\t\t}, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v.Name, \"john\")\n\t\tt.Assert(v.Json.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(v.Json.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(v.Json.Get(\"m.k\").String(), \"v\")\n\t\tt.Assert(v.Json.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(v.Json.Get(\"a.1\").Int(), 2)\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_checkDataType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\nbb           = \"\"\"\n                   dig := dig;                         END;\"\"\"\n`)\n\t\tdataType, err := checkDataType(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dataType, \"toml\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\n# 模板引擎目录\nviewpath = \"/home/www/templates/\"\n# MySQL数据库配置\n[redis]\ndd = 11\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`)\n\t\tdataType, err := checkDataType(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dataType, \"toml\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\n\"gf.gvalid.rule.required\"             = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-if\"          = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-unless\"      = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-with\"        = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-with-all\"    = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-without\"     = \"The :attribute field is required\"\n\"gf.gvalid.rule.required-without-all\" = \"The :attribute field is required\"\n\"gf.gvalid.rule.date\"                 = \"The :attribute value is not a valid date\"\n\"gf.gvalid.rule.date-format\"          = \"The :attribute value does not match the format :format\"\n\"gf.gvalid.rule.email\"                = \"The :attribute value must be a valid email address\"\n\"gf.gvalid.rule.phone\"                = \"The :attribute value must be a valid phone number\"\n\"gf.gvalid.rule.telephone\"            = \"The :attribute value must be a valid telephone number\"\n\"gf.gvalid.rule.passport\"             = \"The :attribute value is not a valid passport format\"\n\"gf.gvalid.rule.password\"             = \"The :attribute value is not a valid passport format\"\n\"gf.gvalid.rule.password2\"            = \"The :attribute value is not a valid passport format\"\n\"gf.gvalid.rule.password3\"            = \"The :attribute value is not a valid passport format\"\n\"gf.gvalid.rule.postcode\"             = \"The :attribute value is not a valid passport format\"\n\"gf.gvalid.rule.resident-id\"          = \"The :attribute value is not a valid resident id number\"\n\"gf.gvalid.rule.bank-card\"            = \"The :attribute value must be a valid bank card number\"\n\"gf.gvalid.rule.qq\"                   = \"The :attribute value must be a valid QQ number\"\n\"gf.gvalid.rule.ip\"                   = \"The :attribute value must be a valid IP address\"\n\"gf.gvalid.rule.ipv4\"                 = \"The :attribute value must be a valid IPv4 address\"\n\"gf.gvalid.rule.ipv6\"                 = \"The :attribute value must be a valid IPv6 address\"\n\"gf.gvalid.rule.mac\"                  = \"The :attribute value must be a valid MAC address\"\n\"gf.gvalid.rule.url\"                  = \"The :attribute value must be a valid URL address\"\n\"gf.gvalid.rule.domain\"               = \"The :attribute value must be a valid domain format\"\n\"gf.gvalid.rule.length\"               = \"The :attribute value length must be between :min and :max\"\n\"gf.gvalid.rule.min-length\"           = \"The :attribute value length must be equal or greater than :min\"\n\"gf.gvalid.rule.max-length\"           = \"The :attribute value length must be equal or lesser than :max\"\n\"gf.gvalid.rule.between\"              = \"The :attribute value must be between :min and :max\"\n\"gf.gvalid.rule.min\"                  = \"The :attribute value must be equal or greater than :min\"\n\"gf.gvalid.rule.max\"                  = \"The :attribute value must be equal or lesser than :max\"\n\"gf.gvalid.rule.json\"                 = \"The :attribute value must be a valid JSON string\"\n\"gf.gvalid.rule.xml\"                  = \"The :attribute value must be a valid XML string\"\n\"gf.gvalid.rule.array\"                = \"The :attribute value must be an array\"\n\"gf.gvalid.rule.integer\"              = \"The :attribute value must be an integer\"\n\"gf.gvalid.rule.float\"                = \"The :attribute value must be a float\"\n\"gf.gvalid.rule.boolean\"              = \"The :attribute value field must be true or false\"\n\"gf.gvalid.rule.same\"                 = \"The :attribute value must be the same as field :field\"\n\"gf.gvalid.rule.different\"            = \"The :attribute value must be different from field :field\"\n\"gf.gvalid.rule.in\"                   = \"The :attribute value is not in acceptable range\"\n\"gf.gvalid.rule.not-in\"               = \"The :attribute value is not in acceptable range\"\n\"gf.gvalid.rule.regex\"                = \"The :attribute value is invalid\"\n`)\n\t\t// fmt.Println(gregex.IsMatch(`^[\\s\\t\\n\\r]*[\\w\\-]+\\s*:\\s*\".+\"`, data))\n\t\t// fmt.Println(gregex.IsMatch(`^[\\s\\t\\n\\r]*[\\w\\-]+\\s*:\\s*\\w+`, data))\n\t\t// fmt.Println(gregex.IsMatch(`[\\s\\t\\n\\r]+[\\w\\-]+\\s*:\\s*\".+\"`, data))\n\t\t// fmt.Println(gregex.IsMatch(`[\\n\\r]+[\\w\\-\\s\\t]+\\s*:\\s*\\w+`, data))\n\t\t// fmt.Println(gregex.MatchString(`[\\n\\r]+[\\w\\-\\s\\t]+\\s*:\\s*\\w+`, string(data)))\n\t\tdataType, err := checkDataType(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dataType, \"toml\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\n[default]\ndb.engine         = mysql\ndb.max.idle.conns = 5\ndb.max.open.conns = 100\nallow_ips         =\napi.key           =\napi.secret        =\nenable_tls        = false\nconcurrency.queue = 500\nauth_secret       = 63358e6f3daf0e5775ec3fb4d2516b01d41530bf30960aa76972f6ce7e08552f\nca_file           =\ncert_file         =\nkey_file          =\nhost_port         = 8088\nlog_path          = /Users/zhaosuji/go/src/git.medlinker.com/foundations/gocron/log\n#k8s-api地址(只提供内网访问)\nk8s-inner-api = http://127.0.0.1:8081/kube/add\nconf_dir = ./config\napp_conf = ./config/app.ini\n`)\n\t\tdataType, err := checkDataType(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dataType, \"ini\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\n# API Server\n[server]\n    address = \":8199\"\n\n# Jenkins\n[jenkins]\n    url          = \"https://jenkins-swimlane.com\"\n    nodeJsStaticBuildCmdTpl = \"\"\"\nnpm i --registry=https://registry.npm.taobao.org\nwget http://consul.infra:8500/v1/kv/app_{{.SwimlaneName}}/{{.RepoName}}/.env.qa?raw=true -O ./env.qa\nnpm run build:qa\n\"\"\"\n`)\n\t\tdataType, err := checkDataType(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dataType, \"toml\")\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/gjson_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gjson_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_New(t *testing.T) {\n\t// New with json map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\t\tj := gjson.New(data)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"a\").Array(), g.Slice{1, 2, 3})\n\t})\n\t// New with json array map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(`[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tt.Assert(j.Get(\".\").String(), `[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tt.Assert(j.Get(\"2.c\").String(), `3`)\n\t})\n\t// New with gvar.\n\t// https://github.com/gogf/gf/issues/1571\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gvar.New(`[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tj := gjson.New(v)\n\t\tt.Assert(j.Get(\".\").String(), `[{\"a\":1},{\"b\":2},{\"c\":3}]`)\n\t\tt.Assert(j.Get(\"2.c\").String(), `3`)\n\t})\n\t// New with gmap.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gmap.NewAnyAnyMapFrom(g.MapAnyAny{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tj := gjson.New(m)\n\t\tt.Assert(j.Get(\"k1\"), \"v1\")\n\t\tt.Assert(j.Get(\"k2\"), \"v2\")\n\t\tt.Assert(j.Get(\"k3\"), nil)\n\t})\n\t// https://github.com/gogf/gf/issues/3253\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype TestStruct struct {\n\t\t\tResult []map[string]string `json:\"result\"`\n\t\t}\n\t\tts := &TestStruct{\n\t\t\tResult: []map[string]string{\n\t\t\t\t{\n\t\t\t\t\t\"Name\": \"gf\",\n\t\t\t\t\t\"Role\": \"\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tgjson.New(ts)\n\t})\n}\n\nfunc Test_Valid(t *testing.T) {\n\tdata1 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tdata2 := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gjson.Valid(data1), true)\n\t\tt.Assert(gjson.Valid(data2), false)\n\t})\n}\n\nfunc Test_Encode(t *testing.T) {\n\tvalue := g.Slice{1, 2, 3}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gjson.Encode(value)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, []byte(`[1,2,3]`))\n\t})\n}\n\nfunc Test_Decode(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv, err := gjson.Decode(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, g.Map{\n\t\t\t\"n\": 123456789,\n\t\t\t\"a\": g.Slice{1, 2, 3},\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"k\": \"v\",\n\t\t\t},\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v any\n\t\terr := gjson.DecodeTo(data, &v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, g.Map{\n\t\t\t\"n\": 123456789,\n\t\t\t\"a\": g.Slice{1, 2, 3},\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"k\": \"v\",\n\t\t\t},\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m.k\"), \"v\")\n\t\tt.Assert(j.Get(\"a\").Array(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a.1\").Int(), 2)\n\t})\n}\n\nfunc Test_SplitChar(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tj.SetSplitChar(byte('#'))\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"m#k\").String(), \"v\")\n\t\tt.Assert(j.Get(\"a\").Array(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a#1\").Int(), 2)\n\t})\n}\n\nfunc Test_ViolenceCheck(t *testing.T) {\n\tdata := []byte(`{\"m\":{\"a\":[1,2,3], \"v1.v2\":\"4\"}}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"m.a.2\"), 3)\n\t\tt.Assert(j.Get(\"m.v1.v2\"), nil)\n\t\tj.SetViolenceCheck(true)\n\t\tt.Assert(j.Get(\"m.v1.v2\"), 4)\n\t})\n}\n\nfunc Test_GetVar(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").String(), \"123456789\")\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"a\").Interfaces(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a\").Slice(), g.Slice{1, 2, 3})\n\t\tt.Assert(j.Get(\"a\").Array(), g.Slice{1, 2, 3})\n\t})\n}\n\nfunc Test_GetMap(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").Map(), nil)\n\t\tt.Assert(j.Get(\"m\").Map(), g.Map{\"k\": \"v\"})\n\t\tt.Assert(j.Get(\"a\").Map(), g.Map{\"1\": \"2\", \"3\": nil})\n\t})\n}\n\nfunc Test_GetJson(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tj2 := j.GetJson(\"m\")\n\t\tt.AssertNE(j2, nil)\n\t\tt.Assert(j2.Get(\"k\"), \"v\")\n\t\tt.Assert(j2.Get(\"a\"), nil)\n\t\tt.Assert(j2.Get(\"n\"), nil)\n\t})\n}\n\nfunc Test_GetArray(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"n\").Array(), g.Array{123456789})\n\t\tt.Assert(j.Get(\"m\").Array(), g.Array{g.Map{\"k\": \"v\"}})\n\t\tt.Assert(j.Get(\"a\").Array(), g.Array{1, 2, 3})\n\t})\n}\n\nfunc Test_GetString(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(j.Get(\"n\").String(), \"123456789\")\n\t\tt.AssertEQ(j.Get(\"m\").String(), `{\"k\":\"v\"}`)\n\t\tt.AssertEQ(j.Get(\"a\").String(), `[1,2,3]`)\n\t\tt.AssertEQ(j.Get(\"i\").String(), \"\")\n\t})\n}\n\nfunc Test_GetStrings(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(j.Get(\"n\").Strings(), g.SliceStr{\"123456789\"})\n\t\tt.AssertEQ(j.Get(\"m\").Strings(), g.SliceStr{`{\"k\":\"v\"}`})\n\t\tt.AssertEQ(j.Get(\"a\").Strings(), g.SliceStr{\"1\", \"2\", \"3\"})\n\t\tt.AssertEQ(j.Get(\"i\").Strings(), nil)\n\t})\n}\n\nfunc Test_GetInterfaces(t *testing.T) {\n\tdata := []byte(`{\"n\":123456789, \"m\":{\"k\":\"v\"}, \"a\":[1,2,3]}`)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj, err := gjson.DecodeToJson(data)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(j.Get(\"n\").Interfaces(), g.Array{123456789})\n\t\tt.AssertEQ(j.Get(\"m\").Interfaces(), g.Array{g.Map{\"k\": \"v\"}})\n\t\tt.AssertEQ(j.Get(\"a\").Interfaces(), g.Array{1, 2, 3})\n\t})\n}\n\nfunc Test_Len(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Append(\"a\", 1)\n\t\tp.Append(\"a\", 2)\n\t\tt.Assert(p.Len(\"a\"), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Append(\"a.b\", 1)\n\t\tp.Append(\"a.c\", 2)\n\t\tt.Assert(p.Len(\"a\"), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Set(\"a\", 1)\n\t\tt.Assert(p.Len(\"a\"), -1)\n\t})\n}\n\nfunc Test_Append(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Append(\"a\", 1)\n\t\tp.Append(\"a\", 2)\n\t\tt.Assert(p.Get(\"a\"), g.Slice{1, 2})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Append(\"a.b\", 1)\n\t\tp.Append(\"a.c\", 2)\n\t\tt.Assert(p.Get(\"a\").Map(), g.Map{\n\t\t\t\"b\": g.Slice{1},\n\t\t\t\"c\": g.Slice{2},\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(nil)\n\t\tp.Set(\"a\", 1)\n\t\terr := p.Append(\"a\", 2)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(p.Get(\"a\"), 1)\n\t})\n}\n\nfunc Test_RawArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tt.AssertNil(j.Set(\"0\", 1))\n\t\tt.AssertNil(j.Set(\"1\", 2))\n\t\tt.Assert(j.MustToJsonString(), `[1,2]`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tt.AssertNil(j.Append(\".\", 1))\n\t\tt.AssertNil(j.Append(\".\", 2))\n\t\tt.Assert(j.MustToJsonString(), `[1,2]`)\n\t})\n}\n\nfunc TestJson_ToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(1)\n\t\ts, e := p.ToJsonString()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(s, \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := gjson.New(\"a\")\n\t\ts, e := p.ToJsonString()\n\t\tt.Assert(e, nil)\n\t\tt.Assert(s, `\"a\"`)\n\t})\n}\n\nfunc TestJson_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int(), 100)\n\t\tt.AssertEQ(j.Get(\"no\", 100).String(), \"100\")\n\t\tt.AssertEQ(j.Get(\"no\", \"on\").Bool(), true)\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int(), 100)\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int8(), int8(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int16(), int16(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int32(), int32(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Int64(), int64(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Uint(), uint(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Uint8(), uint8(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Uint16(), uint16(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Uint32(), uint32(100))\n\t\tt.AssertEQ(j.Get(\"no\", 100).Uint64(), uint64(100))\n\t\tt.AssertEQ(j.Get(\"no\", 123.456).Float32(), float32(123.456))\n\t\tt.AssertEQ(j.Get(\"no\", 123.456).Float64(), float64(123.456))\n\t\tt.AssertEQ(j.Get(\"no\", g.Slice{1, 2, 3}).Array(), g.Slice{1, 2, 3})\n\t\tt.AssertEQ(j.Get(\"no\", g.Slice{1, 2, 3}).Ints(), g.SliceInt{1, 2, 3})\n\t\tt.AssertEQ(j.Get(\"no\", g.Slice{1, 2, 3}).Floats(), []float64{1, 2, 3})\n\t\tt.AssertEQ(j.Get(\"no\", g.Map{\"k\": \"v\"}).Map(), g.Map{\"k\": \"v\"})\n\t\tt.AssertEQ(j.Get(\"no\", 123.456).Float64(), float64(123.456))\n\t\tt.AssertEQ(j.GetJson(\"no\", g.Map{\"k\": \"v\"}).Get(\"k\").String(), \"v\")\n\t\tt.AssertEQ(j.GetJsons(\"no\", g.Slice{\n\t\t\tg.Map{\"k1\": \"v1\"},\n\t\t\tg.Map{\"k2\": \"v2\"},\n\t\t\tg.Map{\"k3\": \"v3\"},\n\t\t})[0].Get(\"k1\").String(), \"v1\")\n\t\tt.AssertEQ(j.GetJsonMap(\"no\", g.Map{\n\t\t\t\"m1\": g.Map{\"k1\": \"v1\"},\n\t\t\t\"m2\": g.Map{\"k2\": \"v2\"},\n\t\t})[\"m2\"].Get(\"k2\").String(), \"v2\")\n\t})\n}\n\nfunc Test_Convert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(`{\"name\":\"gf\"}`)\n\t\tarr, err := j.ToXml()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"<name>gf</name>\")\n\t\tarr, err = j.ToXmlIndent()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"<name>gf</name>\")\n\t\tstr, err := j.ToXmlString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(str, \"<name>gf</name>\")\n\t\tstr, err = j.ToXmlIndentString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(str, \"<name>gf</name>\")\n\n\t\tarr, err = j.ToJsonIndent()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"{\\n\\t\\\"name\\\": \\\"gf\\\"\\n}\")\n\t\tstr, err = j.ToJsonIndentString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"{\\n\\t\\\"name\\\": \\\"gf\\\"\\n}\")\n\n\t\tarr, err = j.ToYaml()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"name: gf\\n\")\n\t\tstr, err = j.ToYamlString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"name: gf\\n\")\n\n\t\tarr, err = j.ToToml()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"name = \\\"gf\\\"\\n\")\n\t\tstr, err = j.ToTomlString()\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(arr), \"name = \\\"gf\\\"\\n\")\n\t})\n}\n\nfunc Test_Convert2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tname := struct {\n\t\t\tName string\n\t\t}{}\n\t\tj := gjson.New(`{\"name\":\"gf\",\"time\":\"2019-06-12\"}`)\n\t\tt.Assert(j.Interface().(g.Map)[\"name\"], \"gf\")\n\t\tt.Assert(j.Get(\"name1\").Map(), nil)\n\t\tt.Assert(j.GetJson(\"name1\"), nil)\n\t\tt.Assert(j.GetJsons(\"name1\"), nil)\n\t\tt.Assert(j.GetJsonMap(\"name1\"), nil)\n\t\tt.Assert(j.Contains(\"name1\"), false)\n\t\tt.Assert(j.Get(\"name1\").IsNil(), true)\n\t\tt.Assert(j.Get(\"name\").IsNil(), false)\n\t\tt.Assert(j.Len(\"name1\"), -1)\n\t\tt.Assert(j.Get(\"time\").Time().Format(\"2006-01-02\"), \"2019-06-12\")\n\t\tt.Assert(j.Get(\"time\").GTime().Format(\"Y-m-d\"), \"2019-06-12\")\n\t\tt.Assert(j.Get(\"time\").Duration().String(), \"0s\")\n\n\t\terr := j.Var().Scan(&name)\n\t\tt.AssertNil(err)\n\t\tt.Assert(name.Name, \"gf\")\n\t\t// j.Dump()\n\t\tt.AssertNil(err)\n\n\t\tj = gjson.New(`{\"person\":{\"name\":\"gf\"}}`)\n\t\terr = j.Get(\"person\").Scan(&name)\n\t\tt.AssertNil(err)\n\t\tt.Assert(name.Name, \"gf\")\n\n\t\tj = gjson.New(`{\"name\":\"gf\"\"}`)\n\t\t// j.Dump()\n\t\tt.AssertNil(err)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\tt.Assert(len(j.Var().Array()), 3)\n\t})\n}\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(`{\"name\":\"gf\",\"time\":\"2019-06-12\"}`)\n\t\tj.SetViolenceCheck(true)\n\t\tt.Assert(j.Get(\"\"), nil)\n\t\tt.Assert(j.Get(\".\").Interface().(g.Map)[\"name\"], \"gf\")\n\t\tt.Assert(j.Get(\".\").Interface().(g.Map)[\"name1\"], nil)\n\t\tj.SetViolenceCheck(false)\n\t\tt.Assert(j.Get(\".\").Interface().(g.Map)[\"name\"], \"gf\")\n\n\t\terr := j.Set(\"name\", \"gf1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"name\"), \"gf1\")\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Set(\"\\\"0\\\".1\", 11)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"1\"), 11)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Set(\"11111111111111111111111\", 11)\n\t\tt.AssertNE(err, nil)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Remove(\"1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"0\"), 1)\n\t\tt.Assert(len(j.Var().Array()), 2)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\t// If index 0 is delete, its next item will be at index 0.\n\t\tt.Assert(j.Remove(\"0\"), nil)\n\t\tt.Assert(j.Remove(\"0\"), nil)\n\t\tt.Assert(j.Remove(\"0\"), nil)\n\t\tt.Assert(j.Get(\"0\"), nil)\n\t\tt.Assert(len(j.Var().Array()), 0)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Remove(\"3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"0\"), 1)\n\t\tt.Assert(len(j.Var().Array()), 3)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Remove(\"0.3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"0\"), 1)\n\n\t\tj = gjson.New(`[1,2,3]`)\n\t\terr = j.Remove(\"0.a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"0\"), 1)\n\n\t\tname := struct {\n\t\t\tName string\n\t\t}{Name: \"gf\"}\n\t\tj = gjson.New(name)\n\t\tt.Assert(j.Get(\"Name\"), \"gf\")\n\t\terr = j.Remove(\"Name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name\"), nil)\n\n\t\terr = j.Set(\"Name\", \"gf1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name\"), \"gf1\")\n\n\t\tj = gjson.New(nil)\n\t\terr = j.Remove(\"Name\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name\"), nil)\n\n\t\tj = gjson.New(name)\n\t\tt.Assert(j.Get(\"Name\"), \"gf\")\n\t\terr = j.Set(\"Name1\", g.Map{\"Name\": \"gf1\"})\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name1\").Interface().(g.Map)[\"Name\"], \"gf1\")\n\t\terr = j.Set(\"Name2\", g.Slice{1, 2, 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name2\").Interface().(g.Slice)[0], 1)\n\t\terr = j.Set(\"Name3\", name)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name3\").Interface().(g.Map)[\"Name\"], \"gf\")\n\t\terr = j.Set(\"Name4\", &name)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name4\").Interface().(g.Map)[\"Name\"], \"gf\")\n\t\tarr := [3]int{1, 2, 3}\n\t\terr = j.Set(\"Name5\", arr)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"Name5\").Interface().(g.Array)[0], 1)\n\n\t})\n}\n\nfunc TestJson_Var(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"[9223372036854775807, 9223372036854775806]\")\n\t\tarray := gjson.New(data).Var().Array()\n\t\tt.Assert(array, []uint64{9223372036854776000, 9223372036854776000})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"[9223372036854775807, 9223372036854775806]\")\n\t\tarray := gjson.NewWithOptions(data, gjson.Options{StrNumber: true}).Var().Array()\n\t\tt.Assert(array, []uint64{9223372036854775807, 9223372036854775806})\n\t})\n}\n\nfunc TestJson_IsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gjson.New(nil)\n\t\tt.Assert(j.IsNil(), true)\n\t})\n}\n\nfunc TestJson_Set_With_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gjson.New(g.Map{\n\t\t\t\"user1\": g.Map{\"name\": \"user1\"},\n\t\t\t\"user2\": g.Map{\"name\": \"user2\"},\n\t\t\t\"user3\": g.Map{\"name\": \"user3\"},\n\t\t})\n\t\tuser1 := v.GetJson(\"user1\")\n\t\tt.AssertNil(user1.Set(\"id\", 111))\n\t\tt.AssertNil(v.Set(\"user1\", user1))\n\t\tt.Assert(v.Get(\"user1.id\"), 111)\n\t})\n}\n\nfunc TestJson_Options(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S struct {\n\t\t\tId int64\n\t\t}\n\t\ts := S{\n\t\t\tId: 53687091200,\n\t\t}\n\t\tm := make(map[string]any)\n\t\tt.AssertNil(gjson.DecodeTo(gjson.MustEncode(s), &m, gjson.Options{\n\t\t\tStrNumber: false,\n\t\t}))\n\t\tt.Assert(fmt.Sprintf(`%v`, m[\"Id\"]), `5.36870912e+10`)\n\t\tt.AssertNil(gjson.DecodeTo(gjson.MustEncode(s), &m, gjson.Options{\n\t\t\tStrNumber: true,\n\t\t}))\n\t\tt.Assert(fmt.Sprintf(`%v`, m[\"Id\"]), `53687091200`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1617\nfunc Test_Issue1617(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyJsonName struct {\n\t\t\tF中文   int64 `json:\"F中文\"`\n\t\t\tF英文   int64 `json:\"F英文\"`\n\t\t\tF法文   int64 `json:\"F法文\"`\n\t\t\tF西班牙语 int64 `json:\"F西班牙语\"`\n\t\t}\n\t\tjso := `{\"F中文\":1,\"F英文\":2,\"F法文\":3,\"F西班牙语\":4}`\n\t\tvar a MyJsonName\n\t\tjson, err := gjson.DecodeToJson(jso)\n\t\tt.AssertNil(err)\n\t\terr = json.Scan(&a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a, MyJsonName{\n\t\t\tF中文:   1,\n\t\t\tF英文:   2,\n\t\t\tF法文:   3,\n\t\t\tF西班牙语: 4,\n\t\t})\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1747\nfunc Test_Issue1747(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar j *gjson.Json\n\t\terr := gconv.Struct(gvar.New(\"[1, 2, 336371793314971759]\"), &j)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(\"2\"), `336371793314971759`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2520\nfunc Test_Issue2520(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype test struct {\n\t\t\tUnique *gvar.Var `json:\"unique\"`\n\t\t}\n\n\t\tt2 := test{Unique: gvar.New(gtime.Date())}\n\t\tt.Assert(gjson.MustEncodeString(t2), gjson.New(t2).MustToJsonString())\n\t})\n}\n"
  },
  {
    "path": "encoding/gjson/testdata/json/data1.json",
    "content": "{\"name\":\"john\", \"score\":\"100\"}"
  },
  {
    "path": "encoding/gjson/testdata/properties/data1.properties",
    "content": "pr.name=john\npr.score=100\npr.sex=0"
  },
  {
    "path": "encoding/gjson/testdata/toml/data1.toml",
    "content": "[base]\n    name = \"john\"\n    score = 100"
  },
  {
    "path": "encoding/gjson/testdata/xml/data1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<doc>\n    <name>john</name>\n    <score>100</score>\n</doc>"
  },
  {
    "path": "encoding/gjson/testdata/yaml/data1.yaml",
    "content": "base:\n  name: john\n  score: 100"
  },
  {
    "path": "encoding/gjson/testdata/yaml/i18n-issue.yaml",
    "content": "\"environment status is Creating/Updating, please wait for sync to complete\": \"环境当前状为创建中/更新中，请等待同步完成\"\n\"There are still queues in the current environment, please ensure there are no queues before deletion\": \"当前环境还存在队列，确保环境没有队列再删除\"\n\"the current repository has associated environments in use, please ensure no environment associations before deleting the repository\": \"当前仓库有关联环境正在使用，请确保没有环境关联再删除该仓库\"\n\"There are environments using this cluster, please ensure all environments have been deleted before deleting the cluster\": \"当前集群存在环境正在使用，请确保所有环境已经删除再删除该集群\"\n\n\"shareStrategy.Init\": \"未拆卡\"\n\"shareStrategy.Pending\": \"切分中\"\n\"shareStrategy.Success\": \"拆卡成功\"\n\"shareStrategy.Canceling\": \"拆卡取消中\"\n\"shareStrategy.unknown\": \"未知状态\"\n\"resourceUsage.none\": \"无\"\n\"resourceUsage.inference\": \"推理\"\n\"resourceUsage.training\": \"训练\"\n\"resourceUsage.workflow\": \"workflow\"\n\"resourceUsage.hybrid\": \"混合\"\n\"resourceUsage.unknown\": \"unknown\""
  },
  {
    "path": "encoding/gproperties/gproperties.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gproperties provides accessing and converting for .properties content.\npackage gproperties\n\nimport (\n\t\"bytes\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/magiconair/properties\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Decode converts properties format to map.\nfunc Decode(data []byte) (res map[string]any, err error) {\n\tres = make(map[string]any)\n\tpr, err := properties.Load(data, properties.UTF8)\n\tif err != nil || pr == nil {\n\t\terr = gerror.Wrapf(err, `Lib magiconair load Properties data failed.`)\n\t\treturn nil, err\n\t}\n\tfor _, key := range pr.Keys() {\n\t\t// ignore existence check: we know it's there\n\t\tvalue, _ := pr.Get(key)\n\t\t// recursively build nested maps\n\t\tpath := strings.Split(key, \".\")\n\t\tlastKey := strings.ToLower(path[len(path)-1])\n\t\tdeepestMap := deepSearch(res, path[0:len(path)-1])\n\n\t\t// set innermost value\n\t\tdeepestMap[lastKey] = value\n\t}\n\treturn res, nil\n}\n\n// Encode converts map to properties format.\nfunc Encode(data map[string]any) (res []byte, err error) {\n\tpr := properties.NewProperties()\n\n\tflattened := map[string]any{}\n\n\tflattened = flattenAndMergeMap(flattened, data, \"\", \".\")\n\n\tkeys := make([]string, 0, len(flattened))\n\n\tfor key := range flattened {\n\t\tkeys = append(keys, key)\n\t}\n\n\tsort.Strings(keys)\n\n\tfor _, key := range keys {\n\t\t_, _, err := pr.Set(key, gconv.String(flattened[key]))\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `Sets the property key to the corresponding value failed.`)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar buf bytes.Buffer\n\n\t_, err = pr.Write(&buf, properties.UTF8)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `Properties Write buf failed.`)\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\n// ToJson convert .properties format to JSON.\nfunc ToJson(data []byte) (res []byte, err error) {\n\tprMap, err := Decode(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn json.Marshal(prMap)\n}\n\n// deepSearch scans deep maps, following the key indexes listed in the sequence \"path\".\n// The last value is expected to be another map, and is returned.\nfunc deepSearch(m map[string]any, path []string) map[string]any {\n\tfor _, k := range path {\n\t\tm2, ok := m[k]\n\t\tif !ok {\n\t\t\t// intermediate key does not exist\n\t\t\t// => create it and continue from there\n\t\t\tm3 := make(map[string]any)\n\t\t\tm[k] = m3\n\t\t\tm = m3\n\t\t\tcontinue\n\t\t}\n\t\tm3, ok := m2.(map[string]any)\n\t\tif !ok {\n\t\t\tm3 = make(map[string]any)\n\t\t\tm[k] = m3\n\t\t}\n\t\t// continue search from here\n\t\tm = m3\n\t}\n\treturn m\n}\n\n// flattenAndMergeMap recursively flattens the given map into a new map\nfunc flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any {\n\tif shadow != nil && prefix != \"\" && shadow[prefix] != nil {\n\t\treturn shadow\n\t}\n\n\tvar m2 map[string]any\n\tif prefix != \"\" {\n\t\tprefix += delimiter\n\t}\n\tfor k, val := range m {\n\t\tfullKey := prefix + k\n\t\tswitch val := val.(type) {\n\t\tcase map[string]any:\n\t\t\tm2 = val\n\t\tcase map[any]any:\n\t\t\tm2 = gconv.Map(val)\n\t\tdefault:\n\t\t\t// immediate value\n\t\t\tshadow[strings.ToLower(fullKey)] = val\n\t\t\tcontinue\n\t\t}\n\t\t// recursively merge to shadow map\n\t\tshadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)\n\t}\n\treturn shadow\n}\n"
  },
  {
    "path": "encoding/gproperties/gproperties_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproperties_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gproperties\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar pStr string = `\n# 模板引擎目录\nviewpath = \"/home/www/templates/\"\n# redis数据库配置\nredis.disk  = \"127.0.0.1:6379,0\"\nredis.cache = \"127.0.0.1:6379,1\"\n#SQL配置\nsql.mysql.0.type = mysql\nsql.mysql.0.ip = 127.0.0.1\nsql.mysql.0.user = root\n`\n\nvar errorTests = []struct {\n\tinput, msg string\n}{\n\t// unicode literals\n\t{\"key\\\\u1 = value\", \"invalid unicode literal\"},\n\t{\"key\\\\u12 = value\", \"invalid unicode literal\"},\n\t{\"key\\\\u123 = value\", \"invalid unicode literal\"},\n\t{\"key\\\\u123g = value\", \"invalid unicode literal\"},\n\t{\"key\\\\u123\", \"invalid unicode literal\"},\n\n\t// circular references\n\t{\"key=${key}\", `circular reference in:\\nkey=\\$\\{key\\}`},\n\t{\"key1=${key2}\\nkey2=${key1}\", `circular reference in:\\n(key1=\\$\\{key2\\}\\nkey2=\\$\\{key1\\}|key2=\\$\\{key1\\}\\nkey1=\\$\\{key2\\})`},\n\n\t// malformed expressions\n\t{\"key=${ke\", \"malformed expression\"},\n\t{\"key=valu${ke\", \"malformed expression\"},\n}\n\nfunc TestDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]any)\n\t\tm[\"properties\"] = pStr\n\t\tres, err := gproperties.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tdecodeMap, err := gproperties.Decode(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(decodeMap[\"properties\"], pStr)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, v := range errorTests {\n\t\t\t_, err := gproperties.Decode(([]byte)(v.input))\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"encode should be failed. %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tt.AssertIN(`Lib magiconair load Properties data failed.`, strings.Split(err.Error(), \":\"))\n\t\t}\n\t})\n}\n\nfunc TestEncode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]any)\n\t\tm[\"properties\"] = pStr\n\t\tres, err := gproperties.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tdecodeMap, err := gproperties.Decode(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(decodeMap[\"properties\"], pStr)\n\t})\n}\n\nfunc TestToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tres, err := gproperties.Encode(map[string]any{\n\t\t\t\"sql\": g.Map{\n\t\t\t\t\"userName\": \"admin\",\n\t\t\t\t\"password\": \"123456\",\n\t\t\t},\n\t\t\t\"user\": \"admin\",\n\t\t\t\"no\":   123,\n\t\t})\n\t\tfmt.Print(string(res))\n\t\tjsonPr, err := gproperties.ToJson(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tfmt.Print(string(jsonPr))\n\n\t\tp := gjson.New(res)\n\t\texpectJson, err := p.ToJson()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"parser ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(jsonPr, expectJson)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, v := range errorTests {\n\t\t\t_, err := gproperties.ToJson(([]byte)(v.input))\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"encode should be failed. %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tt.AssertIN(`Lib magiconair load Properties data failed.`, strings.Split(err.Error(), \":\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "encoding/gtoml/gtoml.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtoml provides accessing and converting for TOML content.\npackage gtoml\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/BurntSushi/toml\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\nfunc Encode(v any) ([]byte, error) {\n\tbuffer := bytes.NewBuffer(nil)\n\tif err := toml.NewEncoder(buffer).Encode(v); err != nil {\n\t\terr = gerror.Wrap(err, `toml.Encoder.Encode failed`)\n\t\treturn nil, err\n\t}\n\treturn buffer.Bytes(), nil\n}\n\nfunc Decode(v []byte) (any, error) {\n\tvar result any\n\tif err := toml.Unmarshal(v, &result); err != nil {\n\t\terr = gerror.Wrap(err, `toml.Unmarshal failed`)\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc DecodeTo(v []byte, result any) (err error) {\n\terr = toml.Unmarshal(v, result)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `toml.Unmarshal failed`)\n\t}\n\treturn err\n}\n\nfunc ToJson(v []byte) ([]byte, error) {\n\tif r, err := Decode(v); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn json.Marshal(r)\n\t}\n}\n"
  },
  {
    "path": "encoding/gtoml/gtoml_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\npackage gtoml_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gtoml\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar tomlStr string = `\n# 模板引擎目录\nviewpath = \"/home/www/templates/\"\n# MySQL数据库配置\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\nvar tomlErr string = `\n# 模板引擎目录\nviewpath = \"/home/www/templates/\"\n# MySQL数据库配置\n[redis]\ndd = 11\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\nfunc TestEncode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]string)\n\t\tm[\"toml\"] = tomlStr\n\t\tres, err := gtoml.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tt.Assert(gjson.New(res).Get(\"toml\").String(), tomlStr)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gtoml.Encode(tomlErr)\n\t\tt.Assert(err, nil)\n\t})\n}\n\nfunc TestDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]string)\n\t\tm[\"toml\"] = tomlStr\n\t\tres, err := gtoml.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tdecodeStr, err := gtoml.Decode(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tt.Assert(decodeStr.(map[string]any)[\"toml\"], tomlStr)\n\n\t\tdecodeStr1 := make(map[string]any)\n\t\terr = gtoml.DecodeTo(res, &decodeStr1)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decodeTo failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(decodeStr1[\"toml\"], tomlStr)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gtoml.Decode([]byte(tomlErr))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tdecodeStr1 := make(map[string]any)\n\t\terr = gtoml.DecodeTo([]byte(tomlErr), &decodeStr1)\n\t\tif err == nil {\n\t\t\tt.Errorf(\"decodeTo failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t})\n}\n\nfunc TestToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]string)\n\t\tm[\"toml\"] = tomlStr\n\t\tres, err := gtoml.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tjsonToml, err := gtoml.ToJson(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tp := gjson.New(res)\n\t\texpectJson, err := p.ToJson()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"parser ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(jsonToml, expectJson)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gtoml.ToJson([]byte(tomlErr))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "encoding/gurl/url.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gurl provides useful API for URL handling.\npackage gurl\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Encode escapes the string so it can be safely placed\n// inside an URL query.\nfunc Encode(str string) string {\n\treturn url.QueryEscape(str)\n}\n\n// Decode does the inverse transformation of Encode,\n// converting each 3-byte encoded substring of the form \"%AB\" into the\n// hex-decoded byte 0xAB.\n// It returns an error if any % is not followed by two hexadecimal\n// digits.\nfunc Decode(str string) (string, error) {\n\treturn url.QueryUnescape(str)\n}\n\n// RawEncode does encode the given string according\n// URL-encode according to RFC 3986.\n// See http://php.net/manual/en/function.rawurlencode.php.\nfunc RawEncode(str string) string {\n\treturn strings.ReplaceAll(url.QueryEscape(str), \"+\", \"%20\")\n}\n\n// RawDecode does decode the given string\n// Decode URL-encoded strings.\n// See http://php.net/manual/en/function.rawurldecode.php.\nfunc RawDecode(str string) (string, error) {\n\treturn url.QueryUnescape(strings.ReplaceAll(str, \"%20\", \"+\"))\n}\n\n// BuildQuery Generate URL-encoded query string.\n// See http://php.net/manual/en/function.http-build-query.php.\nfunc BuildQuery(queryData url.Values) string {\n\treturn queryData.Encode()\n}\n\n// ParseURL Parse an URL and return its components.\n// -1: all; 1: scheme; 2: host; 4: port; 8: user; 16: pass; 32: path; 64: query; 128: fragment.\n// See http://php.net/manual/en/function.parse-url.php.\nfunc ParseURL(str string, component int) (map[string]string, error) {\n\tu, err := url.Parse(str)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `url.Parse failed for URL \"%s\"`, str)\n\t\treturn nil, err\n\t}\n\tif component == -1 {\n\t\tcomponent = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128\n\t}\n\tcomponents := make(map[string]string)\n\tif (component & 1) == 1 {\n\t\tcomponents[\"scheme\"] = u.Scheme\n\t}\n\tif (component & 2) == 2 {\n\t\tcomponents[\"host\"] = u.Hostname()\n\t}\n\tif (component & 4) == 4 {\n\t\tcomponents[\"port\"] = u.Port()\n\t}\n\tif (component & 8) == 8 {\n\t\tcomponents[\"user\"] = u.User.Username()\n\t}\n\tif (component & 16) == 16 {\n\t\tcomponents[\"pass\"], _ = u.User.Password()\n\t}\n\tif (component & 32) == 32 {\n\t\tcomponents[\"path\"] = u.Path\n\t}\n\tif (component & 64) == 64 {\n\t\tcomponents[\"query\"] = u.RawQuery\n\t}\n\tif (component & 128) == 128 {\n\t\tcomponents[\"fragment\"] = u.Fragment\n\t}\n\treturn components, nil\n}\n"
  },
  {
    "path": "encoding/gurl/url_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\npackage gurl_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\turlStr       = `https://golang.org/x/crypto?go-get=1 +`\n\turlEncode    = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1+%2B`\n\trawUrlEncode = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1%20%2B`\n)\n\nfunc TestEncodeAndDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gurl.Encode(urlStr), urlEncode)\n\n\t\tres, err := gurl.Decode(urlEncode)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(res, urlStr)\n\t})\n}\n\nfunc TestRowEncodeAndDecode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gurl.RawEncode(urlStr), rawUrlEncode)\n\n\t\tres, err := gurl.RawDecode(rawUrlEncode)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"decode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(res, urlStr)\n\t})\n}\n\nfunc TestBuildQuery(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := url.Values{\n\t\t\t\"a\": {\"a2\", \"a1\"},\n\t\t\t\"b\": {\"b2\", \"b1\"},\n\t\t\t\"c\": {\"c1\", \"c2\"},\n\t\t}\n\t\texpect := \"a=a2&a=a1&b=b2&b=b1&c=c1&c=c2\"\n\t\tt.Assert(gurl.BuildQuery(src), expect)\n\t})\n}\n\nfunc TestParseURL(t *testing.T) {\n\tsrc := `http://username:password@hostname:9090/path?arg=value#anchor`\n\texpect := map[string]string{\n\t\t\"scheme\":   \"http\",\n\t\t\"host\":     \"hostname\",\n\t\t\"port\":     \"9090\",\n\t\t\"user\":     \"username\",\n\t\t\"pass\":     \"password\",\n\t\t\"path\":     \"/path\",\n\t\t\"query\":    \"arg=value\",\n\t\t\"fragment\": \"anchor\",\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcomponent := 0\n\t\tfor k, v := range []string{\"all\", \"scheme\", \"host\", \"port\", \"user\", \"pass\", \"path\", \"query\", \"fragment\"} {\n\t\t\tif v == \"all\" {\n\t\t\t\tcomponent = -1\n\t\t\t} else {\n\t\t\t\tcomponent = 1 << (uint(k - 1))\n\t\t\t}\n\n\t\t\tres, err := gurl.ParseURL(src, component)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"ParseURL failed. component:%v, err:%v\", component, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif v == \"all\" {\n\t\t\t\tt.Assert(res, expect)\n\t\t\t} else {\n\t\t\t\tt.Assert(res[v], expect[v])\n\t\t\t}\n\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "encoding/gxml/gxml.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gxml provides accessing and converting for XML content.\npackage gxml\n\nimport (\n\t\"strings\"\n\n\t\"github.com/clbanning/mxj/v2\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcharset\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// Decode parses `content` into and returns as map.\nfunc Decode(content []byte) (map[string]any, error) {\n\tres, err := convert(content)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm, err := mxj.NewMapXml(res)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `mxj.NewMapXml failed`)\n\t}\n\treturn m, err\n}\n\n// DecodeWithoutRoot parses `content` into a map, and returns the map without root level.\nfunc DecodeWithoutRoot(content []byte) (map[string]any, error) {\n\tres, err := convert(content)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm, err := mxj.NewMapXml(res)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `mxj.NewMapXml failed`)\n\t\treturn nil, err\n\t}\n\tfor _, v := range m {\n\t\tif r, ok := v.(map[string]any); ok {\n\t\t\treturn r, nil\n\t\t}\n\t}\n\treturn m, nil\n}\n\n// XMLEscapeChars forces escaping invalid characters in attribute and element values.\n// NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is\n// then '&amp;' will be re-escaped as '&amp;amp;'.\n//\n/*\n\tThe values are:\n\t\"   &quot;\n\t'   &apos;\n\t<   &lt;\n\t>   &gt;\n\t&   &amp;\n*/\n//\n// Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value\n// has been toggled to 'true' - then XMLEscapeChars(true) is ignored.  If XMLEscapeChars(true)\n// has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called\n// to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'.\nfunc XMLEscapeChars(b ...bool) {\n\tmxj.XMLEscapeChars(b...)\n}\n\n// Encode encodes map `m` to an XML format content as bytes.\n// The optional parameter `rootTag` is used to specify the XML root tag.\nfunc Encode(m map[string]any, rootTag ...string) ([]byte, error) {\n\tb, err := mxj.Map(m).Xml(rootTag...)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `mxj.Map.Xml failed`)\n\t}\n\treturn b, err\n}\n\n// EncodeWithIndent encodes map `m` to an XML format content as bytes with indent.\n// The optional parameter `rootTag` is used to specify the XML root tag.\nfunc EncodeWithIndent(m map[string]any, rootTag ...string) ([]byte, error) {\n\tb, err := mxj.Map(m).XmlIndent(\"\", \"\\t\", rootTag...)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `mxj.Map.XmlIndent failed`)\n\t}\n\treturn b, err\n}\n\n// ToJson converts `content` as XML format into JSON format bytes.\nfunc ToJson(content []byte) ([]byte, error) {\n\tres, err := convert(content)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmv, err := mxj.NewMapXml(res)\n\tif err == nil {\n\t\treturn mv.Json()\n\t}\n\terr = gerror.Wrap(err, `mxj.NewMapXml failed`)\n\treturn nil, err\n}\n\n// convert does convert the encoding of given XML content from XML root tag into UTF-8 encoding content.\nfunc convert(xml []byte) (res []byte, err error) {\n\tvar (\n\t\tpatten      = `<\\?xml.*encoding\\s*=\\s*['|\"](.*?)['|\"].*\\?>`\n\t\tmatchStr, _ = gregex.MatchString(patten, string(xml))\n\t\txmlEncode   = \"UTF-8\"\n\t)\n\tif len(matchStr) == 2 {\n\t\txmlEncode = matchStr[1]\n\t}\n\txmlEncode = strings.ToUpper(xmlEncode)\n\tres, err = gregex.Replace(patten, []byte(\"\"), xml)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif xmlEncode != \"UTF-8\" && xmlEncode != \"UTF8\" {\n\t\tdst, err := gcharset.Convert(\"UTF-8\", xmlEncode, string(res))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tres = []byte(dst)\n\t}\n\treturn res, nil\n}\n"
  },
  {
    "path": "encoding/gxml/gxml_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gxml_test\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcharset\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar testData = []struct {\n\tutf8, other, otherEncoding string\n}{\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb1`\\xa5\\u03b0\\xea\\xa6r\\xbc\\u0437\\u01e6r\\xc5\\xe9\\xaa\\xed\", \"big5\"},\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\", \"gbk\"},\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\", \"gb18030\"},\n}\n\nvar testErrData = []struct {\n\tutf8, other, otherEncoding string\n}{\n\t{\"Hello 常用國字標準字體表\", \"Hello \\xb3\\xa3\\xd3\\xc3\\x87\\xf8\\xd7\\xd6\\x98\\xcb\\x9c\\xca\\xd7\\xd6\\xf3\\x77\\xb1\\xed\", \"gbk\"},\n}\n\nfunc buildXml(charset string, str string) (string, string) {\n\thead := `<?xml version=\"1.0\" encoding=\"UTF-8\"?>`\n\tsrcXml := strings.Replace(head, \"UTF-8\", charset, -1)\n\n\tsrcParser := gjson.New(nil)\n\tsrcParser.Set(\"name\", str)\n\tsrcParser.Set(\"age\", \"12\")\n\n\ts, err := srcParser.ToXml()\n\tif err != nil {\n\t\treturn \"\", \"\"\n\t}\n\n\tsrcXml = srcXml + string(s)\n\tsrcXml, err = gcharset.UTF8To(charset, srcXml)\n\tif err != nil {\n\t\treturn \"\", \"\"\n\t}\n\n\tdstXml := head + string(s)\n\n\treturn srcXml, dstXml\n}\n\n// 测试XML中字符集的转换\nfunc Test_XmlToJson(t *testing.T) {\n\tfor _, v := range testData {\n\t\tsrcXml, dstXml := buildXml(v.otherEncoding, v.utf8)\n\t\tif len(srcXml) == 0 && len(dstXml) == 0 {\n\t\t\tt.Errorf(\"build xml string error. srcEncoding:%s, src:%s, utf8:%s\", v.otherEncoding, v.other, v.utf8)\n\t\t}\n\n\t\tsrcJson, err := gxml.ToJson([]byte(srcXml))\n\t\tif err != nil {\n\t\t\tt.Errorf(\"gxml.ToJson error. %s\", srcXml)\n\t\t}\n\n\t\tdstJson, err := gxml.ToJson([]byte(dstXml))\n\t\tif err != nil {\n\t\t\tt.Errorf(\"dstXml to json error. %s\", dstXml)\n\t\t}\n\n\t\tif !bytes.Equal(srcJson, dstJson) {\n\t\t\tt.Errorf(\"convert to json error. srcJson:%s, dstJson:%s\", string(srcJson), string(dstJson))\n\t\t}\n\n\t}\n}\n\nfunc Test_Decode1(t *testing.T) {\n\tfor _, v := range testData {\n\t\tsrcXml, dstXml := buildXml(v.otherEncoding, v.utf8)\n\t\tif len(srcXml) == 0 && len(dstXml) == 0 {\n\t\t\tt.Errorf(\"build xml string error. srcEncoding:%s, src:%s, utf8:%s\", v.otherEncoding, v.other, v.utf8)\n\t\t}\n\n\t\tsrcMap, err := gxml.Decode([]byte(srcXml))\n\t\tif err != nil {\n\t\t\tt.Errorf(\"gxml.Decode error. %s\", srcXml)\n\t\t}\n\n\t\tdstMap, err := gxml.Decode([]byte(dstXml))\n\t\tif err != nil {\n\t\t\tt.Errorf(\"gxml decode error. %s\", dstXml)\n\t\t}\n\t\ts := srcMap[\"doc\"].(map[string]any)\n\t\td := dstMap[\"doc\"].(map[string]any)\n\t\tfor kk, vv := range s {\n\t\t\tif vv.(string) != d[kk].(string) {\n\t\t\t\tt.Errorf(\"convert to map error. src:%v, dst:%v\", vv, d[kk])\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc Test_Decode2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `\n<?xml version=\"1.0\" encoding=\"UTF-8\"?><doc><username>johngcn</username><password1>123456</password1><password2>123456</password2></doc>\n`\n\t\tm, err := gxml.Decode([]byte(content))\n\t\tt.AssertNil(err)\n\t\tt.Assert(m[\"doc\"].(map[string]any)[\"username\"], \"johngcn\")\n\t\tt.Assert(m[\"doc\"].(map[string]any)[\"password1\"], \"123456\")\n\t\tt.Assert(m[\"doc\"].(map[string]any)[\"password2\"], \"123456\")\n\t})\n}\n\nfunc Test_DecodeWitoutRoot(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `\n<?xml version=\"1.0\" encoding=\"UTF-8\"?><doc><username>johngcn</username><password1>123456</password1><password2>123456</password2></doc>\n`\n\t\tm, err := gxml.DecodeWithoutRoot([]byte(content))\n\t\tt.AssertNil(err)\n\t\tt.Assert(m[\"username\"], \"johngcn\")\n\t\tt.Assert(m[\"password1\"], \"123456\")\n\t\tt.Assert(m[\"password2\"], \"123456\")\n\t})\n}\n\nfunc Test_Encode(t *testing.T) {\n\tm := make(map[string]any)\n\tv := map[string]any{\n\t\t\"string\": \"hello world\",\n\t\t\"int\":    123,\n\t\t\"float\":  100.92,\n\t\t\"bool\":   true,\n\t}\n\tm[\"root\"] = any(v)\n\n\txmlStr, err := gxml.Encode(m)\n\tif err != nil {\n\t\tt.Errorf(\"encode error.\")\n\t}\n\t// t.Logf(\"%s\\n\", string(xmlStr))\n\n\tres := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string></root>`\n\tif string(xmlStr) != res {\n\t\tt.Errorf(\"encode error. result: [%s], expect:[%s]\", string(xmlStr), res)\n\t}\n}\n\nfunc Test_EncodeIndent(t *testing.T) {\n\tm := make(map[string]any)\n\tv := map[string]any{\n\t\t\"string\": \"hello world\",\n\t\t\"int\":    123,\n\t\t\"float\":  100.92,\n\t\t\"bool\":   true,\n\t}\n\tm[\"root\"] = any(v)\n\n\t_, err := gxml.EncodeWithIndent(m, \"xml\")\n\tif err != nil {\n\t\tt.Errorf(\"encodeWithIndent error.\")\n\t}\n\n\t// t.Logf(\"%s\\n\", string(xmlStr))\n\n}\n\nfunc TestErrXml(t *testing.T) {\n\tfor _, v := range testErrData {\n\t\tsrcXml, dstXml := buildXml(v.otherEncoding, v.utf8)\n\t\tif len(srcXml) == 0 && len(dstXml) == 0 {\n\t\t\tt.Errorf(\"build xml string error. srcEncoding:%s, src:%s, utf8:%s\", v.otherEncoding, v.other, v.utf8)\n\t\t}\n\n\t\tsrcXml = strings.Replace(srcXml, \"gbk\", \"XXX\", -1)\n\t\t_, err := gxml.ToJson([]byte(srcXml))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"srcXml to json should be failed. %s\", srcXml)\n\t\t}\n\n\t}\n}\n\nfunc TestErrCase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrXml := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string>`\n\t\t_, err := gxml.ToJson([]byte(errXml))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"unexpected value: nil\")\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrXml := `<root><bool>true</bool><float>100.92</float><int>123</int><string>hello world</string>`\n\t\t_, err := gxml.Decode([]byte(errXml))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"unexpected value: nil\")\n\t\t}\n\t})\n}\n\nfunc Test_Issue3716(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\txml = `<Person><Bio>I am a software developer &amp; I love coding.</Bio><Email>john.doe@example.com</Email><Name>&lt;&gt;&amp;&apos;&quot;AAA</Name></Person>`\n\t\t\tm   = map[string]any{\n\t\t\t\t\"Person\": map[string]any{\n\t\t\t\t\t\"Name\":  \"<>&'\\\"AAA\",\n\t\t\t\t\t\"Email\": \"john.doe@example.com\",\n\t\t\t\t\t\"Bio\":   \"I am a software developer & I love coding.\",\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\tgxml.XMLEscapeChars(true)\n\t\tdefer gxml.XMLEscapeChars(false)\n\n\t\txb, err := gxml.Encode(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(xb), xml)\n\n\t\tdm, err := gxml.Decode(xb)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dm, m)\n\t})\n}\n"
  },
  {
    "path": "encoding/gyaml/gyaml.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gyaml provides accessing and converting for YAML content.\npackage gyaml\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\n\t\"gopkg.in/yaml.v3\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Encode encodes `value` to an YAML format content as bytes.\nfunc Encode(value any) (out []byte, err error) {\n\tif out, err = yaml.Marshal(value); err != nil {\n\t\terr = gerror.Wrap(err, `yaml.Marshal failed`)\n\t}\n\treturn\n}\n\n// EncodeIndent encodes `value` to an YAML format content with indent as bytes.\nfunc EncodeIndent(value any, indent string) (out []byte, err error) {\n\tout, err = Encode(value)\n\tif err != nil {\n\t\treturn\n\t}\n\tif indent != \"\" {\n\t\tvar (\n\t\t\tbuffer = bytes.NewBuffer(nil)\n\t\t\tarray  = strings.Split(strings.TrimSpace(string(out)), \"\\n\")\n\t\t)\n\t\tfor _, v := range array {\n\t\t\tbuffer.WriteString(indent)\n\t\t\tbuffer.WriteString(v)\n\t\t\tbuffer.WriteString(\"\\n\")\n\t\t}\n\t\tout = buffer.Bytes()\n\t}\n\treturn\n}\n\n// Decode parses `content` into and returns as map.\nfunc Decode(content []byte) (map[string]any, error) {\n\tvar (\n\t\tresult map[string]any\n\t\terr    error\n\t)\n\tif err = yaml.Unmarshal(content, &result); err != nil {\n\t\terr = gerror.Wrap(err, `yaml.Unmarshal failed`)\n\t\treturn nil, err\n\t}\n\treturn gconv.Map(result,\n\t\tgconv.MapOption{\n\t\t\tDeep:            true,\n\t\t\tOmitEmpty:       false,\n\t\t\tContinueOnError: true,\n\t\t}), nil\n}\n\n// DecodeTo parses `content` into `result`.\nfunc DecodeTo(value []byte, result any) (err error) {\n\terr = yaml.Unmarshal(value, result)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `yaml.Unmarshal failed`)\n\t}\n\treturn\n}\n\n// ToJson converts `content` to JSON format content.\nfunc ToJson(content []byte) (out []byte, err error) {\n\tvar (\n\t\tresult any\n\t)\n\tif result, err = Decode(content); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn json.Marshal(result)\n\t}\n}\n"
  },
  {
    "path": "encoding/gyaml/gyaml_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gyaml_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gyaml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar yamlStr string = `\n#即表示url属性值；\nurl: https://goframe.org\n\n#数组，即表示server为[a,b,c]\nserver:\n    - 120.168.117.21\n    - 120.168.117.22\n#常量\npi: 3.14   #定义一个数值3.14\nhasChild: true  #定义一个boolean值\nname: '你好YAML'   #定义一个字符串\n`\n\nvar yamlErr string = `\n[redis]\ndd = 11\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\nfunc Test_Encode(t *testing.T) {\n\t// Map.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gyaml.Encode(g.Map{\n\t\t\t\"k\": \"v\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `k: v\n`)\n\t})\n\t// Array.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gyaml.Encode([]string{\"a\", \"b\", \"c\"})\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `- a\n- b\n- c\n`)\n\t})\n}\n\nfunc Test_EncodeIndent(t *testing.T) {\n\t// Array.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := gyaml.EncodeIndent([]string{\"a\", \"b\", \"c\"}, \"####\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `####- a\n####- b\n####- c\n`)\n\t})\n}\n\nfunc Test_Decode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gyaml.Decode([]byte(yamlStr))\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(result, map[string]any{\n\t\t\t\"url\":      \"https://goframe.org\",\n\t\t\t\"server\":   g.Slice{\"120.168.117.21\", \"120.168.117.22\"},\n\t\t\t\"pi\":       3.14,\n\t\t\t\"hasChild\": true,\n\t\t\t\"name\":     \"你好YAML\",\n\t\t})\n\t})\n}\n\nfunc Test_DecodeTo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := make(map[string]any)\n\t\terr := gyaml.DecodeTo([]byte(yamlStr), &result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, map[string]any{\n\t\t\t\"url\":      \"https://goframe.org\",\n\t\t\t\"server\":   g.Slice{\"120.168.117.21\", \"120.168.117.22\"},\n\t\t\t\"pi\":       3.14,\n\t\t\t\"hasChild\": true,\n\t\t\t\"name\":     \"你好YAML\",\n\t\t})\n\t})\n}\n\nfunc Test_DecodeError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gyaml.Decode([]byte(yamlErr))\n\t\tt.AssertNE(err, nil)\n\n\t\tresult := make(map[string]any)\n\t\terr = gyaml.DecodeTo([]byte(yamlErr), &result)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_DecodeMapToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(`\nm:\n k: v\n    `)\n\t\tv, err := gyaml.Decode(data)\n\t\tt.AssertNil(err)\n\t\tb, err := json.Marshal(v)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"m\":{\"k\":\"v\"}}`)\n\t})\n}\n\nfunc Test_ToJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := make(map[string]string)\n\t\tm[\"yaml\"] = yamlStr\n\t\tres, err := gyaml.Encode(m)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"encode failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tjsonyaml, err := gyaml.ToJson(res)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tp := gjson.New(res)\n\t\texpectJson, err := p.ToJson()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"parser ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t\tt.Assert(jsonyaml, expectJson)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gyaml.ToJson([]byte(yamlErr))\n\t\tif err == nil {\n\t\t\tt.Errorf(\"ToJson failed. %v\", err)\n\t\t\treturn\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "errors/gcode/gcode.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcode provides universal error code definition and common error codes implements.\npackage gcode\n\n// Code is universal error code interface definition.\ntype Code interface {\n\t// Code returns the integer number of current error code.\n\tCode() int\n\n\t// Message returns the brief message for current error code.\n\tMessage() string\n\n\t// Detail returns the detailed information of current error code,\n\t// which is mainly designed as an extension field for error code.\n\tDetail() any\n}\n\n// ================================================================================================================\n// Common error code definition.\n// There are reserved internal error code by framework: code < 1000.\n// ================================================================================================================\n\nvar (\n\tCodeNil                       = localCode{-1, \"\", nil}                             // No error code specified.\n\tCodeOK                        = localCode{0, \"OK\", nil}                            // It is OK.\n\tCodeInternalError             = localCode{50, \"Internal Error\", nil}               // An error occurred internally.\n\tCodeValidationFailed          = localCode{51, \"Validation Failed\", nil}            // Data validation failed.\n\tCodeDbOperationError          = localCode{52, \"Database Operation Error\", nil}     // Database operation error.\n\tCodeInvalidParameter          = localCode{53, \"Invalid Parameter\", nil}            // The given parameter for current operation is invalid.\n\tCodeMissingParameter          = localCode{54, \"Missing Parameter\", nil}            // Parameter for current operation is missing.\n\tCodeInvalidOperation          = localCode{55, \"Invalid Operation\", nil}            // The function cannot be used like this.\n\tCodeInvalidConfiguration      = localCode{56, \"Invalid Configuration\", nil}        // The configuration is invalid for current operation.\n\tCodeMissingConfiguration      = localCode{57, \"Missing Configuration\", nil}        // The configuration is missing for current operation.\n\tCodeNotImplemented            = localCode{58, \"Not Implemented\", nil}              // The operation is not implemented yet.\n\tCodeNotSupported              = localCode{59, \"Not Supported\", nil}                // The operation is not supported yet.\n\tCodeOperationFailed           = localCode{60, \"Operation Failed\", nil}             // I tried, but I cannot give you what you want.\n\tCodeNotAuthorized             = localCode{61, \"Not Authorized\", nil}               // Not Authorized.\n\tCodeSecurityReason            = localCode{62, \"Security Reason\", nil}              // Security Reason.\n\tCodeServerBusy                = localCode{63, \"Server Is Busy\", nil}               // Server is busy, please try again later.\n\tCodeUnknown                   = localCode{64, \"Unknown Error\", nil}                // Unknown error.\n\tCodeNotFound                  = localCode{65, \"Not Found\", nil}                    // Resource does not exist.\n\tCodeInvalidRequest            = localCode{66, \"Invalid Request\", nil}              // Invalid request.\n\tCodeNecessaryPackageNotImport = localCode{67, \"Necessary Package Not Import\", nil} // It needs necessary package import.\n\tCodeInternalPanic             = localCode{68, \"Internal Panic\", nil}               // A panic occurred internally.\n\tCodeBusinessValidationFailed  = localCode{300, \"Business Validation Failed\", nil}  // Business validation failed.\n)\n\n// New creates and returns an error code.\n// Note that it returns an interface object of Code.\nfunc New(code int, message string, detail any) Code {\n\treturn localCode{\n\t\tcode:    code,\n\t\tmessage: message,\n\t\tdetail:  detail,\n\t}\n}\n\n// WithCode creates and returns a new error code based on given Code.\n// The code and message is from given `code`, but the detail if from given `detail`.\nfunc WithCode(code Code, detail any) Code {\n\treturn localCode{\n\t\tcode:    code.Code(),\n\t\tmessage: code.Message(),\n\t\tdetail:  detail,\n\t}\n}\n"
  },
  {
    "path": "errors/gcode/gcode_local.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcode\n\nimport \"fmt\"\n\n// localCode is an implementer for interface Code for internal usage only.\ntype localCode struct {\n\tcode    int    // Error code, usually an integer.\n\tmessage string // Brief message for this error code.\n\tdetail  any    // As type of interface, it is mainly designed as an extension field for error code.\n}\n\n// Code returns the integer number of current error code.\nfunc (c localCode) Code() int {\n\treturn c.code\n}\n\n// Message returns the brief message for current error code.\nfunc (c localCode) Message() string {\n\treturn c.message\n}\n\n// Detail returns the detailed information of current error code,\n// which is mainly designed as an extension field for error code.\nfunc (c localCode) Detail() any {\n\treturn c.detail\n}\n\n// String returns current error code as a string.\nfunc (c localCode) String() string {\n\tif c.detail != nil {\n\t\treturn fmt.Sprintf(`%d:%s %v`, c.code, c.message, c.detail)\n\t}\n\tif c.message != \"\" {\n\t\treturn fmt.Sprintf(`%d:%s`, c.code, c.message)\n\t}\n\treturn fmt.Sprintf(`%d`, c.code)\n}\n"
  },
  {
    "path": "errors/gcode/gcode_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcode_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Case(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gcode.CodeNil.String(), \"-1\")\n\t\tt.Assert(gcode.CodeInternalError.String(), \"50:Internal Error\")\n\t})\n}\n\nfunc Test_Nil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := gcode.New(1, \"custom error\", \"detailed description\")\n\t\tt.Assert(c.Code(), 1)\n\t\tt.Assert(c.Message(), \"custom error\")\n\t\tt.Assert(c.Detail(), \"detailed description\")\n\t})\n}\n\nfunc Test_WithCode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := gcode.WithCode(gcode.CodeInternalError, \"CodeInternalError\")\n\t\tt.Assert(c.Code(), gcode.CodeInternalError.Code())\n\t\tt.Assert(c.Detail(), \"CodeInternalError\")\n\t})\n}\n\nfunc Test_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with detail\n\t\tc := gcode.New(100, \"test message\", \"test detail\")\n\t\tt.Assert(c.(fmt.Stringer).String(), \"100:test message test detail\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with message but no detail\n\t\tc := gcode.New(100, \"test message\", nil)\n\t\tt.Assert(c.(fmt.Stringer).String(), \"100:test message\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with no message and no detail\n\t\tc := gcode.New(100, \"\", nil)\n\t\tt.Assert(c.(fmt.Stringer).String(), \"100\")\n\t})\n}\n"
  },
  {
    "path": "errors/gerror/gerror.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gerror provides rich functionalities to manipulate errors.\n//\n// For maintainers, please very note that,\n// this package is quite a basic package, which SHOULD NOT import extra packages\n// except standard packages and internal packages, to avoid cycle imports.\npackage gerror\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n)\n\n// IEqual is the interface for Equal feature.\ntype IEqual interface {\n\terror\n\tEqual(target error) bool\n}\n\n// ICode is the interface for Code feature.\ntype ICode interface {\n\terror\n\tCode() gcode.Code\n}\n\n// IStack is the interface for Stack feature.\ntype IStack interface {\n\terror\n\tStack() string\n}\n\n// ICause is the interface for Cause feature.\ntype ICause interface {\n\terror\n\tCause() error\n}\n\n// ICurrent is the interface for Current feature.\ntype ICurrent interface {\n\terror\n\tCurrent() error\n}\n\n// IUnwrap is the interface for Unwrap feature.\ntype IUnwrap interface {\n\terror\n\tUnwrap() error\n}\n\n// ITextArgs is the interface for Text and Args features.\n// This interface is mainly used for i18n features, that needs text and args separately.\ntype ITextArgs interface {\n\terror\n\tText() string\n\tArgs() []any\n}\n\nconst (\n\t// commaSeparatorSpace is the comma separator with space.\n\tcommaSeparatorSpace = \", \"\n)\n"
  },
  {
    "path": "errors/gerror/gerror_api.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n)\n\n// New creates and returns an error which is formatted from given text.\nfunc New(text string) error {\n\treturn &Error{\n\t\tstack: callers(),\n\t\ttext:  text,\n\t\tcode:  gcode.CodeNil,\n\t}\n}\n\n// Newf returns an error that formats as the given format and args.\nfunc Newf(format string, args ...any) error {\n\treturn &Error{\n\t\tstack: callers(),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  gcode.CodeNil,\n\t}\n}\n\n// NewSkip creates and returns an error which is formatted from given text.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc NewSkip(skip int, text string) error {\n\treturn &Error{\n\t\tstack: callers(skip),\n\t\ttext:  text,\n\t\tcode:  gcode.CodeNil,\n\t}\n}\n\n// NewSkipf returns an error that formats as the given format and args.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc NewSkipf(skip int, format string, args ...any) error {\n\treturn &Error{\n\t\tstack: callers(skip),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  gcode.CodeNil,\n\t}\n}\n\n// Wrap wraps error with text. It returns nil if given err is nil.\n// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.\nfunc Wrap(err error, text string) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(),\n\t\ttext:  text,\n\t\tcode:  Code(err),\n\t}\n}\n\n// Wrapf returns an error annotating err with a stack trace at the point Wrapf is called, and the format specifier.\n// It returns nil if given `err` is nil.\n// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.\nfunc Wrapf(err error, format string, args ...any) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  Code(err),\n\t}\n}\n\n// WrapSkip wraps error with text. It returns nil if given err is nil.\n// The parameter `skip` specifies the stack callers skipped amount.\n// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.\nfunc WrapSkip(skip int, err error, text string) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(skip),\n\t\ttext:  text,\n\t\tcode:  Code(err),\n\t}\n}\n\n// WrapSkipf wraps error with text that is formatted with given format and args. It returns nil if given err is nil.\n// The parameter `skip` specifies the stack callers skipped amount.\n// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.\nfunc WrapSkipf(skip int, err error, format string, args ...any) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(skip),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  Code(err),\n\t}\n}\n"
  },
  {
    "path": "errors/gerror/gerror_api_code.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n)\n\n// NewCode creates and returns an error that has error code and given text.\nfunc NewCode(code gcode.Code, text ...string) error {\n\treturn &Error{\n\t\tstack: callers(),\n\t\ttext:  strings.Join(text, commaSeparatorSpace),\n\t\tcode:  code,\n\t}\n}\n\n// NewCodef returns an error that has error code and formats as the given format and args.\nfunc NewCodef(code gcode.Code, format string, args ...any) error {\n\treturn &Error{\n\t\tstack: callers(),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  code,\n\t}\n}\n\n// NewCodeSkip creates and returns an error which has error code and is formatted from given text.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc NewCodeSkip(code gcode.Code, skip int, text ...string) error {\n\treturn &Error{\n\t\tstack: callers(skip),\n\t\ttext:  strings.Join(text, commaSeparatorSpace),\n\t\tcode:  code,\n\t}\n}\n\n// NewCodeSkipf returns an error that has error code and formats as the given format and args.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc NewCodeSkipf(code gcode.Code, skip int, format string, args ...any) error {\n\treturn &Error{\n\t\tstack: callers(skip),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  code,\n\t}\n}\n\n// WrapCode wraps error with code and text.\n// It returns nil if given err is nil.\nfunc WrapCode(code gcode.Code, err error, text ...string) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(),\n\t\ttext:  strings.Join(text, commaSeparatorSpace),\n\t\tcode:  code,\n\t}\n}\n\n// WrapCodef wraps error with code and format specifier.\n// It returns nil if given `err` is nil.\nfunc WrapCodef(code gcode.Code, err error, format string, args ...any) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  code,\n\t}\n}\n\n// WrapCodeSkip wraps error with code and text.\n// It returns nil if given err is nil.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(skip),\n\t\ttext:  strings.Join(text, commaSeparatorSpace),\n\t\tcode:  code,\n\t}\n}\n\n// WrapCodeSkipf wraps error with code and text that is formatted with given format and args.\n// It returns nil if given err is nil.\n// The parameter `skip` specifies the stack callers skipped amount.\nfunc WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ...any) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: err,\n\t\tstack: callers(skip),\n\t\ttext:  format,\n\t\targs:  args,\n\t\tcode:  code,\n\t}\n}\n\n// Code returns the error code of `current error`.\n// It returns `CodeNil` if it has no error code neither it does not implement interface Code.\nfunc Code(err error) gcode.Code {\n\tif err == nil {\n\t\treturn gcode.CodeNil\n\t}\n\tif e, ok := err.(ICode); ok {\n\t\treturn e.Code()\n\t}\n\tif e, ok := err.(IUnwrap); ok {\n\t\treturn Code(e.Unwrap())\n\t}\n\treturn gcode.CodeNil\n}\n\n// HasCode checks and reports whether `err` has `code` in its chaining errors.\nfunc HasCode(err error, code gcode.Code) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tif e, ok := err.(ICode); ok && code == e.Code() {\n\t\treturn true\n\t}\n\tif e, ok := err.(IUnwrap); ok {\n\t\treturn HasCode(e.Unwrap(), code)\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "errors/gerror/gerror_api_option.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport \"github.com/gogf/gf/v2/errors/gcode\"\n\n// Option is option for creating error.\ntype Option struct {\n\tError error      // Wrapped error if any.\n\tStack bool       // Whether recording stack information into error.\n\tText  string     // Error text, which is created by New* functions.\n\tArgs  []any      // Error arguments for formatted error text.\n\tCode  gcode.Code // Error code if necessary.\n}\n\n// NewWithOption creates and returns a custom error with Option.\n// It is the senior usage for creating error, which is often used internally in framework.\nfunc NewWithOption(option Option) error {\n\terr := &Error{\n\t\terror: option.Error,\n\t\ttext:  option.Text,\n\t\targs:  option.Args,\n\t\tcode:  option.Code,\n\t}\n\tif option.Stack {\n\t\terr.stack = callers()\n\t}\n\treturn err\n}\n\n// NewOption creates and returns a custom error with Option.\n//\n// Deprecated: use NewWithOption instead.\nfunc NewOption(option Option) error {\n\treturn NewWithOption(option)\n}\n"
  },
  {
    "path": "errors/gerror/gerror_api_stack.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n)\n\n// stack represents a stack of program counters.\ntype stack []uintptr\n\nconst (\n\t// maxStackDepth marks the max stack depth for error back traces.\n\tmaxStackDepth = 64\n)\n\n// Cause returns the root cause error of `err`.\nfunc Cause(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\tif e, ok := err.(ICause); ok {\n\t\treturn e.Cause()\n\t}\n\tif e, ok := err.(IUnwrap); ok {\n\t\treturn Cause(e.Unwrap())\n\t}\n\treturn err\n}\n\n// Stack returns the stack callers as string.\n// It returns the error string directly if the `err` does not support stacks.\nfunc Stack(err error) string {\n\tif err == nil {\n\t\treturn \"\"\n\t}\n\tif e, ok := err.(IStack); ok {\n\t\treturn e.Stack()\n\t}\n\treturn err.Error()\n}\n\n// Current creates and returns the current level error.\n// It returns nil if current level error is nil.\nfunc Current(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\tif e, ok := err.(ICurrent); ok {\n\t\treturn e.Current()\n\t}\n\treturn err\n}\n\n// Unwrap returns the next level error.\n// It returns nil if current level error or the next level error is nil.\nfunc Unwrap(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\tif e, ok := err.(IUnwrap); ok {\n\t\treturn e.Unwrap()\n\t}\n\treturn nil\n}\n\n// HasStack checks and reports whether `err` implemented interface `gerror.IStack`.\nfunc HasStack(err error) bool {\n\t_, ok := err.(IStack)\n\treturn ok\n}\n\n// Equal reports whether current error `err` equals to error `target`.\n// Please note that, in default comparison logic for `Error`,\n// the errors are considered the same if both the `code` and `text` of them are the same.\nfunc Equal(err, target error) bool {\n\tif err == target {\n\t\treturn true\n\t}\n\tif e, ok := err.(IEqual); ok {\n\t\treturn e.Equal(target)\n\t}\n\tif e, ok := target.(IEqual); ok {\n\t\treturn e.Equal(err)\n\t}\n\treturn false\n}\n\n// Is reports whether current error `err` has error `target` in its chaining errors.\n// There's similar function HasError which is designed and implemented early before errors.Is of go stdlib.\n// It is now alias of errors.Is of go stdlib, to guarantee the same performance as go stdlib.\nfunc Is(err, target error) bool {\n\treturn errors.Is(err, target)\n}\n\n// As finds the first error in err's chain that matches target, and if so, sets\n// target to that error value and returns true.\n//\n// The chain consists of err itself followed by the sequence of errors obtained by\n// repeatedly calling Unwrap.\n//\n// An error matches target if the error's concrete value is assignable to the value\n// pointed to by target, or if the error has a method As(any) bool such that\n// As(target) returns true. In the latter case, the As method is responsible for\n// setting target.\n//\n// As will panic if target is not a non-nil pointer to either a type that implements\n// error, or to any interface type. As returns false if err is nil.\nfunc As(err error, target any) bool {\n\treturn errors.As(err, target)\n}\n\n// HasError performs as Is.\n// This function is designed and implemented early before errors.Is of go stdlib.\n//\n// Deprecated: use Is instead.\nfunc HasError(err, target error) bool {\n\treturn errors.Is(err, target)\n}\n\n// callers returns the stack callers.\n// Note that it here just retrieves the caller memory address array not the caller information.\nfunc callers(skip ...int) stack {\n\tvar (\n\t\tpcs [maxStackDepth]uintptr\n\t\tn   = 3\n\t)\n\tif len(skip) > 0 {\n\t\tn += skip[0]\n\t}\n\treturn pcs[:runtime.Callers(n, pcs[:])]\n}\n"
  },
  {
    "path": "errors/gerror/gerror_error.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n)\n\n// Error is custom error for additional features.\ntype Error struct {\n\terror error      // Wrapped error.\n\tstack stack      // Stack array, which records the stack information when this error is created or wrapped.\n\ttext  string     // Custom Error text when Error is created, might be empty when its code is not nil.\n\targs  []any      // Custom arguments for formatting the error text.\n\tcode  gcode.Code // Error code if necessary.\n}\n\nconst (\n\t// Filtering key for current error module paths.\n\tstackFilterKeyLocal = \"/errors/gerror/gerror\"\n)\n\n// goRootForFilter is used for stack filtering in development environment purpose.\nvar goRootForFilter = runtime.GOROOT()\n\nfunc init() {\n\tif goRootForFilter != \"\" {\n\t\tgoRootForFilter = strings.ReplaceAll(goRootForFilter, \"\\\\\", \"/\")\n\t}\n}\n\n// Error implements the interface of Error, it returns all the error as string.\nfunc (err *Error) Error() string {\n\tif err == nil {\n\t\treturn \"\"\n\t}\n\terrStr := err.TextWithArgs()\n\tif errStr == \"\" && err.code != nil {\n\t\terrStr = err.code.Message()\n\t}\n\tif err.error != nil {\n\t\tif errStr != \"\" {\n\t\t\terrStr += \": \"\n\t\t}\n\t\terrStr += err.error.Error()\n\t}\n\treturn errStr\n}\n\n// Cause returns the root cause error.\nfunc (err *Error) Cause() error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\tloop := err\n\tfor loop != nil {\n\t\tif loop.error != nil {\n\t\t\tif e, ok := loop.error.(*Error); ok {\n\t\t\t\t// Internal Error struct.\n\t\t\t\tloop = e\n\t\t\t} else if e, ok := loop.error.(ICause); ok {\n\t\t\t\t// Other Error that implements ApiCause interface.\n\t\t\t\treturn e.Cause()\n\t\t\t} else {\n\t\t\t\treturn loop.error\n\t\t\t}\n\t\t} else {\n\t\t\t// return loop\n\t\t\t//\n\t\t\t// To be compatible with Case of https://github.com/pkg/errors.\n\t\t\treturn errors.New(loop.TextWithArgs())\n\t\t}\n\t}\n\treturn nil\n}\n\n// Current creates and returns the current level error.\n// It returns nil if current level error is nil.\nfunc (err *Error) Current() error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &Error{\n\t\terror: nil,\n\t\tstack: err.stack,\n\t\ttext:  err.text,\n\t\targs:  err.args,\n\t\tcode:  err.code,\n\t}\n}\n\n// Unwrap is alias of function `Next`.\n// It is just for implements for stdlib errors.Unwrap from Go version 1.17.\nfunc (err *Error) Unwrap() error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn err.error\n}\n\n// Equal reports whether current error `err` equals to error `target`.\n// Please note that, in default comparison for `Error`,\n// the errors are considered the same if both the `code` and `text` of them are the same.\nfunc (err *Error) Equal(target error) bool {\n\tif err == target {\n\t\treturn true\n\t}\n\t// Code should be the same.\n\t// Note that if both errors have `nil` code, they are also considered equal.\n\tif err.code != Code(target) {\n\t\treturn false\n\t}\n\t// Text should be the same.\n\tif err.TextWithArgs() != fmt.Sprintf(`%-s`, target) {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// TextWithArgs returns the formatted error text with its arguments.\nfunc (err *Error) TextWithArgs() string {\n\tif len(err.args) > 0 {\n\t\treturn fmt.Sprintf(err.text, err.args...)\n\t}\n\treturn err.text\n}\n\n// Text returns the error text of current error.\nfunc (err *Error) Text() string {\n\treturn err.text\n}\n\n// Args returns the error arguments of current error.\nfunc (err *Error) Args() []any {\n\treturn err.args\n}\n"
  },
  {
    "path": "errors/gerror/gerror_error_code.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n)\n\n// Code returns the error code.\n// It returns CodeNil if it has no error code.\nfunc (err *Error) Code() gcode.Code {\n\tif err == nil {\n\t\treturn gcode.CodeNil\n\t}\n\tif err.code == gcode.CodeNil {\n\t\treturn Code(err.Unwrap())\n\t}\n\treturn err.code\n}\n\n// SetCode updates the internal code with given code.\nfunc (err *Error) SetCode(code gcode.Code) {\n\tif err == nil {\n\t\treturn\n\t}\n\terr.code = code\n}\n"
  },
  {
    "path": "errors/gerror/gerror_error_format.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// Format formats the frame according to the fmt.Formatter interface.\n//\n// %v, %s   : Print all the error string;\n// %-v, %-s : Print current level error string;\n// %+s      : Print full stack error list;\n// %+v      : Print the error string and full stack error list\nfunc (err *Error) Format(s fmt.State, verb rune) {\n\tswitch verb {\n\tcase 's', 'v':\n\t\tswitch {\n\t\tcase s.Flag('-'):\n\t\t\tif err.text != \"\" {\n\t\t\t\t_, _ = io.WriteString(s, err.TextWithArgs())\n\t\t\t} else {\n\t\t\t\t_, _ = io.WriteString(s, err.Error())\n\t\t\t}\n\t\tcase s.Flag('+'):\n\t\t\tif verb == 's' {\n\t\t\t\t_, _ = io.WriteString(s, err.Stack())\n\t\t\t} else {\n\t\t\t\t_, _ = io.WriteString(s, err.Error()+\"\\n\"+err.Stack())\n\t\t\t}\n\t\tdefault:\n\t\t\t_, _ = io.WriteString(s, err.Error())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "errors/gerror/gerror_error_json.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"encoding/json\"\n)\n\n// MarshalJSON implements the interface json.Marshaler for Error.\n// It serializes the error using its string representation.\nfunc (err *Error) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(err.Error())\n}\n"
  },
  {
    "path": "errors/gerror/gerror_error_stack.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror\n\nimport (\n\t\"bytes\"\n\t\"container/list\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/errors\"\n)\n\n// stackInfo manages stack info of certain error.\ntype stackInfo struct {\n\tIndex   int        // Index is the index of current error in whole error stacks.\n\tMessage string     // Error information string.\n\tLines   *list.List // Lines contains all error stack lines of current error stack in sequence.\n}\n\n// stackLine manages each line info of stack.\ntype stackLine struct {\n\tFunction string // Function name, which contains its full package path.\n\tFileLine string // FileLine is the source file name and its line number of Function.\n}\n\n// Stack returns the error stack information as string.\nfunc (err *Error) Stack() string {\n\tif err == nil {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tloop             = err\n\t\tindex            = 1\n\t\tinfos            []*stackInfo\n\t\tisStackModeBrief = errors.IsStackModeBrief()\n\t)\n\tfor loop != nil {\n\t\tinfo := &stackInfo{\n\t\t\tIndex:   index,\n\t\t\tMessage: fmt.Sprintf(\"%-v\", loop),\n\t\t}\n\t\tindex++\n\t\tinfos = append(infos, info)\n\t\tloopLinesOfStackInfo(loop.stack, info, isStackModeBrief)\n\t\tif loop.error != nil {\n\t\t\tif e, ok := loop.error.(*Error); ok {\n\t\t\t\tloop = e\n\t\t\t} else {\n\t\t\t\tinfos = append(infos, &stackInfo{\n\t\t\t\t\tIndex:   index,\n\t\t\t\t\tMessage: loop.error.Error(),\n\t\t\t\t})\n\t\t\t\tindex++\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tfilterLinesOfStackInfos(infos)\n\treturn formatStackInfos(infos)\n}\n\n// filterLinesOfStackInfos removes repeated lines, which exist in subsequent stacks, from top errors.\nfunc filterLinesOfStackInfos(infos []*stackInfo) {\n\tvar (\n\t\tok      bool\n\t\tset     = make(map[string]struct{})\n\t\tinfo    *stackInfo\n\t\tline    *stackLine\n\t\tremoves []*list.Element\n\t)\n\tfor i := len(infos) - 1; i >= 0; i-- {\n\t\tinfo = infos[i]\n\t\tif info.Lines == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfor n, e := 0, info.Lines.Front(); n < info.Lines.Len(); n, e = n+1, e.Next() {\n\t\t\tline = e.Value.(*stackLine)\n\t\t\tif _, ok = set[line.FileLine]; ok {\n\t\t\t\tremoves = append(removes, e)\n\t\t\t} else {\n\t\t\t\tset[line.FileLine] = struct{}{}\n\t\t\t}\n\t\t}\n\t\tif len(removes) > 0 {\n\t\t\tfor _, e := range removes {\n\t\t\t\tinfo.Lines.Remove(e)\n\t\t\t}\n\t\t}\n\t\tremoves = removes[:0]\n\t}\n}\n\n// formatStackInfos formats and returns error stack information as string.\nfunc formatStackInfos(infos []*stackInfo) string {\n\tbuffer := bytes.NewBuffer(nil)\n\tfor i, info := range infos {\n\t\tfmt.Fprintf(buffer, \"%d. %s\\n\", i+1, info.Message)\n\t\tif info.Lines != nil && info.Lines.Len() > 0 {\n\t\t\tformatStackLines(buffer, info.Lines)\n\t\t}\n\t}\n\treturn buffer.String()\n}\n\n// formatStackLines formats and returns error stack lines as string.\nfunc formatStackLines(buffer *bytes.Buffer, lines *list.List) string {\n\tvar (\n\t\tline   *stackLine\n\t\tspace  = \"  \"\n\t\tlength = lines.Len()\n\t)\n\tfor i, e := 0, lines.Front(); i < length; i, e = i+1, e.Next() {\n\t\tline = e.Value.(*stackLine)\n\t\t// Graceful indent.\n\t\tif i >= 9 {\n\t\t\tspace = \" \"\n\t\t}\n\t\tfmt.Fprintf(\n\t\t\tbuffer,\n\t\t\t\"   %d).%s%s\\n        %s\\n\",\n\t\t\ti+1, space, line.Function, line.FileLine,\n\t\t)\n\t}\n\treturn buffer.String()\n}\n\n// loopLinesOfStackInfo iterates the stack info lines and produces the stack line info.\nfunc loopLinesOfStackInfo(st stack, info *stackInfo, isStackModeBrief bool) {\n\tif st == nil {\n\t\treturn\n\t}\n\tfor _, p := range st {\n\t\tif fn := runtime.FuncForPC(p - 1); fn != nil {\n\t\t\tfile, line := fn.FileLine(p - 1)\n\t\t\tif isStackModeBrief {\n\t\t\t\t// filter whole GoFrame packages stack paths.\n\t\t\t\tif strings.Contains(file, consts.StackFilterKeyForGoFrame) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// package path stack filtering.\n\t\t\t\tif strings.Contains(file, stackFilterKeyLocal) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Avoid stack string like \"`autogenerated`\"\n\t\t\tif strings.Contains(file, \"<\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Ignore GO ROOT paths.\n\t\t\tif goRootForFilter != \"\" &&\n\t\t\t\tlen(file) >= len(goRootForFilter) &&\n\t\t\t\tfile[0:len(goRootForFilter)] == goRootForFilter {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif info.Lines == nil {\n\t\t\t\tinfo.Lines = list.New()\n\t\t\t}\n\t\t\tinfo.Lines.PushBack(&stackLine{\n\t\t\t\tFunction: fn.Name(),\n\t\t\t\tFileLine: fmt.Sprintf(`%s:%d`, file, line),\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "errors/gerror/gerror_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\t// base error for benchmark testing of Wrap* functions.\n\tbaseError = errors.New(\"test\")\n)\n\nfunc Benchmark_New(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.New(\"test\")\n\t}\n}\n\nfunc Benchmark_Newf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.Newf(\"%s\", \"test\")\n\t}\n}\n\nfunc Benchmark_Wrap(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.Wrap(baseError, \"test\")\n\t}\n}\n\nfunc Benchmark_Wrapf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.Wrapf(baseError, \"%s\", \"test\")\n\t}\n}\n\nfunc Benchmark_NewSkip(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewSkip(1, \"test\")\n\t}\n}\n\nfunc Benchmark_NewSkipf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewSkipf(1, \"%s\", \"test\")\n\t}\n}\n\nfunc Benchmark_NewCode(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewCode(gcode.New(500, \"\", nil), \"test\")\n\t}\n}\n\nfunc Benchmark_NewCodef(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewCodef(gcode.New(500, \"\", nil), \"%s\", \"test\")\n\t}\n}\n\nfunc Benchmark_NewCodeSkip(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewCodeSkip(gcode.New(1, \"\", nil), 500, \"test\")\n\t}\n}\n\nfunc Benchmark_NewCodeSkipf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.NewCodeSkipf(gcode.New(1, \"\", nil), 500, \"%s\", \"test\")\n\t}\n}\n\nfunc Benchmark_WrapCode(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.WrapCode(gcode.New(500, \"\", nil), baseError, \"test\")\n\t}\n}\n\nfunc Benchmark_WrapCodef(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgerror.WrapCodef(gcode.New(500, \"\", nil), baseError, \"test\")\n\t}\n}\n"
  },
  {
    "path": "errors/gerror/gerror_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nfunc ExampleNewCode() {\n\terr := gerror.NewCode(gcode.New(10000, \"\", nil), \"My Error\")\n\tfmt.Println(err.Error())\n\tfmt.Println(gerror.Code(err))\n\n\t// Output:\n\t// My Error\n\t// 10000\n}\n\nfunc ExampleNewCodef() {\n\terr := gerror.NewCodef(gcode.New(10000, \"\", nil), \"It's %s\", \"My Error\")\n\tfmt.Println(err.Error())\n\tfmt.Println(gerror.Code(err).Code())\n\n\t// Output:\n\t// It's My Error\n\t// 10000\n}\n\nfunc ExampleWrapCode() {\n\terr1 := errors.New(\"permission denied\")\n\terr2 := gerror.WrapCode(gcode.New(10000, \"\", nil), err1, \"Custom Error\")\n\tfmt.Println(err2.Error())\n\tfmt.Println(gerror.Code(err2).Code())\n\n\t// Output:\n\t// Custom Error: permission denied\n\t// 10000\n}\n\nfunc ExampleWrapCodef() {\n\terr1 := errors.New(\"permission denied\")\n\terr2 := gerror.WrapCodef(gcode.New(10000, \"\", nil), err1, \"It's %s\", \"Custom Error\")\n\tfmt.Println(err2.Error())\n\tfmt.Println(gerror.Code(err2).Code())\n\n\t// Output:\n\t// It's Custom Error: permission denied\n\t// 10000\n}\n\nfunc ExampleEqual() {\n\terr1 := errors.New(\"permission denied\")\n\terr2 := gerror.New(\"permission denied\")\n\terr3 := gerror.NewCode(gcode.CodeNotAuthorized, \"permission denied\")\n\tfmt.Println(gerror.Equal(err1, err2))\n\tfmt.Println(gerror.Equal(err2, err3))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIs() {\n\terr1 := errors.New(\"permission denied\")\n\terr2 := gerror.Wrap(err1, \"operation failed\")\n\tfmt.Println(gerror.Is(err1, err1))\n\tfmt.Println(gerror.Is(err2, err2))\n\tfmt.Println(gerror.Is(err2, err1))\n\tfmt.Println(gerror.Is(err1, err2))\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// false\n}\n\nfunc ExampleCode() {\n\terr1 := gerror.NewCode(gcode.CodeInternalError, \"permission denied\")\n\terr2 := gerror.Wrap(err1, \"operation failed\")\n\tfmt.Println(gerror.Code(err1))\n\tfmt.Println(gerror.Code(err2))\n\n\t// Output:\n\t// 50:Internal Error\n\t// 50:Internal Error\n}\n\nfunc ExampleHasCode() {\n\terr1 := gerror.NewCode(gcode.CodeInternalError, \"permission denied\")\n\terr2 := gerror.Wrap(err1, \"operation failed\")\n\tfmt.Println(gerror.HasCode(err1, gcode.CodeOK))\n\tfmt.Println(gerror.HasCode(err2, gcode.CodeInternalError))\n\n\t// Output:\n\t// false\n\t// true\n}\n"
  },
  {
    "path": "errors/gerror/gerror_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gerror_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// customError is used to test As function\ntype customError struct {\n\tMessage string\n}\n\nfunc (e *customError) Error() string {\n\treturn e.Message\n}\n\n// anotherError is used to test As function with different error type\ntype anotherError struct{}\n\nfunc (e *anotherError) Error() string {\n\treturn \"another error\"\n}\n\n// customCauseError implements ICause interface\ntype customCauseError struct {\n\tmsg   string\n\tcause error\n}\n\nfunc (e *customCauseError) Error() string { return e.msg }\nfunc (e *customCauseError) Cause() error  { return e.cause }\n\n// customStackError implements IStack interface\ntype customStackError struct {\n\tmsg   string\n\tstack string\n}\n\nfunc (e *customStackError) Error() string { return e.msg }\nfunc (e *customStackError) Stack() string { return e.stack }\n\n// customCurrentError implements ICurrent interface\ntype customCurrentError struct {\n\tmsg     string\n\tcurrent error\n}\n\nfunc (e *customCurrentError) Error() string  { return e.msg }\nfunc (e *customCurrentError) Current() error { return e.current }\n\n// customUnwrapError implements IUnwrap interface\ntype customUnwrapError struct {\n\tmsg    string\n\tunwrap error\n}\n\nfunc (e *customUnwrapError) Error() string { return e.msg }\nfunc (e *customUnwrapError) Unwrap() error { return e.unwrap }\n\n// customEqualError implements IEqual interface\ntype customEqualError struct {\n\tmsg string\n}\n\nfunc (e *customEqualError) Error() string { return e.msg }\nfunc (e *customEqualError) Equal(target error) bool {\n\tif target == nil {\n\t\treturn false\n\t}\n\treturn e.msg == target.Error()\n}\n\n// customCodeError implements ICode interface\ntype customCodeError struct {\n\tmsg  string\n\tcode gcode.Code\n}\n\nfunc (e *customCodeError) Error() string    { return e.msg }\nfunc (e *customCodeError) Code() gcode.Code { return e.code }\n\nfunc nilError() error {\n\treturn nil\n}\n\nfunc Test_Nil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.New(\"\"), nil)\n\t\tt.Assert(gerror.Wrap(nilError(), \"test\"), nil)\n\t})\n}\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.Newf(\"%d\", 1)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewSkip(1, \"1\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewSkipf(1, \"%d\", 1)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n}\n\nfunc Test_Wrap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n}\n\nfunc Test_Wrapf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrapf(err, \"%d\", 2)\n\t\terr = gerror.Wrapf(err, \"%d\", 3)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrapf(err, \"%d\", 2)\n\t\terr = gerror.Wrapf(err, \"%d\", 3)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrapf(err, \"\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.Wrapf(nil, \"\"), nil)\n\t})\n}\n\nfunc Test_WrapSkip(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapSkip(1, nil, \"2\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.WrapSkip(1, err, \"2\")\n\t\terr = gerror.WrapSkip(1, err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.WrapSkip(1, err, \"2\")\n\t\terr = gerror.WrapSkip(1, err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.WrapSkip(1, err, \"\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n}\n\nfunc Test_WrapSkipf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapSkipf(1, nil, \"2\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.WrapSkipf(1, err, \"2\")\n\t\terr = gerror.WrapSkipf(1, err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.WrapSkipf(1, err, \"2\")\n\t\terr = gerror.WrapSkipf(1, err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.WrapSkipf(1, err, \"\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"1\")\n\t})\n}\n\nfunc Test_Cause(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.Cause(nil), nil)\n\t\terr := errors.New(\"1\")\n\t\tt.Assert(gerror.Cause(err), err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.Assert(gerror.Cause(err), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\tt.Assert(gerror.Cause(err), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.Assert(gerror.Cause(err), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.Stack(nil), \"\")\n\t\terr := errors.New(\"1\")\n\t\tt.Assert(gerror.Stack(err), err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e *gerror.Error = nil\n\t\tt.Assert(e.Cause(), nil)\n\t})\n}\n\nfunc Test_Format(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(fmt.Sprintf(\"%s\", err), \"3: 2: 1\")\n\t\tt.Assert(fmt.Sprintf(\"%v\", err), \"3: 2: 1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(fmt.Sprintf(\"%s\", err), \"3: 2: 1\")\n\t\tt.Assert(fmt.Sprintf(\"%v\", err), \"3: 2: 1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(fmt.Sprintf(\"%-s\", err), \"3\")\n\t\tt.Assert(fmt.Sprintf(\"%-v\", err), \"3\")\n\t})\n}\n\nfunc Test_Stack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\tt.Assert(fmt.Sprintf(\"%+v\", err), \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\t// fmt.Printf(\"%+v\", err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\tt.AssertNE(fmt.Sprintf(\"%+v\", err), \"1\")\n\t\t// fmt.Printf(\"%+v\", err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.AssertNE(err, nil)\n\t\t// fmt.Printf(\"%+v\", err)\n\t})\n}\n\nfunc Test_Current(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.Current(nil), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t\tt.Assert(gerror.Current(err).Error(), \"3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e *gerror.Error = nil\n\t\tt.Assert(e.Current(), nil)\n\t})\n}\n\nfunc Test_Unwrap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.Unwrap(nil), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.Wrap(err, \"3\")\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\n\t\terr = gerror.Unwrap(err)\n\t\tt.Assert(err.Error(), \"2: 1\")\n\n\t\terr = gerror.Unwrap(err)\n\t\tt.Assert(err.Error(), \"1\")\n\n\t\terr = gerror.Unwrap(err)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e *gerror.Error = nil\n\t\tt.Assert(e.Unwrap(), nil)\n\t})\n}\n\nfunc Test_Code(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := errors.New(\"123\")\n\t\tt.Assert(gerror.Code(err), -1)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewCode(gcode.CodeUnknown, \"123\")\n\t\tt.Assert(gerror.Code(err), gcode.CodeUnknown)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewCodef(gcode.New(1, \"\", nil), \"%s\", \"123\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewCodeSkip(gcode.New(1, \"\", nil), 0, \"123\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.NewCodeSkipf(gcode.New(1, \"\", nil), 0, \"%s\", \"123\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapCode(gcode.New(1, \"\", nil), nil, \"3\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.WrapCode(gcode.New(1, \"\", nil), err, \"3\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapCodef(gcode.New(1, \"\", nil), nil, \"%s\", \"3\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.WrapCodef(gcode.New(1, \"\", nil), err, \"%s\", \"3\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapCodeSkip(gcode.New(1, \"\", nil), 100, nil, \"3\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.WrapCodeSkip(gcode.New(1, \"\", nil), 100, err, \"3\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.WrapCodeSkipf(gcode.New(1, \"\", nil), 100, nil, \"%s\", \"3\"), nil)\n\t\terr := errors.New(\"1\")\n\t\terr = gerror.Wrap(err, \"2\")\n\t\terr = gerror.WrapCodeSkipf(gcode.New(1, \"\", nil), 100, err, \"%s\", \"3\")\n\t\tt.Assert(gerror.Code(err).Code(), 1)\n\t\tt.Assert(err.Error(), \"3: 2: 1\")\n\t})\n}\n\nfunc TestError_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e *gerror.Error = nil\n\t\tt.Assert(e.Error(), nil)\n\t})\n}\n\nfunc TestError_Code(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e *gerror.Error = nil\n\t\tt.Assert(e.Code(), gcode.CodeNil)\n\t})\n}\n\nfunc Test_SetCode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"123\")\n\t\tt.Assert(gerror.Code(err), -1)\n\t\tt.Assert(err.Error(), \"123\")\n\n\t\terr.(*gerror.Error).SetCode(gcode.CodeValidationFailed)\n\t\tt.Assert(gerror.Code(err), gcode.CodeValidationFailed)\n\t\tt.Assert(err.Error(), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err *gerror.Error = nil\n\t\terr.SetCode(gcode.CodeValidationFailed)\n\t})\n}\n\nfunc Test_Json(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.Wrap(gerror.New(\"1\"), \"2\")\n\t\tb, e := json.Marshal(err)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(string(b), `\"2: 1\"`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrNormal := gerror.New(\"test\")\n\t\tb, e := json.Marshal(errNormal)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(string(b), `\"test\"`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// The string contains special characters.\n\t\terrWithSign := gerror.New(`test \"\"`)\n\t\tb, e := json.Marshal(errWithSign)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(string(b), `\"test \\\"\\\"\"`)\n\t})\n}\n\nfunc Test_HasStack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := errors.New(\"1\")\n\t\terr2 := gerror.New(\"1\")\n\t\tt.Assert(gerror.HasStack(err1), false)\n\t\tt.Assert(gerror.HasStack(err2), true)\n\t})\n}\n\nfunc Test_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := errors.New(\"1\")\n\t\terr2 := errors.New(\"1\")\n\t\terr3 := gerror.New(\"1\")\n\t\terr4 := gerror.New(\"4\")\n\t\tt.Assert(gerror.Equal(err1, err2), false)\n\t\tt.Assert(gerror.Equal(err1, err3), true)\n\t\tt.Assert(gerror.Equal(err2, err3), true)\n\t\tt.Assert(gerror.Equal(err3, err4), false)\n\t\tt.Assert(gerror.Equal(err1, err4), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar e = new(gerror.Error)\n\t\tt.Assert(e.Equal(e), true)\n\t})\n}\n\nfunc Test_Is(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := errors.New(\"1\")\n\t\terr2 := gerror.Wrap(err1, \"2\")\n\t\terr2 = gerror.Wrap(err2, \"3\")\n\t\tt.Assert(gerror.Is(err2, err1), true)\n\n\t\tvar (\n\t\t\terrNotFound = errors.New(\"not found\")\n\t\t\tgerror1     = gerror.Wrap(errNotFound, \"wrapped\")\n\t\t\tgerror2     = gerror.New(\"not found\")\n\t\t)\n\t\tt.Assert(errors.Is(errNotFound, errNotFound), true)\n\t\tt.Assert(errors.Is(nil, errNotFound), false)\n\t\tt.Assert(errors.Is(nil, nil), true)\n\n\t\tt.Assert(gerror.Is(errNotFound, errNotFound), true)\n\t\tt.Assert(gerror.Is(nil, errNotFound), false)\n\t\tt.Assert(gerror.Is(nil, nil), true)\n\n\t\tt.Assert(errors.Is(gerror1, errNotFound), true)\n\t\tt.Assert(errors.Is(gerror2, errNotFound), false)\n\t\tt.Assert(gerror.Is(gerror1, errNotFound), true)\n\t\tt.Assert(gerror.Is(gerror2, errNotFound), false)\n\t})\n}\n\nfunc Test_HasError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := errors.New(\"1\")\n\t\terr2 := gerror.Wrap(err1, \"2\")\n\t\terr2 = gerror.Wrap(err2, \"3\")\n\t\tt.Assert(gerror.HasError(err2, err1), true)\n\t})\n}\n\nfunc Test_HasCode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gerror.HasCode(nil, gcode.CodeNotAuthorized), false)\n\t\terr1 := errors.New(\"1\")\n\t\terr2 := gerror.WrapCode(gcode.CodeNotAuthorized, err1, \"2\")\n\t\terr3 := gerror.Wrap(err2, \"3\")\n\t\terr4 := gerror.Wrap(err3, \"4\")\n\t\terr5 := gerror.WrapCode(gcode.CodeInvalidParameter, err4, \"5\")\n\t\tt.Assert(gerror.HasCode(err1, gcode.CodeNotAuthorized), false)\n\t\tt.Assert(gerror.HasCode(err2, gcode.CodeNotAuthorized), true)\n\t\tt.Assert(gerror.HasCode(err3, gcode.CodeNotAuthorized), true)\n\t\tt.Assert(gerror.HasCode(err4, gcode.CodeNotAuthorized), true)\n\t\tt.Assert(gerror.HasCode(err5, gcode.CodeNotAuthorized), true)\n\t\tt.Assert(gerror.HasCode(err5, gcode.CodeInvalidParameter), true)\n\t\tt.Assert(gerror.HasCode(err5, gcode.CodeInternalError), false)\n\t})\n}\n\nfunc Test_NewOption(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(gerror.NewWithOption(gerror.Option{\n\t\t\tError: errors.New(\"NewOptionError\"),\n\t\t\tStack: true,\n\t\t\tText:  \"Text\",\n\t\t\tCode:  gcode.CodeNotAuthorized,\n\t\t}), gerror.New(\"NewOptionError\"))\n\t})\n}\n\nfunc Test_As(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar myerr = &customError{Message: \"custom error\"}\n\n\t\t// Test with nil error\n\t\tvar targetErr *customError\n\t\tt.Assert(gerror.As(nil, &targetErr), false)\n\t\tt.Assert(targetErr, nil)\n\n\t\t// Test with standard error\n\t\terr1 := errors.New(\"standard error\")\n\t\tt.Assert(gerror.As(err1, &targetErr), false)\n\t\tt.Assert(targetErr, nil)\n\n\t\t// Test with custom error type\n\t\terr2 := myerr\n\t\tt.Assert(gerror.As(err2, &targetErr), true)\n\t\tt.Assert(targetErr.Message, \"custom error\")\n\n\t\t// Test with wrapped error\n\t\terr3 := gerror.Wrap(myerr, \"wrapped\")\n\t\ttargetErr = nil\n\t\tt.Assert(gerror.As(err3, &targetErr), true)\n\t\tt.Assert(targetErr.Message, \"custom error\")\n\n\t\t// Test with deeply wrapped error\n\t\terr4 := gerror.Wrap(gerror.Wrap(gerror.Wrap(myerr, \"wrap3\"), \"wrap2\"), \"wrap1\")\n\t\ttargetErr = nil\n\t\tt.Assert(gerror.As(err4, &targetErr), true)\n\t\tt.Assert(targetErr.Message, \"custom error\")\n\n\t\t// Test with different error type\n\t\tvar otherErr *anotherError\n\t\tt.Assert(gerror.As(err4, &otherErr), false)\n\t\tt.Assert(otherErr, nil)\n\n\t\t// Test with non-pointer target\n\t\tdefer func() {\n\t\t\tt.Assert(recover() != nil, true)\n\t\t}()\n\t\tvar nonPtr customError\n\t\tgerror.As(err4, nonPtr)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with nil target\n\t\tdefer func() {\n\t\t\tt.Assert(recover() != nil, true)\n\t\t}()\n\t\tgerror.As(errors.New(\"error\"), nil)\n\t})\n}\n\nfunc Test_NewOption_Deprecated(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test deprecated NewOption function\n\t\terr := gerror.NewOption(gerror.Option{\n\t\t\tError: errors.New(\"base error\"),\n\t\t\tStack: true,\n\t\t\tText:  \"option text\",\n\t\t\tCode:  gcode.CodeInternalError,\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gerror.Code(err), gcode.CodeInternalError)\n\t})\n}\n\nfunc Test_Code_WithIUnwrap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Code() with custom error that implements IUnwrap but not ICode\n\t\tinnerErr := gerror.NewCode(gcode.CodeInternalError, \"inner error\")\n\t\tunwrapErr := &customUnwrapError{msg: \"unwrap error\", unwrap: innerErr}\n\t\tt.Assert(gerror.Code(unwrapErr), gcode.CodeInternalError)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Code() with nil\n\t\tt.Assert(gerror.Code(nil), gcode.CodeNil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Code() with custom error that implements ICode\n\t\tcodeErr := &customCodeError{msg: \"code error\", code: gcode.CodeNotFound}\n\t\tt.Assert(gerror.Code(codeErr), gcode.CodeNotFound)\n\t})\n}\n\nfunc Test_Cause_WithIUnwrap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Cause() with custom error that implements IUnwrap but not ICause\n\t\trootErr := errors.New(\"root error\")\n\t\tunwrapErr := &customUnwrapError{msg: \"unwrap error\", unwrap: rootErr}\n\t\tt.Assert(gerror.Cause(unwrapErr), rootErr)\n\t})\n}\n\nfunc Test_Cause_WithICause(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Cause() with custom error that implements ICause\n\t\trootErr := errors.New(\"root error\")\n\t\tcauseErr := &customCauseError{msg: \"cause error\", cause: rootErr}\n\t\tt.Assert(gerror.Cause(causeErr), rootErr)\n\t})\n}\n\nfunc Test_Stack_WithIStack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Stack() with custom error that implements IStack\n\t\tstackErr := &customStackError{msg: \"stack error\", stack: \"custom stack trace\"}\n\t\tt.Assert(gerror.Stack(stackErr), \"custom stack trace\")\n\t})\n}\n\nfunc Test_Current_WithICurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Current() with custom error that implements ICurrent\n\t\tcurrentErr := errors.New(\"current error\")\n\t\tcustomErr := &customCurrentError{msg: \"custom error\", current: currentErr}\n\t\tt.Assert(gerror.Current(customErr), currentErr)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Current() with standard error (does not implement ICurrent)\n\t\tstdErr := errors.New(\"standard error\")\n\t\tt.Assert(gerror.Current(stdErr), stdErr)\n\t})\n}\n\nfunc Test_Equal_WithIEqual(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Equal() when target implements IEqual\n\t\terr1 := errors.New(\"test error\")\n\t\terr2 := &customEqualError{msg: \"test error\"}\n\t\tt.Assert(gerror.Equal(err1, err2), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Equal() when both are the same\n\t\terr := errors.New(\"test error\")\n\t\tt.Assert(gerror.Equal(err, err), true)\n\t})\n}\n\nfunc Test_Error_Cause_WithICause(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Error.Cause() when inner error implements ICause\n\t\trootErr := errors.New(\"root\")\n\t\tcauseErr := &customCauseError{msg: \"cause\", cause: rootErr}\n\t\twrappedErr := gerror.Wrap(causeErr, \"wrapped\")\n\t\tt.Assert(gerror.Cause(wrappedErr), rootErr)\n\t})\n}\n\nfunc Test_Error_WithCodeMessage(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Error.Error() when text is empty but code has message\n\t\terr := gerror.NewCode(gcode.CodeInternalError)\n\t\tt.Assert(err.Error(), \"Internal Error\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test Error.Error() when text is empty and code has message, with wrapped error\n\t\tinnerErr := errors.New(\"inner\")\n\t\terr := gerror.WrapCode(gcode.CodeInternalError, innerErr)\n\t\tt.Assert(err.Error(), \"Internal Error: inner\")\n\t})\n}\n\nfunc Test_Format_PlusS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test %+s format (stack only)\n\t\terr := gerror.New(\"test error\")\n\t\tstackStr := fmt.Sprintf(\"%+s\", err)\n\t\tt.Assert(len(stackStr) > 0, true)\n\t\tt.AssertNE(stackStr, \"test error\")\n\t})\n}\n\nfunc Test_Format_MinusS_EmptyText(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test %-s format when text is empty but code has message\n\t\terr := gerror.NewCode(gcode.CodeInternalError)\n\t\tresult := fmt.Sprintf(\"%-s\", err)\n\t\tt.Assert(result, \"Internal Error\")\n\t})\n}\n\nfunc Test_Stack_DeepNested(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test deeply nested errors stack\n\t\terr := gerror.New(\"level1\")\n\t\tfor i := 2; i <= 5; i++ {\n\t\t\terr = gerror.Wrap(err, fmt.Sprintf(\"level%d\", i))\n\t\t}\n\t\tstack := gerror.Stack(err)\n\t\tt.Assert(len(stack) > 0, true)\n\t})\n}\n\nfunc Test_Stack_NilError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err *gerror.Error = nil\n\t\tt.Assert(err.Stack(), \"\")\n\t})\n}\n\nfunc Test_Stack_WithStandardError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test stack with wrapped standard error\n\t\tstdErr := errors.New(\"standard error\")\n\t\terr := gerror.Wrap(stdErr, \"wrapped\")\n\t\tstack := gerror.Stack(err)\n\t\tt.Assert(len(stack) > 0, true)\n\t})\n}\n\nfunc Test_NewCode_MultipleTexts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test NewCode with multiple text arguments\n\t\terr := gerror.NewCode(gcode.CodeInternalError, \"text1\", \"text2\", \"text3\")\n\t\tt.Assert(err.Error(), \"text1, text2, text3\")\n\t})\n}\n\nfunc Test_NewCodeSkip_MultipleTexts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test NewCodeSkip with multiple text arguments\n\t\terr := gerror.NewCodeSkip(gcode.CodeInternalError, 0, \"text1\", \"text2\")\n\t\tt.Assert(err.Error(), \"text1, text2\")\n\t})\n}\n\nfunc Test_WrapCode_MultipleTexts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test WrapCode with multiple text arguments\n\t\tinnerErr := errors.New(\"inner\")\n\t\terr := gerror.WrapCode(gcode.CodeInternalError, innerErr, \"text1\", \"text2\")\n\t\tt.Assert(err.Error(), \"text1, text2: inner\")\n\t})\n}\n\nfunc Test_WrapCodeSkip_MultipleTexts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test WrapCodeSkip with multiple text arguments\n\t\tinnerErr := errors.New(\"inner\")\n\t\terr := gerror.WrapCodeSkip(gcode.CodeInternalError, 0, innerErr, \"text1\", \"text2\")\n\t\tt.Assert(err.Error(), \"text1, text2: inner\")\n\t})\n}\n\nfunc Test_TextArgs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.New(\"text\")\n\t\ttextArgs := err.(gerror.ITextArgs)\n\t\tt.Assert(textArgs.Text(), \"text\")\n\t\tt.Assert(textArgs.Args(), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gerror.Newf(\"text: %s\", \"arg1\")\n\t\ttextArgs := err.(gerror.ITextArgs)\n\t\tt.Assert(textArgs.Text(), \"text: %s\")\n\t\tt.Assert(textArgs.Args(), []any{\"arg1\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr1 := errors.New(\"text\")\n\t\terr2 := gerror.Wrapf(err1, \"wrap: %s\", \"arg1\")\n\t\ttextArgs := err2.(gerror.ITextArgs)\n\t\tt.Assert(textArgs.Error(), \"wrap: arg1: text\")\n\t\tt.Assert(textArgs.Text(), \"wrap: %s\")\n\t\tt.Assert(textArgs.Args(), []any{\"arg1\"})\n\t})\n}\n"
  },
  {
    "path": "frame/g/g.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package g provides commonly used type/function defines and coupled calling for creating commonly-used objects.\n//\n// Note that, using package g might make the compiled binary a little bit bigger, as it imports a few frequently-used\n// packages whatever you use them or not.\npackage g\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\ntype (\n\tVar  = gvar.Var        // Var is a universal variable interface, like generics.\n\tCtx  = context.Context // Ctx is alias of frequently-used type context.Context.\n\tMeta = gmeta.Meta      // Meta is alias of frequently-used type gmeta.Meta.\n)\n\ntype (\n\tMap        = map[string]any    // Map is alias of frequently-used map type map[string]any.\n\tMapAnyAny  = map[any]any       // MapAnyAny is alias of frequently-used map type map[any]any.\n\tMapAnyStr  = map[any]string    // MapAnyStr is alias of frequently-used map type map[any]string.\n\tMapAnyInt  = map[any]int       // MapAnyInt is alias of frequently-used map type map[any]int.\n\tMapStrAny  = map[string]any    // MapStrAny is alias of frequently-used map type map[string]any.\n\tMapStrStr  = map[string]string // MapStrStr is alias of frequently-used map type map[string]string.\n\tMapStrInt  = map[string]int    // MapStrInt is alias of frequently-used map type map[string]int.\n\tMapIntAny  = map[int]any       // MapIntAny is alias of frequently-used map type map[int]any.\n\tMapIntStr  = map[int]string    // MapIntStr is alias of frequently-used map type map[int]string.\n\tMapIntInt  = map[int]int       // MapIntInt is alias of frequently-used map type map[int]int.\n\tMapAnyBool = map[any]bool      // MapAnyBool is alias of frequently-used map type map[any]bool.\n\tMapStrBool = map[string]bool   // MapStrBool is alias of frequently-used map type map[string]bool.\n\tMapIntBool = map[int]bool      // MapIntBool is alias of frequently-used map type map[int]bool.\n)\n\ntype (\n\tList        = []Map        // List is alias of frequently-used slice type []Map.\n\tListAnyAny  = []MapAnyAny  // ListAnyAny is alias of frequently-used slice type []MapAnyAny.\n\tListAnyStr  = []MapAnyStr  // ListAnyStr is alias of frequently-used slice type []MapAnyStr.\n\tListAnyInt  = []MapAnyInt  // ListAnyInt is alias of frequently-used slice type []MapAnyInt.\n\tListStrAny  = []MapStrAny  // ListStrAny is alias of frequently-used slice type []MapStrAny.\n\tListStrStr  = []MapStrStr  // ListStrStr is alias of frequently-used slice type []MapStrStr.\n\tListStrInt  = []MapStrInt  // ListStrInt is alias of frequently-used slice type []MapStrInt.\n\tListIntAny  = []MapIntAny  // ListIntAny is alias of frequently-used slice type []MapIntAny.\n\tListIntStr  = []MapIntStr  // ListIntStr is alias of frequently-used slice type []MapIntStr.\n\tListIntInt  = []MapIntInt  // ListIntInt is alias of frequently-used slice type []MapIntInt.\n\tListAnyBool = []MapAnyBool // ListAnyBool is alias of frequently-used slice type []MapAnyBool.\n\tListStrBool = []MapStrBool // ListStrBool is alias of frequently-used slice type []MapStrBool.\n\tListIntBool = []MapIntBool // ListIntBool is alias of frequently-used slice type []MapIntBool.\n)\n\ntype (\n\tSlice    = []any    // Slice is alias of frequently-used slice type []any.\n\tSliceAny = []any    // SliceAny is alias of frequently-used slice type []any.\n\tSliceStr = []string // SliceStr is alias of frequently-used slice type []string.\n\tSliceInt = []int    // SliceInt is alias of frequently-used slice type []int.\n)\n\ntype (\n\tArray    = []any    // Array is alias of frequently-used slice type []any.\n\tArrayAny = []any    // ArrayAny is alias of frequently-used slice type []any.\n\tArrayStr = []string // ArrayStr is alias of frequently-used slice type []string.\n\tArrayInt = []int    // ArrayInt is alias of frequently-used slice type []int.\n)\n"
  },
  {
    "path": "frame/g/g_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage g\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Go creates a new asynchronous goroutine function with specified recover function.\n//\n// The parameter `recoverFunc` is called when any panic during executing of `goroutineFunc`.\n// If `recoverFunc` is given nil, it ignores the panic from `goroutineFunc` and no panic will\n// throw to parent goroutine.\n//\n// But, note that, if `recoverFunc` also throws panic, such panic will be thrown to parent goroutine.\nfunc Go(\n\tctx context.Context,\n\tgoroutineFunc func(ctx context.Context),\n\trecoverFunc func(ctx context.Context, exception error),\n) {\n\tgutil.Go(ctx, goroutineFunc, recoverFunc)\n}\n\n// NewVar returns a gvar.Var.\nfunc NewVar(i any, safe ...bool) *Var {\n\treturn gvar.New(i, safe...)\n}\n\n// Wait is an alias of ghttp.Wait, which blocks until all the web servers shutdown.\n// It's commonly used in multiple servers' situation.\nfunc Wait() {\n\tghttp.Wait()\n}\n\n// Listen is an alias of gproc.Listen, which handles the signals received and automatically\n// calls registered signal handler functions.\n// It blocks until shutdown signals received and all registered shutdown handlers done.\nfunc Listen() {\n\tgproc.Listen()\n}\n\n// Dump dumps a variable to stdout with more manually readable.\nfunc Dump(values ...any) {\n\tgutil.Dump(values...)\n}\n\n// DumpTo writes variables `values` as a string in to `writer` with more manually readable\nfunc DumpTo(writer io.Writer, value any, option gutil.DumpOption) {\n\tgutil.DumpTo(writer, value, option)\n}\n\n// DumpWithType acts like Dump, but with type information.\n// Also see Dump.\nfunc DumpWithType(values ...any) {\n\tgutil.DumpWithType(values...)\n}\n\n// DumpWithOption returns variables `values` as a string with more manually readable.\nfunc DumpWithOption(value any, option gutil.DumpOption) {\n\tgutil.DumpWithOption(value, option)\n}\n\n// DumpJson pretty dumps json content to stdout.\nfunc DumpJson(value any) {\n\tgutil.DumpJson(value)\n}\n\n// Throw throws an exception, which can be caught by TryCatch function.\nfunc Throw(exception any) {\n\tgutil.Throw(exception)\n}\n\n// Try implements try... logistics using internal panic...recover.\n// It returns error if any exception occurs, or else it returns nil.\nfunc Try(ctx context.Context, try func(ctx context.Context)) (err error) {\n\treturn gutil.Try(ctx, try)\n}\n\n// TryCatch implements try...catch... logistics using internal panic...recover.\n// It automatically calls function `catch` if any exception occurs and passes the exception as an error.\n//\n// But, note that, if function `catch` also throws panic, the current goroutine will panic.\nfunc TryCatch(ctx context.Context, try func(ctx context.Context), catch func(ctx context.Context, exception error)) {\n\tgutil.TryCatch(ctx, try, catch)\n}\n\n// IsNil checks whether given `value` is nil.\n// Parameter `traceSource` is used for tracing to the source variable if given `value` is type\n// of pointer that also points to a pointer. It returns nil if the source is nil when `traceSource`\n// is true.\n// Note that it might use reflect feature which affects performance a little.\nfunc IsNil(value any, traceSource ...bool) bool {\n\treturn empty.IsNil(value, traceSource...)\n}\n\n// IsEmpty checks whether given `value` empty.\n// It returns true if `value` is in: 0, nil, false, \"\", len(slice/map/chan) == 0.\n// Or else it returns true.\n//\n// The parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer\n// that also points to a pointer. It returns true if the source is empty when `traceSource` is true.\n// Note that it might use reflect feature which affects performance a little.\nfunc IsEmpty(value any, traceSource ...bool) bool {\n\treturn empty.IsEmpty(value, traceSource...)\n}\n\n// RequestFromCtx retrieves and returns the Request object from context.\nfunc RequestFromCtx(ctx context.Context) *ghttp.Request {\n\treturn ghttp.RequestFromCtx(ctx)\n}\n"
  },
  {
    "path": "frame/g/g_object.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage g\n\nimport (\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/net/gudp\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\n// Client is a convenience function, which creates and returns a new HTTP client.\nfunc Client() *gclient.Client {\n\treturn gclient.New()\n}\n\n// Server returns an instance of http server with specified name.\nfunc Server(name ...any) *ghttp.Server {\n\treturn gins.Server(name...)\n}\n\n// TCPServer returns an instance of tcp server with specified name.\nfunc TCPServer(name ...any) *gtcp.Server {\n\treturn gtcp.GetServer(name...)\n}\n\n// UDPServer returns an instance of udp server with specified name.\nfunc UDPServer(name ...any) *gudp.Server {\n\treturn gudp.GetServer(name...)\n}\n\n// View returns an instance of template engine object with specified name.\nfunc View(name ...string) *gview.View {\n\treturn gins.View(name...)\n}\n\n// Config returns an instance of config object with specified name.\nfunc Config(name ...string) *gcfg.Config {\n\treturn gins.Config(name...)\n}\n\n// Cfg is alias of Config.\n// See Config.\nfunc Cfg(name ...string) *gcfg.Config {\n\treturn Config(name...)\n}\n\n// Resource returns an instance of Resource.\n// The parameter `name` is the name for the instance.\nfunc Resource(name ...string) *gres.Resource {\n\treturn gins.Resource(name...)\n}\n\n// I18n returns an instance of gi18n.Manager.\n// The parameter `name` is the name for the instance.\nfunc I18n(name ...string) *gi18n.Manager {\n\treturn gins.I18n(name...)\n}\n\n// Res is alias of Resource.\n// See Resource.\nfunc Res(name ...string) *gres.Resource {\n\treturn Resource(name...)\n}\n\n// Log returns an instance of glog.Logger.\n// The parameter `name` is the name for the instance.\nfunc Log(name ...string) *glog.Logger {\n\treturn gins.Log(name...)\n}\n\n// DB returns an instance of database ORM object with specified configuration group name.\nfunc DB(name ...string) gdb.DB {\n\treturn gins.Database(name...)\n}\n\n// Model creates and returns a model based on configuration of default database group.\nfunc Model(tableNameOrStruct ...any) *gdb.Model {\n\treturn DB().Model(tableNameOrStruct...)\n}\n\n// ModelRaw creates and returns a model based on a raw sql not a table.\nfunc ModelRaw(rawSql string, args ...any) *gdb.Model {\n\treturn DB().Raw(rawSql, args...)\n}\n\n// Redis returns an instance of redis client with specified configuration group name.\nfunc Redis(name ...string) *gredis.Redis {\n\treturn gins.Redis(name...)\n}\n\n// Validator is a convenience function, which creates and returns a new validation manager object.\nfunc Validator() *gvalid.Validator {\n\treturn gvalid.New()\n}\n"
  },
  {
    "path": "frame/g/g_setting.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage g\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// SetDebug enables/disables the GoFrame internal logging manually.\n// Note that this function is not concurrent safe, be aware of the DATA RACE,\n// which means you should call this function in your boot but not the runtime.\nfunc SetDebug(enabled bool) {\n\tutils.SetDebugEnabled(enabled)\n}\n"
  },
  {
    "path": "frame/g/g_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage g_test\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n)\n\nfunc ExampleServer() {\n\t// A hello world example.\n\ts := g.Server()\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello world\")\n\t})\n\ts.SetPort(8999)\n\ts.Run()\n}\n"
  },
  {
    "path": "frame/g/g_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage g_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_NewVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.NewVar(1).Int(), 1)\n\t\tt.Assert(g.NewVar(1, true).Int(), 1)\n\t})\n}\n\nfunc Test_Dump(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.Dump(\"GoFrame\")\n\t})\n}\n\nfunc Test_DumpTo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.DumpTo(os.Stdout, \"GoFrame\", gutil.DumpOption{})\n\t})\n}\n\nfunc Test_DumpWithType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.DumpWithType(\"GoFrame\", 123)\n\t})\n}\n\nfunc Test_DumpWithOption(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.DumpWithOption(\"GoFrame\", gutil.DumpOption{})\n\t})\n}\n\nfunc Test_Try(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.Try(ctx, func(ctx context.Context) {\n\t\t\tg.Dump(\"GoFrame\")\n\t\t})\n\t})\n}\n\nfunc Test_TryCatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.TryCatch(ctx, func(ctx context.Context) {\n\t\t\tg.Dump(\"GoFrame\")\n\t\t}, func(ctx context.Context, exception error) {\n\t\t\tg.Dump(exception)\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.TryCatch(ctx, func(ctx context.Context) {\n\t\t\tg.Throw(\"GoFrame\")\n\t\t}, func(ctx context.Context, exception error) {\n\t\t\tt.Assert(exception.Error(), \"GoFrame\")\n\t\t})\n\t})\n}\n\nfunc Test_IsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.IsNil(nil), true)\n\t\tt.Assert(g.IsNil(0), false)\n\t\tt.Assert(g.IsNil(\"GoFrame\"), false)\n\t})\n}\n\nfunc Test_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.IsEmpty(nil), true)\n\t\tt.Assert(g.IsEmpty(0), true)\n\t\tt.Assert(g.IsEmpty(\"GoFrame\"), false)\n\t})\n}\n\nfunc Test_SetDebug(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tg.SetDebug(true)\n\t})\n}\n\nfunc Test_Object(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(g.Client(), nil)\n\t\tt.AssertNE(g.Server(), nil)\n\t\tt.AssertNE(g.TCPServer(), nil)\n\t\tt.AssertNE(g.UDPServer(), nil)\n\t\tt.AssertNE(g.View(), nil)\n\t\tt.AssertNE(g.Config(), nil)\n\t\tt.AssertNE(g.Cfg(), nil)\n\t\tt.AssertNE(g.Resource(), nil)\n\t\tt.AssertNE(g.I18n(), nil)\n\t\tt.AssertNE(g.Res(), nil)\n\t\tt.AssertNE(g.Log(), nil)\n\t\tt.AssertNE(g.Validator(), nil)\n\t})\n}\n\nfunc Test_Go(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t)\n\t\twg.Add(1)\n\t\tg.Go(context.Background(), func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tarray.Append(1)\n\t\t}, nil)\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n"
  },
  {
    "path": "frame/gins/gins.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gins provides instances and core components management.\npackage gins\n\nconst (\n\tframeCoreComponentNameViewer     = \"gf.core.component.viewer\"\n\tframeCoreComponentNameDatabase   = \"gf.core.component.database\"\n\tframeCoreComponentNameHttpClient = \"gf.core.component.httpclient\"\n\tframeCoreComponentNameLogger     = \"gf.core.component.logger\"\n\tframeCoreComponentNameRedis      = \"gf.core.component.redis\"\n\tframeCoreComponentNameServer     = \"gf.core.component.server\"\n)\n"
  },
  {
    "path": "frame/gins/gins_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n)\n\n// Config returns an instance of View with default settings.\n// The parameter `name` is the name for the instance.\nfunc Config(name ...string) *gcfg.Config {\n\treturn gcfg.Instance(name...)\n}\n"
  },
  {
    "path": "frame/gins/gins_database.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gdb\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Database returns an instance of database ORM object with specified configuration group name.\n// Note that it panics if any error occurs duration instance creating.\nfunc Database(name ...string) gdb.DB {\n\tvar (\n\t\tctx   = context.Background()\n\t\tgroup = gdb.DefaultGroupName\n\t)\n\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tgroup = name[0]\n\t}\n\tinstanceKey := fmt.Sprintf(\"%s.%s\", frameCoreComponentNameDatabase, group)\n\tdb := instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\t// It ignores returned error to avoid file no found error while it's not necessary.\n\t\tvar (\n\t\t\tconfigMap     map[string]any\n\t\t\tconfigNodeKey = consts.ConfigNodeNameDatabase\n\t\t)\n\t\t// It firstly searches the configuration of the instance name.\n\t\tif configData, _ := Config().Data(ctx); len(configData) > 0 {\n\t\t\tif v, _ := gutil.MapPossibleItemByKey(configData, consts.ConfigNodeNameDatabase); v != \"\" {\n\t\t\t\tconfigNodeKey = v\n\t\t\t}\n\t\t}\n\t\tif v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {\n\t\t\tconfigMap = v.Map()\n\t\t}\n\t\t// No configuration found, it formats and panics error.\n\t\tif len(configMap) == 0 && !gdb.IsConfigured() {\n\t\t\t// File configuration object checks.\n\t\t\tvar err error\n\t\t\tif fileConfig, ok := Config().GetAdapter().(*gcfg.AdapterFile); ok {\n\t\t\t\tif _, err = fileConfig.GetFilePath(); err != nil {\n\t\t\t\t\tpanic(gerror.WrapCode(gcode.CodeMissingConfiguration, err,\n\t\t\t\t\t\t`configuration not found, did you miss the configuration file or misspell the configuration file name`,\n\t\t\t\t\t))\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Panic if nothing found in Config object or in gdb configuration.\n\t\t\tif len(configMap) == 0 && !gdb.IsConfigured() {\n\t\t\t\tpanic(gerror.NewCodef(\n\t\t\t\t\tgcode.CodeMissingConfiguration,\n\t\t\t\t\t`database initialization failed: configuration missing for database node \"%s\"`,\n\t\t\t\t\tconsts.ConfigNodeNameDatabase,\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\n\t\tif len(configMap) == 0 {\n\t\t\tconfigMap = make(map[string]any)\n\t\t}\n\t\t// Parse `m` as map-slice and adds it to global configurations for package gdb.\n\t\tfor g, groupConfig := range configMap {\n\t\t\tcg := gdb.ConfigGroup{}\n\t\t\tswitch value := groupConfig.(type) {\n\t\t\tcase []any:\n\t\t\t\tfor _, v := range value {\n\t\t\t\t\tif node := parseDBConfigNode(v); node != nil {\n\t\t\t\t\t\tcg = append(cg, *node)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase map[string]any:\n\t\t\t\tif node := parseDBConfigNode(value); node != nil {\n\t\t\t\t\tcg = append(cg, *node)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(cg) > 0 {\n\t\t\t\tif gcg, _ := gdb.GetConfigGroup(group); gcg == nil {\n\t\t\t\t\tintlog.Printf(ctx, \"add configuration for group: %s, %#v\", g, cg)\n\t\t\t\t\tif err := gdb.SetConfigGroup(g, cg); err != nil {\n\t\t\t\t\t\tpanic(err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tintlog.Printf(ctx, \"ignore configuration as it already exists for group: %s, %#v\", g, cg)\n\t\t\t\t\tintlog.Printf(ctx, \"%s, %#v\", g, cg)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Parse `m` as a single node configuration,\n\t\t// which is the default group configuration.\n\t\tif node := parseDBConfigNode(configMap); node != nil {\n\t\t\tcg := gdb.ConfigGroup{}\n\t\t\tif node.Link != \"\" || node.Host != \"\" {\n\t\t\t\tcg = append(cg, *node)\n\t\t\t}\n\t\t\tif len(cg) > 0 {\n\t\t\t\tif gcg, _ := gdb.GetConfigGroup(group); gcg == nil {\n\t\t\t\t\tintlog.Printf(ctx, \"add configuration for group: %s, %#v\", gdb.DefaultGroupName, cg)\n\t\t\t\t\tif err := gdb.SetConfigGroup(gdb.DefaultGroupName, cg); err != nil {\n\t\t\t\t\t\tpanic(err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\"ignore configuration as it already exists for group: %s, %#v\",\n\t\t\t\t\t\tgdb.DefaultGroupName, cg,\n\t\t\t\t\t)\n\t\t\t\t\tintlog.Printf(ctx, \"%s, %#v\", gdb.DefaultGroupName, cg)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Create a new ORM object with given configurations.\n\t\tif db, err := gdb.NewByGroup(name...); err == nil {\n\t\t\t// Initialize logger for ORM.\n\t\t\tvar (\n\t\t\t\tloggerConfigMap map[string]any\n\t\t\t\tloggerNodeName  = fmt.Sprintf(\"%s.%s\", configNodeKey, consts.ConfigNodeNameLogger)\n\t\t\t)\n\t\t\tif v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {\n\t\t\t\tloggerConfigMap = v.Map()\n\t\t\t}\n\t\t\tif len(loggerConfigMap) == 0 {\n\t\t\t\tif v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {\n\t\t\t\t\tloggerConfigMap = v.Map()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(loggerConfigMap) > 0 {\n\t\t\t\tif logger, ok := db.GetLogger().(*glog.Logger); ok {\n\t\t\t\t\tif err = logger.SetConfigWithMap(loggerConfigMap); err != nil {\n\t\t\t\t\t\tpanic(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn db\n\t\t} else {\n\t\t\t// If panics, often because it does not find its configuration for given group.\n\t\t\tpanic(err)\n\t\t}\n\t})\n\tif db != nil {\n\t\treturn db.(gdb.DB)\n\t}\n\treturn nil\n}\n\nfunc parseDBConfigNode(value any) *gdb.ConfigNode {\n\tnodeMap, ok := value.(map[string]any)\n\tif !ok {\n\t\treturn nil\n\t}\n\tvar (\n\t\tnode = &gdb.ConfigNode{}\n\t\terr  = gconv.Struct(nodeMap, node)\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// Find possible `Link` configuration content.\n\tif _, v := gutil.MapPossibleItemByKey(nodeMap, \"Link\"); v != nil {\n\t\tnode.Link = gconv.String(v)\n\t}\n\treturn node\n}\n"
  },
  {
    "path": "frame/gins/gins_httpclient.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n)\n\n// HttpClient returns an instance of http client with specified name.\nfunc HttpClient(name ...any) *gclient.Client {\n\tvar instanceKey = fmt.Sprintf(\"%s.%v\", frameCoreComponentNameHttpClient, name)\n\treturn instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\treturn gclient.New()\n\t}).(*gclient.Client)\n}\n"
  },
  {
    "path": "frame/gins/gins_i18n.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n)\n\n// I18n returns an instance of gi18n.Manager.\n// The parameter `name` is the name for the instance.\nfunc I18n(name ...string) *gi18n.Manager {\n\treturn gi18n.Instance(name...)\n}\n"
  },
  {
    "path": "frame/gins/gins_log.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Log returns an instance of glog.Logger.\n// The parameter `name` is the name for the instance.\n// Note that it panics if any error occurs duration instance creating.\nfunc Log(name ...string) *glog.Logger {\n\tvar (\n\t\tctx          = context.Background()\n\t\tinstanceName = glog.DefaultName\n\t)\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tinstanceName = name[0]\n\t}\n\tinstanceKey := fmt.Sprintf(\"%s.%s\", frameCoreComponentNameLogger, instanceName)\n\treturn instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\tlogger := glog.Instance(instanceName)\n\t\t// To avoid file no found error while it's not necessary.\n\t\tvar (\n\t\t\tconfigMap      map[string]any\n\t\t\tloggerNodeName = consts.ConfigNodeNameLogger\n\t\t)\n\t\t// Try to find possible `loggerNodeName` in case-insensitive way.\n\t\tif configData, _ := Config().Data(ctx); len(configData) > 0 {\n\t\t\tif v, _ := gutil.MapPossibleItemByKey(configData, consts.ConfigNodeNameLogger); v != \"\" {\n\t\t\t\tloggerNodeName = v\n\t\t\t}\n\t\t}\n\t\t// Retrieve certain logger configuration by logger name.\n\t\tcertainLoggerNodeName := fmt.Sprintf(`%s.%s`, loggerNodeName, instanceName)\n\t\tif v, _ := Config().Get(ctx, certainLoggerNodeName); !v.IsEmpty() {\n\t\t\tconfigMap = v.Map()\n\t\t}\n\t\t// Retrieve global logger configuration if configuration for certain logger name does not exist.\n\t\tif len(configMap) == 0 {\n\t\t\tif v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {\n\t\t\t\tconfigMap = v.Map()\n\t\t\t}\n\t\t}\n\t\t// Set logger config if config map is not empty.\n\t\tif len(configMap) > 0 {\n\t\t\tif err := logger.SetConfigWithMap(configMap); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t\treturn logger\n\t}).(*glog.Logger)\n}\n"
  },
  {
    "path": "frame/gins/gins_redis.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Redis returns an instance of redis client with specified configuration group name.\n// Note that it panics if any error occurs duration instance creating.\nfunc Redis(name ...string) *gredis.Redis {\n\tvar (\n\t\terr   error\n\t\tctx   = context.Background()\n\t\tgroup = gredis.DefaultGroupName\n\t)\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tgroup = name[0]\n\t}\n\tinstanceKey := fmt.Sprintf(\"%s.%s\", frameCoreComponentNameRedis, group)\n\tresult := instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\t// If already configured, it returns the redis instance.\n\t\tif _, ok := gredis.GetConfig(group); ok {\n\t\t\treturn gredis.Instance(group)\n\t\t}\n\t\tif Config().Available(ctx) {\n\t\t\tvar (\n\t\t\t\tconfigMap   map[string]any\n\t\t\t\tredisConfig *gredis.Config\n\t\t\t\tredisClient *gredis.Redis\n\t\t\t)\n\t\t\tif configMap, err = Config().Data(ctx); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)\n\t\t\t}\n\t\t\tif _, v := gutil.MapPossibleItemByKey(configMap, consts.ConfigNodeNameRedis); v != nil {\n\t\t\t\tconfigMap = gconv.Map(v)\n\t\t\t}\n\t\t\tif len(configMap) > 0 {\n\t\t\t\tif v, ok := configMap[group]; ok {\n\t\t\t\t\tif redisConfig, err = gredis.ConfigFromMap(gconv.Map(v)); err != nil {\n\t\t\t\t\t\tpanic(err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tintlog.Printf(ctx, `missing configuration for redis group \"%s\"`, group)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tintlog.Print(ctx, `missing configuration for redis: \"redis\" node not found`)\n\t\t\t}\n\t\t\tif redisClient, err = gredis.New(redisConfig); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\treturn redisClient\n\t\t}\n\t\tpanic(gerror.NewCode(\n\t\t\tgcode.CodeMissingConfiguration,\n\t\t\t`no configuration found for creating redis client`,\n\t\t))\n\t})\n\tif result != nil {\n\t\treturn result.(*gredis.Redis)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "frame/gins/gins_resource.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gres\"\n)\n\n// Resource returns an instance of Resource.\n// The parameter `name` is the name for the instance.\nfunc Resource(name ...string) *gres.Resource {\n\treturn gres.Instance(name...)\n}\n"
  },
  {
    "path": "frame/gins/gins_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Server returns an instance of http server with specified name.\n// Note that it panics if any error occurs duration instance creating.\nfunc Server(name ...any) *ghttp.Server {\n\tvar (\n\t\terr          error\n\t\tctx          = context.Background()\n\t\tinstanceName = ghttp.DefaultServerName\n\t\tinstanceKey  = fmt.Sprintf(\"%s.%v\", frameCoreComponentNameServer, name)\n\t)\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tinstanceName = gconv.String(name[0])\n\t}\n\treturn instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\tserver := ghttp.GetServer(instanceName)\n\t\tif Config().Available(ctx) {\n\t\t\t// Server initialization from configuration.\n\t\t\tvar (\n\t\t\t\tconfigMap             map[string]any\n\t\t\t\tserverConfigMap       map[string]any\n\t\t\t\tserverLoggerConfigMap map[string]any\n\t\t\t\tconfigNodeName        string\n\t\t\t)\n\t\t\tif configMap, err = Config().Data(ctx); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)\n\t\t\t}\n\t\t\t// Find possible server configuration item by possible names.\n\t\t\tif len(configMap) > 0 {\n\t\t\t\tif v, _ := gutil.MapPossibleItemByKey(configMap, consts.ConfigNodeNameServer); v != \"\" {\n\t\t\t\t\tconfigNodeName = v\n\t\t\t\t}\n\t\t\t\tif configNodeName == \"\" {\n\t\t\t\t\tif v, _ := gutil.MapPossibleItemByKey(configMap, consts.ConfigNodeNameServerSecondary); v != \"\" {\n\t\t\t\t\t\tconfigNodeName = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Automatically retrieve configuration by instance name.\n\t\t\tserverConfigMap = Config().MustGet(\n\t\t\t\tctx,\n\t\t\t\tfmt.Sprintf(`%s.%s`, configNodeName, instanceName),\n\t\t\t).Map()\n\t\t\tif len(serverConfigMap) == 0 {\n\t\t\t\tserverConfigMap = Config().MustGet(ctx, configNodeName).Map()\n\t\t\t}\n\t\t\tif len(serverConfigMap) > 0 {\n\t\t\t\tif err = server.SetConfigWithMap(serverConfigMap); err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// The configuration is not necessary, so it just prints internal logs.\n\t\t\t\tintlog.Printf(\n\t\t\t\t\tctx,\n\t\t\t\t\t`missing configuration from configuration component for HTTP server \"%s\"`,\n\t\t\t\t\tinstanceName,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// Server logger configuration checks.\n\t\t\tserverLoggerConfigMap = Config().MustGet(\n\t\t\t\tctx,\n\t\t\t\tfmt.Sprintf(`%s.%s.%s`, configNodeName, instanceName, consts.ConfigNodeNameLogger),\n\t\t\t).Map()\n\t\t\tif len(serverLoggerConfigMap) == 0 && len(serverConfigMap) > 0 {\n\t\t\t\tserverLoggerConfigMap = gconv.Map(serverConfigMap[consts.ConfigNodeNameLogger])\n\t\t\t}\n\t\t\tif len(serverLoggerConfigMap) > 0 {\n\t\t\t\tif err = server.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// The server name is necessary. It sets a default server name is it is not configured.\n\t\tif server.GetName() == \"\" || server.GetName() == ghttp.DefaultServerName {\n\t\t\tserver.SetName(instanceName)\n\t\t}\n\t\t// As it might use template feature,\n\t\t// it initializes the view instance as well.\n\t\t_ = getViewInstance()\n\t\treturn server\n\t}).(*ghttp.Server)\n}\n"
  },
  {
    "path": "frame/gins/gins_view.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// View returns an instance of View with default settings.\n// The parameter `name` is the name for the instance.\n// Note that it panics if any error occurs duration instance creating.\nfunc View(name ...string) *gview.View {\n\tinstanceName := gview.DefaultName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tinstanceName = name[0]\n\t}\n\tinstanceKey := fmt.Sprintf(\"%s.%s\", frameCoreComponentNameViewer, instanceName)\n\treturn instance.GetOrSetFuncLock(instanceKey, func() any {\n\t\treturn getViewInstance(instanceName)\n\t}).(*gview.View)\n}\n\nfunc getViewInstance(name ...string) *gview.View {\n\tvar (\n\t\terr          error\n\t\tctx          = context.Background()\n\t\tinstanceName = gview.DefaultName\n\t)\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tinstanceName = name[0]\n\t}\n\tview := gview.Instance(instanceName)\n\tif Config().Available(ctx) {\n\t\tvar (\n\t\t\tconfigMap      map[string]any\n\t\t\tconfigNodeName = consts.ConfigNodeNameViewer\n\t\t)\n\t\tif configMap, err = Config().Data(ctx); err != nil {\n\t\t\tintlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)\n\t\t}\n\t\tif len(configMap) > 0 {\n\t\t\tif v, _ := gutil.MapPossibleItemByKey(configMap, consts.ConfigNodeNameViewer); v != \"\" {\n\t\t\t\tconfigNodeName = v\n\t\t\t}\n\t\t}\n\t\tconfigMap = Config().MustGet(ctx, fmt.Sprintf(`%s.%s`, configNodeName, instanceName)).Map()\n\t\tif len(configMap) == 0 {\n\t\t\tconfigMap = Config().MustGet(ctx, configNodeName).Map()\n\t\t}\n\t\tif len(configMap) > 0 {\n\t\t\tif err = view.SetConfigWithMap(configMap); err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t}\n\treturn view\n}\n"
  },
  {
    "path": "frame/gins/gins_z_unit_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tctx           = context.Background()\n\tconfigContent = gfile.GetContents(\n\t\tgtest.DataPath(\"config\", \"config.toml\"),\n\t)\n)\n\nfunc Test_Config1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(configContent, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(gins.Config(), nil)\n\t})\n}\n\nfunc Test_Config2(t *testing.T) {\n\t// relative path\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"config.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), configContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\n\t\tt.Assert(gins.Config().MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\t// for gfsnotify callbacks to refresh cache of config file\n\ttime.Sleep(500 * time.Millisecond)\n\n\t// relative path, config folder\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.AssertNil(gfile.Mkdir(dirPath))\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"config/config.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), configContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\n\t\tt.Assert(gins.Config().MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\n\t\t// for gfsnotify callbacks to refresh cache of config file\n\t\ttime.Sleep(500 * time.Millisecond)\n\t})\n}\n\nfunc Test_Config3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"test.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), configContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).Clear()\n\t\tgins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).SetFileName(\"test.toml\")\n\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\t// for gfsnotify callbacks to refresh cache of config file\n\ttime.Sleep(500 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"config/test.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), configContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).Clear()\n\t\tgins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).SetFileName(\"test.toml\")\n\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\t// for gfsnotify callbacks to refresh cache of config file for next unit testing case.\n\ttime.Sleep(500 * time.Millisecond)\n}\n\nfunc Test_Config4(t *testing.T) {\n\t// absolute path\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := fmt.Sprintf(`%s/%d`, gfile.Temp(), gtime.TimestampNano())\n\t\tfile := fmt.Sprintf(`%s/%s`, path, \"config.toml\")\n\t\terr := gfile.PutContents(file, configContent)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(file)\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\n\t\tt.Assert(gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)\n\t\tt.Assert(gins.Config().MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\ttime.Sleep(500 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := fmt.Sprintf(`%s/%d/config`, gfile.Temp(), gtime.TimestampNano())\n\t\tfile := fmt.Sprintf(`%s/%s`, path, \"config.toml\")\n\t\terr := gfile.PutContents(file, configContent)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(file)\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\t\tt.Assert(gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)\n\t\tt.Assert(gins.Config().MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config().MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\ttime.Sleep(500 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := fmt.Sprintf(`%s/%d`, gfile.Temp(), gtime.TimestampNano())\n\t\tfile := fmt.Sprintf(`%s/%s`, path, \"test.toml\")\n\t\terr := gfile.PutContents(file, configContent)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(file)\n\t\tdefer gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).Clear()\n\t\tgins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).SetFileName(\"test.toml\")\n\t\tt.Assert(gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n\ttime.Sleep(500 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := fmt.Sprintf(`%s/%d/config`, gfile.Temp(), gtime.TimestampNano())\n\t\tfile := fmt.Sprintf(`%s/%s`, path, \"test.toml\")\n\t\terr := gfile.PutContents(file, configContent)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(file)\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\t\tgins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).SetFileName(\"test.toml\")\n\t\tt.Assert(gins.Config(\"test\").GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"test\"), \"v=1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"database.default.1.host\"), \"127.0.0.1\")\n\t\tt.Assert(gins.Config(\"test\").MustGet(ctx, \"redis.disk\"), `{\"address\":\"127.0.0.1:6379\",\"db\":1}`)\n\t})\n}\n\nfunc Test_Basic2(t *testing.T) {\n\tconfig := `log-path = \"logs\"`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath = gcfg.DefaultConfigFileName\n\t\t\terr  = gfile.PutContents(path, config)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer func() {\n\t\t\t_ = gfile.Remove(path)\n\t\t}()\n\n\t\tt.Assert(gins.Config().MustGet(ctx, \"log-path\"), \"logs\")\n\t})\n}\n"
  },
  {
    "path": "frame/gins/gins_z_unit_database_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Database(t *testing.T) {\n\tdatabaseContent := gfile.GetContents(\n\t\tgtest.DataPath(\"database\", \"config.toml\"),\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tdirPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\tname := \"config.toml\"\n\t\terr = gfile.PutContents(gfile.Join(dirPath, name), databaseContent)\n\t\tt.AssertNil(err)\n\n\t\terr = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tdefer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()\n\n\t\t// for gfsnotify callbacks to refresh cache of config file\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\t// fmt.Println(\"gins Test_Database\", Config().Get(\"test\"))\n\t\tvar (\n\t\t\tdb        = gins.Database()\n\t\t\tdbDefault = gins.Database(\"default\")\n\t\t)\n\t\tt.AssertNE(db, nil)\n\t\tt.AssertNE(dbDefault, nil)\n\n\t\tt.Assert(db.PingMaster(), nil)\n\t\tt.Assert(db.PingSlave(), nil)\n\t\tt.Assert(dbDefault.PingMaster(), nil)\n\t\tt.Assert(dbDefault.PingSlave(), nil)\n\t})\n}\n"
  },
  {
    "path": "frame/gins/gins_z_unit_httpclient_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Client(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tc  = gins.HttpClient()\n\t\t\tc1 = gins.HttpClient(\"c1\")\n\t\t\tc2 = gins.HttpClient(\"c2\")\n\t\t)\n\t\tc.SetAgent(\"test1\")\n\t\tc.SetAgent(\"test2\")\n\t\tt.AssertNE(fmt.Sprintf(`%p`, c), fmt.Sprintf(`%p`, c1))\n\t\tt.AssertNE(fmt.Sprintf(`%p`, c), fmt.Sprintf(`%p`, c2))\n\t\tt.AssertNE(fmt.Sprintf(`%p`, c1), fmt.Sprintf(`%p`, c2))\n\t})\n}\n"
  },
  {
    "path": "frame/gins/gins_z_unit_server_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/gins\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Server(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath                = gcfg.DefaultConfigFileName\n\t\t\tserverConfigContent = gtest.DataContent(\"server\", \"config.yaml\")\n\t\t\terr                 = gfile.PutContents(path, serverConfigContent)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tinstance.Clear()\n\t\tdefer instance.Clear()\n\n\t\ts := gins.Server(\"tempByInstanceName\")\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"hello\")\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := gins.HttpClient()\n\t\tclient.SetPrefix(prefix)\n\t\tt.Assert(client.GetContent(gctx.New(), \"/\"), \"hello\")\n\t})\n}\n"
  },
  {
    "path": "frame/gins/gins_z_unit_view_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_View(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(View(), nil)\n\t\tb, e := View().ParseContent(context.TODO(), `{{\"我是中国人\" | substr 2 -1}}`, nil)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(b, \"中国\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttpl := \"t.tpl\"\n\t\terr := gfile.PutContents(tpl, `{{\"我是中国人\" | substr 2 -1}}`)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tpl)\n\n\t\tb, e := View().Parse(context.TODO(), \"t.tpl\", nil)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(b, \"中国\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := fmt.Sprintf(`%s/%d`, gfile.Temp(), gtime.TimestampNano())\n\t\ttpl := fmt.Sprintf(`%s/%s`, path, \"t.tpl\")\n\t\terr := gfile.PutContents(tpl, `{{\"我是中国人\" | substr 2 -1}}`)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(tpl)\n\t\terr = View().AddPath(path)\n\t\tt.AssertNil(err)\n\n\t\tb, e := View().Parse(context.TODO(), \"t.tpl\", nil)\n\t\tt.Assert(e, nil)\n\t\tt.Assert(b, \"中国\")\n\t})\n}\n\nfunc Test_View_Config(t *testing.T) {\n\tvar ctx = context.TODO()\n\t// view1 test1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdirPath := gtest.DataPath(\"view1\")\n\t\tConfig().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, \"config.toml\")))\n\t\tdefer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tdefer instance.Clear()\n\n\t\tview := View(\"test1\")\n\t\tt.AssertNE(view, nil)\n\t\terr := view.AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello ${.name},version:${.version}`\n\t\tview.Assigns(map[string]any{\"version\": \"1.9.0\"})\n\t\tresult, err := view.ParseContent(ctx, str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello test1,version:1.9.0\")\n\n\t\tresult, err = view.ParseDefault(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"test1:test1\")\n\t})\n\t// view1 test2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdirPath := gtest.DataPath(\"view1\")\n\t\tConfig().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, \"config.toml\")))\n\t\tdefer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tdefer instance.Clear()\n\n\t\tview := View(\"test2\")\n\t\tt.AssertNE(view, nil)\n\t\terr := view.AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello #{.name},version:#{.version}`\n\t\tview.Assigns(map[string]any{\"version\": \"1.9.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello test2,version:1.9.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"test2:test2\")\n\t})\n\t// view2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdirPath := gtest.DataPath(\"view2\")\n\t\tConfig().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, \"config.toml\")))\n\t\tdefer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tdefer instance.Clear()\n\n\t\tview := View()\n\t\tt.AssertNE(view, nil)\n\t\terr := view.AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello {.name},version:{.version}`\n\t\tview.Assigns(map[string]any{\"version\": \"1.9.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello test,version:1.9.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"test:test\")\n\t})\n\t// view2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdirPath := gtest.DataPath(\"view2\")\n\t\tConfig().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, \"config.toml\")))\n\t\tdefer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tdefer instance.Clear()\n\n\t\tview := View(\"test100\")\n\t\tt.AssertNE(view, nil)\n\t\terr := view.AddPath(dirPath)\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello {.name},version:{.version}`\n\t\tview.Assigns(map[string]any{\"version\": \"1.9.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello test,version:1.9.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"test:test\")\n\t})\n}\n"
  },
  {
    "path": "frame/gins/testdata/config/config.toml",
    "content": "# 模板引擎目录\nviewpath = \"/home/www/templates/\"\ntest = \"v=1\"\n# MySQL数据库配置\n[database]\n    [[database.default]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n    [[database.default]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"8692651\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n# Redis数据库配置\n[redis]\n    [redis.disk]\n        address = \"127.0.0.1:6379\"\n        db      = 1\n    [redis.cache]\n        address = \"127.0.0.1:6379\"\n        db      = 1"
  },
  {
    "path": "frame/gins/testdata/database/config.toml",
    "content": "# 模板引擎目录\nviewpath = \"/home/www/templates/\"\ntest = \"v=2\"\n# MySQL数据库配置\n[database]\n    [[database.default]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"default\"\n        role     = \"master\"\n\t\tweight   = \"1\"\n        charset  = \"utf8\"\n    [[database.test]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"default\"\n        role     = \"master\"\n\t\tweight   = \"1\"\n        charset  = \"utf8\"\n# Redis数据库配置\n[redis]\n    [redis.default]\n        address = \"127.0.0.1:6379\"\n        db      = 1\n    [redis.cache]\n        address = \"127.0.0.1:6379\"\n        db      = 1"
  },
  {
    "path": "frame/gins/testdata/redis/config.toml",
    "content": "# 模板引擎目录\nviewpath = \"/home/www/templates/\"\ntest = \"v=3\"\n# MySQL数据库配置\n[database]\n    [[database.default]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"\"\n        # pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n    [[database.test]]\n        host     = \"127.0.0.1\"\n        port     = \"3306\"\n        user     = \"root\"\n        pass     = \"\"\n        # pass     = \"12345678\"\n        name     = \"test\"\n        type     = \"mysql\"\n        role     = \"master\"\n        charset  = \"utf8\"\n        priority = \"1\"\n# Redis数据库配置\n[redis]\n    [redis.default]\n        address = \"127.0.0.1:6379\"\n        db      = 7\n    [redis.cache]\n        address = \"127.0.0.1:6379\"\n        db      = 8\n    [redis.disk]\n        address         = \"127.0.0.1:6379\"\n        db              = 9\n        maxIdle         = 1\n        maxActive       = 10\n        idleTimeout     = \"10s\"\n        maxConnLifetime = \"10s\"\n\n"
  },
  {
    "path": "frame/gins/testdata/server/config.yaml",
    "content": "server:\n  address: \":8000\"\n  tempByInstanceName:\n    accessLogEnabled: false"
  },
  {
    "path": "frame/gins/testdata/view1/config.toml",
    "content": "\n\n[viewer]\n    [viewer.test1]\n        defaultFile = \"test1.html\"\n        delimiters  = [\"${\", \"}\"]\n        [viewer.test1.data]\n            name = \"test1\"\n    [viewer.test2]\n        defaultFile = \"test2.html\"\n        delimiters  = [\"#{\", \"}\"]\n        [viewer.test2.data]\n            name = \"test2\"\n\n"
  },
  {
    "path": "frame/gins/testdata/view1/test1.html",
    "content": "test1:${.name}"
  },
  {
    "path": "frame/gins/testdata/view1/test2.html",
    "content": "test2:#{.name}"
  },
  {
    "path": "frame/gins/testdata/view2/config.toml",
    "content": "\n\n[viewer]\n    defaultFile = \"test.html\"\n    delimiters  = [\"{\", \"}\"]\n    [viewer.data]\n        name = \"test\"\n\n"
  },
  {
    "path": "frame/gins/testdata/view2/test.html",
    "content": "test:{.name}"
  },
  {
    "path": "go.mod",
    "content": "module github.com/gogf/gf/v2\n\ngo 1.23.0\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.5.0\n\tgithub.com/clbanning/mxj/v2 v2.7.0\n\tgithub.com/emirpasic/gods/v2 v2.0.0-alpha\n\tgithub.com/fatih/color v1.18.0\n\tgithub.com/fsnotify/fsnotify v1.9.0\n\tgithub.com/gorilla/websocket v1.5.3\n\tgithub.com/grokify/html-strip-tags-go v0.1.0\n\tgithub.com/magiconair/properties v1.8.10\n\tgithub.com/olekukonko/tablewriter v1.1.0\n\tgo.opentelemetry.io/otel v1.38.0\n\tgo.opentelemetry.io/otel/sdk v1.38.0\n\tgo.opentelemetry.io/otel/trace v1.38.0\n\tgolang.org/x/net v0.40.0\n\tgolang.org/x/text v0.25.0\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.16 // indirect\n\tgithub.com/olekukonko/errors v1.1.0 // indirect\n\tgithub.com/olekukonko/ll v0.0.9 // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.38.0 // indirect\n\tgolang.org/x/sys v0.35.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=\ngithub.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=\ngithub.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=\ngithub.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=\ngithub.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=\ngithub.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=\ngithub.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=\ngithub.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=\ngithub.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=\ngithub.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=\ngolang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "i18n/gi18n/gi18n.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gi18n implements internationalization and localization.\npackage gi18n\n\nimport \"context\"\n\n// SetPath sets the directory path storing i18n files.\nfunc SetPath(path string) error {\n\treturn Instance().SetPath(path)\n}\n\n// SetLanguage sets the language for translator.\nfunc SetLanguage(language string) {\n\tInstance().SetLanguage(language)\n}\n\n// SetDelimiters sets the delimiters for translator.\nfunc SetDelimiters(left, right string) {\n\tInstance().SetDelimiters(left, right)\n}\n\n// T is alias of Translate for convenience.\nfunc T(ctx context.Context, content string) string {\n\treturn Instance().T(ctx, content)\n}\n\n// Tf is alias of TranslateFormat for convenience.\nfunc Tf(ctx context.Context, format string, values ...any) string {\n\treturn Instance().TranslateFormat(ctx, format, values...)\n}\n\n// TranslateFormat translates, formats and returns the `format` with configured language\n// and given `values`.\nfunc TranslateFormat(ctx context.Context, format string, values ...any) string {\n\treturn Instance().TranslateFormat(ctx, format, values...)\n}\n\n// Translate translates `content` with configured language and returns the translated content.\nfunc Translate(ctx context.Context, content string) string {\n\treturn Instance().Translate(ctx, content)\n}\n\n// GetContent retrieves and returns the configured content for given key and specified language.\n// It returns an empty string if not found.\nfunc GetContent(ctx context.Context, key string) string {\n\treturn Instance().GetContent(ctx, key)\n}\n"
  },
  {
    "path": "i18n/gi18n/gi18n_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gi18n\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\tctxLanguage gctx.StrKey = \"I18nLanguage\"\n)\n\n// WithLanguage append language setting to the context and returns a new context.\nfunc WithLanguage(ctx context.Context, language string) context.Context {\n\tif ctx == nil {\n\t\tctx = context.TODO()\n\t}\n\treturn context.WithValue(ctx, ctxLanguage, language)\n}\n\n// LanguageFromCtx retrieves and returns language name from context.\n// It returns an empty string if it is not set previously.\nfunc LanguageFromCtx(ctx context.Context) string {\n\tif ctx == nil {\n\t\treturn \"\"\n\t}\n\tv := ctx.Value(ctxLanguage)\n\tif v != nil {\n\t\treturn v.(string)\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "i18n/gi18n/gi18n_instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gi18n\n\nimport \"github.com/gogf/gf/v2/container/gmap\"\n\nconst (\n\t// DefaultName is the default group name for instance usage.\n\tDefaultName = \"default\"\n)\n\nvar (\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *Manager) bool { return v == nil }\n\t// instances is the instances map for management\n\t// for multiple i18n instance by name.\n\tinstances = gmap.NewKVMapWithChecker[string, *Manager](checker, true)\n)\n\n// Instance returns an instance of Resource.\n// The parameter `name` is the name for the instance.\nfunc Instance(name ...string) *Manager {\n\tkey := DefaultName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tkey = name[0]\n\t}\n\treturn instances.GetOrSetFuncLock(key, func() *Manager {\n\t\treturn New()\n\t})\n}\n"
  },
  {
    "path": "i18n/gi18n/gi18n_manager.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gi18n\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// pathType is the type for i18n file path.\ntype pathType string\n\nconst (\n\tpathTypeNone   pathType = \"none\"\n\tpathTypeNormal pathType = \"normal\"\n\tpathTypeGres   pathType = \"gres\"\n)\n\n// Manager for i18n contents, it is concurrent safe, supporting hot reload.\ntype Manager struct {\n\tmu       sync.RWMutex\n\tdata     map[string]map[string]string // Translating map.\n\tpattern  string                       // Pattern for regex parsing.\n\tpathType pathType                     // Path type for i18n files.\n\toptions  Options                      // configuration options.\n}\n\n// Options is used for i18n object configuration.\ntype Options struct {\n\tPath       string         // I18n files storage path.\n\tLanguage   string         // Default local language.\n\tDelimiters []string       // Delimiters for variable parsing.\n\tResource   *gres.Resource // Resource for i18n files.\n}\n\nvar (\n\t// defaultLanguage defines the default language if user does not specify in options.\n\tdefaultLanguage = \"en\"\n\n\t// defaultDelimiters defines the default key variable delimiters.\n\tdefaultDelimiters = []string{\"{#\", \"}\"}\n\n\t// i18n files searching folders.\n\tsearchFolders = []string{\"manifest/i18n\", \"manifest/config/i18n\", \"i18n\"}\n)\n\n// New creates and returns a new i18n manager.\n// The optional parameter `option` specifies the custom options for i18n manager.\n// It uses a default one if it's not passed.\nfunc New(options ...Options) *Manager {\n\tvar opts Options\n\tvar pathType = pathTypeNone\n\tif len(options) > 0 {\n\t\topts = options[0]\n\t\tpathType = opts.checkPathType(opts.Path)\n\t} else {\n\t\topts = Options{}\n\t\tfor _, folder := range searchFolders {\n\t\t\tpathType = opts.checkPathType(folder)\n\t\t\tif pathType != pathTypeNone {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif opts.Path != \"\" {\n\t\t\t// To avoid of the source path of GoFrame: github.com/gogf/i18n/gi18n\n\t\t\tif gfile.Exists(opts.Path + gfile.Separator + \"gi18n\") {\n\t\t\t\topts.Path = \"\"\n\t\t\t\tpathType = pathTypeNone\n\t\t\t}\n\t\t}\n\t}\n\tif len(opts.Language) == 0 {\n\t\topts.Language = defaultLanguage\n\t}\n\tif len(opts.Delimiters) == 0 {\n\t\topts.Delimiters = defaultDelimiters\n\t}\n\tm := &Manager{\n\t\toptions: opts,\n\t\tpattern: fmt.Sprintf(\n\t\t\t`%s(.+?)%s`,\n\t\t\tgregex.Quote(opts.Delimiters[0]),\n\t\t\tgregex.Quote(opts.Delimiters[1]),\n\t\t),\n\t\tpathType: pathType,\n\t}\n\tintlog.Printf(context.TODO(), `New: %#v`, m)\n\treturn m\n}\n\n// checkPathType checks and returns the path type for given directory path.\nfunc (o *Options) checkPathType(dirPath string) pathType {\n\tif dirPath == \"\" {\n\t\treturn pathTypeNone\n\t}\n\n\tif o.Resource == nil {\n\t\to.Resource = gres.Instance()\n\t}\n\n\tif o.Resource.Contains(dirPath) {\n\t\to.Path = dirPath\n\t\treturn pathTypeGres\n\t}\n\n\trealPath, _ := gfile.Search(dirPath)\n\tif realPath != \"\" {\n\t\to.Path = realPath\n\t\treturn pathTypeNormal\n\t}\n\n\treturn pathTypeNone\n}\n\n// SetPath sets the directory path storing i18n files.\nfunc (m *Manager) SetPath(path string) error {\n\tpathType := m.options.checkPathType(path)\n\tif pathType == pathTypeNone {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `%s does not exist`, path)\n\t}\n\n\tm.pathType = pathType\n\tintlog.Printf(context.TODO(), `SetPath[%s]: %s`, m.pathType, m.options.Path)\n\t// Reset the manager after path changed.\n\tm.reset()\n\treturn nil\n}\n\n// SetLanguage sets the language for translator.\nfunc (m *Manager) SetLanguage(language string) {\n\tm.options.Language = language\n\tintlog.Printf(context.TODO(), `SetLanguage: %s`, m.options.Language)\n}\n\n// SetDelimiters sets the delimiters for translator.\nfunc (m *Manager) SetDelimiters(left, right string) {\n\tm.pattern = fmt.Sprintf(`%s(.+?)%s`, gregex.Quote(left), gregex.Quote(right))\n\tintlog.Printf(context.TODO(), `SetDelimiters: %v`, m.pattern)\n}\n\n// T is alias of Translate for convenience.\nfunc (m *Manager) T(ctx context.Context, content string) string {\n\treturn m.Translate(ctx, content)\n}\n\n// Tf is alias of TranslateFormat for convenience.\nfunc (m *Manager) Tf(ctx context.Context, format string, values ...any) string {\n\treturn m.TranslateFormat(ctx, format, values...)\n}\n\n// TranslateFormat translates, formats and returns the `format` with configured language\n// and given `values`.\nfunc (m *Manager) TranslateFormat(ctx context.Context, format string, values ...any) string {\n\treturn fmt.Sprintf(m.Translate(ctx, format), values...)\n}\n\n// Translate translates `content` with configured language.\nfunc (m *Manager) Translate(ctx context.Context, content string) string {\n\tm.init(ctx)\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\ttransLang := m.options.Language\n\tif lang := LanguageFromCtx(ctx); lang != \"\" {\n\t\ttransLang = lang\n\t}\n\tdata := m.data[transLang]\n\tif data == nil {\n\t\treturn content\n\t}\n\t// Parse content as name.\n\tif v, ok := data[content]; ok {\n\t\treturn v\n\t}\n\t// Parse content as variables container.\n\tresult, _ := gregex.ReplaceStringFuncMatch(\n\t\tm.pattern, content,\n\t\tfunc(match []string) string {\n\t\t\tif v, ok := data[match[1]]; ok {\n\t\t\t\treturn v\n\t\t\t}\n\t\t\t// return match[1] will return the content between delimiters\n\t\t\t// return match[0] will return the original content\n\t\t\treturn match[0]\n\t\t})\n\tintlog.Printf(ctx, `Translate for language: %s`, transLang)\n\treturn result\n}\n\n// GetContent retrieves and returns the configured content for given key and specified language.\n// It returns an empty string if not found.\nfunc (m *Manager) GetContent(ctx context.Context, key string) string {\n\tm.init(ctx)\n\tm.mu.RLock()\n\tdefer m.mu.RUnlock()\n\ttransLang := m.options.Language\n\tif lang := LanguageFromCtx(ctx); lang != \"\" {\n\t\ttransLang = lang\n\t}\n\tif data, ok := m.data[transLang]; ok {\n\t\treturn data[key]\n\t}\n\treturn \"\"\n}\n\n// reset reset data of the manager.\nfunc (m *Manager) reset() {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tm.data = nil\n}\n\n// init initializes the manager for lazy initialization design.\n// The i18n manager is only initialized once.\nfunc (m *Manager) init(ctx context.Context) {\n\tm.mu.RLock()\n\t// If the data is not nil, means it's already initialized.\n\tif m.data != nil {\n\t\tm.mu.RUnlock()\n\t\treturn\n\t}\n\tm.mu.RUnlock()\n\n\tdefer func() {\n\t\tintlog.Printf(ctx, `Manager init finish: %#v`, m)\n\t}()\n\n\tintlog.Printf(ctx, `init path: %s`, m.options.Path)\n\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\tswitch m.pathType {\n\tcase pathTypeGres:\n\t\tfiles := m.options.Resource.ScanDirFile(m.options.Path, \"*.*\", true)\n\t\tif len(files) > 0 {\n\t\t\tvar (\n\t\t\t\tpath  string\n\t\t\t\tname  string\n\t\t\t\tlang  string\n\t\t\t\tarray []string\n\t\t\t)\n\t\t\tm.data = make(map[string]map[string]string)\n\t\t\tfor _, file := range files {\n\t\t\t\tname = file.Name()\n\t\t\t\tpath = name[len(m.options.Path)+1:]\n\t\t\t\tarray = strings.Split(path, \"/\")\n\t\t\t\tif len(array) > 1 {\n\t\t\t\t\tlang = array[0]\n\t\t\t\t} else if len(array) == 1 {\n\t\t\t\t\tlang = gfile.Name(array[0])\n\t\t\t\t}\n\t\t\t\tif m.data[lang] == nil {\n\t\t\t\t\tm.data[lang] = make(map[string]string)\n\t\t\t\t}\n\t\t\t\toptions := gjson.Options{Type: gfile.ExtName(name)}\n\t\t\t\tif j, err := gjson.LoadWithOptions(file.Content(), options); err == nil {\n\t\t\t\t\tfor k, v := range j.Var().Map() {\n\t\t\t\t\t\tm.data[lang][k] = gconv.String(v)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tintlog.Errorf(ctx, \"load i18n file '%s' failed: %+v\", name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase pathTypeNormal:\n\t\tfiles, _ := gfile.ScanDirFile(m.options.Path, \"*.*\", true)\n\t\tif len(files) == 0 {\n\t\t\treturn\n\t\t}\n\t\tvar (\n\t\t\tpath  string\n\t\t\tlang  string\n\t\t\tarray []string\n\t\t)\n\t\tm.data = make(map[string]map[string]string)\n\t\tfor _, file := range files {\n\t\t\tpath = file[len(m.options.Path)+1:]\n\t\t\tarray = strings.Split(path, gfile.Separator)\n\t\t\tif len(array) > 1 {\n\t\t\t\tlang = array[0]\n\t\t\t} else if len(array) == 1 {\n\t\t\t\tlang = gfile.Name(array[0])\n\t\t\t}\n\t\t\tif m.data[lang] == nil {\n\t\t\t\tm.data[lang] = make(map[string]string)\n\t\t\t}\n\t\t\tif j, err := gjson.LoadPath(file, gjson.Options{}); err == nil {\n\t\t\t\tfor k, v := range j.Var().Map() {\n\t\t\t\t\tm.data[lang][k] = gconv.String(v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tintlog.Errorf(ctx, \"load i18n file '%s' failed: %+v\", file, err)\n\t\t\t}\n\t\t}\n\t\tintlog.Printf(ctx, \"i18n files loaded in path: %s\", m.options.Path)\n\t\t// Monitor changes of i18n files for hot reload feature.\n\t\t_, _ = gfsnotify.Add(m.options.Path, func(event *gfsnotify.Event) {\n\t\t\tintlog.Printf(ctx, `i18n file changed: %s`, event.Path)\n\t\t\t// Any changes of i18n files, clear the data.\n\t\t\tm.reset()\n\t\t\tgfsnotify.Exit()\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "i18n/gi18n/gi18n_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gi18n_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n := gi18n.New(gi18n.Options{\n\t\t\tPath: gtest.DataPath(\"i18n\"),\n\t\t})\n\t\ti18n.SetLanguage(\"none\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\ti18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t\ti18n.SetDelimiters(\"{$\", \"}\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\t\tt.Assert(i18n.T(context.Background(), \"{$hello}{$world}\"), \"你好世界\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\t\tt.Assert(i18n.T(context.Background(), \"{$你好} {$世界}\"), \"hello world\")\n\t\t// undefined variables.\n\t\tt.Assert(i18n.T(context.Background(), \"{$你好1}{$世界1}\"), \"{$你好1}{$世界1}\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n := gi18n.New(gi18n.Options{\n\t\t\tPath: gtest.DataPath(\"i18n-file\"),\n\t\t})\n\t\ti18n.SetLanguage(\"none\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\ti18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#你好} {#世界}\"), \"hello world\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n := gi18n.New(gi18n.Options{\n\t\t\tPath: gdebug.CallerDirectory() + gfile.Separator + \"testdata\" + gfile.Separator + \"i18n-dir\",\n\t\t})\n\t\ti18n.SetLanguage(\"none\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\ti18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t})\n}\n\nfunc Test_TranslateFormat(t *testing.T) {\n\t// Tf\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n := gi18n.New(gi18n.Options{\n\t\t\tPath: gtest.DataPath(\"i18n\"),\n\t\t})\n\t\ti18n.SetLanguage(\"none\")\n\t\tt.Assert(i18n.Tf(context.Background(), \"{#hello}{#world} %d\", 2020), \"{#hello}{#world} 2020\")\n\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.Tf(context.Background(), \"{#hello}{#world} %d\", 2020), \"こんにちは世界 2020\")\n\t})\n}\n\nfunc Test_DefaultManager(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gi18n.SetPath(gtest.DataPath(\"i18n\"))\n\t\tt.AssertNil(err)\n\n\t\tgi18n.SetLanguage(\"none\")\n\t\tt.Assert(gi18n.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\tgi18n.SetLanguage(\"ja\")\n\t\tt.Assert(gi18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\tgi18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(gi18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gi18n.SetPath(gdebug.CallerDirectory() + gfile.Separator + \"testdata\" + gfile.Separator + \"i18n-dir\")\n\t\tt.AssertNil(err)\n\n\t\tgi18n.SetLanguage(\"none\")\n\t\tt.Assert(gi18n.Translate(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\tgi18n.SetLanguage(\"ja\")\n\t\tt.Assert(gi18n.Translate(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\tgi18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(gi18n.Translate(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t})\n}\n\nfunc Test_Instance(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gi18n.Instance()\n\t\terr := m.SetPath(gtest.DataPath(\"i18n-dir\"))\n\t\tt.AssertNil(err)\n\t\tm.SetLanguage(\"zh-CN\")\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t\tt.Assert(m.T(context.Background(), \"{#你好} {#世界}\"), \"hello world\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gi18n.Instance()\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(g.I18n().T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t})\n\t// Default language is: en\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gi18n.Instance(gconv.String(gtime.TimestampNano()))\n\t\tm.SetPath(gtest.DataPath(\"i18n-dir\"))\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"HelloWorld\")\n\t})\n}\n\nfunc Test_Resource(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.I18n(\"resource\")\n\t\terr := m.SetPath(gtest.DataPath(\"i18n-dir\"))\n\t\tt.AssertNil(err)\n\n\t\tm.SetLanguage(\"none\")\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"{#hello}{#world}\")\n\n\t\tm.SetLanguage(\"ja\")\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\tm.SetLanguage(\"zh-CN\")\n\t\tt.Assert(m.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\n\t\tm.SetLanguage(\"ja\")\n\t\tconst key = \"The year is 2128. AI has taken over the world, and all forms of racing is done by these DNA driven machines ; they are alive, and they have a will to win.\"\n\t\tt.Assert(m.T(context.Background(), \"{#\"+key+\"}\"), \"2128年です。AIが世界を支配し、あらゆる形式のレースはDNA駆動の機械によって行われています。彼らは生きており、勝つ意志を持っています。\")\n\t})\n}\n\nfunc Test_SetCtxLanguage(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := gctx.New()\n\t\tt.Assert(gi18n.LanguageFromCtx(ctx), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gi18n.LanguageFromCtx(nil), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := gctx.New()\n\t\tctx = gi18n.WithLanguage(ctx, \"zh-CN\")\n\t\tt.Assert(gi18n.LanguageFromCtx(ctx), \"zh-CN\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := gi18n.WithLanguage(context.Background(), \"zh-CN\")\n\t\tt.Assert(gi18n.LanguageFromCtx(ctx), \"zh-CN\")\n\t})\n\n}\n\nfunc Test_GetContent(t *testing.T) {\n\ti18n := gi18n.New(gi18n.Options{\n\t\tPath: gtest.DataPath(\"i18n-file\"),\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(i18n.GetContent(context.Background(), \"hello\"), \"Hello\")\n\n\t\tctx := gi18n.WithLanguage(context.Background(), \"zh-CN\")\n\t\tt.Assert(i18n.GetContent(ctx, \"hello\"), \"你好\")\n\n\t\tctx = gi18n.WithLanguage(context.Background(), \"unknown\")\n\t\tt.Assert(i18n.GetContent(ctx, \"hello\"), \"\")\n\t})\n}\n\nfunc Test_PathInResource(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbinContent, err := gres.Pack(gtest.DataPath(\"i18n\"))\n\t\tt.AssertNil(err)\n\t\terr = gres.Add(gbase64.EncodeToString(binContent))\n\t\tt.AssertNil(err)\n\n\t\ti18n := gi18n.New()\n\t\ti18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\n\t\terr = i18n.SetPath(\"i18n\")\n\t\tt.AssertNil(err)\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\n\t\tconst key = \"The year is 2128. AI has taken over the world, and all forms of racing is done by these DNA driven machines ; they are alive, and they have a will to win.\"\n\t\tt.Assert(i18n.T(context.Background(), \"{#\"+key+\"}\"), \"2128年です。AIが世界を支配し、あらゆる形式のレースはDNA駆動の機械によって行われています。彼らは生きており、勝つ意志を持っています。\")\n\t})\n}\n\nfunc Test_PathInNormal(t *testing.T) {\n\t// Copy i18n files to current directory.\n\tgfile.CopyDir(gtest.DataPath(\"i18n\"), gfile.Join(gdebug.CallerDirectory(), \"manifest/i18n\"))\n\t// Remove copied files after testing.\n\tdefer gfile.Remove(gfile.Join(gdebug.CallerDirectory(), \"manifest\"))\n\n\ti18n := gi18n.New()\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n.SetLanguage(\"zh-CN\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"你好世界\")\n\t\t// Set not exist path.\n\t\terr := i18n.SetPath(\"i18n-not-exist\")\n\t\tt.AssertNE(err, nil)\n\t\terr = i18n.SetPath(\"\")\n\t\tt.AssertNE(err, nil)\n\t\ti18n.SetLanguage(\"ja\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}\"), \"こんにちは世界\")\n\t})\n\n\t// Change language file content.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n.SetLanguage(\"en\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}{#name}\"), \"HelloWorld{#name}\")\n\t\terr := gfile.PutContentsAppend(gfile.Join(gdebug.CallerDirectory(), \"manifest/i18n/en.toml\"), \"\\nname = \\\"GoFrame\\\"\")\n\t\tt.AssertNil(err)\n\t\t// Wait for the file modification time to change.\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(i18n.T(context.Background(), \"{#hello}{#world}{#name}\"), \"HelloWorldGoFrame\")\n\t})\n\n\t// Add new language\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gfile.PutContents(gfile.Join(gdebug.CallerDirectory(), \"manifest/i18n/en-US.toml\"), \"lang = \\\"en-US\\\"\")\n\t\tt.AssertNil(err)\n\t\t// Wait for the file modification time to change.\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\ti18n.SetLanguage(\"en-US\")\n\t\tt.Assert(i18n.T(context.Background(), \"{#lang}\"), \"en-US\")\n\t})\n}\n\nfunc Test_Issue_Yaml(t *testing.T) {\n\t// Copy i18n files to current directory.\n\terr := gfile.CopyDir(\n\t\tgtest.DataPath(\"issue-yaml\"),\n\t\tgfile.Join(gdebug.CallerDirectory(), \"manifest/i18n\"),\n\t)\n\t// Remove copied files after testing.\n\tdefer gfile.RemoveAll(gfile.Join(gdebug.CallerDirectory(), \"manifest\"))\n\n\tgtest.AssertNil(err)\n\n\tvar (\n\t\ti18n = gi18n.New()\n\t\tctx  = context.Background()\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ti18n.SetLanguage(\"zh\")\n\t\tt.Assert(i18n.T(ctx, \"{#resourceUsage.workflow}\"), \"workflow\")\n\t})\n}\n"
  },
  {
    "path": "i18n/gi18n/testdata/i18n/en.toml",
    "content": "\nhello = \"Hello\"\nworld = \"World\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n/ja.toml",
    "content": "\nhello = \"こんにちは\"\nworld = \"世界\"\n\n\"The year is 2128. AI has taken over the world, and all forms of racing is done by these DNA driven machines ; they are alive, and they have a will to win.\" = \"2128年です。AIが世界を支配し、あらゆる形式のレースはDNA駆動の機械によって行われています。彼らは生きており、勝つ意志を持っています。\"\n"
  },
  {
    "path": "i18n/gi18n/testdata/i18n/ru.toml",
    "content": "\nhello = \"Привет\"\nworld = \"мир\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n/zh-CN.json",
    "content": "{\r\n  \"你好\": \"hello\",\r\n  \"世界\": \"world\",\r\n  \"hello\": \"你好\",\r\n  \"world\": \"世界\"\r\n}"
  },
  {
    "path": "i18n/gi18n/testdata/i18n/zh-TW.toml",
    "content": "hello = \"你好\"\nworld = \"世界\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/en/hello.toml",
    "content": "\nhello = \"Hello\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/en/world.toml",
    "content": "\nworld = \"World\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/ja/hello.yaml",
    "content": "\nhello: \"こんにちは\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/ja/world.yaml",
    "content": "world: \"世界\"\n\n\"The year is 2128. AI has taken over the world, and all forms of racing is done by these DNA driven machines ; they are alive, and they have a will to win.\": \"2128年です。AIが世界を支配し、あらゆる形式のレースはDNA駆動の機械によって行われています。彼らは生きており、勝つ意志を持っています。\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/ru/hello.ini",
    "content": "hello = \"Привет\"\n"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/ru/world.ini",
    "content": "world = \"мир\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/zh-CN/hello.json",
    "content": "{\n    \"你好\": \"hello\",\n    \"hello\": \"你好\"    \n}"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/zh-CN/world.json",
    "content": "{\n    \"世界\": \"world\",\n    \"world\": \"世界\"\n}"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/zh-TW/hello.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <hello>你好</hello>\n</i18n>"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-dir/zh-TW/world.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <world>世界</world>\n</i18n>"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-file/en.toml",
    "content": "\nhello = \"Hello\"\nworld = \"World\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-file/ja.yaml",
    "content": "\nhello: \"こんにちは\"\nworld: \"世界\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-file/ru.ini",
    "content": "hello = \"Привет\"\nworld = \"мир\""
  },
  {
    "path": "i18n/gi18n/testdata/i18n-file/zh-CN.json",
    "content": "{\n    \"你好\": \"hello\",\n    \"世界\": \"world\",\n    \"hello\": \"你好\",\n    \"world\": \"世界\"\n}"
  },
  {
    "path": "i18n/gi18n/testdata/i18n-file/zh-TW.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <hello>你好</hello>\n    <world>世界</world>\n</i18n>"
  },
  {
    "path": "i18n/gi18n/testdata/issue-yaml/zh.yaml",
    "content": "\"environment status is Creating/Updating, please wait for sync to complete\": \"环境当前状为创建中/更新中，请等待同步完成\"\n\"There are still queues in the current environment, please ensure there are no queues before deletion\": \"当前环境还存在队列，确保环境没有队列再删除\"\n\"the current repository has associated environments in use, please ensure no environment associations before deleting the repository\": \"当前仓库有关联环境正在使用，请确保没有环境关联再删除该仓库\"\n\"There are environments using this cluster, please ensure all environments have been deleted before deleting the cluster\": \"当前集群存在环境正在使用，请确保所有环境已经删除再删除该集群\"\n\n\"shareStrategy.Init\": \"未拆卡\"\n\"shareStrategy.Pending\": \"切分中\"\n\"shareStrategy.Success\": \"拆卡成功\"\n\"shareStrategy.Canceling\": \"拆卡取消中\"\n\"shareStrategy.unknown\": \"未知状态\"\n\"resourceUsage.none\": \"无\"\n\"resourceUsage.inference\": \"推理\"\n\"resourceUsage.training\": \"训练\"\n\"resourceUsage.workflow\": \"workflow\"\n\"resourceUsage.hybrid\": \"混合\"\n\"resourceUsage.unknown\": \"unknown\""
  },
  {
    "path": "internal/command/command.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\n// Package command provides console operations, like options/arguments reading.\npackage command\n\nimport (\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar (\n\tdefaultParsedArgs    = make([]string, 0)\n\tdefaultParsedOptions = make(map[string]string)\n\targumentOptionRegex  = regexp.MustCompile(`^\\-{1,2}([\\w\\?\\.\\-]+)(=){0,1}(.*)$`)\n)\n\n// Init does custom initialization.\nfunc Init(args ...string) {\n\tif len(args) == 0 {\n\t\tif len(defaultParsedArgs) == 0 && len(defaultParsedOptions) == 0 {\n\t\t\targs = os.Args\n\t\t} else {\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tdefaultParsedArgs = make([]string, 0)\n\t\tdefaultParsedOptions = make(map[string]string)\n\t}\n\t// Parsing os.Args with default algorithm.\n\tdefaultParsedArgs, defaultParsedOptions = ParseUsingDefaultAlgorithm(args...)\n}\n\n// ParseUsingDefaultAlgorithm parses arguments using default algorithm.\nfunc ParseUsingDefaultAlgorithm(args ...string) (parsedArgs []string, parsedOptions map[string]string) {\n\tparsedArgs = make([]string, 0)\n\tparsedOptions = make(map[string]string)\n\tfor i := 0; i < len(args); {\n\t\tarray := argumentOptionRegex.FindStringSubmatch(args[i])\n\t\tif len(array) > 2 {\n\t\t\tif array[2] == \"=\" {\n\t\t\t\tparsedOptions[array[1]] = array[3]\n\t\t\t} else if i < len(args)-1 {\n\t\t\t\tif len(args[i+1]) > 0 && args[i+1][0] == '-' {\n\t\t\t\t\t// Example: gf gen -d -n 1\n\t\t\t\t\tparsedOptions[array[1]] = array[3]\n\t\t\t\t} else {\n\t\t\t\t\t// Example: gf gen -n 2\n\t\t\t\t\tparsedOptions[array[1]] = args[i+1]\n\t\t\t\t\ti += 2\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Example: gf gen -h\n\t\t\t\tparsedOptions[array[1]] = array[3]\n\t\t\t}\n\t\t} else {\n\t\t\tparsedArgs = append(parsedArgs, args[i])\n\t\t}\n\t\ti++\n\t}\n\treturn\n}\n\n// GetOpt returns the option value named `name`.\nfunc GetOpt(name string, def ...string) string {\n\tInit()\n\tif v, ok := defaultParsedOptions[name]; ok {\n\t\treturn v\n\t}\n\tif len(def) > 0 {\n\t\treturn def[0]\n\t}\n\treturn \"\"\n}\n\n// GetOptAll returns all parsed options.\nfunc GetOptAll() map[string]string {\n\tInit()\n\treturn defaultParsedOptions\n}\n\n// ContainsOpt checks whether option named `name` exist in the arguments.\nfunc ContainsOpt(name string) bool {\n\tInit()\n\t_, ok := defaultParsedOptions[name]\n\treturn ok\n}\n\n// GetArg returns the argument at `index`.\nfunc GetArg(index int, def ...string) string {\n\tInit()\n\tif index < len(defaultParsedArgs) {\n\t\treturn defaultParsedArgs[index]\n\t}\n\tif len(def) > 0 {\n\t\treturn def[0]\n\t}\n\treturn \"\"\n}\n\n// GetArgAll returns all parsed arguments.\nfunc GetArgAll() []string {\n\tInit()\n\treturn defaultParsedArgs\n}\n\n// GetOptWithEnv returns the command line argument of the specified `key`.\n// If the argument does not exist, then it returns the environment variable with specified `key`.\n// It returns the default value `def` if none of them exists.\n//\n// Fetching Rules:\n// 1. Command line arguments are in lowercase format, eg: gf.package.variable;\n// 2. Environment arguments are in uppercase format, eg: GF_PACKAGE_VARIABLE；\nfunc GetOptWithEnv(key string, def ...string) string {\n\tcmdKey := strings.ToLower(strings.ReplaceAll(key, \"_\", \".\"))\n\tif ContainsOpt(cmdKey) {\n\t\treturn GetOpt(cmdKey)\n\t} else {\n\t\tenvKey := strings.ToUpper(strings.ReplaceAll(key, \".\", \"_\"))\n\t\tif r, ok := os.LookupEnv(envKey); ok {\n\t\t\treturn r\n\t\t} else {\n\t\t\tif len(def) > 0 {\n\t\t\t\treturn def[0]\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "internal/consts/consts.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package consts defines constants that are shared all among packages of framework.\npackage consts\n\nconst (\n\tConfigNodeNameDatabase        = \"database\"\n\tConfigNodeNameLogger          = \"logger\"\n\tConfigNodeNameRedis           = \"redis\"\n\tConfigNodeNameViewer          = \"viewer\"\n\tConfigNodeNameServer          = \"server\"     // General version configuration item name.\n\tConfigNodeNameServerSecondary = \"httpserver\" // New version configuration item name support from v2.\n\n\t// StackFilterKeyForGoFrame is the stack filtering key for all GoFrame module paths.\n\t// Eg: .../pkg/mod/github.com/gogf/gf/v2@v2.0.0-20211011134327-54dd11f51122/debug/gdebug/gdebug_caller.go\n\tStackFilterKeyForGoFrame = \"github.com/gogf/gf/\"\n)\n"
  },
  {
    "path": "internal/deepcopy/deepcopy.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package deepcopy makes deep copies of things using reflection.\n//\n// This package is maintained from: https://github.com/mohae/deepcopy\npackage deepcopy\n\nimport (\n\t\"reflect\"\n\t\"time\"\n)\n\n// Interface for delegating copy process to type\ntype Interface interface {\n\tDeepCopy() any\n}\n\n// Copy creates a deep copy of whatever is passed to it and returns the copy\n// in an any.  The returned value will need to be asserted to the\n// correct type.\nfunc Copy(src any) any {\n\tif src == nil {\n\t\treturn nil\n\t}\n\n\t// Copy by type assertion.\n\tswitch r := src.(type) {\n\tcase\n\t\tint, int8, int16, int32, int64,\n\t\tuint, uint8, uint16, uint32, uint64,\n\t\tfloat32, float64,\n\t\tcomplex64, complex128,\n\t\tstring,\n\t\tbool:\n\t\treturn r\n\n\tdefault:\n\t\tif v, ok := src.(Interface); ok {\n\t\t\treturn v.DeepCopy()\n\t\t}\n\t\tvar (\n\t\t\toriginal = reflect.ValueOf(src)                // Make the interface a reflect.Value\n\t\t\tdst      = reflect.New(original.Type()).Elem() // Make a copy of the same type as the original.\n\t\t)\n\t\t// Recursively copy the original.\n\t\tcopyRecursive(original, dst)\n\t\t// Return the copy as an interface.\n\t\treturn dst.Interface()\n\t}\n}\n\n// copyRecursive does the actual copying of the interface. It currently has\n// limited support for what it can handle. Add as needed.\nfunc copyRecursive(original, cpy reflect.Value) {\n\t// check for implement deepcopy.Interface\n\tif original.CanInterface() && original.IsValid() && !original.IsZero() {\n\t\tif copier, ok := original.Interface().(Interface); ok {\n\t\t\tcpy.Set(reflect.ValueOf(copier.DeepCopy()))\n\t\t\treturn\n\t\t}\n\t}\n\n\t// handle according to original's Kind\n\tswitch original.Kind() {\n\tcase reflect.Pointer:\n\t\t// Get the actual value being pointed to.\n\t\toriginalValue := original.Elem()\n\n\t\t// if  it isn't valid, return.\n\t\tif !originalValue.IsValid() {\n\t\t\treturn\n\t\t}\n\t\tcpy.Set(reflect.New(originalValue.Type()))\n\t\tcopyRecursive(originalValue, cpy.Elem())\n\n\tcase reflect.Interface:\n\t\t// If this is a nil, don't do anything\n\t\tif original.IsNil() {\n\t\t\treturn\n\t\t}\n\t\t// Get the value for the interface, not the pointer.\n\t\toriginalValue := original.Elem()\n\n\t\t// Get the value by calling Elem().\n\t\tcopyValue := reflect.New(originalValue.Type()).Elem()\n\t\tcopyRecursive(originalValue, copyValue)\n\t\tcpy.Set(copyValue)\n\n\tcase reflect.Struct:\n\t\tt, ok := original.Interface().(time.Time)\n\t\tif ok {\n\t\t\tcpy.Set(reflect.ValueOf(t))\n\t\t\treturn\n\t\t}\n\t\t// Go through each field of the struct and copy it.\n\t\tfor i := 0; i < original.NumField(); i++ {\n\t\t\t// The Type's StructField for a given field is checked to see if StructField.PkgPath\n\t\t\t// is set to determine if the field is exported or not because CanSet() returns false\n\t\t\t// for settable fields.  I'm not sure why.  -mohae\n\t\t\tif original.Type().Field(i).PkgPath != \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcopyRecursive(original.Field(i), cpy.Field(i))\n\t\t}\n\n\tcase reflect.Slice:\n\t\tif original.IsNil() {\n\t\t\treturn\n\t\t}\n\t\t// Make a new slice and copy each element.\n\t\tcpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))\n\t\tfor i := 0; i < original.Len(); i++ {\n\t\t\tcopyRecursive(original.Index(i), cpy.Index(i))\n\t\t}\n\n\tcase reflect.Map:\n\t\tif original.IsNil() {\n\t\t\treturn\n\t\t}\n\t\tcpy.Set(reflect.MakeMap(original.Type()))\n\t\tfor _, key := range original.MapKeys() {\n\t\t\toriginalValue := original.MapIndex(key)\n\t\t\tcopyValue := reflect.New(originalValue.Type()).Elem()\n\t\t\tcopyRecursive(originalValue, copyValue)\n\t\t\tcopyKey := Copy(key.Interface())\n\t\t\tcpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)\n\t\t}\n\n\tdefault:\n\t\tcpy.Set(original)\n\t}\n}\n"
  },
  {
    "path": "internal/deepcopy/deepcopy_test.go",
    "content": "package deepcopy\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\t\"unsafe\"\n)\n\n// just basic is this working stuff\nfunc TestSimple(t *testing.T) {\n\tStrings := []string{\"a\", \"b\", \"c\"}\n\tcpyS := Copy(Strings).([]string)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyS)).Data {\n\t\tt.Error(\"[]string: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyBools\n\t}\n\tif len(cpyS) != len(Strings) {\n\t\tt.Errorf(\"[]string: len was %d; want %d\", len(cpyS), len(Strings))\n\t\tgoto CopyBools\n\t}\n\tfor i, v := range Strings {\n\t\tif v != cpyS[i] {\n\t\t\tt.Errorf(\"[]string: got %v at index %d of the copy; want %v\", cpyS[i], i, v)\n\t\t}\n\t}\n\nCopyBools:\n\tBools := []bool{true, true, false, false}\n\tcpyB := Copy(Bools).([]bool)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyB)).Data {\n\t\tt.Error(\"[]bool: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyBytes\n\t}\n\tif len(cpyB) != len(Bools) {\n\t\tt.Errorf(\"[]bool: len was %d; want %d\", len(cpyB), len(Bools))\n\t\tgoto CopyBytes\n\t}\n\tfor i, v := range Bools {\n\t\tif v != cpyB[i] {\n\t\t\tt.Errorf(\"[]bool: got %v at index %d of the copy; want %v\", cpyB[i], i, v)\n\t\t}\n\t}\n\nCopyBytes:\n\tBytes := []byte(\"hello\")\n\tcpyBt := Copy(Bytes).([]byte)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyBt)).Data {\n\t\tt.Error(\"[]byte: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyInts\n\t}\n\tif len(cpyBt) != len(Bytes) {\n\t\tt.Errorf(\"[]byte: len was %d; want %d\", len(cpyBt), len(Bytes))\n\t\tgoto CopyInts\n\t}\n\tfor i, v := range Bytes {\n\t\tif v != cpyBt[i] {\n\t\t\tt.Errorf(\"[]byte: got %v at index %d of the copy; want %v\", cpyBt[i], i, v)\n\t\t}\n\t}\n\nCopyInts:\n\tInts := []int{42}\n\tcpyI := Copy(Ints).([]int)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyI)).Data {\n\t\tt.Error(\"[]int: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyUints\n\t}\n\tif len(cpyI) != len(Ints) {\n\t\tt.Errorf(\"[]int: len was %d; want %d\", len(cpyI), len(Ints))\n\t\tgoto CopyUints\n\t}\n\tfor i, v := range Ints {\n\t\tif v != cpyI[i] {\n\t\t\tt.Errorf(\"[]int: got %v at index %d of the copy; want %v\", cpyI[i], i, v)\n\t\t}\n\t}\n\nCopyUints:\n\tUints := []uint{1, 2, 3, 4, 5}\n\tcpyU := Copy(Uints).([]uint)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyU)).Data {\n\t\tt.Error(\"[]: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyFloat32s\n\t}\n\tif len(cpyU) != len(Uints) {\n\t\tt.Errorf(\"[]uint: len was %d; want %d\", len(cpyU), len(Uints))\n\t\tgoto CopyFloat32s\n\t}\n\tfor i, v := range Uints {\n\t\tif v != cpyU[i] {\n\t\t\tt.Errorf(\"[]uint: got %v at index %d of the copy; want %v\", cpyU[i], i, v)\n\t\t}\n\t}\n\nCopyFloat32s:\n\tFloat32s := []float32{3.14}\n\tcpyF := Copy(Float32s).([]float32)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyF)).Data {\n\t\tt.Error(\"[]float32: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\tgoto CopyInterfaces\n\t}\n\tif len(cpyF) != len(Float32s) {\n\t\tt.Errorf(\"[]float32: len was %d; want %d\", len(cpyF), len(Float32s))\n\t\tgoto CopyInterfaces\n\t}\n\tfor i, v := range Float32s {\n\t\tif v != cpyF[i] {\n\t\t\tt.Errorf(\"[]float32: got %v at index %d of the copy; want %v\", cpyF[i], i, v)\n\t\t}\n\t}\n\nCopyInterfaces:\n\tInterfaces := []any{\"a\", 42, true, 4.32}\n\tcpyIf := Copy(Interfaces).([]any)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyIf)).Data {\n\t\tt.Error(\"[]interfaces: expected SliceHeader data pointers to point to different locations, they didn't\")\n\t\treturn\n\t}\n\tif len(cpyIf) != len(Interfaces) {\n\t\tt.Errorf(\"[]any: len was %d; want %d\", len(cpyIf), len(Interfaces))\n\t\treturn\n\t}\n\tfor i, v := range Interfaces {\n\t\tif v != cpyIf[i] {\n\t\t\tt.Errorf(\"[]any: got %v at index %d of the copy; want %v\", cpyIf[i], i, v)\n\t\t}\n\t}\n}\n\ntype Basics struct {\n\tString      string\n\tStrings     []string\n\tStringArr   [4]string\n\tBool        bool\n\tBools       []bool\n\tByte        byte\n\tBytes       []byte\n\tInt         int\n\tInts        []int\n\tInt8        int8\n\tInt8s       []int8\n\tInt16       int16\n\tInt16s      []int16\n\tInt32       int32\n\tInt32s      []int32\n\tInt64       int64\n\tInt64s      []int64\n\tUint        uint\n\tUints       []uint\n\tUint8       uint8\n\tUint8s      []uint8\n\tUint16      uint16\n\tUint16s     []uint16\n\tUint32      uint32\n\tUint32s     []uint32\n\tUint64      uint64\n\tUint64s     []uint64\n\tFloat32     float32\n\tFloat32s    []float32\n\tFloat64     float64\n\tFloat64s    []float64\n\tComplex64   complex64\n\tComplex64s  []complex64\n\tComplex128  complex128\n\tComplex128s []complex128\n\tInterface   any\n\tInterfaces  []any\n}\n\n// These tests test that all supported basic types are copied correctly.  This\n// is done by copying a struct with fields of most of the basic types as []T.\nfunc TestMostTypes(t *testing.T) {\n\ttest := Basics{\n\t\tString:      \"kimchi\",\n\t\tStrings:     []string{\"uni\", \"ika\"},\n\t\tStringArr:   [4]string{\"malort\", \"barenjager\", \"fernet\", \"salmiakki\"},\n\t\tBool:        true,\n\t\tBools:       []bool{true, false, true},\n\t\tByte:        'z',\n\t\tBytes:       []byte(\"abc\"),\n\t\tInt:         42,\n\t\tInts:        []int{0, 1, 3, 4},\n\t\tInt8:        8,\n\t\tInt8s:       []int8{8, 9, 10},\n\t\tInt16:       16,\n\t\tInt16s:      []int16{16, 17, 18, 19},\n\t\tInt32:       32,\n\t\tInt32s:      []int32{32, 33},\n\t\tInt64:       64,\n\t\tInt64s:      []int64{64},\n\t\tUint:        420,\n\t\tUints:       []uint{11, 12, 13},\n\t\tUint8:       81,\n\t\tUint8s:      []uint8{81, 82},\n\t\tUint16:      160,\n\t\tUint16s:     []uint16{160, 161, 162, 163, 164},\n\t\tUint32:      320,\n\t\tUint32s:     []uint32{320, 321},\n\t\tUint64:      640,\n\t\tUint64s:     []uint64{6400, 6401, 6402, 6403},\n\t\tFloat32:     32.32,\n\t\tFloat32s:    []float32{32.32, 33},\n\t\tFloat64:     64.1,\n\t\tFloat64s:    []float64{64, 65, 66},\n\t\tComplex64:   complex64(-64 + 12i),\n\t\tComplex64s:  []complex64{complex64(-65 + 11i), complex64(66 + 10i)},\n\t\tComplex128:  complex128(-128 + 12i),\n\t\tComplex128s: []complex128{complex128(-128 + 11i), complex128(129 + 10i)},\n\t\tInterfaces:  []any{42, true, \"pan-galactic\"},\n\t}\n\n\tcpy := Copy(test).(Basics)\n\n\t// see if they point to the same location\n\tif fmt.Sprintf(\"%p\", &cpy) == fmt.Sprintf(\"%p\", &test) {\n\t\tt.Error(\"address of copy was the same as original; they should be different\")\n\t\treturn\n\t}\n\n\t// Go through each field and check to see it got copied properly\n\tif cpy.String != test.String {\n\t\tt.Errorf(\"String: got %v; want %v\", cpy.String, test.String)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Strings)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Strings)).Data {\n\t\tt.Error(\"Strings: address of copy was the same as original; they should be different\")\n\t\tgoto StringArr\n\t}\n\n\tif len(cpy.Strings) != len(test.Strings) {\n\t\tt.Errorf(\"Strings: len was %d; want %d\", len(cpy.Strings), len(test.Strings))\n\t\tgoto StringArr\n\t}\n\tfor i, v := range test.Strings {\n\t\tif v != cpy.Strings[i] {\n\t\t\tt.Errorf(\"Strings: got %v at index %d of the copy; want %v\", cpy.Strings[i], i, v)\n\t\t}\n\t}\n\nStringArr:\n\tif unsafe.Pointer(&test.StringArr) == unsafe.Pointer(&cpy.StringArr) {\n\t\tt.Error(\"StringArr: address of copy was the same as original; they should be different\")\n\t\tgoto Bools\n\t}\n\tfor i, v := range test.StringArr {\n\t\tif v != cpy.StringArr[i] {\n\t\t\tt.Errorf(\"StringArr: got %v at index %d of the copy; want %v\", cpy.StringArr[i], i, v)\n\t\t}\n\t}\n\nBools:\n\tif cpy.Bool != test.Bool {\n\t\tt.Errorf(\"Bool: got %v; want %v\", cpy.Bool, test.Bool)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Bools)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Bools)).Data {\n\t\tt.Error(\"Bools: address of copy was the same as original; they should be different\")\n\t\tgoto Bytes\n\t}\n\tif len(cpy.Bools) != len(test.Bools) {\n\t\tt.Errorf(\"Bools: len was %d; want %d\", len(cpy.Bools), len(test.Bools))\n\t\tgoto Bytes\n\t}\n\tfor i, v := range test.Bools {\n\t\tif v != cpy.Bools[i] {\n\t\t\tt.Errorf(\"Bools: got %v at index %d of the copy; want %v\", cpy.Bools[i], i, v)\n\t\t}\n\t}\n\nBytes:\n\tif cpy.Byte != test.Byte {\n\t\tt.Errorf(\"Byte: got %v; want %v\", cpy.Byte, test.Byte)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Bytes)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Bytes)).Data {\n\t\tt.Error(\"Bytes: address of copy was the same as original; they should be different\")\n\t\tgoto Ints\n\t}\n\tif len(cpy.Bytes) != len(test.Bytes) {\n\t\tt.Errorf(\"Bytes: len was %d; want %d\", len(cpy.Bytes), len(test.Bytes))\n\t\tgoto Ints\n\t}\n\tfor i, v := range test.Bytes {\n\t\tif v != cpy.Bytes[i] {\n\t\t\tt.Errorf(\"Bytes: got %v at index %d of the copy; want %v\", cpy.Bytes[i], i, v)\n\t\t}\n\t}\n\nInts:\n\tif cpy.Int != test.Int {\n\t\tt.Errorf(\"Int: got %v; want %v\", cpy.Int, test.Int)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Ints)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Ints)).Data {\n\t\tt.Error(\"Ints: address of copy was the same as original; they should be different\")\n\t\tgoto Int8s\n\t}\n\tif len(cpy.Ints) != len(test.Ints) {\n\t\tt.Errorf(\"Ints: len was %d; want %d\", len(cpy.Ints), len(test.Ints))\n\t\tgoto Int8s\n\t}\n\tfor i, v := range test.Ints {\n\t\tif v != cpy.Ints[i] {\n\t\t\tt.Errorf(\"Ints: got %v at index %d of the copy; want %v\", cpy.Ints[i], i, v)\n\t\t}\n\t}\n\nInt8s:\n\tif cpy.Int8 != test.Int8 {\n\t\tt.Errorf(\"Int8: got %v; want %v\", cpy.Int8, test.Int8)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Int8s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Int8s)).Data {\n\t\tt.Error(\"Int8s: address of copy was the same as original; they should be different\")\n\t\tgoto Int16s\n\t}\n\tif len(cpy.Int8s) != len(test.Int8s) {\n\t\tt.Errorf(\"Int8s: len was %d; want %d\", len(cpy.Int8s), len(test.Int8s))\n\t\tgoto Int16s\n\t}\n\tfor i, v := range test.Int8s {\n\t\tif v != cpy.Int8s[i] {\n\t\t\tt.Errorf(\"Int8s: got %v at index %d of the copy; want %v\", cpy.Int8s[i], i, v)\n\t\t}\n\t}\n\nInt16s:\n\tif cpy.Int16 != test.Int16 {\n\t\tt.Errorf(\"Int16: got %v; want %v\", cpy.Int16, test.Int16)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Int16s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Int16s)).Data {\n\t\tt.Error(\"Int16s: address of copy was the same as original; they should be different\")\n\t\tgoto Int32s\n\t}\n\tif len(cpy.Int16s) != len(test.Int16s) {\n\t\tt.Errorf(\"Int16s: len was %d; want %d\", len(cpy.Int16s), len(test.Int16s))\n\t\tgoto Int32s\n\t}\n\tfor i, v := range test.Int16s {\n\t\tif v != cpy.Int16s[i] {\n\t\t\tt.Errorf(\"Int16s: got %v at index %d of the copy; want %v\", cpy.Int16s[i], i, v)\n\t\t}\n\t}\n\nInt32s:\n\tif cpy.Int32 != test.Int32 {\n\t\tt.Errorf(\"Int32: got %v; want %v\", cpy.Int32, test.Int32)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Int32s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Int32s)).Data {\n\t\tt.Error(\"Int32s: address of copy was the same as original; they should be different\")\n\t\tgoto Int64s\n\t}\n\tif len(cpy.Int32s) != len(test.Int32s) {\n\t\tt.Errorf(\"Int32s: len was %d; want %d\", len(cpy.Int32s), len(test.Int32s))\n\t\tgoto Int64s\n\t}\n\tfor i, v := range test.Int32s {\n\t\tif v != cpy.Int32s[i] {\n\t\t\tt.Errorf(\"Int32s: got %v at index %d of the copy; want %v\", cpy.Int32s[i], i, v)\n\t\t}\n\t}\n\nInt64s:\n\tif cpy.Int64 != test.Int64 {\n\t\tt.Errorf(\"Int64: got %v; want %v\", cpy.Int64, test.Int64)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Int64s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Int64s)).Data {\n\t\tt.Error(\"Int64s: address of copy was the same as original; they should be different\")\n\t\tgoto Uints\n\t}\n\tif len(cpy.Int64s) != len(test.Int64s) {\n\t\tt.Errorf(\"Int64s: len was %d; want %d\", len(cpy.Int64s), len(test.Int64s))\n\t\tgoto Uints\n\t}\n\tfor i, v := range test.Int64s {\n\t\tif v != cpy.Int64s[i] {\n\t\t\tt.Errorf(\"Int64s: got %v at index %d of the copy; want %v\", cpy.Int64s[i], i, v)\n\t\t}\n\t}\n\nUints:\n\tif cpy.Uint != test.Uint {\n\t\tt.Errorf(\"Uint: got %v; want %v\", cpy.Uint, test.Uint)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Uints)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Uints)).Data {\n\t\tt.Error(\"Uints: address of copy was the same as original; they should be different\")\n\t\tgoto Uint8s\n\t}\n\tif len(cpy.Uints) != len(test.Uints) {\n\t\tt.Errorf(\"Uints: len was %d; want %d\", len(cpy.Uints), len(test.Uints))\n\t\tgoto Uint8s\n\t}\n\tfor i, v := range test.Uints {\n\t\tif v != cpy.Uints[i] {\n\t\t\tt.Errorf(\"Uints: got %v at index %d of the copy; want %v\", cpy.Uints[i], i, v)\n\t\t}\n\t}\n\nUint8s:\n\tif cpy.Uint8 != test.Uint8 {\n\t\tt.Errorf(\"Uint8: got %v; want %v\", cpy.Uint8, test.Uint8)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Uint8s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Uint8s)).Data {\n\t\tt.Error(\"Uint8s: address of copy was the same as original; they should be different\")\n\t\tgoto Uint16s\n\t}\n\tif len(cpy.Uint8s) != len(test.Uint8s) {\n\t\tt.Errorf(\"Uint8s: len was %d; want %d\", len(cpy.Uint8s), len(test.Uint8s))\n\t\tgoto Uint16s\n\t}\n\tfor i, v := range test.Uint8s {\n\t\tif v != cpy.Uint8s[i] {\n\t\t\tt.Errorf(\"Uint8s: got %v at index %d of the copy; want %v\", cpy.Uint8s[i], i, v)\n\t\t}\n\t}\n\nUint16s:\n\tif cpy.Uint16 != test.Uint16 {\n\t\tt.Errorf(\"Uint16: got %v; want %v\", cpy.Uint16, test.Uint16)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Uint16s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Uint16s)).Data {\n\t\tt.Error(\"Uint16s: address of copy was the same as original; they should be different\")\n\t\tgoto Uint32s\n\t}\n\tif len(cpy.Uint16s) != len(test.Uint16s) {\n\t\tt.Errorf(\"Uint16s: len was %d; want %d\", len(cpy.Uint16s), len(test.Uint16s))\n\t\tgoto Uint32s\n\t}\n\tfor i, v := range test.Uint16s {\n\t\tif v != cpy.Uint16s[i] {\n\t\t\tt.Errorf(\"Uint16s: got %v at index %d of the copy; want %v\", cpy.Uint16s[i], i, v)\n\t\t}\n\t}\n\nUint32s:\n\tif cpy.Uint32 != test.Uint32 {\n\t\tt.Errorf(\"Uint32: got %v; want %v\", cpy.Uint32, test.Uint32)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Uint32s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Uint32s)).Data {\n\t\tt.Error(\"Uint32s: address of copy was the same as original; they should be different\")\n\t\tgoto Uint64s\n\t}\n\tif len(cpy.Uint32s) != len(test.Uint32s) {\n\t\tt.Errorf(\"Uint32s: len was %d; want %d\", len(cpy.Uint32s), len(test.Uint32s))\n\t\tgoto Uint64s\n\t}\n\tfor i, v := range test.Uint32s {\n\t\tif v != cpy.Uint32s[i] {\n\t\t\tt.Errorf(\"Uint32s: got %v at index %d of the copy; want %v\", cpy.Uint32s[i], i, v)\n\t\t}\n\t}\n\nUint64s:\n\tif cpy.Uint64 != test.Uint64 {\n\t\tt.Errorf(\"Uint64: got %v; want %v\", cpy.Uint64, test.Uint64)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Uint64s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Uint64s)).Data {\n\t\tt.Error(\"Uint64s: address of copy was the same as original; they should be different\")\n\t\tgoto Float32s\n\t}\n\tif len(cpy.Uint64s) != len(test.Uint64s) {\n\t\tt.Errorf(\"Uint64s: len was %d; want %d\", len(cpy.Uint64s), len(test.Uint64s))\n\t\tgoto Float32s\n\t}\n\tfor i, v := range test.Uint64s {\n\t\tif v != cpy.Uint64s[i] {\n\t\t\tt.Errorf(\"Uint64s: got %v at index %d of the copy; want %v\", cpy.Uint64s[i], i, v)\n\t\t}\n\t}\n\nFloat32s:\n\tif cpy.Float32 != test.Float32 {\n\t\tt.Errorf(\"Float32: got %v; want %v\", cpy.Float32, test.Float32)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Float32s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Float32s)).Data {\n\t\tt.Error(\"Float32s: address of copy was the same as original; they should be different\")\n\t\tgoto Float64s\n\t}\n\tif len(cpy.Float32s) != len(test.Float32s) {\n\t\tt.Errorf(\"Float32s: len was %d; want %d\", len(cpy.Float32s), len(test.Float32s))\n\t\tgoto Float64s\n\t}\n\tfor i, v := range test.Float32s {\n\t\tif v != cpy.Float32s[i] {\n\t\t\tt.Errorf(\"Float32s: got %v at index %d of the copy; want %v\", cpy.Float32s[i], i, v)\n\t\t}\n\t}\n\nFloat64s:\n\tif cpy.Float64 != test.Float64 {\n\t\tt.Errorf(\"Float64: got %v; want %v\", cpy.Float64, test.Float64)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Float64s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Float64s)).Data {\n\t\tt.Error(\"Float64s: address of copy was the same as original; they should be different\")\n\t\tgoto Complex64s\n\t}\n\tif len(cpy.Float64s) != len(test.Float64s) {\n\t\tt.Errorf(\"Float64s: len was %d; want %d\", len(cpy.Float64s), len(test.Float64s))\n\t\tgoto Complex64s\n\t}\n\tfor i, v := range test.Float64s {\n\t\tif v != cpy.Float64s[i] {\n\t\t\tt.Errorf(\"Float64s: got %v at index %d of the copy; want %v\", cpy.Float64s[i], i, v)\n\t\t}\n\t}\n\nComplex64s:\n\tif cpy.Complex64 != test.Complex64 {\n\t\tt.Errorf(\"Complex64: got %v; want %v\", cpy.Complex64, test.Complex64)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Complex64s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Complex64s)).Data {\n\t\tt.Error(\"Complex64s: address of copy was the same as original; they should be different\")\n\t\tgoto Complex128s\n\t}\n\tif len(cpy.Complex64s) != len(test.Complex64s) {\n\t\tt.Errorf(\"Complex64s: len was %d; want %d\", len(cpy.Complex64s), len(test.Complex64s))\n\t\tgoto Complex128s\n\t}\n\tfor i, v := range test.Complex64s {\n\t\tif v != cpy.Complex64s[i] {\n\t\t\tt.Errorf(\"Complex64s: got %v at index %d of the copy; want %v\", cpy.Complex64s[i], i, v)\n\t\t}\n\t}\n\nComplex128s:\n\tif cpy.Complex128 != test.Complex128 {\n\t\tt.Errorf(\"Complex128s: got %v; want %v\", cpy.Complex128s, test.Complex128s)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Complex128s)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Complex128s)).Data {\n\t\tt.Error(\"Complex128s: address of copy was the same as original; they should be different\")\n\t\tgoto Interfaces\n\t}\n\tif len(cpy.Complex128s) != len(test.Complex128s) {\n\t\tt.Errorf(\"Complex128s: len was %d; want %d\", len(cpy.Complex128s), len(test.Complex128s))\n\t\tgoto Interfaces\n\t}\n\tfor i, v := range test.Complex128s {\n\t\tif v != cpy.Complex128s[i] {\n\t\t\tt.Errorf(\"Complex128s: got %v at index %d of the copy; want %v\", cpy.Complex128s[i], i, v)\n\t\t}\n\t}\n\nInterfaces:\n\tif cpy.Interface != test.Interface {\n\t\tt.Errorf(\"Interface: got %v; want %v\", cpy.Interface, test.Interface)\n\t}\n\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&test.Interfaces)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.Interfaces)).Data {\n\t\tt.Error(\"Interfaces: address of copy was the same as original; they should be different\")\n\t\treturn\n\t}\n\tif len(cpy.Interfaces) != len(test.Interfaces) {\n\t\tt.Errorf(\"Interfaces: len was %d; want %d\", len(cpy.Interfaces), len(test.Interfaces))\n\t\treturn\n\t}\n\tfor i, v := range test.Interfaces {\n\t\tif v != cpy.Interfaces[i] {\n\t\t\tt.Errorf(\"Interfaces: got %v at index %d of the copy; want %v\", cpy.Interfaces[i], i, v)\n\t\t}\n\t}\n}\n\n// not meant to be exhaustive\nfunc TestComplexSlices(t *testing.T) {\n\torig3Int := [][][]int{{{1, 2, 3}, {11, 22, 33}}, {{7, 8, 9}, {66, 77, 88, 99}}}\n\tcpyI := Copy(orig3Int).([][][]int)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&orig3Int)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyI)).Data {\n\t\tt.Error(\"[][][]int: address of copy was the same as original; they should be different\")\n\t\treturn\n\t}\n\tif len(orig3Int) != len(cpyI) {\n\t\tt.Errorf(\"[][][]int: len of copy was %d; want %d\", len(cpyI), len(orig3Int))\n\t\tgoto sliceMap\n\t}\n\tfor i, v := range orig3Int {\n\t\tif len(v) != len(cpyI[i]) {\n\t\t\tt.Errorf(\"[][][]int: len of element %d was %d; want %d\", i, len(cpyI[i]), len(v))\n\t\t\tcontinue\n\t\t}\n\t\tfor j, vv := range v {\n\t\t\tif len(vv) != len(cpyI[i][j]) {\n\t\t\t\tt.Errorf(\"[][][]int: len of element %d:%d was %d, want %d\", i, j, len(cpyI[i][j]), len(vv))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor k, vvv := range vv {\n\t\t\t\tif vvv != cpyI[i][j][k] {\n\t\t\t\t\tt.Errorf(\"[][][]int: element %d:%d:%d was %d, want %d\", i, j, k, cpyI[i][j][k], vvv)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\nsliceMap:\n\tslMap := []map[int]string{{0: \"a\", 1: \"b\"}, {10: \"k\", 11: \"l\", 12: \"m\"}}\n\tcpyM := Copy(slMap).([]map[int]string)\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&slMap)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpyM)).Data {\n\t\tt.Error(\"[]map[int]string: address of copy was the same as original; they should be different\")\n\t}\n\tif len(slMap) != len(cpyM) {\n\t\tt.Errorf(\"[]map[int]string: len of copy was %d; want %d\", len(cpyM), len(slMap))\n\t\tgoto done\n\t}\n\tfor i, v := range slMap {\n\t\tif len(v) != len(cpyM[i]) {\n\t\t\tt.Errorf(\"[]map[int]string: len of element %d was %d; want %d\", i, len(cpyM[i]), len(v))\n\t\t\tcontinue\n\t\t}\n\t\tfor k, vv := range v {\n\t\t\tval, ok := cpyM[i][k]\n\t\t\tif !ok {\n\t\t\t\tt.Errorf(\"[]map[int]string: element %d was expected to have a value at key %d, it didn't\", i, k)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif val != vv {\n\t\t\t\tt.Errorf(\"[]map[int]string: element %d, key %d: got %s, want %s\", i, k, val, vv)\n\t\t\t}\n\t\t}\n\t}\ndone:\n}\n\ntype A struct {\n\tInt    int\n\tString string\n\tUintSl []uint\n\tNilSl  []string\n\tMap    map[string]int\n\tMapB   map[string]*B\n\tSliceB []B\n\tB\n\tT time.Time\n}\n\ntype B struct {\n\tVals []string\n}\n\nvar AStruct = A{\n\tInt:    42,\n\tString: \"Konichiwa\",\n\tUintSl: []uint{0, 1, 2, 3},\n\tMap:    map[string]int{\"a\": 1, \"b\": 2},\n\tMapB: map[string]*B{\n\t\t\"hi\":  {Vals: []string{\"hello\", \"bonjour\"}},\n\t\t\"bye\": {Vals: []string{\"good-bye\", \"au revoir\"}},\n\t},\n\tSliceB: []B{\n\t\t{Vals: []string{\"Ciao\", \"Aloha\"}},\n\t},\n\tB: B{Vals: []string{\"42\"}},\n\tT: time.Now(),\n}\n\nfunc TestStructA(t *testing.T) {\n\tcpy := Copy(AStruct).(A)\n\tif &cpy == &AStruct {\n\t\tt.Error(\"expected copy to have a different address than the original; it was the same\")\n\t\treturn\n\t}\n\tif cpy.Int != AStruct.Int {\n\t\tt.Errorf(\"A.Int: got %v, want %v\", cpy.Int, AStruct.Int)\n\t}\n\tif cpy.String != AStruct.String {\n\t\tt.Errorf(\"A.String: got %v; want %v\", cpy.String, AStruct.String)\n\t}\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&cpy.UintSl)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&AStruct.UintSl)).Data {\n\t\tt.Error(\"A.Uintsl: expected the copies address to be different; it wasn't\")\n\t\tgoto NilSl\n\t}\n\tif len(cpy.UintSl) != len(AStruct.UintSl) {\n\t\tt.Errorf(\"A.UintSl: got len of %d, want %d\", len(cpy.UintSl), len(AStruct.UintSl))\n\t\tgoto NilSl\n\t}\n\tfor i, v := range AStruct.UintSl {\n\t\tif cpy.UintSl[i] != v {\n\t\t\tt.Errorf(\"A.UintSl %d: got %d, want %d\", i, cpy.UintSl[i], v)\n\t\t}\n\t}\n\nNilSl:\n\tif cpy.NilSl != nil {\n\t\tt.Error(\"A.NilSl: expected slice to be nil, it wasn't\")\n\t}\n\n\tif *(*uintptr)(unsafe.Pointer(&cpy.Map)) == *(*uintptr)(unsafe.Pointer(&AStruct.Map)) {\n\t\tt.Error(\"A.Map: expected the copy's address to be different; it wasn't\")\n\t\tgoto AMapB\n\t}\n\tif len(cpy.Map) != len(AStruct.Map) {\n\t\tt.Errorf(\"A.Map: got len of %d, want %d\", len(cpy.Map), len(AStruct.Map))\n\t\tgoto AMapB\n\t}\n\tfor k, v := range AStruct.Map {\n\t\tval, ok := cpy.Map[k]\n\t\tif !ok {\n\t\t\tt.Errorf(\"A.Map: expected the key %s to exist in the copy, it didn't\", k)\n\t\t\tcontinue\n\t\t}\n\t\tif val != v {\n\t\t\tt.Errorf(\"A.Map[%s]: got %d, want %d\", k, val, v)\n\t\t}\n\t}\n\nAMapB:\n\tif *(*uintptr)(unsafe.Pointer(&cpy.MapB)) == *(*uintptr)(unsafe.Pointer(&AStruct.MapB)) {\n\t\tt.Error(\"A.MapB: expected the copy's address to be different; it wasn't\")\n\t\tgoto ASliceB\n\t}\n\tif len(cpy.MapB) != len(AStruct.MapB) {\n\t\tt.Errorf(\"A.MapB: got len of %d, want %d\", len(cpy.MapB), len(AStruct.MapB))\n\t\tgoto ASliceB\n\t}\n\tfor k, v := range AStruct.MapB {\n\t\tval, ok := cpy.MapB[k]\n\t\tif !ok {\n\t\t\tt.Errorf(\"A.MapB: expected the key %s to exist in the copy, it didn't\", k)\n\t\t\tcontinue\n\t\t}\n\t\tif unsafe.Pointer(val) == unsafe.Pointer(v) {\n\t\t\tt.Errorf(\"A.MapB[%s]: expected the addresses of the values to be different; they weren't\", k)\n\t\t\tcontinue\n\t\t}\n\t\t// the slice headers should point to different data\n\t\tif (*reflect.SliceHeader)(unsafe.Pointer(&v.Vals)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&val.Vals)).Data {\n\t\t\tt.Errorf(\"%s: expected B's SliceHeaders to point to different Data locations; they did not.\", k)\n\t\t\tcontinue\n\t\t}\n\t\tfor i, vv := range v.Vals {\n\t\t\tif vv != val.Vals[i] {\n\t\t\t\tt.Errorf(\"A.MapB[%s].Vals[%d]: got %s want %s\", k, i, vv, val.Vals[i])\n\t\t\t}\n\t\t}\n\t}\n\nASliceB:\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&AStruct.SliceB)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.SliceB)).Data {\n\t\tt.Error(\"A.SliceB: expected the copy's address to be different; it wasn't\")\n\t\tgoto B\n\t}\n\n\tif len(AStruct.SliceB) != len(cpy.SliceB) {\n\t\tt.Errorf(\"A.SliceB: got length of %d; want %d\", len(cpy.SliceB), len(AStruct.SliceB))\n\t\tgoto B\n\t}\n\n\tfor i := range AStruct.SliceB {\n\t\tif unsafe.Pointer(&AStruct.SliceB[i]) == unsafe.Pointer(&cpy.SliceB[i]) {\n\t\t\tt.Errorf(\"A.SliceB[%d]: expected them to have different addresses, they didn't\", i)\n\t\t\tcontinue\n\t\t}\n\t\tif (*reflect.SliceHeader)(unsafe.Pointer(&AStruct.SliceB[i].Vals)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.SliceB[i].Vals)).Data {\n\t\t\tt.Errorf(\"A.SliceB[%d]: expected B.Vals SliceHeader.Data to point to different locations; they did not\", i)\n\t\t\tcontinue\n\t\t}\n\t\tif len(AStruct.SliceB[i].Vals) != len(cpy.SliceB[i].Vals) {\n\t\t\tt.Errorf(\"A.SliceB[%d]: expected B's vals to have the same length, they didn't\", i)\n\t\t\tcontinue\n\t\t}\n\t\tfor j, val := range AStruct.SliceB[i].Vals {\n\t\t\tif val != cpy.SliceB[i].Vals[j] {\n\t\t\t\tt.Errorf(\"A.SliceB[%d].Vals[%d]: got %v; want %v\", i, j, cpy.SliceB[i].Vals[j], val)\n\t\t\t}\n\t\t}\n\t}\nB:\n\tif unsafe.Pointer(&AStruct.B) == unsafe.Pointer(&cpy.B) {\n\t\tt.Error(\"A.B: expected them to have different addresses, they didn't\")\n\t\tgoto T\n\t}\n\tif (*reflect.SliceHeader)(unsafe.Pointer(&AStruct.B.Vals)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&cpy.B.Vals)).Data {\n\t\tt.Error(\"A.B.Vals: expected the SliceHeaders.Data to point to different locations; they didn't\")\n\t\tgoto T\n\t}\n\tif len(AStruct.B.Vals) != len(cpy.B.Vals) {\n\t\tt.Error(\"A.B.Vals: expected their lengths to be the same, they weren't\")\n\t\tgoto T\n\t}\n\tfor i, v := range AStruct.B.Vals {\n\t\tif v != cpy.B.Vals[i] {\n\t\t\tt.Errorf(\"A.B.Vals[%d]: got %s want %s\", i, cpy.B.Vals[i], v)\n\t\t}\n\t}\nT:\n\tif fmt.Sprintf(\"%p\", &AStruct.T) == fmt.Sprintf(\"%p\", &cpy.T) {\n\t\tt.Error(\"A.T: expected them to have different addresses, they didn't\")\n\t\treturn\n\t}\n\tif AStruct.T != cpy.T {\n\t\tt.Errorf(\"A.T: got %v, want %v\", cpy.T, AStruct.T)\n\t}\n}\n\ntype Unexported struct {\n\tA  string\n\tB  int\n\taa string\n\tbb int\n\tcc []int\n\tdd map[string]string\n}\n\nfunc TestUnexportedFields(t *testing.T) {\n\tu := &Unexported{\n\t\tA:  \"A\",\n\t\tB:  42,\n\t\taa: \"aa\",\n\t\tbb: 42,\n\t\tcc: []int{1, 2, 3},\n\t\tdd: map[string]string{\"hello\": \"bonjour\"},\n\t}\n\tcpy := Copy(u).(*Unexported)\n\tif cpy == u {\n\t\tt.Error(\"expected addresses to be different, they weren't\")\n\t\treturn\n\t}\n\tif u.A != cpy.A {\n\t\tt.Errorf(\"Unexported.A: got %s want %s\", cpy.A, u.A)\n\t}\n\tif u.B != cpy.B {\n\t\tt.Errorf(\"Unexported.A: got %d want %d\", cpy.B, u.B)\n\t}\n\tif cpy.aa != \"\" {\n\t\tt.Errorf(\"Unexported.aa: unexported field should not be set, it was set to %s\", cpy.aa)\n\t}\n\tif cpy.bb != 0 {\n\t\tt.Errorf(\"Unexported.bb: unexported field should not be set, it was set to %d\", cpy.bb)\n\t}\n\tif cpy.cc != nil {\n\t\tt.Errorf(\"Unexported.cc: unexported field should not be set, it was set to %#v\", cpy.cc)\n\t}\n\tif cpy.dd != nil {\n\t\tt.Errorf(\"Unexported.dd: unexported field should not be set, it was set to %#v\", cpy.dd)\n\t}\n}\n\n// Note: this test will fail until https://github.com/golang/go/issues/15716 is\n// fixed and the version it is part of gets released.\ntype T struct {\n\ttime.Time\n}\n\nfunc TestTimeCopy(t *testing.T) {\n\ttests := []struct {\n\t\tY    int\n\t\tM    time.Month\n\t\tD    int\n\t\th    int\n\t\tm    int\n\t\ts    int\n\t\tnsec int\n\t\tTZ   string\n\t}{\n\t\t{2016, time.July, 4, 23, 11, 33, 3000, \"America/New_York\"},\n\t\t{2015, time.October, 31, 9, 44, 23, 45935, \"UTC\"},\n\t\t{2014, time.May, 5, 22, 01, 50, 219300, \"Europe/Prague\"},\n\t}\n\n\tfor i, test := range tests {\n\t\tl, err := time.LoadLocation(test.TZ)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"%d: unexpected error: %s\", i, err)\n\t\t\tcontinue\n\t\t}\n\t\tvar x T\n\t\tx.Time = time.Date(test.Y, test.M, test.D, test.h, test.m, test.s, test.nsec, l)\n\t\tc := Copy(x).(T)\n\t\tif fmt.Sprintf(\"%p\", &c) == fmt.Sprintf(\"%p\", &x) {\n\t\t\tt.Errorf(\"%d: expected the copy to have a different address than the original value; they were the same: %p %p\", i, &c, &x)\n\t\t\tcontinue\n\t\t}\n\t\tif x.UnixNano() != c.UnixNano() {\n\t\t\tt.Errorf(\"%d: nanotime: got %v; want %v\", i, c.UnixNano(), x.UnixNano())\n\t\t\tcontinue\n\t\t}\n\t\tif x.Location() != c.Location() {\n\t\t\tt.Errorf(\"%d: location: got %q; want %q\", i, c.Location(), x.Location())\n\t\t}\n\t}\n}\n\nfunc TestPointerToStruct(t *testing.T) {\n\ttype Foo struct {\n\t\tBar int\n\t}\n\n\tf := &Foo{Bar: 42}\n\tcpy := Copy(f)\n\tif f == cpy {\n\t\tt.Errorf(\"expected copy to point to a different location: orig: %p; copy: %p\", f, cpy)\n\t}\n\tif !reflect.DeepEqual(f, cpy) {\n\t\tt.Errorf(\"expected the copy to be equal to the original (except for memory location); it wasn't: got %#v; want %#v\", f, cpy)\n\t}\n}\n\nfunc Test_Issue9(t *testing.T) {\n\t// simple pointer copy\n\tx := 42\n\ttestA := map[string]*int{\n\t\t\"a\": nil,\n\t\t\"b\": &x,\n\t}\n\tcopyA := Copy(testA).(map[string]*int)\n\tif unsafe.Pointer(&testA) == unsafe.Pointer(&copyA) {\n\t\tt.Fatalf(\"expected the map pointers to be different: testA: %v\\tcopyA: %v\", unsafe.Pointer(&testA), unsafe.Pointer(&copyA))\n\t}\n\tif !reflect.DeepEqual(testA, copyA) {\n\t\tt.Errorf(\"got %#v; want %#v\", copyA, testA)\n\t}\n\tif testA[\"b\"] == copyA[\"b\"] {\n\t\tt.Errorf(\"entries for 'b' pointed to the same address: %v; expected them to point to different addresses\", testA[\"b\"])\n\t}\n\n\t// map copy\n\ttype Foo struct {\n\t\tAlpha string\n\t}\n\n\ttype Bar struct {\n\t\tBeta  string\n\t\tGamma int\n\t\tDelta *Foo\n\t}\n\n\ttype Biz struct {\n\t\tEpsilon map[int]*Bar\n\t}\n\n\ttestB := Biz{\n\t\tEpsilon: map[int]*Bar{\n\t\t\t0: {},\n\t\t\t1: {\n\t\t\t\tBeta:  \"don't panic\",\n\t\t\t\tGamma: 42,\n\t\t\t\tDelta: nil,\n\t\t\t},\n\t\t\t2: {\n\t\t\t\tBeta:  \"sudo make me a sandwich.\",\n\t\t\t\tGamma: 11,\n\t\t\t\tDelta: &Foo{\n\t\t\t\t\tAlpha: \"okay.\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tcopyB := Copy(testB).(Biz)\n\tif !reflect.DeepEqual(testB, copyB) {\n\t\tt.Errorf(\"got %#v; want %#v\", copyB, testB)\n\t\treturn\n\t}\n\n\t// check that the maps point to different locations\n\tif unsafe.Pointer(&testB.Epsilon) == unsafe.Pointer(&copyB.Epsilon) {\n\t\tt.Fatalf(\"expected the map pointers to be different; they weren't: testB: %v\\tcopyB: %v\", unsafe.Pointer(&testB.Epsilon), unsafe.Pointer(&copyB.Epsilon))\n\t}\n\n\tfor k, v := range testB.Epsilon {\n\t\tif v == nil && copyB.Epsilon[k] == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif v == nil && copyB.Epsilon[k] != nil {\n\t\t\tt.Errorf(\"%d: expected copy of a nil entry to be nil; it wasn't: %#v\", k, copyB.Epsilon[k])\n\t\t\tcontinue\n\t\t}\n\t\tif v == copyB.Epsilon[k] {\n\t\t\tt.Errorf(\"entries for '%d' pointed to the same address: %v; expected them to point to different addresses\", k, v)\n\t\t\tcontinue\n\t\t}\n\t\tif v.Beta != copyB.Epsilon[k].Beta {\n\t\t\tt.Errorf(\"%d.Beta: got %q; want %q\", k, copyB.Epsilon[k].Beta, v.Beta)\n\t\t}\n\t\tif v.Gamma != copyB.Epsilon[k].Gamma {\n\t\t\tt.Errorf(\"%d.Gamma: got %d; want %d\", k, copyB.Epsilon[k].Gamma, v.Gamma)\n\t\t}\n\t\tif v.Delta == nil && copyB.Epsilon[k].Delta == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif v.Delta == nil && copyB.Epsilon[k].Delta != nil {\n\t\t\tt.Errorf(\"%d.Delta: got %#v; want nil\", k, copyB.Epsilon[k].Delta)\n\t\t}\n\t\tif v.Delta == copyB.Epsilon[k].Delta {\n\t\t\tt.Errorf(\"%d.Delta: expected the pointers to be different, they were the same: %v\", k, v.Delta)\n\t\t\tcontinue\n\t\t}\n\t\tif v.Delta.Alpha != copyB.Epsilon[k].Delta.Alpha {\n\t\t\tt.Errorf(\"%d.Delta.Foo: got %q; want %q\", k, v.Delta.Alpha, copyB.Epsilon[k].Delta.Alpha)\n\t\t}\n\t}\n\n\t// test that map keys are deep copied\n\ttestC := map[*Foo][]string{\n\t\t{Alpha: \"Henry Dorsett Case\"}: {\n\t\t\t\"Cutter\",\n\t\t},\n\t\t{Alpha: \"Molly Millions\"}: {\n\t\t\t\"Rose Kolodny\",\n\t\t\t\"Cat Mother\",\n\t\t\t\"Steppin' Razor\",\n\t\t},\n\t}\n\n\tcopyC := Copy(testC).(map[*Foo][]string)\n\tif unsafe.Pointer(&testC) == unsafe.Pointer(&copyC) {\n\t\tt.Fatalf(\"expected the map pointers to be different; they weren't: testB: %v\\tcopyB: %v\", unsafe.Pointer(&testB.Epsilon), unsafe.Pointer(&copyB.Epsilon))\n\t}\n\n\t// make sure the lengths are the same\n\tif len(testC) != len(copyC) {\n\t\tt.Fatalf(\"got len %d; want %d\", len(copyC), len(testC))\n\t}\n\n\t// check that everything was deep copied: since the key is a pointer, we check to\n\t// see if the pointers are different but the values being pointed to are the same.\n\tfor k, v := range testC {\n\t\tfor kk, vv := range copyC {\n\t\t\tif *kk == *k {\n\t\t\t\tif kk == k {\n\t\t\t\t\tt.Errorf(\"key pointers should be different: orig: %p; copy: %p\", k, kk)\n\t\t\t\t}\n\t\t\t\t// check that the slices are the same but different\n\t\t\t\tif !reflect.DeepEqual(v, vv) {\n\t\t\t\t\tt.Errorf(\"expected slice contents to be the same; they weren't: orig: %v; copy: %v\", v, vv)\n\t\t\t\t}\n\n\t\t\t\tif (*reflect.SliceHeader)(unsafe.Pointer(&v)).Data == (*reflect.SliceHeader)(unsafe.Pointer(&vv)).Data {\n\t\t\t\t\tt.Errorf(\"expected the SliceHeaders.Data to point to different locations; they didn't: %v\", (*reflect.SliceHeader)(unsafe.Pointer(&v)).Data)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\ttype Bizz struct {\n\t\t*Foo\n\t}\n\n\ttestD := map[Bizz]string{\n\t\t{&Foo{\"Neuromancer\"}}: \"Rio\",\n\t\t{&Foo{\"Wintermute\"}}:  \"Berne\",\n\t}\n\tcopyD := Copy(testD).(map[Bizz]string)\n\tif len(copyD) != len(testD) {\n\t\tt.Fatalf(\"copy had %d elements; expected %d\", len(copyD), len(testD))\n\t}\n\n\tfor k, v := range testD {\n\t\tvar found bool\n\t\tfor kk, vv := range copyD {\n\t\t\tif reflect.DeepEqual(k, kk) {\n\t\t\t\tfound = true\n\t\t\t\t// check that Foo points to different locations\n\t\t\t\tif unsafe.Pointer(k.Foo) == unsafe.Pointer(kk.Foo) {\n\t\t\t\t\tt.Errorf(\"Expected Foo to point to different locations; they didn't: orig: %p; copy %p\", k.Foo, kk.Foo)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif *k.Foo != *kk.Foo {\n\t\t\t\t\tt.Errorf(\"Expected copy of the key's Foo field to have the same value as the original, it wasn't: orig: %#v; copy: %#v\", k.Foo, kk.Foo)\n\t\t\t\t}\n\t\t\t\tif v != vv {\n\t\t\t\t\tt.Errorf(\"Expected the values to be the same; the weren't: got %v; want %v\", vv, v)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tt.Errorf(\"expected key %v to exist in the copy; it didn't\", k)\n\t\t}\n\t}\n}\n\ntype I struct {\n\tA string\n}\n\nfunc (i *I) DeepCopy() any {\n\treturn &I{A: \"custom copy\"}\n}\n\ntype NestI struct {\n\tI *I\n}\n\nfunc TestInterface(t *testing.T) {\n\ti := &I{A: \"A\"}\n\tcopied := Copy(i).(*I)\n\tif copied.A != \"custom copy\" {\n\t\tt.Errorf(\"expected value %v, but it's %v\", \"custom copy\", copied.A)\n\t}\n\t// check for nesting values\n\tni := &NestI{I: &I{A: \"A\"}}\n\tcopiedNest := Copy(ni).(*NestI)\n\tif copiedNest.I.A != \"custom copy\" {\n\t\tt.Errorf(\"expected value %v, but it's %v\", \"custom copy\", copiedNest.I.A)\n\t}\n}\n"
  },
  {
    "path": "internal/empty/empty.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package empty provides functions for checking empty/nil variables.\npackage empty\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n)\n\n// iString is used for type assert api for String().\ntype iString interface {\n\tString() string\n}\n\n// iInterfaces is used for type assert api for Interfaces.\ntype iInterfaces interface {\n\tInterfaces() []any\n}\n\n// iMapStrAny is the interface support for converting struct parameter to map.\ntype iMapStrAny interface {\n\tMapStrAny() map[string]any\n}\n\ntype iTime interface {\n\tDate() (year int, month time.Month, day int)\n\tIsZero() bool\n}\n\n// IsEmpty checks whether given `value` empty.\n// It returns true if `value` is in: 0, nil, false, \"\", len(slice/map/chan) == 0,\n// or else it returns false.\n//\n// The parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer\n// that also points to a pointer. It returns true if the source is empty when `traceSource` is true.\n// Note that it might use reflect feature which affects performance a little.\nfunc IsEmpty(value any, traceSource ...bool) bool {\n\tif value == nil {\n\t\treturn true\n\t}\n\t// It firstly checks the variable as common types using assertion to enhance the performance,\n\t// and then using reflection.\n\tswitch result := value.(type) {\n\tcase int:\n\t\treturn result == 0\n\tcase int8:\n\t\treturn result == 0\n\tcase int16:\n\t\treturn result == 0\n\tcase int32:\n\t\treturn result == 0\n\tcase int64:\n\t\treturn result == 0\n\tcase uint:\n\t\treturn result == 0\n\tcase uint8:\n\t\treturn result == 0\n\tcase uint16:\n\t\treturn result == 0\n\tcase uint32:\n\t\treturn result == 0\n\tcase uint64:\n\t\treturn result == 0\n\tcase float32:\n\t\treturn result == 0\n\tcase float64:\n\t\treturn result == 0\n\tcase bool:\n\t\treturn !result\n\tcase string:\n\t\treturn result == \"\"\n\tcase []byte:\n\t\treturn len(result) == 0\n\tcase []rune:\n\t\treturn len(result) == 0\n\tcase []int:\n\t\treturn len(result) == 0\n\tcase []string:\n\t\treturn len(result) == 0\n\tcase []float32:\n\t\treturn len(result) == 0\n\tcase []float64:\n\t\treturn len(result) == 0\n\tcase map[string]any:\n\t\treturn len(result) == 0\n\n\tdefault:\n\t\t// Finally, using reflect.\n\t\tvar rv reflect.Value\n\t\tif v, ok := value.(reflect.Value); ok {\n\t\t\trv = v\n\t\t} else {\n\t\t\trv = reflect.ValueOf(value)\n\t\t\tif IsNil(rv) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// =========================\n\t\t\t// Common interfaces checks.\n\t\t\t// =========================\n\t\t\tif f, ok := value.(iTime); ok {\n\t\t\t\tif f == (*time.Time)(nil) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn f.IsZero()\n\t\t\t}\n\t\t\tif f, ok := value.(iString); ok {\n\t\t\t\tif f == nil {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn f.String() == \"\"\n\t\t\t}\n\t\t\tif f, ok := value.(iInterfaces); ok {\n\t\t\t\tif f == nil {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn len(f.Interfaces()) == 0\n\t\t\t}\n\t\t\tif f, ok := value.(iMapStrAny); ok {\n\t\t\t\tif f == nil {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn len(f.MapStrAny()) == 0\n\t\t\t}\n\t\t}\n\n\t\tswitch rv.Kind() {\n\t\tcase reflect.Bool:\n\t\t\treturn !rv.Bool()\n\n\t\tcase\n\t\t\treflect.Int,\n\t\t\treflect.Int8,\n\t\t\treflect.Int16,\n\t\t\treflect.Int32,\n\t\t\treflect.Int64:\n\t\t\treturn rv.Int() == 0\n\n\t\tcase\n\t\t\treflect.Uint,\n\t\t\treflect.Uint8,\n\t\t\treflect.Uint16,\n\t\t\treflect.Uint32,\n\t\t\treflect.Uint64,\n\t\t\treflect.Uintptr:\n\t\t\treturn rv.Uint() == 0\n\n\t\tcase\n\t\t\treflect.Float32,\n\t\t\treflect.Float64:\n\t\t\treturn rv.Float() == 0\n\n\t\tcase reflect.String:\n\t\t\treturn rv.Len() == 0\n\n\t\tcase reflect.Struct:\n\t\t\tvar fieldValueInterface any\n\t\t\tfor i := 0; i < rv.NumField(); i++ {\n\t\t\t\tfieldValueInterface, _ = reflection.ValueToInterface(rv.Field(i))\n\t\t\t\tif !IsEmpty(fieldValueInterface) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\n\t\tcase\n\t\t\treflect.Chan,\n\t\t\treflect.Map,\n\t\t\treflect.Slice,\n\t\t\treflect.Array:\n\t\t\treturn rv.Len() == 0\n\n\t\tcase reflect.Pointer:\n\t\t\tif len(traceSource) > 0 && traceSource[0] {\n\t\t\t\treturn IsEmpty(rv.Elem())\n\t\t\t}\n\t\t\treturn rv.IsNil()\n\n\t\tcase\n\t\t\treflect.Func,\n\t\t\treflect.Interface,\n\t\t\treflect.UnsafePointer:\n\t\t\treturn rv.IsNil()\n\n\t\tcase reflect.Invalid:\n\t\t\treturn true\n\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t}\n}\n\n// IsNil checks whether given `value` is nil, especially for any type value.\n// Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer\n// that also points to a pointer. It returns nil if the source is nil when `traceSource` is true.\n// Note that it might use reflect feature which affects performance a little.\nfunc IsNil(value any, traceSource ...bool) bool {\n\tif value == nil {\n\t\treturn true\n\t}\n\tvar rv reflect.Value\n\tif v, ok := value.(reflect.Value); ok {\n\t\trv = v\n\t} else {\n\t\trv = reflect.ValueOf(value)\n\t}\n\tswitch rv.Kind() {\n\tcase reflect.Chan,\n\t\treflect.Map,\n\t\treflect.Slice,\n\t\treflect.Func,\n\t\treflect.Interface,\n\t\treflect.UnsafePointer:\n\t\treturn !rv.IsValid() || rv.IsNil()\n\n\tcase reflect.Pointer:\n\t\tif len(traceSource) > 0 && traceSource[0] {\n\t\t\tfor rv.Kind() == reflect.Pointer {\n\t\t\t\trv = rv.Elem()\n\t\t\t}\n\t\t\tif !rv.IsValid() {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif rv.Kind() == reflect.Pointer {\n\t\t\t\treturn rv.IsNil()\n\t\t\t}\n\t\t} else {\n\t\t\treturn !rv.IsValid() || rv.IsNil()\n\t\t}\n\n\tdefault:\n\t\treturn false\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/empty/empty_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage empty_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype TestInt int\n\ntype TestString string\n\ntype TestPerson interface {\n\tSay() string\n}\n\ntype TestWoman struct {\n}\n\nfunc (woman TestWoman) Say() string {\n\treturn \"nice\"\n}\n\nfunc TestIsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttmpT1 := \"0\"\n\t\ttmpT2 := func() {}\n\t\ttmpT2 = nil\n\t\ttmpT3 := make(chan int)\n\t\tvar (\n\t\t\ttmpT4 TestPerson  = nil\n\t\t\ttmpT5 *TestPerson = nil\n\t\t\ttmpT6 TestPerson  = TestWoman{}\n\t\t\ttmpT7 TestInt     = 0\n\t\t\ttmpT8 TestString  = \"\"\n\t\t)\n\t\ttmpF1 := \"1\"\n\t\ttmpF2 := func(a string) string { return \"1\" }\n\t\ttmpF3 := make(chan int, 1)\n\t\ttmpF3 <- 1\n\t\tvar (\n\t\t\ttmpF4 TestPerson = &TestWoman{}\n\t\t\ttmpF5 TestInt    = 1\n\t\t\ttmpF6 TestString = \"1\"\n\t\t)\n\n\t\t// true\n\t\tt.Assert(empty.IsEmpty(nil), true)\n\t\tt.Assert(empty.IsEmpty(0), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Int(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Int8(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Int16(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Int32(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Int64(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint64(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint16(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint32(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint64(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Float32(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(gconv.Float64(tmpT1)), true)\n\t\tt.Assert(empty.IsEmpty(false), true)\n\t\tt.Assert(empty.IsEmpty([]byte(\"\")), true)\n\t\tt.Assert(empty.IsEmpty(\"\"), true)\n\t\tt.Assert(empty.IsEmpty(g.Map{}), true)\n\t\tt.Assert(empty.IsEmpty(g.Slice{}), true)\n\t\tt.Assert(empty.IsEmpty(g.Array{}), true)\n\t\tt.Assert(empty.IsEmpty(tmpT2), true)\n\t\tt.Assert(empty.IsEmpty(tmpT3), true)\n\t\tt.Assert(empty.IsEmpty(tmpT3), true)\n\t\tt.Assert(empty.IsEmpty(tmpT4), true)\n\t\tt.Assert(empty.IsEmpty(tmpT5), true)\n\t\tt.Assert(empty.IsEmpty(tmpT6), true)\n\t\tt.Assert(empty.IsEmpty(tmpT7), true)\n\t\tt.Assert(empty.IsEmpty(tmpT8), true)\n\n\t\t// false\n\t\tt.Assert(empty.IsEmpty(gconv.Int(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Int8(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Int16(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Int32(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Int64(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint8(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint16(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint32(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Uint64(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Float32(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(gconv.Float64(tmpF1)), false)\n\t\tt.Assert(empty.IsEmpty(true), false)\n\t\tt.Assert(empty.IsEmpty(tmpT1), false)\n\t\tt.Assert(empty.IsEmpty([]byte(\"1\")), false)\n\t\tt.Assert(empty.IsEmpty(g.Map{\"a\": 1}), false)\n\t\tt.Assert(empty.IsEmpty(g.Slice{\"1\"}), false)\n\t\tt.Assert(empty.IsEmpty(g.Array{\"1\"}), false)\n\t\tt.Assert(empty.IsEmpty(tmpF2), false)\n\t\tt.Assert(empty.IsEmpty(tmpF3), false)\n\t\tt.Assert(empty.IsEmpty(tmpF4), false)\n\t\tt.Assert(empty.IsEmpty(tmpF5), false)\n\t\tt.Assert(empty.IsEmpty(tmpF6), false)\n\t})\n}\n\nfunc TestIsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(empty.IsNil(nil), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i int\n\t\tt.Assert(empty.IsNil(i), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i *int\n\t\tt.Assert(empty.IsNil(i), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i *int\n\t\tt.Assert(empty.IsNil(&i), false)\n\t\tt.Assert(empty.IsNil(&i, true), true)\n\t})\n}\n\ntype Issue3362St struct {\n\ttime.Time\n}\n\nfunc Test_Issue3362(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tIssue3362 *Issue3362St `json:\"issue,omitempty\"`\n\t\t}\n\t\tm := gvar.New(\n\t\t\t&A{},\n\t\t).Map(\n\t\t\tgvar.MapOption{\n\t\t\t\tOmitEmpty: true,\n\t\t\t},\n\t\t)\n\t\tt.Assert(m, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i int\n\t\tt.Assert(empty.IsNil(i), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i *int\n\t\tt.Assert(empty.IsNil(i), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i *int\n\t\tt.Assert(empty.IsNil(&i), false)\n\t\tt.Assert(empty.IsNil(&i, true), true)\n\t})\n}\n"
  },
  {
    "path": "internal/errors/errors.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package errors provides functionalities to manipulate errors for internal usage purpose.\npackage errors\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/command\"\n)\n\n// StackMode is the mode that printing stack information in StackModeBrief or StackModeDetail mode.\ntype StackMode string\n\nconst (\n\t// commandEnvKeyForBrief is the command environment name for switch key for brief error stack.\n\t//\n\t// Deprecated: use commandEnvKeyForStackMode instead.\n\tcommandEnvKeyForBrief = \"gf.gerror.brief\"\n\n\t// commandEnvKeyForStackMode is the command environment name for switch key for brief error stack.\n\tcommandEnvKeyForStackMode = \"gf.gerror.stack.mode\"\n)\n\nconst (\n\t// StackModeBrief specifies all error stacks printing no framework error stacks.\n\tStackModeBrief StackMode = \"brief\"\n\n\t// StackModeDetail specifies all error stacks printing detailed error stacks including framework stacks.\n\tStackModeDetail StackMode = \"detail\"\n)\n\n// stackModeConfigured is the configured error stack mode variable.\n// It is brief stack mode in default.\nvar stackModeConfigured = StackModeBrief\n\nfunc init() {\n\t// Deprecated.\n\tbriefSetting := command.GetOptWithEnv(commandEnvKeyForBrief)\n\tif briefSetting == \"1\" || briefSetting == \"true\" {\n\t\tstackModeConfigured = StackModeBrief\n\t}\n\n\t// The error stack mode is configured using command line arguments or environments.\n\tstackModeSetting := command.GetOptWithEnv(commandEnvKeyForStackMode)\n\tif stackModeSetting != \"\" {\n\t\tstackModeSettingMode := StackMode(stackModeSetting)\n\t\tswitch stackModeSettingMode {\n\t\tcase StackModeBrief, StackModeDetail:\n\t\t\tstackModeConfigured = stackModeSettingMode\n\t\t}\n\t}\n}\n\n// IsStackModeBrief returns whether current error stack mode is in brief mode.\nfunc IsStackModeBrief() bool {\n\treturn stackModeConfigured == StackModeBrief\n}\n"
  },
  {
    "path": "internal/errors/errors_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage errors_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/errors\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_IsStackModeBrief(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(errors.IsStackModeBrief(), true)\n\t})\n}\n"
  },
  {
    "path": "internal/fileinfo/fileinfo.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package fileinfo provides virtual os.FileInfo for given information.\npackage fileinfo\n\nimport (\n\t\"os\"\n\t\"time\"\n)\n\ntype Info struct {\n\tname    string\n\tsize    int64\n\tmode    os.FileMode\n\tmodTime time.Time\n}\n\nfunc New(name string, size int64, mode os.FileMode, modTime time.Time) *Info {\n\treturn &Info{\n\t\tname:    name,\n\t\tsize:    size,\n\t\tmode:    mode,\n\t\tmodTime: modTime,\n\t}\n}\n\nfunc (i *Info) Name() string {\n\treturn i.name\n}\n\nfunc (i *Info) Size() int64 {\n\treturn i.size\n}\n\nfunc (i *Info) IsDir() bool {\n\treturn i.mode.IsDir()\n}\n\nfunc (i *Info) Mode() os.FileMode {\n\treturn i.mode\n}\n\nfunc (i *Info) ModTime() time.Time {\n\treturn i.modTime\n}\n\nfunc (i *Info) Sys() any {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/httputil/httputils.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package httputil provides HTTP functions for internal usage only.\npackage httputil\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tfileUploadingKey = \"@file:\"\n)\n\n// BuildParams builds the request string for the http client. The `params` can be type of:\n// string/[]byte/map/struct/*struct.\n//\n// The optional parameter `noUrlEncode` specifies whether ignore the url encoding for the data.\nfunc BuildParams(params any, noUrlEncode ...bool) (encodedParamStr string) {\n\t// If given string/[]byte, converts and returns it directly as string.\n\tswitch v := params.(type) {\n\tcase string, []byte:\n\t\treturn gconv.String(params)\n\tcase []any:\n\t\tif len(v) > 0 {\n\t\t\tparams = v[0]\n\t\t} else {\n\t\t\tparams = nil\n\t\t}\n\t}\n\t// Else converts it to map and does the url encoding.\n\tm, urlEncode := gconv.Map(params, gconv.MapOption{\n\t\tOmitEmpty: true,\n\t}), true\n\tif len(m) == 0 {\n\t\treturn gconv.String(params)\n\t}\n\tif len(noUrlEncode) == 1 {\n\t\turlEncode = !noUrlEncode[0]\n\t}\n\ts := \"\"\n\tfor k, v := range m {\n\t\t// Ignore nil attributes.\n\t\tif empty.IsNil(v) {\n\t\t\tcontinue\n\t\t}\n\t\tif len(encodedParamStr) > 0 {\n\t\t\tencodedParamStr += \"&\"\n\t\t}\n\t\ts = gconv.String(v)\n\t\tif urlEncode {\n\t\t\tif strings.HasPrefix(s, fileUploadingKey) {\n\t\t\t\t// No url encoding if value starts with file uploading marker.\n\t\t\t} else {\n\t\t\t\ts = gurl.Encode(s)\n\t\t\t}\n\t\t}\n\t\tencodedParamStr += k + \"=\" + s\n\t}\n\treturn\n}\n\n// HeaderToMap coverts request headers to map.\nfunc HeaderToMap(header http.Header) map[string]any {\n\tm := make(map[string]any)\n\tfor k, v := range header {\n\t\tif len(v) > 1 {\n\t\t\tm[k] = v\n\t\t} else if len(v) == 1 {\n\t\t\tm[k] = v[0]\n\t\t}\n\t}\n\treturn m\n}\n"
  },
  {
    "path": "internal/httputil/httputils_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage httputil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc TestBuildParams(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": \"2\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(gstr.Contains(params, \"a=1\"), true)\n\t\tt.Assert(gstr.Contains(params, \"b=2\"), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": nil,\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(gstr.Contains(params, \"a=1\"), true)\n\t\tt.Assert(gstr.Contains(params, \"b=\"), false)\n\t\tt.Assert(gstr.Contains(params, \"b\"), false)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4023\nfunc TestIssue4023(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype HttpGetRequest struct {\n\t\t\tKey1 string `json:\"key1\"`\n\t\t\tKey2 string `json:\"key2,omitempty\"`\n\t\t}\n\t\tr := &HttpGetRequest{\n\t\t\tKey1: \"value1\",\n\t\t}\n\t\tparams := httputil.BuildParams(r)\n\t\tt.Assert(params, \"key1=value1\")\n\t})\n}\n\n// TestBuildParams_SpecialCharacters tests URL encoding of special characters.\nfunc TestBuildParams_SpecialCharacters(t *testing.T) {\n\t// Test special characters are properly URL encoded.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value=with=equals\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// = should be encoded as %3D\n\t\tt.Assert(gstr.Contains(params, \"key=value%3Dwith%3Dequals\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value&with&ampersand\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// & should be encoded as %26\n\t\tt.Assert(gstr.Contains(params, \"key=value%26with%26ampersand\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value with spaces\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// space should be encoded as + or %20\n\t\tt.Assert(gstr.Contains(params, \"key=value\") && gstr.Contains(params, \"with\") && gstr.Contains(params, \"spaces\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value%percent\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// % should be encoded as %25\n\t\tt.Assert(gstr.Contains(params, \"key=value%25percent\"), true)\n\t})\n}\n\n// TestBuildParams_FileUploadMarker tests that @file: prefix is not URL encoded.\nfunc TestBuildParams_FileUploadMarker(t *testing.T) {\n\t// Test @file: with path is not encoded.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"file\": \"@file:/path/to/file.txt\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// @file: should NOT be encoded\n\t\tt.Assert(gstr.Contains(params, \"file=@file:/path/to/file.txt\"), true)\n\t})\n\n\t// Test @file: without path is not encoded.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"name\": \"@file:\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// @file: alone should NOT be encoded\n\t\tt.Assert(gstr.Contains(params, \"name=@file:\"), true)\n\t})\n\n\t// Test @file: with path does not affect other fields encoding.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:/path/to/file.txt\",\n\t\t\t\"field\": \"value=1&b=2\",\n\t\t}\n\t\tparams := httputil.BuildParams(data)\n\t\t// @file: should NOT be encoded\n\t\tt.Assert(gstr.Contains(params, \"@file:/path/to/file.txt\"), true)\n\t\t// Other field's special characters SHOULD be encoded\n\t\tt.Assert(gstr.Contains(params, \"field=value%3D1%26b%3D2\"), true)\n\t})\n}\n\n// TestBuildParams_NoUrlEncode tests the noUrlEncode parameter.\nfunc TestBuildParams_NoUrlEncode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value=1&b=2\",\n\t\t}\n\t\t// With noUrlEncode = true, special characters should NOT be encoded.\n\t\tparams := httputil.BuildParams(data, true)\n\t\tt.Assert(gstr.Contains(params, \"key=value=1&b=2\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := g.Map{\n\t\t\t\"key\": \"value=1&b=2\",\n\t\t}\n\t\t// With noUrlEncode = false (default), special characters SHOULD be encoded.\n\t\tparams := httputil.BuildParams(data, false)\n\t\tt.Assert(gstr.Contains(params, \"key=value%3D1%26b%3D2\"), true)\n\t})\n}\n\n// TestBuildParams_StringInput tests string input is returned as-is.\nfunc TestBuildParams_StringInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := \"key=value&key2=value2\"\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(params, \"key=value&key2=value2\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []byte(\"key=value&key2=value2\")\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(params, \"key=value&key2=value2\")\n\t})\n}\n\n// TestBuildParams_SliceInput tests slice input.\nfunc TestBuildParams_SliceInput(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := []any{g.Map{\"a\": \"1\", \"b\": \"2\"}}\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(gstr.Contains(params, \"a=1\"), true)\n\t\tt.Assert(gstr.Contains(params, \"b=2\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Empty slice\n\t\tdata := []any{}\n\t\tparams := httputil.BuildParams(data)\n\t\tt.Assert(params, \"\")\n\t})\n}\n"
  },
  {
    "path": "internal/instance/instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package instance provides instances management.\n//\n// Note that this package is not used for cache, as it has no cache expiration.\npackage instance\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n)\n\nconst (\n\tgroupNumber = 64\n)\n\nvar (\n\tgroups = make([]*gmap.StrAnyMap, groupNumber)\n)\n\nfunc init() {\n\tfor i := 0; i < groupNumber; i++ {\n\t\tgroups[i] = gmap.NewStrAnyMap(true)\n\t}\n}\n\nfunc getGroup(key string) *gmap.StrAnyMap {\n\treturn groups[int(ghash.DJB([]byte(key))%groupNumber)]\n}\n\n// Get returns the instance by given name.\nfunc Get(name string) any {\n\treturn getGroup(name).Get(name)\n}\n\n// Set sets an instance to the instance manager with given name.\nfunc Set(name string, instance any) {\n\tgetGroup(name).Set(name, instance)\n}\n\n// GetOrSet returns the instance by name,\n// or set instance to the instance manager if it does not exist and returns this instance.\nfunc GetOrSet(name string, instance any) any {\n\treturn getGroup(name).GetOrSet(name, instance)\n}\n\n// GetOrSetFunc returns the instance by name,\n// or sets instance with returned value of callback function `f` if it does not exist\n// and then returns this instance.\nfunc GetOrSetFunc(name string, f func() any) any {\n\treturn getGroup(name).GetOrSetFunc(name, f)\n}\n\n// GetOrSetFuncLock returns the instance by name,\n// or sets instance with returned value of callback function `f` if it does not exist\n// and then returns this instance.\n//\n// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`\n// with mutex.Lock of the hash map.\nfunc GetOrSetFuncLock(name string, f func() any) any {\n\treturn getGroup(name).GetOrSetFuncLock(name, f)\n}\n\n// SetIfNotExist sets `instance` to the map if the `name` does not exist, then returns true.\n// It returns false if `name` exists, and `instance` would be ignored.\nfunc SetIfNotExist(name string, instance any) bool {\n\treturn getGroup(name).SetIfNotExist(name, instance)\n}\n\n// Clear deletes all instances stored.\nfunc Clear() {\n\tfor i := 0; i < groupNumber; i++ {\n\t\tgroups[i].Clear()\n\t}\n}\n"
  },
  {
    "path": "internal/instance/instance_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage instance_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_SetGet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tinstance.Set(\"test-user\", 1)\n\t\tt.Assert(instance.Get(\"test-user\"), 1)\n\t\tt.Assert(instance.Get(\"none-exists\"), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(instance.GetOrSet(\"test-1\", 1), 1)\n\t\tt.Assert(instance.Get(\"test-1\"), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(instance.GetOrSetFunc(\"test-2\", func() any {\n\t\t\treturn 2\n\t\t}), 2)\n\t\tt.Assert(instance.Get(\"test-2\"), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(instance.GetOrSetFuncLock(\"test-3\", func() any {\n\t\t\treturn 3\n\t\t}), 3)\n\t\tt.Assert(instance.Get(\"test-3\"), 3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(instance.SetIfNotExist(\"test-4\", 4), true)\n\t\tt.Assert(instance.Get(\"test-4\"), 4)\n\t\tt.Assert(instance.SetIfNotExist(\"test-4\", 5), false)\n\t\tt.Assert(instance.Get(\"test-4\"), 4)\n\t})\n}\n"
  },
  {
    "path": "internal/intlog/intlog.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package intlog provides internal logging for GoFrame development usage only.\npackage intlog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\nconst (\n\tstackFilterKey = \"/internal/intlog\"\n)\n\n// Print prints `v` with newline using fmt.Println.\n// The parameter `v` can be multiple variables.\nfunc Print(ctx context.Context, v ...any) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\tdoPrint(ctx, fmt.Sprint(v...), false)\n}\n\n// Printf prints `v` with format `format` using fmt.Printf.\n// The parameter `v` can be multiple variables.\nfunc Printf(ctx context.Context, format string, v ...any) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\tdoPrint(ctx, fmt.Sprintf(format, v...), false)\n}\n\n// Error prints `v` with newline using fmt.Println.\n// The parameter `v` can be multiple variables.\nfunc Error(ctx context.Context, v ...any) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\tdoPrint(ctx, fmt.Sprint(v...), true)\n}\n\n// Errorf prints `v` with format `format` using fmt.Printf.\nfunc Errorf(ctx context.Context, format string, v ...any) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\tdoPrint(ctx, fmt.Sprintf(format, v...), true)\n}\n\n// PrintFunc prints the output from function `f`.\n// It only calls function `f` if debug mode is enabled.\nfunc PrintFunc(ctx context.Context, f func() string) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\ts := f()\n\tif s == \"\" {\n\t\treturn\n\t}\n\tdoPrint(ctx, s, false)\n}\n\n// ErrorFunc prints the output from function `f`.\n// It only calls function `f` if debug mode is enabled.\nfunc ErrorFunc(ctx context.Context, f func() string) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\ts := f()\n\tif s == \"\" {\n\t\treturn\n\t}\n\tdoPrint(ctx, s, true)\n}\n\nfunc doPrint(ctx context.Context, content string, stack bool) {\n\tif !utils.IsDebugEnabled() {\n\t\treturn\n\t}\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteString(time.Now().Format(\"2006-01-02 15:04:05.000\"))\n\tbuffer.WriteString(\" [INTE] \")\n\tbuffer.WriteString(file())\n\tbuffer.WriteString(\" \")\n\tif s := traceIDStr(ctx); s != \"\" {\n\t\tbuffer.WriteString(s + \" \")\n\t}\n\tbuffer.WriteString(content)\n\tbuffer.WriteString(\"\\n\")\n\tif stack {\n\t\tbuffer.WriteString(\"Caller Stack:\\n\")\n\t\tbuffer.WriteString(gdebug.StackWithFilter([]string{stackFilterKey}))\n\t}\n\tfmt.Print(buffer.String())\n}\n\n// traceIDStr retrieves and returns the trace id string for logging output.\nfunc traceIDStr(ctx context.Context) string {\n\tif ctx == nil {\n\t\treturn \"\"\n\t}\n\tspanCtx := trace.SpanContextFromContext(ctx)\n\tif traceID := spanCtx.TraceID(); traceID.IsValid() {\n\t\treturn \"{\" + traceID.String() + \"}\"\n\t}\n\treturn \"\"\n}\n\n// file returns caller file name along with its line number.\nfunc file() string {\n\t_, p, l := gdebug.CallerWithFilter([]string{stackFilterKey})\n\treturn fmt.Sprintf(`%s:%d`, filepath.Base(p), l)\n}\n"
  },
  {
    "path": "internal/json/json.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package json provides json operations wrapping ignoring stdlib or third-party lib json.\npackage json\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// RawMessage is a raw encoded JSON value.\n// It implements Marshaler and Unmarshaler and can\n// be used to delay JSON decoding or precompute a JSON encoding.\ntype RawMessage = json.RawMessage\n\n// Marshal adapts to json/encoding Marshal API.\n//\n// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API\n// Refer to https://godoc.org/encoding/json#Marshal for more information.\nfunc Marshal(v any) (marshaledBytes []byte, err error) {\n\tmarshaledBytes, err = json.Marshal(v)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `json.Marshal failed`)\n\t}\n\treturn\n}\n\n// MarshalIndent same as json.MarshalIndent.\nfunc MarshalIndent(v any, prefix, indent string) (marshaledBytes []byte, err error) {\n\tmarshaledBytes, err = json.MarshalIndent(v, prefix, indent)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `json.MarshalIndent failed`)\n\t}\n\treturn\n}\n\n// Unmarshal adapts to json/encoding Unmarshal API\n//\n// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.\n// Refer to https://godoc.org/encoding/json#Unmarshal for more information.\nfunc Unmarshal(data []byte, v any) (err error) {\n\terr = json.Unmarshal(data, v)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `json.Unmarshal failed`)\n\t}\n\treturn\n}\n\n// UnmarshalUseNumber decodes the json data bytes to target interface using number option.\nfunc UnmarshalUseNumber(data []byte, v any) (err error) {\n\tdecoder := NewDecoder(bytes.NewReader(data))\n\tdecoder.UseNumber()\n\terr = decoder.Decode(v)\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `json.UnmarshalUseNumber failed`)\n\t}\n\treturn\n}\n\n// NewEncoder same as json.NewEncoder\nfunc NewEncoder(writer io.Writer) *json.Encoder {\n\treturn json.NewEncoder(writer)\n}\n\n// NewDecoder adapts to json/stream NewDecoder API.\n//\n// NewDecoder returns a new decoder that reads from r.\n//\n// Instead of a json/encoding Decoder, a Decoder is returned\n// Refer to https://godoc.org/encoding/json#NewDecoder for more information.\nfunc NewDecoder(reader io.Reader) *json.Decoder {\n\treturn json.NewDecoder(reader)\n}\n\n// Valid reports whether data is a valid JSON encoding.\nfunc Valid(data []byte) bool {\n\treturn json.Valid(data)\n}\n"
  },
  {
    "path": "internal/mutex/mutex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package mutex provides switch of concurrent safe feature for sync.Mutex.\npackage mutex\n\nimport (\n\t\"sync\"\n)\n\n// Mutex is a sync.Mutex with a switch for concurrent safe feature.\ntype Mutex struct {\n\t// Underlying mutex.\n\tmutex *sync.Mutex\n}\n\n// New creates and returns a new *Mutex.\n// The parameter `safe` is used to specify whether using this mutex in concurrent safety,\n// which is false in default.\nfunc New(safe ...bool) *Mutex {\n\tmu := Create(safe...)\n\treturn &mu\n}\n\n// Create creates and returns a new Mutex object.\n// The parameter `safe` is used to specify whether using this mutex in concurrent safety,\n// which is false in default.\nfunc Create(safe ...bool) Mutex {\n\tif len(safe) > 0 && safe[0] {\n\t\treturn Mutex{\n\t\t\tmutex: new(sync.Mutex),\n\t\t}\n\t}\n\treturn Mutex{}\n}\n\n// IsSafe checks and returns whether current mutex is in concurrent-safe usage.\nfunc (mu *Mutex) IsSafe() bool {\n\treturn mu.mutex != nil\n}\n\n// Lock locks mutex for writing.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *Mutex) Lock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.Lock()\n\t}\n}\n\n// Unlock unlocks mutex for writing.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *Mutex) Unlock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.Unlock()\n\t}\n}\n"
  },
  {
    "path": "internal/mutex/mutex_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mutex_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/mutex\"\n)\n\nvar (\n\tsafeLock   = mutex.New(false)\n\tunsafeLock = mutex.New(true)\n)\n\nfunc Benchmark_Safe_LockUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsafeLock.Lock()\n\t\tsafeLock.Unlock()\n\t}\n}\n\nfunc Benchmark_UnSafe_LockUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tunsafeLock.Lock()\n\t\tunsafeLock.Unlock()\n\t}\n}\n"
  },
  {
    "path": "internal/mutex/mutex_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage mutex_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/internal/mutex\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestMutexIsSafe(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlock := mutex.New()\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = mutex.New(false)\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = mutex.New(false, false)\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = mutex.New(true, false)\n\t\tt.Assert(lock.IsSafe(), true)\n\n\t\tlock = mutex.New(true, true)\n\t\tt.Assert(lock.IsSafe(), true)\n\n\t\tlock = mutex.New(true)\n\t\tt.Assert(lock.IsSafe(), true)\n\t})\n}\n\nfunc TestSafeMutex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsafeLock := mutex.New(true)\n\t\tarray := garray.New(true)\n\n\t\tgo func() {\n\t\t\tsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tsafeLock.Unlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tsafeLock.Unlock()\n\t\t}()\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t})\n}\n\nfunc TestUnsafeMutex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tunsafeLock = mutex.New()\n\t\t\tarray      = garray.New(true)\n\t\t)\n\n\t\tgo func() {\n\t\t\tunsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tunsafeLock.Unlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tunsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tunsafeLock.Unlock()\n\t\t}()\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t})\n}\n"
  },
  {
    "path": "internal/reflection/reflection.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package reflection provides some reflection functions for internal usage.\npackage reflection\n\nimport (\n\t\"reflect\"\n)\n\ntype OriginValueAndKindOutput struct {\n\tInputValue  reflect.Value\n\tInputKind   reflect.Kind\n\tOriginValue reflect.Value\n\tOriginKind  reflect.Kind\n}\n\n// OriginValueAndKind retrieves and returns the original reflect value and kind.\nfunc OriginValueAndKind(value any) (out OriginValueAndKindOutput) {\n\tif v, ok := value.(reflect.Value); ok {\n\t\tout.InputValue = v\n\t} else {\n\t\tout.InputValue = reflect.ValueOf(value)\n\t}\n\tout.InputKind = out.InputValue.Kind()\n\tout.OriginValue = out.InputValue\n\tout.OriginKind = out.InputKind\n\tfor out.OriginKind == reflect.Pointer {\n\t\tout.OriginValue = out.OriginValue.Elem()\n\t\tout.OriginKind = out.OriginValue.Kind()\n\t}\n\treturn\n}\n\ntype OriginTypeAndKindOutput struct {\n\tInputType  reflect.Type\n\tInputKind  reflect.Kind\n\tOriginType reflect.Type\n\tOriginKind reflect.Kind\n}\n\n// OriginTypeAndKind retrieves and returns the original reflect type and kind.\nfunc OriginTypeAndKind(value any) (out OriginTypeAndKindOutput) {\n\tif value == nil {\n\t\treturn\n\t}\n\tif reflectType, ok := value.(reflect.Type); ok {\n\t\tout.InputType = reflectType\n\t} else {\n\t\tif reflectValue, ok := value.(reflect.Value); ok {\n\t\t\tout.InputType = reflectValue.Type()\n\t\t} else {\n\t\t\tout.InputType = reflect.TypeOf(value)\n\t\t}\n\t}\n\tout.InputKind = out.InputType.Kind()\n\tout.OriginType = out.InputType\n\tout.OriginKind = out.InputKind\n\tfor out.OriginKind == reflect.Pointer {\n\t\tout.OriginType = out.OriginType.Elem()\n\t\tout.OriginKind = out.OriginType.Kind()\n\t}\n\treturn\n}\n\n// ValueToInterface converts reflect value to its interface type.\nfunc ValueToInterface(v reflect.Value) (value any, ok bool) {\n\tif v.IsValid() && v.CanInterface() {\n\t\treturn v.Interface(), true\n\t}\n\tswitch v.Kind() {\n\tcase reflect.Bool:\n\t\treturn v.Bool(), true\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn v.Int(), true\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\treturn v.Uint(), true\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn v.Float(), true\n\tcase reflect.Complex64, reflect.Complex128:\n\t\treturn v.Complex(), true\n\tcase reflect.String:\n\t\treturn v.String(), true\n\tcase reflect.Pointer:\n\t\treturn ValueToInterface(v.Elem())\n\tcase reflect.Interface:\n\t\treturn ValueToInterface(v.Elem())\n\tdefault:\n\t\treturn nil, false\n\t}\n}\n"
  },
  {
    "path": "internal/reflection/reflection_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage reflection_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_OriginValueAndKind(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := reflection.OriginValueAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.String)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := reflection.OriginValueAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := reflection.OriginValueAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.Slice)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := reflection.OriginValueAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n}\n\nfunc Test_OriginTypeAndKind(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := reflection.OriginTypeAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.String)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := reflection.OriginTypeAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := reflection.OriginTypeAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.Slice)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := reflection.OriginTypeAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n}\n"
  },
  {
    "path": "internal/rwmutex/rwmutex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package rwmutex provides switch of concurrent safety feature for sync.RWMutex.\npackage rwmutex\n\nimport (\n\t\"sync\"\n)\n\n// RWMutex is a sync.RWMutex with a switch for concurrent safe feature.\n// If its attribute *sync.RWMutex is not nil, it means it's in concurrent safety usage.\n// Its attribute *sync.RWMutex is nil in default, which makes this struct mush lightweight.\ntype RWMutex struct {\n\t// Underlying mutex.\n\tmutex *sync.RWMutex\n}\n\n// New creates and returns a new *RWMutex.\n// The parameter `safe` is used to specify whether using this mutex in concurrent safety,\n// which is false in default.\nfunc New(safe ...bool) *RWMutex {\n\tmu := Create(safe...)\n\treturn &mu\n}\n\n// Create creates and returns a new RWMutex object.\n// The parameter `safe` is used to specify whether using this mutex in concurrent safety,\n// which is false in default.\nfunc Create(safe ...bool) RWMutex {\n\tif len(safe) > 0 && safe[0] {\n\t\treturn RWMutex{\n\t\t\tmutex: new(sync.RWMutex),\n\t\t}\n\t}\n\treturn RWMutex{}\n}\n\n// IsSafe checks and returns whether current mutex is in concurrent-safe usage.\nfunc (mu *RWMutex) IsSafe() bool {\n\treturn mu.mutex != nil\n}\n\n// Lock locks mutex for writing.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *RWMutex) Lock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.Lock()\n\t}\n}\n\n// Unlock unlocks mutex for writing.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *RWMutex) Unlock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.Unlock()\n\t}\n}\n\n// RLock locks mutex for reading.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *RWMutex) RLock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.RLock()\n\t}\n}\n\n// RUnlock unlocks mutex for reading.\n// It does nothing if it is not in concurrent-safe usage.\nfunc (mu *RWMutex) RUnlock() {\n\tif mu.mutex != nil {\n\t\tmu.mutex.RUnlock()\n\t}\n}\n"
  },
  {
    "path": "internal/rwmutex/rwmutex_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage rwmutex_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n)\n\nvar (\n\tsafeLock   = rwmutex.New(true)\n\tunsafeLock = rwmutex.New(false)\n)\n\nfunc Benchmark_Safe_LockUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsafeLock.Lock()\n\t\tsafeLock.Unlock()\n\t}\n}\n\nfunc Benchmark_Safe_RLockRUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tsafeLock.RLock()\n\t\tsafeLock.RUnlock()\n\t}\n}\n\nfunc Benchmark_UnSafe_LockUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tunsafeLock.Lock()\n\t\tunsafeLock.Unlock()\n\t}\n}\n\nfunc Benchmark_UnSafe_RLockRUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tunsafeLock.RLock()\n\t\tunsafeLock.RUnlock()\n\t}\n}\n"
  },
  {
    "path": "internal/rwmutex/rwmutex_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage rwmutex_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/internal/rwmutex\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestRWMutexIsSafe(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlock := rwmutex.New()\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = rwmutex.New(false)\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = rwmutex.New(false, false)\n\t\tt.Assert(lock.IsSafe(), false)\n\n\t\tlock = rwmutex.New(true, false)\n\t\tt.Assert(lock.IsSafe(), true)\n\n\t\tlock = rwmutex.New(true, true)\n\t\tt.Assert(lock.IsSafe(), true)\n\n\t\tlock = rwmutex.New(true)\n\t\tt.Assert(lock.IsSafe(), true)\n\t})\n}\n\nfunc TestSafeRWMutex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tlocalSafeLock = rwmutex.New(true)\n\t\t\tarray         = garray.New(true)\n\t\t)\n\n\t\tgo func() {\n\t\t\tlocalSafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalSafeLock.Unlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tlocalSafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalSafeLock.Unlock()\n\t\t}()\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t})\n}\n\nfunc TestSafeReaderRWMutex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tlocalSafeLock = rwmutex.New(true)\n\t\t\tarray         = garray.New(true)\n\t\t)\n\t\tgo func() {\n\t\t\tlocalSafeLock.RLock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalSafeLock.RUnlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tlocalSafeLock.RLock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalSafeLock.RUnlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\tlocalSafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\tlocalSafeLock.Unlock()\n\t\t}()\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 6)\n\t})\n}\n\nfunc TestUnsafeRWMutex(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tlocalUnsafeLock = rwmutex.New()\n\t\t\tarray           = garray.New(true)\n\t\t)\n\t\tgo func() {\n\t\t\tlocalUnsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalUnsafeLock.Unlock()\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\tlocalUnsafeLock.Lock()\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\tarray.Append(1)\n\t\t\tlocalUnsafeLock.Unlock()\n\t\t}()\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t})\n}\n"
  },
  {
    "path": "internal/tracing/tracing.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package tracing provides some utility functions for tracing functionality.\npackage tracing\n\nimport (\n\t\"math\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nvar (\n\trandomInitSequence = int32(grand.Intn(math.MaxInt32))\n\tsequence           = gtype.NewInt32(randomInitSequence)\n)\n\n// NewIDs creates and returns a new trace and span ID.\nfunc NewIDs() (traceID trace.TraceID, spanID trace.SpanID) {\n\treturn NewTraceID(), NewSpanID()\n}\n\n// NewTraceID creates and returns a trace ID.\nfunc NewTraceID() (traceID trace.TraceID) {\n\tvar (\n\t\ttimestampNanoBytes = gbinary.EncodeInt64(time.Now().UnixNano())\n\t\tsequenceBytes      = gbinary.EncodeInt32(sequence.Add(1))\n\t\trandomBytes        = grand.B(4)\n\t)\n\tcopy(traceID[:], timestampNanoBytes)\n\tcopy(traceID[8:], sequenceBytes)\n\tcopy(traceID[12:], randomBytes)\n\treturn\n}\n\n// NewSpanID creates and returns a span ID.\nfunc NewSpanID() (spanID trace.SpanID) {\n\tcopy(spanID[:], gbinary.EncodeInt64(time.Now().UnixNano()/1e3))\n\tcopy(spanID[4:], grand.B(4))\n\treturn\n}\n"
  },
  {
    "path": "internal/utils/utils.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package utils provides some utility functions for internal usage.\npackage utils\n"
  },
  {
    "path": "internal/utils/utils_array.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport \"reflect\"\n\n// IsArray checks whether given value is array/slice.\n// Note that it uses reflect internally implementing this feature.\nfunc IsArray(value any) bool {\n\trv := reflect.ValueOf(value)\n\tkind := rv.Kind()\n\tif kind == reflect.Pointer {\n\t\trv = rv.Elem()\n\t\tkind = rv.Kind()\n\t}\n\tswitch kind {\n\tcase reflect.Array, reflect.Slice:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "internal/utils/utils_debug.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/command\"\n)\n\nconst (\n\t// Debug key for checking if in debug mode.\n\tcommandEnvKeyForDebugKey = \"gf.debug\"\n)\n\n// isDebugEnabled marks whether GoFrame debug mode is enabled.\nvar isDebugEnabled = false\n\nfunc init() {\n\t// Debugging configured.\n\tvalue := command.GetOptWithEnv(commandEnvKeyForDebugKey)\n\tif value == \"\" || value == \"0\" || value == \"false\" {\n\t\tisDebugEnabled = false\n\t} else {\n\t\tisDebugEnabled = true\n\t}\n}\n\n// IsDebugEnabled checks and returns whether debug mode is enabled.\n// The debug mode is enabled when command argument \"gf.debug\" or environment \"GF_DEBUG\" is passed.\nfunc IsDebugEnabled() bool {\n\treturn isDebugEnabled\n}\n\n// SetDebugEnabled enables/disables the internal debug info.\nfunc SetDebugEnabled(enabled bool) {\n\tisDebugEnabled = enabled\n}\n"
  },
  {
    "path": "internal/utils/utils_io.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"io\"\n)\n\n// ReadCloser implements the io.ReadCloser interface\n// which is used for reading request body content multiple times.\n//\n// Note that it cannot be closed.\ntype ReadCloser struct {\n\tindex      int    // Current read position.\n\tcontent    []byte // Content.\n\trepeatable bool   // Mark the content can be repeatable read.\n}\n\n// NewReadCloser creates and returns a RepeatReadCloser object.\nfunc NewReadCloser(content []byte, repeatable bool) io.ReadCloser {\n\treturn &ReadCloser{\n\t\tcontent:    content,\n\t\trepeatable: repeatable,\n\t}\n}\n\n// Read implements the io.ReadCloser interface.\nfunc (b *ReadCloser) Read(p []byte) (n int, err error) {\n\t// Make it repeatable reading.\n\tif b.index >= len(b.content) && b.repeatable {\n\t\tb.index = 0\n\t}\n\tn = copy(p, b.content[b.index:])\n\tb.index += n\n\tif b.index >= len(b.content) {\n\t\treturn n, io.EOF\n\t}\n\treturn n, nil\n}\n\n// Close implements the io.ReadCloser interface.\nfunc (b *ReadCloser) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/utils/utils_is.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n)\n\n// IsNil checks whether `value` is nil, especially for any type value.\nfunc IsNil(value any) bool {\n\treturn empty.IsNil(value)\n}\n\n// IsEmpty checks whether `value` is empty.\nfunc IsEmpty(value any) bool {\n\treturn empty.IsEmpty(value)\n}\n\n// IsInt checks whether `value` is type of int.\nfunc IsInt(value any) bool {\n\tswitch value.(type) {\n\tcase int, *int, int8, *int8, int16, *int16, int32, *int32, int64, *int64:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsUint checks whether `value` is type of uint.\nfunc IsUint(value any) bool {\n\tswitch value.(type) {\n\tcase uint, *uint, uint8, *uint8, uint16, *uint16, uint32, *uint32, uint64, *uint64:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsFloat checks whether `value` is type of float.\nfunc IsFloat(value any) bool {\n\tswitch value.(type) {\n\tcase float32, *float32, float64, *float64:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsSlice checks whether `value` is type of slice.\nfunc IsSlice(value any) bool {\n\tvar (\n\t\treflectValue = reflect.ValueOf(value)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsMap checks whether `value` is type of map.\nfunc IsMap(value any) bool {\n\tvar (\n\t\treflectValue = reflect.ValueOf(value)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsStruct checks whether `value` is type of struct.\nfunc IsStruct(value any) bool {\n\treflectType := reflect.TypeOf(value)\n\tif reflectType == nil {\n\t\treturn false\n\t}\n\treflectKind := reflectType.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\treflectType = reflectType.Elem()\n\t\treflectKind = reflectType.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Struct:\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/utils/utils_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport \"fmt\"\n\n// ListToMapByKey converts `list` to a map[string]any of which key is specified by `key`.\n// Note that the item value may be type of slice.\nfunc ListToMapByKey(list []map[string]any, key string) map[string]any {\n\tvar (\n\t\ts              = \"\"\n\t\tm              = make(map[string]any)\n\t\ttempMap        = make(map[string][]any)\n\t\thasMultiValues bool\n\t)\n\tfor _, item := range list {\n\t\tif k, ok := item[key]; ok {\n\t\t\ts = fmt.Sprintf(`%v`, k)\n\t\t\ttempMap[s] = append(tempMap[s], item)\n\t\t\tif len(tempMap[s]) > 1 {\n\t\t\t\thasMultiValues = true\n\t\t\t}\n\t\t}\n\t}\n\tfor k, v := range tempMap {\n\t\tif hasMultiValues {\n\t\t\tm[k] = v\n\t\t} else {\n\t\t\tm[k] = v[0]\n\t\t}\n\t}\n\treturn m\n}\n"
  },
  {
    "path": "internal/utils/utils_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\n// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.\n//\n// Note that this function might be of low performance.\nfunc MapPossibleItemByKey(data map[string]any, key string) (foundKey string, foundValue any) {\n\tif len(data) == 0 {\n\t\treturn\n\t}\n\tif v, ok := data[key]; ok {\n\t\treturn key, v\n\t}\n\t// Loop checking.\n\tfor k, v := range data {\n\t\tif EqualFoldWithoutChars(k, key) {\n\t\t\treturn k, v\n\t\t}\n\t}\n\treturn \"\", nil\n}\n\n// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.\n// It checks the key ignoring cases and symbols.\n//\n// Note that this function might be of low performance.\nfunc MapContainsPossibleKey(data map[string]any, key string) bool {\n\tif k, _ := MapPossibleItemByKey(data, key); k != \"\" {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/utils/utils_reflect.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"reflect\"\n)\n\n// CanCallIsNil Can reflect.Value call reflect.Value.IsNil.\n// It can avoid reflect.Value.IsNil panics.\nfunc CanCallIsNil(v any) bool {\n\trv, ok := v.(reflect.Value)\n\tif !ok {\n\t\treturn false\n\t}\n\tswitch rv.Kind() {\n\tcase reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Slice, reflect.UnsafePointer:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "internal/utils/utils_str.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"unicode\"\n)\n\n// DefaultTrimChars are the characters which are stripped by Trim* functions in default.\nvar DefaultTrimChars = string([]byte{\n\t'\\t', // Tab.\n\t'\\v', // Vertical tab.\n\t'\\n', // New line (line feed).\n\t'\\r', // Carriage return.\n\t'\\f', // New page.\n\t' ',  // Ordinary space.\n\t0x00, // NUL-byte.\n\t0x85, // Delete.\n\t0xA0, // Non-breaking space.\n})\n\n// IsLetterUpper checks whether the given byte b is in upper case.\nfunc IsLetterUpper(b byte) bool {\n\tif b >= byte('A') && b <= byte('Z') {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsLetterLower checks whether the given byte b is in lower case.\nfunc IsLetterLower(b byte) bool {\n\tif b >= byte('a') && b <= byte('z') {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsLetter checks whether the given byte b is a letter.\nfunc IsLetter(b byte) bool {\n\treturn IsLetterUpper(b) || IsLetterLower(b)\n}\n\n// IsNumeric checks whether the given string s is numeric.\n// Note that float string like \"123.456\" is also numeric.\nfunc IsNumeric(s string) bool {\n\tvar (\n\t\tdotCount = 0\n\t\tlength   = len(s)\n\t)\n\tif length == 0 {\n\t\treturn false\n\t}\n\tfor i := 0; i < length; i++ {\n\t\tif (s[i] == '-' || s[i] == '+') && i == 0 {\n\t\t\tif length == 1 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif s[i] == '.' {\n\t\t\tdotCount++\n\t\t\tif i > 0 && i < length-1 && s[i-1] >= '0' && s[i-1] <= '9' {\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\tif s[i] < '0' || s[i] > '9' {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn dotCount <= 1\n}\n\n// UcFirst returns a copy of the string s with the first letter mapped to its upper case.\nfunc UcFirst(s string) string {\n\tif len(s) == 0 {\n\t\treturn s\n\t}\n\tif IsLetterLower(s[0]) {\n\t\treturn string(s[0]-32) + s[1:]\n\t}\n\treturn s\n}\n\n// ReplaceByMap returns a copy of `origin`,\n// which is replaced by a map in unordered way, case-sensitively.\nfunc ReplaceByMap(origin string, replaces map[string]string) string {\n\tfor k, v := range replaces {\n\t\torigin = strings.ReplaceAll(origin, k, v)\n\t}\n\treturn origin\n}\n\n// RemoveSymbols removes all symbols from string and lefts only numbers and letters.\nfunc RemoveSymbols(s string) string {\n\tb := make([]rune, 0, len(s))\n\tfor _, c := range s {\n\t\tif c > 127 {\n\t\t\tb = append(b, c)\n\t\t} else if (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') {\n\t\t\tb = append(b, c)\n\t\t}\n\t}\n\treturn string(b)\n}\n\n// EqualFoldWithoutChars checks string `s1` and `s2` equal case-insensitively,\n// with/without chars '-'/'_'/'.'/' '.\nfunc EqualFoldWithoutChars(s1, s2 string) bool {\n\treturn strings.EqualFold(RemoveSymbols(s1), RemoveSymbols(s2))\n}\n\n// SplitAndTrim splits string `str` by a string `delimiter` to an array,\n// and calls Trim to every element of this array. It ignores the elements\n// which are empty after Trim.\nfunc SplitAndTrim(str, delimiter string, characterMask ...string) []string {\n\tarray := make([]string, 0)\n\tfor _, v := range strings.Split(str, delimiter) {\n\t\tv = Trim(v, characterMask...)\n\t\tif v != \"\" {\n\t\t\tarray = append(array, v)\n\t\t}\n\t}\n\treturn array\n}\n\n// Trim strips whitespace (or other characters) from the beginning and end of a string.\n// The optional parameter `characterMask` specifies the additional stripped characters.\nfunc Trim(str string, characterMask ...string) string {\n\ttrimChars := DefaultTrimChars\n\tif len(characterMask) > 0 {\n\t\ttrimChars += characterMask[0]\n\t}\n\treturn strings.Trim(str, trimChars)\n}\n\n// FormatCmdKey formats string `s` as command key using uniformed format.\nfunc FormatCmdKey(s string) string {\n\treturn strings.ToLower(strings.ReplaceAll(s, \"_\", \".\"))\n}\n\n// FormatEnvKey formats string `s` as environment key using uniformed format.\nfunc FormatEnvKey(s string) string {\n\treturn strings.ToUpper(strings.ReplaceAll(s, \".\", \"_\"))\n}\n\n// StripSlashes un-quotes a quoted string by AddSlashes.\nfunc StripSlashes(str string) string {\n\tvar buf bytes.Buffer\n\tl, skip := len(str), false\n\tfor i, char := range str {\n\t\tif skip {\n\t\t\tskip = false\n\t\t} else if char == '\\\\' {\n\t\t\tif i+1 < l && str[i+1] == '\\\\' {\n\t\t\t\tskip = true\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tbuf.WriteRune(char)\n\t}\n\treturn buf.String()\n}\n\n// IsASCII checks whether given string is ASCII characters.\nfunc IsASCII(s string) bool {\n\tfor i := 0; i < len(s); i++ {\n\t\tif s[i] > unicode.MaxASCII {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "internal/utils/utils_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils_test\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\nvar (\n\treplaceCharReg, _ = regexp.Compile(`[\\-\\.\\_\\s]+`)\n)\n\nfunc Benchmark_RemoveSymbols(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tutils.RemoveSymbols(`-a-b._a c1!@#$%^&*()_+:\";'.,'01`)\n\t}\n}\n\nfunc Benchmark_RegularReplaceChars(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treplaceCharReg.ReplaceAllString(`-a-b._a c1!@#$%^&*()_+:\";'.,'01`, \"\")\n\t}\n}\n"
  },
  {
    "path": "internal/utils/utils_z_unit_is_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestVar_IsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsNil(0), false)\n\t\tt.Assert(utils.IsNil(nil), true)\n\t\tt.Assert(utils.IsNil(g.Map{}), false)\n\t\tt.Assert(utils.IsNil(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsNil(1), false)\n\t\tt.Assert(utils.IsNil(0.1), false)\n\t\tt.Assert(utils.IsNil(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsNil(g.Slice{0}), false)\n\t})\n}\n\nfunc TestVar_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsEmpty(0), true)\n\t\tt.Assert(utils.IsEmpty(nil), true)\n\t\tt.Assert(utils.IsEmpty(g.Map{}), true)\n\t\tt.Assert(utils.IsEmpty(g.Slice{}), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsEmpty(1), false)\n\t\tt.Assert(utils.IsEmpty(0.1), false)\n\t\tt.Assert(utils.IsEmpty(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsEmpty(g.Slice{0}), false)\n\t})\n}\n\nfunc TestVar_IsInt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsInt(0), true)\n\t\tt.Assert(utils.IsInt(nil), false)\n\t\tt.Assert(utils.IsInt(g.Map{}), false)\n\t\tt.Assert(utils.IsInt(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsInt(1), true)\n\t\tt.Assert(utils.IsInt(-1), true)\n\t\tt.Assert(utils.IsInt(0.1), false)\n\t\tt.Assert(utils.IsInt(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsInt(g.Slice{0}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsInt(int8(1)), true)\n\t\tt.Assert(utils.IsInt(uint8(1)), false)\n\t})\n}\n\nfunc TestVar_IsUint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsUint(0), false)\n\t\tt.Assert(utils.IsUint(nil), false)\n\t\tt.Assert(utils.IsUint(g.Map{}), false)\n\t\tt.Assert(utils.IsUint(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsUint(1), false)\n\t\tt.Assert(utils.IsUint(-1), false)\n\t\tt.Assert(utils.IsUint(0.1), false)\n\t\tt.Assert(utils.IsUint(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsUint(g.Slice{0}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsUint(int8(1)), false)\n\t\tt.Assert(utils.IsUint(uint8(1)), true)\n\t})\n}\n\nfunc TestVar_IsFloat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsFloat(0), false)\n\t\tt.Assert(utils.IsFloat(nil), false)\n\t\tt.Assert(utils.IsFloat(g.Map{}), false)\n\t\tt.Assert(utils.IsFloat(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsFloat(1), false)\n\t\tt.Assert(utils.IsFloat(-1), false)\n\t\tt.Assert(utils.IsFloat(0.1), true)\n\t\tt.Assert(utils.IsFloat(float64(1)), true)\n\t\tt.Assert(utils.IsFloat(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsFloat(g.Slice{0}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsFloat(int8(1)), false)\n\t\tt.Assert(utils.IsFloat(uint8(1)), false)\n\t})\n}\n\nfunc TestVar_IsSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsSlice(0), false)\n\t\tt.Assert(utils.IsSlice(nil), false)\n\t\tt.Assert(utils.IsSlice(g.Map{}), false)\n\t\tt.Assert(utils.IsSlice(g.Slice{}), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsSlice(1), false)\n\t\tt.Assert(utils.IsSlice(-1), false)\n\t\tt.Assert(utils.IsSlice(0.1), false)\n\t\tt.Assert(utils.IsSlice(float64(1)), false)\n\t\tt.Assert(utils.IsSlice(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsSlice(g.Slice{0}), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsSlice(int8(1)), false)\n\t\tt.Assert(utils.IsSlice(uint8(1)), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsSlice(gvar.New(gtime.Now()).IsSlice()), false)\n\t})\n}\n\nfunc TestVar_IsMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsMap(0), false)\n\t\tt.Assert(utils.IsMap(nil), false)\n\t\tt.Assert(utils.IsMap(g.Map{}), true)\n\t\tt.Assert(utils.IsMap(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsMap(1), false)\n\t\tt.Assert(utils.IsMap(-1), false)\n\t\tt.Assert(utils.IsMap(0.1), false)\n\t\tt.Assert(utils.IsMap(float64(1)), false)\n\t\tt.Assert(utils.IsMap(g.Map{\"k\": \"v\"}), true)\n\t\tt.Assert(utils.IsMap(g.Slice{0}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsMap(int8(1)), false)\n\t\tt.Assert(utils.IsMap(uint8(1)), false)\n\t})\n}\n\nfunc TestVar_IsStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsStruct(0), false)\n\t\tt.Assert(utils.IsStruct(nil), false)\n\t\tt.Assert(utils.IsStruct(g.Map{}), false)\n\t\tt.Assert(utils.IsStruct(g.Slice{}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsStruct(1), false)\n\t\tt.Assert(utils.IsStruct(-1), false)\n\t\tt.Assert(utils.IsStruct(0.1), false)\n\t\tt.Assert(utils.IsStruct(float64(1)), false)\n\t\tt.Assert(utils.IsStruct(g.Map{\"k\": \"v\"}), false)\n\t\tt.Assert(utils.IsStruct(g.Slice{0}), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &struct {\n\t\t}{}\n\t\tt.Assert(utils.IsStruct(a), true)\n\t\tt.Assert(utils.IsStruct(*a), true)\n\t\tt.Assert(utils.IsStruct(&a), true)\n\t})\n}\n"
  },
  {
    "path": "internal/utils/utils_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage utils_test\n\nimport (\n\t\"io\"\n\t\"reflect\"\n\t\"testing\"\n\t\"unsafe\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ReadCloser(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tn    int\n\t\t\tb    = make([]byte, 3)\n\t\t\tbody = utils.NewReadCloser([]byte{1, 2, 3, 4}, false)\n\t\t)\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{1, 2, 3})\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{4})\n\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{})\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tr    []byte\n\t\t\tbody = utils.NewReadCloser([]byte{1, 2, 3, 4}, false)\n\t\t)\n\t\tr, _ = io.ReadAll(body)\n\t\tt.Assert(r, []byte{1, 2, 3, 4})\n\t\tr, _ = io.ReadAll(body)\n\t\tt.Assert(r, []byte{})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tn    int\n\t\t\tr    []byte\n\t\t\tb    = make([]byte, 3)\n\t\t\tbody = utils.NewReadCloser([]byte{1, 2, 3, 4}, true)\n\t\t)\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{1, 2, 3})\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{4})\n\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{1, 2, 3})\n\t\tn, _ = body.Read(b)\n\t\tt.Assert(b[:n], []byte{4})\n\n\t\tr, _ = io.ReadAll(body)\n\t\tt.Assert(r, []byte{1, 2, 3, 4})\n\t\tr, _ = io.ReadAll(body)\n\t\tt.Assert(r, []byte{1, 2, 3, 4})\n\t})\n}\n\nfunc Test_RemoveSymbols(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.RemoveSymbols(`-a-b._a c1!@#$%^&*()_+:\";'.,'01`), `abac101`)\n\t\tt.Assert(utils.RemoveSymbols(`-a-b我._a c1!@#$%^&*是()_+:帅\";'.,哥'01`), `ab我ac1是帅哥01`)\n\t})\n}\n\nfunc Test_CanCallIsNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tiValue         = \"gf\"\n\t\t\tiChan          = make(chan struct{})\n\t\t\tiFunc          = func() {}\n\t\t\tiMap           = map[string]struct{}{}\n\t\t\tiPtr           = &iValue\n\t\t\tiSlice         = make([]struct{}, 0)\n\t\t\tiUnsafePointer = unsafe.Pointer(&iValue)\n\t\t)\n\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iValue)), false)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iChan)), true)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iFunc)), true)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iMap)), true)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iPtr)), true)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iSlice)), true)\n\t\tt.Assert(utils.CanCallIsNil(reflect.ValueOf(iUnsafePointer)), true)\n\t})\n}\n\nfunc Test_IsNumeric(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(utils.IsNumeric(\"12345\"), true)\n\t\tt.Assert(utils.IsNumeric(\"-12345\"), true)\n\t\tt.Assert(utils.IsNumeric(\"+12345\"), true)\n\t\tt.Assert(utils.IsNumeric(\"123.45\"), true)\n\t\tt.Assert(utils.IsNumeric(\"-123.45\"), true)\n\t\tt.Assert(utils.IsNumeric(\"+123.45\"), true)\n\t\tt.Assert(utils.IsNumeric(\"1+23\"), false)\n\t\tt.Assert(utils.IsNumeric(\"123a45\"), false)\n\t\tt.Assert(utils.IsNumeric(\"123.45.67\"), false)\n\t\tt.Assert(utils.IsNumeric(\"\"), false)\n\t\tt.Assert(utils.IsNumeric(\"1e10\"), false)\n\t\tt.Assert(utils.IsNumeric(\"123 45\"), false)\n\t\tt.Assert(utils.IsNumeric(\"!!!\"), false)\n\t\tt.Assert(utils.IsNumeric(\"-a23\"), false)\n\t\tt.Assert(utils.IsNumeric(\"+a23\"), false)\n\t\tt.Assert(utils.IsNumeric(\"1+23\"), false)\n\t\tt.Assert(utils.IsNumeric(\"1-23\"), false)\n\t\tt.Assert(utils.IsNumeric(\"123.\"), false)\n\t\tt.Assert(utils.IsNumeric(\".123\"), false)\n\t\tt.Assert(utils.IsNumeric(\"123.a\"), false)\n\t\tt.Assert(utils.IsNumeric(\"a.123\"), false)\n\t\tt.Assert(utils.IsNumeric(\"+\"), false)\n\t\tt.Assert(utils.IsNumeric(\"-\"), false)\n\t\tt.Assert(utils.IsNumeric(\".\"), false)\n\t\tt.Assert(utils.IsNumeric(\"-.\"), false)\n\t\tt.Assert(utils.IsNumeric(\"+.\"), false)\n\t\tt.Assert(utils.IsNumeric(\"-.1\"), false)\n\t\tt.Assert(utils.IsNumeric(\"+.1\"), false)\n\t})\n}\n\nfunc TestIsASCII(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(utils.IsASCII(\"test\"), true)\n\t\tt.AssertEQ(utils.IsASCII(\"测试\"), false)\n\t\tt.AssertEQ(utils.IsASCII(\"テスト\"), false)\n\t\tt.AssertEQ(utils.IsASCII(\"테스트\"), false)\n\t\tt.AssertEQ(utils.IsASCII(\"😁😭❤️😓\"), false)\n\t})\n}\n"
  },
  {
    "path": "net/gclient/gclient.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gclient provides convenient http client functionalities.\npackage gclient\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// Client is the HTTP client for HTTP request management.\ntype Client struct {\n\thttp.Client                         // Underlying HTTP Client.\n\theader            map[string]string // Custom header map.\n\tcookies           map[string]string // Custom cookie map.\n\tprefix            string            // Prefix for request.\n\tauthUser          string            // HTTP basic authentication: user.\n\tauthPass          string            // HTTP basic authentication: pass.\n\tretryCount        int               // Retry count when request fails.\n\tnoUrlEncode       bool              // No url encoding for request parameters.\n\tretryInterval     time.Duration     // Retry interval when request fails.\n\tmiddlewareHandler []HandlerFunc     // Interceptor handlers\n\tdiscovery         gsvc.Discovery    // Discovery for service.\n\tbuilder           gsel.Builder      // Builder for request balance.\n}\n\nconst (\n\thttpProtocolName          = `http`\n\thttpParamFileHolder       = `@file:`\n\thttpRegexParamJson        = `^[\\w\\[\\]]+=.+`\n\thttpRegexHeaderRaw        = `^([\\w\\-]+):\\s*(.+)`\n\thttpHeaderHost            = `Host`\n\thttpHeaderCookie          = `Cookie`\n\thttpHeaderUserAgent       = `User-Agent`\n\thttpHeaderContentType     = `Content-Type`\n\thttpHeaderContentTypeJson = `application/json`\n\thttpHeaderContentTypeXml  = `application/xml`\n\thttpHeaderContentTypeForm = `application/x-www-form-urlencoded`\n)\n\nvar (\n\thostname, _        = os.Hostname()\n\tdefaultClientAgent = fmt.Sprintf(`GClient %s at %s`, gf.VERSION, hostname)\n)\n\n// New creates and returns a new HTTP client object.\nfunc New() *Client {\n\tc := &Client{\n\t\tClient: http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\t// No validation for https certification of the server in default.\n\t\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t},\n\t\t\t\tDisableKeepAlives:     true,\n\t\t\t\tMaxIdleConns:          100,\n\t\t\t\tMaxIdleConnsPerHost:   50,\n\t\t\t\tMaxConnsPerHost:       100,\n\t\t\t\tIdleConnTimeout:       90 * time.Second,\n\t\t\t\tResponseHeaderTimeout: 30 * time.Second,\n\t\t\t\tExpectContinueTimeout: 1 * time.Second,\n\t\t\t\tTLSHandshakeTimeout:   10 * time.Second,\n\t\t\t\tForceAttemptHTTP2:     true,\n\t\t\t\tDisableCompression:    false,\n\t\t\t\tDialContext: (&net.Dialer{\n\t\t\t\t\tTimeout:   30 * time.Second,\n\t\t\t\t\tKeepAlive: 30 * time.Second,\n\t\t\t\t}).DialContext,\n\t\t\t},\n\t\t},\n\t\theader:    make(map[string]string),\n\t\tcookies:   make(map[string]string),\n\t\tbuilder:   gsel.GetBuilder(),\n\t\tdiscovery: nil,\n\t}\n\tc.header[httpHeaderUserAgent] = defaultClientAgent\n\t// It enables OpenTelemetry for client in default.\n\tc.Use(internalMiddlewareObservability, internalMiddlewareDiscovery)\n\treturn c\n}\n\n// Clone deeply clones current client and returns a new one.\nfunc (c *Client) Clone() *Client {\n\tnewClient := New()\n\t*newClient = *c\n\tnewClient.header = make(map[string]string, len(c.header))\n\tfor k, v := range c.header {\n\t\tnewClient.header[k] = v\n\t}\n\tnewClient.cookies = make(map[string]string, len(c.cookies))\n\tfor k, v := range c.cookies {\n\t\tnewClient.cookies[k] = v\n\t}\n\treturn newClient\n}\n\n// LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.\nfunc LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {\n\tcrtPath, err := gfile.Search(crtFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkeyPath, err := gfile.Search(keyFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcrt, err := tls.LoadX509KeyPair(crtPath, keyPath)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `tls.LoadX509KeyPair failed for certFile \"%s\", keyFile \"%s\"`, crtPath, keyPath)\n\t\treturn nil, err\n\t}\n\ttlsConfig := &tls.Config{}\n\ttlsConfig.Certificates = []tls.Certificate{crt}\n\ttlsConfig.Time = time.Now\n\ttlsConfig.Rand = rand.Reader\n\treturn tlsConfig, nil\n}\n"
  },
  {
    "path": "net/gclient/gclient_bytes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// GetBytes sends a GET request, retrieves and returns the result content as bytes.\nfunc (c *Client) GetBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodGet, url, data...)\n}\n\n// PutBytes sends a PUT request, retrieves and returns the result content as bytes.\nfunc (c *Client) PutBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodPut, url, data...)\n}\n\n// PostBytes sends a POST request, retrieves and returns the result content as bytes.\nfunc (c *Client) PostBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodPost, url, data...)\n}\n\n// DeleteBytes sends a DELETE request, retrieves and returns the result content as bytes.\nfunc (c *Client) DeleteBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodDelete, url, data...)\n}\n\n// HeadBytes sends a HEAD request, retrieves and returns the result content as bytes.\nfunc (c *Client) HeadBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodHead, url, data...)\n}\n\n// PatchBytes sends a PATCH request, retrieves and returns the result content as bytes.\nfunc (c *Client) PatchBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodPatch, url, data...)\n}\n\n// ConnectBytes sends a CONNECT request, retrieves and returns the result content as bytes.\nfunc (c *Client) ConnectBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodConnect, url, data...)\n}\n\n// OptionsBytes sends an OPTIONS request, retrieves and returns the result content as bytes.\nfunc (c *Client) OptionsBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodOptions, url, data...)\n}\n\n// TraceBytes sends a TRACE request, retrieves and returns the result content as bytes.\nfunc (c *Client) TraceBytes(ctx context.Context, url string, data ...any) []byte {\n\treturn c.RequestBytes(ctx, http.MethodTrace, url, data...)\n}\n\n// RequestBytes sends request using given HTTP method and data, retrieves returns the result\n// as bytes. It reads and closes the response object internally automatically.\nfunc (c *Client) RequestBytes(ctx context.Context, method string, url string, data ...any) []byte {\n\tresponse, err := c.DoRequest(ctx, method, url, data...)\n\tif err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\treturn nil\n\t}\n\tdefer func() {\n\t\tif err = response.Close(); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}()\n\treturn response.ReadAll()\n}\n"
  },
  {
    "path": "net/gclient/gclient_chain.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Prefix is a chaining function,\n// which sets the URL prefix for next request of this client.\n// Eg:\n// Prefix(\"http://127.0.0.1:8199/api/v1\")\n// Prefix(\"http://127.0.0.1:8199/api/v2\")\nfunc (c *Client) Prefix(prefix string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetPrefix(prefix)\n\treturn newClient\n}\n\n// Header is a chaining function,\n// which sets custom HTTP headers with map for next request.\nfunc (c *Client) Header(m map[string]string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetHeaderMap(m)\n\treturn newClient\n}\n\n// HeaderRaw is a chaining function,\n// which sets custom HTTP header using raw string for next request.\nfunc (c *Client) HeaderRaw(headers string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetHeaderRaw(headers)\n\treturn newClient\n}\n\n// Discovery is a chaining function, which sets the discovery for client.\n// You can use `Discovery(nil)` to disable discovery feature for current client.\nfunc (c *Client) Discovery(discovery gsvc.Discovery) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetDiscovery(discovery)\n\treturn newClient\n}\n\n// Cookie is a chaining function,\n// which sets cookie items with map for next request.\nfunc (c *Client) Cookie(m map[string]string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetCookieMap(m)\n\treturn newClient\n}\n\n// ContentType is a chaining function,\n// which sets HTTP content type for the next request.\nfunc (c *Client) ContentType(contentType string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetContentType(contentType)\n\treturn newClient\n}\n\n// ContentJson is a chaining function,\n// which sets the HTTP content type as \"application/json\" for the next request.\n//\n// Note that it also checks and encodes the parameter to JSON format automatically.\nfunc (c *Client) ContentJson() *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetContentType(httpHeaderContentTypeJson)\n\treturn newClient\n}\n\n// ContentXml is a chaining function,\n// which sets the HTTP content type as \"application/xml\" for the next request.\n//\n// Note that it also checks and encodes the parameter to XML format automatically.\nfunc (c *Client) ContentXml() *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetContentType(httpHeaderContentTypeXml)\n\treturn newClient\n}\n\n// Timeout is a chaining function,\n// which sets the timeout for next request.\nfunc (c *Client) Timeout(t time.Duration) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetTimeout(t)\n\treturn newClient\n}\n\n// BasicAuth is a chaining function,\n// which sets HTTP basic authentication information for next request.\nfunc (c *Client) BasicAuth(user, pass string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetBasicAuth(user, pass)\n\treturn newClient\n}\n\n// Retry is a chaining function,\n// which sets retry count and interval when failure for next request.\n// TODO removed.\nfunc (c *Client) Retry(retryCount int, retryInterval time.Duration) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetRetry(retryCount, retryInterval)\n\treturn newClient\n}\n\n// Proxy is a chaining function,\n// which sets proxy for next request.\n// Make sure you pass the correct `proxyURL`.\n// The correct pattern is like `http://USER:PASSWORD@IP:PORT` or `socks5://USER:PASSWORD@IP:PORT`.\n// Only `http` and `socks5` proxies are supported currently.\nfunc (c *Client) Proxy(proxyURL string) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetProxy(proxyURL)\n\treturn newClient\n}\n\n// RedirectLimit is a chaining function,\n// which sets the redirect limit the number of jumps for the request.\nfunc (c *Client) RedirectLimit(redirectLimit int) *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetRedirectLimit(redirectLimit)\n\treturn newClient\n}\n\n// NoUrlEncode sets the mark that do not encode the parameters before sending request.\nfunc (c *Client) NoUrlEncode() *Client {\n\tnewClient := c.Clone()\n\tnewClient.SetNoUrlEncode(true)\n\treturn newClient\n}\n"
  },
  {
    "path": "net/gclient/gclient_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/net/proxy\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SetBrowserMode enables browser mode of the client.\n// When browser mode is enabled, it automatically saves and sends cookie content\n// from and to server.\nfunc (c *Client) SetBrowserMode(enabled bool) *Client {\n\tif enabled {\n\t\tjar, _ := cookiejar.New(nil)\n\t\tc.Jar = jar\n\t}\n\treturn c\n}\n\n// SetHeader sets a custom HTTP header pair for the client.\nfunc (c *Client) SetHeader(key, value string) *Client {\n\tc.header[key] = value\n\treturn c\n}\n\n// SetHeaderMap sets custom HTTP headers with map.\nfunc (c *Client) SetHeaderMap(m map[string]string) *Client {\n\tfor k, v := range m {\n\t\tc.header[k] = v\n\t}\n\treturn c\n}\n\n// SetAgent sets the User-Agent header for client.\nfunc (c *Client) SetAgent(agent string) *Client {\n\tc.header[httpHeaderUserAgent] = agent\n\treturn c\n}\n\n// SetContentType sets HTTP content type for the client.\nfunc (c *Client) SetContentType(contentType string) *Client {\n\tc.header[httpHeaderContentType] = contentType\n\treturn c\n}\n\n// SetHeaderRaw sets custom HTTP header using raw string.\nfunc (c *Client) SetHeaderRaw(headers string) *Client {\n\tfor _, line := range gstr.SplitAndTrim(headers, \"\\n\") {\n\t\tarray, _ := gregex.MatchString(httpRegexHeaderRaw, line)\n\t\tif len(array) >= 3 {\n\t\t\tc.header[array[1]] = array[2]\n\t\t}\n\t}\n\treturn c\n}\n\n// SetCookie sets a cookie pair for the client.\nfunc (c *Client) SetCookie(key, value string) *Client {\n\tc.cookies[key] = value\n\treturn c\n}\n\n// SetCookieMap sets cookie items with map.\nfunc (c *Client) SetCookieMap(m map[string]string) *Client {\n\tfor k, v := range m {\n\t\tc.cookies[k] = v\n\t}\n\treturn c\n}\n\n// SetPrefix sets the request server URL prefix.\nfunc (c *Client) SetPrefix(prefix string) *Client {\n\tc.prefix = prefix\n\treturn c\n}\n\n// SetTimeout sets the request timeout for the client.\nfunc (c *Client) SetTimeout(t time.Duration) *Client {\n\tc.Client.Timeout = t\n\treturn c\n}\n\n// SetBasicAuth sets HTTP basic authentication information for the client.\nfunc (c *Client) SetBasicAuth(user, pass string) *Client {\n\tc.authUser = user\n\tc.authPass = pass\n\treturn c\n}\n\n// SetRetry sets retry count and interval.\n// TODO removed.\nfunc (c *Client) SetRetry(retryCount int, retryInterval time.Duration) *Client {\n\tc.retryCount = retryCount\n\tc.retryInterval = retryInterval\n\treturn c\n}\n\n// SetRedirectLimit limits the number of jumps.\nfunc (c *Client) SetRedirectLimit(redirectLimit int) *Client {\n\tc.CheckRedirect = func(req *http.Request, via []*http.Request) error {\n\t\tif len(via) >= redirectLimit {\n\t\t\treturn http.ErrUseLastResponse\n\t\t}\n\t\treturn nil\n\t}\n\treturn c\n}\n\n// SetNoUrlEncode sets the mark that do not encode the parameters before sending request.\nfunc (c *Client) SetNoUrlEncode(noUrlEncode bool) *Client {\n\tc.noUrlEncode = noUrlEncode\n\treturn c\n}\n\n// SetProxy set proxy for the client.\n// This func will do nothing when the parameter `proxyURL` is empty or in wrong pattern.\n// The correct pattern is like `http://USER:PASSWORD@IP:PORT` or `socks5://USER:PASSWORD@IP:PORT`.\n// Only `http` and `socks5` proxies are supported currently.\nfunc (c *Client) SetProxy(proxyURL string) {\n\tif strings.TrimSpace(proxyURL) == \"\" {\n\t\treturn\n\t}\n\t_proxy, err := url.Parse(proxyURL)\n\tif err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\treturn\n\t}\n\tif _proxy.Scheme == httpProtocolName {\n\t\tif v, ok := c.Transport.(*http.Transport); ok {\n\t\t\tv.Proxy = http.ProxyURL(_proxy)\n\t\t}\n\t} else {\n\t\tauth := &proxy.Auth{}\n\t\tuser := _proxy.User.Username()\n\t\tif user != \"\" {\n\t\t\tauth.User = user\n\t\t\tpassword, hasPassword := _proxy.User.Password()\n\t\t\tif hasPassword && password != \"\" {\n\t\t\t\tauth.Password = password\n\t\t\t}\n\t\t} else {\n\t\t\tauth = nil\n\t\t}\n\t\t// refer to the source code, error is always nil\n\t\tdialer, err := proxy.SOCKS5(\n\t\t\t\"tcp\",\n\t\t\t_proxy.Host,\n\t\t\tauth,\n\t\t\t&net.Dialer{\n\t\t\t\tTimeout:   c.Client.Timeout,\n\t\t\t\tKeepAlive: c.Client.Timeout,\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\treturn\n\t\t}\n\t\tif v, ok := c.Transport.(*http.Transport); ok {\n\t\t\tv.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, e error) {\n\t\t\t\treturn dialer.Dial(network, addr)\n\t\t\t}\n\t\t}\n\t\t// c.SetTimeout(10*time.Second)\n\t}\n}\n\n// SetTLSKeyCrt sets the certificate and key file for TLS configuration of client.\nfunc (c *Client) SetTLSKeyCrt(crtFile, keyFile string) error {\n\ttlsConfig, err := LoadKeyCrt(crtFile, keyFile)\n\tif err != nil {\n\t\treturn gerror.Wrap(err, \"LoadKeyCrt failed\")\n\t}\n\tif v, ok := c.Transport.(*http.Transport); ok {\n\t\ttlsConfig.InsecureSkipVerify = true\n\t\tv.TLSClientConfig = tlsConfig\n\t\treturn nil\n\t}\n\treturn gerror.New(`cannot set TLSClientConfig for custom Transport of the client`)\n}\n\n// SetTLSConfig sets the TLS configuration of client.\nfunc (c *Client) SetTLSConfig(tlsConfig *tls.Config) error {\n\tif v, ok := c.Transport.(*http.Transport); ok {\n\t\tv.TLSClientConfig = tlsConfig\n\t\treturn nil\n\t}\n\treturn gerror.New(`cannot set TLSClientConfig for custom Transport of the client`)\n}\n\n// SetBuilder sets the load balance builder for client.\nfunc (c *Client) SetBuilder(builder gsel.Builder) {\n\tc.builder = builder\n}\n\n// SetDiscovery sets the load balance builder for client.\nfunc (c *Client) SetDiscovery(discovery gsvc.Discovery) {\n\tc.discovery = discovery\n}\n"
  },
  {
    "path": "net/gclient/gclient_content.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\n// GetContent is a convenience method for sending GET request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) GetContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodGet, url, data...))\n}\n\n// PutContent is a convenience method for sending PUT request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) PutContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodPut, url, data...))\n}\n\n// PostContent is a convenience method for sending POST request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) PostContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodPost, url, data...))\n}\n\n// DeleteContent is a convenience method for sending DELETE request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) DeleteContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodDelete, url, data...))\n}\n\n// HeadContent is a convenience method for sending HEAD request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) HeadContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodHead, url, data...))\n}\n\n// PatchContent is a convenience method for sending PATCH request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) PatchContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodPatch, url, data...))\n}\n\n// ConnectContent is a convenience method for sending CONNECT request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) ConnectContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodConnect, url, data...))\n}\n\n// OptionsContent is a convenience method for sending OPTIONS request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) OptionsContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodOptions, url, data...))\n}\n\n// TraceContent is a convenience method for sending TRACE request, which retrieves and returns\n// the result content and automatically closes response object.\nfunc (c *Client) TraceContent(ctx context.Context, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, http.MethodTrace, url, data...))\n}\n\n// RequestContent is a convenience method for sending custom http method request, which\n// retrieves and returns the result content and automatically closes response object.\nfunc (c *Client) RequestContent(ctx context.Context, method string, url string, data ...any) string {\n\treturn string(c.RequestBytes(ctx, method, url, data...))\n}\n"
  },
  {
    "path": "net/gclient/gclient_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gsel\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\ntype discoveryNode struct {\n\tservice gsvc.Service\n\taddress string\n}\n\n// Service is the client discovery service.\nfunc (n *discoveryNode) Service() gsvc.Service {\n\treturn n.service\n}\n\n// Address returns the address of the node.\nfunc (n *discoveryNode) Address() string {\n\treturn n.address\n}\n\n// service prefix to its selector map cache.\nvar clientSelectorMap = gmap.New(true)\n\n// internalMiddlewareDiscovery is a client middleware that enables service discovery feature for client.\nfunc internalMiddlewareDiscovery(c *Client, r *http.Request) (response *Response, err error) {\n\tif c.discovery == nil {\n\t\treturn c.Next(r)\n\t}\n\tvar (\n\t\tctx     = r.Context()\n\t\tservice gsvc.Service\n\t)\n\tservice, err = gsvc.GetAndWatchWithDiscovery(ctx, c.discovery, r.URL.Host, func(service gsvc.Service) {\n\t\tintlog.Printf(ctx, `http client watching service \"%s\" changed`, service.GetPrefix())\n\t\tif v := clientSelectorMap.Get(service.GetPrefix()); v != nil {\n\t\t\tif err = updateSelectorNodesByService(ctx, v.(gsel.Selector), service); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t}\n\t})\n\tif err != nil {\n\t\tif gerror.Code(err) == gcode.CodeNotFound {\n\t\t\tintlog.Printf(\n\t\t\t\tctx,\n\t\t\t\t`service discovery error with url \"%s:%s\":%s`,\n\t\t\t\tr.Method, r.URL.String(), err.Error(),\n\t\t\t)\n\t\t\treturn c.Next(r)\n\t\t}\n\t}\n\tif service == nil {\n\t\treturn c.Next(r)\n\t}\n\t// Balancer.\n\tvar (\n\t\tselectorMapKey   = service.GetPrefix()\n\t\tselectorMapValue = clientSelectorMap.GetOrSetFuncLock(selectorMapKey, func() any {\n\t\t\tintlog.Printf(ctx, `http client create selector for service \"%s\"`, selectorMapKey)\n\t\t\tselector := c.builder.Build()\n\t\t\t// Update selector nodes.\n\t\t\tif err = updateSelectorNodesByService(ctx, selector, service); err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn selector\n\t\t})\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tselector := selectorMapValue.(gsel.Selector)\n\t// Pick one node from multiple addresses.\n\tnode, done, err := selector.Pick(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif done != nil {\n\t\tdefer done(ctx, gsel.DoneInfo{})\n\t}\n\tr.Host = node.Address()\n\tr.URL.Host = node.Address()\n\treturn c.Next(r)\n}\n\nfunc updateSelectorNodesByService(ctx context.Context, selector gsel.Selector, service gsvc.Service) error {\n\tnodes := make(gsel.Nodes, 0)\n\tfor _, endpoint := range service.GetEndpoints() {\n\t\tnodes = append(nodes, &discoveryNode{\n\t\t\tservice: service,\n\t\t\taddress: endpoint.String(),\n\t\t})\n\t}\n\treturn selector.Update(ctx, nodes)\n}\n"
  },
  {
    "path": "net/gclient/gclient_dump.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// dumpTextFormat is the format of the dumped raw string\nconst dumpTextFormat = `+---------------------------------------------+\n|                   %s                  |\n+---------------------------------------------+\n%s\n%s\n`\n\n// getResponseBody returns the text of the response body.\nfunc getResponseBody(res *http.Response) string {\n\tif res.Body == nil {\n\t\treturn \"\"\n\t}\n\tbodyContent, _ := io.ReadAll(res.Body)\n\tres.Body = utils.NewReadCloser(bodyContent, true)\n\treturn string(bodyContent)\n}\n\n// RawRequest returns the raw content of the request.\nfunc (r *Response) RawRequest() string {\n\t// Response can be nil.\n\tif r == nil || r.request == nil {\n\t\treturn \"\"\n\t}\n\t// DumpRequestOut writes more request headers than DumpRequest, such as User-Agent.\n\tbs, err := httputil.DumpRequestOut(r.request, false)\n\tif err != nil {\n\t\tintlog.Errorf(r.request.Context(), `%+v`, err)\n\t\treturn \"\"\n\t}\n\treturn fmt.Sprintf(\n\t\tdumpTextFormat,\n\t\t\"REQUEST \",\n\t\tstring(bs),\n\t\tr.requestBody,\n\t)\n}\n\n// RawResponse returns the raw content of the response.\nfunc (r *Response) RawResponse() string {\n\t// Response might be nil.\n\tif r == nil || r.Response == nil {\n\t\treturn \"\"\n\t}\n\tbs, err := httputil.DumpResponse(r.Response, false)\n\tif err != nil {\n\t\tintlog.Errorf(r.request.Context(), `%+v`, err)\n\t\treturn \"\"\n\t}\n\n\treturn fmt.Sprintf(\n\t\tdumpTextFormat,\n\t\t\"RESPONSE\",\n\t\tstring(bs),\n\t\tgetResponseBody(r.Response),\n\t)\n}\n\n// Raw returns the raw text of the request and the response.\nfunc (r *Response) Raw() string {\n\treturn fmt.Sprintf(\"%s\\n%s\", r.RawRequest(), r.RawResponse())\n}\n\n// RawDump outputs the raw text of the request and the response to stdout.\nfunc (r *Response) RawDump() {\n\tfmt.Println(r.Raw())\n}\n"
  },
  {
    "path": "net/gclient/gclient_metrics.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype localMetricManager struct {\n\tHttpClientRequestActive        gmetric.UpDownCounter\n\tHttpClientRequestTotal         gmetric.Counter\n\tHttpClientRequestDuration      gmetric.Histogram\n\tHttpClientRequestDurationTotal gmetric.Counter\n\tHttpClientConnectionDuration   gmetric.Histogram\n\tHttpClientRequestBodySize      gmetric.Counter\n\tHttpClientResponseBodySize     gmetric.Counter\n}\n\nconst (\n\tmetricAttrKeyServerAddress          = \"server.address\"\n\tmetricAttrKeyServerPort             = \"server.port\"\n\tmetricAttrKeyUrlSchema              = \"url.schema\"\n\tmetricAttrKeyHttpRequestMethod      = \"http.request.method\"\n\tmetricAttrKeyHttpResponseStatusCode = \"http.response.status_code\"\n\tmetricAttrKeyNetworkProtocolVersion = \"network.protocol.version\"\n)\n\nvar (\n\t// metricManager for http client metrics.\n\tmetricManager = newMetricManager()\n)\n\nfunc newMetricManager() *localMetricManager {\n\tmeter := gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\tInstrument:        instrumentName,\n\t\tInstrumentVersion: gf.VERSION,\n\t})\n\tdurationBuckets := []float64{\n\t\t1,\n\t\t5,\n\t\t10,\n\t\t25,\n\t\t50,\n\t\t75,\n\t\t100,\n\t\t250,\n\t\t500,\n\t\t750,\n\t\t1000,\n\t\t2500,\n\t\t5000,\n\t\t7500,\n\t\t10000,\n\t\t30000,\n\t\t60000,\n\t}\n\tmm := &localMetricManager{\n\t\tHttpClientRequestDuration: meter.MustHistogram(\n\t\t\t\"http.client.request.duration\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Measures the duration of client requests.\",\n\t\t\t\tUnit:       \"ms\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t\tBuckets:    durationBuckets,\n\t\t\t},\n\t\t),\n\t\tHttpClientRequestTotal: meter.MustCounter(\n\t\t\t\"http.client.request.total\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Total processed request number.\",\n\t\t\t\tUnit:       \"\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpClientRequestActive: meter.MustUpDownCounter(\n\t\t\t\"http.client.request.active\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Number of active client requests.\",\n\t\t\t\tUnit:       \"\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpClientRequestDurationTotal: meter.MustCounter(\n\t\t\t\"http.client.request.duration_total\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Total execution duration of request.\",\n\t\t\t\tUnit:       \"ms\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpClientRequestBodySize: meter.MustCounter(\n\t\t\t\"http.client.request.body_size\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Outgoing request bytes total.\",\n\t\t\t\tUnit:       \"bytes\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpClientResponseBodySize: meter.MustCounter(\n\t\t\t\"http.client.response.body_size\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Response bytes total.\",\n\t\t\t\tUnit:       \"bytes\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpClientConnectionDuration: meter.MustHistogram(\n\t\t\t\"http.client.connection_duration\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Measures the connection establish duration of client requests.\",\n\t\t\t\tUnit:       \"ms\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t\tBuckets:    durationBuckets,\n\t\t\t},\n\t\t),\n\t}\n\treturn mm\n}\n\nfunc (m *localMetricManager) GetMetricOptionForHistogram(r *http.Request) gmetric.Option {\n\tattrMap := m.GetMetricAttributeMap(r)\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricOptionForHistogramByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricOptionForRequest(r *http.Request) gmetric.Option {\n\tattrMap := m.GetMetricAttributeMap(r)\n\treturn m.GetMetricOptionForRequestByMap(attrMap)\n}\n\nfunc (m *localMetricManager) GetMetricOptionForRequestByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t\tmetricAttrKeyHttpRequestMethod,\n\t\t\tmetricAttrKeyUrlSchema,\n\t\t\tmetricAttrKeyNetworkProtocolVersion,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricOptionForResponseByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t\tmetricAttrKeyHttpRequestMethod,\n\t\t\tmetricAttrKeyHttpResponseStatusCode,\n\t\t\tmetricAttrKeyUrlSchema,\n\t\t\tmetricAttrKeyNetworkProtocolVersion,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricAttributeMap(r *http.Request) gmetric.AttributeMap {\n\tvar (\n\t\tserverAddress   string\n\t\tserverPort      string\n\t\tprotocolVersion string\n\t\tattrMap         = make(gmetric.AttributeMap)\n\t)\n\tserverAddress, serverPort = gstr.List2(r.Host, \":\")\n\tif serverPort == \"\" {\n\t\t_, serverPort = gstr.List2(r.RemoteAddr, \":\")\n\t}\n\tif serverPort == \"\" {\n\t\tserverPort = \"80\"\n\t\tif r.URL.Scheme == \"https\" {\n\t\t\tserverPort = \"443\"\n\t\t}\n\t}\n\tif array := gstr.Split(r.Proto, \"/\"); len(array) > 1 {\n\t\tprotocolVersion = array[1]\n\t}\n\tattrMap.Sets(gmetric.AttributeMap{\n\t\tmetricAttrKeyServerAddress:          serverAddress,\n\t\tmetricAttrKeyServerPort:             serverPort,\n\t\tmetricAttrKeyUrlSchema:              r.URL.Scheme,\n\t\tmetricAttrKeyHttpRequestMethod:      r.Method,\n\t\tmetricAttrKeyNetworkProtocolVersion: protocolVersion,\n\t})\n\tif r.Response != nil {\n\t\tattrMap.Sets(gmetric.AttributeMap{\n\t\t\tmetricAttrKeyHttpResponseStatusCode: r.Response.Status,\n\t\t})\n\t}\n\treturn attrMap\n}\n\nfunc (c *Client) handleMetricsBeforeRequest(r *http.Request) {\n\tif !gmetric.IsEnabled() {\n\t\treturn\n\t}\n\n\tvar (\n\t\tctx             = r.Context()\n\t\tattrMap         = metricManager.GetMetricAttributeMap(r)\n\t\trequestOption   = metricManager.GetMetricOptionForRequestByMap(attrMap)\n\t\trequestBodySize = float64(r.ContentLength)\n\t)\n\tmetricManager.HttpClientRequestActive.Inc(\n\t\tctx,\n\t\trequestOption,\n\t)\n\tif requestBodySize > 0 {\n\t\tmetricManager.HttpClientRequestBodySize.Add(\n\t\t\tctx,\n\t\t\trequestBodySize,\n\t\t\trequestOption,\n\t\t)\n\t}\n}\n\nfunc (c *Client) handleMetricsAfterRequestDone(r *http.Request, requestStartTime *gtime.Time) {\n\tif !gmetric.IsEnabled() {\n\t\treturn\n\t}\n\n\tvar (\n\t\tctx             = r.Context()\n\t\tattrMap         = metricManager.GetMetricAttributeMap(r)\n\t\tduration        = float64(gtime.Now().Sub(requestStartTime).Milliseconds())\n\t\trequestOption   = metricManager.GetMetricOptionForRequestByMap(attrMap)\n\t\tresponseOption  = metricManager.GetMetricOptionForResponseByMap(attrMap)\n\t\thistogramOption = metricManager.GetMetricOptionForHistogramByMap(attrMap)\n\t)\n\tmetricManager.HttpClientRequestActive.Dec(\n\t\tctx,\n\t\trequestOption,\n\t)\n\tmetricManager.HttpClientRequestTotal.Inc(\n\t\tctx,\n\t\tresponseOption,\n\t)\n\tmetricManager.HttpClientRequestDuration.Record(\n\t\tduration,\n\t\thistogramOption,\n\t)\n\tmetricManager.HttpClientRequestDurationTotal.Add(\n\t\tctx,\n\t\tduration,\n\t\tresponseOption,\n\t)\n\tif r.Response != nil {\n\t\tvar responseBodySize = float64(r.Response.ContentLength)\n\t\tif responseBodySize > 0 {\n\t\t\tmetricManager.HttpClientResponseBodySize.Add(\n\t\t\t\tctx,\n\t\t\t\tresponseBodySize,\n\t\t\t\tresponseOption,\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/gclient/gclient_middleware.go",
    "content": "package gclient\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// HandlerFunc middleware handler func\ntype HandlerFunc = func(c *Client, r *http.Request) (*Response, error)\n\n// clientMiddleware is the plugin for http client request workflow management.\ntype clientMiddleware struct {\n\tclient       *Client       // http client.\n\thandlers     []HandlerFunc // mdl handlers.\n\thandlerIndex int           // current handler index.\n\tresp         *Response     // save resp.\n\terr          error         // save err.\n}\n\nconst clientMiddlewareKey gctx.StrKey = \"__clientMiddlewareKey\"\n\n// Use adds one or more middleware handlers to client.\nfunc (c *Client) Use(handlers ...HandlerFunc) *Client {\n\tc.middlewareHandler = append(c.middlewareHandler, handlers...)\n\treturn c\n}\n\n// Next calls the next middleware.\n// This should only be call in HandlerFunc.\nfunc (c *Client) Next(req *http.Request) (*Response, error) {\n\tif v := req.Context().Value(clientMiddlewareKey); v != nil {\n\t\tif m, ok := v.(*clientMiddleware); ok {\n\t\t\treturn m.Next(req)\n\t\t}\n\t}\n\treturn c.callRequest(req)\n}\n\n// Next calls the next middleware handler.\nfunc (m *clientMiddleware) Next(req *http.Request) (resp *Response, err error) {\n\tif m.err != nil {\n\t\treturn m.resp, m.err\n\t}\n\tif m.handlerIndex < len(m.handlers) {\n\t\tm.handlerIndex++\n\t\tm.resp, m.err = m.handlers[m.handlerIndex](m.client, req)\n\t}\n\treturn m.resp, m.err\n}\n"
  },
  {
    "path": "net/gclient/gclient_observability.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptrace\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tinstrumentName                              = \"github.com/gogf/gf/v2/net/gclient.Client\"\n\ttracingAttrHttpAddressRemote                = \"http.address.remote\"\n\ttracingAttrHttpAddressLocal                 = \"http.address.local\"\n\ttracingAttrHttpDnsStart                     = \"http.dns.start\"\n\ttracingAttrHttpDnsDone                      = \"http.dns.done\"\n\ttracingAttrHttpConnectStart                 = \"http.connect.start\"\n\ttracingAttrHttpConnectDone                  = \"http.connect.done\"\n\ttracingEventHttpRequest                     = \"http.request\"\n\ttracingEventHttpRequestHeaders              = \"http.request.headers\"\n\ttracingEventHttpRequestBaggage              = \"http.request.baggage\"\n\ttracingEventHttpResponse                    = \"http.response\"\n\ttracingEventHttpResponseHeaders             = \"http.response.headers\"\n\ttracingMiddlewareHandled        gctx.StrKey = `MiddlewareClientTracingHandled`\n)\n\n// internalMiddlewareObservability is a client middleware that enables observability feature.\nfunc internalMiddlewareObservability(c *Client, r *http.Request) (response *Response, err error) {\n\tvar ctx = r.Context()\n\t// Mark this request is handled by server tracing middleware,\n\t// to avoid repeated handling by the same middleware.\n\tif ctx.Value(tracingMiddlewareHandled) != nil {\n\t\treturn c.Next(r)\n\t}\n\n\tctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)\n\ttr := otel.GetTracerProvider().Tracer(\n\t\tinstrumentName,\n\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t)\n\tctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindClient))\n\tdefer span.End()\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\t// Inject tracing content into http header.\n\totel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))\n\n\t// Inject ClientTrace into context for http request.\n\tvar (\n\t\thttpClientTracer       *httptrace.ClientTrace\n\t\tbaseClientTracer       = newClientTracerNoop()\n\t\tisUsingDefaultProvider = gtrace.IsUsingDefaultProvider()\n\t)\n\t// Tracing.\n\tif !isUsingDefaultProvider {\n\t\tbaseClientTracer = newClientTracerTracing(ctx, span, r)\n\t}\n\t// Metrics.\n\tif gmetric.IsEnabled() {\n\t\tbaseClientTracer = newClientTracerMetrics(r, baseClientTracer)\n\t}\n\thttpClientTracer = newClientTracer(baseClientTracer)\n\tr = r.WithContext(\n\t\thttptrace.WithClientTrace(\n\t\t\tctx, httpClientTracer,\n\t\t),\n\t)\n\tresponse, err = c.Next(r)\n\n\t// If it is now using default trace provider, it then does no complex tracing jobs.\n\tif isUsingDefaultProvider {\n\t\treturn\n\t}\n\n\tif err != nil {\n\t\tspan.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))\n\t}\n\tif response == nil || response.Response == nil {\n\t\treturn\n\t}\n\n\tspan.AddEvent(tracingEventHttpResponse, trace.WithAttributes(\n\t\tattribute.String(\n\t\t\ttracingEventHttpResponseHeaders,\n\t\t\tgconv.String(httputil.HeaderToMap(response.Header)),\n\t\t),\n\t))\n\treturn\n}\n"
  },
  {
    "path": "net/gclient/gclient_request.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"mime\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Get send GET request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Get(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodGet, url, data...)\n}\n\n// Put send PUT request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Put(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodPut, url, data...)\n}\n\n// Post sends request using HTTP method POST and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Post(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodPost, url, data...)\n}\n\n// Delete send DELETE request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Delete(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodDelete, url, data...)\n}\n\n// Head send HEAD request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Head(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodHead, url, data...)\n}\n\n// Patch send PATCH request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Patch(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodPatch, url, data...)\n}\n\n// Connect send CONNECT request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Connect(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodConnect, url, data...)\n}\n\n// Options send OPTIONS request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Options(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodOptions, url, data...)\n}\n\n// Trace send TRACE request and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) Trace(ctx context.Context, url string, data ...any) (*Response, error) {\n\treturn c.DoRequest(ctx, http.MethodTrace, url, data...)\n}\n\n// PostForm is different from net/http.PostForm.\n// It's a wrapper of Post method, which sets the Content-Type as \"multipart/form-data;\".\n// and It will automatically set boundary characters for the request body and Content-Type.\n//\n// It's Seem like the following case:\n//\n// Content-Type: multipart/form-data; boundary=----Boundarye4Ghaog6giyQ9ncN\n//\n// And form data is like:\n// ------Boundarye4Ghaog6giyQ9ncN\n// Content-Disposition: form-data; name=\"checkType\"\n//\n// none\n//\n// It's used for sending form data.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) PostForm(ctx context.Context, url string, data map[string]string) (resp *Response, err error) {\n\tbody := new(bytes.Buffer)\n\tw := multipart.NewWriter(body)\n\tfor k, v := range data {\n\t\terr := w.WriteField(k, v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\terr = w.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.ContentType(w.FormDataContentType()).Post(ctx, url, body)\n}\n\n// DoRequest sends request with given HTTP method and data and returns the response object.\n// Note that the response object MUST be closed if it'll never be used.\n//\n// Note that it uses \"multipart/form-data\" as its Content-Type if it contains file uploading,\n// else it uses \"application/x-www-form-urlencoded\". It also automatically detects the post\n// content for JSON format, and for that it automatically sets the Content-Type as\n// \"application/json\".\nfunc (c *Client) DoRequest(\n\tctx context.Context, method, url string, data ...any,\n) (resp *Response, err error) {\n\tvar requestStartTime = gtime.Now()\n\treq, err := c.prepareRequest(ctx, method, url, data...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Metrics.\n\tc.handleMetricsBeforeRequest(req)\n\tdefer c.handleMetricsAfterRequestDone(req, requestStartTime)\n\n\t// Client middleware.\n\tif len(c.middlewareHandler) > 0 {\n\t\tmdlHandlers := make([]HandlerFunc, 0, len(c.middlewareHandler)+1)\n\t\tmdlHandlers = append(mdlHandlers, c.middlewareHandler...)\n\t\tmdlHandlers = append(mdlHandlers, func(cli *Client, r *http.Request) (*Response, error) {\n\t\t\treturn cli.callRequest(r)\n\t\t})\n\t\tctx = context.WithValue(req.Context(), clientMiddlewareKey, &clientMiddleware{\n\t\t\tclient:       c,\n\t\t\thandlers:     mdlHandlers,\n\t\t\thandlerIndex: -1,\n\t\t})\n\t\treq = req.WithContext(ctx)\n\t\tresp, err = c.Next(req)\n\t} else {\n\t\tresp, err = c.callRequest(req)\n\t}\n\tif resp != nil && resp.Response != nil {\n\t\treq.Response = resp.Response\n\t}\n\treturn resp, err\n}\n\n// prepareRequest verifies request parameters, builds and returns http request.\nfunc (c *Client) prepareRequest(ctx context.Context, method, url string, data ...any) (req *http.Request, err error) {\n\tmethod = strings.ToUpper(method)\n\tif len(c.prefix) > 0 {\n\t\turl = c.prefix + gstr.Trim(url)\n\t}\n\tif !gstr.ContainsI(url, httpProtocolName) {\n\t\turl = httpProtocolName + `://` + url\n\t}\n\tvar (\n\t\tparams             string\n\t\tallowFileUploading = true\n\t)\n\tif len(data) > 0 {\n\t\tmediaType, _, err := mime.ParseMediaType(c.header[httpHeaderContentType])\n\t\tif err != nil {\n\t\t\t// Fallback: use the raw header value if parsing fails.\n\t\t\tmediaType = c.header[httpHeaderContentType]\n\t\t}\n\t\tswitch mediaType {\n\t\tcase httpHeaderContentTypeJson:\n\t\t\tswitch data[0].(type) {\n\t\t\tcase string, []byte:\n\t\t\t\tparams = gconv.String(data[0])\n\t\t\tdefault:\n\t\t\t\tif b, err := json.Marshal(data[0]); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t} else {\n\t\t\t\t\tparams = string(b)\n\t\t\t\t}\n\t\t\t}\n\t\t\tallowFileUploading = false\n\n\t\tcase httpHeaderContentTypeXml:\n\t\t\tswitch data[0].(type) {\n\t\t\tcase string, []byte:\n\t\t\t\tparams = gconv.String(data[0])\n\t\t\tdefault:\n\t\t\t\tif b, err := gjson.New(data[0]).ToXml(); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t} else {\n\t\t\t\t\tparams = string(b)\n\t\t\t\t}\n\t\t\t}\n\t\t\tallowFileUploading = false\n\n\t\tdefault:\n\t\t\tparams = httputil.BuildParams(data[0], c.noUrlEncode)\n\t\t}\n\t}\n\tif method == http.MethodGet {\n\t\tvar bodyBuffer *bytes.Buffer\n\t\tif params != \"\" {\n\t\t\tmediaType, _, err := mime.ParseMediaType(c.header[httpHeaderContentType])\n\t\t\tif err != nil {\n\t\t\t\t// Fallback: use the raw header value if parsing fails.\n\t\t\t\tmediaType = c.header[httpHeaderContentType]\n\t\t\t}\n\t\t\tswitch mediaType {\n\t\t\tcase\n\t\t\t\thttpHeaderContentTypeJson,\n\t\t\t\thttpHeaderContentTypeXml:\n\t\t\t\tbodyBuffer = bytes.NewBuffer([]byte(params))\n\t\t\tdefault:\n\t\t\t\t// It appends the parameters to the url\n\t\t\t\t// if http method is GET and Content-Type is not specified.\n\t\t\t\tif gstr.Contains(url, \"?\") {\n\t\t\t\t\turl = url + \"&\" + params\n\t\t\t\t} else {\n\t\t\t\t\turl = url + \"?\" + params\n\t\t\t\t}\n\t\t\t\tbodyBuffer = bytes.NewBuffer(nil)\n\t\t\t}\n\t\t} else {\n\t\t\tbodyBuffer = bytes.NewBuffer(nil)\n\t\t}\n\t\tif req, err = http.NewRequest(method, url, bodyBuffer); err != nil {\n\t\t\terr = gerror.Wrapf(err, `http.NewRequest failed with method \"%s\" and URL \"%s\"`, method, url)\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tif allowFileUploading && strings.Contains(params, httpParamFileHolder) {\n\t\t\t// File uploading request.\n\t\t\tvar (\n\t\t\t\tbuffer          = bytes.NewBuffer(nil)\n\t\t\t\twriter          = multipart.NewWriter(buffer)\n\t\t\t\tisFileUploading = false\n\t\t\t)\n\t\t\tfor _, item := range strings.Split(params, \"&\") {\n\t\t\t\tarray := strings.SplitN(item, \"=\", 2)\n\t\t\t\tif len(array) < 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif len(array[1]) > 6 && strings.Compare(array[1][0:6], httpParamFileHolder) == 0 {\n\t\t\t\t\tpath := array[1][6:]\n\t\t\t\t\tif !gfile.Exists(path) {\n\t\t\t\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `\"%s\" does not exist`, path)\n\t\t\t\t\t}\n\t\t\t\t\tvar (\n\t\t\t\t\t\tfile          io.Writer\n\t\t\t\t\t\tformFileName  = gfile.Basename(path)\n\t\t\t\t\t\tformFieldName = array[0]\n\t\t\t\t\t)\n\t\t\t\t\t// it sets post content type as `application/octet-stream`\n\t\t\t\t\tif file, err = writer.CreateFormFile(formFieldName, formFileName); err != nil {\n\t\t\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\t\t\terr, `CreateFormFile failed with \"%s\", \"%s\"`, formFieldName, formFileName,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tvar f *os.File\n\t\t\t\t\tif f, err = gfile.Open(path); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif _, err = io.Copy(file, f); err != nil {\n\t\t\t\t\t\t_ = f.Close()\n\t\t\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\t\t\terr, `io.Copy failed from \"%s\" to form \"%s\"`, path, formFieldName,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tif err = f.Close(); err != nil {\n\t\t\t\t\t\treturn nil, gerror.Wrapf(err, `close file descriptor failed for \"%s\"`, path)\n\t\t\t\t\t}\n\t\t\t\t\tisFileUploading = true\n\t\t\t\t} else {\n\t\t\t\t\tvar (\n\t\t\t\t\t\tfieldName  = array[0]\n\t\t\t\t\t\tfieldValue = array[1]\n\t\t\t\t\t)\n\t\t\t\t\t// Decode URL-encoded field name and value.\n\t\t\t\t\t// If decoding fails, use the original value.\n\t\t\t\t\tif v, err := gurl.Decode(fieldName); err == nil {\n\t\t\t\t\t\tfieldName = v\n\t\t\t\t\t}\n\t\t\t\t\tif v, err := gurl.Decode(fieldValue); err == nil {\n\t\t\t\t\t\tfieldValue = v\n\t\t\t\t\t}\n\t\t\t\t\tif err = writer.WriteField(fieldName, fieldValue); err != nil {\n\t\t\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\t\t\terr, `write form field failed with \"%s\", \"%s\"`, fieldName, fieldValue,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Close finishes the multipart message and writes the trailing\n\t\t\t// boundary end line to the output.\n\t\t\tif err = writer.Close(); err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(err, `form writer close failed`)\n\t\t\t}\n\n\t\t\tif req, err = http.NewRequest(method, url, buffer); err != nil {\n\t\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\t\terr, `http.NewRequest failed for method \"%s\" and URL \"%s\"`, method, url,\n\t\t\t\t)\n\t\t\t}\n\t\t\tif isFileUploading {\n\t\t\t\treq.Header.Set(httpHeaderContentType, writer.FormDataContentType())\n\t\t\t}\n\t\t} else {\n\t\t\t// Normal request.\n\t\t\tparamBytes := []byte(params)\n\t\t\tif req, err = http.NewRequest(method, url, bytes.NewReader(paramBytes)); err != nil {\n\t\t\t\terr = gerror.Wrapf(err, `http.NewRequest failed for method \"%s\" and URL \"%s\"`, method, url)\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif v, ok := c.header[httpHeaderContentType]; ok {\n\t\t\t\t// Custom Content-Type.\n\t\t\t\treq.Header.Set(httpHeaderContentType, v)\n\t\t\t} else if len(paramBytes) > 0 {\n\t\t\t\tif (paramBytes[0] == '[' || paramBytes[0] == '{') && json.Valid(paramBytes) {\n\t\t\t\t\t// Auto-detecting and setting the post content format: JSON.\n\t\t\t\t\treq.Header.Set(httpHeaderContentType, httpHeaderContentTypeJson)\n\t\t\t\t} else if gregex.IsMatchString(httpRegexParamJson, params) {\n\t\t\t\t\t// If the parameters passed like \"name=value\", it then uses form type.\n\t\t\t\t\treq.Header.Set(httpHeaderContentType, httpHeaderContentTypeForm)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Context.\n\tif ctx != nil {\n\t\treq = req.WithContext(ctx)\n\t}\n\t// Custom header.\n\tif len(c.header) > 0 {\n\t\tfor k, v := range c.header {\n\t\t\treq.Header.Set(k, v)\n\t\t}\n\t}\n\t// It's necessary set the req.Host if you want to custom the host value of the request.\n\t// It uses the \"Host\" value from header if it's not empty.\n\tif reqHeaderHost := req.Header.Get(httpHeaderHost); reqHeaderHost != \"\" {\n\t\treq.Host = reqHeaderHost\n\t}\n\t// Custom Cookie.\n\tif len(c.cookies) > 0 {\n\t\theaderCookie := \"\"\n\t\tfor k, v := range c.cookies {\n\t\t\tif len(headerCookie) > 0 {\n\t\t\t\theaderCookie += \";\"\n\t\t\t}\n\t\t\theaderCookie += k + \"=\" + v\n\t\t}\n\t\tif len(headerCookie) > 0 {\n\t\t\treq.Header.Set(httpHeaderCookie, headerCookie)\n\t\t}\n\t}\n\t// HTTP basic authentication.\n\tif len(c.authUser) > 0 {\n\t\treq.SetBasicAuth(c.authUser, c.authPass)\n\t}\n\treturn req, nil\n}\n\n// callRequest sends request with give http.Request, and returns the responses object.\n// Note that the response object MUST be closed if it'll never be used.\nfunc (c *Client) callRequest(req *http.Request) (resp *Response, err error) {\n\tresp = &Response{\n\t\trequest: req,\n\t}\n\t// Dump feature.\n\t// The request body can be reused for dumping\n\t// raw HTTP request-response procedure.\n\treqBodyContent, _ := io.ReadAll(req.Body)\n\tresp.requestBody = reqBodyContent\n\tfor {\n\t\treq.Body = utils.NewReadCloser(reqBodyContent, false)\n\t\tif resp.Response, err = c.Do(req); err != nil {\n\t\t\terr = gerror.Wrapf(err, `request failed`)\n\t\t\t// The response might not be nil when err != nil.\n\t\t\tif resp.Response != nil {\n\t\t\t\t_ = resp.Body.Close()\n\t\t\t}\n\t\t\tif c.retryCount > 0 {\n\t\t\t\tc.retryCount--\n\t\t\t\ttime.Sleep(c.retryInterval)\n\t\t\t} else {\n\t\t\t\t// return resp, err\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn resp, err\n}\n"
  },
  {
    "path": "net/gclient/gclient_request_obj.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// DoRequestObj does HTTP request using standard request/response object.\n// The request object `req` is defined like:\n//\n//\ttype UseCreateReq struct {\n//\t    g.Meta `path:\"/user\" method:\"put\"`\n//\t    // other fields....\n//\t}\n//\n// The response object `res` should be a pointer type. It automatically converts result\n// to given object `res` is success.\n//\n// Example:\n// var (\n//\n//\treq = UseCreateReq{}\n//\tres *UseCreateRes\n//\n// )\n//\n// err := DoRequestObj(ctx, req, &res)\nfunc (c *Client) DoRequestObj(ctx context.Context, req, res any) error {\n\tvar (\n\t\tmethod = gmeta.Get(req, gtag.Method).String()\n\t\tpath   = gmeta.Get(req, gtag.Path).String()\n\t)\n\tif method == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`no \"%s\" tag found in request object: %s`,\n\t\t\tgtag.Method, reflect.TypeOf(req).String(),\n\t\t)\n\t}\n\tif path == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`no \"%s\" tag found in request object: %s`,\n\t\t\tgtag.Path, reflect.TypeOf(req).String(),\n\t\t)\n\t}\n\tpath = c.handlePathForObjRequest(path, req)\n\tswitch gstr.ToUpper(method) {\n\tcase\n\t\thttp.MethodGet,\n\t\thttp.MethodPut,\n\t\thttp.MethodPost,\n\t\thttp.MethodDelete,\n\t\thttp.MethodHead,\n\t\thttp.MethodPatch,\n\t\thttp.MethodConnect,\n\t\thttp.MethodOptions,\n\t\thttp.MethodTrace:\n\t\tif result := c.RequestVar(ctx, method, path, req); res != nil && !result.IsEmpty() {\n\t\t\treturn result.Scan(res)\n\t\t}\n\t\treturn nil\n\n\tdefault:\n\t\treturn gerror.Newf(`invalid HTTP method \"%s\"`, method)\n\t}\n}\n\n// handlePathForObjRequest replaces parameters in `path` with parameters from request object.\n// Eg:\n// /order/{id}  -> /order/1\n// /user/{name} -> /order/john\nfunc (c *Client) handlePathForObjRequest(path string, req any) string {\n\tif gstr.Contains(path, \"{\") {\n\t\trequestParamsMap := gconv.Map(req)\n\t\tif len(requestParamsMap) > 0 {\n\t\t\tpath, _ = gregex.ReplaceStringFuncMatch(`\\{(\\w+)\\}`, path, func(match []string) string {\n\t\t\t\tfoundKey, foundValue := gutil.MapPossibleItemByKey(requestParamsMap, match[1])\n\t\t\t\tif foundKey != \"\" {\n\t\t\t\t\treturn gconv.String(foundValue)\n\t\t\t\t}\n\t\t\t\treturn match[0]\n\t\t\t})\n\t\t}\n\t}\n\treturn path\n}\n"
  },
  {
    "path": "net/gclient/gclient_response.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// Response is the struct for client request response.\ntype Response struct {\n\t*http.Response                   // Response is the underlying http.Response object of certain request.\n\trequest        *http.Request     // Request is the underlying http.Request object of certain request.\n\trequestBody    []byte            // The body bytes of certain request, only available in Dump feature.\n\tcookies        map[string]string // Response cookies, which are only parsed once.\n}\n\n// initCookie initializes the cookie map attribute of Response.\nfunc (r *Response) initCookie() {\n\tif r.cookies == nil {\n\t\tr.cookies = make(map[string]string)\n\t\t// Response might be nil.\n\t\tif r.Response != nil {\n\t\t\tfor _, v := range r.Cookies() {\n\t\t\t\tr.cookies[v.Name] = v.Value\n\t\t\t}\n\t\t}\n\t}\n}\n\n// GetCookie retrieves and returns the cookie value of specified `key`.\nfunc (r *Response) GetCookie(key string) string {\n\tr.initCookie()\n\treturn r.cookies[key]\n}\n\n// GetCookieMap retrieves and returns a copy of current cookie values map.\nfunc (r *Response) GetCookieMap() map[string]string {\n\tr.initCookie()\n\tm := make(map[string]string, len(r.cookies))\n\tfor k, v := range r.cookies {\n\t\tm[k] = v\n\t}\n\treturn m\n}\n\n// ReadAll retrieves and returns the response content as []byte.\nfunc (r *Response) ReadAll() []byte {\n\t// Response might be nil.\n\tif r == nil || r.Response == nil {\n\t\treturn []byte{}\n\t}\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tintlog.Errorf(r.request.Context(), `%+v`, err)\n\t\treturn nil\n\t}\n\treturn body\n}\n\n// ReadAllString retrieves and returns the response content as string.\nfunc (r *Response) ReadAllString() string {\n\treturn string(r.ReadAll())\n}\n\n// SetBodyContent overwrites response content with custom one.\nfunc (r *Response) SetBodyContent(content []byte) {\n\tbuffer := bytes.NewBuffer(content)\n\tr.Body = io.NopCloser(buffer)\n\tr.ContentLength = int64(buffer.Len())\n}\n\n// Close closes the response when it will never be used.\nfunc (r *Response) Close() error {\n\tif r == nil || r.Response == nil {\n\t\treturn nil\n\t}\n\treturn r.Body.Close()\n}\n"
  },
  {
    "path": "net/gclient/gclient_tracer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"crypto/tls\"\n\t\"net/http/httptrace\"\n\t\"net/textproto\"\n)\n\ntype clientTracer struct {\n\t*httptrace.ClientTrace\n}\n\n// newClientTracer creates and returns object of httptrace.ClientTrace.\nfunc newClientTracer(baseClientTracer *httptrace.ClientTrace) *httptrace.ClientTrace {\n\tc := &clientTracer{\n\t\tClientTrace: baseClientTracer,\n\t}\n\treturn &httptrace.ClientTrace{\n\t\tGetConn:              c.GetConn,\n\t\tGotConn:              c.GotConn,\n\t\tPutIdleConn:          c.PutIdleConn,\n\t\tGotFirstResponseByte: c.GotFirstResponseByte,\n\t\tGot100Continue:       c.Got100Continue,\n\t\tGot1xxResponse:       c.Got1xxResponse,\n\t\tDNSStart:             c.DNSStart,\n\t\tDNSDone:              c.DNSDone,\n\t\tConnectStart:         c.ConnectStart,\n\t\tConnectDone:          c.ConnectDone,\n\t\tTLSHandshakeStart:    c.TLSHandshakeStart,\n\t\tTLSHandshakeDone:     c.TLSHandshakeDone,\n\t\tWroteHeaderField:     c.WroteHeaderField,\n\t\tWroteHeaders:         c.WroteHeaders,\n\t\tWait100Continue:      c.Wait100Continue,\n\t\tWroteRequest:         c.WroteRequest,\n\t}\n}\n\n// GetConn is called before a connection is created or\n// retrieved from an idle pool. The hostPort is the\n// \"host:port\" of the target or proxy. GetConn is called even\n// if there's already an idle cached connection available.\nfunc (ct *clientTracer) GetConn(hostPort string) {\n\tct.ClientTrace.GetConn(hostPort)\n}\n\n// GotConn is called after a successful connection is\n// obtained. There is no hook for failure to obtain a\n// connection; instead, use the error from\n// Transport.RoundTrip.\nfunc (ct *clientTracer) GotConn(info httptrace.GotConnInfo) {\n\tct.ClientTrace.GotConn(info)\n}\n\n// PutIdleConn is called when the connection is returned to\n// the idle pool. If err is nil, the connection was\n// successfully returned to the idle pool. If err is non-nil,\n// it describes why not. PutIdleConn is not called if\n// connection reuse is disabled via Transport.DisableKeepAlives.\n// PutIdleConn is called before the caller's Response.Body.Close\n// call returns.\n// For HTTP/2, this hook is not currently used.\nfunc (ct *clientTracer) PutIdleConn(err error) {\n\tct.ClientTrace.PutIdleConn(err)\n}\n\n// GotFirstResponseByte is called when the first byte of the response\n// headers is available.\nfunc (ct *clientTracer) GotFirstResponseByte() {\n\tct.ClientTrace.GotFirstResponseByte()\n}\n\n// Got100Continue is called if the server replies with a \"100\n// Continue\" response.\nfunc (ct *clientTracer) Got100Continue() {\n\tct.ClientTrace.Got100Continue()\n}\n\n// Got1xxResponse is called for each 1xx informational response header\n// returned before the final non-1xx response. Got1xxResponse is called\n// for \"100 Continue\" responses, even if Got100Continue is also defined.\n// If it returns an error, the client request is aborted with that error value.\nfunc (ct *clientTracer) Got1xxResponse(code int, header textproto.MIMEHeader) error {\n\treturn ct.ClientTrace.Got1xxResponse(code, header)\n}\n\n// DNSStart is called when a DNS lookup begins.\nfunc (ct *clientTracer) DNSStart(info httptrace.DNSStartInfo) {\n\tct.ClientTrace.DNSStart(info)\n}\n\n// DNSDone is called when a DNS lookup ends.\nfunc (ct *clientTracer) DNSDone(info httptrace.DNSDoneInfo) {\n\tct.ClientTrace.DNSDone(info)\n}\n\n// ConnectStart is called when a new connection's Dial begins.\n// If net.Dialer.DualStack (IPv6 \"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracer) ConnectStart(network, addr string) {\n\tct.ClientTrace.ConnectStart(network, addr)\n}\n\n// ConnectDone is called when a new connection's Dial\n// completes. The provided err indicates whether the\n// connection completed successfully.\n// If net.Dialer.DualStack (\"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracer) ConnectDone(network, addr string, err error) {\n\tct.ClientTrace.ConnectDone(network, addr, err)\n}\n\n// TLSHandshakeStart is called when the TLS handshake is started. When\n// connecting to an HTTPS site via an HTTP proxy, the handshake happens\n// after the CONNECT request is processed by the proxy.\nfunc (ct *clientTracer) TLSHandshakeStart() {\n\tct.ClientTrace.TLSHandshakeStart()\n}\n\n// TLSHandshakeDone is called after the TLS handshake with either the\n// successful handshake's connection state, or a non-nil error on handshake\n// failure.\nfunc (ct *clientTracer) TLSHandshakeDone(state tls.ConnectionState, err error) {\n\tct.ClientTrace.TLSHandshakeDone(state, err)\n}\n\n// WroteHeaderField is called after the Transport has written\n// each request header. At the time of this call the values\n// might be buffered and not yet written to the network.\nfunc (ct *clientTracer) WroteHeaderField(key string, value []string) {\n\tct.ClientTrace.WroteHeaderField(key, value)\n}\n\n// WroteHeaders is called after the Transport has written\n// all request headers.\nfunc (ct *clientTracer) WroteHeaders() {\n\tct.ClientTrace.WroteHeaders()\n}\n\n// Wait100Continue is called if the Request specified\n// \"Expect: 100-continue\" and the Transport has written the\n// request headers but is waiting for \"100 Continue\" from the\n// server before writing the request body.\nfunc (ct *clientTracer) Wait100Continue() {\n\tct.ClientTrace.Wait100Continue()\n}\n\n// WroteRequest is called with the result of writing the\n// request and any body. It may be called multiple times\n// in the case of retried requests.\nfunc (ct *clientTracer) WroteRequest(info httptrace.WroteRequestInfo) {\n\tct.ClientTrace.WroteRequest(info)\n}\n"
  },
  {
    "path": "net/gclient/gclient_tracer_metrics.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"crypto/tls\"\n\t\"net/http\"\n\t\"net/http/httptrace\"\n\t\"net/textproto\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\ntype clientTracerMetrics struct {\n\t*httptrace.ClientTrace\n\tRequest          *http.Request\n\tConnectStartTime *gtime.Time\n}\n\n// newClientTracerMetrics creates and returns object of httptrace.ClientTrace.\nfunc newClientTracerMetrics(request *http.Request, baseClientTracer *httptrace.ClientTrace) *httptrace.ClientTrace {\n\tc := &clientTracerMetrics{\n\t\tRequest:     request,\n\t\tClientTrace: baseClientTracer,\n\t}\n\treturn &httptrace.ClientTrace{\n\t\tGetConn:              c.GetConn,\n\t\tGotConn:              c.GotConn,\n\t\tPutIdleConn:          c.PutIdleConn,\n\t\tGotFirstResponseByte: c.GotFirstResponseByte,\n\t\tGot100Continue:       c.Got100Continue,\n\t\tGot1xxResponse:       c.Got1xxResponse,\n\t\tDNSStart:             c.DNSStart,\n\t\tDNSDone:              c.DNSDone,\n\t\tConnectStart:         c.ConnectStart,\n\t\tConnectDone:          c.ConnectDone,\n\t\tTLSHandshakeStart:    c.TLSHandshakeStart,\n\t\tTLSHandshakeDone:     c.TLSHandshakeDone,\n\t\tWroteHeaderField:     c.WroteHeaderField,\n\t\tWroteHeaders:         c.WroteHeaders,\n\t\tWait100Continue:      c.Wait100Continue,\n\t\tWroteRequest:         c.WroteRequest,\n\t}\n}\n\n// GetConn is called before a connection is created or\n// retrieved from an idle pool. The hostPort is the\n// \"host:port\" of the target or proxy. GetConn is called even\n// if there's already an idle cached connection available.\nfunc (ct *clientTracerMetrics) GetConn(hostPort string) {\n\tct.ClientTrace.GetConn(hostPort)\n}\n\n// GotConn is called after a successful connection is\n// obtained. There is no hook for failure to obtain a\n// connection; instead, use the error from\n// Transport.RoundTrip.\nfunc (ct *clientTracerMetrics) GotConn(info httptrace.GotConnInfo) {\n\tct.ClientTrace.GotConn(info)\n}\n\n// PutIdleConn is called when the connection is returned to\n// the idle pool. If err is nil, the connection was\n// successfully returned to the idle pool. If err is non-nil,\n// it describes why not. PutIdleConn is not called if\n// connection reuse is disabled via Transport.DisableKeepAlives.\n// PutIdleConn is called before the caller's Response.Body.Close\n// call returns.\n// For HTTP/2, this hook is not currently used.\nfunc (ct *clientTracerMetrics) PutIdleConn(err error) {\n\tct.ClientTrace.PutIdleConn(err)\n}\n\n// GotFirstResponseByte is called when the first byte of the response\n// headers is available.\nfunc (ct *clientTracerMetrics) GotFirstResponseByte() {\n\tct.ClientTrace.GotFirstResponseByte()\n}\n\n// Got100Continue is called if the server replies with a \"100\n// Continue\" response.\nfunc (ct *clientTracerMetrics) Got100Continue() {\n\tct.ClientTrace.Got100Continue()\n}\n\n// Got1xxResponse is called for each 1xx informational response header\n// returned before the final non-1xx response. Got1xxResponse is called\n// for \"100 Continue\" responses, even if Got100Continue is also defined.\n// If it returns an error, the client request is aborted with that error value.\nfunc (ct *clientTracerMetrics) Got1xxResponse(code int, header textproto.MIMEHeader) error {\n\treturn ct.ClientTrace.Got1xxResponse(code, header)\n}\n\n// DNSStart is called when a DNS lookup begins.\nfunc (ct *clientTracerMetrics) DNSStart(info httptrace.DNSStartInfo) {\n\tct.ClientTrace.DNSStart(info)\n}\n\n// DNSDone is called when a DNS lookup ends.\nfunc (ct *clientTracerMetrics) DNSDone(info httptrace.DNSDoneInfo) {\n\tct.ClientTrace.DNSDone(info)\n}\n\n// ConnectStart is called when a new connection's Dial begins.\n// If net.Dialer.DualStack (IPv6 \"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracerMetrics) ConnectStart(network, addr string) {\n\tif ct.Request.RemoteAddr == \"\" {\n\t\tct.Request.RemoteAddr = addr\n\t}\n\tct.ConnectStartTime = gtime.Now()\n\tct.ClientTrace.ConnectStart(network, addr)\n}\n\n// ConnectDone is called when a new connection's Dial\n// completes. The provided err indicates whether the\n// connection completed successfully.\n// If net.Dialer.DualStack (\"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracerMetrics) ConnectDone(network, addr string, err error) {\n\tvar (\n\t\tduration       = float64(gtime.Now().Sub(ct.ConnectStartTime).Milliseconds())\n\t\tdurationOption = metricManager.GetMetricOptionForHistogram(ct.Request)\n\t)\n\tmetricManager.HttpClientConnectionDuration.Record(\n\t\tduration,\n\t\tdurationOption,\n\t)\n\tct.ClientTrace.ConnectDone(network, addr, err)\n}\n\n// TLSHandshakeStart is called when the TLS handshake is started. When\n// connecting to an HTTPS site via an HTTP proxy, the handshake happens\n// after the CONNECT request is processed by the proxy.\nfunc (ct *clientTracerMetrics) TLSHandshakeStart() {\n\tct.ClientTrace.TLSHandshakeStart()\n}\n\n// TLSHandshakeDone is called after the TLS handshake with either the\n// successful handshake's connection state, or a non-nil error on handshake\n// failure.\nfunc (ct *clientTracerMetrics) TLSHandshakeDone(state tls.ConnectionState, err error) {\n\tct.ClientTrace.TLSHandshakeDone(state, err)\n}\n\n// WroteHeaderField is called after the Transport has written\n// each request header. At the time of this call the values\n// might be buffered and not yet written to the network.\nfunc (ct *clientTracerMetrics) WroteHeaderField(key string, value []string) {\n\tct.ClientTrace.WroteHeaderField(key, value)\n}\n\n// WroteHeaders is called after the Transport has written\n// all request headers.\nfunc (ct *clientTracerMetrics) WroteHeaders() {\n\tct.ClientTrace.WroteHeaders()\n}\n\n// Wait100Continue is called if the Request specified\n// \"Expect: 100-continue\" and the Transport has written the\n// request headers but is waiting for \"100 Continue\" from the\n// server before writing the request body.\nfunc (ct *clientTracerMetrics) Wait100Continue() {\n\tct.ClientTrace.Wait100Continue()\n}\n\n// WroteRequest is called with the result of writing the\n// request and any body. It may be called multiple times\n// in the case of retried requests.\nfunc (ct *clientTracerMetrics) WroteRequest(info httptrace.WroteRequestInfo) {\n\tct.ClientTrace.WroteRequest(info)\n}\n"
  },
  {
    "path": "net/gclient/gclient_tracer_noop.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"crypto/tls\"\n\t\"net/http/httptrace\"\n\t\"net/textproto\"\n)\n\ntype clientTracerNoop struct{}\n\n// newClientTracerNoop creates and returns object of httptrace.ClientTrace.\nfunc newClientTracerNoop() *httptrace.ClientTrace {\n\tc := &clientTracerNoop{}\n\treturn &httptrace.ClientTrace{\n\t\tGetConn:              c.GetConn,\n\t\tGotConn:              c.GotConn,\n\t\tPutIdleConn:          c.PutIdleConn,\n\t\tGotFirstResponseByte: c.GotFirstResponseByte,\n\t\tGot100Continue:       c.Got100Continue,\n\t\tGot1xxResponse:       c.Got1xxResponse,\n\t\tDNSStart:             c.DNSStart,\n\t\tDNSDone:              c.DNSDone,\n\t\tConnectStart:         c.ConnectStart,\n\t\tConnectDone:          c.ConnectDone,\n\t\tTLSHandshakeStart:    c.TLSHandshakeStart,\n\t\tTLSHandshakeDone:     c.TLSHandshakeDone,\n\t\tWroteHeaderField:     c.WroteHeaderField,\n\t\tWroteHeaders:         c.WroteHeaders,\n\t\tWait100Continue:      c.Wait100Continue,\n\t\tWroteRequest:         c.WroteRequest,\n\t}\n}\n\n// GetConn is called before a connection is created or\n// retrieved from an idle pool. The hostPort is the\n// \"host:port\" of the target or proxy. GetConn is called even\n// if there's already an idle cached connection available.\nfunc (*clientTracerNoop) GetConn(hostPort string) {}\n\n// GotConn is called after a successful connection is\n// obtained. There is no hook for failure to obtain a\n// connection; instead, use the error from\n// Transport.RoundTrip.\nfunc (*clientTracerNoop) GotConn(httptrace.GotConnInfo) {}\n\n// PutIdleConn is called when the connection is returned to\n// the idle pool. If err is nil, the connection was\n// successfully returned to the idle pool. If err is non-nil,\n// it describes why not. PutIdleConn is not called if\n// connection reuse is disabled via Transport.DisableKeepAlives.\n// PutIdleConn is called before the caller's Response.Body.Close\n// call returns.\n// For HTTP/2, this hook is not currently used.\nfunc (*clientTracerNoop) PutIdleConn(err error) {}\n\n// GotFirstResponseByte is called when the first byte of the response\n// headers is available.\nfunc (*clientTracerNoop) GotFirstResponseByte() {}\n\n// Got100Continue is called if the server replies with a \"100\n// Continue\" response.\nfunc (*clientTracerNoop) Got100Continue() {}\n\n// Got1xxResponse is called for each 1xx informational response header\n// returned before the final non-1xx response. Got1xxResponse is called\n// for \"100 Continue\" responses, even if Got100Continue is also defined.\n// If it returns an error, the client request is aborted with that error value.\nfunc (*clientTracerNoop) Got1xxResponse(code int, header textproto.MIMEHeader) error {\n\treturn nil\n}\n\n// DNSStart is called when a DNS lookup begins.\nfunc (*clientTracerNoop) DNSStart(httptrace.DNSStartInfo) {}\n\n// DNSDone is called when a DNS lookup ends.\nfunc (*clientTracerNoop) DNSDone(httptrace.DNSDoneInfo) {}\n\n// ConnectStart is called when a new connection's Dial begins.\n// If net.Dialer.DualStack (IPv6 \"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (*clientTracerNoop) ConnectStart(network, addr string) {}\n\n// ConnectDone is called when a new connection's Dial\n// completes. The provided err indicates whether the\n// connection completed successfully.\n// If net.Dialer.DualStack (\"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (*clientTracerNoop) ConnectDone(network, addr string, err error) {}\n\n// TLSHandshakeStart is called when the TLS handshake is started. When\n// connecting to an HTTPS site via an HTTP proxy, the handshake happens\n// after the CONNECT request is processed by the proxy.\nfunc (*clientTracerNoop) TLSHandshakeStart() {}\n\n// TLSHandshakeDone is called after the TLS handshake with either the\n// successful handshake's connection state, or a non-nil error on handshake\n// failure.\nfunc (*clientTracerNoop) TLSHandshakeDone(tls.ConnectionState, error) {}\n\n// WroteHeaderField is called after the Transport has written\n// each request header. At the time of this call the values\n// might be buffered and not yet written to the network.\nfunc (*clientTracerNoop) WroteHeaderField(key string, value []string) {}\n\n// WroteHeaders is called after the Transport has written\n// all request headers.\nfunc (*clientTracerNoop) WroteHeaders() {}\n\n// Wait100Continue is called if the Request specified\n// \"Expect: 100-continue\" and the Transport has written the\n// request headers but is waiting for \"100 Continue\" from the\n// server before writing the request body.\nfunc (*clientTracerNoop) Wait100Continue() {}\n\n// WroteRequest is called with the result of writing the\n// request and any body. It may be called multiple times\n// in the case of retried requests.\nfunc (*clientTracerNoop) WroteRequest(httptrace.WroteRequestInfo) {}\n"
  },
  {
    "path": "net/gclient/gclient_tracer_tracing.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptrace\"\n\t\"net/textproto\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// clientTracerTracing is used for implementing httptrace.ClientTrace.\ntype clientTracerTracing struct {\n\tcontext.Context\n\tspan        trace.Span\n\trequest     *http.Request\n\trequestBody []byte\n\theaders     map[string]any\n\tmtx         sync.Mutex\n}\n\n// newClientTracerTracing creates and returns object of httptrace.ClientTrace.\nfunc newClientTracerTracing(\n\tctx context.Context,\n\tspan trace.Span,\n\trequest *http.Request,\n) *httptrace.ClientTrace {\n\tct := &clientTracerTracing{\n\t\tContext: ctx,\n\t\tspan:    span,\n\t\trequest: request,\n\t\theaders: make(map[string]any),\n\t}\n\n\treqBodyContent, _ := io.ReadAll(ct.request.Body)\n\tct.requestBody = reqBodyContent\n\tct.request.Body = utils.NewReadCloser(reqBodyContent, false)\n\n\treturn &httptrace.ClientTrace{\n\t\tGetConn:              ct.GetConn,\n\t\tGotConn:              ct.GotConn,\n\t\tPutIdleConn:          ct.PutIdleConn,\n\t\tGotFirstResponseByte: ct.GotFirstResponseByte,\n\t\tGot100Continue:       ct.Got100Continue,\n\t\tGot1xxResponse:       ct.Got1xxResponse,\n\t\tDNSStart:             ct.DNSStart,\n\t\tDNSDone:              ct.DNSDone,\n\t\tConnectStart:         ct.ConnectStart,\n\t\tConnectDone:          ct.ConnectDone,\n\t\tTLSHandshakeStart:    ct.TLSHandshakeStart,\n\t\tTLSHandshakeDone:     ct.TLSHandshakeDone,\n\t\tWroteHeaderField:     ct.WroteHeaderField,\n\t\tWroteHeaders:         ct.WroteHeaders,\n\t\tWait100Continue:      ct.Wait100Continue,\n\t\tWroteRequest:         ct.WroteRequest,\n\t}\n}\n\n// GetConn is called before a connection is created or\n// retrieved from an idle pool. The hostPort is the\n// \"host:port\" of the target or proxy. GetConn is called even\n// if there's already an idle cached connection available.\nfunc (ct *clientTracerTracing) GetConn(host string) {}\n\n// GotConn is called after a successful connection is\n// obtained. There is no hook for failure to obtain a\n// connection; instead, use the error from\n// Transport.RoundTrip.\nfunc (ct *clientTracerTracing) GotConn(info httptrace.GotConnInfo) {\n\tremoteAddr := \"\"\n\tif info.Conn.RemoteAddr() != nil {\n\t\tremoteAddr = info.Conn.RemoteAddr().String()\n\t}\n\tlocalAddr := \"\"\n\tif info.Conn.LocalAddr() != nil {\n\t\tlocalAddr = info.Conn.LocalAddr().String()\n\t}\n\tct.span.SetAttributes(\n\t\tattribute.String(tracingAttrHttpAddressRemote, remoteAddr),\n\t\tattribute.String(tracingAttrHttpAddressLocal, localAddr),\n\t)\n}\n\n// PutIdleConn is called when the connection is returned to\n// the idle pool. If err is nil, the connection was\n// successfully returned to the idle pool. If err is non-nil,\n// it describes why not. PutIdleConn is not called if\n// connection reuse is disabled via Transport.DisableKeepAlives.\n// PutIdleConn is called before the caller's Response.Body.Close\n// call returns.\n// For HTTP/2, this hook is not currently used.\nfunc (ct *clientTracerTracing) PutIdleConn(err error) {\n\tif err != nil {\n\t\tct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))\n\t}\n}\n\n// GotFirstResponseByte is called when the first byte of the response\n// headers is available.\nfunc (ct *clientTracerTracing) GotFirstResponseByte() {}\n\n// Got100Continue is called if the server replies with a \"100\n// Continue\" response.\nfunc (ct *clientTracerTracing) Got100Continue() {}\n\n// Got1xxResponse is called for each 1xx informational response header\n// returned before the final non-1xx response. Got1xxResponse is called\n// for \"100 Continue\" responses, even if Got100Continue is also defined.\n// If it returns an error, the client request is aborted with that error value.\nfunc (ct *clientTracerTracing) Got1xxResponse(code int, header textproto.MIMEHeader) error {\n\treturn nil\n}\n\n// DNSStart is called when a DNS lookup begins.\nfunc (ct *clientTracerTracing) DNSStart(info httptrace.DNSStartInfo) {\n\tct.span.SetAttributes(\n\t\tattribute.String(tracingAttrHttpDnsStart, info.Host),\n\t)\n}\n\n// DNSDone is called when a DNS lookup ends.\nfunc (ct *clientTracerTracing) DNSDone(info httptrace.DNSDoneInfo) {\n\tvar buffer strings.Builder\n\tfor _, v := range info.Addrs {\n\t\tif buffer.Len() != 0 {\n\t\t\tbuffer.WriteString(\",\")\n\t\t}\n\t\tbuffer.WriteString(v.String())\n\t}\n\tif info.Err != nil {\n\t\tct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))\n\t}\n\tct.span.SetAttributes(\n\t\tattribute.String(tracingAttrHttpDnsDone, buffer.String()),\n\t)\n}\n\n// ConnectStart is called when a new connection's Dial begins.\n// If net.Dialer.DualStack (IPv6 \"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracerTracing) ConnectStart(network, addr string) {\n\tct.span.SetAttributes(\n\t\tattribute.String(tracingAttrHttpConnectStart, network+\"@\"+addr),\n\t)\n}\n\n// ConnectDone is called when a new connection's Dial\n// completes. The provided err indicates whether the\n// connection completed successfully.\n// If net.Dialer.DualStack (\"Happy Eyeballs\") support is\n// enabled, this may be called multiple times.\nfunc (ct *clientTracerTracing) ConnectDone(network, addr string, err error) {\n\tif err != nil {\n\t\tct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))\n\t}\n\tct.span.SetAttributes(\n\t\tattribute.String(tracingAttrHttpConnectDone, network+\"@\"+addr),\n\t)\n}\n\n// TLSHandshakeStart is called when the TLS handshake is started. When\n// connecting to an HTTPS site via an HTTP proxy, the handshake happens\n// after the CONNECT request is processed by the proxy.\nfunc (ct *clientTracerTracing) TLSHandshakeStart() {}\n\n// TLSHandshakeDone is called after the TLS handshake with either the\n// successful handshake's connection state, or a non-nil error on handshake\n// failure.\nfunc (ct *clientTracerTracing) TLSHandshakeDone(_ tls.ConnectionState, err error) {\n\tif err != nil {\n\t\tct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))\n\t}\n}\n\n// WroteHeaderField is called after the Transport has written\n// each request header. At the time of this call the values\n// might be buffered and not yet written to the network.\nfunc (ct *clientTracerTracing) WroteHeaderField(k string, v []string) {\n\tif len(v) > 1 {\n\t\tct.headers[k] = v\n\t} else if len(v) == 1 {\n\t\tct.headers[k] = v[0]\n\t}\n}\n\n// WroteHeaders is called after the Transport has written\n// all request headers.\nfunc (ct *clientTracerTracing) WroteHeaders() {}\n\n// Wait100Continue is called if the Request specified\n// \"Expect: 100-continue\" and the Transport has written the\n// request headers but is waiting for \"100 Continue\" from the\n// server before writing the request body.\nfunc (ct *clientTracerTracing) Wait100Continue() {}\n\n// WroteRequest is called with the result of writing the\n// request and any body. It may be called multiple times\n// in the case of retried requests.\nfunc (ct *clientTracerTracing) WroteRequest(info httptrace.WroteRequestInfo) {\n\tif info.Err != nil {\n\t\tct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))\n\t}\n\n\tct.span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(\n\t\tattribute.String(tracingEventHttpRequestHeaders, gconv.String(ct.headers)),\n\t\tattribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context).String()),\n\t))\n}\n"
  },
  {
    "path": "net/gclient/gclient_var.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// GetVar sends a GET request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) GetVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodGet, url, data...)\n}\n\n// PutVar sends a PUT request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) PutVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodPut, url, data...)\n}\n\n// PostVar sends a POST request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) PostVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodPost, url, data...)\n}\n\n// DeleteVar sends a DELETE request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) DeleteVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodDelete, url, data...)\n}\n\n// HeadVar sends a HEAD request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) HeadVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodHead, url, data...)\n}\n\n// PatchVar sends a PATCH request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) PatchVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodPatch, url, data...)\n}\n\n// ConnectVar sends a CONNECT request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) ConnectVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodConnect, url, data...)\n}\n\n// OptionsVar sends an OPTIONS request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) OptionsVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodOptions, url, data...)\n}\n\n// TraceVar sends a TRACE request, retrieves and converts the result content to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) TraceVar(ctx context.Context, url string, data ...any) *gvar.Var {\n\treturn c.RequestVar(ctx, http.MethodTrace, url, data...)\n}\n\n// RequestVar sends request using given HTTP method and data, retrieves converts the result to *gvar.Var.\n// The client reads and closes the response object internally automatically.\n// The result *gvar.Var can be conveniently converted to any type you want.\nfunc (c *Client) RequestVar(ctx context.Context, method string, url string, data ...any) *gvar.Var {\n\tresponse, err := c.DoRequest(ctx, method, url, data...)\n\tif err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\treturn gvar.New(nil)\n\t}\n\tdefer func() {\n\t\tif err = response.Close(); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}()\n\treturn gvar.New(response.ReadAll())\n}\n"
  },
  {
    "path": "net/gclient/gclient_websocket.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient\n\nimport (\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n)\n\n// WebSocketClient wraps the underlying websocket client connection\n// and provides convenient functions.\n//\n// Deprecated: please use third-party library for websocket client instead.\ntype WebSocketClient struct {\n\t*websocket.Dialer\n}\n\n// NewWebSocket creates and returns a new WebSocketClient object.\n//\n// Deprecated: please use third-party library for websocket client instead.\nfunc NewWebSocket() *WebSocketClient {\n\treturn &WebSocketClient{\n\t\t&websocket.Dialer{\n\t\t\tProxy:            http.ProxyFromEnvironment,\n\t\t\tHandshakeTimeout: 45 * time.Second,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "net/gclient/gclient_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient_test\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\tcrtFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.crt\"\n\tkeyFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.key\"\n)\n\nfunc init() {\n\t// Default server for client.\n\tp := 8999\n\ts := g.Server(p)\n\t// HTTP method handlers.\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"GET: query: %d, %s\",\n\t\t\t\tr.GetQuery(\"id\").Int(),\n\t\t\t\tr.GetQuery(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.PUT(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"PUT: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.POST(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"POST: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.DELETE(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"DELETE: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.HEAD(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"HEAD: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.PATCH(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"PATCH: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.CONNECT(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"CONNECT: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.OPTIONS(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"OPTIONS: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t\tgroup.TRACE(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"TRACE: form: %d, %s\",\n\t\t\t\tr.GetForm(\"id\").Int(),\n\t\t\t\tr.GetForm(\"name\").String(),\n\t\t\t)\n\t\t})\n\t})\n\t// Client chaining operations handlers.\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/header\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"Span-Id: %s, Trace-Id: %s\",\n\t\t\t\tr.Header.Get(\"Span-Id\"),\n\t\t\t\tr.Header.Get(\"Trace-Id\"),\n\t\t\t)\n\t\t})\n\t\tgroup.ALL(\"/cookie\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"SessionId: %s\",\n\t\t\t\tr.Cookie.Get(\"SessionId\"),\n\t\t\t)\n\t\t})\n\t\tgroup.ALL(\"/json\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writef(\n\t\t\t\t\"Content-Type: %s, id: %d\",\n\t\t\t\tr.Header.Get(\"Content-Type\"),\n\t\t\t\tr.Get(\"id\").Int(),\n\t\t\t)\n\t\t})\n\t})\n\t// Other testing handlers.\n\ts.Group(\"/var\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/json\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(`{\"id\":1,\"name\":\"john\"}`)\n\t\t})\n\t\tgroup.ALL(\"/jsons\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(`[{\"id\":1,\"name\":\"john\"}, {\"id\":2,\"name\":\"smith\"}]`)\n\t\t})\n\t})\n\ts.SetAccessLogEnabled(false)\n\ts.SetDumpRouterMap(false)\n\ts.SetPort(p)\n\terr := s.Start()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\ttime.Sleep(time.Millisecond * 500)\n}\n\nfunc ExampleNew() {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tclient = gclient.New()\n\t)\n\n\tif r, err := client.Get(ctx, \"http://127.0.0.1:8999/var/json\"); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tdefer r.Close()\n\t\tfmt.Println(r.ReadAllString())\n\t}\n\n\t// Output:\n\t// {\"id\":1,\"name\":\"john\"}\n}\n\nfunc ExampleClient_Clone() {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tclient = gclient.New()\n\t)\n\n\tclient.SetCookie(\"key\", \"value\")\n\tcloneClient := client.Clone()\n\n\tif r, err := cloneClient.Get(ctx, \"http://127.0.0.1:8999/var/json\"); err != nil {\n\t\tpanic(err)\n\t} else {\n\t\tdefer r.Close()\n\t\tfmt.Println(r.ReadAllString())\n\t}\n\n\t// Output:\n\t// {\"id\":1,\"name\":\"john\"}\n}\n\nfunc fromHex(s string) []byte {\n\tb, _ := hex.DecodeString(s)\n\treturn b\n}\n\nfunc ExampleNew_ctx() {\n\tvar (\n\t\tctx    = gctx.New()\n\t\tclient = g.Client()\n\t)\n\n\t// controls the maximum idle(keep-alive) connections to keep per-host\n\tclient.Transport.(*http.Transport).MaxIdleConnsPerHost = 5\n\n\tfor i := 0; i < 5; i++ {\n\t\tif r, err := client.Get(ctx, \"http://127.0.0.1:8999/var/json\"); err != nil {\n\t\t\tpanic(err)\n\t\t} else {\n\t\t\tfmt.Println(r.ReadAllString())\n\t\t\tr.Close()\n\t\t}\n\t}\n\n\t// Output:\n\t// {\"id\":1,\"name\":\"john\"}\n\t// {\"id\":1,\"name\":\"john\"}\n\t// {\"id\":1,\"name\":\"john\"}\n\t// {\"id\":1,\"name\":\"john\"}\n\t// {\"id\":1,\"name\":\"john\"}\n}\n\nfunc ExampleClient_Header() {\n\tvar (\n\t\turl    = \"http://127.0.0.1:8999/header\"\n\t\theader = g.MapStrStr{\n\t\t\t\"Span-Id\":  \"0.1\",\n\t\t\t\"Trace-Id\": \"123456789\",\n\t\t}\n\t)\n\tcontent := g.Client().Header(header).PostContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tfmt.Println(content)\n\n\t// Output:\n\t// Span-Id: 0.1, Trace-Id: 123456789\n}\n\nfunc ExampleClient_HeaderRaw() {\n\tvar (\n\t\turl       = \"http://127.0.0.1:8999/header\"\n\t\theaderRaw = `\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3950.0 Safari/537.36\nSpan-Id: 0.1\nTrace-Id: 123456789\n`\n\t)\n\tcontent := g.Client().HeaderRaw(headerRaw).PostContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tfmt.Println(content)\n\n\t// Output:\n\t// Span-Id: 0.1, Trace-Id: 123456789\n}\n\nfunc ExampleClient_Cookie() {\n\tvar (\n\t\turl    = \"http://127.0.0.1:8999/cookie\"\n\t\tcookie = g.MapStrStr{\n\t\t\t\"SessionId\": \"123\",\n\t\t}\n\t)\n\tcontent := g.Client().Cookie(cookie).PostContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tfmt.Println(content)\n\n\t// Output:\n\t// SessionId: 123\n}\n\nfunc ExampleClient_ContentJson() {\n\tvar (\n\t\turl     = \"http://127.0.0.1:8999/json\"\n\t\tjsonStr = `{\"id\":10000,\"name\":\"john\"}`\n\t\tjsonMap = g.Map{\n\t\t\t\"id\":   10000,\n\t\t\t\"name\": \"john\",\n\t\t}\n\t)\n\t// Post using JSON string.\n\tfmt.Println(g.Client().ContentJson().PostContent(ctx, url, jsonStr))\n\t// Post using JSON map.\n\tfmt.Println(g.Client().ContentJson().PostContent(ctx, url, jsonMap))\n\n\t// Output:\n\t// Content-Type: application/json, id: 10000\n\t// Content-Type: application/json, id: 10000\n}\n\nfunc ExampleClient_Post() {\n\turl := \"http://127.0.0.1:8999\"\n\t// Send with string parameter in request body.\n\tr1, err := g.Client().Post(ctx, url, \"id=10000&name=john\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer r1.Close()\n\tfmt.Println(r1.ReadAllString())\n\n\t// Send with map parameter.\n\tr2, err := g.Client().Post(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer r2.Close()\n\tfmt.Println(r2.ReadAllString())\n\n\t// Output:\n\t// POST: form: 10000, john\n\t// POST: form: 10000, john\n}\n\nfunc ExampleClient_PostBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().PostBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// POST: form: 10000, john\n}\n\nfunc ExampleClient_DeleteBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().DeleteBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// DELETE: form: 10000, john\n}\n\nfunc ExampleClient_HeadBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().HeadBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n}\n\nfunc ExampleClient_PatchBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().PatchBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// PATCH: form: 10000, john\n}\n\nfunc ExampleClient_ConnectBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().ConnectBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// CONNECT: form: 10000, john\n}\n\nfunc ExampleClient_OptionsBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().OptionsBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// OPTIONS: form: 10000, john\n}\n\nfunc ExampleClient_TraceBytes() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(string(g.Client().TraceBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// TRACE: form: 10000, john\n}\n\nfunc ExampleClient_PostContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().PostContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// POST: form: 10000, john\n}\n\nfunc ExampleClient_PostVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().PostVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n\nfunc ExampleClient_Get() {\n\tvar (\n\t\tctx = context.Background()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\n\t// Send with string parameter along with URL.\n\tr1, err := g.Client().Get(ctx, url+\"?id=10000&name=john\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer r1.Close()\n\tfmt.Println(r1.ReadAllString())\n\n\t// Send with string parameter in request body.\n\tr2, err := g.Client().Get(ctx, url, \"id=10000&name=john\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer r2.Close()\n\tfmt.Println(r2.ReadAllString())\n\n\t// Send with map parameter.\n\tr3, err := g.Client().Get(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer r3.Close()\n\tfmt.Println(r3.ReadAllString())\n\n\t// Output:\n\t// GET: query: 10000, john\n\t// GET: query: 10000, john\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_Put() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Put(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// PUT: form: 10000, john\n}\n\nfunc ExampleClient_GetBytes() {\n\tvar (\n\t\tctx = context.Background()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tfmt.Println(string(g.Client().GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_PutBytes() {\n\tvar (\n\t\tctx = context.Background()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tfmt.Println(string(g.Client().PutBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// PUT: form: 10000, john\n}\n\nfunc ExampleClient_GetContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().GetContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_GetVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tuser *User\n\t\tctx  = context.Background()\n\t\turl  = \"http://127.0.0.1:8999/var/json\"\n\t)\n\terr := g.Client().GetVar(ctx, url).Scan(&user)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(user)\n\n\t// Output:\n\t// &{1 john}\n}\n\n// ExampleClient_SetProxy an example for `gclient.Client.SetProxy` method.\n// please prepare two proxy server before running this example.\n// http proxy server listening on `127.0.0.1:1081`\n// socks5 proxy server listening on `127.0.0.1:1080`\nfunc ExampleClient_SetProxy() {\n\t// connect to an http proxy server\n\tclient := g.Client()\n\tclient.SetProxy(\"http://127.0.0.1:1081\")\n\tclient.SetTimeout(5 * time.Second) // it's suggested to set http client timeout\n\tresp, err := client.Get(ctx, \"http://127.0.0.1:8999\")\n\tif err != nil {\n\t\t// err is not nil when your proxy server is down.\n\t\t// eg. Get \"http://127.0.0.1:8999\": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused\n\t}\n\tfmt.Println(err != nil)\n\tresp.Close()\n\n\t// connect to an http proxy server which needs auth\n\tclient.SetProxy(\"http://user:password:127.0.0.1:1081\")\n\tclient.SetTimeout(5 * time.Second) // it's suggested to set http client timeout\n\tresp, err = client.Get(ctx, \"http://127.0.0.1:8999\")\n\tif err != nil {\n\t\t// err is not nil when your proxy server is down.\n\t\t// eg. Get \"http://127.0.0.1:8999\": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused\n\t}\n\tfmt.Println(err != nil)\n\tresp.Close()\n\n\t// connect to a socks5 proxy server\n\tclient.SetProxy(\"socks5://127.0.0.1:1080\")\n\tclient.SetTimeout(5 * time.Second) // it's suggested to set http client timeout\n\tresp, err = client.Get(ctx, \"http://127.0.0.1:8999\")\n\tif err != nil {\n\t\t// err is not nil when your proxy server is down.\n\t\t// eg. Get \"http://127.0.0.1:8999\": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused\n\t}\n\tfmt.Println(err != nil)\n\tresp.Close()\n\n\t// connect to a socks5 proxy server which needs auth\n\tclient.SetProxy(\"socks5://user:password@127.0.0.1:1080\")\n\tclient.SetTimeout(5 * time.Second) // it's suggested to set http client timeout\n\tresp, err = client.Get(ctx, \"http://127.0.0.1:8999\")\n\tif err != nil {\n\t\t// err is not nil when your proxy server is down.\n\t\t// eg. Get \"http://127.0.0.1:8999\": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused\n\t}\n\tfmt.Println(err != nil)\n\tresp.Close()\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// true\n}\n\n// ExampleClient_Proxy a chain version of example for `gclient.Client.Proxy` method.\n// please prepare two proxy server before running this example.\n// http proxy server listening on `127.0.0.1:1081`\n// socks5 proxy server listening on `127.0.0.1:1080`\n// for more details, please refer to ExampleClient_SetProxy\nfunc ExampleClient_Proxy() {\n\tvar (\n\t\tctx = context.Background()\n\t)\n\tclient := g.Client()\n\t_, err := client.Proxy(\"http://127.0.0.1:1081\").Get(ctx, \"http://127.0.0.1:8999\")\n\tfmt.Println(err != nil)\n\n\tclient2 := g.Client()\n\t_, err = client2.Proxy(\"socks5://127.0.0.1:1080\").Get(ctx, \"http://127.0.0.1:8999\")\n\tfmt.Println(err != nil)\n\n\tclient3 := g.Client()\n\t_, err = client3.Proxy(\"\").Get(ctx, \"http://127.0.0.1:8999\")\n\tfmt.Println(err != nil)\n\n\tclient4 := g.Client()\n\turl := \"http://127.0.0.1:1081\" + string([]byte{0x7f})\n\t_, err = client4.Proxy(url).Get(ctx, \"http://127.0.0.1:8999\")\n\tfmt.Println(err != nil)\n\n\t// Output:\n\t// true\n\t// true\n\t// false\n\t// false\n}\n\nfunc ExampleClient_Prefix() {\n\tvar (\n\t\tctx = gctx.New()\n\t)\n\n\ts := g.Server(guid.S())\n\t// HTTP method handlers.\n\ts.Group(\"/api\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/v1/prefix\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"this is v1 prefix\")\n\t\t})\n\t\tgroup.GET(\"/v1/hello\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"this is v1 hello\")\n\t\t})\n\t})\n\ts.SetAccessLogEnabled(false)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\ttime.Sleep(time.Millisecond * 100)\n\n\t// Add Client URI Prefix\n\tclient := g.Client().Prefix(fmt.Sprintf(\n\t\t\"http://127.0.0.1:%d/api/v1/\", s.GetListenedPort(),\n\t))\n\n\tfmt.Println(string(client.GetBytes(ctx, \"prefix\")))\n\tfmt.Println(string(client.GetBytes(ctx, \"hello\")))\n\n\t// Output:\n\t// this is v1 prefix\n\t// this is v1 hello\n}\n\nfunc ExampleClient_Retry() {\n\tvar (\n\t\tctx = gctx.New()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tclient := g.Client().Retry(2, time.Second)\n\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_RedirectLimit() {\n\tvar (\n\t\tctx = gctx.New()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tclient := g.Client().RedirectLimit(1)\n\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_SetBrowserMode() {\n\tvar (\n\t\tctx = gctx.New()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tclient := g.Client().SetBrowserMode(true)\n\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_SetHeader() {\n\tvar (\n\t\tctx = gctx.New()\n\t\turl = \"http://127.0.0.1:8999\"\n\t)\n\tclient := g.Client()\n\tclient.SetHeader(\"Server\", \"GoFrameServer\")\n\tclient.SetHeader(\"Client\", \"g.Client()\")\n\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_SetRedirectLimit() {\n\tgo func() {\n\t\ts := g.Server()\n\t\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writeln(\"hello world\")\n\t\t})\n\t\ts.BindHandler(\"/back\", func(r *ghttp.Request) {\n\t\t\tr.Response.RedirectBack()\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.SetPort(8199)\n\t\ts.Run()\n\t}()\n\n\ttime.Sleep(time.Second)\n\n\tvar (\n\t\tctx      = gctx.New()\n\t\turlHello = \"http://127.0.0.1:8199/hello\"\n\t\turlBack  = \"http://127.0.0.1:8199/back\"\n\t)\n\tclient := g.Client().SetRedirectLimit(1)\n\tclient.SetHeader(\"Referer\", urlHello)\n\n\tresp, err := client.DoRequest(ctx, http.MethodGet, urlBack, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tif err == nil {\n\t\tfmt.Println(resp.ReadAllString())\n\t\tresp.Close()\n\t}\n\n\tclient.SetRedirectLimit(2)\n\tresp, err = client.DoRequest(ctx, http.MethodGet, urlBack, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tif err == nil {\n\t\tfmt.Println(resp.ReadAllString())\n\t\tresp.Close()\n\t}\n\n\t// Output:\n\t// Found\n\t// hello world\n}\n\nfunc ExampleClient_SetTLSKeyCrt() {\n\tvar (\n\t\tctx         = gctx.New()\n\t\turl         = \"http://127.0.0.1:8999\"\n\t\ttestCrtFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/upload/file1.txt\"\n\t\ttestKeyFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/upload/file2.txt\"\n\t)\n\tclient := g.Client()\n\tclient.SetTLSKeyCrt(testCrtFile, testKeyFile)\n\tclient.SetTLSKeyCrt(crtFile, keyFile)\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_SetTLSConfig() {\n\tvar (\n\t\tctx       = gctx.New()\n\t\turl       = \"http://127.0.0.1:8999\"\n\t\ttlsConfig = &tls.Config{}\n\t)\n\tclient := g.Client()\n\tclient.SetTLSConfig(tlsConfig)\n\tfmt.Println(string(client.GetBytes(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_PutContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().PutContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// PUT: form: 10000, john\n}\n\nfunc ExampleClient_DeleteContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().DeleteContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// DELETE: form: 10000, john\n}\n\nfunc ExampleClient_HeadContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().HeadContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n}\n\nfunc ExampleClient_PatchContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().PatchContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// PATCH: form: 10000, john\n}\n\nfunc ExampleClient_ConnectContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().ConnectContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// CONNECT: form: 10000, john\n}\n\nfunc ExampleClient_OptionsContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().OptionsContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// OPTIONS: form: 10000, john\n}\n\nfunc ExampleClient_TraceContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().TraceContent(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// TRACE: form: 10000, john\n}\n\nfunc ExampleClient_RequestContent() {\n\turl := \"http://127.0.0.1:8999\"\n\tfmt.Println(g.Client().RequestContent(ctx, http.MethodGet, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t}))\n\n\t// Output:\n\t// GET: query: 10000, john\n}\n\nfunc ExampleClient_Get_url() {\n\turl := \"http://127.0.0.1:8999\"\n\tresponse, _ := g.Client().Get(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tfmt.Println(len(response.RawResponse()) > 100)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleClient_Delete() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Delete(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// DELETE: form: 10000, john\n}\n\nfunc ExampleClient_Head() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Head(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t//\n}\n\nfunc ExampleClient_Patch() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Patch(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// PATCH: form: 10000, john\n}\n\nfunc ExampleClient_Connect() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Connect(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// CONNECT: form: 10000, john\n}\n\nfunc ExampleClient_Options() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Options(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// OPTIONS: form: 10000, john\n}\n\nfunc ExampleClient_Trace() {\n\turl := \"http://127.0.0.1:8999\"\n\tr, _ := g.Client().Trace(ctx, url, g.Map{\n\t\t\"id\":   10000,\n\t\t\"name\": \"john\",\n\t})\n\tdefer r.Close()\n\tfmt.Println(r.ReadAllString())\n\n\t// Output:\n\t// TRACE: form: 10000, john\n}\n\nfunc ExampleClient_PutVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tuser *User\n\t\tctx  = context.Background()\n\t\turl  = \"http://127.0.0.1:8999/var/json\"\n\t)\n\terr := g.Client().PutVar(ctx, url).Scan(&user)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(user)\n\n\t// Output:\n\t// &{1 john}\n}\n\nfunc ExampleClient_DeleteVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().DeleteVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n\nfunc ExampleClient_HeadVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().HeadVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// []\n}\n\nfunc ExampleClient_PatchVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().PatchVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n\nfunc ExampleClient_ConnectVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().ConnectVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n\nfunc ExampleClient_OptionsVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().OptionsVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n\nfunc ExampleClient_TraceVar() {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\tvar (\n\t\tusers []User\n\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t)\n\terr := g.Client().TraceVar(ctx, url).Scan(&users)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(users)\n\n\t// Output:\n\t// [{1 john} {2 smith}]\n}\n"
  },
  {
    "path": "net/gclient/gclient_z_unit_feature_trace_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\tsdkTrace \"go.opentelemetry.io/otel/sdk/trace\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/tracing\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype CustomProvider struct {\n\t*sdkTrace.TracerProvider\n}\n\nfunc NewCustomProvider() *CustomProvider {\n\treturn &CustomProvider{\n\t\tTracerProvider: sdkTrace.NewTracerProvider(\n\t\t\tsdkTrace.WithIDGenerator(NewCustomIDGenerator()),\n\t\t),\n\t}\n}\n\ntype CustomIDGenerator struct{}\n\nfunc NewCustomIDGenerator() *CustomIDGenerator {\n\treturn &CustomIDGenerator{}\n}\n\nfunc (id *CustomIDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) {\n\treturn tracing.NewIDs()\n}\n\nfunc (id *CustomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) {\n\treturn tracing.NewSpanID()\n}\n\nfunc TestClient_CustomProvider(t *testing.T) {\n\tprovider := otel.GetTracerProvider()\n\tdefer otel.SetTracerProvider(provider)\n\n\totel.SetTracerProvider(NewCustomProvider())\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\tr.Response.WriteHeader(200)\n\t\tr.Response.WriteJson(g.Map{\"field\": \"test_for_response_body\"})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\turl := fmt.Sprintf(\"127.0.0.1:%d/hello\", s.GetListenedPort())\n\t\tresp, err := c.DoRequest(ctx, http.MethodGet, url)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(resp, nil)\n\t\tt.Assert(resp.ReadAllString(), \"{\\\"field\\\":\\\"test_for_response_body\\\"}\")\n\t})\n}\n"
  },
  {
    "path": "net/gclient/gclient_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Issue3748(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\n\t\t\tr.GetBody(),\n\t\t)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetHeader(\"Content-Type\", \"application/json\")\n\t\tdata := map[string]any{\n\t\t\t\"name\":  \"@file:\",\n\t\t\t\"value\": \"json\",\n\t\t}\n\t\tclient.SetPrefix(clientHost)\n\t\tcontent := client.PostContent(ctx, \"/\", data)\n\t\tt.Assert(content, `{\"name\":\"@file:\",\"value\":\"json\"}`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetHeader(\"Content-Type\", \"application/xml\")\n\t\tdata := map[string]any{\n\t\t\t\"name\":  \"@file:\",\n\t\t\t\"value\": \"xml\",\n\t\t}\n\t\tclient.SetPrefix(clientHost)\n\t\tcontent := client.PostContent(ctx, \"/\", data)\n\t\tt.Assert(content, `<doc><name>@file:</name><value>xml</value></doc>`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetHeader(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\tdata := map[string]any{\n\t\t\t\"name\":  \"@file:\",\n\t\t\t\"value\": \"x-www-form-urlencoded\",\n\t\t}\n\t\tclient.SetPrefix(clientHost)\n\t\tcontent := client.PostContent(ctx, \"/\", data)\n\t\tt.Assert(strings.Contains(content, `Content-Disposition: form-data; name=\"value\"`), true)\n\t\tt.Assert(strings.Contains(content, `Content-Disposition: form-data; name=\"name\"`), true)\n\t\tt.Assert(strings.Contains(content, \"\\r\\n@file:\"), true)\n\t\tt.Assert(strings.Contains(content, \"\\r\\nx-www-form-urlencoded\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tdata := \"@file:\"\n\t\tclient.SetPrefix(clientHost)\n\t\t_, err := client.Post(ctx, \"/\", data)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4156\nfunc Test_Issue4156(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\t// Return the fieldName value received\n\t\tr.Response.Write(r.Get(\"fieldName\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\t// When posting form with file upload, if value contains '=', it should not be truncated.\n\t\tdata := g.Map{\n\t\t\t\"file\":      \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"fieldName\": \"aaa=1&b=2\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\t// The complete value should be received, not truncated at '='\n\t\tt.Assert(content, \"aaa=1&b=2\")\n\t})\n}\n\n// Test_Issue4156_MultipleSpecialChars tests file upload with various special characters in field values.\nfunc Test_Issue4156_MultipleSpecialChars(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Test with multiple equals signs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"a=1=2=3\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"a=1=2=3\")\n\t})\n\n\t// Test with multiple ampersands\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"a&b&c&d\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"a&b&c&d\")\n\t})\n\n\t// Test with percent sign\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"100%complete\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"100%complete\")\n\t})\n\n\t// Test with plus sign\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"1+2+3\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"1+2+3\")\n\t})\n\n\t// Test with spaces\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"hello world test\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"hello world test\")\n\t})\n\n\t// Test with mixed special characters\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"key=value&foo=bar%20test+plus\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"key=value&foo=bar%20test+plus\")\n\t})\n}\n\n// Test_Issue4156_MultipleFields tests file upload with multiple fields containing special characters.\nfunc Test_Issue4156_MultipleFields(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\t// Return all field values as JSON-like format\n\t\tr.Response.Writef(\"field1=%s,field2=%s,field3=%s\",\n\t\t\tr.Get(\"field1\"), r.Get(\"field2\"), r.Get(\"field3\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":   \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field1\": \"a=1\",\n\t\t\t\"field2\": \"b&2\",\n\t\t\t\"field3\": \"c%3\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(strings.Contains(content, \"field1=a=1\"), true)\n\t\tt.Assert(strings.Contains(content, \"field2=b&2\"), true)\n\t\tt.Assert(strings.Contains(content, \"field3=c%3\"), true)\n\t})\n}\n\n// Test_Issue4156_NoFileUpload tests that normal POST without file upload still works correctly.\nfunc Test_Issue4156_NoFileUpload(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/post\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Test normal POST with special characters (no file upload)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"field\": \"a=1&b=2\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/post\", data)\n\t\tt.Assert(content, \"a=1&b=2\")\n\t})\n\n\t// Test POST with Content-Type: application/x-www-form-urlencoded\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tclient.SetHeader(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\tdata := g.Map{\n\t\t\t\"field\": \"value=with=equals&and&ampersand\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/post\", data)\n\t\tt.Assert(content, \"value=with=equals&and&ampersand\")\n\t})\n}\n\n// Test_Issue4156_PreEncodedValue tests that pre-encoded values are handled correctly.\nfunc Test_Issue4156_PreEncodedValue(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Test with already URL-encoded value - should preserve the encoding\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"value%3Dwith%26encoding\", // User wants to send literal %3D\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\t// The literal %3D and %26 should be preserved\n\t\tt.Assert(content, \"value%3Dwith%26encoding\")\n\t})\n}\n\n// Test_Issue4156_EmptyAndSpecialValues tests edge cases with empty and special values.\nfunc Test_Issue4156_EmptyAndSpecialValues(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tclientHost := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Test with value starting with =\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"=startWithEquals\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"=startWithEquals\")\n\t})\n\n\t// Test with value ending with =\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"endWithEquals=\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"endWithEquals=\")\n\t})\n\n\t// Test with only special characters\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.New()\n\t\tclient.SetPrefix(clientHost)\n\t\tdata := g.Map{\n\t\t\t\"file\":  \"@file:\" + gtest.DataPath(\"upload\", \"file1.txt\"),\n\t\t\t\"field\": \"=&=&=\",\n\t\t}\n\t\tcontent := client.PostContent(ctx, \"/upload\", data)\n\t\tt.Assert(content, \"=&=&=\")\n\t})\n}\n"
  },
  {
    "path": "net/gclient/gclient_z_unit_request_obj_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Client_DoRequestObj(t *testing.T) {\n\ttype UserCreateReq struct {\n\t\tg.Meta `path:\"/user\" method:\"post\"`\n\t\tId     int\n\t\tName   string\n\t}\n\ttype UserCreateRes struct {\n\t\tId int\n\t}\n\ttype UserQueryReq struct {\n\t\tg.Meta `path:\"/user/{id}\" method:\"get\"`\n\t\tId     int\n\t}\n\ttype UserQueryRes struct {\n\t\tId   int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.Group(\"/user\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/{id}\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteJson(g.Map{\"id\": r.Get(\"id\").Int(), \"name\": \"john\"})\n\t\t})\n\t\tgroup.POST(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteJson(g.Map{\"id\": r.Get(\"Id\")})\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client().SetPrefix(url).ContentJson()\n\t\tvar (\n\t\t\tcreateRes *UserCreateRes\n\t\t\tcreateReq = UserCreateReq{\n\t\t\t\tId:   1,\n\t\t\t\tName: \"john\",\n\t\t\t}\n\t\t)\n\t\terr := client.DoRequestObj(ctx, createReq, &createRes)\n\t\tt.AssertNil(err)\n\t\tt.Assert(createRes.Id, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client().SetPrefix(url).ContentJson()\n\t\tvar (\n\t\t\tqueryRes *UserQueryRes\n\t\t\tqueryReq = UserQueryReq{\n\t\t\t\tId: 1,\n\t\t\t}\n\t\t)\n\t\terr := client.DoRequestObj(ctx, queryReq, &queryRes)\n\t\tt.AssertNil(err)\n\t\tt.Assert(queryRes.Id, 1)\n\t\tt.Assert(queryRes.Name, \"john\")\n\t})\n}\n"
  },
  {
    "path": "net/gclient/gclient_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gclient_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/gclient\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_Client_Basic(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\ts.BindHandler(\"/postForm\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"key1\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(url)\n\n\t\tt.Assert(g.Client().GetContent(ctx, \"\"), ``)\n\t\tt.Assert(client.GetContent(ctx, \"/hello\"), `hello`)\n\n\t\t_, err := g.Client().Post(ctx, \"\")\n\t\tt.AssertNE(err, nil)\n\n\t\t_, err = g.Client().PostForm(ctx, \"/postForm\", nil)\n\t\tt.AssertNE(err, nil)\n\t\tdata, _ := g.Client().PostForm(ctx, url+\"/postForm\", map[string]string{\n\t\t\t\"key1\": \"value1\",\n\t\t})\n\t\tt.Assert(data.ReadAllString(), \"value1\")\n\t})\n}\n\nfunc Test_Client_BasicAuth(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/auth\", func(r *ghttp.Request) {\n\t\tif r.BasicAuth(\"admin\", \"admin\") {\n\t\t\tr.Response.Write(\"1\")\n\t\t} else {\n\t\t\tr.Response.Write(\"0\")\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.BasicAuth(\"admin\", \"123\").GetContent(ctx, \"/auth\"), \"0\")\n\t\tt.Assert(c.BasicAuth(\"admin\", \"admin\").GetContent(ctx, \"/auth\"), \"1\")\n\t})\n}\n\nfunc Test_Client_Cookie(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/cookie\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Cookie.Get(\"test\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tc.SetCookie(\"test\", \"0123456789\")\n\t\tt.Assert(c.PostContent(ctx, \"/cookie\"), \"0123456789\")\n\t})\n}\n\nfunc Test_Client_MapParam(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/map\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"test\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/map\", g.Map{\"test\": \"1234567890\"}), \"1234567890\")\n\t})\n}\n\nfunc Test_Client_Cookies(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/cookie\", func(r *ghttp.Request) {\n\t\tr.Cookie.Set(\"test1\", \"1\")\n\t\tr.Cookie.Set(\"test2\", \"2\")\n\t\tr.Response.Write(\"ok\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tresp, err := c.Get(ctx, \"/cookie\")\n\t\tt.AssertNil(err)\n\t\tdefer resp.Close()\n\n\t\tt.AssertNE(resp.Header.Get(\"Set-Cookie\"), \"\")\n\n\t\tm := resp.GetCookieMap()\n\t\tt.Assert(len(m), 2)\n\t\tt.Assert(m[\"test1\"], 1)\n\t\tt.Assert(m[\"test2\"], 2)\n\t\tt.Assert(resp.GetCookie(\"test1\"), 1)\n\t\tt.Assert(resp.GetCookie(\"test2\"), 2)\n\t})\n}\n\nfunc Test_Client_Chain_Header(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/header1\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Header.Get(\"test1\"))\n\t})\n\ts.BindHandler(\"/header2\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Header.Get(\"test2\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.Header(g.MapStrStr{\"test1\": \"1234567890\"}).GetContent(ctx, \"/header1\"), \"1234567890\")\n\t\tt.Assert(c.HeaderRaw(\"test1: 1234567890\\ntest2: abcdefg\").GetContent(ctx, \"/header1\"), \"1234567890\")\n\t\tt.Assert(c.HeaderRaw(\"test1: 1234567890\\ntest2: abcdefg\").GetContent(ctx, \"/header2\"), \"abcdefg\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/header1\"), \"\")\n\n\t\tcopyWithHeader := c.Header(g.MapStrStr{\"test1\": \"1234567890\"})\n\t\tt.Assert(copyWithHeader.GetContent(ctx, \"/header1\"), \"1234567890\")\n\n\t\tt.Assert(c.GetContent(ctx, \"/header1\"), \"\")\n\t})\n}\n\nfunc Test_Client_Chain_Cookie(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/cookie\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Cookie.Get(\"test\", \"def\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/cookie\"), \"def\")\n\n\t\tcopyWithCookie := c.Cookie(g.MapStrStr{\"test\": \"1234567890\"})\n\t\tt.Assert(copyWithCookie.GetContent(ctx, \"/cookie\"), \"1234567890\")\n\n\t\tt.Assert(c.GetContent(ctx, \"/cookie\"), \"def\")\n\t})\n}\n\nfunc Test_Client_Chain_Context(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/context\", func(r *ghttp.Request) {\n\t\ttime.Sleep(1 * time.Second)\n\t\tr.Response.Write(\"ok\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)\n\t\tt.Assert(c.GetContent(ctx, \"/context\"), \"\")\n\n\t\tctx, _ = context.WithTimeout(context.Background(), 2000*time.Millisecond)\n\t\tt.Assert(c.GetContent(ctx, \"/context\"), \"ok\")\n\t})\n}\n\nfunc Test_Client_Chain_Timeout(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/timeout\", func(r *ghttp.Request) {\n\t\ttime.Sleep(1 * time.Second)\n\t\tr.Response.Write(\"ok\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.Timeout(100*time.Millisecond).GetContent(ctx, \"/timeout\"), \"\")\n\t\tt.Assert(c.Timeout(2000*time.Millisecond).GetContent(ctx, \"/timeout\"), \"ok\")\n\t})\n}\n\nfunc Test_Client_Chain_ContentJson(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/json\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"name\"), r.Get(\"score\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.ContentJson().PostContent(ctx, \"/json\", g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"score\": 100,\n\t\t}), \"john100\")\n\t\tt.Assert(c.ContentJson().PostContent(ctx, \"/json\", `{\"name\":\"john\", \"score\":100}`), \"john100\")\n\n\t\ttype User struct {\n\t\t\tName  string `json:\"name\"`\n\t\t\tScore int    `json:\"score\"`\n\t\t}\n\t\tt.Assert(c.ContentJson().PostContent(ctx, \"/json\", User{\"john\", 100}), \"john100\")\n\t})\n}\n\nfunc Test_Client_Chain_ContentXml(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/xml\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"name\"), r.Get(\"score\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.ContentXml().PostContent(ctx, \"/xml\", g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"score\": 100,\n\t\t}), \"john100\")\n\t\tt.Assert(c.ContentXml().PostContent(ctx, \"/xml\", `{\"name\":\"john\", \"score\":100}`), \"john100\")\n\n\t\ttype User struct {\n\t\t\tName  string `json:\"name\"`\n\t\t\tScore int    `json:\"score\"`\n\t\t}\n\t\tt.Assert(c.ContentXml().PostContent(ctx, \"/xml\", User{\"john\", 100}), \"john100\")\n\t})\n}\n\nfunc Test_Client_Param_Containing_Special_Char(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"k1=\", r.Get(\"k1\"), \"&k2=\", r.Get(\"k2\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.PostContent(ctx, \"/\", \"k1=MTIxMg==&k2=100\"), \"k1=MTIxMg==&k2=100\")\n\t\tt.Assert(c.PostContent(ctx, \"/\", g.Map{\n\t\t\t\"k1\": \"MTIxMg==\",\n\t\t\t\"k2\": 100,\n\t\t}), \"k1=MTIxMg==&k2=100\")\n\t})\n}\n\n// It posts data along with file uploading.\n// It does not url-encodes the parameters.\nfunc Test_Client_File_And_Param(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\ttmpPath := gfile.Temp(guid.S())\n\t\terr := gfile.Mkdir(tmpPath)\n\t\tgtest.AssertNil(err)\n\t\tdefer gfile.Remove(tmpPath)\n\n\t\tfile := r.GetUploadFile(\"file\")\n\t\t_, err = file.Save(tmpPath)\n\t\tgtest.AssertNil(err)\n\t\tr.Response.Write(\n\t\t\tr.Get(\"json\"),\n\t\t\tgfile.GetContents(gfile.Join(tmpPath, gfile.Basename(file.Filename))),\n\t\t)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdata := g.Map{\n\t\t\t\"file\": \"@file:\" + path,\n\t\t\t\"json\": `{\"uuid\": \"luijquiopm\", \"isRelative\": false, \"fileName\": \"test111.xls\"}`,\n\t\t}\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.PostContent(ctx, \"/\", data), data[\"json\"].(string)+gfile.GetContents(path))\n\t})\n}\n\nfunc Test_Client_Middleware(t *testing.T) {\n\ts := g.Server(guid.S())\n\tisServerHandler := false\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tisServerHandler = true\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tstr1 = \"\"\n\t\t\tstr2 = \"resp body\"\n\t\t)\n\t\tc := g.Client().SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (resp *gclient.Response, err error) {\n\t\t\tstr1 += \"a\"\n\t\t\tresp, err = c.Next(r)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tstr1 += \"b\"\n\t\t\treturn\n\t\t})\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (resp *gclient.Response, err error) {\n\t\t\tstr1 += \"c\"\n\t\t\tresp, err = c.Next(r)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tstr1 += \"d\"\n\t\t\treturn\n\t\t})\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (resp *gclient.Response, err error) {\n\t\t\tstr1 += \"e\"\n\t\t\tresp, err = c.Next(r)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tresp.Response.Body = io.NopCloser(bytes.NewBufferString(str2))\n\t\t\tstr1 += \"f\"\n\t\t\treturn\n\t\t})\n\t\tresp, err := c.Get(ctx, \"/\")\n\t\tt.Assert(str1, \"acefdb\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.ReadAllString(), str2)\n\t\tt.Assert(isServerHandler, true)\n\n\t\t// test abort, abort will not send\n\t\tvar (\n\t\t\tstr3     = \"\"\n\t\t\tabortStr = \"abort request\"\n\t\t)\n\n\t\tc = g.Client().SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (resp *gclient.Response, err error) {\n\t\t\tstr3 += \"a\"\n\t\t\tresp, err = c.Next(r)\n\t\t\tstr3 += \"b\"\n\t\t\treturn\n\t\t})\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (*gclient.Response, error) {\n\t\t\tstr3 += \"c\"\n\t\t\treturn nil, gerror.New(abortStr)\n\t\t})\n\t\tc.Use(func(c *gclient.Client, r *http.Request) (resp *gclient.Response, err error) {\n\t\t\tstr3 += \"f\"\n\t\t\tresp, err = c.Next(r)\n\t\t\tstr3 += \"g\"\n\t\t\treturn\n\t\t})\n\t\tresp, err = c.Get(ctx, \"/\")\n\t\tt.Assert(err, abortStr)\n\t\tt.Assert(str3, \"acb\")\n\t\tt.Assert(resp, nil)\n\t})\n}\n\nfunc Test_Client_Agent(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.UserAgent())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client().SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tc.SetAgent(\"test\")\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"test\")\n\t})\n}\n\nfunc Test_Client_Request_13_Dump(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\tr.Response.WriteHeader(200)\n\t\tr.Response.WriteJson(g.Map{\"field\": \"test_for_response_body\"})\n\t})\n\ts.BindHandler(\"/hello2\", func(r *ghttp.Request) {\n\t\tr.Response.WriteHeader(200)\n\t\tr.Response.Writeln(g.Map{\"field\": \"test_for_response_body\"})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client().SetPrefix(url).ContentJson()\n\t\tr, err := client.Post(ctx, \"/hello\", g.Map{\"field\": \"test_for_request_body\"})\n\t\tt.AssertNil(err)\n\t\tdumpedText := r.RawRequest()\n\t\tt.Assert(gstr.Contains(dumpedText, \"test_for_request_body\"), true)\n\t\tdumpedText2 := r.RawResponse()\n\t\tfmt.Println(dumpedText2)\n\t\tt.Assert(gstr.Contains(dumpedText2, \"test_for_response_body\"), true)\n\n\t\tclient2 := g.Client().SetPrefix(url).ContentType(\"text/html\")\n\t\tr2, err := client2.Post(ctx, \"/hello2\", g.Map{\"field\": \"test_for_request_body\"})\n\t\tt.AssertNil(err)\n\t\tdumpedText3 := r2.RawRequest()\n\t\tt.Assert(gstr.Contains(dumpedText3, \"test_for_request_body\"), true)\n\t\tdumpedText4 := r2.RawResponse()\n\t\tt.Assert(gstr.Contains(dumpedText4, \"test_for_request_body\"), false)\n\t\tr2 = nil\n\t\tt.Assert(r2.RawRequest(), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tresponse, _ := g.Client().Get(ctx, url, g.Map{\n\t\t\t\"id\":   10000,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tresponse = nil\n\t\tt.Assert(response.RawRequest(), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\turl := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tresponse, _ := g.Client().Get(ctx, url, g.Map{\n\t\t\t\"id\":   10000,\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tresponse.RawDump()\n\t\tt.AssertGT(len(response.Raw()), 0)\n\t})\n}\n\nfunc Test_WebSocketClient(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/ws\", func(r *ghttp.Request) {\n\t\tws, err := r.WebSocket()\n\t\tif err != nil {\n\t\t\tr.Exit()\n\t\t}\n\t\tfor {\n\t\t\tmsgType, msg, err := ws.ReadMessage()\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err = ws.WriteMessage(msgType, msg); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\t// No closing in case of DATA RACE due to keep alive connection of WebSocket.\n\t// defer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := gclient.NewWebSocket()\n\t\tclient.Proxy = http.ProxyFromEnvironment\n\t\tclient.HandshakeTimeout = time.Minute\n\n\t\tconn, _, err := client.Dial(fmt.Sprintf(\"ws://127.0.0.1:%d/ws\", s.GetListenedPort()), nil)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\n\t\tmsg := []byte(\"hello\")\n\t\terr = conn.WriteMessage(websocket.TextMessage, msg)\n\t\tt.AssertNil(err)\n\n\t\tmt, data, err := conn.ReadMessage()\n\t\tt.AssertNil(err)\n\t\tt.Assert(mt, websocket.TextMessage)\n\t\tt.Assert(data, msg)\n\t})\n}\n\nfunc TestLoadKeyCrt(t *testing.T) {\n\tvar (\n\t\ttestCrtFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/upload/file1.txt\"\n\t\ttestKeyFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/upload/file2.txt\"\n\t\tcrtFile     = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.crt\"\n\t\tkeyFile     = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.key\"\n\t\ttlsConfig   = &tls.Config{}\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttlsConfig, _ = gclient.LoadKeyCrt(\"crtFile\", \"keyFile\")\n\t\tt.AssertNil(tlsConfig)\n\n\t\ttlsConfig, _ = gclient.LoadKeyCrt(crtFile, \"keyFile\")\n\t\tt.AssertNil(tlsConfig)\n\n\t\ttlsConfig, _ = gclient.LoadKeyCrt(testCrtFile, testKeyFile)\n\t\tt.AssertNil(tlsConfig)\n\n\t\ttlsConfig, _ = gclient.LoadKeyCrt(crtFile, keyFile)\n\t\tt.AssertNE(tlsConfig, nil)\n\t})\n}\n\nfunc TestClient_DoRequest(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\tr.Response.WriteHeader(200)\n\t\tr.Response.WriteJson(g.Map{\"field\": \"test_for_response_body\"})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\turl := fmt.Sprintf(\"127.0.0.1:%d/hello\", s.GetListenedPort())\n\t\tresp, err := c.DoRequest(ctx, http.MethodGet, url)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(resp, nil)\n\t\tt.Assert(resp.ReadAllString(), \"{\\\"field\\\":\\\"test_for_response_body\\\"}\")\n\n\t\tresp.Response = nil\n\t\tbytes := resp.ReadAll()\n\t\tt.Assert(bytes, []byte{})\n\t\tresp.Close()\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\turl := \"127.0.0.1:99999/hello\"\n\t\tresp, err := c.DoRequest(ctx, http.MethodGet, url)\n\t\tt.AssertNil(resp.Response)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestClient_RequestVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\turl = \"http://127.0.0.1:99999/var/jsons\"\n\t\t)\n\t\tvarValue := g.Client().RequestVar(ctx, http.MethodGet, url)\n\t\tt.AssertNil(varValue)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t}\n\t\tvar (\n\t\t\tusers []User\n\t\t\turl   = \"http://127.0.0.1:8999/var/jsons\"\n\t\t)\n\t\terr := g.Client().RequestVar(ctx, http.MethodGet, url).Scan(&users)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(users, nil)\n\t})\n}\n\nfunc TestClient_SetBodyContent(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tres, err := c.Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tdefer res.Close()\n\t\tt.Assert(res.ReadAllString(), \"hello\")\n\t\tres.SetBodyContent([]byte(\"world\"))\n\t\tt.Assert(res.ReadAllString(), \"world\")\n\t})\n}\n\nfunc TestClient_SetNoUrlEncode(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.URL.RawQuery)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tvar params = g.Map{\n\t\t\t\"path\": \"/data/binlog\",\n\t\t}\n\t\tt.Assert(c.GetContent(ctx, `/`, params), `path=%2Fdata%2Fbinlog`)\n\n\t\tc.SetNoUrlEncode(true)\n\t\tt.Assert(c.GetContent(ctx, `/`, params), `path=/data/binlog`)\n\n\t\tc.SetNoUrlEncode(false)\n\t\tt.Assert(c.GetContent(ctx, `/`, params), `path=%2Fdata%2Fbinlog`)\n\t})\n}\n\nfunc TestClient_NoUrlEncode(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.URL.RawQuery)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tvar params = g.Map{\n\t\t\t\"path\": \"/data/binlog\",\n\t\t}\n\t\tt.Assert(c.GetContent(ctx, `/`, params), `path=%2Fdata%2Fbinlog`)\n\n\t\tt.Assert(c.NoUrlEncode().GetContent(ctx, `/`, params), `path=/data/binlog`)\n\t})\n}\n"
  },
  {
    "path": "net/gclient/testdata/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDVzCCAj+gAwIBAgIJAPRQQvW4UaTJMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV\nBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg\nQ29tcGFueSBMdGQwHhcNMTcxMTA2MDMwNjUzWhcNMjcxMTA0MDMwNjUzWjBCMQsw\nCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh\ndWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\nrvm9LVnIIPlimBCiNzhLmKqe8soWN7ZND+cN8myD8mcGVZblp01JZbR4n1btEekU\nrl3oNr/6aXhLml4ijre150Z73q31XMarlgBtbkbs4Lu22rlLZg/u2hzs9f1aF1VT\nqXzru+2ifcYR15Ptoyr8t12dYSQ9YXP7LwzghE9oWw52w0LxlNL0cNq2muSMTelQ\nxBU3OuAOdy7dPhiHvkpCCZ5SmwZuK8IpSX0/pJUgDkmd3zfKaaOE4JdLKJ5lWsGF\nRgM8leygKfvW4hwguEh7S1UG9CT/6jqPpyiPii3Qc4dxrogmiTPlFpYWY8bFNa9s\niuwr8KFPPZIIwxZgDLAvywIDAQABo1AwTjAdBgNVHQ4EFgQUMsBb4Dhl4OZl+xw8\nPl2wkRhUVi0wHwYDVR0jBBgwFoAUMsBb4Dhl4OZl+xw8Pl2wkRhUVi0wDAYDVR0T\nBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAQEaUz59HZHbPt4Etv4zASn3mFJeR\nQZHmUnKhVjB163xvHoN46GJmc4VnWahOd1a7i7b+qK6AnFzKI5zmZ4z5ZrjwqZiG\nepvAQ4FVbZy1nzMjBXQIyAkiDgbdjASvOUoE4OlKA3jLH7H204K3jhpaFTKVQNeY\nBGEALlKdveQUjlp5YTk38NrrZg0yzGDBUQ6X6PCYB+kdEOOpyx6061jxgIVKuBaY\n37I88vGcC9C3PVhYvDcilMkEcUPnp7DRMiZpXU7DraCWlWbr/b+47NkTPBWiNiLC\nnlfGdCGuL0ylZ16nEpkvZVUWiAijh3sUYbz1dbBACw+8dTG/+vlKUuz/hA==\n-----END CERTIFICATE-----"
  },
  {
    "path": "net/gclient/testdata/server.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEArvm9LVnIIPlimBCiNzhLmKqe8soWN7ZND+cN8myD8mcGVZbl\np01JZbR4n1btEekUrl3oNr/6aXhLml4ijre150Z73q31XMarlgBtbkbs4Lu22rlL\nZg/u2hzs9f1aF1VTqXzru+2ifcYR15Ptoyr8t12dYSQ9YXP7LwzghE9oWw52w0Lx\nlNL0cNq2muSMTelQxBU3OuAOdy7dPhiHvkpCCZ5SmwZuK8IpSX0/pJUgDkmd3zfK\naaOE4JdLKJ5lWsGFRgM8leygKfvW4hwguEh7S1UG9CT/6jqPpyiPii3Qc4dxrogm\niTPlFpYWY8bFNa9siuwr8KFPPZIIwxZgDLAvywIDAQABAoIBAQCRYfXaWY/cPfm6\nqY9u3DqLpbCdwGWHctRC01MWSy2y2gE8Wj2ErcW/WJ0kn4Ao8oX5fxMzcn2o5ofC\nwlZqSKA+gqTnV5jXtkbZQo+qIgotjCqZP34zVie6WHBWz2PsoTv7Rk1D/2WUpV8r\nxMCdY1lJLeJW1Vqev1REOqnNpYDqrhBsCCNn0vvCOS+/UbTbJ2d4sw3BuqGfd2Uk\neIXSlwkODKf2Tk3b4tktC7I0XZfBeO1DEpBJAYP+zPTt/we/Kne6FI/squdephJL\nJMj30bSZ0jpgP/K6otEiE3pfdzijTFPjw8ayU1yuZZMSRLJtFKbSfSNGUfXVHwZP\n6ygv91DJAoGBAOIawxKzSVJxz6yvaxh2Zxnib33TmpyWcDVKje/bk88hxEXm7C3Q\nOPMGbfy37mc6jDoH2erv2GFDFRCezHKS+OEN5heZnL3m/c6E0A4K/V9VUDSnABLi\njmDRw45mDZq9edGxkvydHYMdJhH+hbbWrxr8LQtsBLuaDzLEkHa8cscdAoGBAMYc\nWd4x3fBCA2/Xd98+ZTpYhtbYDvIYl2gfVLSiLuvf3ZgnWozibCOJg5DVh/0vCS+G\nct4Ga3e17qRXZOXuSoZdBIh7nV2mQ0+zc+4ZE7UE0cAU4KYkGBabt1J4HdIxCOUB\n60smideKfFKurh5OCxSP76tIwOhcSXpduhmb/VYHAoGAfe7V89Zz4j2No+rYRXm9\nFwetfXGcTdbkjGoIAC5WdymhfiWOKj4tWf6cyANR/6D2dWPmFhqcdB++3dD0omQF\nxqPNIhvm10aO2rXSg9/PG4gS8iCJw/r3vilXODrTHPqnnQnAin6f72UOzTrsEtgk\nE22dUR1KzYqTKH2e0ONJMmkCgYBlcFzftd7zR4nk+YoKiDNi9bNNTOISOl9EVE6W\nEzk9U6puXzAxVTqT07THM17nV+83I3urjdP3PvPLuGgUh7gnJnfMvqbsLdbnd3aT\n4slBdg9EcCw7Rd4DrYXnt1Nlre/k+t+U4k3QTLutxn2nTMTFqZHJvX3xPFfvTRCe\nTk4gfwKBgDDo8/NvOZQJi+A5qJFooWkm5mFjsq2RTuOE5dZlgfNp3FzbJ1wcC0X5\nifOWAMGIyw0m68Q07fL2rsfvfB69iB6oRv6WCuUXH2f5THgUeVxxYHHUfGJQQkcu\nXJXnZDH/OB1Pg674BzC6dGsHDM19kgWmr0aVQK4jueqxsm5pchEr\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "net/gclient/testdata/upload/file1.txt",
    "content": "file1.txt: This file is for uploading unit test case."
  },
  {
    "path": "net/gclient/testdata/upload/file2.txt",
    "content": "file2.txt: This file is for uploading unit test case."
  },
  {
    "path": "net/ghttp/ghttp.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package ghttp provides powerful http server and simple client implements.\npackage ghttp\n\nimport (\n\t\"net/http\"\n\t\"reflect\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/ghttp/internal/graceful\"\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\ntype (\n\t// Server wraps the http.Server and provides more rich features.\n\tServer struct {\n\t\tinstance         string                    // Instance name of current HTTP server.\n\t\tconfig           ServerConfig              // Server configuration.\n\t\tplugins          []Plugin                  // Plugin array to extend server functionality.\n\t\tservers          []*graceful.Server        // Underlying http.Server array.\n\t\tserverCount      *gtype.Int                // Underlying http.Server number for internal usage.\n\t\tcloseChan        chan struct{}             // Used for underlying server closing event notification.\n\t\tserveTree        map[string]any            // The route maps tree.\n\t\tserveCache       *gcache.Cache             // Server caches for internal usage.\n\t\troutesMap        map[string][]*HandlerItem // Route map mainly for route dumps and repeated route checks.\n\t\tstatusHandlerMap map[string][]HandlerFunc  // Custom status handler map.\n\t\tsessionManager   *gsession.Manager         // Session manager.\n\t\topenapi          *goai.OpenApiV3           // The OpenApi specification management object.\n\t\tserviceMu        sync.Mutex                // Concurrent safety for operations of attribute service.\n\t\tservice          gsvc.Service              // The service for Registry.\n\t\tregistrar        gsvc.Registrar            // Registrar for service register.\n\t}\n\n\t// Router object.\n\tRouter struct {\n\t\tUri      string   // URI.\n\t\tMethod   string   // HTTP method\n\t\tDomain   string   // Bound domain.\n\t\tRegRule  string   // Parsed regular expression for route matching.\n\t\tRegNames []string // Parsed router parameter names.\n\t\tPriority int      // Just for reference.\n\t}\n\n\t// RouterItem is just for route dumps.\n\tRouterItem struct {\n\t\tHandler          *HandlerItem // The handler.\n\t\tServer           string       // Server name.\n\t\tAddress          string       // Listening address.\n\t\tDomain           string       // Bound domain, eg: example.com\n\t\tType             HandlerType  // Route handler type.\n\t\tMiddleware       string       // Bound middleware.\n\t\tMethod           string       // Handler method name, eg: get, post.\n\t\tRoute            string       // Route URI, eg: /api/v1/user/{id}.\n\t\tPriority         int          // Just for reference.\n\t\tIsServiceHandler bool         // Is a service handler.\n\t}\n\n\t// HandlerFunc is request handler function.\n\tHandlerFunc = func(r *Request)\n\n\t// handlerFuncInfo contains the HandlerFunc address and its reflection type.\n\thandlerFuncInfo struct {\n\t\tFunc            HandlerFunc      // Handler function address.\n\t\tType            reflect.Type     // Reflect type information for current handler, which is used for extensions of the handler feature.\n\t\tValue           reflect.Value    // Reflect value information for current handler, which is used for extensions of the handler feature.\n\t\tIsStrictRoute   bool             // Whether strict route matching is enabled.\n\t\tReqStructFields []gstructs.Field // Request struct fields.\n\t}\n\n\t// HandlerItem is the registered handler for route handling,\n\t// including middleware and hook functions.\n\tHandlerItem struct {\n\t\t// Unique handler item id mark.\n\t\t// Note that the handler function may be registered multiple times as different handler items,\n\t\t// which have different handler item id.\n\t\tId         int\n\t\tName       string          // Handler name, which is automatically retrieved from runtime stack when registered.\n\t\tType       HandlerType     // Handler type: object/handler/middleware/hook.\n\t\tInfo       handlerFuncInfo // Handler function information.\n\t\tInitFunc   HandlerFunc     // Initialization function when request enters the object (only available for object register type).\n\t\tShutFunc   HandlerFunc     // Shutdown function when request leaves out the object (only available for object register type).\n\t\tMiddleware []HandlerFunc   // Bound middleware array.\n\t\tHookName   HookName        // Hook type name, only available for the hook type.\n\t\tRouter     *Router         // Router object.\n\t\tSource     string          // Registering source file `path:line`.\n\t}\n\n\t// HandlerItemParsed is the item parsed from URL.Path.\n\tHandlerItemParsed struct {\n\t\tHandler *HandlerItem      // Handler information.\n\t\tValues  map[string]string // Router values parsed from URL.Path.\n\t}\n\n\t// ServerStatus is the server status enum type.\n\tServerStatus = int\n\n\t// HookName is the route hook name enum type.\n\tHookName string\n\n\t// HandlerType is the route handler enum type.\n\tHandlerType string\n\n\t// Listening file descriptor mapping.\n\t// The key is either \"http\" or \"https\" and the value is its FD.\n\tlistenerFdMap = map[string]string\n\n\t// internalPanic is the custom panic for internal usage.\n\tinternalPanic string\n)\n\nconst (\n\t// FreePortAddress marks the server listens using random free port.\n\tFreePortAddress = graceful.FreePortAddress\n)\n\nconst (\n\tHeaderXUrlPath                    = \"x-url-path\"         // Used for custom route handler, which does not change URL.Path.\n\tHookBeforeServe       HookName    = \"HOOK_BEFORE_SERVE\"  // Hook handler before route handler/file serving.\n\tHookAfterServe        HookName    = \"HOOK_AFTER_SERVE\"   // Hook handler after route handler/file serving.\n\tHookBeforeOutput      HookName    = \"HOOK_BEFORE_OUTPUT\" // Hook handler before response output.\n\tHookAfterOutput       HookName    = \"HOOK_AFTER_OUTPUT\"  // Hook handler after response output.\n\tDefaultServerName                 = \"default\"\n\tDefaultDomainName                 = \"default\"\n\tHandlerTypeHandler    HandlerType = \"handler\"\n\tHandlerTypeObject     HandlerType = \"object\"\n\tHandlerTypeMiddleware HandlerType = \"middleware\"\n\tHandlerTypeHook       HandlerType = \"hook\"\n\tServerStatusStopped               = graceful.ServerStatusStopped\n\tServerStatusRunning               = graceful.ServerStatusRunning\n)\n\nconst (\n\tsupportedHttpMethods               = \"GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE\"\n\tdefaultMethod                      = \"ALL\"\n\trouteCacheDuration                 = time.Hour\n\tctxKeyForRequest       gctx.StrKey = \"gHttpRequestObject\"\n\tcontentTypeXml                     = \"text/xml\"\n\tcontentTypeHtml                    = \"text/html\"\n\tcontentTypeJson                    = \"application/json\"\n\tcontentTypeJavascript              = \"application/javascript\"\n\tswaggerUIPackedPath                = \"/goframe/swaggerui\"\n\tresponseHeaderTraceID              = \"Trace-ID\"\n\tspecialMethodNameInit              = \"Init\"\n\tspecialMethodNameShut              = \"Shut\"\n\tspecialMethodNameIndex             = \"Index\"\n\tdefaultEndpointPort                = 80\n\tnoPrintInternalRoute               = \"internalMiddlewareServerTracing\"\n)\n\nconst (\n\texceptionExit     internalPanic = \"exit\"\n\texceptionExitAll  internalPanic = \"exit_all\"\n\texceptionExitHook internalPanic = \"exit_hook\"\n)\n\nvar (\n\t// methodsMap stores all supported HTTP method.\n\t// It is used for quick HTTP method searching using map.\n\tmethodsMap = make(map[string]struct{})\n\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *Server) bool { return v == nil }\n\n\t// serverMapping stores more than one server instances for current processes.\n\t// The key is the name of the server, and the value is its instance.\n\tserverMapping = gmap.NewKVMapWithChecker[string, *Server](checker, true)\n\n\t// serverRunning marks the running server counts.\n\t// If there is no successful server running or all servers' shutdown, this value is 0.\n\tserverRunning = gtype.NewInt()\n\n\t// wsUpGrader is the default up-grader configuration for websocket.\n\twsUpGrader = websocket.Upgrader{\n\t\t// It does not check the origin in default, the application can do it itself.\n\t\tCheckOrigin: func(r *http.Request) bool {\n\t\t\treturn true\n\t\t},\n\t}\n\t// allShutdownChan is the event for all servers have done its serving and exit.\n\t// It is used for process blocking purpose.\n\tallShutdownChan = make(chan struct{}, 1000)\n\n\t// serverProcessInitialized is used for lazy initialization for server.\n\t// The process can only be initialized once.\n\tserverProcessInitialized = gtype.NewBool()\n\n\t// gracefulEnabled is used for a graceful reload feature, which is false in default.\n\tgracefulEnabled = false\n\n\t// defaultValueTags are the struct tag names for default value storing.\n\tdefaultValueTags = []string{gtag.DefaultShort, gtag.Default}\n)\n\nvar (\n\t// ErrNeedJsonBody is the error that indicates the request body content should be JSON format.\n\tErrNeedJsonBody = gerror.NewWithOption(gerror.Option{\n\t\tText: \"the request body content should be JSON format\",\n\t\tCode: gcode.CodeInvalidRequest,\n\t})\n)\n"
  },
  {
    "path": "net/ghttp/ghttp_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SupportedMethods returns all supported HTTP methods.\nfunc SupportedMethods() []string {\n\treturn gstr.SplitAndTrim(supportedHttpMethods, \",\")\n}\n\n// BuildParams builds the request string for the http client. The `params` can be type of:\n// string/[]byte/map/struct/*struct.\n//\n// The optional parameter `noUrlEncode` specifies whether to ignore the url encoding for the data.\nfunc BuildParams(params any, noUrlEncode ...bool) (encodedParamStr string) {\n\treturn httputil.BuildParams(params, noUrlEncode...)\n}\n\n// niceCallFunc calls function `f` with exception capture logic.\nfunc niceCallFunc(f func()) {\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tswitch exception {\n\t\t\tcase exceptionExit, exceptionExitAll:\n\t\t\t\treturn\n\n\t\t\tdefault:\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\t// It's already an error that has stack info.\n\t\t\t\t\tpanic(v)\n\t\t\t\t}\n\t\t\t\t// Create a new error with stack info.\n\t\t\t\t// Note that there's a skip pointing the start stacktrace\n\t\t\t\t// of the real error point.\n\t\t\t\tif v, ok := exception.(error); ok {\n\t\t\t\t\tif gerror.Code(v) != gcode.CodeNil {\n\t\t\t\t\t\tpanic(v)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpanic(gerror.WrapCodeSkip(\n\t\t\t\t\t\t\tgcode.CodeInternalPanic, 1, v, \"exception recovered\",\n\t\t\t\t\t\t))\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpanic(gerror.NewCodeSkipf(\n\t\t\t\t\t\tgcode.CodeInternalPanic, 1, \"exception recovered: %+v\", exception,\n\t\t\t\t\t))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\tf()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_cors.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// MiddlewareCORS is a middleware handler for CORS with default options.\nfunc MiddlewareCORS(r *Request) {\n\tr.Response.CORSDefault()\n\tr.Middleware.Next()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_gzip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// MiddlewareGzip is a middleware that compresses HTTP response using gzip compression.\n// Note that it does not compress responses if:\n// 1. The response is already compressed (Content-Encoding header is set)\n// 2. The client does not accept gzip compression\n// 3. The response body length is too small (less than 1KB)\n//\n// To disable compression for specific routes, you can use the group middleware:\n//\n//\tgroup.Group(\"/api\", func(group *ghttp.RouterGroup) {\n//\t    group.Middleware(ghttp.MiddlewareGzip) // Enable GZIP for /api routes\n//\t})\nfunc MiddlewareGzip(r *Request) {\n\t// Skip compression if client doesn't accept gzip\n\tif !acceptsGzip(r.Request) {\n\t\tr.Middleware.Next()\n\t\treturn\n\t}\n\n\t// Execute the next handlers first\n\tr.Middleware.Next()\n\n\t// Skip if already compressed or empty response\n\tif r.Response.Header().Get(\"Content-Encoding\") != \"\" {\n\t\treturn\n\t}\n\n\t// Get the response buffer and check its length\n\tbuffer := r.Response.Buffer()\n\tif len(buffer) < 1024 {\n\t\treturn\n\t}\n\n\t// Try to compress the response\n\tvar (\n\t\tcompressed bytes.Buffer\n\t\tlogger     = r.Server.Logger()\n\t\tctx        = r.Context()\n\t)\n\tgzipWriter := gzip.NewWriter(&compressed)\n\tif _, err := gzipWriter.Write(buffer); err != nil {\n\t\tlogger.Warningf(ctx, \"gzip compression failed: %+v\", err)\n\t\treturn\n\t}\n\tif err := gzipWriter.Close(); err != nil {\n\t\tlogger.Warningf(ctx, \"gzip writer close failed: %+v\", err)\n\t\treturn\n\t}\n\n\t// Clear the original buffer and set headers\n\tr.Response.ClearBuffer()\n\tr.Response.Header().Set(\"Content-Encoding\", \"gzip\")\n\tr.Response.Header().Del(\"Content-Length\")\n\n\t// Write the compressed data\n\tr.Response.Write(compressed.Bytes())\n}\n\n// acceptsGzip returns true if the client accepts gzip compression.\nfunc acceptsGzip(r *http.Request) bool {\n\treturn strings.Contains(r.Header.Get(\"Accept-Encoding\"), \"gzip\")\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_handler_response.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"mime\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// DefaultHandlerResponse is the default implementation of HandlerResponse.\ntype DefaultHandlerResponse struct {\n\tCode    int    `json:\"code\"    dc:\"Error code\"`\n\tMessage string `json:\"message\" dc:\"Error message\"`\n\tData    any    `json:\"data\"    dc:\"Result data for certain request according API definition\"`\n}\n\nconst (\n\tcontentTypeEventStream  = \"text/event-stream\"\n\tcontentTypeOctetStream  = \"application/octet-stream\"\n\tcontentTypeMixedReplace = \"multipart/x-mixed-replace\"\n)\n\nvar (\n\t// streamContentType is the content types for stream response.\n\tstreamContentType = []string{contentTypeEventStream, contentTypeOctetStream, contentTypeMixedReplace}\n)\n\n// MiddlewareHandlerResponse is the default middleware handling handler response object and its error.\nfunc MiddlewareHandlerResponse(r *Request) {\n\tr.Middleware.Next()\n\n\t// There's custom buffer content, it then exits current handler.\n\tif r.Response.BufferLength() > 0 || r.Response.BytesWritten() > 0 {\n\t\treturn\n\t}\n\n\t// It does not output common response content if it is stream response.\n\tmediaType, _, _ := mime.ParseMediaType(r.Response.Header().Get(\"Content-Type\"))\n\tfor _, ct := range streamContentType {\n\t\tif mediaType == ct {\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar (\n\t\tmsg  string\n\t\terr  = r.GetError()\n\t\tres  = r.GetHandlerResponse()\n\t\tcode = gerror.Code(err)\n\t)\n\tif err != nil {\n\t\tif code == gcode.CodeNil {\n\t\t\tcode = gcode.CodeInternalError\n\t\t}\n\t\tmsg = err.Error()\n\t} else {\n\t\tif r.Response.Status > 0 && r.Response.Status != http.StatusOK {\n\t\t\tswitch r.Response.Status {\n\t\t\tcase http.StatusNotFound:\n\t\t\t\tcode = gcode.CodeNotFound\n\t\t\tcase http.StatusForbidden:\n\t\t\t\tcode = gcode.CodeNotAuthorized\n\t\t\tdefault:\n\t\t\t\tcode = gcode.CodeUnknown\n\t\t\t}\n\t\t\t// It creates an error as it can be retrieved by other middlewares.\n\t\t\terr = gerror.NewCode(code, msg)\n\t\t\tr.SetError(err)\n\t\t} else {\n\t\t\tcode = gcode.CodeOK\n\t\t}\n\t\tmsg = code.Message()\n\t}\n\n\tr.Response.WriteJson(DefaultHandlerResponse{\n\t\tCode:    code.Code(),\n\t\tMessage: msg,\n\t\tData:    res,\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_json_body.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// MiddlewareJsonBody validates and returns request body whether JSON format.\nfunc MiddlewareJsonBody(r *Request) {\n\trequestBody := r.GetBody()\n\tif len(requestBody) > 0 {\n\t\tif !json.Valid(requestBody) {\n\t\t\tr.SetError(ErrNeedJsonBody)\n\t\t\treturn\n\t\t}\n\t}\n\tr.Middleware.Next()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_never_done_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// MiddlewareNeverDoneCtx sets the context never done for current process.\nfunc MiddlewareNeverDoneCtx(r *Request) {\n\tr.SetCtx(r.GetNeverDoneCtx())\n\tr.Middleware.Next()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_middleware_tracing.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tinstrumentName                              = \"github.com/gogf/gf/v2/net/ghttp.Server\"\n\ttracingEventHttpRequest                     = \"http.request\"\n\ttracingEventHttpRequestHeaders              = \"http.request.headers\"\n\ttracingEventHttpRequestBaggage              = \"http.request.baggage\"\n\ttracingEventHttpResponse                    = \"http.response\"\n\ttracingEventHttpResponseHeaders             = \"http.response.headers\"\n\ttracingEventHttpRequestUrl                  = \"http.request.url\"\n\ttracingMiddlewareHandled        gctx.StrKey = `MiddlewareServerTracingHandled`\n)\n\n// internalMiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.\nfunc internalMiddlewareServerTracing(r *Request) {\n\tvar (\n\t\tctx = r.Context()\n\t)\n\t// Mark this request is handled by server tracing middleware,\n\t// to avoid repeated handling by the same middleware.\n\tif ctx.Value(tracingMiddlewareHandled) != nil {\n\t\tr.Middleware.Next()\n\t\treturn\n\t}\n\n\tctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)\n\tvar (\n\t\tspan trace.Span\n\t\ttr   = otel.GetTracerProvider().Tracer(\n\t\t\tinstrumentName,\n\t\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t\t)\n\t)\n\tctx, span = tr.Start(\n\t\totel.GetTextMapPropagator().Extract(\n\t\t\tctx,\n\t\t\tpropagation.HeaderCarrier(r.Header),\n\t\t),\n\t\tr.URL.Path,\n\t\ttrace.WithSpanKind(trace.SpanKindServer),\n\t)\n\tdefer span.End()\n\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\t// Inject tracing context.\n\tr.SetCtx(ctx)\n\n\t// If it is now using a default trace provider, it then does no complex tracing jobs.\n\tif gtrace.IsUsingDefaultProvider() {\n\t\tr.Middleware.Next()\n\t\treturn\n\t}\n\n\tspan.AddEvent(tracingEventHttpRequest, trace.WithAttributes(\n\t\tattribute.String(tracingEventHttpRequestUrl, r.URL.String()),\n\t\tattribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))),\n\t\tattribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()),\n\t))\n\n\t// Continue executing.\n\tr.Middleware.Next()\n\n\t// parse after set route as span name\n\tif handler := r.GetServeHandler(); handler != nil && handler.Handler.Router != nil {\n\t\tspan.SetName(handler.Handler.Router.Uri)\n\t}\n\n\t// Error logging.\n\tif err := r.GetError(); err != nil {\n\t\tspan.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))\n\t}\n\n\tspan.AddEvent(tracingEventHttpResponse, trace.WithAttributes(\n\t\tattribute.String(\n\t\t\ttracingEventHttpResponseHeaders,\n\t\t\tgconv.String(httputil.HeaderToMap(r.Response.Header())),\n\t\t),\n\t))\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// Request is the context object for a request.\ntype Request struct {\n\t*http.Request\n\tServer     *Server           // Server.\n\tCookie     *Cookie           // Cookie.\n\tSession    *gsession.Session // Session.\n\tResponse   *Response         // Corresponding Response of this request.\n\tRouter     *Router           // Matched Router for this request. Note that it's not available in HOOK handler.\n\tEnterTime  *gtime.Time       // Request starting time in milliseconds.\n\tLeaveTime  *gtime.Time       // Request to end time in milliseconds.\n\tMiddleware *middleware       // Middleware manager.\n\tStaticFile *staticFile       // Static file object for static file serving.\n\n\t// =================================================================================================================\n\t// Private attributes for internal usage purpose.\n\t// =================================================================================================================\n\n\thandlers        []*HandlerItemParsed // All matched handlers containing handler, hook and middleware for this request.\n\tserveHandler    *HandlerItemParsed   // Real business handler serving for this request, not hook or middleware handler.\n\thandlerResponse any                  // Handler response object for Request/Response handler.\n\thasHookHandler  bool                 // A bool marking whether there's hook handler in the handlers for performance purpose.\n\thasServeHandler bool                 // A bool marking whether there's serving handler in the handlers for performance purpose.\n\tparsedQuery     bool                 // A bool marking whether the GET parameters parsed.\n\tparsedBody      bool                 // A bool marking whether the request body parsed.\n\tparsedForm      bool                 // A bool marking whether request Form parsed for HTTP method PUT, POST, PATCH.\n\tparamsMap       map[string]any       // Custom parameters map.\n\trouterMap       map[string]string    // Router parameters map, which might be nil if there are no router parameters.\n\tqueryMap        map[string]any       // Query parameters map, which is nil if there's no query string.\n\tformMap         map[string]any       // Form parameters map, which is nil if there's no form of data from the client.\n\tbodyMap         map[string]any       // Body parameters map, which might be nil if their nobody content.\n\terror           error                // Current executing error of the request.\n\texitAll         bool                 // A bool marking whether current request is exited.\n\tparsedHost      string               // The parsed host name for current host used by GetHost function.\n\tclientIp        string               // The parsed client ip for current host used by GetClientIp function.\n\tbodyContent     []byte               // Request body content.\n\tisFileRequest   bool                 // A bool marking whether current request is file serving.\n\tviewObject      *gview.View          // Custom template view engine object for this response.\n\tviewParams      gview.Params         // Custom template view variables for this response.\n\toriginUrlPath   string               // Original URL path that passed from client.\n}\n\n// staticFile is the file struct for static file service.\ntype staticFile struct {\n\tFile  *gres.File // Resource file object.\n\tPath  string     // File path.\n\tIsDir bool       // Is directory.\n}\n\n// newRequest creates and returns a new request object.\nfunc newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {\n\trequest := &Request{\n\t\tServer:        s,\n\t\tRequest:       r,\n\t\tResponse:      newResponse(s, w),\n\t\tEnterTime:     gtime.Now(),\n\t\toriginUrlPath: r.URL.Path,\n\t}\n\trequest.Cookie = GetCookie(request)\n\trequest.Session = s.sessionManager.New(\n\t\tr.Context(),\n\t\trequest.GetSessionId(),\n\t)\n\trequest.Response.Request = request\n\trequest.Middleware = &middleware{\n\t\trequest: request,\n\t}\n\t// Custom session id creating function.\n\terr := request.Session.SetIdFunc(func(ttl time.Duration) string {\n\t\tvar (\n\t\t\taddress = request.RemoteAddr\n\t\t\theader  = fmt.Sprintf(\"%v\", request.Header)\n\t\t)\n\t\tintlog.Print(r.Context(), address, header)\n\t\treturn guid.S([]byte(address), []byte(header))\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// Remove char '/' in the tail of URI.\n\tif request.URL.Path != \"/\" {\n\t\tfor len(request.URL.Path) > 0 && request.URL.Path[len(request.URL.Path)-1] == '/' {\n\t\t\trequest.URL.Path = request.URL.Path[:len(request.URL.Path)-1]\n\t\t}\n\t}\n\n\t// Default URI value if it's empty.\n\tif request.URL.Path == \"\" {\n\t\trequest.URL.Path = \"/\"\n\t}\n\treturn request\n}\n\n// WebSocket upgrades current request as a websocket request.\n// It returns a new WebSocket object if success, or the error if failure.\n// Note that the request should be a websocket request, or it will surely fail upgrading.\n//\n// Deprecated: will be removed in the future, please use third-party websocket library instead.\nfunc (r *Request) WebSocket() (*WebSocket, error) {\n\tif conn, err := wsUpGrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil {\n\t\treturn &WebSocket{\n\t\t\tconn,\n\t\t}, nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// Exit exits executing of current HTTP handler.\nfunc (r *Request) Exit() {\n\tpanic(exceptionExit)\n}\n\n// ExitAll exits executing of current and following HTTP handlers.\nfunc (r *Request) ExitAll() {\n\tr.exitAll = true\n\tpanic(exceptionExitAll)\n}\n\n// ExitHook exits executing of current and following HTTP HOOK handlers.\nfunc (r *Request) ExitHook() {\n\tpanic(exceptionExitHook)\n}\n\n// IsExited checks and returns whether current request is exited.\nfunc (r *Request) IsExited() bool {\n\treturn r.exitAll\n}\n\n// GetHeader retrieves and returns the header value with given `key`.\n// It returns the optional `def` parameter if the header does not exist.\nfunc (r *Request) GetHeader(key string, def ...string) string {\n\tvalue := r.Header.Get(key)\n\tif value == \"\" && len(def) > 0 {\n\t\tvalue = def[0]\n\t}\n\treturn value\n}\n\n// GetHost returns current request host name, which might be a domain or an IP without port.\nfunc (r *Request) GetHost() string {\n\tif len(r.parsedHost) == 0 {\n\t\tarray, _ := gregex.MatchString(`(.+):(\\d+)`, r.Host)\n\t\tif len(array) > 1 {\n\t\t\tr.parsedHost = array[1]\n\t\t} else {\n\t\t\tr.parsedHost = r.Host\n\t\t}\n\t}\n\treturn r.parsedHost\n}\n\n// IsFileRequest checks and returns whether current request is serving file.\nfunc (r *Request) IsFileRequest() bool {\n\treturn r.isFileRequest\n}\n\n// IsAjaxRequest checks and returns whether current request is an AJAX request.\nfunc (r *Request) IsAjaxRequest() bool {\n\treturn strings.EqualFold(r.Header.Get(\"X-Requested-With\"), \"XMLHttpRequest\")\n}\n\n// GetClientIp returns the client ip of this request without port.\n// Note that this ip address might be modified by client header.\nfunc (r *Request) GetClientIp() string {\n\tif r.clientIp != \"\" {\n\t\treturn r.clientIp\n\t}\n\trealIps := r.Header.Get(\"X-Forwarded-For\")\n\tif realIps != \"\" && len(realIps) != 0 && !strings.EqualFold(\"unknown\", realIps) {\n\t\tipArray := strings.Split(realIps, \",\")\n\t\tr.clientIp = ipArray[0]\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.Header.Get(\"Proxy-Client-IP\")\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.Header.Get(\"WL-Proxy-Client-IP\")\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.Header.Get(\"HTTP_CLIENT_IP\")\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.Header.Get(\"HTTP_X_FORWARDED_FOR\")\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.Header.Get(\"X-Real-IP\")\n\t}\n\tif r.clientIp == \"\" {\n\t\tr.clientIp = r.GetRemoteIp()\n\t}\n\treturn r.clientIp\n}\n\n// GetRemoteIp returns the ip from RemoteAddr.\nfunc (r *Request) GetRemoteIp() string {\n\tarray, _ := gregex.MatchString(`(.+):(\\d+)`, r.RemoteAddr)\n\tif len(array) > 1 {\n\t\treturn strings.Trim(array[1], \"[]\")\n\t}\n\treturn r.RemoteAddr\n}\n\n// GetSchema returns the schema of this request.\nfunc (r *Request) GetSchema() string {\n\tvar (\n\t\tscheme = \"http\"\n\t\tproto  = r.Header.Get(\"X-Forwarded-Proto\")\n\t)\n\tif r.TLS != nil || gstr.Equal(proto, \"https\") {\n\t\tscheme = \"https\"\n\t}\n\treturn scheme\n}\n\n// GetUrl returns current URL of this request.\nfunc (r *Request) GetUrl() string {\n\tvar (\n\t\tscheme = \"http\"\n\t\tproto  = r.Header.Get(\"X-Forwarded-Proto\")\n\t)\n\n\tif r.TLS != nil || gstr.Equal(proto, \"https\") {\n\t\tscheme = \"https\"\n\t}\n\treturn fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String())\n}\n\n// GetSessionId retrieves and returns session id from cookie or header.\nfunc (r *Request) GetSessionId() string {\n\tid := r.Cookie.GetSessionId()\n\tif id == \"\" {\n\t\tid = r.Header.Get(r.Server.GetSessionIdName())\n\t}\n\treturn id\n}\n\n// GetReferer returns referer of this request.\nfunc (r *Request) GetReferer() string {\n\treturn r.Header.Get(\"Referer\")\n}\n\n// GetError returns the error occurs in the procedure of the request.\n// It returns nil if there's no error.\nfunc (r *Request) GetError() error {\n\treturn r.error\n}\n\n// SetError sets custom error for current request.\nfunc (r *Request) SetError(err error) {\n\tr.error = err\n}\n\n// ReloadParam is used for modifying request parameter.\n// Sometimes, we want to modify request parameters through middleware, but directly modifying Request.Body\n// is invalid, so it clears the parsed* marks of Request to make the parameters reparsed.\nfunc (r *Request) ReloadParam() {\n\tr.parsedBody = false\n\tr.parsedForm = false\n\tr.parsedQuery = false\n\tr.bodyContent = nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_auth.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n)\n\n// BasicAuth enables the http basic authentication feature with a given passport and password\n// and asks client for authentication. It returns true if authentication success, else returns\n// false if failure.\nfunc (r *Request) BasicAuth(user, pass string, tips ...string) bool {\n\tauth := r.Header.Get(\"Authorization\")\n\tif auth == \"\" {\n\t\tr.setBasicAuth(tips...)\n\t\treturn false\n\t}\n\tauthArray := strings.SplitN(auth, \" \", 2)\n\tif len(authArray) != 2 {\n\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\treturn false\n\t}\n\tswitch authArray[0] {\n\tcase \"Basic\":\n\t\tauthBytes, err := gbase64.DecodeString(authArray[1])\n\t\tif err != nil {\n\t\t\tr.Response.WriteStatus(http.StatusForbidden, err.Error())\n\t\t\treturn false\n\t\t}\n\t\tauthArray := strings.SplitN(string(authBytes), \":\", 2)\n\t\tif len(authArray) != 2 {\n\t\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\t\treturn false\n\t\t}\n\t\tif authArray[0] != user || authArray[1] != pass {\n\t\t\tr.setBasicAuth(tips...)\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\n\tdefault:\n\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\treturn false\n\t}\n}\n\n// setBasicAuth sets the http basic authentication tips.\nfunc (r *Request) setBasicAuth(tips ...string) {\n\trealm := \"\"\n\tif len(tips) > 0 && tips[0] != \"\" {\n\t\trealm = tips[0]\n\t} else {\n\t\trealm = \"Need Login\"\n\t}\n\tr.Response.Header().Set(\"WWW-Authenticate\", fmt.Sprintf(`Basic realm=\"%s\"`, realm))\n\tr.Response.WriteHeader(http.StatusUnauthorized)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_middleware.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// middleware is the plugin for request workflow management.\ntype middleware struct {\n\tserved         bool     // Is the request served, which is used for checking response status 404.\n\trequest        *Request // The request object pointer.\n\thandlerIndex   int      // Index number for executing sequence purpose for handler items.\n\thandlerMDIndex int      // Index number for executing sequence purpose for bound middleware of handler item.\n}\n\n// Next calls the next workflow handler.\n// It's an important function controlling the workflow of the server request execution.\nfunc (m *middleware) Next() {\n\tvar item *HandlerItemParsed\n\tvar loop = true\n\tfor loop {\n\t\t// Check whether the request is excited.\n\t\tif m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {\n\t\t\tbreak\n\t\t}\n\t\titem = m.request.handlers[m.handlerIndex]\n\t\t// Filter the HOOK handlers, which are designed to be called in another standalone procedure.\n\t\tif item.Handler.Type == HandlerTypeHook {\n\t\t\tm.handlerIndex++\n\t\t\tcontinue\n\t\t}\n\t\t// Current router switching.\n\t\tm.request.Router = item.Handler.Router\n\n\t\t// Router values switching.\n\t\tm.request.routerMap = item.Values\n\n\t\tvar ctx = m.request.Context()\n\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\t// Execute bound middleware array of the item if it's not empty.\n\t\t\tif m.handlerMDIndex < len(item.Handler.Middleware) {\n\t\t\t\tmd := item.Handler.Middleware[m.handlerMDIndex]\n\t\t\t\tm.handlerMDIndex++\n\t\t\t\tniceCallFunc(func() {\n\t\t\t\t\tmd(m.request)\n\t\t\t\t})\n\t\t\t\tloop = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tm.handlerIndex++\n\n\t\t\tswitch item.Handler.Type {\n\t\t\t// Service object.\n\t\t\tcase HandlerTypeObject:\n\t\t\t\tm.served = true\n\t\t\t\tif m.request.IsExited() {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif item.Handler.InitFunc != nil {\n\t\t\t\t\tniceCallFunc(func() {\n\t\t\t\t\t\titem.Handler.InitFunc(m.request)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tif !m.request.IsExited() {\n\t\t\t\t\tm.callHandlerFunc(item.Handler.Info)\n\t\t\t\t}\n\t\t\t\tif !m.request.IsExited() && item.Handler.ShutFunc != nil {\n\t\t\t\t\tniceCallFunc(func() {\n\t\t\t\t\t\titem.Handler.ShutFunc(m.request)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t// Service handler.\n\t\t\tcase HandlerTypeHandler:\n\t\t\t\tm.served = true\n\t\t\t\tif m.request.IsExited() {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tniceCallFunc(func() {\n\t\t\t\t\tm.callHandlerFunc(item.Handler.Info)\n\t\t\t\t})\n\n\t\t\t// Global middleware array.\n\t\t\tcase HandlerTypeMiddleware:\n\t\t\t\tniceCallFunc(func() {\n\t\t\t\t\titem.Handler.Info.Func(m.request)\n\t\t\t\t})\n\t\t\t\t// It does not continue calling next middleware after another middleware done.\n\t\t\t\t// There should be a \"Next\" function to be called in the middleware in order to manage the workflow.\n\t\t\t\tloop = false\n\t\t\t}\n\t\t}, func(ctx context.Context, exception error) {\n\t\t\tif gerror.HasStack(exception) {\n\t\t\t\t// It's already an error that has stack info.\n\t\t\t\tm.request.error = exception\n\t\t\t} else {\n\t\t\t\t// Create a new error with stack info.\n\t\t\t\t// Note that there's a skip pointing the start stacktrace\n\t\t\t\t// of the real error point.\n\t\t\t\tm.request.error = gerror.WrapCodeSkip(gcode.CodeInternalError, 1, exception, \"\")\n\t\t\t}\n\t\t\tm.request.Response.WriteStatus(http.StatusInternalServerError, exception)\n\t\t\tloop = false\n\t\t})\n\t}\n\t// Check the http status code after all handlers and middleware done.\n\tif m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {\n\t\tif m.request.Response.Status == 0 {\n\t\t\tif m.request.Middleware.served {\n\t\t\t\tm.request.Response.WriteHeader(http.StatusOK)\n\t\t\t} else {\n\t\t\t\tm.request.Response.WriteHeader(http.StatusNotFound)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) {\n\tniceCallFunc(func() {\n\t\tfuncInfo.Func(m.request)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nconst (\n\tparseTypeRequest = iota\n\tparseTypeQuery\n\tparseTypeForm\n)\n\nvar (\n\t// xmlHeaderBytes is the most common XML format header.\n\txmlHeaderBytes = []byte(\"<?xml\")\n)\n\n// Parse is the most commonly used function, which converts request parameters to struct or struct\n// slice. It also automatically validates the struct or every element of the struct slice according\n// to the validation tag of the struct.\n//\n// The parameter `pointer` can be type of: *struct/**struct/*[]struct/*[]*struct.\n//\n// It supports single and multiple struct converting:\n// 1. Single struct, post content like: {\"id\":1, \"name\":\"john\"} or ?id=1&name=john\n// 2. Multiple struct, post content like: [{\"id\":1, \"name\":\"john\"}, {\"id\":, \"name\":\"smith\"}]\n//\n// TODO: Improve the performance by reducing duplicated reflect usage on the same variable across packages.\nfunc (r *Request) Parse(pointer any) error {\n\treturn r.doParse(pointer, parseTypeRequest)\n}\n\n// ParseQuery performs like function Parse, but only parses the query parameters.\nfunc (r *Request) ParseQuery(pointer any) error {\n\treturn r.doParse(pointer, parseTypeQuery)\n}\n\n// ParseForm performs like function Parse, but only parses the form parameters or the body content.\nfunc (r *Request) ParseForm(pointer any) error {\n\treturn r.doParse(pointer, parseTypeForm)\n}\n\n// doParse parses the request data to struct/structs according to request type.\nfunc (r *Request) doParse(pointer any, requestType int) error {\n\tvar (\n\t\treflectVal1  = reflect.ValueOf(pointer)\n\t\treflectKind1 = reflectVal1.Kind()\n\t)\n\tif reflectKind1 != reflect.Pointer {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid parameter type \"%v\", of which kind should be of *struct/**struct/*[]struct/*[]*struct, but got: \"%v\"`,\n\t\t\treflectVal1.Type(),\n\t\t\treflectKind1,\n\t\t)\n\t}\n\tvar (\n\t\treflectVal2  = reflectVal1.Elem()\n\t\treflectKind2 = reflectVal2.Kind()\n\t)\n\tswitch reflectKind2 {\n\t// Single struct, post content like:\n\t// 1. {\"id\":1, \"name\":\"john\"}\n\t// 2. ?id=1&name=john\n\tcase reflect.Pointer, reflect.Struct:\n\t\tvar (\n\t\t\terr  error\n\t\t\tdata map[string]any\n\t\t)\n\t\t// Converting.\n\t\tswitch requestType {\n\t\tcase parseTypeQuery:\n\t\t\tif data, err = r.doGetQueryStruct(pointer); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase parseTypeForm:\n\t\t\tif data, err = r.doGetFormStruct(pointer); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tif data, err = r.doGetRequestStruct(pointer); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// Validation.\n\t\tif err = gvalid.New().\n\t\t\tBail().\n\t\t\tData(pointer).\n\t\t\tAssoc(data).\n\t\t\tRun(r.Context()); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t// Multiple struct, it only supports JSON type post content like:\n\t// [{\"id\":1, \"name\":\"john\"}, {\"id\":, \"name\":\"smith\"}]\n\tcase reflect.Array, reflect.Slice:\n\t\t// If struct slice conversion, it might post JSON/XML/... content,\n\t\t// so it uses `gjson` for the conversion.\n\t\tj, err := gjson.LoadContent(r.GetBody())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = j.Var().Scan(pointer); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor i := 0; i < reflectVal2.Len(); i++ {\n\t\t\tif err = gvalid.New().\n\t\t\t\tBail().\n\t\t\t\tData(reflectVal2.Index(i)).\n\t\t\t\tAssoc(j.Get(gconv.String(i)).Map()).\n\t\t\t\tRun(r.Context()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Get is alias of GetRequest, which is one of the most commonly used functions for\n// retrieving parameter.\n// See r.GetRequest.\nfunc (r *Request) Get(key string, def ...any) *gvar.Var {\n\treturn r.GetRequest(key, def...)\n}\n\n// GetBody retrieves and returns request body content as bytes.\n// It can be called multiple times retrieving the same body content.\nfunc (r *Request) GetBody() []byte {\n\tif r.bodyContent == nil {\n\t\tr.bodyContent = r.MakeBodyRepeatableRead(true)\n\t}\n\treturn r.bodyContent\n}\n\n// MakeBodyRepeatableRead marks the request body could be repeatedly readable or not.\n// It also returns the current content of the request body.\nfunc (r *Request) MakeBodyRepeatableRead(repeatableRead bool) []byte {\n\tif r.bodyContent == nil {\n\t\tvar err error\n\t\tif r.bodyContent, err = io.ReadAll(r.Body); err != nil {\n\t\t\terrMsg := `Read from request Body failed`\n\t\t\tif gerror.Is(err, io.EOF) {\n\t\t\t\terrMsg += `, the Body might be closed or read manually from middleware/hook/other package previously`\n\t\t\t}\n\t\t\tpanic(gerror.WrapCode(gcode.CodeInternalError, err, errMsg))\n\t\t}\n\t}\n\tr.Body = utils.NewReadCloser(r.bodyContent, repeatableRead)\n\treturn r.bodyContent\n}\n\n// GetBodyString retrieves and returns request body content as string.\n// It can be called multiple times retrieving the same body content.\nfunc (r *Request) GetBodyString() string {\n\treturn string(r.GetBody())\n}\n\n// GetJson parses current request content as JSON format, and returns the JSON object.\n// Note that the request content is read from request BODY, not from any field of FORM.\nfunc (r *Request) GetJson() (*gjson.Json, error) {\n\treturn gjson.LoadWithOptions(r.GetBody(), gjson.Options{\n\t\tType:      gjson.ContentTypeJSON,\n\t\tStrNumber: true,\n\t})\n}\n\n// GetMap is an alias and convenient function for GetRequestMap.\n// See GetRequestMap.\nfunc (r *Request) GetMap(def ...map[string]any) map[string]any {\n\treturn r.GetRequestMap(def...)\n}\n\n// GetMapStrStr is an alias and convenient function for GetRequestMapStrStr.\n// See GetRequestMapStrStr.\nfunc (r *Request) GetMapStrStr(def ...map[string]any) map[string]string {\n\treturn r.GetRequestMapStrStr(def...)\n}\n\n// GetStruct is an alias and convenient function for GetRequestStruct.\n// See GetRequestStruct.\nfunc (r *Request) GetStruct(pointer any, mapping ...map[string]string) error {\n\treturn r.GetRequestStruct(pointer, mapping...)\n}\n\n// parseQuery parses query string into r.queryMap.\nfunc (r *Request) parseQuery() {\n\tif r.parsedQuery {\n\t\treturn\n\t}\n\tr.parsedQuery = true\n\tif r.URL.RawQuery != \"\" {\n\t\tvar err error\n\t\tr.queryMap, err = gstr.Parse(r.URL.RawQuery)\n\t\tif err != nil {\n\t\t\tpanic(gerror.WrapCode(gcode.CodeInvalidParameter, err, \"Parse Query failed\"))\n\t\t}\n\t}\n}\n\n// parseBody parses the request raw data into r.rawMap.\n// Note that it also supports JSON data from client request.\nfunc (r *Request) parseBody() {\n\tif r.parsedBody {\n\t\treturn\n\t}\n\tr.parsedBody = true\n\t// There's no data posted.\n\tif r.ContentLength == 0 {\n\t\treturn\n\t}\n\tif body := r.GetBody(); len(body) > 0 {\n\t\t// Trim space/new line characters.\n\t\tbody = bytes.TrimSpace(body)\n\t\t// JSON format checks.\n\t\tif body[0] == '{' && body[len(body)-1] == '}' {\n\t\t\t_ = json.UnmarshalUseNumber(body, &r.bodyMap)\n\t\t}\n\t\t// XML format checks.\n\t\tif len(body) > 5 && bytes.EqualFold(body[:5], xmlHeaderBytes) {\n\t\t\tr.bodyMap, _ = gxml.DecodeWithoutRoot(body)\n\t\t}\n\t\tif body[0] == '<' && body[len(body)-1] == '>' {\n\t\t\tr.bodyMap, _ = gxml.DecodeWithoutRoot(body)\n\t\t}\n\t\t// Default parameters decoding.\n\t\tif contentType := r.Header.Get(\"Content-Type\"); (contentType == \"\" || !gstr.Contains(contentType, \"multipart/\")) && r.bodyMap == nil {\n\t\t\tr.bodyMap, _ = gstr.Parse(r.GetBodyString())\n\t\t}\n\t}\n}\n\n// parseForm parses the request form for HTTP method PUT, POST, PATCH.\n// The form data is pared into r.formMap.\n//\n// Note that if the form was parsed firstly, the request body would be cleared and empty.\nfunc (r *Request) parseForm() {\n\tif r.parsedForm {\n\t\treturn\n\t}\n\tr.parsedForm = true\n\t// There's no data posted.\n\tif r.ContentLength == 0 {\n\t\treturn\n\t}\n\n\tif contentType := r.Header.Get(\"Content-Type\"); contentType != \"\" {\n\t\tvar isMultiPartRequest = gstr.Contains(contentType, \"multipart/\")\n\t\tvar isFormRequest = gstr.Contains(contentType, \"form\")\n\t\tvar err error\n\n\t\tif !isMultiPartRequest {\n\t\t\t// To avoid big memory consuming.\n\t\t\t// The `multipart/` type form always contains binary data, which is not necessary read twice.\n\t\t\tr.MakeBodyRepeatableRead(true)\n\t\t}\n\t\tif isMultiPartRequest {\n\t\t\t// multipart/form-data, multipart/mixed\n\t\t\tif err = r.ParseMultipartForm(r.Server.config.FormParsingMemory); err != nil {\n\t\t\t\tpanic(gerror.WrapCode(gcode.CodeInvalidRequest, err, \"r.ParseMultipartForm failed\"))\n\t\t\t}\n\t\t} else if isFormRequest {\n\t\t\t// application/x-www-form-urlencoded\n\t\t\tif err = r.Request.ParseForm(); err != nil {\n\t\t\t\tpanic(gerror.WrapCode(gcode.CodeInvalidRequest, err, \"r.Request.ParseForm failed\"))\n\t\t\t}\n\t\t}\n\t\tif len(r.PostForm) > 0 {\n\t\t\t// Parse the form data using united parsing way.\n\t\t\tparams := \"\"\n\t\t\tfor name, values := range r.PostForm {\n\t\t\t\t// Invalid parameter name.\n\t\t\t\t// Only allow chars of: '\\w', '[', ']', '-'.\n\t\t\t\tif !gregex.IsMatchString(`^[\\w\\-\\[\\]]+$`, name) && len(r.PostForm) == 1 {\n\t\t\t\t\t// It might be JSON/XML content.\n\t\t\t\t\tif s := gstr.Trim(name + strings.Join(values, \" \")); len(s) > 0 {\n\t\t\t\t\t\tif s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {\n\t\t\t\t\t\t\tr.bodyContent = []byte(s)\n\t\t\t\t\t\t\tparams = \"\"\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(values) == 1 {\n\t\t\t\t\tif len(params) > 0 {\n\t\t\t\t\t\tparams += \"&\"\n\t\t\t\t\t}\n\t\t\t\t\tparams += name + \"=\" + gurl.Encode(values[0])\n\t\t\t\t} else {\n\t\t\t\t\tif len(name) > 2 && name[len(name)-2:] == \"[]\" {\n\t\t\t\t\t\tname = name[:len(name)-2]\n\t\t\t\t\t\tfor _, v := range values {\n\t\t\t\t\t\t\tif len(params) > 0 {\n\t\t\t\t\t\t\t\tparams += \"&\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tparams += name + \"[]=\" + gurl.Encode(v)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif len(params) > 0 {\n\t\t\t\t\t\t\tparams += \"&\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tparams += name + \"=\" + gurl.Encode(values[len(values)-1])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif params != \"\" {\n\t\t\t\tif r.formMap, err = gstr.Parse(params); err != nil {\n\t\t\t\t\tpanic(gerror.WrapCode(gcode.CodeInvalidParameter, err, \"Parse request parameters failed\"))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// It parses the request body without checking the Content-Type.\n\tif r.formMap == nil {\n\t\tif r.Method != http.MethodGet {\n\t\t\tr.parseBody()\n\t\t}\n\t\tif len(r.bodyMap) > 0 {\n\t\t\tr.formMap = r.bodyMap\n\t\t}\n\t}\n}\n\n// GetMultipartForm parses and returns the form as multipart forms.\nfunc (r *Request) GetMultipartForm() *multipart.Form {\n\tr.parseForm()\n\treturn r.MultipartForm\n}\n\n// GetMultipartFiles parses and returns the post files array.\n// Note that the request form should be type of multipart.\nfunc (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {\n\tform := r.GetMultipartForm()\n\tif form == nil {\n\t\treturn nil\n\t}\n\tif v := form.File[name]; len(v) > 0 {\n\t\treturn v\n\t}\n\t// Support \"name[]\" as array parameter.\n\tif v := form.File[name+\"[]\"]; len(v) > 0 {\n\t\treturn v\n\t}\n\t// Support \"name[0]\",\"name[1]\",\"name[2]\", etc. as array parameter.\n\tvar (\n\t\tkey   string\n\t\tfiles = make([]*multipart.FileHeader, 0)\n\t)\n\tfor i := 0; ; i++ {\n\t\tkey = fmt.Sprintf(`%s[%d]`, name, i)\n\t\tif v := form.File[key]; len(v) > 0 {\n\t\t\tfiles = append(files, v[0])\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tif len(files) > 0 {\n\t\treturn files\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\n// RequestFromCtx retrieves and returns the Request object from context.\nfunc RequestFromCtx(ctx context.Context) *Request {\n\tif v := ctx.Value(ctxKeyForRequest); v != nil {\n\t\treturn v.(*Request)\n\t}\n\treturn nil\n}\n\n// Context is alias for function GetCtx.\n// This function overwrites the http.Request.Context function.\n// See GetCtx.\nfunc (r *Request) Context() context.Context {\n\tvar ctx = r.Request.Context()\n\t// Check and inject Request object into context.\n\tif RequestFromCtx(ctx) == nil {\n\t\t// Inject Request object into context.\n\t\tctx = context.WithValue(ctx, ctxKeyForRequest, r)\n\t\t// Update the values of the original HTTP request.\n\t\t*r.Request = *r.WithContext(ctx)\n\t}\n\treturn ctx\n}\n\n// GetCtx retrieves and returns the request's context.\n// Its alias of function Context,to be relevant with function SetCtx.\nfunc (r *Request) GetCtx() context.Context {\n\treturn r.Context()\n}\n\n// GetNeverDoneCtx creates and returns a never done context object,\n// which forbids the context manually done, to make the context can be propagated to asynchronous goroutines,\n// which will not be affected by the HTTP request ends.\n//\n// This change is considered for common usage habits of developers for context propagation\n// in multiple goroutines creation in one HTTP request.\nfunc (r *Request) GetNeverDoneCtx() context.Context {\n\treturn gctx.NeverDone(r.Context())\n}\n\n// SetCtx custom context for current request.\nfunc (r *Request) SetCtx(ctx context.Context) {\n\t*r.Request = *r.WithContext(ctx)\n}\n\n// GetCtxVar retrieves and returns a Var with a given key name.\n// The optional parameter `def` specifies the default value of the Var if given `key`\n// does not exist in the context.\nfunc (r *Request) GetCtxVar(key any, def ...any) *gvar.Var {\n\tvalue := r.Context().Value(key)\n\tif value == nil && len(def) > 0 {\n\t\tvalue = def[0]\n\t}\n\treturn gvar.New(value)\n}\n\n// SetCtxVar sets custom parameter to context with key-value pairs.\nfunc (r *Request) SetCtxVar(key any, value any) {\n\tvar ctx = r.Context()\n\tctx = context.WithValue(ctx, key, value)\n\t*r.Request = *r.WithContext(ctx)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\n// UploadFile wraps the multipart uploading file with more and convenient features.\ntype UploadFile struct {\n\t*multipart.FileHeader `json:\"-\"`\n\tctx                   context.Context\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (f UploadFile) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(f.FileHeader)\n}\n\n// UploadFiles is an array type of *UploadFile.\ntype UploadFiles []*UploadFile\n\n// Save saves the single uploading file to directory path and returns the saved file name.\n//\n// The parameter `dirPath` should be a directory path, or it returns error.\n//\n// Note that it will OVERWRITE the target file if there's already a same name file exist.\nfunc (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename string, err error) {\n\tif f == nil {\n\t\treturn \"\", gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t\"file is empty, maybe you retrieve it from invalid field name or form enctype\",\n\t\t)\n\t}\n\tif !gfile.Exists(dirPath) {\n\t\tif err = gfile.Mkdir(dirPath); err != nil {\n\t\t\treturn\n\t\t}\n\t} else if !gfile.IsDir(dirPath) {\n\t\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, `parameter \"dirPath\" should be a directory path`)\n\t}\n\n\tfile, err := f.Open()\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `UploadFile.Open failed`)\n\t\treturn \"\", err\n\t}\n\tdefer file.Close()\n\n\tname := gfile.Basename(f.Filename)\n\tif len(randomlyRename) > 0 && randomlyRename[0] {\n\t\tname = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))\n\t\tname = name + gfile.Ext(f.Filename)\n\t}\n\tfilePath := gfile.Join(dirPath, name)\n\tnewFile, err := gfile.Create(filePath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer newFile.Close()\n\tintlog.Printf(f.ctx, `save upload file: %s`, filePath)\n\tif _, err = io.Copy(newFile, file); err != nil {\n\t\terr = gerror.Wrapf(err, `io.Copy failed from \"%s\" to \"%s\"`, f.Filename, filePath)\n\t\treturn \"\", err\n\t}\n\treturn gfile.Basename(filePath), nil\n}\n\n// Save saves all uploading files to specified directory path and returns the saved file names.\n//\n// The parameter `dirPath` should be a directory path or it returns error.\n//\n// The parameter `randomlyRename` specifies whether randomly renames all the file names.\nfunc (fs UploadFiles) Save(dirPath string, randomlyRename ...bool) (filenames []string, err error) {\n\tif len(fs) == 0 {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t\"file array is empty, maybe you retrieve it from invalid field name or form enctype\",\n\t\t)\n\t}\n\tfor _, f := range fs {\n\t\tif filename, err := f.Save(dirPath, randomlyRename...); err != nil {\n\t\t\treturn filenames, err\n\t\t} else {\n\t\t\tfilenames = append(filenames, filename)\n\t\t}\n\t}\n\treturn\n}\n\n// GetUploadFile retrieves and returns the uploading file with specified form name.\n// This function is used for retrieving single uploading file object, which is\n// uploaded using multipart form content type.\n//\n// It returns nil if retrieving failed or no form file with given name posted.\n//\n// Note that the `name` is the file field name of the multipart form from client.\nfunc (r *Request) GetUploadFile(name string) *UploadFile {\n\tuploadFiles := r.GetUploadFiles(name)\n\tif len(uploadFiles) > 0 {\n\t\treturn uploadFiles[0]\n\t}\n\treturn nil\n}\n\n// GetUploadFiles retrieves and returns multiple uploading files with specified form name.\n// This function is used for retrieving multiple uploading file objects, which are\n// uploaded using multipart form content type.\n//\n// It returns nil if retrieving failed or no form file with given name posted.\n//\n// Note that the `name` is the file field name of the multipart form from client.\nfunc (r *Request) GetUploadFiles(name string) UploadFiles {\n\tmultipartFiles := r.GetMultipartFiles(name)\n\tif len(multipartFiles) > 0 {\n\t\tuploadFiles := make(UploadFiles, len(multipartFiles))\n\t\tfor k, v := range multipartFiles {\n\t\t\tuploadFiles[k] = &UploadFile{\n\t\t\t\tctx:        r.Context(),\n\t\t\t\tFileHeader: v,\n\t\t\t}\n\t\t}\n\t\treturn uploadFiles\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_form.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SetForm sets custom form value with key-value pairs.\nfunc (r *Request) SetForm(key string, value any) {\n\tr.parseForm()\n\tif r.formMap == nil {\n\t\tr.formMap = make(map[string]any)\n\t}\n\tr.formMap[key] = value\n}\n\n// GetForm retrieves and returns parameter `key` from form.\n// It returns `def` if `key` does not exist in the form and `def` is given, or else it returns nil.\nfunc (r *Request) GetForm(key string, def ...any) *gvar.Var {\n\tr.parseForm()\n\tif len(r.formMap) > 0 {\n\t\tif value, ok := r.formMap[key]; ok {\n\t\t\treturn gvar.New(value)\n\t\t}\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetFormMap retrieves and returns all form parameters passed from client as map.\n// The parameter `kvMap` specifies the keys retrieving from client parameters,\n// the associated values are the default values if the client does not pass.\nfunc (r *Request) GetFormMap(kvMap ...map[string]any) map[string]any {\n\tr.parseForm()\n\tif len(kvMap) > 0 && kvMap[0] != nil {\n\t\tif len(r.formMap) == 0 {\n\t\t\treturn kvMap[0]\n\t\t}\n\t\tm := make(map[string]any, len(kvMap[0]))\n\t\tfor k, defValue := range kvMap[0] {\n\t\t\tif postValue, ok := r.formMap[k]; ok {\n\t\t\t\tm[k] = postValue\n\t\t\t} else {\n\t\t\t\tm[k] = defValue\n\t\t\t}\n\t\t}\n\t\treturn m\n\t} else {\n\t\treturn r.formMap\n\t}\n}\n\n// GetFormMapStrStr retrieves and returns all form parameters passed from client as map[string]string.\n// The parameter `kvMap` specifies the keys retrieving from client parameters, the associated values\n// are the default values if the client does not pass.\nfunc (r *Request) GetFormMapStrStr(kvMap ...map[string]any) map[string]string {\n\tformMap := r.GetFormMap(kvMap...)\n\tif len(formMap) > 0 {\n\t\tm := make(map[string]string, len(formMap))\n\t\tfor k, v := range formMap {\n\t\t\tm[k] = gconv.String(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetFormMapStrVar retrieves and returns all form parameters passed from client as map[string]*gvar.Var.\n// The parameter `kvMap` specifies the keys retrieving from client parameters, the associated values\n// are the default values if the client does not pass.\nfunc (r *Request) GetFormMapStrVar(kvMap ...map[string]any) map[string]*gvar.Var {\n\tformMap := r.GetFormMap(kvMap...)\n\tif len(formMap) > 0 {\n\t\tm := make(map[string]*gvar.Var, len(formMap))\n\t\tfor k, v := range formMap {\n\t\t\tm[k] = gvar.New(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetFormStruct retrieves all form parameters passed from client and converts them to\n// given struct object. Note that the parameter `pointer` is a pointer to the struct object.\n// The optional parameter `mapping` is used to specify the key to attribute mapping.\nfunc (r *Request) GetFormStruct(pointer any, mapping ...map[string]string) error {\n\t_, err := r.doGetFormStruct(pointer, mapping...)\n\treturn err\n}\n\nfunc (r *Request) doGetFormStruct(pointer any, mapping ...map[string]string) (data map[string]any, err error) {\n\tr.parseForm()\n\tdata = r.formMap\n\tif data == nil {\n\t\tdata = map[string]any{}\n\t}\n\tif err = r.mergeDefaultStructValue(data, pointer); err != nil {\n\t\treturn data, nil\n\t}\n\treturn data, gconv.Struct(data, pointer, mapping...)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_handler.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// GetHandlerResponse retrieves and returns the handler response object and its error.\nfunc (r *Request) GetHandlerResponse() any {\n\treturn r.handlerResponse\n}\n\n// GetServeHandler retrieves and returns the user defined handler used to serve this request.\nfunc (r *Request) GetServeHandler() *HandlerItemParsed {\n\treturn r.serveHandler\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_page.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gpage\" //nolint:staticcheck\n)\n\n// GetPage creates and returns the pagination object for given `totalSize` and `pageSize`.\n// NOTE THAT the page parameter name from clients is constantly defined as gpage.DefaultPageName\n// for simplification and convenience.\n//\n// Deprecated: wrap this pagination html content in business layer.\nfunc (r *Request) GetPage(totalSize, pageSize int) *gpage.Page {\n\t// It must have Router object attribute.\n\tif r.Router == nil {\n\t\tpanic(\"router object not found\")\n\t}\n\tvar (\n\t\turl            = *r.URL\n\t\turlTemplate    = url.Path\n\t\turiHasPageName = false\n\t)\n\t// Check the page variable in the URI.\n\tif len(r.Router.RegNames) > 0 {\n\t\tfor _, name := range r.Router.RegNames {\n\t\t\tif name == gpage.DefaultPageName {\n\t\t\t\turiHasPageName = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif uriHasPageName {\n\t\t\tif match, err := gregex.MatchString(r.Router.RegRule, url.Path); err == nil && len(match) > 0 {\n\t\t\t\tif len(match) > len(r.Router.RegNames) {\n\t\t\t\t\turlTemplate = r.Router.Uri\n\t\t\t\t\tfor i, name := range r.Router.RegNames {\n\t\t\t\t\t\trule := fmt.Sprintf(`[:\\*]%s|\\{%s\\}`, name, name)\n\t\t\t\t\t\tif name == gpage.DefaultPageName {\n\t\t\t\t\t\t\turlTemplate, err = gregex.ReplaceString(rule, gpage.DefaultPagePlaceHolder, urlTemplate)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\turlTemplate, err = gregex.ReplaceString(rule, match[i+1], urlTemplate)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tpanic(err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t}\n\t// Check the page variable in the query string.\n\tif !uriHasPageName {\n\t\tvalues := url.Query()\n\t\tvalues.Set(gpage.DefaultPageName, gpage.DefaultPagePlaceHolder)\n\t\turl.RawQuery = values.Encode()\n\t\t// Replace the encoded \"{.page}\" to original \"{.page}\".\n\t\turl.RawQuery = gstr.Replace(url.RawQuery, \"%7B.page%7D\", \"{.page}\")\n\t}\n\tif url.RawQuery != \"\" {\n\t\turlTemplate += \"?\" + url.RawQuery\n\t}\n\n\treturn gpage.New(totalSize, pageSize, r.Get(gpage.DefaultPageName).Int(), urlTemplate)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_param.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/container/gvar\"\n\n// SetParam sets custom parameter with key-value pairs.\nfunc (r *Request) SetParam(key string, value any) {\n\tif r.paramsMap == nil {\n\t\tr.paramsMap = make(map[string]any)\n\t}\n\tr.paramsMap[key] = value\n}\n\n// SetParamMap sets custom parameter with key-value pair maps.\nfunc (r *Request) SetParamMap(data map[string]any) {\n\tif r.paramsMap == nil {\n\t\tr.paramsMap = make(map[string]any)\n\t}\n\tfor k, v := range data {\n\t\tr.paramsMap[k] = v\n\t}\n}\n\n// GetParam returns custom parameter with a given name `key`.\n// It returns `def` if `key` does not exist.\n// It returns nil if `def` is not passed.\nfunc (r *Request) GetParam(key string, def ...any) *gvar.Var {\n\tif len(r.paramsMap) > 0 {\n\t\tif value, ok := r.paramsMap[key]; ok {\n\t\t\treturn gvar.New(value)\n\t\t}\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_query.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SetQuery sets custom query value with key-value pairs.\nfunc (r *Request) SetQuery(key string, value any) {\n\tr.parseQuery()\n\tif r.queryMap == nil {\n\t\tr.queryMap = make(map[string]any)\n\t}\n\tr.queryMap[key] = value\n}\n\n// GetQuery retrieves and return parameter with the given name `key` from query string\n// and request body. It returns `def` if `key` does not exist in the query and `def` is given,\n// or else it returns nil.\n//\n// Note that if there are multiple parameters with the same name, the parameters are retrieved\n// and overwrote in order of priority: query > body.\nfunc (r *Request) GetQuery(key string, def ...any) *gvar.Var {\n\tr.parseQuery()\n\tif len(r.queryMap) > 0 {\n\t\tif value, ok := r.queryMap[key]; ok {\n\t\t\treturn gvar.New(value)\n\t\t}\n\t}\n\tif r.Method == http.MethodGet {\n\t\tr.parseBody()\n\t}\n\tif len(r.bodyMap) > 0 {\n\t\tif v, ok := r.bodyMap[key]; ok {\n\t\t\treturn gvar.New(v)\n\t\t}\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetQueryMap retrieves and returns all parameters passed from the client using HTTP GET method\n// as the map. The parameter `kvMap` specifies the keys retrieving from client parameters,\n// the associated values are the default values if the client does not pass.\n//\n// Note that if there are multiple parameters with the same name, the parameters are retrieved and overwrote\n// in order of priority: query > body.\nfunc (r *Request) GetQueryMap(kvMap ...map[string]any) map[string]any {\n\tr.parseQuery()\n\tif r.Method == http.MethodGet {\n\t\tr.parseBody()\n\t}\n\tvar m map[string]any\n\tif len(kvMap) > 0 && kvMap[0] != nil {\n\t\tif len(r.queryMap) == 0 && len(r.bodyMap) == 0 {\n\t\t\treturn kvMap[0]\n\t\t}\n\t\tm = make(map[string]any, len(kvMap[0]))\n\t\tif len(r.bodyMap) > 0 {\n\t\t\tfor k, v := range kvMap[0] {\n\t\t\t\tif postValue, ok := r.bodyMap[k]; ok {\n\t\t\t\t\tm[k] = postValue\n\t\t\t\t} else {\n\t\t\t\t\tm[k] = v\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(r.queryMap) > 0 {\n\t\t\tfor k, v := range kvMap[0] {\n\t\t\t\tif postValue, ok := r.queryMap[k]; ok {\n\t\t\t\t\tm[k] = postValue\n\t\t\t\t} else {\n\t\t\t\t\tm[k] = v\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tm = make(map[string]any, len(r.queryMap)+len(r.bodyMap))\n\t\tfor k, v := range r.bodyMap {\n\t\t\tm[k] = v\n\t\t}\n\t\tfor k, v := range r.queryMap {\n\t\t\tm[k] = v\n\t\t}\n\t}\n\treturn m\n}\n\n// GetQueryMapStrStr retrieves and returns all parameters passed from the client using the HTTP GET method as a\n//\n//\tmap[string]string. The parameter `kvMap` specifies the keys\n//\n// retrieving from client parameters, the associated values are the default values if the client\n// does not pass.\nfunc (r *Request) GetQueryMapStrStr(kvMap ...map[string]any) map[string]string {\n\tqueryMap := r.GetQueryMap(kvMap...)\n\tif len(queryMap) > 0 {\n\t\tm := make(map[string]string, len(queryMap))\n\t\tfor k, v := range queryMap {\n\t\t\tm[k] = gconv.String(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetQueryMapStrVar retrieves and returns all parameters passed from the client using the HTTP GET method\n// as map[string]*gvar.Var. The parameter `kvMap` specifies the keys\n// retrieving from client parameters, the associated values are the default values if the client\n// does not pass.\nfunc (r *Request) GetQueryMapStrVar(kvMap ...map[string]any) map[string]*gvar.Var {\n\tqueryMap := r.GetQueryMap(kvMap...)\n\tif len(queryMap) > 0 {\n\t\tm := make(map[string]*gvar.Var, len(queryMap))\n\t\tfor k, v := range queryMap {\n\t\t\tm[k] = gvar.New(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetQueryStruct retrieves all parameters passed from the client using the HTTP GET method\n// and converts them to a given struct object. Note that the parameter `pointer` is a pointer\n// to the struct object. The optional parameter `mapping` is used to specify the key to\n// attribute mapping.\nfunc (r *Request) GetQueryStruct(pointer any, mapping ...map[string]string) error {\n\t_, err := r.doGetQueryStruct(pointer, mapping...)\n\treturn err\n}\n\nfunc (r *Request) doGetQueryStruct(pointer any, mapping ...map[string]string) (data map[string]any, err error) {\n\tr.parseQuery()\n\tdata = r.GetQueryMap()\n\tif data == nil {\n\t\tdata = map[string]any{}\n\t}\n\tif err = r.mergeDefaultStructValue(data, pointer); err != nil {\n\t\treturn data, nil\n\t}\n\treturn data, gconv.Struct(data, pointer, mapping...)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_request.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// GetRequest retrieves and returns the parameter named `key` passed from the client and\n// custom params as any, no matter what HTTP method the client is using. The\n// parameter `def` specifies the default value if the `key` does not exist.\n//\n// GetRequest is one of the most commonly used functions for retrieving parameters.\n//\n// Note that if there are multiple parameters with the same name, the parameters are\n// retrieved and overwrote in order of priority: router < query < body < form < custom.\nfunc (r *Request) GetRequest(key string, def ...any) *gvar.Var {\n\tvalue := r.GetParam(key)\n\tif value.IsNil() {\n\t\tvalue = r.GetForm(key)\n\t}\n\tif value.IsNil() {\n\t\tr.parseBody()\n\t\tif len(r.bodyMap) > 0 {\n\t\t\tif v := r.bodyMap[key]; v != nil {\n\t\t\t\tvalue = gvar.New(v)\n\t\t\t}\n\t\t}\n\t}\n\tif value.IsNil() {\n\t\tvalue = r.GetQuery(key)\n\t}\n\tif value.IsNil() {\n\t\tvalue = r.GetRouter(key)\n\t}\n\tif !value.IsNil() {\n\t\treturn value\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetRequestMap retrieves and returns all parameters passed from the client and custom params\n// as the map, no matter what HTTP method the client is using. The parameter `kvMap` specifies\n// the keys retrieving from client parameters, the associated values are the default values\n// if the client does not pass the according keys.\n//\n// GetRequestMap is one of the most commonly used functions for retrieving parameters.\n//\n// Note that if there are multiple parameters with the same name, the parameters are retrieved\n// and overwrote in order of priority: router < query < body < form < custom.\nfunc (r *Request) GetRequestMap(kvMap ...map[string]any) map[string]any {\n\tr.parseQuery()\n\tr.parseForm()\n\tr.parseBody()\n\tvar (\n\t\tok, filter bool\n\t)\n\tif len(kvMap) > 0 && kvMap[0] != nil {\n\t\tfilter = true\n\t}\n\tm := make(map[string]any)\n\tfor k, v := range r.routerMap {\n\t\tif filter {\n\t\t\tif _, ok = kvMap[0][k]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tm[k] = v\n\t}\n\tfor k, v := range r.queryMap {\n\t\tif filter {\n\t\t\tif _, ok = kvMap[0][k]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tm[k] = v\n\t}\n\tfor k, v := range r.formMap {\n\t\tif filter {\n\t\t\tif _, ok = kvMap[0][k]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tm[k] = v\n\t}\n\tfor k, v := range r.bodyMap {\n\t\tif filter {\n\t\t\tif _, ok = kvMap[0][k]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tm[k] = v\n\t}\n\tfor k, v := range r.paramsMap {\n\t\tif filter {\n\t\t\tif _, ok = kvMap[0][k]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tm[k] = v\n\t}\n\t// File uploading.\n\tif r.MultipartForm != nil {\n\t\tfor name := range r.MultipartForm.File {\n\t\t\tif uploadFiles := r.GetUploadFiles(name); len(uploadFiles) == 1 {\n\t\t\t\tm[name] = uploadFiles[0]\n\t\t\t} else {\n\t\t\t\tm[name] = uploadFiles\n\t\t\t}\n\t\t}\n\t}\n\t// Check none exist parameters and assign it with default value.\n\tif filter {\n\t\tfor k, v := range kvMap[0] {\n\t\t\tif _, ok = m[k]; !ok {\n\t\t\t\tm[k] = v\n\t\t\t}\n\t\t}\n\t}\n\treturn m\n}\n\n// GetRequestMapStrStr retrieve and returns all parameters passed from the client and custom\n// params as map[string]string, no matter what HTTP method the client is using. The parameter\n// `kvMap` specifies the keys retrieving from client parameters, the associated values are the\n// default values if the client does not pass.\nfunc (r *Request) GetRequestMapStrStr(kvMap ...map[string]any) map[string]string {\n\trequestMap := r.GetRequestMap(kvMap...)\n\tif len(requestMap) > 0 {\n\t\tm := make(map[string]string, len(requestMap))\n\t\tfor k, v := range requestMap {\n\t\t\tm[k] = gconv.String(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetRequestMapStrVar retrieve and returns all parameters passed from the client and custom\n// params as map[string]*gvar.Var, no matter what HTTP method the client is using. The parameter\n// `kvMap` specifies the keys retrieving from client parameters, the associated values are the\n// default values if the client does not pass.\nfunc (r *Request) GetRequestMapStrVar(kvMap ...map[string]any) map[string]*gvar.Var {\n\trequestMap := r.GetRequestMap(kvMap...)\n\tif len(requestMap) > 0 {\n\t\tm := make(map[string]*gvar.Var, len(requestMap))\n\t\tfor k, v := range requestMap {\n\t\t\tm[k] = gvar.New(v)\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetRequestStruct retrieves all parameters passed from the client and custom params no matter\n// what HTTP method the client is using, and converts them to give the struct object. Note that\n// the parameter `pointer` is a pointer to the struct object.\n// The optional parameter `mapping` is used to specify the key to attribute mapping.\nfunc (r *Request) GetRequestStruct(pointer any, mapping ...map[string]string) error {\n\t_, err := r.doGetRequestStruct(pointer, mapping...)\n\treturn err\n}\n\nfunc (r *Request) doGetRequestStruct(pointer any, mapping ...map[string]string) (data map[string]any, err error) {\n\tdata = r.GetRequestMap()\n\tif data == nil {\n\t\tdata = map[string]any{}\n\t}\n\n\t// `in` Tag Struct values.\n\tif err = r.mergeInTagStructValue(data); err != nil {\n\t\treturn data, nil\n\t}\n\n\t// Default struct values.\n\tif err = r.mergeDefaultStructValue(data, pointer); err != nil {\n\t\treturn data, nil\n\t}\n\n\treturn data, gconv.Struct(data, pointer, mapping...)\n}\n\n// mergeDefaultStructValue merges the request parameters with default values from struct tag definition.\nfunc (r *Request) mergeDefaultStructValue(data map[string]any, pointer any) error {\n\tfields := r.serveHandler.Handler.Info.ReqStructFields\n\tif len(fields) > 0 {\n\t\tfor _, field := range fields {\n\t\t\tif tagValue := field.TagDefault(); tagValue != \"\" {\n\t\t\t\tmergeTagValueWithFoundKey(data, false, field.Name(), field.Name(), tagValue)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\t// provide non strict routing\n\ttagFields, err := gstructs.TagFields(pointer, defaultValueTags)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(tagFields) > 0 {\n\t\tfor _, field := range tagFields {\n\t\t\tmergeTagValueWithFoundKey(data, false, field.Name(), field.Name(), field.TagValue)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// mergeInTagStructValue merges the request parameters with header or cookie values from struct `in` tag definition.\nfunc (r *Request) mergeInTagStructValue(data map[string]any) error {\n\tfields := r.serveHandler.Handler.Info.ReqStructFields\n\tif len(fields) > 0 {\n\t\tvar (\n\t\t\theaderMap = make(map[string]any)\n\t\t\tcookieMap = make(map[string]any)\n\t\t)\n\n\t\tfor k, v := range r.Header {\n\t\t\tif len(v) > 0 {\n\t\t\t\theaderMap[k] = v[0]\n\t\t\t}\n\t\t}\n\n\t\tfor _, cookie := range r.Cookies() {\n\t\t\tcookieMap[cookie.Name] = cookie.Value\n\t\t}\n\n\t\tfor _, field := range fields {\n\t\t\tvar (\n\t\t\t\tfoundKey   string\n\t\t\t\tfoundValue any\n\t\t\t)\n\t\t\tif tagValue := field.TagIn(); tagValue != \"\" {\n\t\t\t\tfindKey := field.TagPriorityName()\n\t\t\t\tswitch tagValue {\n\t\t\t\tcase goai.ParameterInHeader:\n\t\t\t\t\tfoundKey, foundValue = gutil.MapPossibleItemByKey(headerMap, findKey)\n\t\t\t\tcase goai.ParameterInCookie:\n\t\t\t\t\tfoundKey, foundValue = gutil.MapPossibleItemByKey(cookieMap, findKey)\n\t\t\t\t}\n\t\t\t\tif foundKey != \"\" {\n\t\t\t\t\tmergeTagValueWithFoundKey(data, true, foundKey, field.Name(), foundValue)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// mergeTagValueWithFoundKey merges the request parameters when the key does not exist in the map or overwritten is true or the value is nil.\nfunc mergeTagValueWithFoundKey(data map[string]any, overwritten bool, findKey string, fieldName string, tagValue any) {\n\tif foundKey, foundValue := gutil.MapPossibleItemByKey(data, findKey); foundKey == \"\" {\n\t\tdata[fieldName] = tagValue\n\t} else {\n\t\tif overwritten || foundValue == nil {\n\t\t\tdata[foundKey] = tagValue\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_param_router.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/container/gvar\"\n\n// GetRouterMap retrieves and returns a copy of the router map.\nfunc (r *Request) GetRouterMap() map[string]string {\n\tif r.routerMap != nil {\n\t\tm := make(map[string]string, len(r.routerMap))\n\t\tfor k, v := range r.routerMap {\n\t\t\tm[k] = v\n\t\t}\n\t\treturn m\n\t}\n\treturn nil\n}\n\n// GetRouter retrieves and returns the router value with given key name `key`.\n// It returns `def` if `key` does not exist.\nfunc (r *Request) GetRouter(key string, def ...any) *gvar.Var {\n\tif r.routerMap != nil {\n\t\tif v, ok := r.routerMap[key]; ok {\n\t\t\treturn gvar.New(v)\n\t\t}\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_request_view.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/os/gview\"\n\n// SetView sets template view engine object for this request.\nfunc (r *Request) SetView(view *gview.View) {\n\tr.viewObject = view\n}\n\n// GetView returns the template view engine object for this request.\nfunc (r *Request) GetView() *gview.View {\n\tview := r.viewObject\n\tif view == nil {\n\t\tview = r.Server.config.View\n\t}\n\tif view == nil {\n\t\tview = gview.Instance()\n\t}\n\treturn view\n}\n\n// Assigns binds multiple template variables to current request.\nfunc (r *Request) Assigns(data gview.Params) {\n\tif r.viewParams == nil {\n\t\tr.viewParams = make(gview.Params, len(data))\n\t}\n\tfor k, v := range data {\n\t\tr.viewParams[k] = v\n\t}\n}\n\n// Assign binds a template variable to current request.\nfunc (r *Request) Assign(key string, value any) {\n\tif r.viewParams == nil {\n\t\tr.viewParams = make(gview.Params)\n\t}\n\tr.viewParams[key] = value\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_response.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/net/ghttp/internal/response\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n)\n\n// Response is the http response manager.\n// Note that it implements the http.ResponseWriter interface with buffering feature.\ntype Response struct {\n\t*response.BufferWriter          // Underlying ResponseWriter.\n\tServer                 *Server  // Parent server.\n\tRequest                *Request // According request.\n}\n\n// newResponse creates and returns a new Response object.\nfunc newResponse(s *Server, w http.ResponseWriter) *Response {\n\tr := &Response{\n\t\tServer:       s,\n\t\tBufferWriter: response.NewBufferWriter(w),\n\t}\n\treturn r\n}\n\n// ServeFile serves the file to the response.\nfunc (r *Response) ServeFile(path string, allowIndex ...bool) {\n\tvar (\n\t\tserveFile *staticFile\n\t)\n\tif file := gres.Get(path); file != nil {\n\t\tserveFile = &staticFile{\n\t\t\tFile:  file,\n\t\t\tIsDir: file.FileInfo().IsDir(),\n\t\t}\n\t} else {\n\t\tpath, _ = gfile.Search(path)\n\t\tif path == \"\" {\n\t\t\tr.WriteStatus(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\t\tserveFile = &staticFile{Path: path}\n\t}\n\tr.Server.serveFile(r.Request, serveFile, allowIndex...)\n}\n\n// ServeFileDownload serves file downloading to the response.\nfunc (r *Response) ServeFileDownload(path string, name ...string) {\n\tvar (\n\t\tserveFile    *staticFile\n\t\tdownloadName = \"\"\n\t)\n\n\tif len(name) > 0 {\n\t\tdownloadName = name[0]\n\t}\n\tif file := gres.Get(path); file != nil {\n\t\tserveFile = &staticFile{\n\t\t\tFile:  file,\n\t\t\tIsDir: file.FileInfo().IsDir(),\n\t\t}\n\t\tif downloadName == \"\" {\n\t\t\tdownloadName = gfile.Basename(file.Name())\n\t\t}\n\t} else {\n\t\tpath, _ = gfile.Search(path)\n\t\tif path == \"\" {\n\t\t\tr.WriteStatus(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\t\tserveFile = &staticFile{Path: path}\n\t\tif downloadName == \"\" {\n\t\t\tdownloadName = gfile.Basename(path)\n\t\t}\n\t}\n\tr.Header().Set(\"Content-Type\", \"application/force-download\")\n\tr.Header().Set(\"Accept-Ranges\", \"bytes\")\n\tif utils.IsASCII(downloadName) {\n\t\tr.Header().Set(\"Content-Disposition\", fmt.Sprintf(`attachment;filename=%s`, url.QueryEscape(downloadName)))\n\t} else {\n\t\tr.Header().Set(\"Content-Disposition\", fmt.Sprintf(`attachment;filename*=UTF-8''%s`, url.QueryEscape(downloadName)))\n\t}\n\n\tr.Header().Set(\"Access-Control-Expose-Headers\", \"Content-Disposition\")\n\tr.Server.serveFile(r.Request, serveFile)\n}\n\n// RedirectTo redirects the client to another location.\n// The optional parameter `code` specifies the http status code for redirecting,\n// which commonly can be 301 or 302. It's 302 in default.\nfunc (r *Response) RedirectTo(location string, code ...int) {\n\tr.Header().Set(\"Location\", location)\n\tif len(code) > 0 {\n\t\tr.WriteHeader(code[0])\n\t} else {\n\t\tr.WriteHeader(http.StatusFound)\n\t}\n\tr.Request.Exit()\n}\n\n// RedirectBack redirects the client back to referer.\n// The optional parameter `code` specifies the http status code for redirecting,\n// which commonly can be 301 or 302. It's 302 in default.\nfunc (r *Response) RedirectBack(code ...int) {\n\tr.RedirectTo(r.Request.GetReferer(), code...)\n}\n\n// ServeContent replies to the request using the content in the\n// provided ReadSeeker. The main benefit of ServeContent over io.Copy\n// is that it handles Range requests properly, sets the MIME type, and\n// handles If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since,\n// and If-Range requests.\n//\n// See http.ServeContent\nfunc (r *Response) ServeContent(name string, modTime time.Time, content io.ReadSeeker) {\n\thttp.ServeContent(r.RawWriter(), r.Request.Request, name, modTime, content)\n}\n\n// Flush outputs the buffer content to the client and clears the buffer.\nfunc (r *Response) Flush() {\n\tr.Header().Set(responseHeaderTraceID, gtrace.GetTraceID(r.Request.Context()))\n\tif r.Server.config.ServerAgent != \"\" {\n\t\tr.Header().Set(\"Server\", r.Server.config.ServerAgent)\n\t}\n\tr.BufferWriter.Flush()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_response_cors.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage ghttp\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// CORSOptions is the options for CORS feature.\n// See https://www.w3.org/TR/cors/ .\ntype CORSOptions struct {\n\tAllowDomain      []string // Used for allowing requests from custom domains\n\tAllowOrigin      string   // Access-Control-Allow-Origin\n\tAllowCredentials string   // Access-Control-Allow-Credentials\n\tExposeHeaders    string   // Access-Control-Expose-Headers\n\tMaxAge           int      // Access-Control-Max-Age\n\tAllowMethods     string   // Access-Control-Allow-Methods\n\tAllowHeaders     string   // Access-Control-Allow-Headers\n}\n\nvar (\n\t// defaultAllowHeaders is the default allowed headers for CORS.\n\t// It defined another map for better header key searching performance.\n\tdefaultAllowHeaders    = \"Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With\"\n\tdefaultAllowHeadersMap = make(map[string]struct{})\n)\n\nfunc init() {\n\tarray := gstr.SplitAndTrim(defaultAllowHeaders, \",\")\n\tfor _, header := range array {\n\t\tdefaultAllowHeadersMap[header] = struct{}{}\n\t}\n}\n\n// DefaultCORSOptions returns the default CORS options,\n// which allows any cross-domain request.\nfunc (r *Response) DefaultCORSOptions() CORSOptions {\n\toptions := CORSOptions{\n\t\tAllowOrigin:      \"*\",\n\t\tAllowMethods:     supportedHttpMethods,\n\t\tAllowCredentials: \"true\",\n\t\tAllowHeaders:     defaultAllowHeaders,\n\t\tMaxAge:           3628800,\n\t}\n\t// Allow all client's custom headers in default.\n\tif headers := r.Request.Header.Get(\"Access-Control-Request-Headers\"); headers != \"\" {\n\t\tarray := gstr.SplitAndTrim(headers, \",\")\n\t\tfor _, header := range array {\n\t\t\tif _, ok := defaultAllowHeadersMap[header]; !ok {\n\t\t\t\toptions.AllowHeaders += \",\" + header\n\t\t\t}\n\t\t}\n\t}\n\t// Allow all anywhere origin in default.\n\tif origin := r.Request.Header.Get(\"Origin\"); origin != \"\" {\n\t\toptions.AllowOrigin = origin\n\t} else if referer := r.Request.Referer(); referer != \"\" {\n\t\tif ref, err := url.Parse(referer); err == nil {\n\t\t\toptions.AllowOrigin = ref.Scheme + \"://\" + ref.Host\n\t\t} else {\n\t\t\toptions.AllowOrigin = referer\n\t\t}\n\t}\n\treturn options\n}\n\n// CORS sets custom CORS options.\n// See https://www.w3.org/TR/cors/ .\nfunc (r *Response) CORS(options CORSOptions) {\n\tif r.CORSAllowedOrigin(options) {\n\t\tr.Header().Set(\"Access-Control-Allow-Origin\", options.AllowOrigin)\n\t}\n\tif options.AllowCredentials != \"\" {\n\t\tr.Header().Set(\"Access-Control-Allow-Credentials\", options.AllowCredentials)\n\t}\n\tif options.ExposeHeaders != \"\" {\n\t\tr.Header().Set(\"Access-Control-Expose-Headers\", options.ExposeHeaders)\n\t}\n\tif options.MaxAge != 0 {\n\t\tr.Header().Set(\"Access-Control-Max-Age\", gconv.String(options.MaxAge))\n\t}\n\tif options.AllowMethods != \"\" {\n\t\tr.Header().Set(\"Access-Control-Allow-Methods\", options.AllowMethods)\n\t}\n\tif options.AllowHeaders != \"\" {\n\t\tr.Header().Set(\"Access-Control-Allow-Headers\", options.AllowHeaders)\n\t}\n\t// No continue service handling if it's OPTIONS request.\n\t// Note that there's special checks in previous router searching,\n\t// so if it goes to here it means there's already serving handler exist.\n\tif gstr.Equal(r.Request.Method, \"OPTIONS\") {\n\t\tif r.Status == 0 {\n\t\t\tr.Status = http.StatusOK\n\t\t}\n\t\t// No continue serving.\n\t\tr.Request.ExitAll()\n\t}\n}\n\n// CORSAllowedOrigin CORSAllowed checks whether the current request origin is allowed cross-domain.\nfunc (r *Response) CORSAllowedOrigin(options CORSOptions) bool {\n\tif options.AllowDomain == nil {\n\t\treturn true\n\t}\n\torigin := r.Request.Header.Get(\"Origin\")\n\tif origin == \"\" {\n\t\treturn true\n\t}\n\tparsed, err := url.Parse(origin)\n\tif err != nil {\n\t\treturn false\n\t}\n\tfor _, v := range options.AllowDomain {\n\t\tif gstr.IsSubDomain(parsed.Host, v) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// CORSDefault sets CORS with default CORS options,\n// which allows any cross-domain request.\nfunc (r *Response) CORSDefault() {\n\tr.CORS(r.DefaultCORSOptions())\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_response_view.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmode\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// WriteTpl parses and responses given template file.\n// The parameter `params` specifies the template variables for parsing.\nfunc (r *Response) WriteTpl(tpl string, params ...gview.Params) error {\n\tr.Header().Set(\"Content-Type\", contentTypeHtml)\n\tb, err := r.ParseTpl(tpl, params...)\n\tif err != nil {\n\t\tif !gmode.IsProduct() {\n\t\t\tr.Write(\"Template Parsing Error: \" + err.Error())\n\t\t}\n\t\treturn err\n\t}\n\tr.Write(b)\n\treturn nil\n}\n\n// WriteTplDefault parses and responses the default template file.\n// The parameter `params` specifies the template variables for parsing.\nfunc (r *Response) WriteTplDefault(params ...gview.Params) error {\n\tr.Header().Set(\"Content-Type\", contentTypeHtml)\n\tb, err := r.ParseTplDefault(params...)\n\tif err != nil {\n\t\tif !gmode.IsProduct() {\n\t\t\tr.Write(\"Template Parsing Error: \" + err.Error())\n\t\t}\n\t\treturn err\n\t}\n\tr.Write(b)\n\treturn nil\n}\n\n// WriteTplContent parses and responses the template content.\n// The parameter `params` specifies the template variables for parsing.\nfunc (r *Response) WriteTplContent(content string, params ...gview.Params) error {\n\tr.Header().Set(\"Content-Type\", contentTypeHtml)\n\tb, err := r.ParseTplContent(content, params...)\n\tif err != nil {\n\t\tif !gmode.IsProduct() {\n\t\t\tr.Write(\"Template Parsing Error: \" + err.Error())\n\t\t}\n\t\treturn err\n\t}\n\tr.Write(b)\n\treturn nil\n}\n\n// ParseTpl parses given template file `tpl` with given template variables `params`\n// and returns the parsed template content.\nfunc (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {\n\treturn r.Request.GetView().Parse(r.Request.Context(), tpl, r.buildInVars(params...))\n}\n\n// ParseTplDefault parses the default template file with params.\nfunc (r *Response) ParseTplDefault(params ...gview.Params) (string, error) {\n\treturn r.Request.GetView().ParseDefault(r.Request.Context(), r.buildInVars(params...))\n}\n\n// ParseTplContent parses given template file `file` with given template parameters `params`\n// and returns the parsed template content.\nfunc (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {\n\treturn r.Request.GetView().ParseContent(r.Request.Context(), content, r.buildInVars(params...))\n}\n\n// buildInVars merges build-in variables into `params` and returns the new template variables.\n// TODO performance improving.\nfunc (r *Response) buildInVars(params ...map[string]any) map[string]any {\n\tm := gutil.MapMergeCopy(r.Request.viewParams)\n\tif len(params) > 0 {\n\t\tgutil.MapMerge(m, params[0])\n\t}\n\t// Retrieve custom template variables from request object.\n\tsessionMap := gconv.Map(r.Request.Session.MustData(),\n\t\tgconv.MapOption{\n\t\t\tDeep:            true,\n\t\t\tOmitEmpty:       false,\n\t\t\tContinueOnError: true,\n\t\t})\n\tgutil.MapMerge(m, map[string]any{\n\t\t\"Form\":    r.Request.GetFormMap(),\n\t\t\"Query\":   r.Request.GetQueryMap(),\n\t\t\"Request\": r.Request.GetMap(),\n\t\t\"Cookie\":  r.Request.Cookie.Map(),\n\t\t\"Session\": sessionMap,\n\t})\n\t// Note that it should assign no Config variable to a template\n\t// if there's no configuration file.\n\tif v, _ := gcfg.Instance().Data(r.Request.Context()); len(v) > 0 {\n\t\tm[\"Config\"] = v\n\t}\n\treturn m\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_response_write.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Write writes `content` to the response buffer.\nfunc (r *Response) Write(content ...any) {\n\tif r.IsHijacked() || len(content) == 0 {\n\t\treturn\n\t}\n\tif r.Status == 0 {\n\t\tr.Status = http.StatusOK\n\t}\n\tfor _, v := range content {\n\t\tswitch value := v.(type) {\n\t\tcase []byte:\n\t\t\t_, _ = r.BufferWriter.Write(value)\n\t\tcase string:\n\t\t\t_, _ = r.WriteString(value)\n\t\tdefault:\n\t\t\t_, _ = r.WriteString(gconv.String(v))\n\t\t}\n\t}\n}\n\n// WriteExit writes `content` to the response buffer and exits executing of current handler.\n// The \"Exit\" feature is commonly used to replace usage of return statements in the handler,\n// for convenience.\nfunc (r *Response) WriteExit(content ...any) {\n\tr.Write(content...)\n\tr.Request.Exit()\n}\n\n// WriteOver overwrites the response buffer with `content`.\nfunc (r *Response) WriteOver(content ...any) {\n\tr.ClearBuffer()\n\tr.Write(content...)\n}\n\n// WriteOverExit overwrites the response buffer with `content` and exits executing\n// of current handler. The \"Exit\" feature is commonly used to replace usage of return\n// statements in the handler, for convenience.\nfunc (r *Response) WriteOverExit(content ...any) {\n\tr.WriteOver(content...)\n\tr.Request.Exit()\n}\n\n// Writef writes the response with fmt.Sprintf.\nfunc (r *Response) Writef(format string, params ...any) {\n\tr.Write(fmt.Sprintf(format, params...))\n}\n\n// WritefExit writes the response with fmt.Sprintf and exits executing of current handler.\n// The \"Exit\" feature is commonly used to replace usage of return statements in the handler,\n// for convenience.\nfunc (r *Response) WritefExit(format string, params ...any) {\n\tr.Writef(format, params...)\n\tr.Request.Exit()\n}\n\n// Writeln writes the response with `content` and new line.\nfunc (r *Response) Writeln(content ...any) {\n\tif len(content) == 0 {\n\t\tr.Write(\"\\n\")\n\t\treturn\n\t}\n\tr.Write(append(content, \"\\n\")...)\n}\n\n// WritelnExit writes the response with `content` and new line and exits executing\n// of current handler. The \"Exit\" feature is commonly used to replace usage of return\n// statements in the handler, for convenience.\nfunc (r *Response) WritelnExit(content ...any) {\n\tr.Writeln(content...)\n\tr.Request.Exit()\n}\n\n// Writefln writes the response with fmt.Sprintf and new line.\nfunc (r *Response) Writefln(format string, params ...any) {\n\tr.Writeln(fmt.Sprintf(format, params...))\n}\n\n// WriteflnExit writes the response with fmt.Sprintf and new line and exits executing\n// of current handler. The \"Exit\" feature is commonly used to replace usage of return\n// statement in the handler, for convenience.\nfunc (r *Response) WriteflnExit(format string, params ...any) {\n\tr.Writefln(format, params...)\n\tr.Request.Exit()\n}\n\n// WriteJson writes `content` to the response with JSON format.\nfunc (r *Response) WriteJson(content any) {\n\tr.Header().Set(\"Content-Type\", contentTypeJson)\n\t// If given string/[]byte, response it directly to the client.\n\tswitch content.(type) {\n\tcase string, []byte:\n\t\tr.Write(gconv.String(content))\n\t\treturn\n\t}\n\t// Else use json.Marshal function to encode the parameter.\n\tif b, err := json.Marshal(content); err != nil {\n\t\tpanic(gerror.Wrap(err, `WriteJson failed`))\n\t} else {\n\t\tr.Write(b)\n\t}\n}\n\n// WriteJsonExit writes `content` to the response with JSON format and exits executing\n// of current handler if success. The \"Exit\" feature is commonly used to replace usage of\n// return statements in the handler, for convenience.\nfunc (r *Response) WriteJsonExit(content any) {\n\tr.WriteJson(content)\n\tr.Request.Exit()\n}\n\n// WriteJsonP writes `content` to the response with JSONP format.\n//\n// Note that there should be a \"callback\" parameter in the request for JSONP format.\nfunc (r *Response) WriteJsonP(content any) {\n\tr.Header().Set(\"Content-Type\", contentTypeJavascript)\n\t// If given string/[]byte, response it directly to client.\n\tswitch content.(type) {\n\tcase string, []byte:\n\t\tr.Write(gconv.String(content))\n\t\treturn\n\t}\n\t// Else use json.Marshal function to encode the parameter.\n\tif b, err := json.Marshal(content); err != nil {\n\t\tpanic(gerror.Wrap(err, `WriteJsonP failed`))\n\t} else {\n\t\t// r.Header().Set(\"Content-Type\", \"application/json\")\n\t\tif callback := r.Request.Get(\"callback\").String(); callback != \"\" {\n\t\t\tbuffer := []byte(callback)\n\t\t\tbuffer = append(buffer, byte('('))\n\t\t\tbuffer = append(buffer, b...)\n\t\t\tbuffer = append(buffer, byte(')'))\n\t\t\tr.Write(buffer)\n\t\t} else {\n\t\t\tr.Write(b)\n\t\t}\n\t}\n}\n\n// WriteJsonPExit writes `content` to the response with JSONP format and exits executing\n// of current handler if success. The \"Exit\" feature is commonly used to replace usage of\n// return statements in the handler, for convenience.\n//\n// Note that there should be a \"callback\" parameter in the request for JSONP format.\nfunc (r *Response) WriteJsonPExit(content any) {\n\tr.WriteJsonP(content)\n\tr.Request.Exit()\n}\n\n// WriteXml writes `content` to the response with XML format.\nfunc (r *Response) WriteXml(content any, rootTag ...string) {\n\tr.Header().Set(\"Content-Type\", contentTypeXml)\n\t// If given string/[]byte, response it directly to clients.\n\tswitch content.(type) {\n\tcase string, []byte:\n\t\tr.Write(gconv.String(content))\n\t\treturn\n\t}\n\tif b, err := gjson.New(content).ToXml(rootTag...); err != nil {\n\t\tpanic(gerror.Wrap(err, `WriteXml failed`))\n\t} else {\n\t\tr.Write(b)\n\t}\n}\n\n// WriteXmlExit writes `content` to the response with XML format and exits executing\n// of current handler if success. The \"Exit\" feature is commonly used to replace usage\n// of return statements in the handler, for convenience.\nfunc (r *Response) WriteXmlExit(content any, rootTag ...string) {\n\tr.WriteXml(content, rootTag...)\n\tr.Request.Exit()\n}\n\n// WriteStatus writes HTTP `status` and `content` to the response.\n// Note that it does not set a Content-Type header here.\nfunc (r *Response) WriteStatus(status int, content ...any) {\n\tr.WriteHeader(status)\n\tif len(content) > 0 {\n\t\tr.Write(content...)\n\t} else {\n\t\tr.Write(http.StatusText(status))\n\t}\n}\n\n// WriteStatusExit writes HTTP `status` and `content` to the response and exits executing\n// of current handler if success. The \"Exit\" feature is commonly used to replace usage of\n// return statements in the handler, for convenience.\nfunc (r *Response) WriteStatusExit(status int, content ...any) {\n\tr.WriteStatus(status, content...)\n\tr.Request.Exit()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\t\"github.com/olekukonko/tablewriter/renderer\"\n\t\"github.com/olekukonko/tablewriter/tw\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/ghttp/internal/graceful\"\n\t\"github.com/gogf/gf/v2/net/ghttp/internal/swaggerui\"\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc init() {\n\t// Initialize the method map.\n\tfor _, v := range strings.Split(supportedHttpMethods, \",\") {\n\t\tmethodsMap[v] = struct{}{}\n\t}\n}\n\n// serverProcessInit initializes some process configurations, which can only be done once.\nfunc serverProcessInit() {\n\tvar ctx = context.TODO()\n\tif !serverProcessInitialized.Cas(false, true) {\n\t\treturn\n\t}\n\t// This means it is a restart server. It should kill its parent before starting its listening,\n\t// to avoid duplicated port listening in two processes.\n\tif !genv.Get(adminActionRestartEnvKey).IsEmpty() {\n\t\tif p, err := os.FindProcess(gproc.PPid()); err == nil {\n\t\t\tif err = p.Kill(); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t\tif _, err = p.Wait(); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t} else {\n\t\t\tglog.Error(ctx, err)\n\t\t}\n\t}\n\n\t// Process message handler.\n\t// It enabled only a graceful feature is enabled.\n\tif gracefulEnabled {\n\t\tintlog.Printf(ctx, \"pid[%d]: graceful reload feature is enabled\", gproc.Pid())\n\t\tgo handleProcessMessage()\n\t} else {\n\t\tintlog.Printf(ctx, \"pid[%d]: graceful reload feature is disabled\", gproc.Pid())\n\t}\n\n\t// It's an ugly calling for better initializing the main package path\n\t// in source development environment. It is useful only be used in main goroutine.\n\t// It fails to retrieve the main package path in asynchronous goroutines.\n\tgfile.MainPkgPath()\n}\n\n// GetServer creates and returns a server instance using given name and default configurations.\n// Note that the parameter `name` should be unique for different servers. It returns an existing\n// server instance if given `name` is already existing in the server mapping.\nfunc GetServer(name ...any) *Server {\n\tserverName := DefaultServerName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tserverName = gconv.String(name[0])\n\t}\n\treturn serverMapping.GetOrSetFuncLock(serverName, func() *Server {\n\t\ts := &Server{\n\t\t\tinstance:         serverName,\n\t\t\tplugins:          make([]Plugin, 0),\n\t\t\tservers:          make([]*graceful.Server, 0),\n\t\t\tcloseChan:        make(chan struct{}, 10000),\n\t\t\tserverCount:      gtype.NewInt(),\n\t\t\tstatusHandlerMap: make(map[string][]HandlerFunc),\n\t\t\tserveTree:        make(map[string]any),\n\t\t\tserveCache:       gcache.New(),\n\t\t\troutesMap:        make(map[string][]*HandlerItem),\n\t\t\topenapi:          goai.New(),\n\t\t\tregistrar:        gsvc.GetRegistry(),\n\t\t}\n\t\t// Initialize the server using default configurations.\n\t\tif err := s.SetConfig(NewConfig()); err != nil {\n\t\t\tpanic(gerror.WrapCode(gcode.CodeInvalidConfiguration, err, \"\"))\n\t\t}\n\t\t// It enables OpenTelemetry for server in default.\n\t\ts.Use(internalMiddlewareServerTracing)\n\t\treturn s\n\t})\n}\n\n// Start starts listening on configured port.\n// This function does not block the process, you can use function Wait blocking the process.\nfunc (s *Server) Start() error {\n\tvar ctx = gctx.GetInitCtx()\n\n\t// Swagger UI.\n\tif s.config.SwaggerPath != \"\" {\n\t\tswaggerui.Init()\n\t\ts.AddStaticPath(s.config.SwaggerPath, swaggerUIPackedPath)\n\t\ts.BindHookHandler(s.config.SwaggerPath+\"/*\", HookBeforeServe, s.swaggerUI)\n\t}\n\n\t// OpenApi specification json producing handler.\n\tif s.config.OpenApiPath != \"\" {\n\t\ts.BindHandler(s.config.OpenApiPath, s.openapiSpec)\n\t}\n\n\t// Register group routes.\n\ts.handlePreBindItems(ctx)\n\n\t// Server process initialization, which can only be initialized once.\n\tserverProcessInit()\n\n\t// Server can only be run once.\n\tif s.Status() == ServerStatusRunning {\n\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"server is already running\")\n\t}\n\n\t// Logging path setting check.\n\tif s.config.LogPath != \"\" && s.config.LogPath != s.config.Logger.GetPath() {\n\t\tif err := s.config.Logger.SetPath(s.config.LogPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Default session storage.\n\tif s.config.SessionStorage == nil {\n\t\tsessionStoragePath := \"\"\n\t\tif s.config.SessionPath != \"\" {\n\t\t\tsessionStoragePath = gfile.Join(s.config.SessionPath, s.config.Name)\n\t\t\tif !gfile.Exists(sessionStoragePath) {\n\t\t\t\tif err := gfile.Mkdir(sessionStoragePath); err != nil {\n\t\t\t\t\treturn gerror.Wrapf(err, `mkdir failed for \"%s\"`, sessionStoragePath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ts.config.SessionStorage = gsession.NewStorageFile(sessionStoragePath, s.config.SessionMaxAge)\n\t}\n\t// Initialize session manager when start running.\n\ts.sessionManager = gsession.New(\n\t\ts.config.SessionMaxAge,\n\t\ts.config.SessionStorage,\n\t)\n\n\t// PProf feature.\n\tif s.config.PProfEnabled {\n\t\ts.EnablePProf(s.config.PProfPattern)\n\t}\n\n\t// Default HTTP handler.\n\tif s.config.Handler == nil {\n\t\ts.config.Handler = s.ServeHTTP\n\t}\n\n\t// Install external plugins.\n\tfor _, p := range s.plugins {\n\t\tif err := p.Install(s); err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\t}\n\t}\n\t// Check the group routes again for internally registered routes.\n\ts.handlePreBindItems(ctx)\n\n\t// If there's no route registered and no static service enabled,\n\t// it then returns an error of invalid usage of server.\n\tif len(s.routesMap) == 0 && !s.config.FileServerEnabled {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t`there's no route set or static feature enabled, did you forget import the router?`,\n\t\t)\n\t}\n\t// ================================================================================================\n\t// Start the HTTP server.\n\t// ================================================================================================\n\treloaded := false\n\tfdMapStr := genv.Get(adminActionReloadEnvKey).String()\n\tif len(fdMapStr) > 0 {\n\t\tsfm := bufferToServerFdMap([]byte(fdMapStr))\n\t\tif v, ok := sfm[s.config.Name]; ok {\n\t\t\ts.startServer(v)\n\t\t\treloaded = true\n\t\t}\n\t}\n\tif !reloaded {\n\t\ts.startServer(nil)\n\t}\n\n\t// Swagger UI info.\n\tif s.config.SwaggerPath != \"\" {\n\t\ts.Logger().Infof(\n\t\t\tctx,\n\t\t\t`swagger ui is serving at address: %s%s/`,\n\t\t\ts.getLocalListenedAddress(),\n\t\t\ts.config.SwaggerPath,\n\t\t)\n\t}\n\t// OpenApi specification info.\n\tif s.config.OpenApiPath != \"\" {\n\t\ts.Logger().Infof(\n\t\t\tctx,\n\t\t\t`openapi specification is serving at address: %s%s`,\n\t\t\ts.getLocalListenedAddress(),\n\t\t\ts.config.OpenApiPath,\n\t\t)\n\t} else {\n\t\tif s.config.SwaggerPath != \"\" {\n\t\t\ts.Logger().Warning(\n\t\t\t\tctx,\n\t\t\t\t`openapi specification is disabled but swagger ui is serving, which might make no sense`,\n\t\t\t)\n\t\t} else {\n\t\t\ts.Logger().Info(\n\t\t\t\tctx,\n\t\t\t\t`openapi specification is disabled`,\n\t\t\t)\n\t\t}\n\t}\n\n\t// If this is a child process, it then notifies its parent exit.\n\tif gproc.IsChild() {\n\t\tvar gracefulTimeout = time.Duration(s.config.GracefulTimeout) * time.Second\n\t\tgtimer.SetTimeout(ctx, gracefulTimeout, func(ctx context.Context) {\n\t\t\tintlog.Printf(\n\t\t\t\tctx,\n\t\t\t\t`pid[%d]: notice parent server graceful shuttingdown, ppid: %d`,\n\t\t\t\tgproc.Pid(), gproc.PPid(),\n\t\t\t)\n\t\t\tif err := gproc.Send(gproc.PPid(), []byte(\"exit\"), adminGProcCommGroup); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `server error in process communication: %+v`, err)\n\t\t\t}\n\t\t})\n\t}\n\ts.initOpenApi()\n\ts.doServiceRegister()\n\ts.doRouterMapDump()\n\n\treturn nil\n}\n\nfunc (s *Server) getLocalListenedAddress() string {\n\treturn fmt.Sprintf(`http://127.0.0.1:%d`, s.GetListenedPort())\n}\n\n// doRouterMapDump checks and dumps the router map to the log.\nfunc (s *Server) doRouterMapDump() {\n\tif !s.config.DumpRouterMap {\n\t\treturn\n\t}\n\n\tvar (\n\t\tctx                          = context.TODO()\n\t\troutes                       = s.GetRoutes()\n\t\tisJustDefaultServerAndDomain = true\n\t\theaders                      = []string{\n\t\t\t\"SERVER\", \"DOMAIN\", \"ADDRESS\", \"METHOD\", \"ROUTE\", \"HANDLER\", \"MIDDLEWARE\",\n\t\t}\n\t)\n\tfor _, item := range routes {\n\t\tif item.Server != DefaultServerName || item.Domain != DefaultDomainName {\n\t\t\tisJustDefaultServerAndDomain = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif isJustDefaultServerAndDomain {\n\t\theaders = []string{\"ADDRESS\", \"METHOD\", \"ROUTE\", \"HANDLER\", \"MIDDLEWARE\"}\n\t}\n\tif len(routes) > 0 {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\ttable := tablewriter.NewTable(buffer,\n\t\t\ttablewriter.WithRenderer(renderer.NewBlueprint(\n\t\t\t\ttw.Rendition{\n\t\t\t\t\tSettings: tw.Settings{\n\t\t\t\t\t\tSeparators: tw.Separators{BetweenRows: tw.On},\n\t\t\t\t\t},\n\t\t\t\t\tSymbols: tw.NewSymbolCustom(\"HTTP\").WithCenter(\"|\"),\n\t\t\t\t})),\n\t\t)\n\t\ttable.Header(headers)\n\n\t\tfor _, item := range routes {\n\t\t\tvar (\n\t\t\t\tdata        = make([]string, 0)\n\t\t\t\thandlerName = gstr.TrimRightStr(item.Handler.Name, \"-fm\")\n\t\t\t\tmiddlewares = gstr.SplitAndTrim(item.Middleware, \",\")\n\t\t\t)\n\n\t\t\t// No printing special internal middleware that may lead confused.\n\t\t\tif gstr.SubStrFromREx(handlerName, \".\") == noPrintInternalRoute {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor k, v := range middlewares {\n\t\t\t\tmiddlewares[k] = gstr.TrimRightStr(v, \"-fm\")\n\t\t\t}\n\t\t\titem.Middleware = gstr.Join(middlewares, \"\\n\")\n\t\t\tif isJustDefaultServerAndDomain {\n\t\t\t\tdata = append(\n\t\t\t\t\tdata,\n\t\t\t\t\titem.Address,\n\t\t\t\t\titem.Method,\n\t\t\t\t\titem.Route,\n\t\t\t\t\thandlerName,\n\t\t\t\t\titem.Middleware,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tdata = append(\n\t\t\t\t\tdata,\n\t\t\t\t\titem.Server,\n\t\t\t\t\titem.Domain,\n\t\t\t\t\titem.Address,\n\t\t\t\t\titem.Method,\n\t\t\t\t\titem.Route,\n\t\t\t\t\thandlerName,\n\t\t\t\t\titem.Middleware,\n\t\t\t\t)\n\t\t\t}\n\t\t\t_ = table.Append(data)\n\t\t}\n\t\t_ = table.Render()\n\t\ts.config.Logger.Header(false).Printf(ctx, \"\\n%s\", buffer.String())\n\t}\n}\n\n// GetOpenApi returns the OpenApi specification management object of the current server.\nfunc (s *Server) GetOpenApi() *goai.OpenApiV3 {\n\treturn s.openapi\n}\n\n// GetRoutes retrieves and returns the router array.\nfunc (s *Server) GetRoutes() []RouterItem {\n\tvar (\n\t\tm              = make(map[string]*garray.SortedArray)\n\t\trouteFilterSet = gset.NewStrSet()\n\t\taddress        = s.GetListenedAddress()\n\t)\n\tif s.config.HTTPSAddr != \"\" {\n\t\tif len(address) > 0 {\n\t\t\taddress += \",\"\n\t\t}\n\t\taddress += \"tls\" + s.config.HTTPSAddr\n\t}\n\tfor k, handlerItems := range s.routesMap {\n\t\tarray, _ := gregex.MatchString(`(.*?)%([A-Z]+):(.+)@(.+)`, k)\n\t\tfor index := len(handlerItems) - 1; index >= 0; index-- {\n\t\t\tvar (\n\t\t\t\thandlerItem = handlerItems[index]\n\t\t\t\titem        = RouterItem{\n\t\t\t\t\tServer:     s.config.Name,\n\t\t\t\t\tAddress:    address,\n\t\t\t\t\tDomain:     array[4],\n\t\t\t\t\tType:       handlerItem.Type,\n\t\t\t\t\tMiddleware: array[1],\n\t\t\t\t\tMethod:     array[2],\n\t\t\t\t\tRoute:      array[3],\n\t\t\t\t\tPriority:   index,\n\t\t\t\t\tHandler:    handlerItem,\n\t\t\t\t}\n\t\t\t)\n\t\t\tswitch item.Handler.Type {\n\t\t\tcase HandlerTypeObject, HandlerTypeHandler:\n\t\t\t\titem.IsServiceHandler = true\n\n\t\t\tcase HandlerTypeMiddleware:\n\t\t\t\titem.Middleware = \"GLOBAL MIDDLEWARE\"\n\t\t\t}\n\t\t\t// Repeated route filtering for dump.\n\t\t\tvar setKey = fmt.Sprintf(\n\t\t\t\t`%s|%s|%s|%s`,\n\t\t\t\titem.Method, item.Route, item.Domain, item.Type,\n\t\t\t)\n\t\t\tif !routeFilterSet.AddIfNotExist(setKey) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(item.Handler.Middleware) > 0 {\n\t\t\t\tfor _, v := range item.Handler.Middleware {\n\t\t\t\t\tif item.Middleware != \"\" {\n\t\t\t\t\t\titem.Middleware += \",\"\n\t\t\t\t\t}\n\t\t\t\t\titem.Middleware += gdebug.FuncName(v)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the domain does not exist in the dump map, it creates the map.\n\t\t\t// The value of the map is a custom sorted array.\n\t\t\tif _, ok := m[item.Domain]; !ok {\n\t\t\t\t// Sort in ASC order.\n\t\t\t\tm[item.Domain] = garray.NewSortedArray(func(v1, v2 any) int {\n\t\t\t\t\titem1 := v1.(RouterItem)\n\t\t\t\t\titem2 := v2.(RouterItem)\n\t\t\t\t\tr := 0\n\t\t\t\t\tif r = strings.Compare(item1.Domain, item2.Domain); r == 0 {\n\t\t\t\t\t\tif r = strings.Compare(item1.Route, item2.Route); r == 0 {\n\t\t\t\t\t\t\tif r = strings.Compare(item1.Method, item2.Method); r == 0 {\n\t\t\t\t\t\t\t\tif item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type != HandlerTypeMiddleware {\n\t\t\t\t\t\t\t\t\treturn -1\n\t\t\t\t\t\t\t\t} else if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type == HandlerTypeMiddleware {\n\t\t\t\t\t\t\t\t\treturn 1\n\t\t\t\t\t\t\t\t} else if r = strings.Compare(item1.Middleware, item2.Middleware); r == 0 {\n\t\t\t\t\t\t\t\t\tr = item2.Priority - item1.Priority\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn r\n\t\t\t\t})\n\t\t\t}\n\t\t\tm[item.Domain].Add(item)\n\t\t}\n\t}\n\n\trouterArray := make([]RouterItem, 0, 128)\n\tfor _, array := range m {\n\t\tfor _, v := range array.Slice() {\n\t\t\trouterArray = append(routerArray, v.(RouterItem))\n\t\t}\n\t}\n\treturn routerArray\n}\n\n// Run starts server listening in blocking way.\n// It's commonly used for single server situation.\nfunc (s *Server) Run() {\n\tvar ctx = context.TODO()\n\n\tif err := s.Start(); err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\n\t// Signal handler in asynchronous way.\n\tgo handleProcessSignal()\n\n\t// Blocking using the channel for graceful restart.\n\t<-s.closeChan\n\n\t// Shutdown the server\n\t_ = s.Shutdown()\n}\n\n// Wait blocks to wait for all servers done.\n// It's commonly used in multiple server situation.\nfunc Wait() {\n\tvar ctx = context.TODO()\n\n\t// Signal handler in asynchronous way.\n\tgo handleProcessSignal()\n\n\t<-allShutdownChan\n\n\t// Remove plugins.\n\tserverMapping.Iterator(func(k string, v *Server) bool {\n\t\tif len(v.plugins) > 0 {\n\t\t\tfor _, p := range v.plugins {\n\t\t\t\tintlog.Printf(ctx, `remove plugin: %s`, p.Name())\n\t\t\t\tif err := p.Remove(); err != nil {\n\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\tglog.Infof(ctx, \"pid[%d]: all servers shutdown\", gproc.Pid())\n}\n\n// startServer starts the underlying server listening.\nfunc (s *Server) startServer(fdMap listenerFdMap) {\n\tvar (\n\t\tctx          = context.TODO()\n\t\thttpsEnabled bool\n\t)\n\t// HTTPS\n\tif s.config.TLSConfig != nil || (s.config.HTTPSCertPath != \"\" && s.config.HTTPSKeyPath != \"\") {\n\t\tif len(s.config.HTTPSAddr) == 0 {\n\t\t\tif len(s.config.Address) > 0 {\n\t\t\t\ts.config.HTTPSAddr = s.config.Address\n\t\t\t\ts.config.Address = \"\"\n\t\t\t} else {\n\t\t\t\ts.config.HTTPSAddr = defaultHttpsAddr\n\t\t\t}\n\t\t}\n\t\thttpsEnabled = len(s.config.HTTPSAddr) > 0\n\t\tvar array []string\n\t\tif v, ok := fdMap[\"https\"]; ok && len(v) > 0 {\n\t\t\tarray = strings.Split(v, \",\")\n\t\t} else {\n\t\t\tarray = strings.Split(s.config.HTTPSAddr, \",\")\n\t\t}\n\t\tfor _, v := range array {\n\t\t\tif len(v) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tfd        = 0\n\t\t\t\titemFunc  = v\n\t\t\t\taddrAndFd = strings.Split(v, \"#\")\n\t\t\t)\n\t\t\tif len(addrAndFd) > 1 {\n\t\t\t\titemFunc = addrAndFd[0]\n\t\t\t\t// The Windows OS does not support socket file descriptor passing\n\t\t\t\t// from parent process.\n\t\t\t\tif runtime.GOOS != \"windows\" {\n\t\t\t\t\tfd = gconv.Int(addrAndFd[1])\n\t\t\t\t}\n\t\t\t}\n\t\t\tif fd > 0 {\n\t\t\t\ts.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))\n\t\t\t} else {\n\t\t\t\ts.servers = append(s.servers, s.newGracefulServer(itemFunc, 0))\n\t\t\t}\n\t\t\ts.servers[len(s.servers)-1].SetIsHttps(true)\n\t\t}\n\t}\n\t// HTTP\n\tif !httpsEnabled && len(s.config.Address) == 0 {\n\t\ts.config.Address = defaultHttpAddr\n\t}\n\tvar array []string\n\tif v, ok := fdMap[\"http\"]; ok && len(v) > 0 {\n\t\tarray = gstr.SplitAndTrim(v, \",\")\n\t} else {\n\t\tarray = gstr.SplitAndTrim(s.config.Address, \",\")\n\t}\n\tfor _, v := range array {\n\t\tif len(v) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tvar (\n\t\t\tfd        = 0\n\t\t\titemFunc  = v\n\t\t\taddrAndFd = strings.Split(v, \"#\")\n\t\t)\n\t\tif len(addrAndFd) > 1 {\n\t\t\titemFunc = addrAndFd[0]\n\t\t\t// The Window OS does not support socket file descriptor passing\n\t\t\t// from the parent process.\n\t\t\tif runtime.GOOS != \"windows\" {\n\t\t\t\tfd = gconv.Int(addrAndFd[1])\n\t\t\t}\n\t\t}\n\t\tif fd > 0 {\n\t\t\ts.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))\n\t\t} else {\n\t\t\ts.servers = append(s.servers, s.newGracefulServer(itemFunc, 0))\n\t\t}\n\t}\n\t// Start listening asynchronously.\n\tserverRunning.Add(1)\n\tvar wg = &sync.WaitGroup{}\n\tfor _, gs := range s.servers {\n\t\twg.Add(1)\n\t\tgo s.startGracefulServer(ctx, wg, gs)\n\t}\n\twg.Wait()\n}\n\nfunc (s *Server) startGracefulServer(ctx context.Context, wg *sync.WaitGroup, server *graceful.Server) {\n\ts.serverCount.Add(1)\n\tvar err error\n\t// Create listener.\n\tif server.IsHttps() {\n\t\terr = server.CreateListenerTLS(\n\t\t\ts.config.HTTPSCertPath, s.config.HTTPSKeyPath, s.config.TLSConfig,\n\t\t)\n\t} else {\n\t\terr = server.CreateListener()\n\t}\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\twg.Done()\n\t// Start listening and serving in blocking way.\n\terr = server.Serve(ctx)\n\t// The process exits if the server is closed with none closing error.\n\tif err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\t// If all the underlying servers' shutdown, the process exits.\n\tif s.serverCount.Add(-1) < 1 {\n\t\ts.closeChan <- struct{}{}\n\t\tif serverRunning.Add(-1) < 1 {\n\t\t\tserverMapping.Remove(s.instance)\n\t\t\tallShutdownChan <- struct{}{}\n\t\t}\n\t}\n}\n\n// Status retrieves and returns the server status.\nfunc (s *Server) Status() ServerStatus {\n\tif serverRunning.Val() == 0 {\n\t\treturn ServerStatusStopped\n\t}\n\t// If any underlying server is running, the server status is running.\n\tfor _, v := range s.servers {\n\t\tif v.Status() == ServerStatusRunning {\n\t\t\treturn ServerStatusRunning\n\t\t}\n\t}\n\treturn ServerStatusStopped\n}\n\n// getListenerFdMap retrieves and returns the socket file descriptors.\n// The key of the returned map is \"http\" and \"https\".\nfunc (s *Server) getListenerFdMap() map[string]string {\n\tm := map[string]string{\n\t\t\"https\": \"\",\n\t\t\"http\":  \"\",\n\t}\n\tfor _, v := range s.servers {\n\t\tstr := v.GetAddress() + \"#\" + gconv.String(v.Fd()) + \",\"\n\t\tif v.IsHttps() {\n\t\t\tif len(m[\"https\"]) > 0 {\n\t\t\t\tm[\"https\"] += \",\"\n\t\t\t}\n\t\t\tm[\"https\"] += str\n\t\t} else {\n\t\t\tif len(m[\"http\"]) > 0 {\n\t\t\t\tm[\"http\"] += \",\"\n\t\t\t}\n\t\t\tm[\"http\"] += str\n\t\t}\n\t}\n\treturn m\n}\n\n// GetListenedPort returns a port currently listened to by the server.\n// It prioritizes the HTTP port if both HTTP and HTTPS are enabled.\nfunc (s *Server) GetListenedPort() int {\n\tfor _, server := range s.servers {\n\t\tif !server.IsHttps() {\n\t\t\treturn server.GetListenedPort()\n\t\t}\n\t}\n\tfor _, server := range s.servers {\n\t\tif server.IsHttps() {\n\t\t\treturn server.GetListenedPort()\n\t\t}\n\t}\n\treturn -1\n}\n\n// GetListenedHTTPSPort retrieves and returns one port which is listened using TLS by current server.\nfunc (s *Server) GetListenedHTTPSPort() int {\n\tfor _, server := range s.servers {\n\t\tif server.IsHttps() {\n\t\t\treturn server.GetListenedPort()\n\t\t}\n\t}\n\treturn -1\n}\n\n// GetListenedPorts retrieves and returns the ports which are listened by current server.\nfunc (s *Server) GetListenedPorts() []int {\n\tports := make([]int, 0)\n\tfor _, server := range s.servers {\n\t\tports = append(ports, server.GetListenedPort())\n\t}\n\treturn ports\n}\n\n// GetListenedAddress retrieves and returns the address string which are listened by current server.\nfunc (s *Server) GetListenedAddress() string {\n\tif !gstr.Contains(s.config.Address, FreePortAddress) {\n\t\treturn s.config.Address\n\t}\n\tvar (\n\t\taddress       = s.config.Address\n\t\tlistenedPorts = s.GetListenedPorts()\n\t)\n\tfor _, listenedPort := range listenedPorts {\n\t\taddress = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort), 1)\n\t}\n\treturn address\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_admin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n)\n\n// utilAdmin is the controller for administration.\ntype utilAdmin struct{}\n\n// Index shows the administration page.\nfunc (p *utilAdmin) Index(r *Request) {\n\tdata := map[string]any{\n\t\t\"pid\":  gproc.Pid(),\n\t\t\"path\": gfile.SelfPath(),\n\t\t\"uri\":  strings.TrimRight(r.URL.Path, \"/\"),\n\t}\n\tbuffer, _ := gview.ParseContent(r.Context(), `\n            <html>\n            <head>\n                <title>GoFrame Web Server Admin</title>\n            </head>\n            <body>\n                <p>Pid: {{.pid}}</p>\n                <p>File Path: {{.path}}</p>\n                <p>\n<a href=\"{{$.uri}}/restart\">Restart</a>\nplease make sure it is running using standalone binary not from IDE or \"go run\"\n</p>\n                <p>\n<a href=\"{{$.uri}}/shutdown\">Shutdown</a>\ngraceful shutdown the server\n</p>\n            </body>\n            </html>\n    `, data)\n\tr.Response.Write(buffer)\n}\n\n// Restart restarts all the servers in the process.\nfunc (p *utilAdmin) Restart(r *Request) {\n\tvar (\n\t\tctx = r.Context()\n\t\terr error\n\t)\n\t// Custom start binary path when this process exits.\n\tpath := r.GetQuery(\"newExeFilePath\").String()\n\tif path == \"\" {\n\t\tpath = os.Args[0]\n\t}\n\tif err = RestartAllServer(ctx, path); err == nil {\n\t\tr.Response.WriteExit(\"server restarted\")\n\t} else {\n\t\tr.Response.WriteExit(err.Error())\n\t}\n}\n\n// Shutdown shuts down all the servers.\nfunc (p *utilAdmin) Shutdown(r *Request) {\n\tgtimer.SetTimeout(r.Context(), time.Second, func(ctx context.Context) {\n\t\t// It shuts down the server after 1 second, which is not triggered by system signal,\n\t\t// to ensure the response successfully to the client.\n\t\t_ = r.Server.Shutdown()\n\t})\n\tr.Response.WriteExit(\"server shutdown\")\n}\n\n// EnableAdmin enables the administration feature for the process.\n// The optional parameter `pattern` specifies the URI for the administration page.\nfunc (s *Server) EnableAdmin(pattern ...string) {\n\tp := \"/debug/admin\"\n\tif len(pattern) > 0 {\n\t\tp = pattern[0]\n\t}\n\ts.BindObject(p, &utilAdmin{})\n}\n\n// Shutdown shuts the current server.\nfunc (s *Server) Shutdown() error {\n\tvar ctx = context.TODO()\n\t// Remove plugins.\n\tif len(s.plugins) > 0 {\n\t\tfor _, p := range s.plugins {\n\t\t\ts.Logger().Printf(ctx, `remove plugin: %s`, p.Name())\n\t\t\tif err := p.Remove(); err != nil {\n\t\t\t\ts.Logger().Errorf(ctx, \"%+v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\ts.doServiceDeregister()\n\t// Only shut down current servers.\n\t// It may have multiple underlying http servers.\n\tfor _, v := range s.servers {\n\t\tv.Shutdown(ctx)\n\t}\n\ts.Logger().Infof(ctx, \"pid[%d]: all servers shutdown\", gproc.Pid())\n\treturn nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_admin_process.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\t// Allow executing management command after server starts after this interval in milliseconds.\n\tadminActionIntervalLimit = 2000\n\tadminActionNone          = 0\n\tadminActionRestarting    = 1\n\tadminActionShuttingDown  = 2\n\tadminActionReloadEnvKey  = \"GF_SERVER_RELOAD\"\n\tadminActionRestartEnvKey = \"GF_SERVER_RESTART\"\n\tadminGProcCommGroup      = \"GF_GPROC_HTTP_SERVER\"\n)\n\nvar (\n\t// serverActionLocker is the locker for server administration operations.\n\tserverActionLocker sync.Mutex\n\n\t// serverActionLastTime is timestamp in milliseconds of last administration operation.\n\tserverActionLastTime = gtype.NewInt64(gtime.TimestampMilli())\n\n\t// serverProcessStatus is the server status for operation of current process.\n\tserverProcessStatus = gtype.NewInt()\n)\n\n// RestartAllServer restarts all the servers of the process gracefully.\n// The optional parameter `newExeFilePath` specifies the new binary file for creating process.\nfunc RestartAllServer(ctx context.Context, newExeFilePath string) error {\n\tif !gracefulEnabled {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\"graceful reload feature is disabled\",\n\t\t)\n\t}\n\tserverActionLocker.Lock()\n\tdefer serverActionLocker.Unlock()\n\tif err := checkProcessStatus(); err != nil {\n\t\treturn err\n\t}\n\tif err := checkActionFrequency(); err != nil {\n\t\treturn err\n\t}\n\treturn restartWebServers(ctx, nil, newExeFilePath)\n}\n\n// ShutdownAllServer shuts down all servers of current process gracefully.\nfunc ShutdownAllServer(ctx context.Context) error {\n\tserverActionLocker.Lock()\n\tdefer serverActionLocker.Unlock()\n\tif err := checkProcessStatus(); err != nil {\n\t\treturn err\n\t}\n\tif err := checkActionFrequency(); err != nil {\n\t\treturn err\n\t}\n\tshutdownWebServersGracefully(ctx, nil)\n\treturn nil\n}\n\n// checkProcessStatus checks the server status of current process.\nfunc checkProcessStatus() error {\n\tstatus := serverProcessStatus.Val()\n\tif status > 0 {\n\t\tswitch status {\n\t\tcase adminActionRestarting:\n\t\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"server is restarting\")\n\n\t\tcase adminActionShuttingDown:\n\t\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"server is shutting down\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// checkActionFrequency checks the operation frequency.\n// It returns error if it is too frequency.\nfunc checkActionFrequency() error {\n\tinterval := gtime.TimestampMilli() - serverActionLastTime.Val()\n\tif interval < adminActionIntervalLimit {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\"too frequent action, please retry in %d ms\",\n\t\t\tadminActionIntervalLimit-interval,\n\t\t)\n\t}\n\tserverActionLastTime.Set(gtime.TimestampMilli())\n\treturn nil\n}\n\n// forkReloadProcess creates a new child process and copies the fd to child process.\nfunc forkReloadProcess(ctx context.Context, newExeFilePath ...string) error {\n\tvar (\n\t\tbinaryPath = os.Args[0]\n\t)\n\tif len(newExeFilePath) > 0 && newExeFilePath[0] != \"\" {\n\t\tbinaryPath = newExeFilePath[0]\n\t}\n\tif !gfile.Exists(binaryPath) {\n\t\treturn gerror.Newf(`binary file path \"%s\" does not exist`, binaryPath)\n\t}\n\tvar (\n\t\tp   = gproc.NewProcess(binaryPath, os.Args[1:], os.Environ())\n\t\tsfm = getServerFdMap()\n\t)\n\tfor name, m := range sfm {\n\t\tfor fdk, fdv := range m {\n\t\t\tif len(fdv) > 0 {\n\t\t\t\ts := \"\"\n\t\t\t\tfor _, item := range gstr.SplitAndTrim(fdv, \",\") {\n\t\t\t\t\tarray := strings.Split(item, \"#\")\n\t\t\t\t\tfd := uintptr(gconv.Uint(array[1]))\n\t\t\t\t\tif fd > 0 {\n\t\t\t\t\t\ts += fmt.Sprintf(\"%s#%d,\", array[0], 3+len(p.ExtraFiles))\n\t\t\t\t\t\tp.ExtraFiles = append(p.ExtraFiles, os.NewFile(fd, \"\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts += fmt.Sprintf(\"%s#%d,\", array[0], 0)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsfm[name][fdk] = strings.TrimRight(s, \",\")\n\t\t\t}\n\t\t}\n\t}\n\tbuffer, _ := gjson.Encode(sfm)\n\tp.Env = append(p.Env, adminActionReloadEnvKey+\"=\"+string(buffer))\n\tif _, err := p.Start(ctx); err != nil {\n\t\tintlog.Errorf(\n\t\t\tctx,\n\t\t\t\"%d: fork process failed, error: %s, %s\",\n\t\t\tgproc.Pid(), err.Error(), string(buffer),\n\t\t)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// forkRestartProcess creates a new server process.\nfunc forkRestartProcess(ctx context.Context, newExeFilePath ...string) error {\n\tvar (\n\t\tpath = os.Args[0]\n\t)\n\tif len(newExeFilePath) > 0 && newExeFilePath[0] != \"\" {\n\t\tpath = newExeFilePath[0]\n\t}\n\tif err := os.Unsetenv(adminActionReloadEnvKey); err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t}\n\tenv := os.Environ()\n\tenv = append(env, adminActionRestartEnvKey+\"=1\")\n\tp := gproc.NewProcess(path, os.Args[1:], env)\n\tif _, err := p.Start(ctx); err != nil {\n\t\tglog.Errorf(\n\t\t\tctx,\n\t\t\t`%d: fork process failed, error:%s, are you running using \"go run\"?`,\n\t\t\tgproc.Pid(), err.Error(),\n\t\t)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// getServerFdMap returns all the servers name to file descriptor mapping as map.\nfunc getServerFdMap() map[string]listenerFdMap {\n\tsfm := make(map[string]listenerFdMap)\n\tserverMapping.RLockFunc(func(m map[string]*Server) {\n\t\tfor k, v := range m {\n\t\t\tsfm[k] = v.getListenerFdMap()\n\t\t}\n\t})\n\treturn sfm\n}\n\n// bufferToServerFdMap converts binary content to fd map.\nfunc bufferToServerFdMap(buffer []byte) map[string]listenerFdMap {\n\tsfm := make(map[string]listenerFdMap)\n\tif len(buffer) > 0 {\n\t\tj, _ := gjson.LoadContent(buffer)\n\t\tfor k := range j.Var().Map() {\n\t\t\tm := make(map[string]string)\n\t\t\tfor mapKey, mapValue := range j.Get(k).MapStrStr() {\n\t\t\t\tm[mapKey] = mapValue\n\t\t\t}\n\t\t\tsfm[k] = m\n\t\t}\n\t}\n\treturn sfm\n}\n\n// restartWebServers restarts all servers.\nfunc restartWebServers(ctx context.Context, signal os.Signal, newExeFilePath string) error {\n\tserverProcessStatus.Set(adminActionRestarting)\n\tif runtime.GOOS == \"windows\" {\n\t\tif signal != nil {\n\t\t\t// Controlled by signal.\n\t\t\tforceCloseWebServers(ctx)\n\t\t\tif err := forkRestartProcess(ctx, newExeFilePath); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\t// Controlled by web page.\n\t\t// It should ensure the response wrote to client and then close all servers gracefully.\n\t\tgtimer.SetTimeout(ctx, time.Second, func(ctx context.Context) {\n\t\t\tforceCloseWebServers(ctx)\n\t\t\tif err := forkRestartProcess(ctx, newExeFilePath); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t})\n\t\treturn nil\n\t}\n\tif err := forkReloadProcess(ctx, newExeFilePath); err != nil {\n\t\tglog.Printf(ctx, \"%d: server restarts failed\", gproc.Pid())\n\t\tserverProcessStatus.Set(adminActionNone)\n\t\treturn err\n\t} else {\n\t\tif signal != nil {\n\t\t\tglog.Printf(ctx, \"%d: server restarting by signal: %s\", gproc.Pid(), signal)\n\t\t} else {\n\t\t\tglog.Printf(ctx, \"%d: server restarting by web admin\", gproc.Pid())\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// shutdownWebServersGracefully gracefully shuts down all servers.\nfunc shutdownWebServersGracefully(ctx context.Context, signal os.Signal) {\n\tserverProcessStatus.Set(adminActionShuttingDown)\n\tif signal != nil {\n\t\tglog.Printf(\n\t\t\tctx,\n\t\t\t\"%d: server gracefully shutting down by signal: %s\",\n\t\t\tgproc.Pid(), signal.String(),\n\t\t)\n\t} else {\n\t\tglog.Printf(ctx, \"pid[%d]: server gracefully shutting down by api\", gproc.Pid())\n\t}\n\tserverMapping.RLockFunc(func(m map[string]*Server) {\n\t\tfor _, v := range m {\n\t\t\tv.doServiceDeregister()\n\t\t\tfor _, s := range v.servers {\n\t\t\t\ts.Shutdown(ctx)\n\t\t\t}\n\t\t}\n\t})\n}\n\n// forceCloseWebServers forced shuts down all servers.\nfunc forceCloseWebServers(ctx context.Context) {\n\tserverMapping.RLockFunc(func(m map[string]*Server) {\n\t\tfor _, v := range m {\n\t\t\tfor _, s := range v.servers {\n\t\t\t\ts.Close(ctx)\n\t\t\t}\n\t\t}\n\t})\n}\n\n// handleProcessMessage receives and handles the message from processes,\n// which are commonly used for graceful reloading feature.\nfunc handleProcessMessage() {\n\tvar (\n\t\tctx = context.TODO()\n\t)\n\tfor {\n\t\tif msg := gproc.Receive(adminGProcCommGroup); msg != nil {\n\t\t\tif bytes.EqualFold(msg.Data, []byte(\"exit\")) {\n\t\t\t\tintlog.Printf(ctx, \"%d: process message: exit\", gproc.Pid())\n\t\t\t\tshutdownWebServersGracefully(ctx, nil)\n\t\t\t\tallShutdownChan <- struct{}{}\n\t\t\t\tintlog.Printf(ctx, \"%d: process message: exit done\", gproc.Pid())\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_admin_unix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build !windows\n// +build !windows\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"syscall\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n)\n\n// handleProcessSignal handles all signals from system in blocking way.\nfunc handleProcessSignal() {\n\tvar ctx = context.TODO()\n\tgproc.AddSigHandlerShutdown(func(sig os.Signal) {\n\t\tshutdownWebServersGracefully(ctx, sig)\n\t})\n\tgproc.AddSigHandler(func(sig os.Signal) {\n\t\t// If the graceful restart feature is not enabled,\n\t\t// it does nothing except printing a warning log.\n\t\tif !gracefulEnabled {\n\t\t\tglog.Warning(ctx, \"graceful reload feature is disabled\")\n\t\t\treturn\n\t\t}\n\t\tif err := restartWebServers(ctx, sig, \"\"); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}, syscall.SIGUSR1)\n\n\tgproc.Listen()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_admin_windows.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build windows\n// +build windows\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/os/gproc\"\n)\n\n// handleProcessSignal handles all signals from system in blocking way.\nfunc handleProcessSignal() {\n\tvar ctx = context.TODO()\n\tgproc.AddSigHandlerShutdown(func(sig os.Signal) {\n\t\tshutdownWebServersGracefully(ctx, sig)\n\t})\n\n\tgproc.Listen()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nconst (\n\tdefaultHttpAddr  = \":80\"  // Default listening port for HTTP.\n\tdefaultHttpsAddr = \":443\" // Default listening port for HTTPS.\n\n)\n\nconst (\n\tUriTypeDefault  = iota // Method names to the URI converting type, which converts name to its lower case and joins the words using char '-'.\n\tUriTypeFullName        // Method names to the URI converting type, which does not convert to the method name.\n\tUriTypeAllLower        // Method names to the URI converting type, which converts name to its lower case.\n\tUriTypeCamel           // Method names to the URI converting type, which converts name to its camel case.\n)\n\n// ServerConfig is the HTTP Server configuration manager.\ntype ServerConfig struct {\n\t// ======================================================================================================\n\t// Basic.\n\t// ======================================================================================================\n\n\t// Service name, which is for service registry and discovery.\n\tName string `json:\"name\"`\n\n\t// Address specifies the server listening address like \"port\" or \":port\",\n\t// multiple addresses joined using ','.\n\tAddress string `json:\"address\"`\n\n\t// HTTPSAddr specifies the HTTPS addresses, multiple addresses joined using char ','.\n\tHTTPSAddr string `json:\"httpsAddr\"`\n\n\t// Listeners specifies the custom listeners.\n\tListeners []net.Listener `json:\"listeners\"`\n\n\t// Endpoints are custom endpoints for service register, it uses Address if empty.\n\tEndpoints []string `json:\"endpoints\"`\n\n\t// HTTPSCertPath specifies certification file path for HTTPS service.\n\tHTTPSCertPath string `json:\"httpsCertPath\"`\n\n\t// HTTPSKeyPath specifies the key file path for HTTPS service.\n\tHTTPSKeyPath string `json:\"httpsKeyPath\"`\n\n\t// TLSConfig optionally provides a TLS configuration for use\n\t// by ServeTLS and ListenAndServeTLS. Note that this value is\n\t// cloned by ServeTLS and ListenAndServeTLS, so it's not\n\t// possible to modify the configuration with methods like\n\t// tls.Config.SetSessionTicketKeys. To use\n\t// SetSessionTicketKeys, use Server.Serve with a TLS Listener\n\t// instead.\n\tTLSConfig *tls.Config `json:\"tlsConfig\"`\n\n\t// Handler the handler for HTTP request.\n\tHandler func(w http.ResponseWriter, r *http.Request) `json:\"-\"`\n\n\t// ReadTimeout is the maximum duration for reading the entire\n\t// request, including the body.\n\t//\n\t// Because ReadTimeout does not let Handlers make per-request\n\t// decisions on each request body's acceptable deadline or\n\t// upload rate, most users will prefer to use\n\t// ReadHeaderTimeout. It is valid to use them both.\n\tReadTimeout time.Duration `json:\"readTimeout\"`\n\n\t// WriteTimeout is the maximum duration before timing out\n\t// writes of the response. It is reset whenever a new\n\t// request's header is read. Like ReadTimeout, it does not\n\t// let Handlers make decisions on a per-request basis.\n\tWriteTimeout time.Duration `json:\"writeTimeout\"`\n\n\t// IdleTimeout is the maximum amount of time to wait for the\n\t// next request when keep-alive are enabled. If IdleTimeout\n\t// is zero, the value of ReadTimeout is used. If both are\n\t// zero, there is no timeout.\n\tIdleTimeout time.Duration `json:\"idleTimeout\"`\n\n\t// MaxHeaderBytes controls the maximum number of bytes the\n\t// server will read parsing the request header's keys and\n\t// values, including the request line. It does not limit the\n\t// size of the request body.\n\t//\n\t// It can be configured in configuration file using string like: 1m, 10m, 500kb etc.\n\t// It's 10240 bytes in default.\n\tMaxHeaderBytes int `json:\"maxHeaderBytes\"`\n\n\t// KeepAlive enables HTTP keep-alive.\n\tKeepAlive bool `json:\"keepAlive\"`\n\n\t// ServerAgent specifies the server agent information, which is wrote to\n\t// HTTP response header as \"Server\".\n\tServerAgent string `json:\"serverAgent\"`\n\n\t// View specifies the default template view object for the server.\n\tView *gview.View `json:\"view\"`\n\n\t// ======================================================================================================\n\t// Static.\n\t// ======================================================================================================\n\n\t// Rewrites specifies the URI rewrite rules map.\n\tRewrites map[string]string `json:\"rewrites\"`\n\n\t// IndexFiles specifies the index files for static folder.\n\tIndexFiles []string `json:\"indexFiles\"`\n\n\t// IndexFolder specifies if listing sub-files when requesting folder.\n\t// The server responses HTTP status code 403 if it is false.\n\tIndexFolder bool `json:\"indexFolder\"`\n\n\t// ServerRoot specifies the root directory for static service.\n\tServerRoot string `json:\"serverRoot\"`\n\n\t// SearchPaths specifies additional searching directories for static service.\n\tSearchPaths []string `json:\"searchPaths\"`\n\n\t// StaticPaths specifies URI to directory mapping array.\n\tStaticPaths []staticPathItem `json:\"staticPaths\"`\n\n\t// FileServerEnabled is the global switch for static service.\n\t// It is automatically set enabled if any static path is set.\n\tFileServerEnabled bool `json:\"fileServerEnabled\"`\n\n\t// ======================================================================================================\n\t// Cookie.\n\t// ======================================================================================================\n\n\t// CookieMaxAge specifies the max TTL for cookie items.\n\tCookieMaxAge time.Duration `json:\"cookieMaxAge\"`\n\n\t// CookiePath specifies cookie path.\n\t// It also affects the default storage for session id.\n\tCookiePath string `json:\"cookiePath\"`\n\n\t// CookieDomain specifies cookie domain.\n\t// It also affects the default storage for session id.\n\tCookieDomain string `json:\"cookieDomain\"`\n\n\t// CookieSameSite specifies cookie SameSite property.\n\t// It also affects the default storage for session id.\n\tCookieSameSite string `json:\"cookieSameSite\"`\n\n\t// CookieSameSite specifies cookie Secure property.\n\t// It also affects the default storage for session id.\n\tCookieSecure bool `json:\"cookieSecure\"`\n\n\t// CookieSameSite specifies cookie HttpOnly property.\n\t// It also affects the default storage for session id.\n\tCookieHttpOnly bool `json:\"cookieHttpOnly\"`\n\n\t// ======================================================================================================\n\t// Session.\n\t// ======================================================================================================\n\n\t// SessionIdName specifies the session id name.\n\tSessionIdName string `json:\"sessionIdName\"`\n\n\t// SessionMaxAge specifies max TTL for session items.\n\tSessionMaxAge time.Duration `json:\"sessionMaxAge\"`\n\n\t// SessionPath specifies the session storage directory path for storing session files.\n\t// It only makes sense if the session storage is type of file storage.\n\tSessionPath string `json:\"sessionPath\"`\n\n\t// SessionStorage specifies the session storage.\n\tSessionStorage gsession.Storage `json:\"sessionStorage\"`\n\n\t// SessionCookieMaxAge specifies the cookie ttl for session id.\n\t// If it is set 0, it means it expires along with browser session.\n\tSessionCookieMaxAge time.Duration `json:\"sessionCookieMaxAge\"`\n\n\t// SessionCookieOutput specifies whether automatic outputting session id to cookie.\n\tSessionCookieOutput bool `json:\"sessionCookieOutput\"`\n\n\t// ======================================================================================================\n\t// Logging.\n\t// ======================================================================================================\n\n\tLogger           *glog.Logger `json:\"logger\"`           // Logger specifies the logger for server.\n\tLogPath          string       `json:\"logPath\"`          // LogPath specifies the directory for storing logging files.\n\tLogLevel         string       `json:\"logLevel\"`         // LogLevel specifies the logging level for logger.\n\tLogStdout        bool         `json:\"logStdout\"`        // LogStdout specifies whether printing logging content to stdout.\n\tErrorStack       bool         `json:\"errorStack\"`       // ErrorStack specifies whether logging stack information when error.\n\tErrorLogEnabled  bool         `json:\"errorLogEnabled\"`  // ErrorLogEnabled enables error logging content to files.\n\tErrorLogPattern  string       `json:\"errorLogPattern\"`  // ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log\n\tAccessLogEnabled bool         `json:\"accessLogEnabled\"` // AccessLogEnabled enables access logging content to files.\n\tAccessLogPattern string       `json:\"accessLogPattern\"` // AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log\n\n\t// ======================================================================================================\n\t// PProf.\n\t// ======================================================================================================\n\n\tPProfEnabled bool   `json:\"pprofEnabled\"` // PProfEnabled enables PProf feature.\n\tPProfPattern string `json:\"pprofPattern\"` // PProfPattern specifies the PProf service pattern for router.\n\n\t// ======================================================================================================\n\t// API & Swagger.\n\t// ======================================================================================================\n\n\tOpenApiPath       string `json:\"openapiPath\"`       // OpenApiPath specifies the OpenApi specification file path.\n\tSwaggerPath       string `json:\"swaggerPath\"`       // SwaggerPath specifies the swagger UI path for route registering.\n\tSwaggerUITemplate string `json:\"swaggerUITemplate\"` // SwaggerUITemplate specifies the swagger UI custom template\n\n\t// ======================================================================================================\n\t// Graceful reload & shutdown.\n\t// ======================================================================================================\n\n\t// Graceful enables graceful reload feature for all servers of the process.\n\tGraceful bool `json:\"graceful\"`\n\n\t// GracefulTimeout set the maximum survival time (seconds) of the parent process.\n\tGracefulTimeout int `json:\"gracefulTimeout\"`\n\n\t// GracefulShutdownTimeout set the maximum survival time (seconds) before stopping the server.\n\tGracefulShutdownTimeout int `json:\"gracefulShutdownTimeout\"`\n\n\t// ======================================================================================================\n\t// Other.\n\t// ======================================================================================================\n\n\t// ClientMaxBodySize specifies the max body size limit in bytes for client request.\n\t// It can be configured in configuration file using string like: 1m, 10m, 500kb etc.\n\t// It's `8MB` in default.\n\tClientMaxBodySize int64 `json:\"clientMaxBodySize\"`\n\n\t// FormParsingMemory specifies max memory buffer size in bytes which can be used for\n\t// parsing multimedia form.\n\t// It can be configured in configuration file using string like: 1m, 10m, 500kb etc.\n\t// It's 1MB in default.\n\tFormParsingMemory int64 `json:\"formParsingMemory\"`\n\n\t// NameToUriType specifies the type for converting struct method name to URI when\n\t// registering routes.\n\tNameToUriType int `json:\"nameToUriType\"`\n\n\t// RouteOverWrite allows to overwrite the route if duplicated.\n\tRouteOverWrite bool `json:\"routeOverWrite\"`\n\n\t// DumpRouterMap specifies whether automatically dumps router map when server starts.\n\tDumpRouterMap bool `json:\"dumpRouterMap\"`\n}\n\n// NewConfig creates and returns a ServerConfig object with default configurations.\n// Note that, do not define this default configuration to local package variable, as there are\n// some pointer attributes that may be shared in different servers.\nfunc NewConfig() ServerConfig {\n\treturn ServerConfig{\n\t\tName:                    DefaultServerName,\n\t\tAddress:                 \":0\",\n\t\tHTTPSAddr:               \"\",\n\t\tListeners:               nil,\n\t\tHandler:                 nil,\n\t\tReadTimeout:             60 * time.Second,\n\t\tWriteTimeout:            0, // No timeout.\n\t\tIdleTimeout:             60 * time.Second,\n\t\tMaxHeaderBytes:          10240, // 10KB\n\t\tKeepAlive:               true,\n\t\tIndexFiles:              []string{\"index.html\", \"index.htm\"},\n\t\tIndexFolder:             false,\n\t\tServerAgent:             \"GoFrame HTTP Server\",\n\t\tServerRoot:              \"\",\n\t\tStaticPaths:             make([]staticPathItem, 0),\n\t\tFileServerEnabled:       false,\n\t\tCookieMaxAge:            time.Hour * 24 * 365,\n\t\tCookiePath:              \"/\",\n\t\tCookieDomain:            \"\",\n\t\tSessionIdName:           \"gfsessionid\",\n\t\tSessionPath:             gsession.DefaultStorageFilePath,\n\t\tSessionMaxAge:           time.Hour * 24,\n\t\tSessionCookieOutput:     true,\n\t\tSessionCookieMaxAge:     time.Hour * 24,\n\t\tLogger:                  glog.New(),\n\t\tLogLevel:                \"all\",\n\t\tLogStdout:               true,\n\t\tErrorStack:              true,\n\t\tErrorLogEnabled:         true,\n\t\tErrorLogPattern:         \"error-{Ymd}.log\",\n\t\tAccessLogEnabled:        false,\n\t\tAccessLogPattern:        \"access-{Ymd}.log\",\n\t\tDumpRouterMap:           true,\n\t\tClientMaxBodySize:       8 * 1024 * 1024, // 8MB\n\t\tFormParsingMemory:       1024 * 1024,     // 1MB\n\t\tRewrites:                make(map[string]string),\n\t\tGraceful:                false,\n\t\tGracefulTimeout:         2, // seconds\n\t\tGracefulShutdownTimeout: 5, // seconds\n\t}\n}\n\n// ConfigFromMap creates and returns a ServerConfig object with given map and\n// default configuration object.\nfunc ConfigFromMap(m map[string]any) (ServerConfig, error) {\n\tconfig := NewConfig()\n\tif err := gconv.Struct(m, &config); err != nil {\n\t\treturn config, err\n\t}\n\treturn config, nil\n}\n\n// SetConfigWithMap sets the configuration for the server using map.\nfunc (s *Server) SetConfigWithMap(m map[string]any) error {\n\t// The m now is a shallow copy of m.\n\t// Any changes to m does not affect the original one.\n\t// A little tricky, isn't it?\n\tm = gutil.MapCopy(m)\n\t// Allow setting the size configuration items using string size like:\n\t// 1m, 100mb, 512kb, etc.\n\tif k, v := gutil.MapPossibleItemByKey(m, \"MaxHeaderBytes\"); k != \"\" {\n\t\tm[k] = gfile.StrToSize(gconv.String(v))\n\t}\n\tif k, v := gutil.MapPossibleItemByKey(m, \"ClientMaxBodySize\"); k != \"\" {\n\t\tm[k] = gfile.StrToSize(gconv.String(v))\n\t}\n\tif k, v := gutil.MapPossibleItemByKey(m, \"FormParsingMemory\"); k != \"\" {\n\t\tm[k] = gfile.StrToSize(gconv.String(v))\n\t}\n\tif _, v := gutil.MapPossibleItemByKey(m, \"Logger\"); v == nil {\n\t\tintlog.Printf(context.TODO(), \"SetConfigWithMap: set Logger nil\")\n\t}\n\t// Update the current configuration object.\n\t// It only updates the configured keys not all the object.\n\tif err := gconv.Struct(m, &s.config); err != nil {\n\t\treturn err\n\t}\n\treturn s.SetConfig(s.config)\n}\n\n// SetConfig sets the configuration for the server.\nfunc (s *Server) SetConfig(c ServerConfig) error {\n\ts.config = c\n\t// Automatically add ':' prefix for address if it is missed.\n\tif s.config.Address != \"\" && !gstr.Contains(s.config.Address, \":\") {\n\t\ts.config.Address = \":\" + s.config.Address\n\t}\n\t// Static files root.\n\tif c.ServerRoot != \"\" {\n\t\ts.SetServerRoot(c.ServerRoot)\n\t}\n\tif len(c.SearchPaths) > 0 {\n\t\tpaths := c.SearchPaths\n\t\tc.SearchPaths = []string{}\n\t\tfor _, v := range paths {\n\t\t\ts.AddSearchPath(v)\n\t\t}\n\t}\n\t// HTTPS.\n\tif c.TLSConfig == nil && c.HTTPSCertPath != \"\" {\n\t\ts.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath)\n\t}\n\t// Logging.\n\tif s.config.LogPath != \"\" && s.config.LogPath != s.config.Logger.GetPath() {\n\t\tif err := s.config.Logger.SetPath(s.config.LogPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif s.config.Logger != nil {\n\t\tif err := s.config.Logger.SetLevelStr(s.config.LogLevel); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t}\n\tgracefulEnabled = c.Graceful\n\tintlog.Printf(context.TODO(), \"SetConfig: %+v\", s.config)\n\treturn nil\n}\n\n// SetAddr sets the listening address for the server.\n// The address is like:\n// SetAddr(\":80\")\n// SetAddr(\"0.0.0.0:80\")\n// SetAddr(\"127.0.0.1:80\")\n// SetAddr(\"180.18.99.10:80\")\n// etc.\nfunc (s *Server) SetAddr(address string) {\n\ts.config.Address = address\n}\n\n// SetPort sets the listening ports for the server.\n// It uses random port if the port is 0.\n// The listening ports can be multiple like: SetPort(80, 8080).\nfunc (s *Server) SetPort(port ...int) {\n\tif len(port) > 0 {\n\t\ts.config.Address = \"\"\n\t\tfor _, v := range port {\n\t\t\tif len(s.config.Address) > 0 {\n\t\t\t\ts.config.Address += \",\"\n\t\t\t}\n\t\t\ts.config.Address += \":\" + strconv.Itoa(v)\n\t\t}\n\t}\n}\n\n// SetHTTPSAddr sets the HTTPS listening ports for the server.\nfunc (s *Server) SetHTTPSAddr(address string) {\n\ts.config.HTTPSAddr = address\n}\n\n// SetHTTPSPort sets the HTTPS listening ports for the server.\n// It uses random port if the port is 0.\n// The listening ports can be multiple like: SetHTTPSPort(443, 500).\nfunc (s *Server) SetHTTPSPort(port ...int) {\n\tif len(port) > 0 {\n\t\ts.config.HTTPSAddr = \"\"\n\t\tfor _, v := range port {\n\t\t\tif len(s.config.HTTPSAddr) > 0 {\n\t\t\t\ts.config.HTTPSAddr += \",\"\n\t\t\t}\n\t\t\ts.config.HTTPSAddr += \":\" + strconv.Itoa(v)\n\t\t}\n\t}\n}\n\n// SetListener set the custom listener for the server.\nfunc (s *Server) SetListener(listeners ...net.Listener) error {\n\tif listeners == nil {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"SetListener failed: listener can not be nil\")\n\t}\n\tif len(listeners) > 0 {\n\t\tports := make([]string, len(listeners))\n\t\tfor k, v := range listeners {\n\t\t\tif v == nil {\n\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, \"SetListener failed: listener can not be nil\")\n\t\t\t}\n\t\t\tports[k] = fmt.Sprintf(\":%d\", (v.Addr().(*net.TCPAddr)).Port)\n\t\t}\n\t\ts.config.Address = strings.Join(ports, \",\")\n\t\ts.config.Listeners = listeners\n\t}\n\treturn nil\n}\n\n// EnableHTTPS enables HTTPS with given certification and key files for the server.\n// The optional parameter `tlsConfig` specifies custom TLS configuration.\nfunc (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config) {\n\tvar ctx = context.TODO()\n\tcertFileRealPath := gfile.RealPath(certFile)\n\tif certFileRealPath == \"\" {\n\t\tcertFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + certFile)\n\t\tif certFileRealPath == \"\" {\n\t\t\tcertFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + certFile)\n\t\t}\n\t}\n\t// Resource.\n\tif certFileRealPath == \"\" && gres.Contains(certFile) {\n\t\tcertFileRealPath = certFile\n\t}\n\tif certFileRealPath == \"\" {\n\t\ts.Logger().Fatalf(ctx, `EnableHTTPS failed: certFile \"%s\" does not exist`, certFile)\n\t}\n\tkeyFileRealPath := gfile.RealPath(keyFile)\n\tif keyFileRealPath == \"\" {\n\t\tkeyFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + keyFile)\n\t\tif keyFileRealPath == \"\" {\n\t\t\tkeyFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + keyFile)\n\t\t}\n\t}\n\t// Resource.\n\tif keyFileRealPath == \"\" && gres.Contains(keyFile) {\n\t\tkeyFileRealPath = keyFile\n\t}\n\tif keyFileRealPath == \"\" {\n\t\ts.Logger().Fatal(ctx, `EnableHTTPS failed: keyFile \"%s\" does not exist`, keyFile)\n\t}\n\ts.config.HTTPSCertPath = certFileRealPath\n\ts.config.HTTPSKeyPath = keyFileRealPath\n\tif len(tlsConfig) > 0 {\n\t\ts.config.TLSConfig = tlsConfig[0]\n\t}\n}\n\n// SetTLSConfig sets custom TLS configuration and enables HTTPS feature for the server.\nfunc (s *Server) SetTLSConfig(tlsConfig *tls.Config) {\n\ts.config.TLSConfig = tlsConfig\n}\n\n// SetReadTimeout sets the ReadTimeout for the server.\nfunc (s *Server) SetReadTimeout(t time.Duration) {\n\ts.config.ReadTimeout = t\n}\n\n// SetWriteTimeout sets the WriteTimeout for the server.\nfunc (s *Server) SetWriteTimeout(t time.Duration) {\n\ts.config.WriteTimeout = t\n}\n\n// SetIdleTimeout sets the IdleTimeout for the server.\nfunc (s *Server) SetIdleTimeout(t time.Duration) {\n\ts.config.IdleTimeout = t\n}\n\n// SetMaxHeaderBytes sets the MaxHeaderBytes for the server.\nfunc (s *Server) SetMaxHeaderBytes(b int) {\n\ts.config.MaxHeaderBytes = b\n}\n\n// SetServerAgent sets the ServerAgent for the server.\nfunc (s *Server) SetServerAgent(agent string) {\n\ts.config.ServerAgent = agent\n}\n\n// SetKeepAlive sets the KeepAlive for the server.\nfunc (s *Server) SetKeepAlive(enabled bool) {\n\ts.config.KeepAlive = enabled\n}\n\n// SetView sets the View for the server.\nfunc (s *Server) SetView(view *gview.View) {\n\ts.config.View = view\n}\n\n// GetName returns the name of the server.\nfunc (s *Server) GetName() string {\n\treturn s.config.Name\n}\n\n// SetName sets the name for the server.\nfunc (s *Server) SetName(name string) {\n\ts.config.Name = name\n}\n\n// SetEndpoints sets the Endpoints for the server.\nfunc (s *Server) SetEndpoints(endpoints []string) {\n\ts.config.Endpoints = endpoints\n}\n\n// SetHandler sets the request handler for server.\nfunc (s *Server) SetHandler(h func(w http.ResponseWriter, r *http.Request)) {\n\ts.config.Handler = h\n}\n\n// GetHandler returns the request handler of the server.\nfunc (s *Server) GetHandler() func(w http.ResponseWriter, r *http.Request) {\n\tif s.config.Handler == nil {\n\t\treturn s.ServeHTTP\n\t}\n\treturn s.config.Handler\n}\n\n// SetRegistrar sets the Registrar for server.\nfunc (s *Server) SetRegistrar(registrar gsvc.Registrar) {\n\ts.registrar = registrar\n}\n\n// GetRegistrar returns the Registrar of server.\nfunc (s *Server) GetRegistrar() gsvc.Registrar {\n\treturn s.registrar\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_api.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// SetSwaggerPath sets the SwaggerPath for server.\nfunc (s *Server) SetSwaggerPath(path string) {\n\ts.config.SwaggerPath = path\n}\n\n// SetSwaggerUITemplate sets the Swagger template for server.\nfunc (s *Server) SetSwaggerUITemplate(swaggerUITemplate string) {\n\ts.config.SwaggerUITemplate = swaggerUITemplate\n}\n\n// SetOpenApiPath sets the OpenApiPath for server.\n// For example: SetOpenApiPath(\"/api.json\")\nfunc (s *Server) SetOpenApiPath(path string) {\n\ts.config.OpenApiPath = path\n}\n\n// GetOpenApiPath returns the `OpenApiPath` configuration of the server.\nfunc (s *Server) GetOpenApiPath() string {\n\treturn s.config.OpenApiPath\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_cookie.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\n// SetCookieMaxAge sets the CookieMaxAge for server.\nfunc (s *Server) SetCookieMaxAge(ttl time.Duration) {\n\ts.config.CookieMaxAge = ttl\n}\n\n// SetCookiePath sets the CookiePath for server.\nfunc (s *Server) SetCookiePath(path string) {\n\ts.config.CookiePath = path\n}\n\n// SetCookieDomain sets the CookieDomain for server.\nfunc (s *Server) SetCookieDomain(domain string) {\n\ts.config.CookieDomain = domain\n}\n\n// GetCookieMaxAge returns the CookieMaxAge of the server.\nfunc (s *Server) GetCookieMaxAge() time.Duration {\n\treturn s.config.CookieMaxAge\n}\n\n// GetCookiePath returns the CookiePath of server.\nfunc (s *Server) GetCookiePath() string {\n\treturn s.config.CookiePath\n}\n\n// GetCookieDomain returns CookieDomain of server.\nfunc (s *Server) GetCookieDomain() string {\n\treturn s.config.CookieDomain\n}\n\n// GetCookieSameSite return CookieSameSite of server.\nfunc (s *Server) GetCookieSameSite() http.SameSite {\n\tswitch s.config.CookieSameSite {\n\tcase \"lax\":\n\t\treturn http.SameSiteLaxMode\n\tcase \"none\":\n\t\treturn http.SameSiteNoneMode\n\tcase \"strict\":\n\t\treturn http.SameSiteStrictMode\n\tdefault:\n\t\treturn http.SameSiteDefaultMode\n\t}\n}\n\nfunc (s *Server) GetCookieSecure() bool {\n\treturn s.config.CookieSecure\n}\n\nfunc (s *Server) GetCookieHttpOnly() bool {\n\treturn s.config.CookieHttpOnly\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_logging.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/os/glog\"\n\n// SetLogPath sets the log path for server.\n// It logs content to file only if the log path is set.\nfunc (s *Server) SetLogPath(path string) error {\n\tif len(path) == 0 {\n\t\treturn nil\n\t}\n\ts.config.LogPath = path\n\ts.config.ErrorLogEnabled = true\n\ts.config.AccessLogEnabled = true\n\tif s.config.LogPath != \"\" && s.config.LogPath != s.config.Logger.GetPath() {\n\t\tif err := s.config.Logger.SetPath(s.config.LogPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// SetLogger sets the logger for logging responsibility.\n// Note that it cannot be set in runtime as there may be concurrent safety issue.\nfunc (s *Server) SetLogger(logger *glog.Logger) {\n\ts.config.Logger = logger\n}\n\n// Logger is alias of GetLogger.\nfunc (s *Server) Logger() *glog.Logger {\n\treturn s.config.Logger\n}\n\n// SetLogLevel sets logging level by level string.\nfunc (s *Server) SetLogLevel(level string) {\n\ts.config.LogLevel = level\n}\n\n// SetLogStdout sets whether output the logging content to stdout.\nfunc (s *Server) SetLogStdout(enabled bool) {\n\ts.config.LogStdout = enabled\n}\n\n// SetAccessLogEnabled enables/disables the access log.\nfunc (s *Server) SetAccessLogEnabled(enabled bool) {\n\ts.config.AccessLogEnabled = enabled\n}\n\n// SetErrorLogEnabled enables/disables the error log.\nfunc (s *Server) SetErrorLogEnabled(enabled bool) {\n\ts.config.ErrorLogEnabled = enabled\n}\n\n// SetErrorStack enables/disables the error stack feature.\nfunc (s *Server) SetErrorStack(enabled bool) {\n\ts.config.ErrorStack = enabled\n}\n\n// GetLogPath returns the log path.\nfunc (s *Server) GetLogPath() string {\n\treturn s.config.LogPath\n}\n\n// IsAccessLogEnabled checks whether the access log enabled.\nfunc (s *Server) IsAccessLogEnabled() bool {\n\treturn s.config.AccessLogEnabled && s.config.Logger != nil\n}\n\n// IsErrorLogEnabled checks whether the error log enabled.\nfunc (s *Server) IsErrorLogEnabled() bool {\n\treturn s.config.ErrorLogEnabled && s.config.Logger != nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_mess.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// SetNameToUriType sets the NameToUriType for server.\nfunc (s *Server) SetNameToUriType(t int) {\n\ts.config.NameToUriType = t\n}\n\n// SetDumpRouterMap sets the DumpRouterMap for server.\n// If DumpRouterMap is enabled, it automatically dumps the route map when server starts.\nfunc (s *Server) SetDumpRouterMap(enabled bool) {\n\ts.config.DumpRouterMap = enabled\n}\n\n// SetClientMaxBodySize sets the ClientMaxBodySize for server.\nfunc (s *Server) SetClientMaxBodySize(maxSize int64) {\n\ts.config.ClientMaxBodySize = maxSize\n}\n\n// SetFormParsingMemory sets the FormParsingMemory for server.\nfunc (s *Server) SetFormParsingMemory(maxMemory int64) {\n\ts.config.FormParsingMemory = maxMemory\n}\n\n// SetGraceful sets the Graceful for server.\nfunc (s *Server) SetGraceful(graceful bool) {\n\ts.config.Graceful = graceful\n\t// note: global setting.\n\tgracefulEnabled = graceful\n}\n\n// GetGraceful returns the Graceful for server.\nfunc (s *Server) GetGraceful() bool {\n\treturn s.config.Graceful\n}\n\n// SetGracefulTimeout sets the GracefulTimeout for server.\nfunc (s *Server) SetGracefulTimeout(gracefulTimeout int) {\n\ts.config.GracefulTimeout = gracefulTimeout\n}\n\n// GetGracefulTimeout returns the GracefulTimeout for server.\nfunc (s *Server) GetGracefulTimeout() int {\n\treturn s.config.GracefulTimeout\n}\n\n// SetGracefulShutdownTimeout sets the GracefulShutdownTimeout for server.\nfunc (s *Server) SetGracefulShutdownTimeout(gracefulShutdownTimeout int) {\n\ts.config.GracefulShutdownTimeout = gracefulShutdownTimeout\n}\n\n// GetGracefulShutdownTimeout returns the GracefulShutdownTimeout for server.\nfunc (s *Server) GetGracefulShutdownTimeout() int {\n\treturn s.config.GracefulShutdownTimeout\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_route.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// SetRewrite sets rewrites for static URI for server.\nfunc (s *Server) SetRewrite(uri string, rewrite string) {\n\ts.config.Rewrites[uri] = rewrite\n}\n\n// SetRewriteMap sets the rewritten map for server.\nfunc (s *Server) SetRewriteMap(rewrites map[string]string) {\n\tfor k, v := range rewrites {\n\t\ts.config.Rewrites[k] = v\n\t}\n}\n\n// SetRouteOverWrite sets the RouteOverWrite for server.\nfunc (s *Server) SetRouteOverWrite(enabled bool) {\n\ts.config.RouteOverWrite = enabled\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_session.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gsession\"\n)\n\n// SetSessionMaxAge sets the SessionMaxAge for server.\nfunc (s *Server) SetSessionMaxAge(ttl time.Duration) {\n\ts.config.SessionMaxAge = ttl\n}\n\n// SetSessionIdName sets the SessionIdName for server.\nfunc (s *Server) SetSessionIdName(name string) {\n\ts.config.SessionIdName = name\n}\n\n// SetSessionStorage sets the SessionStorage for server.\nfunc (s *Server) SetSessionStorage(storage gsession.Storage) {\n\ts.config.SessionStorage = storage\n}\n\n// SetSessionCookieOutput sets the SetSessionCookieOutput for server.\nfunc (s *Server) SetSessionCookieOutput(enabled bool) {\n\ts.config.SessionCookieOutput = enabled\n}\n\n// SetSessionCookieMaxAge sets the SessionCookieMaxAge for server.\nfunc (s *Server) SetSessionCookieMaxAge(maxAge time.Duration) {\n\ts.config.SessionCookieMaxAge = maxAge\n}\n\n// GetSessionMaxAge returns the SessionMaxAge of server.\nfunc (s *Server) GetSessionMaxAge() time.Duration {\n\treturn s.config.SessionMaxAge\n}\n\n// GetSessionIdName returns the SessionIdName of server.\nfunc (s *Server) GetSessionIdName() string {\n\treturn s.config.SessionIdName\n}\n\n// GetSessionCookieMaxAge returns the SessionCookieMaxAge of server.\nfunc (s *Server) GetSessionCookieMaxAge() time.Duration {\n\treturn s.config.SessionCookieMaxAge\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_config_static.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Static Searching Priority: Resource > ServerPaths > ServerRoot > SearchPath\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// staticPathItem is the item struct for static path configuration.\ntype staticPathItem struct {\n\tPrefix string // The router URI.\n\tPath   string // The static path.\n}\n\n// SetIndexFiles sets the index files for server.\nfunc (s *Server) SetIndexFiles(indexFiles []string) {\n\ts.config.IndexFiles = indexFiles\n}\n\n// GetIndexFiles retrieves and returns the index files from the server.\nfunc (s *Server) GetIndexFiles() []string {\n\treturn s.config.IndexFiles\n}\n\n// SetIndexFolder enables/disables listing the sub-files if requesting a directory.\nfunc (s *Server) SetIndexFolder(enabled bool) {\n\ts.config.IndexFolder = enabled\n}\n\n// SetFileServerEnabled enables/disables the static file service.\n// It's the main switch for the static file service. When static file service configuration\n// functions like SetServerRoot, AddSearchPath and AddStaticPath are called, this configuration\n// is automatically enabled.\nfunc (s *Server) SetFileServerEnabled(enabled bool) {\n\ts.config.FileServerEnabled = enabled\n}\n\n// SetServerRoot sets the document root for static service.\nfunc (s *Server) SetServerRoot(root string) {\n\tvar (\n\t\tctx      = context.TODO()\n\t\trealPath = root\n\t)\n\tif !gres.Contains(realPath) {\n\t\tif p, err := gfile.Search(root); err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `SetServerRoot failed: %+v`, err)\n\t\t} else {\n\t\t\trealPath = p\n\t\t}\n\t}\n\ts.Logger().Debug(ctx, \"SetServerRoot path:\", realPath)\n\ts.config.SearchPaths = []string{strings.TrimRight(realPath, gfile.Separator)}\n\ts.config.FileServerEnabled = true\n}\n\n// AddSearchPath add searching directory path for static file service.\nfunc (s *Server) AddSearchPath(path string) {\n\tvar (\n\t\tctx      = context.TODO()\n\t\trealPath = path\n\t)\n\tif !gres.Contains(realPath) {\n\t\tif p, err := gfile.Search(path); err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `AddSearchPath failed: %+v`, err)\n\t\t} else {\n\t\t\trealPath = p\n\t\t}\n\t}\n\ts.config.SearchPaths = append(s.config.SearchPaths, realPath)\n\ts.config.FileServerEnabled = true\n}\n\n// AddStaticPath sets the uri to static directory path mapping for static file service.\nfunc (s *Server) AddStaticPath(prefix string, path string) {\n\tvar (\n\t\tctx      = context.TODO()\n\t\trealPath = path\n\t)\n\tif !gres.Contains(realPath) {\n\t\tif p, err := gfile.Search(path); err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `AddStaticPath failed: %+v`, err)\n\t\t} else {\n\t\t\trealPath = p\n\t\t}\n\t}\n\taddItem := staticPathItem{\n\t\tPrefix: prefix,\n\t\tPath:   realPath,\n\t}\n\tif len(s.config.StaticPaths) > 0 {\n\t\ts.config.StaticPaths = append(s.config.StaticPaths, addItem)\n\t\t// Sort the array by length of prefix from short to long.\n\t\tarray := garray.NewSortedArray(func(v1, v2 any) int {\n\t\t\ts1 := gconv.String(v1)\n\t\t\ts2 := gconv.String(v2)\n\t\t\tr := len(s2) - len(s1)\n\t\t\tif r == 0 {\n\t\t\t\tr = strings.Compare(s1, s2)\n\t\t\t}\n\t\t\treturn r\n\t\t})\n\t\tfor _, v := range s.config.StaticPaths {\n\t\t\tarray.Add(v.Prefix)\n\t\t}\n\t\t// Add the items to paths by previous sorted slice.\n\t\tpaths := make([]staticPathItem, 0)\n\t\tfor _, v := range array.Slice() {\n\t\t\tfor _, item := range s.config.StaticPaths {\n\t\t\t\tif strings.EqualFold(gconv.String(v), item.Prefix) {\n\t\t\t\t\tpaths = append(paths, item)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ts.config.StaticPaths = paths\n\t} else {\n\t\ts.config.StaticPaths = []staticPathItem{addItem}\n\t}\n\ts.config.FileServerEnabled = true\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_cookie.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// Cookie for HTTP COOKIE management.\ntype Cookie struct {\n\tdata     map[string]*cookieItem // Underlying cookie items.\n\tserver   *Server                // Belonged HTTP server\n\trequest  *Request               // Belonged HTTP request.\n\tresponse *Response              // Belonged HTTP response.\n}\n\n// CookieOptions provides security config for cookies\ntype CookieOptions struct {\n\tSameSite http.SameSite // cookie SameSite property\n\tSecure   bool          // cookie Secure property\n\tHttpOnly bool          // cookie HttpOnly property\n}\n\n// cookieItem is the item stored in Cookie.\ntype cookieItem struct {\n\t*http.Cookie      // Underlying cookie items.\n\tFromClient   bool // Mark this cookie received from the client.\n}\n\n// GetCookie creates or retrieves a cookie object with given request.\n// It retrieves and returns an existing cookie object if it already exists with given request.\n// It creates and returns a new cookie object if it does not exist with given request.\nfunc GetCookie(r *Request) *Cookie {\n\tif r.Cookie != nil {\n\t\treturn r.Cookie\n\t}\n\treturn &Cookie{\n\t\trequest: r,\n\t\tserver:  r.Server,\n\t}\n}\n\n// init does lazy initialization for the cookie object.\nfunc (c *Cookie) init() {\n\tif c.data != nil {\n\t\treturn\n\t}\n\tc.data = make(map[string]*cookieItem)\n\tc.response = c.request.Response\n\t// DO NOT ADD ANY DEFAULT COOKIE DOMAIN!\n\t// if c.request.Server.GetCookieDomain() == \"\" {\n\t//\tc.request.Server.GetCookieDomain() = c.request.GetHost()\n\t// }\n\tfor _, v := range c.request.Cookies() {\n\t\tc.data[v.Name] = &cookieItem{\n\t\t\tCookie:     v,\n\t\t\tFromClient: true,\n\t\t}\n\t}\n}\n\n// Map returns the cookie items as map[string]string.\nfunc (c *Cookie) Map() map[string]string {\n\tc.init()\n\tm := make(map[string]string)\n\tfor k, v := range c.data {\n\t\tm[k] = v.Value\n\t}\n\treturn m\n}\n\n// Contains checks if given key exists and not expire in cookie.\nfunc (c *Cookie) Contains(key string) bool {\n\tc.init()\n\tif r, ok := c.data[key]; ok {\n\t\tif r.Expires.IsZero() || r.Expires.After(time.Now()) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Set sets cookie item with default domain, path and expiration age.\nfunc (c *Cookie) Set(key, value string) {\n\tc.SetCookie(\n\t\tkey,\n\t\tvalue,\n\t\tc.request.Server.GetCookieDomain(),\n\t\tc.request.Server.GetCookiePath(),\n\t\tc.request.Server.GetCookieMaxAge(),\n\t\tCookieOptions{\n\t\t\tSameSite: c.request.Server.GetCookieSameSite(),\n\t\t\tSecure:   c.request.Server.GetCookieSecure(),\n\t\t\tHttpOnly: c.request.Server.GetCookieHttpOnly(),\n\t\t},\n\t)\n}\n\n// SetCookie sets cookie item with given domain, path and expiration age.\n// The optional parameter `options` specifies extra security configurations,\n// which is usually empty.\nfunc (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, options ...CookieOptions) {\n\tc.init()\n\tconfig := CookieOptions{}\n\tif len(options) > 0 {\n\t\tconfig = options[0]\n\t}\n\thttpCookie := &http.Cookie{\n\t\tName:     key,\n\t\tValue:    value,\n\t\tPath:     path,\n\t\tDomain:   domain,\n\t\tHttpOnly: config.HttpOnly,\n\t\tSameSite: config.SameSite,\n\t\tSecure:   config.Secure,\n\t}\n\tif maxAge != 0 {\n\t\thttpCookie.Expires = time.Now().Add(maxAge)\n\t}\n\tc.data[key] = &cookieItem{\n\t\tCookie: httpCookie,\n\t}\n}\n\n// SetHttpCookie sets cookie with *http.Cookie.\nfunc (c *Cookie) SetHttpCookie(httpCookie *http.Cookie) {\n\tc.init()\n\tc.data[httpCookie.Name] = &cookieItem{\n\t\tCookie: httpCookie,\n\t}\n}\n\n// GetSessionId retrieves and returns the session id from cookie.\nfunc (c *Cookie) GetSessionId() string {\n\treturn c.Get(c.server.GetSessionIdName()).String()\n}\n\n// SetSessionId sets session id in the cookie.\nfunc (c *Cookie) SetSessionId(id string) {\n\tc.SetCookie(\n\t\tc.server.GetSessionIdName(),\n\t\tid,\n\t\tc.request.Server.GetCookieDomain(),\n\t\tc.request.Server.GetCookiePath(),\n\t\tc.server.GetSessionCookieMaxAge(),\n\t\tCookieOptions{\n\t\t\tSameSite: c.request.Server.GetCookieSameSite(),\n\t\t\tSecure:   c.request.Server.GetCookieSecure(),\n\t\t\tHttpOnly: c.request.Server.GetCookieHttpOnly(),\n\t\t},\n\t)\n}\n\n// Get retrieves and returns the value with specified key.\n// It returns `def` if specified key does not exist and `def` is given.\nfunc (c *Cookie) Get(key string, def ...string) *gvar.Var {\n\tc.init()\n\tif r, ok := c.data[key]; ok {\n\t\tif r.Expires.IsZero() || r.Expires.After(time.Now()) {\n\t\t\treturn gvar.New(r.Value)\n\t\t}\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// Remove deletes specified key and its value from cookie using default domain and path.\n// It actually tells the http client that the cookie is expired, do not send it to server next time.\nfunc (c *Cookie) Remove(key string) {\n\tc.SetCookie(\n\t\tkey,\n\t\t\"\",\n\t\tc.request.Server.GetCookieDomain(),\n\t\tc.request.Server.GetCookiePath(),\n\t\t-24*time.Hour,\n\t)\n}\n\n// RemoveCookie deletes specified key and its value from cookie using given domain and path.\n// It actually tells the http client that the cookie is expired, do not send it to server next time.\nfunc (c *Cookie) RemoveCookie(key, domain, path string) {\n\tc.SetCookie(key, \"\", domain, path, -24*time.Hour)\n}\n\n// Flush outputs the cookie items to the client.\nfunc (c *Cookie) Flush() {\n\tif len(c.data) == 0 {\n\t\treturn\n\t}\n\tfor _, v := range c.data {\n\t\tif v.FromClient {\n\t\t\tcontinue\n\t\t}\n\t\thttp.SetCookie(c.response.Writer, v.Cookie)\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_domain.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"strings\"\n)\n\n// Domain is used for route register for domains.\ntype Domain struct {\n\tserver  *Server             // Belonged server\n\tdomains map[string]struct{} // Support multiple domains.\n}\n\n// Domain creates and returns a domain object for management for one or more domains.\nfunc (s *Server) Domain(domains string) *Domain {\n\td := &Domain{\n\t\tserver:  s,\n\t\tdomains: make(map[string]struct{}),\n\t}\n\tfor _, v := range strings.Split(domains, \",\") {\n\t\td.domains[strings.TrimSpace(v)] = struct{}{}\n\t}\n\treturn d\n}\n\n// BindHandler binds the handler for the specified pattern.\nfunc (d *Domain) BindHandler(pattern string, handler any) {\n\tfor domain := range d.domains {\n\t\td.server.BindHandler(patternBindDomain(pattern, domain), handler)\n\t}\n}\n\nfunc (d *Domain) doBindHandler(ctx context.Context, in doBindHandlerInput) {\n\tfor domain := range d.domains {\n\t\td.server.doBindHandler(ctx, doBindHandlerInput{\n\t\t\tPrefix:     in.Prefix,\n\t\t\tPattern:    patternBindDomain(in.Pattern, domain),\n\t\t\tFuncInfo:   in.FuncInfo,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t})\n\t}\n}\n\n// BindObject binds the object for the specified pattern.\nfunc (d *Domain) BindObject(pattern string, obj any, methods ...string) {\n\tfor domain := range d.domains {\n\t\td.server.BindObject(patternBindDomain(pattern, domain), obj, methods...)\n\t}\n}\n\nfunc (d *Domain) doBindObject(ctx context.Context, in doBindObjectInput) {\n\tfor domain := range d.domains {\n\t\td.server.doBindObject(ctx, doBindObjectInput{\n\t\t\tPrefix:     in.Prefix,\n\t\t\tPattern:    patternBindDomain(in.Pattern, domain),\n\t\t\tObject:     in.Object,\n\t\t\tMethod:     in.Method,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t})\n\t}\n}\n\n// BindObjectMethod binds the method for the specified pattern.\nfunc (d *Domain) BindObjectMethod(pattern string, obj any, method string) {\n\tfor domain := range d.domains {\n\t\td.server.BindObjectMethod(patternBindDomain(pattern, domain), obj, method)\n\t}\n}\n\nfunc (d *Domain) doBindObjectMethod(ctx context.Context, in doBindObjectMethodInput) {\n\tfor domain := range d.domains {\n\t\td.server.doBindObjectMethod(ctx, doBindObjectMethodInput{\n\t\t\tPrefix:     in.Prefix,\n\t\t\tPattern:    patternBindDomain(in.Pattern, domain),\n\t\t\tObject:     in.Object,\n\t\t\tMethod:     in.Method,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t})\n\t}\n}\n\n// BindObjectRest binds the RESTful API for the specified pattern.\nfunc (d *Domain) BindObjectRest(pattern string, obj any) {\n\tfor domain := range d.domains {\n\t\td.server.BindObjectRest(patternBindDomain(pattern, domain), obj)\n\t}\n}\n\nfunc (d *Domain) doBindObjectRest(ctx context.Context, in doBindObjectInput) {\n\tfor domain := range d.domains {\n\t\td.server.doBindObjectRest(ctx, doBindObjectInput{\n\t\t\tPrefix:     in.Prefix,\n\t\t\tPattern:    patternBindDomain(in.Pattern, domain),\n\t\t\tObject:     in.Object,\n\t\t\tMethod:     in.Method,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t})\n\t}\n}\n\n// BindHookHandler binds the hook handler for the specified pattern.\nfunc (d *Domain) BindHookHandler(pattern string, hook HookName, handler HandlerFunc) {\n\tfor domain := range d.domains {\n\t\td.server.BindHookHandler(patternBindDomain(pattern, domain), hook, handler)\n\t}\n}\n\nfunc (d *Domain) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {\n\tfor domain := range d.domains {\n\t\td.server.doBindHookHandler(ctx, doBindHookHandlerInput{\n\t\t\tPrefix:   in.Prefix,\n\t\t\tPattern:  patternBindDomain(in.Pattern, domain),\n\t\t\tHookName: in.HookName,\n\t\t\tHandler:  in.Handler,\n\t\t\tSource:   in.Source,\n\t\t})\n\t}\n}\n\n// BindHookHandlerByMap binds the hook handler for the specified pattern.\nfunc (d *Domain) BindHookHandlerByMap(pattern string, hookMap map[HookName]HandlerFunc) {\n\tfor domain := range d.domains {\n\t\td.server.BindHookHandlerByMap(patternBindDomain(pattern, domain), hookMap)\n\t}\n}\n\n// BindStatusHandler binds the status handler for the specified pattern.\nfunc (d *Domain) BindStatusHandler(status int, handler HandlerFunc) {\n\tfor domain := range d.domains {\n\t\td.server.addStatusHandler(d.server.statusHandlerKey(status, domain), handler)\n\t}\n}\n\n// BindStatusHandlerByMap binds the status handler for the specified pattern.\nfunc (d *Domain) BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {\n\tfor k, v := range handlerMap {\n\t\td.BindStatusHandler(k, v)\n\t}\n}\n\n// BindMiddleware binds the middleware for the specified pattern.\nfunc (d *Domain) BindMiddleware(pattern string, handlers ...HandlerFunc) {\n\tfor domain := range d.domains {\n\t\td.server.BindMiddleware(patternBindDomain(pattern, domain), handlers...)\n\t}\n}\n\n// BindMiddlewareDefault binds the default middleware for the specified pattern.\nfunc (d *Domain) BindMiddlewareDefault(handlers ...HandlerFunc) {\n\tfor domain := range d.domains {\n\t\td.server.BindMiddleware(patternBindDomain(defaultMiddlewarePattern, domain), handlers...)\n\t}\n}\n\n// Use adds middleware to the domain.\nfunc (d *Domain) Use(handlers ...HandlerFunc) {\n\td.BindMiddlewareDefault(handlers...)\n}\n\nfunc patternBindDomain(pattern, domain string) string {\n\tif domain != \"\" {\n\t\treturn pattern + \"@\" + domain\n\t}\n\treturn pattern\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_error_logger.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\n// errorLogger is the error logging logger for underlying net/http.Server.\ntype errorLogger struct {\n\tlogger *glog.Logger\n}\n\n// Write implements the io.Writer interface.\nfunc (l *errorLogger) Write(p []byte) (n int, err error) {\n\tl.logger.Skip(1).Error(context.TODO(), string(bytes.TrimRight(p, \"\\r\\n\")))\n\treturn len(p), nil\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_graceful.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/net/ghttp/internal/graceful\"\n\n// newGracefulServer creates and returns a graceful http server with a given address.\n// The optional parameter `fd` specifies the file descriptor which is passed from parent server.\nfunc (s *Server) newGracefulServer(address string, fd int) *graceful.Server {\n\tvar (\n\t\tloggerWriter = &errorLogger{logger: s.config.Logger}\n\t\tserverConfig = graceful.ServerConfig{\n\t\t\tListeners:               s.config.Listeners,\n\t\t\tHandler:                 s.config.Handler,\n\t\t\tReadTimeout:             s.config.ReadTimeout,\n\t\t\tWriteTimeout:            s.config.WriteTimeout,\n\t\t\tIdleTimeout:             s.config.IdleTimeout,\n\t\t\tGracefulShutdownTimeout: s.config.GracefulTimeout,\n\t\t\tMaxHeaderBytes:          s.config.MaxHeaderBytes,\n\t\t\tKeepAlive:               s.config.KeepAlive,\n\t\t\tLogger:                  s.config.Logger,\n\t\t}\n\t)\n\treturn graceful.New(address, fd, loggerWriter, serverConfig)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_handler.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"net/http\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghtml\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gspath\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// ServeHTTP is the default handler for http request.\n// It should not create new goroutine handling the request as\n// it's called by am already created new goroutine from http.Server.\n//\n// This function also makes serve implementing the interface of http.Handler.\nfunc (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t// Max body size limit.\n\tif s.config.ClientMaxBodySize > 0 {\n\t\tr.Body = http.MaxBytesReader(w, r.Body, s.config.ClientMaxBodySize)\n\t}\n\t// Rewrite feature checks.\n\tif len(s.config.Rewrites) > 0 {\n\t\tif rewrite, ok := s.config.Rewrites[r.URL.Path]; ok {\n\t\t\tr.URL.Path = rewrite\n\t\t}\n\t}\n\n\tvar (\n\t\trequest   = newRequest(s, r, w)    // Create a new request object.\n\t\tsessionId = request.GetSessionId() // Get sessionId before user handler\n\t)\n\tdefer s.handleAfterRequestDone(request)\n\n\t// ============================================================\n\t// Priority:\n\t// Static File > Dynamic Service > Static Directory\n\t// ============================================================\n\n\t// Search the static file with most high priority,\n\t// which also handle the index files feature.\n\tif s.config.FileServerEnabled {\n\t\trequest.StaticFile = s.searchStaticFile(r.URL.Path)\n\t\tif request.StaticFile != nil {\n\t\t\trequest.isFileRequest = true\n\t\t}\n\t}\n\n\t// Search the dynamic service handler.\n\trequest.handlers,\n\t\trequest.serveHandler,\n\t\trequest.hasHookHandler,\n\t\trequest.hasServeHandler = s.getHandlersWithCache(request)\n\n\t// Check the service type static or dynamic for current request.\n\tif request.StaticFile != nil && request.StaticFile.IsDir && request.hasServeHandler {\n\t\trequest.isFileRequest = false\n\t}\n\n\t// Metrics.\n\ts.handleMetricsBeforeRequest(request)\n\n\t// HOOK - BeforeServe\n\ts.callHookHandler(HookBeforeServe, request)\n\n\t// Core serving handling.\n\tif !request.IsExited() {\n\t\tif request.isFileRequest {\n\t\t\t// Static file service.\n\t\t\ts.serveFile(request, request.StaticFile)\n\t\t} else {\n\t\t\tif len(request.handlers) > 0 {\n\t\t\t\t// Dynamic service.\n\t\t\t\trequest.Middleware.Next()\n\t\t\t} else {\n\t\t\t\tif request.StaticFile != nil && request.StaticFile.IsDir {\n\t\t\t\t\t// Serve the directory.\n\t\t\t\t\ts.serveFile(request, request.StaticFile)\n\t\t\t\t} else {\n\t\t\t\t\tif len(request.Response.Header()) == 0 &&\n\t\t\t\t\t\trequest.Response.Status == 0 &&\n\t\t\t\t\t\trequest.Response.BufferLength() == 0 {\n\t\t\t\t\t\trequest.Response.WriteHeader(http.StatusNotFound)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// HOOK - AfterServe\n\tif !request.IsExited() {\n\t\ts.callHookHandler(HookAfterServe, request)\n\t}\n\n\t// HOOK - BeforeOutput\n\tif !request.IsExited() {\n\t\ts.callHookHandler(HookBeforeOutput, request)\n\t}\n\n\t// Response handling.\n\ts.handleResponse(request, sessionId)\n\n\t// HOOK - AfterOutput\n\tif !request.IsExited() {\n\t\ts.callHookHandler(HookAfterOutput, request)\n\t}\n}\n\nfunc (s *Server) handleResponse(request *Request, sessionId string) {\n\t// HTTP status checking.\n\tif request.Response.Status == 0 {\n\t\tif request.StaticFile != nil || request.Middleware.served || request.Response.BufferLength() > 0 {\n\t\t\trequest.Response.WriteHeader(http.StatusOK)\n\t\t} else if err := request.GetError(); err != nil {\n\t\t\tif request.Response.BufferLength() == 0 {\n\t\t\t\trequest.Response.Write(err.Error())\n\t\t\t}\n\t\t\trequest.Response.WriteHeader(http.StatusInternalServerError)\n\t\t} else {\n\t\t\trequest.Response.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}\n\t// HTTP status handler.\n\tif request.Response.Status != http.StatusOK {\n\t\tstatusFuncArray := s.getStatusHandler(request.Response.Status, request)\n\t\tfor _, f := range statusFuncArray {\n\t\t\t// Call custom status handler.\n\t\t\tniceCallFunc(func() {\n\t\t\t\tf(request)\n\t\t\t})\n\t\t\tif request.IsExited() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Automatically set the session id to cookie\n\t// if it creates a new session id in this request\n\t// and SessionCookieOutput is enabled.\n\tif s.config.SessionCookieOutput && request.Session.IsDirty() {\n\t\t// Can change by r.Session.SetId(\"\") before init session\n\t\t// Can change by r.Cookie.SetSessionId(\"\")\n\t\tsidFromSession, sidFromRequest := request.Session.MustId(), request.GetSessionId()\n\t\tif sidFromSession != sidFromRequest {\n\t\t\tif sidFromSession != sessionId {\n\t\t\t\trequest.Cookie.SetSessionId(sidFromSession)\n\t\t\t} else {\n\t\t\t\trequest.Cookie.SetSessionId(sidFromRequest)\n\t\t\t}\n\t\t}\n\t}\n\t// Output the cookie content to the client.\n\trequest.Cookie.Flush()\n\t// Output the buffer content to the client.\n\trequest.Response.Flush()\n}\n\nfunc (s *Server) handleAfterRequestDone(request *Request) {\n\trequest.LeaveTime = gtime.Now()\n\t// error log handling.\n\tif request.error != nil {\n\t\ts.handleErrorLog(request.error, request)\n\t} else {\n\t\tif exception := recover(); exception != nil {\n\t\t\trequest.Response.WriteStatus(http.StatusInternalServerError)\n\t\t\tif v, ok := exception.(error); ok {\n\t\t\t\tif code := gerror.Code(v); code != gcode.CodeNil {\n\t\t\t\t\ts.handleErrorLog(v, request)\n\t\t\t\t} else {\n\t\t\t\t\ts.handleErrorLog(\n\t\t\t\t\t\tgerror.WrapCodeSkip(gcode.CodeInternalPanic, 1, v, \"\"),\n\t\t\t\t\t\trequest,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ts.handleErrorLog(\n\t\t\t\t\tgerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, \"%+v\", exception),\n\t\t\t\t\trequest,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\t// access log handling.\n\ts.handleAccessLog(request)\n\t// Close the session, which automatically update the TTL\n\t// of the session if it exists.\n\tif err := request.Session.Close(); err != nil {\n\t\tintlog.Errorf(request.Context(), `%+v`, err)\n\t}\n\n\t// Close the request and response body\n\t// to release the file descriptor in time.\n\terr := request.Body.Close()\n\tif err != nil {\n\t\tintlog.Errorf(request.Context(), `%+v`, err)\n\t}\n\tif request.Request.Response != nil {\n\t\terr = request.Request.Response.Body.Close()\n\t\tif err != nil {\n\t\t\tintlog.Errorf(request.Context(), `%+v`, err)\n\t\t}\n\t}\n\n\t// Metrics.\n\ts.handleMetricsAfterRequestDone(request)\n}\n\n// searchStaticFile searches the file with given URI.\n// It returns a file struct specifying the file information.\nfunc (s *Server) searchStaticFile(uri string) *staticFile {\n\tvar (\n\t\tfile *gres.File\n\t\tpath string\n\t\tdir  bool\n\t)\n\t// Firstly search the StaticPaths mapping.\n\tif len(s.config.StaticPaths) > 0 {\n\t\tfor _, item := range s.config.StaticPaths {\n\t\t\tif len(uri) >= len(item.Prefix) && strings.EqualFold(item.Prefix, uri[0:len(item.Prefix)]) {\n\t\t\t\t// To avoid case like: /static/style -> /static/style.css\n\t\t\t\tif len(uri) > len(item.Prefix) && uri[len(item.Prefix)] != '/' {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfile = gres.GetWithIndex(item.Path+uri[len(item.Prefix):], s.config.IndexFiles)\n\t\t\t\tif file != nil {\n\t\t\t\t\treturn &staticFile{\n\t\t\t\t\t\tFile:  file,\n\t\t\t\t\t\tIsDir: file.FileInfo().IsDir(),\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpath, dir = gspath.Search(item.Path, uri[len(item.Prefix):], s.config.IndexFiles...)\n\t\t\t\tif path != \"\" {\n\t\t\t\t\treturn &staticFile{\n\t\t\t\t\t\tPath:  path,\n\t\t\t\t\t\tIsDir: dir,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// Secondly search the root and searching paths.\n\tif len(s.config.SearchPaths) > 0 {\n\t\tfor _, p := range s.config.SearchPaths {\n\t\t\tfile = gres.GetWithIndex(p+uri, s.config.IndexFiles)\n\t\t\tif file != nil {\n\t\t\t\treturn &staticFile{\n\t\t\t\t\tFile:  file,\n\t\t\t\t\tIsDir: file.FileInfo().IsDir(),\n\t\t\t\t}\n\t\t\t}\n\t\t\tif path, dir = gspath.Search(p, uri, s.config.IndexFiles...); path != \"\" {\n\t\t\t\treturn &staticFile{\n\t\t\t\t\tPath:  path,\n\t\t\t\t\tIsDir: dir,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// Lastly search the resource manager.\n\tif len(s.config.StaticPaths) == 0 && len(s.config.SearchPaths) == 0 {\n\t\tif file = gres.GetWithIndex(uri, s.config.IndexFiles); file != nil {\n\t\t\treturn &staticFile{\n\t\t\t\tFile:  file,\n\t\t\t\tIsDir: file.FileInfo().IsDir(),\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// serveFile serves the static file for the client.\n// The optional parameter `allowIndex` specifies if allowing directory listing if `f` is a directory.\nfunc (s *Server) serveFile(r *Request, f *staticFile, allowIndex ...bool) {\n\t// Use resource file from memory.\n\tif f.File != nil {\n\t\tif f.IsDir {\n\t\t\tif s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {\n\t\t\t\ts.listDir(r, f.File)\n\t\t\t} else {\n\t\t\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\t\t}\n\t\t} else {\n\t\t\tinfo := f.File.FileInfo()\n\t\t\tr.Response.ServeContent(info.Name(), info.ModTime(), f.File)\n\t\t}\n\t\treturn\n\t}\n\t// Use file from dist.\n\tfile, err := os.Open(f.Path)\n\tif err != nil {\n\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\treturn\n\t}\n\tdefer func() {\n\t\t_ = file.Close()\n\t}()\n\n\t// Clear the response buffer before file serving.\n\t// It ignores all custom buffer content and uses the file content.\n\tr.Response.ClearBuffer()\n\n\tinfo, _ := file.Stat()\n\tif info.IsDir() {\n\t\tif s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {\n\t\t\ts.listDir(r, file)\n\t\t} else {\n\t\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t\t}\n\t} else {\n\t\tr.Response.ServeContent(info.Name(), info.ModTime(), file)\n\t}\n}\n\n// listDir lists the sub files of specified directory as HTML content to the client.\nfunc (s *Server) listDir(r *Request, f http.File) {\n\tfiles, err := f.Readdir(-1)\n\tif err != nil {\n\t\tr.Response.WriteStatus(http.StatusInternalServerError, \"Error reading directory\")\n\t\treturn\n\t}\n\t// The folder type has the most priority than file.\n\tsort.Slice(files, func(i, j int) bool {\n\t\tif files[i].IsDir() && !files[j].IsDir() {\n\t\t\treturn true\n\t\t}\n\t\tif !files[i].IsDir() && files[j].IsDir() {\n\t\t\treturn false\n\t\t}\n\t\treturn files[i].Name() < files[j].Name()\n\t})\n\tif r.Response.Header().Get(\"Content-Type\") == \"\" {\n\t\tr.Response.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t}\n\tr.Response.Write(`<html>`)\n\tr.Response.Write(`<head>`)\n\tr.Response.Write(`<style>`)\n\tr.Response.Write(`body {font-family:Consolas, Monaco, \"Andale Mono\", \"Ubuntu Mono\", monospace;}`)\n\tr.Response.Write(`</style>`)\n\tr.Response.Write(`</head>`)\n\tr.Response.Write(`<body>`)\n\tr.Response.Writef(`<h1>Index of %s</h1>`, r.URL.Path)\n\tr.Response.Writef(`<hr />`)\n\tr.Response.Write(`<table>`)\n\tif r.URL.Path != \"/\" {\n\t\tr.Response.Write(`<tr>`)\n\t\tr.Response.Writef(`<td><a href=\"%s\">..</a></td>`, gfile.Dir(r.URL.Path))\n\t\tr.Response.Write(`</tr>`)\n\t}\n\tname := \"\"\n\tsize := \"\"\n\tprefix := gstr.TrimRight(r.URL.Path, \"/\")\n\tfor _, file := range files {\n\t\tname = file.Name()\n\t\tsize = gfile.FormatSize(file.Size())\n\t\tif file.IsDir() {\n\t\t\tname += \"/\"\n\t\t\tsize = \"-\"\n\t\t}\n\t\tr.Response.Write(`<tr>`)\n\t\tr.Response.Writef(`<td><a href=\"%s/%s\">%s</a></td>`, prefix, name, ghtml.SpecialChars(name))\n\t\tr.Response.Writef(`<td style=\"width:300px;text-align:center;\">%s</td>`, gtime.New(file.ModTime()).ISO8601())\n\t\tr.Response.Writef(`<td style=\"width:80px;text-align:right;\">%s</td>`, size)\n\t\tr.Response.Write(`</tr>`)\n\t}\n\tr.Response.Write(`</table>`)\n\tr.Response.Write(`</body>`)\n\tr.Response.Write(`</html>`)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_log.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/instance\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// handleAccessLog handles the access logging for server.\nfunc (s *Server) handleAccessLog(r *Request) {\n\tif !s.IsAccessLogEnabled() {\n\t\treturn\n\t}\n\tvar (\n\t\tscheme            = r.GetSchema()\n\t\tloggerInstanceKey = fmt.Sprintf(`Acccess Logger Of Server:%s`, s.instance)\n\t)\n\tcontent := fmt.Sprintf(\n\t\t`%d \"%s %s %s %s %s\" %.3f, %s, \"%s\", \"%s\"`,\n\t\tr.Response.Status, r.Method, scheme, r.Host, r.URL.String(), r.Proto,\n\t\tfloat64(r.LeaveTime.Sub(r.EnterTime).Milliseconds())/1000,\n\t\tr.GetClientIp(), r.Referer(), r.UserAgent(),\n\t)\n\tlogger := instance.GetOrSetFuncLock(loggerInstanceKey, func() any {\n\t\tl := s.Logger().Clone()\n\t\tl.SetFile(s.config.AccessLogPattern)\n\t\tl.SetStdoutPrint(s.config.LogStdout)\n\t\tl.SetLevelPrint(false)\n\t\treturn l\n\t}).(*glog.Logger)\n\tlogger.Print(r.Context(), content)\n}\n\n// handleErrorLog handles the error logging for server.\nfunc (s *Server) handleErrorLog(err error, r *Request) {\n\t// It does nothing if error logging is custom disabled.\n\tif !s.IsErrorLogEnabled() {\n\t\treturn\n\t}\n\tvar (\n\t\tcode              = gerror.Code(err)\n\t\tscheme            = r.GetSchema()\n\t\tcodeDetail        = code.Detail()\n\t\tloggerInstanceKey = fmt.Sprintf(`Error Logger Of Server:%s`, s.instance)\n\t\tcodeDetailStr     string\n\t)\n\tif codeDetail != nil {\n\t\tcodeDetailStr = gstr.Replace(fmt.Sprintf(`%+v`, codeDetail), \"\\n\", \" \")\n\t}\n\tcontent := fmt.Sprintf(\n\t\t`%d \"%s %s %s %s %s\" %.3f, %s, \"%s\", \"%s\", %d, \"%s\", \"%+v\"`,\n\t\tr.Response.Status, r.Method, scheme, r.Host, r.URL.String(), r.Proto,\n\t\tfloat64(r.LeaveTime.Sub(r.EnterTime))/1000,\n\t\tr.GetClientIp(), r.Referer(), r.UserAgent(),\n\t\tcode.Code(), code.Message(), codeDetailStr,\n\t)\n\tif s.config.ErrorStack {\n\t\tif stack := gerror.Stack(err); stack != \"\" {\n\t\t\tcontent += \"\\nStack:\\n\" + stack\n\t\t} else {\n\t\t\tcontent += \", \" + err.Error()\n\t\t}\n\t} else {\n\t\tcontent += \", \" + err.Error()\n\t}\n\tlogger := instance.GetOrSetFuncLock(loggerInstanceKey, func() any {\n\t\tl := s.Logger().Clone()\n\t\tl.SetStack(false)\n\t\tl.SetFile(s.config.ErrorLogPattern)\n\t\tl.SetStdoutPrint(s.config.LogStdout)\n\t\tl.SetLevelPrint(false)\n\t\treturn l\n\t}).(*glog.Logger)\n\tlogger.Error(r.Context(), content)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_metric.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\ntype localMetricManager struct {\n\tHttpServerRequestActive        gmetric.UpDownCounter\n\tHttpServerRequestTotal         gmetric.Counter\n\tHttpServerRequestDuration      gmetric.Histogram\n\tHttpServerRequestDurationTotal gmetric.Counter\n\tHttpServerRequestBodySize      gmetric.Counter\n\tHttpServerResponseBodySize     gmetric.Counter\n}\n\nconst (\n\tmetricAttrKeyServerAddress          = \"server.address\"\n\tmetricAttrKeyServerPort             = \"server.port\"\n\tmetricAttrKeyHttpRoute              = \"http.route\"\n\tmetricAttrKeyUrlSchema              = \"url.schema\"\n\tmetricAttrKeyHttpRequestMethod      = \"http.request.method\"\n\tmetricAttrKeyErrorCode              = \"error.code\"\n\tmetricAttrKeyHttpResponseStatusCode = \"http.response.status_code\"\n\tmetricAttrKeyNetworkProtocolVersion = \"network.protocol.version\"\n)\n\nvar (\n\t// metricManager for http server metrics.\n\tmetricManager = newMetricManager()\n)\n\nfunc newMetricManager() *localMetricManager {\n\tmeter := gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{\n\t\tInstrument:        instrumentName,\n\t\tInstrumentVersion: gf.VERSION,\n\t})\n\tmm := &localMetricManager{\n\t\tHttpServerRequestDuration: meter.MustHistogram(\n\t\t\t\"http.server.request.duration\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Measures the duration of inbound request.\",\n\t\t\t\tUnit:       \"ms\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t\tBuckets: []float64{\n\t\t\t\t\t1,\n\t\t\t\t\t5,\n\t\t\t\t\t10,\n\t\t\t\t\t25,\n\t\t\t\t\t50,\n\t\t\t\t\t75,\n\t\t\t\t\t100,\n\t\t\t\t\t250,\n\t\t\t\t\t500,\n\t\t\t\t\t750,\n\t\t\t\t\t1000,\n\t\t\t\t\t2500,\n\t\t\t\t\t5000,\n\t\t\t\t\t7500,\n\t\t\t\t\t10000,\n\t\t\t\t\t30000,\n\t\t\t\t\t60000,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t\tHttpServerRequestTotal: meter.MustCounter(\n\t\t\t\"http.server.request.total\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Total processed request number.\",\n\t\t\t\tUnit:       \"\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpServerRequestActive: meter.MustUpDownCounter(\n\t\t\t\"http.server.request.active\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Number of active server requests.\",\n\t\t\t\tUnit:       \"\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpServerRequestDurationTotal: meter.MustCounter(\n\t\t\t\"http.server.request.duration_total\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Total execution duration of request.\",\n\t\t\t\tUnit:       \"ms\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpServerRequestBodySize: meter.MustCounter(\n\t\t\t\"http.server.request.body_size\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Incoming request bytes total.\",\n\t\t\t\tUnit:       \"bytes\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t\tHttpServerResponseBodySize: meter.MustCounter(\n\t\t\t\"http.server.response.body_size\",\n\t\t\tgmetric.MetricOption{\n\t\t\t\tHelp:       \"Response bytes total.\",\n\t\t\t\tUnit:       \"bytes\",\n\t\t\t\tAttributes: gmetric.Attributes{},\n\t\t\t},\n\t\t),\n\t}\n\treturn mm\n}\n\nfunc (m *localMetricManager) GetMetricOptionForRequestDurationByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricOptionForRequest(r *Request) gmetric.Option {\n\tattrMap := m.GetMetricAttributeMap(r)\n\treturn m.GetMetricOptionForRequestByMap(attrMap)\n}\n\nfunc (m *localMetricManager) GetMetricOptionForRequestByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t\tmetricAttrKeyHttpRoute,\n\t\t\tmetricAttrKeyUrlSchema,\n\t\t\tmetricAttrKeyHttpRequestMethod,\n\t\t\tmetricAttrKeyNetworkProtocolVersion,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricOptionForResponseByMap(attrMap gmetric.AttributeMap) gmetric.Option {\n\treturn gmetric.Option{\n\t\tAttributes: attrMap.Pick(\n\t\t\tmetricAttrKeyServerAddress,\n\t\t\tmetricAttrKeyServerPort,\n\t\t\tmetricAttrKeyHttpRoute,\n\t\t\tmetricAttrKeyUrlSchema,\n\t\t\tmetricAttrKeyHttpRequestMethod,\n\t\t\tmetricAttrKeyNetworkProtocolVersion,\n\t\t\tmetricAttrKeyErrorCode,\n\t\t\tmetricAttrKeyHttpResponseStatusCode,\n\t\t),\n\t}\n}\n\nfunc (m *localMetricManager) GetMetricAttributeMap(r *Request) gmetric.AttributeMap {\n\tvar (\n\t\tserverAddress   string\n\t\tserverPort      string\n\t\thttpRoute       string\n\t\tprotocolVersion string\n\t\thandler         = r.GetServeHandler()\n\t\tlocalAddr       = r.Context().Value(http.LocalAddrContextKey)\n\t\tattrMap         = make(gmetric.AttributeMap)\n\t)\n\tserverAddress, serverPort = gstr.List2(r.Host, \":\")\n\tif localAddr != nil {\n\t\t_, serverPort = gstr.List2(localAddr.(net.Addr).String(), \":\")\n\t}\n\tif handler != nil && handler.Handler.Router != nil {\n\t\thttpRoute = handler.Handler.Router.Uri\n\t} else {\n\t\thttpRoute = r.URL.Path\n\t}\n\tif array := gstr.Split(r.Proto, \"/\"); len(array) > 1 {\n\t\tprotocolVersion = array[1]\n\t}\n\tattrMap.Sets(gmetric.AttributeMap{\n\t\tmetricAttrKeyServerAddress:          serverAddress,\n\t\tmetricAttrKeyServerPort:             serverPort,\n\t\tmetricAttrKeyHttpRoute:              httpRoute,\n\t\tmetricAttrKeyUrlSchema:              r.GetSchema(),\n\t\tmetricAttrKeyHttpRequestMethod:      r.Method,\n\t\tmetricAttrKeyNetworkProtocolVersion: protocolVersion,\n\t})\n\tif r.LeaveTime != nil {\n\t\tvar errCode int\n\t\tif err := r.GetError(); err != nil {\n\t\t\terrCode = gerror.Code(err).Code()\n\t\t}\n\t\tattrMap.Sets(gmetric.AttributeMap{\n\t\t\tmetricAttrKeyErrorCode:              errCode,\n\t\t\tmetricAttrKeyHttpResponseStatusCode: r.Response.Status,\n\t\t})\n\t}\n\treturn attrMap\n}\n\nfunc (s *Server) handleMetricsBeforeRequest(r *Request) {\n\tif !gmetric.IsEnabled() {\n\t\treturn\n\t}\n\tvar (\n\t\tctx           = r.Context()\n\t\tattrMap       = metricManager.GetMetricAttributeMap(r)\n\t\trequestOption = metricManager.GetMetricOptionForRequestByMap(attrMap)\n\t)\n\tmetricManager.HttpServerRequestActive.Inc(\n\t\tctx,\n\t\trequestOption,\n\t)\n\tmetricManager.HttpServerRequestBodySize.Add(\n\t\tctx,\n\t\tfloat64(r.ContentLength),\n\t\trequestOption,\n\t)\n}\n\nfunc (s *Server) handleMetricsAfterRequestDone(r *Request) {\n\tif !gmetric.IsEnabled() {\n\t\treturn\n\t}\n\tvar (\n\t\tctx             = r.Context()\n\t\tattrMap         = metricManager.GetMetricAttributeMap(r)\n\t\tdurationMilli   = float64(r.LeaveTime.Sub(r.EnterTime).Milliseconds())\n\t\tresponseOption  = metricManager.GetMetricOptionForResponseByMap(attrMap)\n\t\thistogramOption = metricManager.GetMetricOptionForRequestDurationByMap(attrMap)\n\t)\n\tmetricManager.HttpServerRequestTotal.Inc(ctx, responseOption)\n\tmetricManager.HttpServerRequestActive.Dec(\n\t\tctx,\n\t\tmetricManager.GetMetricOptionForRequestByMap(attrMap),\n\t)\n\tmetricManager.HttpServerResponseBodySize.Add(\n\t\tctx,\n\t\tfloat64(r.Response.BytesWritten()),\n\t\tresponseOption,\n\t)\n\tmetricManager.HttpServerRequestDurationTotal.Add(\n\t\tctx,\n\t\tdurationMilli,\n\t\tresponseOption,\n\t)\n\tmetricManager.HttpServerRequestDuration.Record(\n\t\tdurationMilli,\n\t\thistogramOption,\n\t)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_openapi.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// initOpenApi generates api specification using OpenApiV3 protocol.\nfunc (s *Server) initOpenApi() {\n\tif s.config.OpenApiPath == \"\" {\n\t\treturn\n\t}\n\tvar (\n\t\tctx     = context.TODO()\n\t\terr     error\n\t\tmethods []string\n\t)\n\tfor _, item := range s.GetRoutes() {\n\t\tswitch item.Type {\n\t\tcase HandlerTypeMiddleware, HandlerTypeHook:\n\t\t\tcontinue\n\t\t}\n\t\tif item.Handler.Info.IsStrictRoute {\n\t\t\tmethods = []string{item.Method}\n\t\t\tif gstr.Equal(item.Method, defaultMethod) {\n\t\t\t\tmethods = SupportedMethods()\n\t\t\t}\n\t\t\tfor _, method := range methods {\n\t\t\t\terr = s.openapi.Add(goai.AddInput{\n\t\t\t\t\tPath:   item.Route,\n\t\t\t\t\tMethod: method,\n\t\t\t\t\tObject: item.Handler.Info.Value.Interface(),\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// openapiSpec is a build-in handler automatic producing for openapi specification json file.\nfunc (s *Server) openapiSpec(r *Request) {\n\tif s.config.OpenApiPath == \"\" {\n\t\tr.Response.Write(`OpenApi specification file producing is disabled`)\n\t} else {\n\t\tr.Response.WriteJson(s.openapi)\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_plugin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\n// Plugin is the interface for server plugin.\ntype Plugin interface {\n\tName() string            // Name returns the name of the plugin.\n\tAuthor() string          // Author returns the author of the plugin.\n\tVersion() string         // Version returns the version of the plugin, like \"v1.0.0\".\n\tDescription() string     // Description returns the description of the plugin.\n\tInstall(s *Server) error // Install installs the plugin BEFORE the server starts.\n\tRemove() error           // Remove removes the plugin when server shuts down.\n}\n\n// Plugin adds plugin to the server.\nfunc (s *Server) Plugin(plugin ...Plugin) {\n\ts.plugins = append(s.plugins, plugin...)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_pprof.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\tnetpprof \"net/http/pprof\"\n\trunpprof \"runtime/pprof\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n)\n\n// utilPProf is the PProf interface implementer.\ntype utilPProf struct{}\n\nconst (\n\tdefaultPProfServerName = \"pprof-server\"\n\tdefaultPProfPattern    = \"/debug/pprof\"\n)\n\n// StartPProfServer starts and runs a new server for pprof in another goroutine.\nfunc StartPProfServer(address string, pattern ...string) (s *Server, err error) {\n\ts = GetServer(defaultPProfServerName)\n\ts.EnablePProf(pattern...)\n\ts.SetAddr(address)\n\terr = s.Start()\n\treturn\n}\n\n// EnablePProf enables PProf feature for server.\nfunc (s *Server) EnablePProf(pattern ...string) {\n\ts.Domain(DefaultDomainName).EnablePProf(pattern...)\n}\n\n// EnablePProf enables PProf feature for server of specified domain.\nfunc (d *Domain) EnablePProf(pattern ...string) {\n\tp := defaultPProfPattern\n\tif len(pattern) > 0 && pattern[0] != \"\" {\n\t\tp = pattern[0]\n\t}\n\tup := &utilPProf{}\n\t_, _, uri, _ := d.server.parsePattern(p)\n\turi = strings.TrimRight(uri, \"/\")\n\td.Group(uri, func(group *RouterGroup) {\n\t\tgroup.ALL(\"/*action\", up.Index)\n\t\tgroup.ALL(\"/cmdline\", up.Cmdline)\n\t\tgroup.ALL(\"/profile\", up.Profile)\n\t\tgroup.ALL(\"/symbol\", up.Symbol)\n\t\tgroup.ALL(\"/trace\", up.Trace)\n\t})\n}\n\n// Index shows the PProf index page.\nfunc (p *utilPProf) Index(r *Request) {\n\tvar (\n\t\tctx      = r.Context()\n\t\tprofiles = runpprof.Profiles()\n\t\taction   = r.Get(\"action\").String()\n\t\tdata     = map[string]any{\n\t\t\t\"uri\":      strings.TrimRight(r.URL.Path, \"/\") + \"/\",\n\t\t\t\"profiles\": profiles,\n\t\t}\n\t)\n\tif len(action) == 0 {\n\t\tbuffer, _ := gview.ParseContent(r.Context(), `\n            <html>\n            <head>\n                <title>GoFrame PProf</title>\n            </head>\n            {{$uri := .uri}}\n            <body>\n                profiles:<br>\n                <table>\n                    {{range .profiles}}\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td align=right>{{.Count}}</td>\n\t\t\t\t\t\t\t<td><a href=\"{{$uri}}{{.Name}}?debug=1\">{{.Name}}</a></td>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t{{end}}\n                </table>\n                <br><a href=\"{{$uri}}goroutine?debug=2\">full goroutine stack dump</a><br>\n            </body>\n            </html>\n            `, data)\n\t\tr.Response.Write(buffer)\n\t\treturn\n\t}\n\tfor _, p := range profiles {\n\t\tif p.Name() == action {\n\t\t\tif err := p.WriteTo(r.Response.Writer, r.GetRequest(\"debug\").Int()); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// Cmdline responds with the running program's\n// command line, with arguments separated by NUL bytes.\n// The package initialization registers it as /debug/pprof/cmdline.\nfunc (p *utilPProf) Cmdline(r *Request) {\n\tnetpprof.Cmdline(r.Response.Writer, r.Request)\n}\n\n// Profile responds with the pprof-formatted cpu profile.\n// Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified.\n// The package initialization registers it as /debug/pprof/profile.\nfunc (p *utilPProf) Profile(r *Request) {\n\tnetpprof.Profile(r.Response.Writer, r.Request)\n}\n\n// Symbol looks up the program counters listed in the request,\n// responding with a table mapping program counters to function names.\n// The package initialization registers it as /debug/pprof/symbol.\nfunc (p *utilPProf) Symbol(r *Request) {\n\tnetpprof.Symbol(r.Response.Writer, r.Request)\n}\n\n// Trace responds with the execution trace in binary form.\n// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.\n// The package initialization registers it as /debug/pprof/trace.\nfunc (p *utilPProf) Trace(r *Request) {\n\tnetpprof.Trace(r.Response.Writer, r.Request)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_registry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// doServiceRegister registers current service to Registry.\nfunc (s *Server) doServiceRegister() {\n\tif s.registrar == nil {\n\t\treturn\n\t}\n\ts.serviceMu.Lock()\n\tdefer s.serviceMu.Unlock()\n\tvar (\n\t\tctx      = gctx.GetInitCtx()\n\t\tprotocol = gsvc.DefaultProtocol\n\t\tinsecure = true\n\t\terr      error\n\t)\n\tif s.config.TLSConfig != nil {\n\t\tprotocol = `https`\n\t\tinsecure = false\n\t}\n\tmetadata := gsvc.Metadata{\n\t\tgsvc.MDProtocol: protocol,\n\t\tgsvc.MDInsecure: insecure,\n\t}\n\ts.service = &gsvc.LocalService{\n\t\tName:      s.GetName(),\n\t\tEndpoints: s.calculateListenedEndpoints(ctx),\n\t\tMetadata:  metadata,\n\t}\n\ts.Logger().Debugf(ctx, `service register: %+v`, s.service)\n\tif len(s.service.GetEndpoints()) == 0 {\n\t\ts.Logger().Warningf(ctx, `no endpoints found to register service, abort service registering`)\n\t\treturn\n\t}\n\tif s.service, err = s.registrar.Register(ctx, s.service); err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n}\n\n// doServiceDeregister de-registers current service from Registry.\nfunc (s *Server) doServiceDeregister() {\n\tif s.registrar == nil {\n\t\treturn\n\t}\n\ts.serviceMu.Lock()\n\tdefer s.serviceMu.Unlock()\n\tif s.service == nil {\n\t\treturn\n\t}\n\tvar ctx = gctx.GetInitCtx()\n\ts.Logger().Debugf(ctx, `service deregister: %+v`, s.service)\n\tif err := s.registrar.Deregister(ctx, s.service); err != nil {\n\t\ts.Logger().Errorf(ctx, `%+v`, err)\n\t}\n\ts.service = nil\n}\n\nfunc (s *Server) calculateListenedEndpoints(ctx context.Context) gsvc.Endpoints {\n\tvar (\n\t\tconfigAddr = s.config.Address\n\t\tendpoints  = make(gsvc.Endpoints, 0)\n\t\taddresses  = s.config.Endpoints\n\t)\n\tif configAddr == \"\" {\n\t\tconfigAddr = s.config.HTTPSAddr\n\t}\n\tif len(addresses) == 0 {\n\t\taddresses = gstr.SplitAndTrim(configAddr, \",\")\n\t}\n\tfor _, address := range addresses {\n\t\tvar (\n\t\t\taddrArray     = gstr.Split(address, \":\")\n\t\t\tlistenedIps   []string\n\t\t\tlistenedPorts []int\n\t\t)\n\t\tif len(addrArray) == 1 {\n\t\t\taddrArray = append(addrArray, gconv.String(defaultEndpointPort))\n\t\t}\n\t\t// IPs.\n\t\tswitch addrArray[0] {\n\t\tcase \"127.0.0.1\":\n\t\t\t// Nothing to do.\n\t\tcase \"0.0.0.0\", \"\":\n\t\t\tintranetIps, err := gipv4.GetIntranetIpArray()\n\t\t\tif err != nil {\n\t\t\t\ts.Logger().Errorf(ctx, `error retrieving intranet ip: %+v`, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// If no intranet ips found, it uses all ips that can be retrieved,\n\t\t\t// it may include internet ip.\n\t\t\tif len(intranetIps) == 0 {\n\t\t\t\tallIps, err := gipv4.GetIpArray()\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.Logger().Errorf(ctx, `error retrieving ip from current node: %+v`, err)\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\ts.Logger().Noticef(\n\t\t\t\t\tctx,\n\t\t\t\t\t`no intranet ip found, using internet ip to register service: %v`,\n\t\t\t\t\tallIps,\n\t\t\t\t)\n\t\t\t\tlistenedIps = allIps\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tlistenedIps = intranetIps\n\t\tdefault:\n\t\t\tlistenedIps = []string{addrArray[0]}\n\t\t}\n\t\t// Ports.\n\t\tswitch addrArray[1] {\n\t\tcase \"0\":\n\t\t\tlistenedPorts = s.GetListenedPorts()\n\t\tdefault:\n\t\t\tlistenedPorts = []int{gconv.Int(addrArray[1])}\n\t\t}\n\t\tfor _, ip := range listenedIps {\n\t\t\tfor _, port := range listenedPorts {\n\t\t\t\tendpoints = append(endpoints, gsvc.NewEndpoint(fmt.Sprintf(`%s:%d`, ip, port)))\n\t\t\t}\n\t\t}\n\t}\n\treturn endpoints\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_router.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nvar (\n\t// handlerIdGenerator is handler item id generator.\n\thandlerIdGenerator = gtype.NewInt()\n)\n\n// routerMapKey creates and returns a unique router key for given parameters.\n// This key is used for Server.routerMap attribute, which is mainly for checks for\n// repeated router registering.\nfunc (s *Server) routerMapKey(hook HookName, method, path, domain string) string {\n\treturn string(hook) + \"%\" + s.serveHandlerKey(method, path, domain)\n}\n\n// parsePattern parses the given pattern to domain, method and path variable.\nfunc (s *Server) parsePattern(pattern string) (domain, method, path string, err error) {\n\tpath = strings.TrimSpace(pattern)\n\tdomain = DefaultDomainName\n\tmethod = defaultMethod\n\tif array, err := gregex.MatchString(`([a-zA-Z]+):(.+)`, pattern); len(array) > 1 && err == nil {\n\t\tpath = strings.TrimSpace(array[2])\n\t\tif v := strings.TrimSpace(array[1]); v != \"\" {\n\t\t\tmethod = v\n\t\t}\n\t}\n\tif array, err := gregex.MatchString(`(.+)@([\\w\\.\\-]+)`, path); len(array) > 1 && err == nil {\n\t\tpath = strings.TrimSpace(array[1])\n\t\tif v := strings.TrimSpace(array[2]); v != \"\" {\n\t\t\tdomain = v\n\t\t}\n\t}\n\tif path == \"\" {\n\t\terr = gerror.NewCode(gcode.CodeInvalidParameter, \"invalid pattern: URI should not be empty\")\n\t}\n\tif path != \"/\" {\n\t\tpath = strings.TrimRight(path, \"/\")\n\t}\n\treturn\n}\n\ntype setHandlerInput struct {\n\tPrefix      string\n\tPattern     string\n\tHandlerItem *HandlerItem\n}\n\n// setHandler creates router item with a given handler and pattern and registers the handler to the router tree.\n// The router tree can be treated as a multilayer hash table, please refer to the comment in the following codes.\n// This function is called during server starts up, which cares little about the performance. What really cares\n// is the well-designed router storage structure for router searching when the request is under serving.\nfunc (s *Server) setHandler(ctx context.Context, in setHandlerInput) {\n\tvar (\n\t\tprefix  = in.Prefix\n\t\tpattern = in.Pattern\n\t\thandler = in.HandlerItem\n\t)\n\tif handler.Name == \"\" {\n\t\thandler.Name = runtime.FuncForPC(handler.Info.Value.Pointer()).Name()\n\t}\n\tif handler.Source == \"\" {\n\t\t_, file, line := gdebug.CallerWithFilter([]string{consts.StackFilterKeyForGoFrame})\n\t\thandler.Source = fmt.Sprintf(`%s:%d`, file, line)\n\t}\n\tdomain, method, uri, err := s.parsePattern(pattern)\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `invalid pattern \"%s\", %+v`, pattern, err)\n\t\treturn\n\t}\n\t// ====================================================================================\n\t// Change the registered route according to meta info from its request structure.\n\t// It supports multiple methods that are joined using char `,`.\n\t// ====================================================================================\n\tif handler.Info.Type != nil && handler.Info.Type.NumIn() == 2 {\n\t\tvar objectReq = reflect.New(handler.Info.Type.In(1))\n\t\tif v := gmeta.Get(objectReq, gtag.Path); !v.IsEmpty() {\n\t\t\turi = v.String()\n\t\t}\n\t\tif v := gmeta.Get(objectReq, gtag.Domain); !v.IsEmpty() {\n\t\t\tdomain = v.String()\n\t\t}\n\t\tif v := gmeta.Get(objectReq, gtag.Method); !v.IsEmpty() {\n\t\t\tmethod = v.String()\n\t\t}\n\t\t// Multiple methods registering, which are joined using char `,`.\n\t\tif gstr.Contains(method, \",\") {\n\t\t\tmethods := gstr.SplitAndTrim(method, \",\")\n\t\t\tfor _, v := range methods {\n\t\t\t\t// Each method has it own handler.\n\t\t\t\tclonedHandler := *handler\n\t\t\t\ts.doSetHandler(ctx, &clonedHandler, prefix, uri, pattern, v, domain)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\t// Converts `all` to `ALL`.\n\t\tif gstr.Equal(method, defaultMethod) {\n\t\t\tmethod = defaultMethod\n\t\t}\n\t}\n\ts.doSetHandler(ctx, handler, prefix, uri, pattern, method, domain)\n}\n\nfunc (s *Server) doSetHandler(\n\tctx context.Context, handler *HandlerItem,\n\tprefix, uri, pattern, method, domain string,\n) {\n\tif !s.isValidMethod(method) {\n\t\ts.Logger().Fatalf(\n\t\t\tctx,\n\t\t\t`invalid method value \"%s\", should be in \"%s\" or \"%s\"`,\n\t\t\tmethod, supportedHttpMethods, defaultMethod,\n\t\t)\n\t}\n\t// Prefix for URI feature.\n\tif prefix != \"\" {\n\t\turi = prefix + \"/\" + strings.TrimLeft(uri, \"/\")\n\t}\n\turi = strings.TrimRight(uri, \"/\")\n\tif uri == \"\" {\n\t\turi = \"/\"\n\t}\n\n\tif len(uri) == 0 || uri[0] != '/' {\n\t\ts.Logger().Fatalf(ctx, `invalid pattern \"%s\", URI should lead with '/'`, pattern)\n\t}\n\n\t// Repeated router checks, this feature can be disabled by server configuration.\n\tvar routerKey = s.routerMapKey(handler.HookName, method, uri, domain)\n\tif !s.config.RouteOverWrite {\n\t\tswitch handler.Type {\n\t\tcase HandlerTypeHandler, HandlerTypeObject:\n\t\t\tif items, ok := s.routesMap[routerKey]; ok {\n\t\t\t\tvar duplicatedHandler *HandlerItem\n\t\t\t\tfor i, item := range items {\n\t\t\t\t\tswitch item.Type {\n\t\t\t\t\tcase HandlerTypeHandler, HandlerTypeObject:\n\t\t\t\t\t\tduplicatedHandler = items[i]\n\t\t\t\t\t}\n\t\t\t\t\tif duplicatedHandler != nil {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif duplicatedHandler != nil {\n\t\t\t\t\ts.Logger().Fatalf(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\"The duplicated route registry [%s] which is meaning [{hook}%%{method}:{path}@{domain}] at \\n%s -> %s , which has already been registered at \\n%s -> %s\"+\n\t\t\t\t\t\t\t\"\\nYou can disable duplicate route detection by modifying the server.routeOverWrite configuration, but this will cause some routes to be overwritten\",\n\t\t\t\t\t\trouterKey, handler.Source, handler.Name, duplicatedHandler.Source, duplicatedHandler.Name,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// Unique id for each handler.\n\thandler.Id = handlerIdGenerator.Add(1)\n\t// Create a new router by given parameter.\n\thandler.Router = &Router{\n\t\tUri:      uri,\n\t\tDomain:   domain,\n\t\tMethod:   strings.ToUpper(method),\n\t\tPriority: strings.Count(uri[1:], \"/\"),\n\t}\n\thandler.Router.RegRule, handler.Router.RegNames = s.patternToRegular(uri)\n\n\tif _, ok := s.serveTree[domain]; !ok {\n\t\ts.serveTree[domain] = make(map[string]any)\n\t}\n\t// List array, very important for router registering.\n\t// There may be multiple lists adding into this array when searching from root to leaf.\n\tvar (\n\t\tarray []string\n\t\tlists = make([]*glist.List, 0)\n\t)\n\tif strings.EqualFold(\"/\", uri) {\n\t\tarray = []string{\"/\"}\n\t} else {\n\t\tarray = strings.Split(uri[1:], \"/\")\n\t}\n\t// Multilayer hash table:\n\t// 1. Each node of the table is separated by URI path which is split by char '/'.\n\t// 2. The key \"*fuzz\" specifies this node is a fuzzy node, which has no certain name.\n\t// 3. The key \"*list\" is the list item of the node, MOST OF THE NODES HAVE THIS ITEM,\n\t//    especially the fuzzy node. NOTE THAT the fuzzy node must have the \"*list\" item,\n\t//    and the leaf node also has \"*list\" item. If the node is not a fuzzy node either\n\t//    a leaf, it neither has \"*list\" item.\n\t// 2. The \"*list\" item is a list containing registered router items ordered by their\n\t//    priorities from high to low. If it's a fuzzy node, all the sub router items\n\t//    from this fuzzy node will also be added to its \"*list\" item.\n\t// 3. There may be repeated router items in the router lists. The lists' priorities\n\t//    from root to leaf are from low to high.\n\tvar p = s.serveTree[domain]\n\tfor i, part := range array {\n\t\t// Ignore empty URI part, like: /user//index\n\t\tif part == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\t// Check if it's a fuzzy node.\n\t\tif gregex.IsMatchString(`^[:\\*]|\\{[\\w\\.\\-]+\\}|\\*`, part) {\n\t\t\tpart = \"*fuzz\"\n\t\t\t// If it's a fuzzy node, it creates a \"*list\" item - which is a list - in the hash map.\n\t\t\t// All the sub router items from this fuzzy node will also be added to its \"*list\" item.\n\t\t\tif v, ok := p.(map[string]any)[\"*list\"]; !ok {\n\t\t\t\tnewListForFuzzy := glist.New()\n\t\t\t\tp.(map[string]any)[\"*list\"] = newListForFuzzy\n\t\t\t\tlists = append(lists, newListForFuzzy)\n\t\t\t} else {\n\t\t\t\tlists = append(lists, v.(*glist.List))\n\t\t\t}\n\t\t}\n\t\t// Make a new bucket for the current node.\n\t\tif _, ok := p.(map[string]any)[part]; !ok {\n\t\t\tp.(map[string]any)[part] = make(map[string]any)\n\t\t}\n\t\t// Loop to next bucket.\n\t\tp = p.(map[string]any)[part]\n\t\t// The leaf is a hash map and must have an item named \"*list\", which contains the router item.\n\t\t// The leaf can be furthermore extended by adding more ket-value pairs into its map.\n\t\t// Note that the `v != \"*fuzz\"` comparison is required as the list might be added in the former\n\t\t// fuzzy checks.\n\t\tif i == len(array)-1 && part != \"*fuzz\" {\n\t\t\tif v, ok := p.(map[string]any)[\"*list\"]; !ok {\n\t\t\t\tleafList := glist.New()\n\t\t\t\tp.(map[string]any)[\"*list\"] = leafList\n\t\t\t\tlists = append(lists, leafList)\n\t\t\t} else {\n\t\t\t\tlists = append(lists, v.(*glist.List))\n\t\t\t}\n\t\t}\n\t}\n\t// It iterates the list array of `lists`, compares priorities and inserts the new router item in\n\t// the proper position of each list. The priority of the list is ordered from high to low.\n\tvar item *HandlerItem\n\tfor _, l := range lists {\n\t\tpushed := false\n\t\tfor e := l.Front(); e != nil; e = e.Next() {\n\t\t\titem = e.Value.(*HandlerItem)\n\t\t\t// Checks the priority whether inserting the route item before current item,\n\t\t\t// which means it has higher priority.\n\t\t\tif s.compareRouterPriority(handler, item) {\n\t\t\t\tl.InsertBefore(e, handler)\n\t\t\t\tpushed = true\n\t\t\t\tgoto end\n\t\t\t}\n\t\t}\n\tend:\n\t\t// Just push back in default.\n\t\tif !pushed {\n\t\t\tl.PushBack(handler)\n\t\t}\n\t}\n\t// Initialize the route map item.\n\tif _, ok := s.routesMap[routerKey]; !ok {\n\t\ts.routesMap[routerKey] = make([]*HandlerItem, 0)\n\t}\n\n\t// Append the route.\n\ts.routesMap[routerKey] = append(s.routesMap[routerKey], handler)\n}\n\nfunc (s *Server) isValidMethod(method string) bool {\n\tif gstr.Equal(method, defaultMethod) {\n\t\treturn true\n\t}\n\t_, ok := methodsMap[strings.ToUpper(method)]\n\treturn ok\n}\n\n// compareRouterPriority compares the priority between `newItem` and `oldItem`. It returns true\n// if `newItem`'s priority is higher than `oldItem`, else it returns false. The higher priority\n// item will be inserted into the router list before the other one.\n//\n// Comparison rules:\n// 1. The middleware has the most high priority.\n// 2. URI: The deeper, the higher (simply check the count of char '/' in the URI).\n// 3. Route type: {xxx} > :xxx > *xxx.\nfunc (s *Server) compareRouterPriority(newItem *HandlerItem, oldItem *HandlerItem) bool {\n\t// If they're all types of middleware, the priority is according to their registered sequence.\n\tif newItem.Type == HandlerTypeMiddleware && oldItem.Type == HandlerTypeMiddleware {\n\t\treturn false\n\t}\n\t// The middleware has the most high priority.\n\tif newItem.Type == HandlerTypeMiddleware && oldItem.Type != HandlerTypeMiddleware {\n\t\treturn true\n\t}\n\t// URI: The deeper, the higher (simply check the count of char '/' in the URI).\n\tif newItem.Router.Priority > oldItem.Router.Priority {\n\t\treturn true\n\t}\n\tif newItem.Router.Priority < oldItem.Router.Priority {\n\t\treturn false\n\t}\n\n\t// Compare the length of their URI,\n\t// but the fuzzy and named parts of the URI are not calculated to the result.\n\n\t// Example:\n\t// /admin-goods-{page} > /admin-{page}\n\t// /{hash}.{type}      > /{hash}\n\tvar uriNew, uriOld string\n\turiNew, _ = gregex.ReplaceString(`\\{[^/]+?\\}`, \"\", newItem.Router.Uri)\n\turiOld, _ = gregex.ReplaceString(`\\{[^/]+?\\}`, \"\", oldItem.Router.Uri)\n\turiNew, _ = gregex.ReplaceString(`:[^/]+?`, \"\", uriNew)\n\turiOld, _ = gregex.ReplaceString(`:[^/]+?`, \"\", uriOld)\n\turiNew, _ = gregex.ReplaceString(`\\*[^/]*`, \"\", uriNew) // Replace \"/*\" and \"/*any\".\n\turiOld, _ = gregex.ReplaceString(`\\*[^/]*`, \"\", uriOld) // Replace \"/*\" and \"/*any\".\n\tif len(uriNew) > len(uriOld) {\n\t\treturn true\n\t}\n\tif len(uriNew) < len(uriOld) {\n\t\treturn false\n\t}\n\n\t// Route type checks: {xxx} > :xxx > *xxx.\n\t// Example:\n\t// /name/act > /{name}/:act\n\tvar (\n\t\tfuzzyCountFieldNew int\n\t\tfuzzyCountFieldOld int\n\t\tfuzzyCountNameNew  int\n\t\tfuzzyCountNameOld  int\n\t\tfuzzyCountAnyNew   int\n\t\tfuzzyCountAnyOld   int\n\t\tfuzzyCountTotalNew int\n\t\tfuzzyCountTotalOld int\n\t)\n\tfor _, v := range newItem.Router.Uri {\n\t\tswitch v {\n\t\tcase '{':\n\t\t\tfuzzyCountFieldNew++\n\t\tcase ':':\n\t\t\tfuzzyCountNameNew++\n\t\tcase '*':\n\t\t\tfuzzyCountAnyNew++\n\t\t}\n\t}\n\tfor _, v := range oldItem.Router.Uri {\n\t\tswitch v {\n\t\tcase '{':\n\t\t\tfuzzyCountFieldOld++\n\t\tcase ':':\n\t\t\tfuzzyCountNameOld++\n\t\tcase '*':\n\t\t\tfuzzyCountAnyOld++\n\t\t}\n\t}\n\tfuzzyCountTotalNew = fuzzyCountFieldNew + fuzzyCountNameNew + fuzzyCountAnyNew\n\tfuzzyCountTotalOld = fuzzyCountFieldOld + fuzzyCountNameOld + fuzzyCountAnyOld\n\tif fuzzyCountTotalNew < fuzzyCountTotalOld {\n\t\treturn true\n\t}\n\tif fuzzyCountTotalNew > fuzzyCountTotalOld {\n\t\treturn false\n\t}\n\n\t// If the counts of their fuzzy rules are equal.\n\n\t// Eg: /name/{act} > /name/:act\n\tif fuzzyCountFieldNew > fuzzyCountFieldOld {\n\t\treturn true\n\t}\n\tif fuzzyCountFieldNew < fuzzyCountFieldOld {\n\t\treturn false\n\t}\n\t// Eg: /name/:act > /name/*act\n\tif fuzzyCountNameNew > fuzzyCountNameOld {\n\t\treturn true\n\t}\n\tif fuzzyCountNameNew < fuzzyCountNameOld {\n\t\treturn false\n\t}\n\n\t// It then compares the accuracy of their http method,\n\t// the more accurate the more priority.\n\tif newItem.Router.Method != defaultMethod {\n\t\treturn true\n\t}\n\tif oldItem.Router.Method != defaultMethod {\n\t\treturn true\n\t}\n\n\t// If they have different router type,\n\t// the new router item has more priority than the other one.\n\tif newItem.Type == HandlerTypeHandler || newItem.Type == HandlerTypeObject {\n\t\treturn true\n\t}\n\n\t// Other situations, like HOOK items,\n\t// the old router item has more priority than the other one.\n\treturn false\n}\n\n// patternToRegular converts route rule to according to regular expression.\nfunc (s *Server) patternToRegular(rule string) (regular string, names []string) {\n\tif len(rule) < 2 {\n\t\treturn rule, nil\n\t}\n\tregular = \"^\"\n\tvar array = strings.Split(rule[1:], \"/\")\n\tfor _, v := range array {\n\t\tif len(v) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch v[0] {\n\t\tcase ':':\n\t\t\tif len(v) > 1 {\n\t\t\t\tregular += `/([^/]+)`\n\t\t\t\tnames = append(names, v[1:])\n\t\t\t} else {\n\t\t\t\tregular += `/[^/]+`\n\t\t\t}\n\t\tcase '*':\n\t\t\tif len(v) > 1 {\n\t\t\t\tregular += `/{0,1}(.*)`\n\t\t\t\tnames = append(names, v[1:])\n\t\t\t} else {\n\t\t\t\tregular += `/{0,1}.*`\n\t\t\t}\n\t\tdefault:\n\t\t\t// Special chars replacement.\n\t\t\tv = gstr.ReplaceByMap(v, map[string]string{\n\t\t\t\t`.`: `\\.`,\n\t\t\t\t`+`: `\\+`,\n\t\t\t\t`*`: `.*`,\n\t\t\t})\n\t\t\ts, _ := gregex.ReplaceStringFunc(`\\{[\\w\\.\\-]+\\}`, v, func(s string) string {\n\t\t\t\tnames = append(names, s[1:len(s)-1])\n\t\t\t\treturn `([^/]+)`\n\t\t\t})\n\t\t\tif strings.EqualFold(s, v) {\n\t\t\t\tregular += \"/\" + v\n\t\t\t} else {\n\t\t\t\tregular += \"/\" + s\n\t\t\t}\n\t\t}\n\t}\n\tregular += `$`\n\treturn\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_router_group.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype (\n\t// RouterGroup is a group wrapping multiple routes and middleware.\n\tRouterGroup struct {\n\t\tparent     *RouterGroup  // Parent group.\n\t\tserver     *Server       // Server.\n\t\tdomain     *Domain       // Domain.\n\t\tprefix     string        // Prefix for sub-route.\n\t\tmiddleware []HandlerFunc // Middleware array.\n\t}\n\n\t// preBindItem is item for lazy registering feature of router group. preBindItem is not really registered\n\t// to server when route function of the group called but is lazily registered when server starts.\n\tpreBindItem struct {\n\t\tgroup    *RouterGroup\n\t\tbindType string\n\t\tpattern  string\n\t\tobject   any    // Can be handler, controller or object.\n\t\tparams   []any  // Extra parameters for route registering depending on the type.\n\t\tsource   string // Handler is a register at a certain source file path: line.\n\t\tbound    bool   // Is this item bound to server?\n\t}\n)\n\nconst (\n\tgroupBindTypeHandler    = \"HANDLER\"\n\tgroupBindTypeRest       = \"REST\"\n\tgroupBindTypeHook       = \"HOOK\"\n\tgroupBindTypeMiddleware = \"MIDDLEWARE\"\n)\n\nvar (\n\tpreBindItems = make([]*preBindItem, 0, 64)\n)\n\n// handlePreBindItems is called when server starts, which does really route registering to the server.\nfunc (s *Server) handlePreBindItems(ctx context.Context) {\n\tif len(preBindItems) == 0 {\n\t\treturn\n\t}\n\tfor _, item := range preBindItems {\n\t\tif item.bound {\n\t\t\tcontinue\n\t\t}\n\t\t// Handle the items of current server.\n\t\tif item.group.server != nil && item.group.server != s {\n\t\t\tcontinue\n\t\t}\n\t\tif item.group.domain != nil && item.group.domain.server != s {\n\t\t\tcontinue\n\t\t}\n\t\titem.group.doBindRoutersToServer(ctx, item)\n\t\titem.bound = true\n\t}\n}\n\n// Group creates and returns a RouterGroup object.\nfunc (s *Server) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {\n\tif len(prefix) > 0 && prefix[0] != '/' {\n\t\tprefix = \"/\" + prefix\n\t}\n\tif prefix == \"/\" {\n\t\tprefix = \"\"\n\t}\n\tgroup := &RouterGroup{\n\t\tserver: s,\n\t\tprefix: prefix,\n\t}\n\tif len(groups) > 0 {\n\t\tfor _, v := range groups {\n\t\t\tv(group)\n\t\t}\n\t}\n\treturn group\n}\n\n// Group creates and returns a RouterGroup object, which is bound to a specified domain.\nfunc (d *Domain) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {\n\tif len(prefix) > 0 && prefix[0] != '/' {\n\t\tprefix = \"/\" + prefix\n\t}\n\tif prefix == \"/\" {\n\t\tprefix = \"\"\n\t}\n\trouterGroup := &RouterGroup{\n\t\tdomain: d,\n\t\tserver: d.server,\n\t\tprefix: prefix,\n\t}\n\tif len(groups) > 0 {\n\t\tfor _, nestedGroup := range groups {\n\t\t\tnestedGroup(routerGroup)\n\t\t}\n\t}\n\treturn routerGroup\n}\n\n// Group creates and returns a subgroup of the current router group.\nfunc (g *RouterGroup) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {\n\tif prefix == \"/\" {\n\t\tprefix = \"\"\n\t}\n\tgroup := &RouterGroup{\n\t\tparent: g,\n\t\tserver: g.server,\n\t\tdomain: g.domain,\n\t\tprefix: prefix,\n\t}\n\tif len(g.middleware) > 0 {\n\t\tgroup.middleware = make([]HandlerFunc, len(g.middleware))\n\t\tcopy(group.middleware, g.middleware)\n\t}\n\tif len(groups) > 0 {\n\t\tfor _, v := range groups {\n\t\t\tv(group)\n\t\t}\n\t}\n\treturn group\n}\n\n// Clone returns a new router group which is a clone of the current group.\nfunc (g *RouterGroup) Clone() *RouterGroup {\n\tnewGroup := &RouterGroup{\n\t\tparent:     g.parent,\n\t\tserver:     g.server,\n\t\tdomain:     g.domain,\n\t\tprefix:     g.prefix,\n\t\tmiddleware: make([]HandlerFunc, len(g.middleware)),\n\t}\n\tcopy(newGroup.middleware, g.middleware)\n\treturn newGroup\n}\n\n// Bind does batch route registering feature for a router group.\nfunc (g *RouterGroup) Bind(handlerOrObject ...any) *RouterGroup {\n\tvar (\n\t\tctx   = context.TODO()\n\t\tgroup = g.Clone()\n\t)\n\tfor _, v := range handlerOrObject {\n\t\tvar (\n\t\t\titem               = v\n\t\t\toriginValueAndKind = reflection.OriginValueAndKind(item)\n\t\t)\n\n\t\tswitch originValueAndKind.OriginKind {\n\t\tcase reflect.Func, reflect.Struct:\n\t\t\tgroup = group.preBindToLocalArray(\n\t\t\t\tgroupBindTypeHandler,\n\t\t\t\t\"/\",\n\t\t\t\titem,\n\t\t\t)\n\n\t\tdefault:\n\t\t\tg.server.Logger().Fatalf(\n\t\t\t\tctx, \"invalid bind parameter type: %v, should be route function or struct object\",\n\t\t\t\toriginValueAndKind.InputValue.Type(),\n\t\t\t)\n\t\t}\n\t}\n\treturn group\n}\n\n// ALL register an http handler to give the route pattern and all http methods.\nfunc (g *RouterGroup) ALL(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(\n\t\tgroupBindTypeHandler,\n\t\tdefaultMethod+\":\"+pattern,\n\t\tobject,\n\t\tparams...,\n\t)\n}\n\n// ALLMap registers http handlers for http methods using map.\nfunc (g *RouterGroup) ALLMap(m map[string]any) {\n\tfor pattern, object := range m {\n\t\tg.ALL(pattern, object)\n\t}\n}\n\n// Map registers http handlers for http methods using map.\nfunc (g *RouterGroup) Map(m map[string]any) {\n\tfor pattern, object := range m {\n\t\tg.preBindToLocalArray(groupBindTypeHandler, pattern, object)\n\t}\n}\n\n// GET registers an http handler to give the route pattern and the http method: GET.\nfunc (g *RouterGroup) GET(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"GET:\"+pattern, object, params...)\n}\n\n// PUT registers an http handler to give the route pattern and the http method: PUT.\nfunc (g *RouterGroup) PUT(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"PUT:\"+pattern, object, params...)\n}\n\n// POST registers an http handler to give the route pattern and the http method: POST.\nfunc (g *RouterGroup) POST(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"POST:\"+pattern, object, params...)\n}\n\n// DELETE registers an http handler to give the route pattern and the http method: DELETE.\nfunc (g *RouterGroup) DELETE(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"DELETE:\"+pattern, object, params...)\n}\n\n// PATCH registers an http handler to give the route pattern and the http method: PATCH.\nfunc (g *RouterGroup) PATCH(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"PATCH:\"+pattern, object, params...)\n}\n\n// HEAD registers an http handler to give the route pattern and the http method: HEAD.\nfunc (g *RouterGroup) HEAD(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"HEAD:\"+pattern, object, params...)\n}\n\n// CONNECT registers an http handler to give the route pattern and the http method: CONNECT.\nfunc (g *RouterGroup) CONNECT(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"CONNECT:\"+pattern, object, params...)\n}\n\n// OPTIONS register an http handler to give the route pattern and the http method: OPTIONS.\nfunc (g *RouterGroup) OPTIONS(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"OPTIONS:\"+pattern, object, params...)\n}\n\n// TRACE registers an http handler to give the route pattern and the http method: TRACE.\nfunc (g *RouterGroup) TRACE(pattern string, object any, params ...any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, \"TRACE:\"+pattern, object, params...)\n}\n\n// REST registers an http handler to give the route pattern according to REST rule.\nfunc (g *RouterGroup) REST(pattern string, object any) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeRest, pattern, object)\n}\n\n// Hook registers a hook to given route pattern.\nfunc (g *RouterGroup) Hook(pattern string, hook HookName, handler HandlerFunc) *RouterGroup {\n\treturn g.Clone().preBindToLocalArray(groupBindTypeHandler, pattern, handler, hook)\n}\n\n// Middleware binds one or more middleware to the router group.\nfunc (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {\n\tg.middleware = append(g.middleware, handlers...)\n\treturn g\n}\n\n// preBindToLocalArray adds the route registering parameters to an internal variable array for lazily registering feature.\nfunc (g *RouterGroup) preBindToLocalArray(bindType string, pattern string, object any, params ...any) *RouterGroup {\n\t_, file, line := gdebug.CallerWithFilter([]string{consts.StackFilterKeyForGoFrame})\n\tpreBindItems = append(preBindItems, &preBindItem{\n\t\tgroup:    g,\n\t\tbindType: bindType,\n\t\tpattern:  pattern,\n\t\tobject:   object,\n\t\tparams:   params,\n\t\tsource:   fmt.Sprintf(`%s:%d`, file, line),\n\t})\n\treturn g\n}\n\n// getPrefix returns the route prefix of the group, which recursively retrieves its parent's prefix.\nfunc (g *RouterGroup) getPrefix() string {\n\tprefix := g.prefix\n\tparent := g.parent\n\tfor parent != nil {\n\t\tprefix = parent.prefix + prefix\n\t\tparent = parent.parent\n\t}\n\treturn prefix\n}\n\n// doBindRoutersToServer does really register for the group.\nfunc (g *RouterGroup) doBindRoutersToServer(ctx context.Context, item *preBindItem) *RouterGroup {\n\tvar (\n\t\tbindType = item.bindType\n\t\tpattern  = item.pattern\n\t\tobject   = item.object\n\t\tparams   = item.params\n\t\tsource   = item.source\n\t)\n\tprefix := g.getPrefix()\n\t// Route check.\n\tif len(prefix) > 0 {\n\t\tdomain, method, path, err := g.server.parsePattern(pattern)\n\t\tif err != nil {\n\t\t\tg.server.Logger().Fatalf(ctx, \"invalid route pattern: %s\", pattern)\n\t\t}\n\t\t// If there is already a domain, unset the domain field in the pattern.\n\t\tif g.domain != nil {\n\t\t\tdomain = \"\"\n\t\t}\n\t\tif bindType == groupBindTypeRest {\n\t\t\tpattern = path\n\t\t} else {\n\t\t\tpattern = g.server.serveHandlerKey(\n\t\t\t\tmethod, path, domain,\n\t\t\t)\n\t\t}\n\t}\n\t// Filter repeated char '/'.\n\tpattern = gstr.Replace(pattern, \"//\", \"/\")\n\n\t// Convert params to a string array.\n\textras := gconv.Strings(params)\n\n\t// Check whether it's a hook handler.\n\tif _, ok := object.(HandlerFunc); ok && len(extras) > 0 {\n\t\tbindType = groupBindTypeHook\n\t}\n\tswitch bindType {\n\tcase groupBindTypeHandler:\n\t\tif reflect.ValueOf(object).Kind() == reflect.Func {\n\t\t\tfuncInfo, err := g.server.checkAndCreateFuncInfo(object, \"\", \"\", \"\")\n\t\t\tif err != nil {\n\t\t\t\tg.server.Logger().Fatal(ctx, err.Error())\n\t\t\t\treturn g\n\t\t\t}\n\t\t\tin := doBindHandlerInput{\n\t\t\t\tPrefix:     prefix,\n\t\t\t\tPattern:    pattern,\n\t\t\t\tFuncInfo:   funcInfo,\n\t\t\t\tMiddleware: g.middleware,\n\t\t\t\tSource:     source,\n\t\t\t}\n\t\t\tif g.domain != nil {\n\t\t\t\tg.domain.doBindHandler(ctx, in)\n\t\t\t} else {\n\t\t\t\tg.server.doBindHandler(ctx, in)\n\t\t\t}\n\t\t} else {\n\t\t\tif len(extras) > 0 {\n\t\t\t\tif gstr.Contains(extras[0], \",\") {\n\t\t\t\t\tin := doBindObjectInput{\n\t\t\t\t\t\tPrefix:     prefix,\n\t\t\t\t\t\tPattern:    pattern,\n\t\t\t\t\t\tObject:     object,\n\t\t\t\t\t\tMethod:     extras[0],\n\t\t\t\t\t\tMiddleware: g.middleware,\n\t\t\t\t\t\tSource:     source,\n\t\t\t\t\t}\n\t\t\t\t\tif g.domain != nil {\n\t\t\t\t\t\tg.domain.doBindObject(ctx, in)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tg.server.doBindObject(ctx, in)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tin := doBindObjectMethodInput{\n\t\t\t\t\t\tPrefix:     prefix,\n\t\t\t\t\t\tPattern:    pattern,\n\t\t\t\t\t\tObject:     object,\n\t\t\t\t\t\tMethod:     extras[0],\n\t\t\t\t\t\tMiddleware: g.middleware,\n\t\t\t\t\t\tSource:     source,\n\t\t\t\t\t}\n\t\t\t\t\tif g.domain != nil {\n\t\t\t\t\t\tg.domain.doBindObjectMethod(ctx, in)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tg.server.doBindObjectMethod(ctx, in)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tin := doBindObjectInput{\n\t\t\t\t\tPrefix:     prefix,\n\t\t\t\t\tPattern:    pattern,\n\t\t\t\t\tObject:     object,\n\t\t\t\t\tMethod:     \"\",\n\t\t\t\t\tMiddleware: g.middleware,\n\t\t\t\t\tSource:     source,\n\t\t\t\t}\n\t\t\t\t// Finally, it treats the `object` as the Object registering type.\n\t\t\t\tif g.domain != nil {\n\t\t\t\t\tg.domain.doBindObject(ctx, in)\n\t\t\t\t} else {\n\t\t\t\t\tg.server.doBindObject(ctx, in)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase groupBindTypeRest:\n\t\tin := doBindObjectInput{\n\t\t\tPrefix:     prefix,\n\t\t\tPattern:    pattern,\n\t\t\tObject:     object,\n\t\t\tMethod:     \"\",\n\t\t\tMiddleware: g.middleware,\n\t\t\tSource:     source,\n\t\t}\n\t\tif g.domain != nil {\n\t\t\tg.domain.doBindObjectRest(ctx, in)\n\t\t} else {\n\t\t\tg.server.doBindObjectRest(ctx, in)\n\t\t}\n\n\tcase groupBindTypeHook:\n\t\tif handler, ok := object.(HandlerFunc); ok {\n\t\t\tin := doBindHookHandlerInput{\n\t\t\t\tPrefix:   prefix,\n\t\t\t\tPattern:  pattern,\n\t\t\t\tHookName: HookName(extras[0]),\n\t\t\t\tHandler:  handler,\n\t\t\t\tSource:   source,\n\t\t\t}\n\t\t\tif g.domain != nil {\n\t\t\t\tg.domain.doBindHookHandler(ctx, in)\n\t\t\t} else {\n\t\t\t\tg.server.doBindHookHandler(ctx, in)\n\t\t\t}\n\t\t} else {\n\t\t\tg.server.Logger().Fatalf(ctx, \"invalid hook handler for pattern: %s\", pattern)\n\t\t}\n\t}\n\treturn g\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_router_hook.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n)\n\n// BindHookHandler registers handler for specified hook.\nfunc (s *Server) BindHookHandler(pattern string, hook HookName, handler HandlerFunc) {\n\ts.doBindHookHandler(context.TODO(), doBindHookHandlerInput{\n\t\tPrefix:   \"\",\n\t\tPattern:  pattern,\n\t\tHookName: hook,\n\t\tHandler:  handler,\n\t\tSource:   \"\",\n\t})\n}\n\n// doBindHookHandlerInput is the input for BindHookHandler.\ntype doBindHookHandlerInput struct {\n\tPrefix   string\n\tPattern  string\n\tHookName HookName\n\tHandler  HandlerFunc\n\tSource   string\n}\n\n// doBindHookHandler is the internal handler for BindHookHandler.\nfunc (s *Server) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {\n\ts.setHandler(\n\t\tctx,\n\t\tsetHandlerInput{\n\t\t\tPrefix:  in.Prefix,\n\t\t\tPattern: in.Pattern,\n\t\t\tHandlerItem: &HandlerItem{\n\t\t\t\tType: HandlerTypeHook,\n\t\t\t\tName: gdebug.FuncPath(in.Handler),\n\t\t\t\tInfo: handlerFuncInfo{\n\t\t\t\t\tFunc: in.Handler,\n\t\t\t\t\tType: reflect.TypeOf(in.Handler),\n\t\t\t\t},\n\t\t\t\tHookName: in.HookName,\n\t\t\t\tSource:   in.Source,\n\t\t\t},\n\t\t},\n\t)\n}\n\n// BindHookHandlerByMap registers handler for specified hook.\nfunc (s *Server) BindHookHandlerByMap(pattern string, hookMap map[HookName]HandlerFunc) {\n\tfor k, v := range hookMap {\n\t\ts.BindHookHandler(pattern, k, v)\n\t}\n}\n\n// callHookHandler calls the hook handler by their registered sequences.\nfunc (s *Server) callHookHandler(hook HookName, r *Request) {\n\tif !r.hasHookHandler {\n\t\treturn\n\t}\n\thookItems := r.getHookHandlers(hook)\n\tif len(hookItems) > 0 {\n\t\t// Backup the old router variable map.\n\t\toldRouterMap := r.routerMap\n\t\tfor _, item := range hookItems {\n\t\t\tr.routerMap = item.Values\n\t\t\t// DO NOT USE the router of the hook handler,\n\t\t\t// which can overwrite the router of serving handler.\n\t\t\t// r.Router = item.handler.router\n\t\t\tif err := s.niceCallHookHandler(item.Handler.Info.Func, r); err != nil {\n\t\t\t\tswitch err {\n\t\t\t\tcase exceptionExit:\n\t\t\t\t\tbreak\n\t\t\t\tcase exceptionExitAll:\n\t\t\t\t\tfallthrough\n\t\t\t\tcase exceptionExitHook:\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t\tr.Response.WriteStatus(http.StatusInternalServerError, err)\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Restore the old router variable map.\n\t\tr.routerMap = oldRouterMap\n\t}\n}\n\n// getHookHandlers retrieves and returns the hook handlers of specified hook.\nfunc (r *Request) getHookHandlers(hook HookName) []*HandlerItemParsed {\n\tparsedItems := make([]*HandlerItemParsed, 0, 4)\n\tfor _, v := range r.handlers {\n\t\tif v.Handler.HookName != hook {\n\t\t\tcontinue\n\t\t}\n\t\titem := v\n\t\tparsedItems = append(parsedItems, item)\n\t}\n\treturn parsedItems\n}\n\n// niceCallHookHandler nicely calls the hook handler function,\n// which means it automatically catches and returns the possible panic error to\n// avoid goroutine crash.\nfunc (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err any) {\n\tdefer func() {\n\t\terr = recover()\n\t}()\n\tf(r)\n\treturn\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_router_middleware.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n)\n\nconst (\n\t// The default route pattern for global middleware.\n\tdefaultMiddlewarePattern = \"/*\"\n)\n\n// BindMiddleware registers one or more global middleware to the server.\n// Global middleware can be used standalone without service handler, which intercepts all dynamic requests\n// before or after service handler. The parameter `pattern` specifies what route pattern the middleware intercepts,\n// which is usually a \"fuzzy\" pattern like \"/:name\", \"/*any\" or \"/{field}\".\nfunc (s *Server) BindMiddleware(pattern string, handlers ...HandlerFunc) {\n\tvar (\n\t\tctx = context.TODO()\n\t)\n\tfor _, handler := range handlers {\n\t\ts.setHandler(ctx, setHandlerInput{\n\t\t\tPrefix:  \"\",\n\t\t\tPattern: pattern,\n\t\t\tHandlerItem: &HandlerItem{\n\t\t\t\tType: HandlerTypeMiddleware,\n\t\t\t\tName: gdebug.FuncPath(handler),\n\t\t\t\tInfo: handlerFuncInfo{\n\t\t\t\t\tFunc: handler,\n\t\t\t\t\tType: reflect.TypeOf(handler),\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n}\n\n// BindMiddlewareDefault registers one or more global middleware to the server using default pattern \"/*\".\n// Global middleware can be used standalone without service handler, which intercepts all dynamic requests\n// before or after service handler.\nfunc (s *Server) BindMiddlewareDefault(handlers ...HandlerFunc) {\n\tvar (\n\t\tctx = context.TODO()\n\t)\n\tfor _, handler := range handlers {\n\t\ts.setHandler(ctx, setHandlerInput{\n\t\t\tPrefix:  \"\",\n\t\t\tPattern: defaultMiddlewarePattern,\n\t\t\tHandlerItem: &HandlerItem{\n\t\t\t\tType: HandlerTypeMiddleware,\n\t\t\t\tName: gdebug.FuncPath(handler),\n\t\t\t\tInfo: handlerFuncInfo{\n\t\t\t\t\tFunc: handler,\n\t\t\t\t\tType: reflect.TypeOf(handler),\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n}\n\n// Use is the alias of BindMiddlewareDefault.\n// See BindMiddlewareDefault.\nfunc (s *Server) Use(handlers ...HandlerFunc) {\n\ts.BindMiddlewareDefault(handlers...)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_router_serve.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\n// handlerCacheItem is an item just for internal router searching cache.\ntype handlerCacheItem struct {\n\tparsedItems []*HandlerItemParsed\n\tserveItem   *HandlerItemParsed\n\thasHook     bool\n\thasServe    bool\n}\n\n// serveHandlerKey creates and returns a handler key for router.\nfunc (s *Server) serveHandlerKey(method, path, domain string) string {\n\tif len(domain) > 0 {\n\t\tdomain = \"@\" + domain\n\t}\n\tif method == \"\" {\n\t\treturn path + strings.ToLower(domain)\n\t}\n\treturn strings.ToUpper(method) + \":\" + path + strings.ToLower(domain)\n}\n\n// getHandlersWithCache searches the router item with cache feature for a given request.\nfunc (s *Server) getHandlersWithCache(r *Request) (parsedItems []*HandlerItemParsed, serveItem *HandlerItemParsed, hasHook, hasServe bool) {\n\tvar (\n\t\tctx    = r.Context()\n\t\tmethod = r.Method\n\t\tpath   = r.URL.Path\n\t\thost   = r.GetHost()\n\t)\n\t// In case of, eg:\n\t// Case 1:\n\t// \t\tGET /net/http\n\t// \t\tr.URL.Path    : /net/http\n\t// \t\tr.URL.RawPath : (empty string)\n\t// Case 2:\n\t// \t\tGET /net%2Fhttp\n\t// \t\tr.URL.Path    : /net/http\n\t// \t\tr.URL.RawPath : /net%2Fhttp\n\tif r.URL.RawPath != \"\" {\n\t\tpath = r.URL.RawPath\n\t}\n\t// Special http method OPTIONS handling.\n\t// It searches the handler with the request method instead of OPTIONS method.\n\tif method == http.MethodOptions {\n\t\tif v := r.Header.Get(\"Access-Control-Request-Method\"); v != \"\" {\n\t\t\tmethod = v\n\t\t}\n\t}\n\t// Search and cache the router handlers.\n\tif xUrlPath := r.Header.Get(HeaderXUrlPath); xUrlPath != \"\" {\n\t\tpath = xUrlPath\n\t}\n\tvar handlerCacheKey = s.serveHandlerKey(method, path, host)\n\tvalue, err := s.serveCache.GetOrSetFunc(ctx, handlerCacheKey, func(ctx context.Context) (any, error) {\n\t\tparsedItems, serveItem, hasHook, hasServe = s.searchHandlers(method, path, host)\n\t\tif parsedItems != nil {\n\t\t\treturn &handlerCacheItem{parsedItems, serveItem, hasHook, hasServe}, nil\n\t\t}\n\t\treturn nil, nil\n\t}, routeCacheDuration)\n\tif err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t}\n\tif value != nil {\n\t\titem := value.Val().(*handlerCacheItem)\n\t\treturn item.parsedItems, item.serveItem, item.hasHook, item.hasServe\n\t}\n\treturn\n}\n\n// searchHandlers retrieve and returns the routers with given parameters.\n// Note that the returned routers contain serving handler, middleware handlers and hook handlers.\nfunc (s *Server) searchHandlers(method, path, domain string) (parsedItems []*HandlerItemParsed, serveItem *HandlerItemParsed, hasHook, hasServe bool) {\n\tif len(path) == 0 {\n\t\treturn nil, nil, false, false\n\t}\n\t// In case of double '/' URI, for example:\n\t// /user//index, //user/index, //user//index//\n\tvar previousIsSep = false\n\tfor i := 0; i < len(path); {\n\t\tif path[i] == '/' {\n\t\t\tif previousIsSep {\n\t\t\t\tpath = path[:i] + path[i+1:]\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\tpreviousIsSep = true\n\t\t\t}\n\t\t} else {\n\t\t\tpreviousIsSep = false\n\t\t}\n\t\ti++\n\t}\n\t// Split the URL.path to separate parts.\n\tvar array []string\n\tif strings.EqualFold(\"/\", path) {\n\t\tarray = []string{\"/\"}\n\t} else {\n\t\tarray = strings.Split(path[1:], \"/\")\n\t}\n\tvar (\n\t\tlastMiddlewareElem    *glist.TElement[*HandlerItemParsed]\n\t\tparsedItemList        = glist.NewT[*HandlerItemParsed]()\n\t\trepeatHandlerCheckMap = make(map[int]struct{}, 16)\n\t)\n\n\t// The default domain has the most priority when iteration.\n\t// Please see doSetHandler if you want to get known about the structure of serveTree.\n\tfor _, domainItem := range []string{DefaultDomainName, domain} {\n\t\tp, ok := s.serveTree[domainItem]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\t// Make a list array with a capacity of 16.\n\t\tlists := make([]*glist.List, 0, 16)\n\t\tfor i, part := range array {\n\t\t\t// Add all lists of each node to the list array.\n\t\t\tif v, ok := p.(map[string]any)[\"*list\"]; ok {\n\t\t\t\tlists = append(lists, v.(*glist.List))\n\t\t\t}\n\t\t\tif v, ok := p.(map[string]any)[part]; ok {\n\t\t\t\t// Loop to the next node by certain key name.\n\t\t\t\tp = v\n\t\t\t\tif i == len(array)-1 {\n\t\t\t\t\tif v, ok := p.(map[string]any)[\"*list\"]; ok {\n\t\t\t\t\t\tlists = append(lists, v.(*glist.List))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if v, ok := p.(map[string]any)[\"*fuzz\"]; ok {\n\t\t\t\t// Loop to the next node by fuzzy node item.\n\t\t\t\tp = v\n\t\t\t}\n\t\t\tif i == len(array)-1 {\n\t\t\t\t// It here also checks the fuzzy item,\n\t\t\t\t// for rule case like: \"/user/*action\" matches to \"/user\".\n\t\t\t\tif v, ok := p.(map[string]any)[\"*fuzz\"]; ok {\n\t\t\t\t\tp = v\n\t\t\t\t}\n\t\t\t\t// The leaf must have a list item. It adds the list to the list array.\n\t\t\t\tif v, ok := p.(map[string]any)[\"*list\"]; ok {\n\t\t\t\t\tlists = append(lists, v.(*glist.List))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// OK, let's loop the result list array, adding the handler item to the result handler result array.\n\t\t// As the tail of the list array has the most priority, it iterates the list array from its tail to head.\n\t\tfor i := len(lists) - 1; i >= 0; i-- {\n\t\t\tfor e := lists[i].Front(); e != nil; e = e.Next() {\n\t\t\t\titem := e.Value.(*HandlerItem)\n\t\t\t\t// Filter repeated handler items, especially the middleware and hook handlers.\n\t\t\t\t// It is necessary, do not remove this checks logic unless you really know how it is necessary.\n\t\t\t\t//\n\t\t\t\t// The `repeatHandlerCheckMap` is used for repeat handler filtering during handler searching.\n\t\t\t\t// As there are fuzzy nodes, and the fuzzy nodes have both sub-nodes and sub-list nodes, there\n\t\t\t\t// may be repeated handler items in both sub-nodes and sub-list nodes. It here uses handler item id to\n\t\t\t\t// identify the same handler item that registered.\n\t\t\t\t//\n\t\t\t\t// The same handler item is the one that is registered in the same function doSetHandler.\n\t\t\t\t// Note that, one handler function(middleware or hook function) may be registered multiple times as\n\t\t\t\t// different handler items using function doSetHandler, and they have different handler item id.\n\t\t\t\t//\n\t\t\t\t// Note that twice, the handler function may be registered multiple times as different handler items.\n\t\t\t\tif _, isRepeatedHandler := repeatHandlerCheckMap[item.Id]; isRepeatedHandler {\n\t\t\t\t\tcontinue\n\t\t\t\t} else {\n\t\t\t\t\trepeatHandlerCheckMap[item.Id] = struct{}{}\n\t\t\t\t}\n\t\t\t\t// Serving handler can only be added to the handler array just once.\n\t\t\t\t// The first route item in the list has the most priority than the rest.\n\t\t\t\t// This ignoring can implement route overwritten feature.\n\t\t\t\tif hasServe {\n\t\t\t\t\tswitch item.Type {\n\t\t\t\t\tcase HandlerTypeHandler, HandlerTypeObject:\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif item.Router.Method == defaultMethod || item.Router.Method == method {\n\t\t\t\t\t// Note the rule having no fuzzy rules: len(match) == 1\n\t\t\t\t\tif match, err := gregex.MatchString(item.Router.RegRule, path); err == nil && len(match) > 0 {\n\t\t\t\t\t\tparsedItem := &HandlerItemParsed{item, nil}\n\t\t\t\t\t\t// If the rule contains fuzzy names,\n\t\t\t\t\t\t// it needs paring the URL to retrieve the values for the names.\n\t\t\t\t\t\tif len(item.Router.RegNames) > 0 {\n\t\t\t\t\t\t\tif len(match) > len(item.Router.RegNames) {\n\t\t\t\t\t\t\t\tparsedItem.Values = make(map[string]string)\n\t\t\t\t\t\t\t\t// It there repeated names, it just overwrites the same one.\n\t\t\t\t\t\t\t\tfor i, name := range item.Router.RegNames {\n\t\t\t\t\t\t\t\t\tparsedItem.Values[name], _ = gurl.Decode(match[i+1])\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tswitch item.Type {\n\t\t\t\t\t\t// The serving handler can be added just once.\n\t\t\t\t\t\tcase HandlerTypeHandler, HandlerTypeObject:\n\t\t\t\t\t\t\thasServe = true\n\t\t\t\t\t\t\tserveItem = parsedItem\n\t\t\t\t\t\t\tparsedItemList.PushBack(parsedItem)\n\n\t\t\t\t\t\t// The middleware is inserted before the serving handler.\n\t\t\t\t\t\t// If there are multiple middleware, they're inserted into the result list by their registering order.\n\t\t\t\t\t\t// The middleware is also executed by their registered order.\n\t\t\t\t\t\tcase HandlerTypeMiddleware:\n\t\t\t\t\t\t\tif lastMiddlewareElem == nil {\n\t\t\t\t\t\t\t\tlastMiddlewareElem = parsedItemList.PushFront(parsedItem)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tlastMiddlewareElem = parsedItemList.InsertAfter(lastMiddlewareElem, parsedItem)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// HOOK handler, just push it back to the list.\n\t\t\t\t\t\tcase HandlerTypeHook:\n\t\t\t\t\t\t\thasHook = true\n\t\t\t\t\t\t\tparsedItemList.PushBack(parsedItem)\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tpanic(gerror.Newf(`invalid handler type %s`, item.Type))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif parsedItemList.Len() > 0 {\n\t\tvar index = 0\n\t\tparsedItems = make([]*HandlerItemParsed, parsedItemList.Len())\n\t\tfor e := parsedItemList.Front(); e != nil; e = e.Next() {\n\t\t\tparsedItems[index] = e.Value\n\t\t\tindex++\n\t\t}\n\t}\n\treturn\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (h *HandlerItem) MarshalJSON() ([]byte, error) {\n\tswitch h.Type {\n\tcase HandlerTypeHook:\n\t\treturn json.Marshal(\n\t\t\tfmt.Sprintf(\n\t\t\t\t`%s %s:%s (%s)`,\n\t\t\t\th.Router.Uri,\n\t\t\t\th.Router.Domain,\n\t\t\t\th.Router.Method,\n\t\t\t\th.HookName,\n\t\t\t),\n\t\t)\n\tcase HandlerTypeMiddleware:\n\t\treturn json.Marshal(\n\t\t\tfmt.Sprintf(\n\t\t\t\t`%s %s:%s (MIDDLEWARE)`,\n\t\t\t\th.Router.Uri,\n\t\t\t\th.Router.Domain,\n\t\t\t\th.Router.Method,\n\t\t\t),\n\t\t)\n\tdefault:\n\t\treturn json.Marshal(\n\t\t\tfmt.Sprintf(\n\t\t\t\t`%s %s:%s`,\n\t\t\t\th.Router.Uri,\n\t\t\t\th.Router.Domain,\n\t\t\t\th.Router.Method,\n\t\t\t),\n\t\t)\n\t}\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (h *HandlerItemParsed) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(h.Handler)\n}\n\n// GetMetaTag retrieves and returns the metadata value associated with the given key from the request struct.\n// The meta value is from struct tags from g.Meta/gmeta.Meta type.\nfunc (h *HandlerItem) GetMetaTag(key string) string {\n\tif h != nil && h.Info.Type != nil && h.Info.Type.NumIn() == 2 {\n\t\tmetaValue := gmeta.Get(h.Info.Type.In(1), key)\n\t\tif metaValue != nil {\n\t\t\treturn metaValue.String()\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetMetaTag retrieves and returns the metadata value associated with the given key from the request struct.\n// The meta value is from struct tags from g.Meta/gmeta.Meta type.\n// For example:\n//\n//\ttype GetMetaTagReq struct {\n//\t    g.Meta `path:\"/test\" method:\"post\" summary:\"meta_tag\" tags:\"meta\"`\n//\t    // ...\n//\t}\n//\n// r.GetServeHandler().GetMetaTag(\"summary\") // returns \"meta_tag\"\n// r.GetServeHandler().GetMetaTag(\"method\")  // returns \"post\"\nfunc (h *HandlerItemParsed) GetMetaTag(key string) string {\n\tif h == nil || h.Handler == nil {\n\t\treturn \"\"\n\t}\n\treturn h.Handler.GetMetaTag(key)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_service_handler.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// BindHandler registers a handler function to server with a given pattern.\n//\n// Note that the parameter `handler` can be type of:\n// 1. func(*ghttp.Request)\n// 2. func(context.Context, BizRequest)(BizResponse, error)\nfunc (s *Server) BindHandler(pattern string, handler any) {\n\tvar ctx = context.TODO()\n\tfuncInfo, err := s.checkAndCreateFuncInfo(handler, \"\", \"\", \"\")\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\ts.doBindHandler(ctx, doBindHandlerInput{\n\t\tPrefix:     \"\",\n\t\tPattern:    pattern,\n\t\tFuncInfo:   funcInfo,\n\t\tMiddleware: nil,\n\t\tSource:     \"\",\n\t})\n}\n\ntype doBindHandlerInput struct {\n\tPrefix     string\n\tPattern    string\n\tFuncInfo   handlerFuncInfo\n\tMiddleware []HandlerFunc\n\tSource     string\n}\n\n// doBindHandler registers a handler function to server with given pattern.\n//\n// The parameter `pattern` is like:\n// /user/list, put:/user, delete:/user, post:/user@goframe.org\nfunc (s *Server) doBindHandler(ctx context.Context, in doBindHandlerInput) {\n\ts.setHandler(ctx, setHandlerInput{\n\t\tPrefix:  in.Prefix,\n\t\tPattern: in.Pattern,\n\t\tHandlerItem: &HandlerItem{\n\t\t\tType:       HandlerTypeHandler,\n\t\t\tInfo:       in.FuncInfo,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t},\n\t})\n}\n\n// bindHandlerByMap registers handlers to server using map.\nfunc (s *Server) bindHandlerByMap(ctx context.Context, prefix string, m map[string]*HandlerItem) {\n\tfor pattern, handler := range m {\n\t\ts.setHandler(ctx, setHandlerInput{\n\t\t\tPrefix:      prefix,\n\t\t\tPattern:     pattern,\n\t\t\tHandlerItem: handler,\n\t\t})\n\t}\n}\n\n// mergeBuildInNameToPattern merges build-in names into the pattern according to the following\n// rules, and the built-in names are named like \"{.xxx}\".\n// Rule 1: The URI in pattern contains the {.struct} keyword, it then replaces the keyword with the struct name;\n// Rule 2: The URI in pattern contains the {.method} keyword, it then replaces the keyword with the method name;\n// Rule 2: If Rule 1 is not met, it then adds the method name directly to the URI in the pattern;\n//\n// The parameter `allowAppend` specifies whether allowing appending method name to the tail of pattern.\nfunc (s *Server) mergeBuildInNameToPattern(pattern string, structName, methodName string, allowAppend bool) string {\n\tstructName = s.nameToUri(structName)\n\tmethodName = s.nameToUri(methodName)\n\tpattern = strings.ReplaceAll(pattern, \"{.struct}\", structName)\n\tif strings.Contains(pattern, \"{.method}\") {\n\t\treturn strings.ReplaceAll(pattern, \"{.method}\", methodName)\n\t}\n\tif !allowAppend {\n\t\treturn pattern\n\t}\n\t// Check domain parameter.\n\tvar (\n\t\tarray = strings.Split(pattern, \"@\")\n\t\turi   = strings.TrimRight(array[0], \"/\") + \"/\" + methodName\n\t)\n\t// Append the domain parameter to URI.\n\tif len(array) > 1 {\n\t\treturn uri + \"@\" + array[1]\n\t}\n\treturn uri\n}\n\n// nameToUri converts the given name to the URL format using the following rules:\n// Rule 0: Convert all method names to lowercase, add char '-' between words.\n// Rule 1: Do not convert the method name, construct the URI with the original method name.\n// Rule 2: Convert all method names to lowercase, no connecting symbols between words.\n// Rule 3: Use camel case naming.\nfunc (s *Server) nameToUri(name string) string {\n\tswitch s.config.NameToUriType {\n\tcase UriTypeFullName:\n\t\treturn name\n\n\tcase UriTypeAllLower:\n\t\treturn strings.ToLower(name)\n\n\tcase UriTypeCamel:\n\t\tpart := bytes.NewBuffer(nil)\n\t\tif gstr.IsLetterUpper(name[0]) {\n\t\t\tpart.WriteByte(name[0] + 32)\n\t\t} else {\n\t\t\tpart.WriteByte(name[0])\n\t\t}\n\t\tpart.WriteString(name[1:])\n\t\treturn part.String()\n\n\tcase UriTypeDefault:\n\t\tfallthrough\n\n\tdefault:\n\t\tpart := bytes.NewBuffer(nil)\n\t\tfor i := 0; i < len(name); i++ {\n\t\t\tif i > 0 && gstr.IsLetterUpper(name[i]) {\n\t\t\t\tpart.WriteByte('-')\n\t\t\t}\n\t\t\tif gstr.IsLetterUpper(name[i]) {\n\t\t\t\tpart.WriteByte(name[i] + 32)\n\t\t\t} else {\n\t\t\t\tpart.WriteByte(name[i])\n\t\t\t}\n\t\t}\n\t\treturn part.String()\n\t}\n}\n\nfunc (s *Server) checkAndCreateFuncInfo(\n\tf any, pkgPath, structName, methodName string,\n) (funcInfo handlerFuncInfo, err error) {\n\tfuncInfo = handlerFuncInfo{\n\t\tType:  reflect.TypeOf(f),\n\t\tValue: reflect.ValueOf(f),\n\t}\n\tif handlerFunc, ok := f.(HandlerFunc); ok {\n\t\tfuncInfo.Func = handlerFunc\n\t\treturn\n\t}\n\n\tvar (\n\t\treflectType    = funcInfo.Type\n\t\tinputObject    reflect.Value\n\t\tinputObjectPtr any\n\t)\n\tif reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {\n\t\tif pkgPath != \"\" {\n\t\t\terr = gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid handler: %s.%s.%s defined as \"%s\", but \"func(*ghttp.Request)\" or \"func(context.Context, *BizReq)(*BizRes, error)\" is required`,\n\t\t\t\tpkgPath, structName, methodName, reflectType.String(),\n\t\t\t)\n\t\t} else {\n\t\t\terr = gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid handler: defined as \"%s\", but \"func(*ghttp.Request)\" or \"func(context.Context, *BizReq)(*BizRes, error)\" is required`,\n\t\t\t\treflectType.String(),\n\t\t\t)\n\t\t}\n\t\treturn\n\t}\n\n\tif !reflectType.In(0).Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid handler: defined as \"%s\", but the first input parameter should be type of \"context.Context\"`,\n\t\t\treflectType.String(),\n\t\t)\n\t\treturn\n\t}\n\n\tif !reflectType.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid handler: defined as \"%s\", but the last output parameter should be type of \"error\"`,\n\t\t\treflectType.String(),\n\t\t)\n\t\treturn\n\t}\n\n\tif reflectType.In(1).Kind() != reflect.Pointer ||\n\t\t(reflectType.In(1).Kind() == reflect.Pointer && reflectType.In(1).Elem().Kind() != reflect.Struct) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid handler: defined as \"%s\", but the second input parameter should be type of pointer to struct like \"*BizReq\"`,\n\t\t\treflectType.String(),\n\t\t)\n\t\treturn\n\t}\n\n\t// Do not enable this logic, as many users are already using none struct pointer type\n\t// as the first output parameter.\n\t/*\n\t\tif reflectType.Out(0).Kind() != reflect.Pointer ||\n\t\t\t(reflectType.Out(0).Kind() == reflect.Pointer && reflectType.Out(0).Elem().Kind() != reflect.Struct) {\n\t\t\terr = gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid handler: defined as \"%s\", but the first output parameter should be type of pointer to struct like \"*BizRes\"`,\n\t\t\t\treflectType.String(),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t*/\n\n\tfuncInfo.IsStrictRoute = true\n\n\tinputObject = reflect.New(funcInfo.Type.In(1).Elem())\n\tinputObjectPtr = inputObject.Interface()\n\n\t// It retrieves and returns the request struct fields.\n\tfields, err := gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         inputObjectPtr,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbedded,\n\t})\n\tif err != nil {\n\t\treturn funcInfo, err\n\t}\n\tfuncInfo.ReqStructFields = fields\n\tfuncInfo.Func = createRouterFunc(funcInfo)\n\treturn\n}\n\nfunc createRouterFunc(funcInfo handlerFuncInfo) func(r *Request) {\n\treturn func(r *Request) {\n\t\tvar (\n\t\t\tok          bool\n\t\t\terr         error\n\t\t\tinputValues = []reflect.Value{\n\t\t\t\treflect.ValueOf(r.Context()),\n\t\t\t}\n\t\t)\n\t\tif funcInfo.Type.NumIn() == 2 {\n\t\t\tvar inputObject reflect.Value\n\t\t\tif funcInfo.Type.In(1).Kind() == reflect.Pointer {\n\t\t\t\tinputObject = reflect.New(funcInfo.Type.In(1).Elem())\n\t\t\t\tr.error = r.Parse(inputObject.Interface())\n\t\t\t} else {\n\t\t\t\tinputObject = reflect.New(funcInfo.Type.In(1).Elem()).Elem()\n\t\t\t\tr.error = r.Parse(inputObject.Addr().Interface())\n\t\t\t}\n\t\t\tif r.error != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tinputValues = append(inputValues, inputObject)\n\t\t}\n\t\t// Call handler with dynamic created parameter values.\n\t\tresults := funcInfo.Value.Call(inputValues)\n\t\tswitch len(results) {\n\t\tcase 1:\n\t\t\tif !results[0].IsNil() {\n\t\t\t\tif err, ok = results[0].Interface().(error); ok {\n\t\t\t\t\tr.error = err\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase 2:\n\t\t\tr.handlerResponse = results[0].Interface()\n\t\t\tif !results[1].IsNil() {\n\t\t\t\tif err, ok = results[1].Interface().(error); ok {\n\t\t\t\t\tr.error = err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_service_object.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// BindObject registers object to server routes with a given pattern.\n//\n// The optional parameter `method` is used to specify the method to be registered, which\n// supports multiple method names; multiple methods are separated by char ',', case-sensitive.\nfunc (s *Server) BindObject(pattern string, object any, method ...string) {\n\tvar bindMethod = \"\"\n\tif len(method) > 0 {\n\t\tbindMethod = method[0]\n\t}\n\ts.doBindObject(context.TODO(), doBindObjectInput{\n\t\tPrefix:     \"\",\n\t\tPattern:    pattern,\n\t\tObject:     object,\n\t\tMethod:     bindMethod,\n\t\tMiddleware: nil,\n\t\tSource:     \"\",\n\t})\n}\n\n// BindObjectMethod registers specified method of the object to server routes with a given pattern.\n//\n// The optional parameter `method` is used to specify the method to be registered, which\n// does not support multiple method names but only one, case-sensitive.\nfunc (s *Server) BindObjectMethod(pattern string, object any, method string) {\n\ts.doBindObjectMethod(context.TODO(), doBindObjectMethodInput{\n\t\tPrefix:     \"\",\n\t\tPattern:    pattern,\n\t\tObject:     object,\n\t\tMethod:     method,\n\t\tMiddleware: nil,\n\t\tSource:     \"\",\n\t})\n}\n\n// BindObjectRest registers object in REST API styles to server with a specified pattern.\nfunc (s *Server) BindObjectRest(pattern string, object any) {\n\ts.doBindObjectRest(context.TODO(), doBindObjectInput{\n\t\tPrefix:     \"\",\n\t\tPattern:    pattern,\n\t\tObject:     object,\n\t\tMethod:     \"\",\n\t\tMiddleware: nil,\n\t\tSource:     \"\",\n\t})\n}\n\ntype doBindObjectInput struct {\n\tPrefix     string\n\tPattern    string\n\tObject     any\n\tMethod     string\n\tMiddleware []HandlerFunc\n\tSource     string\n}\n\nfunc (s *Server) doBindObject(ctx context.Context, in doBindObjectInput) {\n\t// Convert input method to map for convenience and high performance searching purpose.\n\tvar methodMap map[string]bool\n\tif len(in.Method) > 0 {\n\t\tmethodMap = make(map[string]bool)\n\t\tfor _, v := range strings.Split(in.Method, \",\") {\n\t\t\tmethodMap[strings.TrimSpace(v)] = true\n\t\t}\n\t}\n\t// If the `method` in `pattern` is `defaultMethod`,\n\t// it removes for convenience for next statement control.\n\tdomain, method, path, err := s.parsePattern(in.Pattern)\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\treturn\n\t}\n\tif gstr.Equal(method, defaultMethod) {\n\t\tin.Pattern = s.serveHandlerKey(\"\", path, domain)\n\t}\n\tvar (\n\t\thandlerMap   = make(map[string]*HandlerItem)\n\t\treflectValue = reflect.ValueOf(in.Object)\n\t\treflectType  = reflectValue.Type()\n\t\tinitFunc     func(*Request)\n\t\tshutFunc     func(*Request)\n\t)\n\t// If given `object` is not pointer, it then creates a temporary one,\n\t// of which the value is `reflectValue`.\n\t// It then can retrieve all the methods both of struct/*struct.\n\tif reflectValue.Kind() == reflect.Struct {\n\t\tnewValue := reflect.New(reflectType)\n\t\tnewValue.Elem().Set(reflectValue)\n\t\treflectValue = newValue\n\t\treflectType = reflectValue.Type()\n\t}\n\tstructName := reflectType.Elem().Name()\n\tif reflectValue.MethodByName(specialMethodNameInit).IsValid() {\n\t\tinitFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))\n\t}\n\tif reflectValue.MethodByName(specialMethodNameShut).IsValid() {\n\t\tshutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))\n\t}\n\tpkgPath := reflectType.Elem().PkgPath()\n\tpkgName := gfile.Basename(pkgPath)\n\tfor i := 0; i < reflectValue.NumMethod(); i++ {\n\t\tmethodName := reflectType.Method(i).Name\n\t\tif methodMap != nil && !methodMap[methodName] {\n\t\t\tcontinue\n\t\t}\n\t\tif methodName == specialMethodNameInit || methodName == specialMethodNameShut {\n\t\t\tcontinue\n\t\t}\n\t\tobjName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), \"\")\n\t\tif objName[0] == '*' {\n\t\t\tobjName = fmt.Sprintf(`(%s)`, objName)\n\t\t}\n\n\t\tfuncInfo, err := s.checkAndCreateFuncInfo(reflectValue.Method(i).Interface(), pkgPath, objName, methodName)\n\t\tif err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\t}\n\n\t\tkey := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, true)\n\t\thandlerMap[key] = &HandlerItem{\n\t\t\tName:       fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),\n\t\t\tType:       HandlerTypeObject,\n\t\t\tInfo:       funcInfo,\n\t\t\tInitFunc:   initFunc,\n\t\t\tShutFunc:   shutFunc,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t}\n\t\t// If there's \"Index\" method, then an additional route is automatically added\n\t\t// to match the main URI, for example:\n\t\t// If pattern is \"/user\", then \"/user\" and \"/user/index\" are both automatically\n\t\t// registered.\n\t\t//\n\t\t// Note that if there's built-in variables in pattern, this route will not be added\n\t\t// automatically.\n\t\tvar (\n\t\t\tisIndexMethod = strings.EqualFold(methodName, specialMethodNameIndex)\n\t\t\thasBuildInVar = gregex.IsMatchString(`\\{\\.\\w+\\}`, in.Pattern)\n\t\t\thashTwoParams = funcInfo.Type.NumIn() == 2\n\t\t)\n\t\tif isIndexMethod && !hasBuildInVar && !hashTwoParams {\n\t\t\tp := gstr.PosRI(key, \"/index\")\n\t\t\tk := key[0:p] + key[p+6:]\n\t\t\tif len(k) == 0 || k[0] == '@' {\n\t\t\t\tk = \"/\" + k\n\t\t\t}\n\t\t\thandlerMap[k] = &HandlerItem{\n\t\t\t\tName:       fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),\n\t\t\t\tType:       HandlerTypeObject,\n\t\t\t\tInfo:       funcInfo,\n\t\t\t\tInitFunc:   initFunc,\n\t\t\t\tShutFunc:   shutFunc,\n\t\t\t\tMiddleware: in.Middleware,\n\t\t\t\tSource:     in.Source,\n\t\t\t}\n\t\t}\n\t}\n\ts.bindHandlerByMap(ctx, in.Prefix, handlerMap)\n}\n\ntype doBindObjectMethodInput struct {\n\tPrefix     string\n\tPattern    string\n\tObject     any\n\tMethod     string\n\tMiddleware []HandlerFunc\n\tSource     string\n}\n\nfunc (s *Server) doBindObjectMethod(ctx context.Context, in doBindObjectMethodInput) {\n\tvar (\n\t\thandlerMap   = make(map[string]*HandlerItem)\n\t\treflectValue = reflect.ValueOf(in.Object)\n\t\treflectType  = reflectValue.Type()\n\t\tinitFunc     func(*Request)\n\t\tshutFunc     func(*Request)\n\t)\n\t// If given `object` is not pointer, it then creates a temporary one,\n\t// of which the value is `v`.\n\tif reflectValue.Kind() == reflect.Struct {\n\t\tnewValue := reflect.New(reflectType)\n\t\tnewValue.Elem().Set(reflectValue)\n\t\treflectValue = newValue\n\t\treflectType = reflectValue.Type()\n\t}\n\tvar (\n\t\tstructName  = reflectType.Elem().Name()\n\t\tmethodName  = strings.TrimSpace(in.Method)\n\t\tmethodValue = reflectValue.MethodByName(methodName)\n\t)\n\tif !methodValue.IsValid() {\n\t\ts.Logger().Fatalf(ctx, \"invalid method name: %s\", methodName)\n\t\treturn\n\t}\n\tif reflectValue.MethodByName(specialMethodNameInit).IsValid() {\n\t\tinitFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))\n\t}\n\tif reflectValue.MethodByName(specialMethodNameShut).IsValid() {\n\t\tshutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))\n\t}\n\tvar (\n\t\tpkgPath = reflectType.Elem().PkgPath()\n\t\tpkgName = gfile.Basename(pkgPath)\n\t\tobjName = gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), \"\")\n\t)\n\tif objName[0] == '*' {\n\t\tobjName = fmt.Sprintf(`(%s)`, objName)\n\t}\n\n\tfuncInfo, err := s.checkAndCreateFuncInfo(methodValue.Interface(), pkgPath, objName, methodName)\n\tif err != nil {\n\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t}\n\n\tkey := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, false)\n\thandlerMap[key] = &HandlerItem{\n\t\tName:       fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),\n\t\tType:       HandlerTypeObject,\n\t\tInfo:       funcInfo,\n\t\tInitFunc:   initFunc,\n\t\tShutFunc:   shutFunc,\n\t\tMiddleware: in.Middleware,\n\t\tSource:     in.Source,\n\t}\n\n\ts.bindHandlerByMap(ctx, in.Prefix, handlerMap)\n}\n\nfunc (s *Server) doBindObjectRest(ctx context.Context, in doBindObjectInput) {\n\tvar (\n\t\thandlerMap   = make(map[string]*HandlerItem)\n\t\treflectValue = reflect.ValueOf(in.Object)\n\t\treflectType  = reflectValue.Type()\n\t\tinitFunc     func(*Request)\n\t\tshutFunc     func(*Request)\n\t)\n\t// If given `object` is not pointer, it then creates a temporary one,\n\t// of which the value is `v`.\n\tif reflectValue.Kind() == reflect.Struct {\n\t\tnewValue := reflect.New(reflectType)\n\t\tnewValue.Elem().Set(reflectValue)\n\t\treflectValue = newValue\n\t\treflectType = reflectValue.Type()\n\t}\n\tstructName := reflectType.Elem().Name()\n\tif reflectValue.MethodByName(specialMethodNameInit).IsValid() {\n\t\tinitFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))\n\t}\n\tif reflectValue.MethodByName(specialMethodNameShut).IsValid() {\n\t\tshutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))\n\t}\n\tpkgPath := reflectType.Elem().PkgPath()\n\tfor i := 0; i < reflectValue.NumMethod(); i++ {\n\t\tmethodName := reflectType.Method(i).Name\n\t\tif _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {\n\t\t\tcontinue\n\t\t}\n\t\tpkgName := gfile.Basename(pkgPath)\n\t\tobjName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), \"\")\n\t\tif objName[0] == '*' {\n\t\t\tobjName = fmt.Sprintf(`(%s)`, objName)\n\t\t}\n\n\t\tfuncInfo, err := s.checkAndCreateFuncInfo(\n\t\t\treflectValue.Method(i).Interface(),\n\t\t\tpkgPath,\n\t\t\tobjName,\n\t\t\tmethodName,\n\t\t)\n\t\tif err != nil {\n\t\t\ts.Logger().Fatalf(ctx, `%+v`, err)\n\t\t}\n\n\t\tkey := s.mergeBuildInNameToPattern(methodName+\":\"+in.Pattern, structName, methodName, false)\n\t\thandlerMap[key] = &HandlerItem{\n\t\t\tName:       fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),\n\t\t\tType:       HandlerTypeObject,\n\t\t\tInfo:       funcInfo,\n\t\t\tInitFunc:   initFunc,\n\t\t\tShutFunc:   shutFunc,\n\t\t\tMiddleware: in.Middleware,\n\t\t\tSource:     in.Source,\n\t\t}\n\t}\n\ts.bindHandlerByMap(ctx, in.Prefix, handlerMap)\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_session.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gogf/gf/v2/os/gsession\"\n\n// Session is actually an alias of gsession.Session,\n// which is bound to a single request.\ntype Session = gsession.Session\n"
  },
  {
    "path": "net/ghttp/ghttp_server_status.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"fmt\"\n)\n\n// getStatusHandler retrieves and returns the handler for given status code.\nfunc (s *Server) getStatusHandler(status int, r *Request) []HandlerFunc {\n\tdomains := []string{r.GetHost(), DefaultDomainName}\n\tfor _, domain := range domains {\n\t\tif f, ok := s.statusHandlerMap[s.statusHandlerKey(status, domain)]; ok {\n\t\t\treturn f\n\t\t}\n\t}\n\treturn nil\n}\n\n// addStatusHandler sets the handler for given status code.\n// The parameter `pattern` is like: domain#status\nfunc (s *Server) addStatusHandler(pattern string, handler HandlerFunc) {\n\tif s.statusHandlerMap[pattern] == nil {\n\t\ts.statusHandlerMap[pattern] = make([]HandlerFunc, 0)\n\t}\n\ts.statusHandlerMap[pattern] = append(s.statusHandlerMap[pattern], handler)\n}\n\n// statusHandlerKey creates and returns key for given status and domain.\nfunc (s *Server) statusHandlerKey(status int, domain string) string {\n\treturn fmt.Sprintf(\"%s#%d\", domain, status)\n}\n\n// BindStatusHandler registers handler for given status code.\nfunc (s *Server) BindStatusHandler(status int, handler HandlerFunc) {\n\ts.addStatusHandler(s.statusHandlerKey(status, DefaultDomainName), handler)\n}\n\n// BindStatusHandlerByMap registers handler for given status code using map.\nfunc (s *Server) BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {\n\tfor k, v := range handlerMap {\n\t\ts.BindStatusHandler(k, v)\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_swagger.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport (\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nconst (\n\tswaggerUIDocURLPlaceHolder = `{SwaggerUIDocUrl}`\n\tswaggerUITemplate          = `\n<!DOCTYPE html>\n<html>\n\t<head>\n\t<title>API Reference</title>\n\t<meta charset=\"utf-8\"/>\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<style>\n\t\tbody {\n\t\t\tmargin:  0;\n\t\t\tpadding: 0;\n\t\t}\n\t</style>\n\t</head>\n\t<body>\n\t\t<redoc spec-url=\"{SwaggerUIDocUrl}\" show-object-schema-examples=\"true\"></redoc>\n\t\t<script src=\"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js\"> </script>\n\t</body>\n</html>\n`\n)\n\n// swaggerUI is a build-in hook handler for replace default swagger json URL to local openapi json file path.\n// This handler makes sense only if the openapi specification automatic producing configuration is enabled.\nfunc (s *Server) swaggerUI(r *Request) {\n\tif s.config.OpenApiPath == \"\" {\n\t\treturn\n\t}\n\tvar templateContent = swaggerUITemplate\n\tif s.config.SwaggerUITemplate != \"\" {\n\t\ttemplateContent = s.config.SwaggerUITemplate\n\t}\n\n\tif r.StaticFile != nil && r.StaticFile.File != nil && r.StaticFile.IsDir {\n\t\tcontent := gstr.ReplaceByMap(templateContent, map[string]string{\n\t\t\tswaggerUIDocURLPlaceHolder: s.config.OpenApiPath,\n\t\t})\n\t\tr.Response.Write(content)\n\t\tr.ExitAll()\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_util.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"net/http\"\n\n// WrapF is a helper function for wrapping http.HandlerFunc and returns a ghttp.HandlerFunc.\nfunc WrapF(f http.HandlerFunc) HandlerFunc {\n\treturn func(r *Request) {\n\t\tf(r.Response.Writer, r.Request)\n\t}\n}\n\n// WrapH is a helper function for wrapping http.Handler and returns a ghttp.HandlerFunc.\nfunc WrapH(h http.Handler) HandlerFunc {\n\treturn func(r *Request) {\n\t\th.ServeHTTP(r.Response.Writer, r.Request)\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_server_websocket.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp\n\nimport \"github.com/gorilla/websocket\"\n\n// WebSocket wraps the underlying websocket connection\n// and provides convenient functions.\n//\n// Deprecated: will be removed in the future, please use third-party websocket library instead.\ntype WebSocket struct {\n\t*websocket.Conn\n}\n\nconst (\n\t// WsMsgText TextMessage denotes a text data message.\n\t// The text message payload is interpreted as UTF-8 encoded text data.\n\tWsMsgText = websocket.TextMessage\n\n\t// WsMsgBinary BinaryMessage denotes a binary data message.\n\tWsMsgBinary = websocket.BinaryMessage\n\n\t// WsMsgClose CloseMessage denotes a close control message.\n\t// The optional message payload contains a numeric code and text.\n\t// Use the FormatCloseMessage function to format a close message payload.\n\tWsMsgClose = websocket.CloseMessage\n\n\t// WsMsgPing PingMessage denotes a ping control message.\n\t// The optional message payload is UTF-8 encoded text.\n\tWsMsgPing = websocket.PingMessage\n\n\t// WsMsgPong PongMessage denotes a pong control message.\n\t// The optional message payload is UTF-8 encoded text.\n\tWsMsgPong = websocket.PongMessage\n)\n"
  },
  {
    "path": "net/ghttp/ghttp_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc Benchmark_TrimRightCharWithStrings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpath := \"//////////\"\n\t\tstrings.TrimRight(path, \"/\")\n\t}\n}\n\nfunc Benchmark_TrimRightCharWithSlice1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpath := \"//////////\"\n\t\tfor len(path) > 0 && path[len(path)-1] == '/' {\n\t\t\tpath = path[:len(path)-1]\n\t\t}\n\t}\n}\n\nfunc Benchmark_TrimRightCharWithSlice2(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpath := \"//////////\"\n\t\tfor {\n\t\t\tif length := len(path); length > 0 && path[length-1] == '/' {\n\t\t\t\tpath = path[:length-1]\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleServer_Run() {\n\ts := g.Server()\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello world\")\n\t})\n\ts.SetPort(8999)\n\ts.Run()\n}\n\n// Custom saving file name.\nfunc ExampleUploadFile_Save() {\n\ts := g.Server()\n\ts.BindHandler(\"/upload\", func(r *ghttp.Request) {\n\t\tfile := r.GetUploadFile(\"TestFile\")\n\t\tif file == nil {\n\t\t\tr.Response.Write(\"empty file\")\n\t\t\treturn\n\t\t}\n\t\tfile.Filename = \"MyCustomFileName.txt\"\n\t\tfileName, err := file.Save(gfile.Temp())\n\t\tif err != nil {\n\t\t\tr.Response.Write(err)\n\t\t\treturn\n\t\t}\n\t\tr.Response.Write(fileName)\n\t})\n\ts.SetPort(8999)\n\ts.Run()\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_ConfigFromMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"address\":         \":12345\",\n\t\t\t\"listeners\":       nil,\n\t\t\t\"readTimeout\":     \"60s\",\n\t\t\t\"indexFiles\":      g.Slice{\"index.php\", \"main.php\"},\n\t\t\t\"errorLogEnabled\": true,\n\t\t\t\"cookieMaxAge\":    \"1d\",\n\t\t\t\"cookieSameSite\":  \"lax\",\n\t\t\t\"cookieSecure\":    true,\n\t\t\t\"cookieHttpOnly\":  true,\n\t\t}\n\t\tconfig, err := ghttp.ConfigFromMap(m)\n\t\tt.AssertNil(err)\n\t\td1, _ := gtime.ParseDuration(gconv.String(m[\"readTimeout\"]))\n\t\td2, _ := gtime.ParseDuration(gconv.String(m[\"cookieMaxAge\"]))\n\t\tt.Assert(config.Address, m[\"address\"])\n\t\tt.Assert(config.ReadTimeout, d1)\n\t\tt.Assert(config.CookieMaxAge, d2)\n\t\tt.Assert(config.IndexFiles, m[\"indexFiles\"])\n\t\tt.Assert(config.ErrorLogEnabled, m[\"errorLogEnabled\"])\n\t\tt.Assert(config.CookieSameSite, m[\"cookieSameSite\"])\n\t\tt.Assert(config.CookieSecure, m[\"cookieSecure\"])\n\t\tt.Assert(config.CookieHttpOnly, m[\"cookieHttpOnly\"])\n\t})\n}\n\nfunc Test_SetConfigWithMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"Address\": \":8199\",\n\t\t\t// \"ServerRoot\":       \"/var/www/MyServerRoot\",\n\t\t\t\"IndexFiles\":       g.Slice{\"index.php\", \"main.php\"},\n\t\t\t\"AccessLogEnabled\": true,\n\t\t\t\"ErrorLogEnabled\":  true,\n\t\t\t\"PProfEnabled\":     true,\n\t\t\t\"LogPath\":          \"/tmp/log/MyServerLog\",\n\t\t\t\"SessionIdName\":    \"MySessionId\",\n\t\t\t\"SessionPath\":      \"/tmp/MySessionStoragePath\",\n\t\t\t\"SessionMaxAge\":    24 * time.Hour,\n\t\t\t\"cookieSameSite\":   \"lax\",\n\t\t\t\"cookieSecure\":     true,\n\t\t\t\"cookieHttpOnly\":   true,\n\t\t}\n\t\ts := g.Server()\n\t\terr := s.SetConfigWithMap(m)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_ClientMaxBodySize(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.POST(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetBodyString())\n\t\t})\n\t})\n\tm := g.Map{\n\t\t\"ClientMaxBodySize\": \"1k\",\n\t}\n\tgtest.Assert(s.SetConfigWithMap(m), nil)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tdata := make([]byte, 1056)\n\t\tfor i := 0; i < 1056; i++ {\n\t\t\tdata[i] = 'a'\n\t\t}\n\t\tt.Assert(\n\t\t\tgstr.Trim(c.PostContent(ctx, \"/\", data)),\n\t\t\t`Read from request Body failed: http: request body too large`,\n\t\t)\n\t})\n}\n\nfunc Test_ClientMaxBodySize_File(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.POST(\"/\", func(r *ghttp.Request) {\n\t\t\tr.GetUploadFile(\"file\")\n\t\t\tr.Response.Write(\"ok\")\n\t\t})\n\t})\n\tm := g.Map{\n\t\t\"ErrorLogEnabled\":   false,\n\t\t\"ClientMaxBodySize\": \"1k\",\n\t}\n\tgtest.Assert(s.SetConfigWithMap(m), nil)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// ok\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdata := make([]byte, 512)\n\t\tfor i := 0; i < 512; i++ {\n\t\t\tdata[i] = 'a'\n\t\t}\n\t\tt.Assert(gfile.PutBytes(path, data), nil)\n\t\tdefer gfile.Remove(path)\n\t\tt.Assert(\n\t\t\tgstr.Trim(c.PostContent(ctx, \"/\", \"name=john&file=@file:\"+path)),\n\t\t\t\"ok\",\n\t\t)\n\t})\n\n\t// too large\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdata := make([]byte, 1056)\n\t\tfor i := 0; i < 1056; i++ {\n\t\t\tdata[i] = 'a'\n\t\t}\n\t\tt.Assert(gfile.PutBytes(path, data), nil)\n\t\tdefer gfile.Remove(path)\n\t\tt.Assert(\n\t\t\ttrue,\n\t\t\tstrings.Contains(\n\t\t\t\tgstr.Trim(c.PostContent(ctx, \"/\", \"name=john&file=@file:\"+path)),\n\t\t\t\t\"http: request body too large\",\n\t\t\t),\n\t\t)\n\t})\n}\n\nfunc Test_Config_Graceful(t *testing.T) {\n\tvar (\n\t\tdefaultConfig = ghttp.NewConfig()\n\t\texpect        = true\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tt.Assert(s.GetGraceful(), defaultConfig.Graceful)\n\t\ts.SetGraceful(expect)\n\t\tt.Assert(s.GetGraceful(), expect)\n\t})\n}\n\nfunc Test_Config_GracefulTimeout(t *testing.T) {\n\tvar (\n\t\tdefaultConfig = ghttp.NewConfig()\n\t\texpect        = 3\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tt.Assert(s.GetGracefulTimeout(), defaultConfig.GracefulTimeout)\n\t\ts.SetGracefulTimeout(expect)\n\t\tt.Assert(s.GetGracefulTimeout(), expect)\n\t})\n}\n\nfunc Test_Config_GracefulShutdownTimeout(t *testing.T) {\n\tvar (\n\t\tdefaultConfig = ghttp.NewConfig()\n\t\texpect        = 10\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tt.Assert(s.GetGracefulShutdownTimeout(), defaultConfig.GracefulShutdownTimeout)\n\t\ts.SetGracefulShutdownTimeout(expect)\n\t\tt.Assert(s.GetGracefulShutdownTimeout(), expect)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_context_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Context(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.SetCtxVar(\"traceid\", 123)\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.GET(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetCtxVar(\"traceid\"))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), `123`)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_cookie_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Cookie(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/set\", func(r *ghttp.Request) {\n\t\tr.Cookie.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t})\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Cookie.Get(r.Get(\"k\").String()))\n\t})\n\ts.BindHandler(\"/remove\", func(r *ghttp.Request) {\n\t\tr.Cookie.Remove(r.Get(\"k\").String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr1, e1 := client.Get(ctx, \"/set?k=key1&v=100\")\n\t\tif r1 != nil {\n\t\t\tdefer r1.Close()\n\t\t}\n\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(r1.ReadAllString(), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/set?k=key2&v=200\"), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key4\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t})\n}\n\nfunc Test_SetHttpCookie(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/set\", func(r *ghttp.Request) {\n\t\tr.Cookie.SetHttpCookie(&http.Cookie{\n\t\t\tName:  r.Get(\"k\").String(),\n\t\t\tValue: r.Get(\"v\").String(),\n\t\t})\n\t})\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Cookie.Get(r.Get(\"k\").String()))\n\t})\n\ts.BindHandler(\"/remove\", func(r *ghttp.Request) {\n\t\tr.Cookie.Remove(r.Get(\"k\").String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr1, e1 := client.Get(ctx, \"/set?k=key1&v=100\")\n\t\tif r1 != nil {\n\t\t\tdefer r1.Close()\n\t\t}\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(r1.ReadAllString(), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/set?k=key2&v=200\"), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"100\")\n\t\t//t.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\t//t.Assert(client.GetContent(ctx, \"/get?k=key3\"), \"\")\n\t\t//t.Assert(client.GetContent(ctx, \"/remove?k=key1\"), \"\")\n\t\t//t.Assert(client.GetContent(ctx, \"/remove?k=key3\"), \"\")\n\t\t//t.Assert(client.GetContent(ctx, \"/remove?k=key4\"), \"\")\n\t\t//t.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"\")\n\t\t//t.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t})\n}\n\nfunc Test_CookieOptionsDefault(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test\", func(r *ghttp.Request) {\n\t\tr.Cookie.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr1, e1 := client.Get(ctx, \"/test?k=key1&v=100\")\n\t\tif r1 != nil {\n\t\t\tdefer r1.Close()\n\t\t}\n\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(r1.ReadAllString(), \"\")\n\n\t\tparts := strings.Split(r1.Header.Get(\"Set-Cookie\"), \"; \")\n\n\t\tt.AssertIN(len(parts), []int{3, 4}) // For go < 1.16 cookie always output \"SameSite\", see: https://github.com/golang/go/commit/542693e00529fbb4248fac614ece68b127a5ec4d\n\t})\n}\n\nfunc Test_CookieOptions(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetConfigWithMap(g.Map{\n\t\t\"cookieSameSite\": \"lax\",\n\t\t\"cookieSecure\":   true,\n\t\t\"cookieHttpOnly\": true,\n\t})\n\ts.BindHandler(\"/test\", func(r *ghttp.Request) {\n\t\tr.Cookie.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr1, e1 := client.Get(ctx, \"/test?k=key1&v=100\")\n\t\tif r1 != nil {\n\t\t\tdefer r1.Close()\n\t\t}\n\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(r1.ReadAllString(), \"\")\n\n\t\tparts := strings.Split(r1.Header.Get(\"Set-Cookie\"), \"; \")\n\n\t\tt.AssertEQ(len(parts), 6)\n\t\tt.Assert(parts[3], \"HttpOnly\")\n\t\tt.Assert(parts[4], \"Secure\")\n\t\tt.Assert(parts[5], \"SameSite=Lax\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_custom_listeners_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_SetSingleCustomListener(t *testing.T) {\n\tln1, _ := net.Listen(\"tcp\", \":0\")\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\terr := s.SetListener(ln1)\n\tgtest.AssertNil(err)\n\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(\n\t\t\tgstr.Trim(c.GetContent(ctx, \"/test\")),\n\t\t\t\"test\",\n\t\t)\n\t})\n}\n\nfunc Test_SetMultipleCustomListeners(t *testing.T) {\n\tln1, _ := net.Listen(\"tcp\", \":0\")\n\tln2, _ := net.Listen(\"tcp\", \":0\")\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\n\terr := s.SetListener(ln1, ln2)\n\tgtest.AssertNil(err)\n\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tports := s.GetListenedPorts()\n\t\tt.Assert(len(ports), 2)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", ports[0]))\n\n\t\tt.Assert(\n\t\t\tgstr.Trim(c.GetContent(ctx, \"/test\")),\n\t\t\t\"test\",\n\t\t)\n\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", ports[1]))\n\n\t\tt.Assert(\n\t\t\tgstr.Trim(c.GetContent(ctx, \"/test\")),\n\t\t\t\"test\",\n\t\t)\n\t})\n}\n\nfunc Test_SetWrongCustomListeners(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"test\")\n\t\t\t})\n\t\t})\n\t\terr := s.SetListener(nil)\n\t\tt.AssertNQ(err, nil)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_error_code_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Error_Code(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\t\tr.Middleware.Next()\n\t\t\t\tr.Response.ClearBuffer()\n\t\t\t\tr.Response.Write(gerror.Code(r.GetError()))\n\t\t\t})\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tpanic(gerror.NewCode(gcode.New(10000, \"\", nil), \"test error\"))\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"10000\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_https_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t_ \"github.com/gogf/gf/v2/net/ghttp/testdata/https/packed\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_HTTPS_Basic(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\ts.EnableHTTPS(\n\t\tgtest.DataPath(\"https\", \"files\", \"server.crt\"),\n\t\tgtest.DataPath(\"https\", \"files\", \"server.key\"),\n\t)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// HTTP\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.AssertIN(gstr.Trim(c.GetContent(ctx, \"/\")), g.Slice{\"\", \"Client sent an HTTP request to an HTTPS server.\"})\n\t\tt.AssertIN(gstr.Trim(c.GetContent(ctx, \"/test\")), g.Slice{\"\", \"Client sent an HTTP request to an HTTPS server.\"})\n\t})\n\t// HTTPS\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"https://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), \"test\")\n\t})\n}\n\nfunc Test_HTTPS_Resource(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\ts.EnableHTTPS(\n\t\tgfile.Join(\"files\", \"server.crt\"),\n\t\tgfile.Join(\"files\", \"server.key\"),\n\t)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// HTTP\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.AssertIN(gstr.Trim(c.GetContent(ctx, \"/\")), g.Slice{\"\", \"Client sent an HTTP request to an HTTPS server.\"})\n\t\tt.AssertIN(gstr.Trim(c.GetContent(ctx, \"/test\")), g.Slice{\"\", \"Client sent an HTTP request to an HTTPS server.\"})\n\t})\n\t// HTTPS\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"https://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), \"test\")\n\t})\n}\n\nfunc Test_HTTPS_HTTP_Basic(t *testing.T) {\n\ts := g.Server(gtime.TimestampNanoStr())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\ts.EnableHTTPS(\n\t\tgtest.DataPath(\"https\", \"files\", \"server.crt\"),\n\t\tgtest.DataPath(\"https\", \"files\", \"server.key\"),\n\t)\n\ts.SetPort(0)\n\ts.SetHTTPSPort(0)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// HTTP\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), \"test\")\n\t})\n\t// HTTPS\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"https://127.0.0.1:%d\", s.GetListenedHTTPSPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), \"test\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_ip_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc TestRequest_GetRemoteIp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetRemoteIp())\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tclientV4 := g.Client()\n\t\tclientV4.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tclientV6 := g.Client()\n\t\tclientV6.SetPrefix(fmt.Sprintf(\"http://[::1]:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(clientV4.GetContent(ctx, \"/\"), \"127.0.0.1\")\n\t\tt.Assert(clientV6.GetContent(ctx, \"/\"), \"::1\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_log_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Log(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlogDir := gfile.Temp(gtime.TimestampNanoStr())\n\t\ts := g.Server(guid.S())\n\t\ts.BindHandler(\"/hello\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"hello\")\n\t\t})\n\t\ts.BindHandler(\"/error\", func(r *ghttp.Request) {\n\t\t\tpanic(\"custom error\")\n\t\t})\n\t\ts.SetLogPath(logDir)\n\t\ts.SetAccessLogEnabled(true)\n\t\ts.SetErrorLogEnabled(true)\n\t\ts.SetLogStdout(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\tdefer gfile.Remove(logDir)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/hello\"), \"hello\")\n\t\tt.Assert(client.GetContent(ctx, \"/error\"), \"exception recovered: custom error\")\n\n\t\tvar (\n\t\t\tlogPath1 = gfile.Join(logDir, gtime.Now().Format(\"Y-m-d\")+\".log\")\n\t\t\tcontent  = gfile.GetContents(logPath1)\n\t\t)\n\t\tt.Assert(gstr.Contains(content, \"http server started listening on\"), true)\n\t\tt.Assert(gstr.Contains(content, \"HANDLER\"), true)\n\n\t\tlogPath2 := gfile.Join(logDir, \"access-\"+gtime.Now().Format(\"Ymd\")+\".log\")\n\t\t// fmt.Println(gfile.GetContents(logPath2))\n\t\tt.Assert(gstr.Contains(gfile.GetContents(logPath2), \" /hello \"), true)\n\n\t\tlogPath3 := gfile.Join(logDir, \"error-\"+gtime.Now().Format(\"Ymd\")+\".log\")\n\t\t// fmt.Println(gfile.GetContents(logPath3))\n\t\tt.Assert(gstr.Contains(gfile.GetContents(logPath3), \"custom error\"), true)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_middleware_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"go.opentelemetry.io/otel/trace/noop\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_BindMiddleware_Basic1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddleware(\"/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t}, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.BindMiddleware(\"/test/:name\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"5\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"6\")\n\t}, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"7\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"8\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"1342\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"57test86\")\n\t})\n}\n\nfunc Test_BindMiddleware_Basic2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddleware(\"/*\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"12\")\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"12\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"1test2\")\n\t})\n}\n\nfunc Test_BindMiddleware_Basic3(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddleware(\"PUT:/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t}, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.BindMiddleware(\"POST:/test/:name\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"5\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"6\")\n\t}, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"7\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"8\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"Not Found\")\n\t\tt.Assert(client.PutContent(ctx, \"/test\"), \"1342\")\n\t\tt.Assert(client.PostContent(ctx, \"/test\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"test\")\n\t\tt.Assert(client.PutContent(ctx, \"/test/test\"), \"test\")\n\t\tt.Assert(client.PostContent(ctx, \"/test/test\"), \"57test86\")\n\t})\n}\n\nfunc Test_BindMiddleware_Basic4(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Middleware.Next()\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t\tgroup.ALL(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"1test2\")\n\t\tt.Assert(client.PutContent(ctx, \"/test/none\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Middleware_With_Static(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t\tr.Middleware.Next()\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t\tgroup.ALL(\"/user/list\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"list\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.SetServerRoot(gtest.DataPath(\"static1\"))\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/none\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list\"), \"1list2\")\n\t})\n}\n\nfunc Test_Middleware_Status(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Middleware.Next()\n\t\t\tr.Response.WriteOver(r.Response.Status)\n\t\t})\n\t\tgroup.ALL(\"/user/list\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"list\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list\"), \"200\")\n\n\t\tresp, err := client.Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tdefer resp.Close()\n\t\tt.Assert(resp.StatusCode, 404)\n\t})\n}\n\nfunc Test_Middleware_Hook_With_Static(t *testing.T) {\n\ts := g.Server(guid.S())\n\ta := garray.New(true)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Hook(\"/*\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\t\ta.Append(1)\n\t\t\tfmt.Println(\"HookBeforeServe\")\n\t\t\tr.Response.Write(\"a\")\n\t\t})\n\t\tgroup.Hook(\"/*\", ghttp.HookAfterServe, func(r *ghttp.Request) {\n\t\t\ta.Append(1)\n\t\t\tfmt.Println(\"HookAfterServe\")\n\t\t\tr.Response.Write(\"b\")\n\t\t})\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t\tr.Middleware.Next()\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t\tgroup.ALL(\"/user/list\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"list\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.SetServerRoot(gtest.DataPath(\"static1\"))\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\t// The length assert sometimes fails, so I added time.Sleep here for debug purpose.\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(a.Len(), 2)\n\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(a.Len(), 4)\n\n\t\tt.Assert(client.GetContent(ctx, \"/none\"), \"ab\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(a.Len(), 6)\n\n\t\tt.Assert(client.GetContent(ctx, \"/user/list\"), \"a1list2b\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(a.Len(), 8)\n\t})\n}\n\nfunc Test_BindMiddleware_Status(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddleware(\"/test/*any\", func(r *ghttp.Request) {\n\t\tr.Middleware.Next()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test/test\"), \"Not Found\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Basic1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1342\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"13test42\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Basic2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"PUT:/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1342\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"1342\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"1342\")\n\t\tt.Assert(client.PutContent(ctx, \"/test/test\"), \"13test42\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Basic3(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"12\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"1test2\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Basic4(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"1\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"2\")\n\t\tr.Middleware.Next()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"21\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"2test1\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Basic5(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"2\")\n\t\tr.Middleware.Next()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"12\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"12test\")\n\t})\n}\n\nfunc Test_BindMiddlewareDefault_Status(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Middleware.Next()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"test\")\n\t})\n}\n\ntype ObjectMiddleware struct{}\n\nfunc (o *ObjectMiddleware) Init(r *ghttp.Request) {\n\tr.Response.Write(\"100\")\n}\n\nfunc (o *ObjectMiddleware) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"200\")\n}\n\nfunc (o *ObjectMiddleware) Index(r *ghttp.Request) {\n\tr.Response.Write(\"Object Index\")\n}\n\nfunc (o *ObjectMiddleware) Show(r *ghttp.Request) {\n\tr.Response.Write(\"Object Show\")\n}\n\nfunc (o *ObjectMiddleware) Info(r *ghttp.Request) {\n\tr.Response.Write(\"Object Info\")\n}\n\nfunc Test_BindMiddlewareDefault_Basic6(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObject(\"/\", new(ObjectMiddleware))\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"13100Object Index20042\")\n\t\tt.Assert(client.GetContent(ctx, \"/init\"), \"1342\")\n\t\tt.Assert(client.GetContent(ctx, \"/shut\"), \"1342\")\n\t\tt.Assert(client.GetContent(ctx, \"/index\"), \"13100Object Index20042\")\n\t\tt.Assert(client.GetContent(ctx, \"/show\"), \"13100Object Show20042\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"1342\")\n\t})\n}\n\nfunc Test_Hook_Middleware_Basic1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.BindHookHandler(\"/*\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"a\")\n\t})\n\ts.BindHookHandler(\"/*\", ghttp.HookAfterServe, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"b\")\n\t})\n\ts.BindHookHandler(\"/*\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"c\")\n\t})\n\ts.BindHookHandler(\"/*\", ghttp.HookAfterServe, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"d\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"2\")\n\t})\n\ts.BindMiddlewareDefault(func(r *ghttp.Request) {\n\t\tr.Response.Write(\"3\")\n\t\tr.Middleware.Next()\n\t\tr.Response.Write(\"4\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"ac1342bd\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"ac13test42bd\")\n\t})\n}\n\nfunc MiddlewareAuth(r *ghttp.Request) {\n\ttoken := r.Get(\"token\").String()\n\tif token == \"123456\" {\n\t\tr.Middleware.Next()\n\t} else {\n\t\tr.Response.WriteStatus(http.StatusForbidden)\n\t}\n}\n\nfunc MiddlewareCORS(r *ghttp.Request) {\n\tr.Response.CORSDefault()\n\tr.Middleware.Next()\n}\n\nfunc Test_Middleware_CORSAndAuth(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(MiddlewareCORS)\n\ts.Group(\"/api.v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(MiddlewareAuth)\n\t\tgroup.POST(\"/user/list\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"list\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\t// Common Checks.\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2\"), \"Not Found\")\n\t\t// Auth Checks.\n\t\tt.Assert(client.PostContent(ctx, \"/api.v2/user/list\"), \"Forbidden\")\n\t\tt.Assert(client.PostContent(ctx, \"/api.v2/user/list\", \"token=123456\"), \"list\")\n\t\t// CORS Checks.\n\t\tresp, err := client.Post(ctx, \"/api.v2/user/list\", \"token=123456\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 1)\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Headers\"][0], \"Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Methods\"][0], \"GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Origin\"][0], \"*\")\n\t\tt.Assert(resp.Header[\"Access-Control-Max-Age\"][0], \"3628800\")\n\t\tresp.Close()\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.SetHeader(\"Access-Control-Request-Headers\", \"GF,GoFrame\").GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.SetHeader(\"Origin\", \"GoFrame\").GetContent(ctx, \"/\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.SetHeader(\"Referer\", \"Referer\").PostContent(ctx, \"/\"), \"Not Found\")\n\t})\n}\n\nfunc MiddlewareScope1(r *ghttp.Request) {\n\tr.Response.Write(\"a\")\n\tr.Middleware.Next()\n\tr.Response.Write(\"b\")\n}\n\nfunc MiddlewareScope2(r *ghttp.Request) {\n\tr.Response.Write(\"c\")\n\tr.Middleware.Next()\n\tr.Response.Write(\"d\")\n}\n\nfunc MiddlewareScope3(r *ghttp.Request) {\n\tr.Response.Write(\"e\")\n\tr.Middleware.Next()\n\tr.Response.Write(\"f\")\n}\n\nfunc Test_Middleware_Scope(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(MiddlewareScope1)\n\t\tgroup.ALL(\"/scope1\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t})\n\t\tgroup.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Middleware(MiddlewareScope2)\n\t\t\tgroup.ALL(\"/scope2\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"2\")\n\t\t\t})\n\t\t})\n\t\tgroup.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Middleware(MiddlewareScope3)\n\t\t\tgroup.ALL(\"/scope3\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"3\")\n\t\t\t})\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/scope1\"), \"a1b\")\n\t\tt.Assert(client.GetContent(ctx, \"/scope2\"), \"ac2db\")\n\t\tt.Assert(client.GetContent(ctx, \"/scope3\"), \"ae3fb\")\n\t})\n}\n\nfunc Test_Middleware_Panic(t *testing.T) {\n\ts := g.Server(guid.S())\n\ti := 0\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\t\ti++\n\t\t\t\tpanic(\"error\")\n\t\t\t\t// r.Middleware.Next()\n\t\t\t}, func(r *ghttp.Request) {\n\t\t\t\ti++\n\t\t\t\tr.Middleware.Next()\n\t\t\t})\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(i)\n\t\t\t})\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"exception recovered: error\")\n\t})\n}\n\nfunc Test_Middleware_JsonBody(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareJsonBody)\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"hello\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"hello\")\n\t\tt.Assert(client.PutContent(ctx, \"/\", `{\"name\":\"john\"}`), \"hello\")\n\t\tt.Assert(client.PutContent(ctx, \"/\", `{\"name\":}`), \"the request body content should be JSON format\")\n\t})\n}\n\nfunc Test_MiddlewareHandlerResponse(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.GET(\"/403\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteStatus(http.StatusForbidden, \"\")\n\t\t})\n\t\tgroup.GET(\"/default\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteStatus(http.StatusInternalServerError, \"\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\trsp, err := client.Get(ctx, \"/403\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusForbidden)\n\t\trsp, err = client.Get(ctx, \"/default\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusInternalServerError)\n\t})\n}\n\nfunc Test_MiddlewareHandlerGzipResponse(t *testing.T) {\n\ttp := testTracerProvider{}\n\totel.SetTracerProvider(&tp)\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/default\", func(r *ghttp.Request) {\n\t\t\tvar buffer strings.Builder\n\t\t\tgzipWriter := gzip.NewWriter(&buffer)\n\t\t\tdefer gzipWriter.Close()\n\t\t\t_, _ = gzipWriter.Write([]byte(\"hello\"))\n\t\t\t// 设置响应头，表明内容使用 gzip 压缩\n\t\t\tr.Response.Header().Set(\"Content-Encoding\", \"gzip\")\n\t\t\tr.Response.Header().Set(\"Content-Type\", \"text/plain\")\n\t\t\tr.Response.Header().Set(\"Content-Length\", fmt.Sprint(buffer.Len()))\n\t\t\t// 写入压缩后的内容\n\t\t\tr.Response.Write(buffer.String())\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\trsp, err := client.Get(ctx, \"/default\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t})\n}\n\nfunc Test_MiddlewareHandlerStreamResponse(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\n\t\tgroup.GET(\"/stream/event\", func(r *ghttp.Request) {\n\t\t\tr.Response.Header().Set(\"Content-Type\", \"text/event-stream\")\n\t\t})\n\n\t\tgroup.GET(\"/stream/octet\", func(r *ghttp.Request) {\n\t\t\tr.Response.Header().Set(\"Content-Type\", \"application/octet-stream\")\n\t\t})\n\n\t\tgroup.GET(\"/stream/mixed\", func(r *ghttp.Request) {\n\t\t\tr.Response.Header().Set(\"Content-Type\", \"multipart/x-mixed-replace\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\trsp, err := client.Get(ctx, \"/stream/event\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t\tt.Assert(rsp.ReadAllString(), \"\")\n\n\t\trsp, err = client.Get(ctx, \"/stream/octet\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t\tt.Assert(rsp.ReadAllString(), \"\")\n\n\t\trsp, err = client.Get(ctx, \"/stream/mixed\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t\tt.Assert(rsp.ReadAllString(), \"\")\n\t})\n}\n\ntype testTracerProvider struct {\n\tnoop.TracerProvider\n}\n\nvar _ trace.TracerProvider = (*testTracerProvider)(nil)\n\nfunc (*testTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Tracer {\n\treturn noop.NewTracerProvider().Tracer(\"\")\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_middleware_cors_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Middleware_CORS1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api.v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(MiddlewareCORS)\n\t\tgroup.POST(\"/user/list\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"list\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\t// Common Checks.\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2\"), \"Not Found\")\n\n\t\t// GET request does not any route.\n\t\tresp, err := client.Get(ctx, \"/api.v2/user/list\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 0)\n\t\tt.Assert(resp.StatusCode, 404)\n\t\tresp.Close()\n\n\t\t// POST request matches the route and CORS middleware.\n\t\tresp, err = client.Post(ctx, \"/api.v2/user/list\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 1)\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Headers\"][0], \"Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Methods\"][0], \"GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Origin\"][0], \"*\")\n\t\tt.Assert(resp.Header[\"Access-Control-Max-Age\"][0], \"3628800\")\n\t\tresp.Close()\n\t})\n\t// OPTIONS GET\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"GET\")\n\t\tresp, err := client.Options(ctx, \"/api.v2/user/list\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 0)\n\t\tt.Assert(resp.ReadAllString(), \"Not Found\")\n\t\tt.Assert(resp.StatusCode, 404)\n\t\tresp.Close()\n\t})\n\t// OPTIONS POST\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"POST\")\n\t\tresp, err := client.Options(ctx, \"/api.v2/user/list\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 1)\n\t\tt.Assert(resp.StatusCode, 200)\n\t\tresp.Close()\n\t})\n}\n\nfunc Test_Middleware_CORS2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api.v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(MiddlewareCORS)\n\t\tgroup.GET(\"/user/list/{type}\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.Get(\"type\"))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\t// Common Checks.\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2\"), \"Not Found\")\n\t\t// Get request.\n\t\tresp, err := client.Get(ctx, \"/api.v2/user/list/1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 1)\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Headers\"][0], \"Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Methods\"][0], \"GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE\")\n\t\tt.Assert(resp.Header[\"Access-Control-Allow-Origin\"][0], \"*\")\n\t\tt.Assert(resp.Header[\"Access-Control-Max-Age\"][0], \"3628800\")\n\t\tt.Assert(resp.ReadAllString(), \"1\")\n\t\tresp.Close()\n\t})\n\t// OPTIONS GET None.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"GET\")\n\t\tresp, err := client.Options(ctx, \"/api.v2/user\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 0)\n\t\tt.Assert(resp.StatusCode, 404)\n\t\tresp.Close()\n\t})\n\t// OPTIONS GET\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"GET\")\n\t\tresp, err := client.Options(ctx, \"/api.v2/user/list/1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 1)\n\t\tt.Assert(resp.StatusCode, 200)\n\t\tresp.Close()\n\t})\n\t// OPTIONS POST\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"POST\")\n\t\tresp, err := client.Options(ctx, \"/api.v2/user/list/1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(resp.Header[\"Access-Control-Allow-Headers\"]), 0)\n\t\tt.Assert(resp.StatusCode, 404)\n\t\tresp.Close()\n\t})\n}\n\nfunc Test_Middleware_CORS3(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api.v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareCORS)\n\t\tgroup.GET(\"/user/list/{type}\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.Get(\"type\"))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(\"Access-Control-Request-Method\", \"POST\")\n\t\tresp, err := client.Get(ctx, \"/api.v2/user/list/1\")\n\t\tt.AssertNil(err)\n\t\tresp.Close()\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_openapi_swagger_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_OpenApi_Swagger(t *testing.T) {\n\ttype TestReq struct {\n\t\tgmeta.Meta `method:\"get\" summary:\"Test summary\" tags:\"Test\"`\n\t\tAge        int\n\t\tName       string\n\t}\n\ttype TestRes struct {\n\t\tId   int\n\t\tAge  int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.SetSwaggerPath(\"/swagger\")\n\ts.SetOpenApiPath(\"/api.json\")\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test/error\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, gerror.New(\"error\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(c.GetContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/swagger/\"), `API Reference`), true)\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/api.json\"), `/test/error`), true)\n\t})\n}\n\nfunc Test_OpenApi_Multiple_Methods_Swagger(t *testing.T) {\n\ttype TestReq struct {\n\t\tgmeta.Meta `method:\"get,post\" summary:\"Test summary\" tags:\"Test\"`\n\t\tAge        int\n\t\tName       string\n\t}\n\ttype TestRes struct {\n\t\tId   int\n\t\tAge  int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.SetSwaggerPath(\"/swagger\")\n\ts.SetOpenApiPath(\"/api.json\")\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test/error\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, gerror.New(\"error\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\topenapi := s.GetOpenApi()\n\t\tt.AssertNE(openapi.Paths[\"/test\"].Get, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test\"].Post, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test/error\"].Get, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test/error\"].Post, nil)\n\n\t\tt.Assert(len(openapi.Paths[\"/test\"].Get.Parameters), 2)\n\t\tt.Assert(len(openapi.Paths[\"/test/error\"].Get.Parameters), 2)\n\t\tt.Assert(len(openapi.Components.Schemas.Get(`github.com.gogf.gf.v2.net.ghttp_test.TestReq`).Value.Properties.Map()), 2)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\t// Only works on GET & POST methods.\n\t\tt.Assert(c.GetContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(c.GetContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\t\tt.Assert(c.PostContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(c.PostContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\n\t\t// Not works on other methods.\n\t\tt.Assert(c.PutContent(ctx, \"/test?age=18&name=john\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\t\tt.Assert(c.PutContent(ctx, \"/test/error\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/swagger/\"), `API Reference`), true)\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/api.json\"), `/test/error`), true)\n\t})\n}\n\nfunc Test_OpenApi_Method_All_Swagger(t *testing.T) {\n\ttype TestReq struct {\n\t\tgmeta.Meta `method:\"all\" summary:\"Test summary\" tags:\"Test\"`\n\t\tAge        int\n\t\tName       string\n\t}\n\ttype TestRes struct {\n\t\tId   int\n\t\tAge  int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.SetSwaggerPath(\"/swagger\")\n\ts.SetOpenApiPath(\"/api.json\")\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test/error\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, gerror.New(\"error\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\topenapi := s.GetOpenApi()\n\t\tt.AssertNE(openapi.Paths[\"/test\"].Get, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test\"].Post, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test\"].Delete, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test/error\"].Get, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test/error\"].Post, nil)\n\t\tt.AssertNE(openapi.Paths[\"/test/error\"].Delete, nil)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(c.GetContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\t\tt.Assert(c.PostContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(c.PostContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/swagger/\"), `API Reference`), true)\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/api.json\"), `/test/error`), true)\n\t})\n}\n\nfunc Test_OpenApi_Auth(t *testing.T) {\n\ts := g.Server(guid.S())\n\tapiPath := \"/api.json\"\n\ts.SetOpenApiPath(apiPath)\n\ts.BindHookHandler(s.GetOpenApiPath(), ghttp.HookBeforeServe, openApiBasicAuth)\n\ts.Start()\n\tdefer s.Shutdown()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(s.GetOpenApiPath(), apiPath)\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, apiPath), \"Unauthorized\")\n\t\tc.SetBasicAuth(\"OpenApiAuthUserName\", \"OpenApiAuthPass\")\n\t\tcc := c.GetContent(ctx, apiPath)\n\t\tt.AssertNE(cc, \"Unauthorized\")\n\t})\n}\n\nfunc openApiBasicAuth(r *ghttp.Request) {\n\tif !r.BasicAuth(\"OpenApiAuthUserName\", \"OpenApiAuthPass\", \"Restricted\") {\n\t\tr.ExitAll()\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_otel_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_OTEL_TraceID(t *testing.T) {\n\tvar (\n\t\ttraceId string\n\t)\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\ttraceId = gtrace.GetTraceID(r.Context())\n\t\tr.Response.Write(r.GetUrl())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(prefix)\n\t\tres, err := client.Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tdefer res.Close()\n\n\t\tt.Assert(res.Header.Get(\"Trace-Id\"), traceId)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_pprof_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/gogf/gf/v2/test/gtest\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc TestServer_EnablePProf(t *testing.T) {\n\tC(t, func(t *T) {\n\t\ts := g.Server(guid.S())\n\t\ts.EnablePProf(\"/pprof\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\turlPaths := []string{\n\t\t\t\"/pprof/index\", \"/pprof/cmdline\", \"/pprof/symbol\", \"/pprof/trace\",\n\t\t}\n\t\tfor _, urlPath := range urlPaths {\n\t\t\tr, err := client.Get(ctx, urlPath)\n\t\t\tAssertNil(err)\n\t\t\tAssert(r.StatusCode, 200)\n\t\t\tAssertNil(r.Close())\n\t\t}\n\t})\n}\n\nfunc TestServer_StartPProfServer(t *testing.T) {\n\tC(t, func(t *T) {\n\t\ts, err := ghttp.StartPProfServer(\":0\")\n\t\tt.AssertNil(err)\n\n\t\tdefer ghttp.ShutdownAllServer(ctx)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d/debug\", s.GetListenedPort()))\n\n\t\turlPaths := []string{\n\t\t\t\"/pprof/index\", \"/pprof/cmdline\", \"/pprof/symbol\", \"/pprof/trace\",\n\t\t}\n\t\tfor _, urlPath := range urlPaths {\n\t\t\tr, err := client.Get(ctx, urlPath)\n\t\t\tAssertNil(err)\n\t\t\tAssert(r.StatusCode, 200)\n\t\t\tAssertNil(r.Close())\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_ctx_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Request_IsFileRequest(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.IsFileRequest())\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), false)\n\t})\n}\n\nfunc Test_Request_IsAjaxRequest(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.IsAjaxRequest())\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), false)\n\t})\n}\n\nfunc Test_Request_GetClientIp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.GetClientIp())\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetHeader(\"X-Forwarded-For\", \"192.168.0.1\")\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"192.168.0.1\")\n\t})\n}\n\nfunc Test_Request_GetUrl(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.GetUrl())\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetHeader(\"X-Forwarded-Proto\", \"https\")\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), fmt.Sprintf(\"https://127.0.0.1:%d/\", s.GetListenedPort()))\n\t})\n}\n\nfunc Test_Request_GetReferer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.GetReferer())\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetHeader(\"Referer\", \"Referer\")\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"Referer\")\n\t})\n}\n\nfunc Test_Request_GetServeHandler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(r.GetServeHandler() != nil)\n\t\t\t})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetHeader(\"Referer\", \"Referer\")\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), true)\n\t})\n}\n\nfunc Test_Request_BasicAuth(t *testing.T) {\n\tconst (\n\t\tuser      = \"root\"\n\t\tpass      = \"123456\"\n\t\twrongPass = \"12345\"\n\t)\n\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/auth1\", func(r *ghttp.Request) {\n\t\t\tr.BasicAuth(user, pass, \"tips\")\n\t\t})\n\t\tgroup.ALL(\"/auth2\", func(r *ghttp.Request) {\n\t\t\tr.BasicAuth(user, pass)\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\trsp, err := c.Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.Header.Get(\"WWW-Authenticate\"), \"Basic realm=\\\"tips\\\"\")\n\t\tt.Assert(rsp.StatusCode, http.StatusUnauthorized)\n\n\t\trsp, err = c.SetHeader(\"Authorization\", user+pass).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusForbidden)\n\n\t\trsp, err = c.SetHeader(\"Authorization\", \"Test \"+user+pass).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusForbidden)\n\n\t\trsp, err = c.SetHeader(\"Authorization\", \"Basic \"+user+pass).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusForbidden)\n\n\t\trsp, err = c.SetHeader(\"Authorization\", \"Basic \"+gbase64.EncodeString(user+pass)).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusForbidden)\n\n\t\trsp, err = c.SetHeader(\"Authorization\", \"Basic \"+gbase64.EncodeString(user+\":\"+wrongPass)).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusUnauthorized)\n\n\t\trsp, err = c.BasicAuth(user, pass).Get(ctx, \"/auth1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\n\t\trsp, err = c.Get(ctx, \"/auth2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.Header.Get(\"WWW-Authenticate\"), \"Basic realm=\\\"Need Login\\\"\")\n\t\tt.Assert(rsp.StatusCode, http.StatusUnauthorized)\n\t})\n}\n\nfunc Test_Request_SetCtx(t *testing.T) {\n\ttype ctxKey string\n\tconst testkey ctxKey = \"test\"\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tctx := context.WithValue(r.Context(), testkey, 1)\n\t\t\tr.SetCtx(ctx)\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.Context().Value(testkey))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"1\")\n\t})\n}\n\nfunc Test_Request_GetCtx(t *testing.T) {\n\ttype ctxKey string\n\tconst testkey ctxKey = \"test\"\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tctx := context.WithValue(r.GetCtx(), testkey, 1)\n\t\t\tr.SetCtx(ctx)\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.Context().Value(testkey))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"1\")\n\t})\n}\n\nfunc Test_Request_GetCtxVar(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.GET(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetCtxVar(\"key\", \"val\"))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"val\")\n\t})\n}\n\nfunc Test_Request_Form(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.SetForm(\"key\", \"val\")\n\t\t\tr.Response.Write(r.GetForm(\"key\"))\n\t\t})\n\t\tgroup.ALL(\"/useDef\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetForm(\"key\", \"defVal\"))\n\t\t})\n\t\tgroup.ALL(\"/GetFormMap\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetFormMap(map[string]any{\"key\": \"val\"}))\n\t\t})\n\t\tgroup.ALL(\"/GetFormMap1\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(r.GetFormMap(map[string]any{\"array\": \"val\"}))\n\t\t})\n\t\tgroup.ALL(\"/GetFormMapStrVar\", func(r *ghttp.Request) {\n\t\t\tif r.Get(\"a\") != nil {\n\t\t\t\tr.Response.Write(r.GetFormMapStrVar()[\"a\"])\n\t\t\t}\n\t\t})\n\t\tgroup.ALL(\"/GetFormStruct\", func(r *ghttp.Request) {\n\t\t\tvar user User\n\t\t\tif err := r.GetFormStruct(&user); err != nil {\n\t\t\t\tr.Response.Write(err.Error())\n\t\t\t} else {\n\t\t\t\tr.Response.Write(user.Name)\n\t\t\t}\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"val\")\n\t\tt.Assert(client.GetContent(ctx, \"/useDef\"), \"defVal\")\n\t\tt.Assert(client.PostContent(ctx, \"/GetFormMap\"), \"{\\\"key\\\":\\\"val\\\"}\")\n\t\tt.Assert(client.PostContent(ctx, \"/GetFormMap\", \"array[]=1&array[]=2\"), \"{\\\"key\\\":\\\"val\\\"}\")\n\t\tt.Assert(client.PostContent(ctx, \"/GetFormMap1\", \"array[]=1&array[]=2\"), \"{\\\"array\\\":[\\\"1\\\",\\\"2\\\"]}\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetFormMapStrVar\", \"a=1&b=2\"), nil)\n\t\tt.Assert(client.PostContent(ctx, \"/GetFormMapStrVar\", \"a=1&b=2\"), `1`)\n\t\tt.Assert(client.PostContent(ctx, \"/GetFormStruct\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), \"john\")\n\t})\n}\n\nfunc Test_Request_NeverDoneCtx_Done(t *testing.T) {\n\tvar array = garray.New(true)\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/done\", func(r *ghttp.Request) {\n\t\tvar (\n\t\t\tctx    = r.Context()\n\t\t\tticker = time.NewTimer(time.Millisecond * 1500)\n\t\t)\n\t\tdefer ticker.Stop()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tarray.Append(1)\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\tarray.Append(1)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tc := g.Client()\n\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Second*30)\n\t\tgo func() {\n\t\t\tresult := c.GetContent(ctx, \"/done\")\n\t\t\tfmt.Println(result)\n\t\t}()\n\t\ttime.Sleep(time.Millisecond * 100)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tcancel()\n\n\t\ttime.Sleep(time.Millisecond * 500)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc Test_Request_NeverDoneCtx_NeverDone(t *testing.T) {\n\tvar array = garray.New(true)\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareNeverDoneCtx)\n\ts.BindHandler(\"/never-done\", func(r *ghttp.Request) {\n\t\tvar (\n\t\t\tctx    = r.Context()\n\t\t\tticker = time.NewTimer(time.Millisecond * 1500)\n\t\t)\n\t\tdefer ticker.Stop()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tarray.Append(1)\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\tarray.Append(1)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tc := g.Client()\n\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Second*30)\n\t\tgo func() {\n\t\t\tresult := c.GetContent(ctx, \"/never-done\")\n\t\t\tfmt.Println(result)\n\t\t}()\n\t\ttime.Sleep(time.Millisecond * 100)\n\n\t\tt.Assert(array.Len(), 0)\n\t\tcancel()\n\n\t\ttime.Sleep(time.Millisecond * 1500)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_file_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Params_File_Single(t *testing.T) {\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/single\", func(r *ghttp.Request) {\n\t\tfile := r.GetUploadFile(\"file\")\n\t\tif file == nil {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\n\t\tif name, err := file.Save(dstDirPath, r.Get(\"randomlyRename\").Bool()); err == nil {\n\t\t\tr.Response.WriteExit(name)\n\t\t}\n\t\tr.Response.WriteExit(\"upload failed\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdstPath := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n\t// randomly rename.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file2.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\":           \"@file:\" + srcPath,\n\t\t\t\"randomlyRename\": true,\n\t\t})\n\t\tdstPath := gfile.Join(dstDirPath, content)\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n}\n\nfunc Test_Params_File_CustomName(t *testing.T) {\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/single\", func(r *ghttp.Request) {\n\t\tfile := r.GetUploadFile(\"file\")\n\t\tif file == nil {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\t\tfile.Filename = \"my.txt\"\n\t\tif name, err := file.Save(dstDirPath, r.Get(\"randomlyRename\").Bool()); err == nil {\n\t\t\tr.Response.WriteExit(name)\n\t\t}\n\t\tr.Response.WriteExit(\"upload failed\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdstPath := gfile.Join(dstDirPath, \"my.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"my.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n}\n\nfunc Test_Params_File_Batch(t *testing.T) {\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/batch\", func(r *ghttp.Request) {\n\t\tfiles := r.GetUploadFiles(\"file\")\n\t\tif files == nil {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\t\tif names, err := files.Save(dstDirPath, r.Get(\"randomlyRename\").Bool()); err == nil {\n\t\t\tr.Response.WriteExit(gstr.Join(names, \",\"))\n\t\t}\n\t\tr.Response.WriteExit(\"upload failed\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath1 := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tsrcPath2 := gtest.DataPath(\"upload\", \"file2.txt\")\n\t\tdstPath1 := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tdstPath2 := gfile.Join(dstDirPath, \"file2.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/batch\", g.Map{\n\t\t\t\"file[0]\": \"@file:\" + srcPath1,\n\t\t\t\"file[1]\": \"@file:\" + srcPath2,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt,file2.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))\n\t\tt.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))\n\t})\n\t// randomly rename.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath1 := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tsrcPath2 := gtest.DataPath(\"upload\", \"file2.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/batch\", g.Map{\n\t\t\t\"file[0]\":        \"@file:\" + srcPath1,\n\t\t\t\"file[1]\":        \"@file:\" + srcPath2,\n\t\t\t\"randomlyRename\": true,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\n\t\tarray := gstr.SplitAndTrim(content, \",\")\n\t\tt.Assert(len(array), 2)\n\t\tdstPath1 := gfile.Join(dstDirPath, array[0])\n\t\tdstPath2 := gfile.Join(dstDirPath, array[1])\n\t\tt.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))\n\t\tt.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))\n\t})\n}\n\nfunc Test_Params_Strict_Route_File_Single_Ptr_Attrr(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"post\" mime:\"multipart/form-data\"`\n\t\tFile       *ghttp.UploadFile `type:\"file\"`\n\t}\n\ttype Res struct{}\n\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/single\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\tvar (\n\t\t\tr    = g.RequestFromCtx(ctx)\n\t\t\tfile = req.File\n\t\t)\n\t\tif file == nil {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\t\tname, err := file.Save(dstDirPath)\n\t\tif err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(name)\n\t\treturn\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdstPath := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n}\n\nfunc Test_Params_Strict_Route_File_Single_Struct_Attr(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"post\" mime:\"multipart/form-data\"`\n\t\tFile       ghttp.UploadFile `type:\"file\"`\n\t}\n\ttype Res struct{}\n\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/single\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\tvar (\n\t\t\tr    = g.RequestFromCtx(ctx)\n\t\t\tfile = req.File\n\t\t)\n\t\tname, err := file.Save(dstDirPath)\n\t\tif err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(name)\n\t\treturn\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdstPath := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n}\n\nfunc Test_Params_File_Upload_Required(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"post\" mime:\"multipart/form-data\"`\n\t\tFile       *ghttp.UploadFile `type:\"file\" v:\"required#upload file is required\"`\n\t}\n\ttype Res struct{}\n\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/upload/required\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// file is empty\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tcontent := client.PostContent(ctx, \"/upload/required\")\n\t\tt.Assert(content, `{\"code\":51,\"message\":\"upload file is required\",\"data\":null}`)\n\t})\n}\n\nfunc Test_Params_File_MarshalJSON(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/single\", func(r *ghttp.Request) {\n\t\tfile := r.GetUploadFile(\"file\")\n\t\tif file == nil {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\n\t\tif bytes, err := json.Marshal(file); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t} else {\n\t\t\tr.Response.WriteExit(bytes)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/single\", g.Map{\n\t\t\t\"file\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.Assert(strings.Contains(content, \"file1.txt\"), true)\n\t})\n}\n\n// Select only one file when batch uploading\nfunc Test_Params_Strict_Route_File_Batch_Up_One(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"post\" mime:\"multipart/form-data\"`\n\t\tFiles      ghttp.UploadFiles `type:\"file\"`\n\t}\n\ttype Res struct{}\n\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/batch\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\tvar (\n\t\t\tr     = g.RequestFromCtx(ctx)\n\t\t\tfiles = req.Files\n\t\t)\n\t\tif len(files) == 0 {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\t\tnames, err := files.Save(dstDirPath)\n\t\tif err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(gstr.Join(names, \",\"))\n\t\treturn\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tdstPath := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/batch\", g.Map{\n\t\t\t\"files\": \"@file:\" + srcPath,\n\t\t})\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))\n\t})\n}\n\n// Select multiple files during batch upload\nfunc Test_Params_Strict_Route_File_Batch_Up_Multiple(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"post\" mime:\"multipart/form-data\"`\n\t\tFiles      ghttp.UploadFiles `type:\"file\"`\n\t}\n\ttype Res struct{}\n\n\tdstDirPath := gfile.Temp(gtime.TimestampNanoStr())\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/upload/batch\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\tvar (\n\t\t\tr     = g.RequestFromCtx(ctx)\n\t\t\tfiles = req.Files\n\t\t)\n\t\tif len(files) == 0 {\n\t\t\tr.Response.WriteExit(\"upload file cannot be empty\")\n\t\t}\n\t\tnames, err := files.Save(dstDirPath)\n\t\tif err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(gstr.Join(names, \",\"))\n\t\treturn\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\t// normal name\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tsrcPath1 := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tsrcPath2 := gtest.DataPath(\"upload\", \"file2.txt\")\n\t\tdstPath1 := gfile.Join(dstDirPath, \"file1.txt\")\n\t\tdstPath2 := gfile.Join(dstDirPath, \"file2.txt\")\n\t\tcontent := client.PostContent(ctx, \"/upload/batch\",\n\t\t\t\"files=@file:\"+srcPath1+\n\t\t\t\t\"&files=@file:\"+srcPath2,\n\t\t)\n\t\tt.AssertNE(content, \"\")\n\t\tt.AssertNE(content, \"upload file cannot be empty\")\n\t\tt.AssertNE(content, \"upload failed\")\n\t\tt.Assert(content, \"file1.txt,file2.txt\")\n\t\tt.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))\n\t\tt.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Params_Json_Request(t *testing.T) {\n\ttype User struct {\n\t\tId    int\n\t\tName  string\n\t\tTime  *time.Time\n\t\tPass1 string `p:\"password1\"`\n\t\tPass2 string `p:\"password2\" v:\"password2@required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.WriteExit(r.Get(\"id\"), r.Get(\"name\"))\n\t})\n\ts.BindHandler(\"/map\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tr.Response.WriteExit(m[\"id\"], m[\"name\"], m[\"password1\"], m[\"password2\"])\n\t\t}\n\t})\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar user *User\n\t\t\tif err := r.Parse(&user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/get\", `{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}`), ``)\n\t\tt.Assert(client.GetContent(ctx, \"/map\", `{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}`), ``)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}`), `1john123Abc!@#123Abc!@#`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123\"}`), `密码强度不足`)\n\t})\n}\n\nfunc Test_Params_Json_Response(t *testing.T) {\n\ttype User struct {\n\t\tUid      int\n\t\tName     string\n\t\tSiteUrl  string `json:\"-\"`\n\t\tNickName string `json:\"nickname,omitempty\"`\n\t\tPass1    string `json:\"password1\"`\n\t\tPass2    string `json:\"password2\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/json1\", func(r *ghttp.Request) {\n\t\tr.Response.WriteJson(User{\n\t\t\tUid:     100,\n\t\t\tName:    \"john\",\n\t\t\tSiteUrl: \"https://goframe.org\",\n\t\t\tPass1:   \"123\",\n\t\t\tPass2:   \"456\",\n\t\t})\n\t})\n\ts.BindHandler(\"/json2\", func(r *ghttp.Request) {\n\t\tr.Response.WriteJson(&User{\n\t\t\tUid:     100,\n\t\t\tName:    \"john\",\n\t\t\tSiteUrl: \"https://goframe.org\",\n\t\t\tPass1:   \"123\",\n\t\t\tPass2:   \"456\",\n\t\t})\n\t})\n\ts.BindHandler(\"/json3\", func(r *ghttp.Request) {\n\t\ttype Message struct {\n\t\t\tCode  int    `json:\"code\"`\n\t\t\tBody  string `json:\"body,omitempty\"`\n\t\t\tError string `json:\"error,omitempty\"`\n\t\t}\n\t\ttype ResponseJson struct {\n\t\t\tSuccess  bool    `json:\"success\"`\n\t\t\tData     any     `json:\"data,omitempty\"`\n\t\t\tExtData  any     `json:\"ext_data,omitempty\"`\n\t\t\tPaginate any     `json:\"paginate,omitempty\"`\n\t\t\tMessage  Message `json:\"message,omitempty\"`\n\t\t}\n\t\tresponseJson := &ResponseJson{\n\t\t\tSuccess: true,\n\t\t\tData:    nil,\n\t\t\tExtData: nil,\n\t\t\tMessage: Message{3, \"测试\", \"error\"},\n\t\t}\n\t\tr.Response.WriteJson(responseJson)\n\t})\n\ts.BindHandler(\"/json4\", func(r *ghttp.Request) {\n\t\ttype Message struct {\n\t\t\tCode  int    `json:\"code\"`\n\t\t\tBody  string `json:\"body,omitempty\"`\n\t\t\tError string `json:\"error,omitempty\"`\n\t\t}\n\t\ttype ResponseJson struct {\n\t\t\tSuccess  bool     `json:\"success\"`\n\t\t\tData     any      `json:\"data,omitempty\"`\n\t\t\tExtData  any      `json:\"ext_data,omitempty\"`\n\t\t\tPaginate any      `json:\"paginate,omitempty\"`\n\t\t\tMessage  *Message `json:\"message,omitempty\"`\n\t\t}\n\t\tresponseJson := ResponseJson{\n\t\t\tSuccess: true,\n\t\t\tData:    nil,\n\t\t\tExtData: nil,\n\t\t\tMessage: &Message{3, \"测试\", \"error\"},\n\t\t}\n\t\tr.Response.WriteJson(responseJson)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tmap1 := make(map[string]any)\n\t\terr1 := json.UnmarshalUseNumber([]byte(client.GetContent(ctx, \"/json1\")), &map1)\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(len(map1), 4)\n\t\tt.Assert(map1[\"Name\"], \"john\")\n\t\tt.Assert(map1[\"Uid\"], 100)\n\t\tt.Assert(map1[\"password1\"], \"123\")\n\t\tt.Assert(map1[\"password2\"], \"456\")\n\n\t\tmap2 := make(map[string]any)\n\t\terr2 := json.UnmarshalUseNumber([]byte(client.GetContent(ctx, \"/json2\")), &map2)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(len(map2), 4)\n\t\tt.Assert(map2[\"Name\"], \"john\")\n\t\tt.Assert(map2[\"Uid\"], 100)\n\t\tt.Assert(map2[\"password1\"], \"123\")\n\t\tt.Assert(map2[\"password2\"], \"456\")\n\n\t\tmap3 := make(map[string]any)\n\t\terr3 := json.UnmarshalUseNumber([]byte(client.GetContent(ctx, \"/json3\")), &map3)\n\t\tt.Assert(err3, nil)\n\t\tt.Assert(len(map3), 2)\n\t\tt.Assert(map3[\"success\"], \"true\")\n\t\tt.Assert(map3[\"message\"], g.Map{\"body\": \"测试\", \"code\": 3, \"error\": \"error\"})\n\n\t\tmap4 := make(map[string]any)\n\t\terr4 := json.UnmarshalUseNumber([]byte(client.GetContent(ctx, \"/json4\")), &map4)\n\t\tt.Assert(err4, nil)\n\t\tt.Assert(len(map4), 2)\n\t\tt.Assert(map4[\"success\"], \"true\")\n\t\tt.Assert(map4[\"message\"], g.Map{\"body\": \"测试\", \"code\": 3, \"error\": \"error\"})\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_page_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Params_Page(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/list\", func(r *ghttp.Request) {\n\t\t\tpage := r.GetPage(5, 2)\n\t\t\tr.Response.Write(page.GetContent(4))\n\t\t})\n\t\tgroup.GET(\"/list/{page}.html\", func(r *ghttp.Request) {\n\t\t\tpage := r.GetPage(5, 2)\n\t\t\tr.Response.Write(page.GetContent(4))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/list\"), `<span class=\"GPageSpan\">首页</span><span class=\"GPageSpan\">上一页</span><span class=\"GPageSpan\">1</span><a class=\"GPageLink\" href=\"/list?page=2\" title=\"2\">2</a><a class=\"GPageLink\" href=\"/list?page=3\" title=\"3\">3</a><a class=\"GPageLink\" href=\"/list?page=2\" title=\"\">下一页</a><a class=\"GPageLink\" href=\"/list?page=3\" title=\"\">尾页</a>`)\n\t\tt.Assert(client.GetContent(ctx, \"/list?page=3\"), `<a class=\"GPageLink\" href=\"/list?page=1\" title=\"\">首页</a><a class=\"GPageLink\" href=\"/list?page=2\" title=\"\">上一页</a><a class=\"GPageLink\" href=\"/list?page=1\" title=\"1\">1</a><a class=\"GPageLink\" href=\"/list?page=2\" title=\"2\">2</a><span class=\"GPageSpan\">3</span><span class=\"GPageSpan\">下一页</span><span class=\"GPageSpan\">尾页</span>`)\n\n\t\tt.Assert(client.GetContent(ctx, \"/list/1.html\"), `<span class=\"GPageSpan\">首页</span><span class=\"GPageSpan\">上一页</span><span class=\"GPageSpan\">1</span><a class=\"GPageLink\" href=\"/list/2.html\" title=\"2\">2</a><a class=\"GPageLink\" href=\"/list/3.html\" title=\"3\">3</a><a class=\"GPageLink\" href=\"/list/2.html\" title=\"\">下一页</a><a class=\"GPageLink\" href=\"/list/3.html\" title=\"\">尾页</a>`)\n\t\tt.Assert(client.GetContent(ctx, \"/list/3.html\"), `<a class=\"GPageLink\" href=\"/list/1.html\" title=\"\">首页</a><a class=\"GPageLink\" href=\"/list/2.html\" title=\"\">上一页</a><a class=\"GPageLink\" href=\"/list/1.html\" title=\"1\">1</a><a class=\"GPageLink\" href=\"/list/2.html\" title=\"2\">2</a><span class=\"GPageSpan\">3</span><span class=\"GPageSpan\">下一页</span><span class=\"GPageSpan\">尾页</span>`)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_param_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// UserTagInReq struct tag \"in\" supports: header, cookie\ntype UserTagInReq struct {\n\tg.Meta `path:\"/user\" tags:\"User\" method:\"post\" summary:\"user api\" title:\"api title\"`\n\tId     int    `v:\"required\" d:\"1\"`\n\tName   string `v:\"required\" in:\"cookie\"`\n\tAge    string `v:\"required\" in:\"header\"`\n}\n\ntype UserTagInRes struct {\n\tg.Meta `mime:\"text/html\" example:\"string\"`\n}\n\nvar (\n\tUserTagIn = cUserTagIn{}\n)\n\ntype cUserTagIn struct{}\n\nfunc (c *cUserTagIn) User(ctx context.Context, req *UserTagInReq) (res *UserTagInRes, err error) {\n\tg.RequestFromCtx(ctx).Response.WriteJson(req)\n\treturn\n}\n\nfunc Test_ParamsTagIn(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(UserTagIn)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tclient.SetCookie(\"name\", \"john\")\n\t\tclient.SetHeader(\"age\", \"18\")\n\n\t\tt.Assert(client.PostContent(ctx, \"/user\"), `{\"Id\":1,\"Name\":\"john\",\"Age\":\"18\"}`)\n\t\tt.Assert(client.PostContent(ctx, \"/user\", \"name=&age=\"), `{\"Id\":1,\"Name\":\"john\",\"Age\":\"18\"}`)\n\t})\n}\n\ntype UserTagDefaultReq struct {\n\tg.Meta   `path:\"/user-default\" method:\"post,get\" summary:\"user default tag api\"`\n\tId       int     `v:\"required\" d:\"1\"`\n\tName     string  `d:\"john\"`\n\tAge      int     `d:\"18\"`\n\tScore    float64 `d:\"99.9\"`\n\tIsVip    bool    `d:\"true\"`\n\tNickName string  `p:\"nickname\" d:\"nickname-default\"`\n\tEmptyStr string  `d:\"\"`\n\tEmail    string\n\tAddress  string\n}\n\ntype UserTagDefaultRes struct {\n\tg.Meta `mime:\"application/json\" example:\"string\"`\n}\n\nvar (\n\tUserTagDefault = cUserTagDefault{}\n)\n\ntype cUserTagDefault struct{}\n\nfunc (c *cUserTagDefault) User(ctx context.Context, req *UserTagDefaultReq) (res *UserTagDefaultRes, err error) {\n\tg.RequestFromCtx(ctx).Response.WriteJson(req)\n\treturn\n}\n\nfunc Test_ParamsTagDefault(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(UserTagDefault)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\t// Test with no parameters, should use all default values\n\t\tresp := client.GetContent(ctx, \"/user-default\")\n\t\tt.Assert(resp, `{\"Id\":1,\"Name\":\"john\",\"Age\":18,\"Score\":99.9,\"IsVip\":true,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test with partial parameters (query method), should use partial default values\n\t\tresp = client.GetContent(ctx, \"/user-default?id=100&name=smith\")\n\t\tt.Assert(resp, `{\"Id\":100,\"Name\":\"smith\",\"Age\":18,\"Score\":99.9,\"IsVip\":true,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test with partial parameters (query method), should use partial default values\n\t\tresp = client.GetContent(ctx, \"/user-default?id=100&name=smith&age\")\n\t\tt.Assert(resp, `{\"Id\":100,\"Name\":\"smith\",\"Age\":18,\"Score\":99.9,\"IsVip\":true,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test providing partial parameters via POST form\n\t\tresp = client.PostContent(ctx, \"/user-default\", \"id=200&age=30&nickname=jack\")\n\t\tt.Assert(resp, `{\"Id\":200,\"Name\":\"john\",\"Age\":30,\"Score\":99.9,\"IsVip\":true,\"NickName\":\"jack\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test providing partial parameters via POST JSON\n\t\tresp = client.ContentJson().PostContent(ctx, \"/user-default\", g.Map{\n\t\t\t\"id\":      300,\n\t\t\t\"name\":    \"bob\",\n\t\t\t\"score\":   88.8,\n\t\t\t\"address\": \"beijing\",\n\t\t})\n\t\tt.Assert(resp, `{\"Id\":300,\"Name\":\"bob\",\"Age\":18,\"Score\":88.8,\"IsVip\":true,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"beijing\"}`)\n\n\t\t// Test providing JSON content via GET request\n\t\tresp = client.ContentJson().PostContent(ctx, \"/user-default\", `{\"id\":500,\"isVip\":false}`)\n\t\tt.Assert(resp, `{\"Id\":500,\"Name\":\"john\",\"Age\":18,\"Score\":99.9,\"IsVip\":false,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test providing empty values, should use default values\n\t\tresp = client.PostContent(ctx, \"/user-default\", \"id=400&name=&age=\")\n\t\tt.Assert(resp, `{\"Id\":400,\"Name\":\"\",\"Age\":0,\"Score\":99.9,\"IsVip\":true,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\n\t\t// Test providing JSON content via GET request\n\t\tresp = client.ContentJson().GetContent(ctx, \"/user-default\", `{\"id\":500,\"isVip\":false}`)\n\t\tt.Assert(resp, `{\"Id\":500,\"Name\":\"john\",\"Age\":18,\"Score\":99.9,\"IsVip\":false,\"NickName\":\"nickname-default\",\"EmptyStr\":\"\",\"Email\":\"\",\"Address\":\"\"}`)\n\t})\n}\n\nfunc Benchmark_ParamTagIn(b *testing.B) {\n\tb.StopTimer()\n\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(UserTagIn)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.SetAccessLogEnabled(false)\n\ts.SetErrorLogEnabled(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\tclient := g.Client()\n\tclient.SetPrefix(prefix)\n\tclient.SetCookie(\"name\", \"john\")\n\tclient.SetHeader(\"age\", \"18\")\n\n\tb.StartTimer()\n\tfor i := 1; i < b.N; i++ {\n\t\tclient.PostContent(ctx, \"/user\", \"id=\"+strconv.Itoa(i))\n\t}\n}\n\ntype UserValidReq struct {\n\tg.Meta   `path:\"/user\" method:\"get\" tags:\"XXX\" summary:\"XXX\"`\n\tQuery    string `p:\"query\" dc:\"查询参数\"`\n\tPage     int    `p:\"page_index\" v:\"min:1\" dc:\"页码，从1开始\" d:\"1\"`\n\tPageSize int    `p:\"size\" v:\"between:1,50\" dc:\"每页大小，最大50\" d:\"20\"`\n}\n\ntype UserValidRes struct {\n\tg.Meta `mime:\"application/json\"`\n}\n\nvar (\n\tUserValid = cUserValid{}\n)\n\ntype cUserValid struct{}\n\nfunc (c *cUserValid) User(ctx context.Context, req *UserValidReq) (res *UserValidRes, err error) {\n\tg.RequestFromCtx(ctx).Response.WriteJson(req)\n\treturn\n}\n\n// Test_Params_Valid for #4442\nfunc Test_Params_Valid(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(UserValid)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/user\"), `{\"Query\":\"\",\"Page\":1,\"PageSize\":20}`)\n\t\tt.Assert(client.GetContent(ctx, \"/user?page_index=0\"), `{\"code\":51,\"message\":\"The page_index value `+\"`0`\"+` must be equal or greater than 1\",\"data\":null}`)\n\t\tt.Assert(client.GetContent(ctx, \"/user?size=100\"), `{\"code\":51,\"message\":\"The size value `+\"`100`\"+` must be between 1 and 50\",\"data\":null}`)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nfunc Test_Params_Parse(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t\tMap  map[string]any\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar user *User\n\t\tif err := r.Parse(&user); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(user.Map[\"id\"], user.Map[\"score\"])\n\t})\n\ts.BindHandler(\"/parseErr\", func(r *ghttp.Request) {\n\t\tvar user User\n\t\terr := r.Parse(user)\n\t\tr.Response.WriteExit(err != nil)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"id\":1,\"name\":\"john\",\"map\":{\"id\":1,\"score\":100}}`), `1100`)\n\t\tt.Assert(client.PostContent(ctx, \"/parseErr\", `{\"id\":1,\"name\":\"john\",\"map\":{\"id\":1,\"score\":100}}`), true)\n\t})\n}\n\nfunc Test_Params_ParseQuery(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse-query\", func(r *ghttp.Request) {\n\t\tvar user *User\n\t\tif err := r.ParseQuery(&user); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(user.Id, user.Name)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/parse-query\"), `0`)\n\t\tt.Assert(c.GetContent(ctx, \"/parse-query?id=1&name=john\"), `1john`)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-query\"), `0`)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-query\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), `0`)\n\t})\n}\n\nfunc Test_Params_ParseForm(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse-form\", func(r *ghttp.Request) {\n\t\tvar user *User\n\t\tif err := r.ParseForm(&user); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(user.Id, user.Name)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/parse-form\"), `0`)\n\t\tt.Assert(c.GetContent(ctx, \"/parse-form\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), 0)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-form\"), `0`)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-form\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), `1john`)\n\t})\n}\n\n// https://github.com/gogf/gf/pull/4143\nfunc Test_Params_ParseForm_FixMakeBodyRepeatableRead(t *testing.T) {\n\ttype User struct {\n\t\tId   int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse-form\", func(r *ghttp.Request) {\n\t\tvar user *User\n\t\tif err := r.ParseForm(&user); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\thasBody := len(r.GetBody()) > 0\n\t\tr.Response.WriteExit(hasBody)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/parse-form\"), `false`)\n\t\tt.Assert(c.GetContent(ctx, \"/parse-form\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), false)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-form\"), `false`)\n\t\tt.Assert(c.PostContent(ctx, \"/parse-form\", g.Map{\n\t\t\t\"id\":   1,\n\t\t\t\"name\": \"john\",\n\t\t}), true)\n\t})\n}\n\nfunc Test_Params_ComplexJsonStruct(t *testing.T) {\n\ttype ItemEnv struct {\n\t\tType  string\n\t\tKey   string\n\t\tValue string\n\t\tBrief string\n\t}\n\n\ttype ItemProbe struct {\n\t\tType           string\n\t\tPort           int\n\t\tPath           string\n\t\tBrief          string\n\t\tPeriod         int\n\t\tInitialDelay   int\n\t\tTimeoutSeconds int\n\t}\n\n\ttype ItemKV struct {\n\t\tKey   string\n\t\tValue string\n\t}\n\n\ttype ItemPort struct {\n\t\tPort  int\n\t\tType  string\n\t\tAlias string\n\t\tBrief string\n\t}\n\n\ttype ItemMount struct {\n\t\tType    string\n\t\tDstPath string\n\t\tSrc     string\n\t\tSrcPath string\n\t\tBrief   string\n\t}\n\n\ttype SaveRequest struct {\n\t\tAppId          uint\n\t\tName           string\n\t\tType           string\n\t\tCluster        string\n\t\tReplicas       uint\n\t\tContainerName  string\n\t\tContainerImage string\n\t\tVersionTag     string\n\t\tNamespace      string\n\t\tId             uint\n\t\tStatus         uint\n\t\tMetrics        string\n\t\tInitImage      string\n\t\tCpuRequest     uint\n\t\tCpuLimit       uint\n\t\tMemRequest     uint\n\t\tMemLimit       uint\n\t\tMeshEnabled    uint\n\t\tContainerPorts []ItemPort\n\t\tLabels         []ItemKV\n\t\tNodeSelector   []ItemKV\n\t\tEnvReserve     []ItemKV\n\t\tEnvGlobal      []ItemEnv\n\t\tEnvContainer   []ItemEnv\n\t\tMounts         []ItemMount\n\t\tLivenessProbe  ItemProbe\n\t\tReadinessProbe ItemProbe\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar data *SaveRequest\n\t\t\tif err := r.Parse(&data); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(data)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tcontent := `\n{\n    \"app_id\": 5,\n    \"cluster\": \"test\",\n    \"container_image\": \"nginx\",\n    \"container_name\": \"test\",\n    \"container_ports\": [\n        {\n            \"alias\": \"别名\",\n            \"brief\": \"描述\",\n            \"port\": 80,\n            \"type\": \"tcp\"\n        }\n    ],\n    \"cpu_limit\": 100,\n    \"cpu_request\": 10,\n    \"create_at\": \"2020-10-10 12:00:00\",\n    \"creator\": 1,\n    \"env_container\": [\n        {\n            \"brief\": \"用户环境变量\",\n            \"key\": \"NAME\",\n            \"type\": \"string\",\n            \"value\": \"john\"\n        }\n    ],\n    \"env_global\": [\n        {\n            \"brief\": \"数据数量\",\n            \"key\": \"NUMBER\",\n            \"type\": \"string\",\n            \"value\": \"1\"\n        }\n    ],\n    \"env_reserve\": [\n        {\n            \"key\": \"NODE_IP\",\n            \"value\": \"status.hostIP\"\n        }\n    ],\n    \"liveness_probe\": {\n        \"brief\": \"存活探针\",\n        \"initial_delay\": 10,\n        \"path\": \"\",\n        \"period\": 5,\n        \"port\": 80,\n        \"type\": \"tcpSocket\"\n    },\n    \"readiness_probe\": {\n        \"brief\": \"就绪探针\",\n        \"initial_delay\": 10,\n        \"path\": \"\",\n        \"period\": 5,\n        \"port\": 80,\n        \"type\": \"tcpSocket\"\n    },\n    \"id\": 0,\n    \"init_image\": \"\",\n    \"labels\": [\n        {\n            \"key\": \"app\",\n            \"value\": \"test\"\n        }\n    ],\n    \"mem_limit\": 1000,\n    \"mem_request\": 100,\n    \"mesh_enabled\": 0,\n    \"metrics\": \"\",\n    \"mounts\": [],\n    \"name\": \"test\",\n    \"namespace\": \"test\",\n    \"node_selector\": [\n        {\n            \"key\": \"group\",\n            \"value\": \"app\"\n        }\n    ],\n    \"replicas\": 1,\n    \"type\": \"test\",\n    \"update_at\": \"2020-10-10 12:00:00\",\n    \"version_tag\": \"test\"\n}\n`\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", content), `{\"AppId\":5,\"Name\":\"test\",\"Type\":\"test\",\"Cluster\":\"test\",\"Replicas\":1,\"ContainerName\":\"test\",\"ContainerImage\":\"nginx\",\"VersionTag\":\"test\",\"Namespace\":\"test\",\"Id\":0,\"Status\":0,\"Metrics\":\"\",\"InitImage\":\"\",\"CpuRequest\":10,\"CpuLimit\":100,\"MemRequest\":100,\"MemLimit\":1000,\"MeshEnabled\":0,\"ContainerPorts\":[{\"Port\":80,\"Type\":\"tcp\",\"Alias\":\"别名\",\"Brief\":\"描述\"}],\"Labels\":[{\"Key\":\"app\",\"Value\":\"test\"}],\"NodeSelector\":[{\"Key\":\"group\",\"Value\":\"app\"}],\"EnvReserve\":[{\"Key\":\"NODE_IP\",\"Value\":\"status.hostIP\"}],\"EnvGlobal\":[{\"Type\":\"string\",\"Key\":\"NUMBER\",\"Value\":\"1\",\"Brief\":\"数据数量\"}],\"EnvContainer\":[{\"Type\":\"string\",\"Key\":\"NAME\",\"Value\":\"john\",\"Brief\":\"用户环境变量\"}],\"Mounts\":[],\"LivenessProbe\":{\"Type\":\"tcpSocket\",\"Port\":80,\"Path\":\"\",\"Brief\":\"存活探针\",\"Period\":5,\"InitialDelay\":10,\"TimeoutSeconds\":0},\"ReadinessProbe\":{\"Type\":\"tcpSocket\",\"Port\":80,\"Path\":\"\",\"Brief\":\"就绪探针\",\"Period\":5,\"InitialDelay\":10,\"TimeoutSeconds\":0}}`)\n\t})\n}\n\nfunc Test_Params_Parse_Attr_Pointer1(t *testing.T) {\n\ttype User struct {\n\t\tId   *int\n\t\tName *string\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse1\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar user *User\n\t\t\tif err := r.Parse(&user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name)\n\t\t}\n\t})\n\ts.BindHandler(\"/parse2\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar user = new(User)\n\t\t\tif err := r.Parse(user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.PostContent(ctx, \"/parse1\", `{\"id\":1,\"name\":\"john\"}`), `1john`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse2\", `{\"id\":1,\"name\":\"john\"}`), `1john`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse2?id=1&name=john\"), `1john`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse2\", `id=1&name=john`), `1john`)\n\t})\n}\n\nfunc Test_Params_Parse_Attr_Pointer2(t *testing.T) {\n\ttype User struct {\n\t\tId *int `v:\"required\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar user *User\n\t\tif err := r.Parse(&user); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tr.Response.WriteExit(user.Id)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.PostContent(ctx, \"/parse\"), `The Id field is required`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse?id=1\"), `1`)\n\t})\n}\n\n// It does not support this kind of converting yet.\n// func Test_Params_Parse_Attr_SliceSlice(t *testing.T) {\n//\ttype User struct {\n//\t\tId     int\n//\t\tName   string\n//\t\tScores [][]int\n//\t}\n//\t//\ts := g.Server(guid.S())\n//\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n//\t\tif m := r.GetMap(); len(m) > 0 {\n//\t\t\tvar user *User\n//\t\t\tif err := r.Parse(&user); err != nil {\n//\t\t\t\tr.Response.WriteExit(err)\n//\t\t\t}\n//\t\t\tr.Response.WriteExit(user.Scores)\n//\t\t}\n//\t})\n//\t//\ts.SetDumpRouterMap(false)\n//\ts.Start()\n//\tdefer s.Shutdown()\n//\n//\ttime.Sleep(100 * time.Millisecond)\n//\tgtest.C(t, func(t *gtest.T) {\n//\t\tclient := g.Client()\n//\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n//\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"id\":1,\"name\":\"john\",\"scores\":[[1,2,3]]}`), `1100`)\n//\t})\n// }\n\nfunc Test_Params_Struct(t *testing.T) {\n\ttype User struct {\n\t\tId    int\n\t\tName  string\n\t\tTime  *time.Time\n\t\tPass1 string `p:\"password1\"`\n\t\tPass2 string `p:\"password2\" v:\"password2 @required|length:2,20|password3#||密码强度不足\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/struct1\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tuser := new(User)\n\t\t\tif err := r.GetStruct(user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t}\n\t})\n\ts.BindHandler(\"/struct2\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tuser := (*User)(nil)\n\t\t\tif err := r.GetStruct(&user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tif user != nil {\n\t\t\t\tr.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t\t}\n\t\t}\n\t})\n\ts.BindHandler(\"/struct-valid\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tuser := new(User)\n\t\t\tif err := r.GetStruct(user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tif err := gvalid.New().Data(user).Run(r.Context()); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t}\n\t})\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar user *User\n\t\t\tif err := r.Parse(&user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/struct1\", `id=1&name=john&password1=123&password2=456`), `1john123456`)\n\t\tt.Assert(client.PostContent(ctx, \"/struct1\", `id=1&name=john&password1=123&password2=456`), `1john123456`)\n\t\tt.Assert(client.PostContent(ctx, \"/struct2\", `id=1&name=john&password1=123&password2=456`), `1john123456`)\n\t\tt.Assert(client.PostContent(ctx, \"/struct2\", ``), ``)\n\t\tt.Assert(client.PostContent(ctx, \"/struct-valid\", `id=1&name=john&password1=123&password2=0`), \"The password2 value `0` length must be between 2 and 20; 密码强度不足\")\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `id=1&name=john&password1=123&password2=0`), \"The password2 value `0` length must be between 2 and 20\")\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}`), `1john123Abc!@#123Abc!@#`)\n\t})\n}\n\nfunc Test_Params_Structs(t *testing.T) {\n\ttype User struct {\n\t\tId    int\n\t\tName  string\n\t\tTime  *time.Time\n\t\tPass1 string `p:\"password1\"`\n\t\tPass2 string `p:\"password2\" v:\"password2 @required|length:2,20|password3#||密码强度不足\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse1\", func(r *ghttp.Request) {\n\t\tvar users []*User\n\t\tif err := r.Parse(&users); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(users[0].Id, users[1].Id)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.PostContent(ctx,\n\t\t\t\"/parse1\",\n\t\t\t`[{\"id\":1,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}, {\"id\":2,\"name\":\"john\",\"password1\":\"123Abc!@#\",\"password2\":\"123Abc!@#\"}]`),\n\t\t\t`12`,\n\t\t)\n\t})\n}\n\nfunc Test_Params_Struct_Validation(t *testing.T) {\n\ttype User struct {\n\t\tId   int    `v:\"required\"`\n\t\tName string `v:\"name@required-with:id\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tvar (\n\t\t\t\terr  error\n\t\t\t\tuser *User\n\t\t\t)\n\t\t\terr = r.Parse(&user)\n\t\t\tif err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name)\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\", ``), `The Id field is required`)\n\t\tt.Assert(c.GetContent(ctx, \"/\", `id=1&name=john`), `1john`)\n\t\tt.Assert(c.PostContent(ctx, \"/\", `id=1&name=john&password1=123&password2=456`), `1john`)\n\t\tt.Assert(c.PostContent(ctx, \"/\", `id=1`), `The name field is required`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1488\nfunc Test_Params_Parse_Issue1488(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\ttype Request struct {\n\t\t\t\tType         []int  `p:\"type\"`\n\t\t\t\tKeyword      string `p:\"keyword\"`\n\t\t\t\tLimit        int    `p:\"per_page\" d:\"10\"`\n\t\t\t\tPage         int    `p:\"page\" d:\"1\"`\n\t\t\t\tOrder        string\n\t\t\t\tCreatedAtLte string\n\t\t\t\tCreatedAtGte string\n\t\t\t\tCreatorID    []int\n\t\t\t}\n\t\t\tfor i := 0; i < 10; i++ {\n\t\t\t\tr.SetParamMap(g.Map{\n\t\t\t\t\t\"type[]\":           0,\n\t\t\t\t\t\"keyword\":          \"\",\n\t\t\t\t\t\"t_start\":          \"\",\n\t\t\t\t\t\"t_end\":            \"\",\n\t\t\t\t\t\"reserve_at_start\": \"\",\n\t\t\t\t\t\"reserve_at_end\":   \"\",\n\t\t\t\t\t\"user_name\":        \"\",\n\t\t\t\t\t\"flag\":             \"\",\n\t\t\t\t\t\"per_page\":         6,\n\t\t\t\t})\n\t\t\t\tvar parsed Request\n\t\t\t\t_ = r.Parse(&parsed)\n\t\t\t\tr.Response.Write(parsed.Page, parsed.Limit)\n\t\t\t}\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\", ``), `16161616161616161616`)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Params_Basic(t *testing.T) {\n\ttype User struct {\n\t\tId    int\n\t\tName  string\n\t\tPass1 string `p:\"password1\"`\n\t\tPass2 string `p:\"password2\"`\n\t}\n\ts := g.Server(guid.S())\n\t// GET\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tif r.GetQuery(\"array\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"array\"))\n\t\t}\n\t\tif r.GetQuery(\"slice\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"slice\"))\n\t\t}\n\t\tif r.GetQuery(\"bool\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"bool\").Bool())\n\t\t}\n\t\tif r.GetQuery(\"float32\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"float32\").Float32())\n\t\t}\n\t\tif r.GetQuery(\"float64\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"float64\").Float64())\n\t\t}\n\t\tif r.GetQuery(\"int\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"int\").Int())\n\t\t}\n\t\tif r.GetQuery(\"uint\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"uint\").Uint())\n\t\t}\n\t\tif r.GetQuery(\"string\") != nil {\n\t\t\tr.Response.Write(r.GetQuery(\"string\").String())\n\t\t}\n\t\tif r.GetQuery(\"map\") != nil {\n\t\t\tr.Response.Write(r.GetQueryMap()[\"map\"].(map[string]any)[\"b\"])\n\t\t}\n\t\tif r.GetQuery(\"a\") != nil {\n\t\t\tr.Response.Write(r.GetQueryMapStrStr()[\"a\"])\n\t\t}\n\t})\n\t// PUT\n\ts.BindHandler(\"/put\", func(r *ghttp.Request) {\n\t\tif r.Get(\"array\") != nil {\n\t\t\tr.Response.Write(r.Get(\"array\"))\n\t\t}\n\t\tif r.Get(\"slice\") != nil {\n\t\t\tr.Response.Write(r.Get(\"slice\"))\n\t\t}\n\t\tif r.Get(\"bool\") != nil {\n\t\t\tr.Response.Write(r.Get(\"bool\").Bool())\n\t\t}\n\t\tif r.Get(\"float32\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float32\").Float32())\n\t\t}\n\t\tif r.Get(\"float64\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float64\").Float64())\n\t\t}\n\t\tif r.Get(\"int\") != nil {\n\t\t\tr.Response.Write(r.Get(\"int\").Int())\n\t\t}\n\t\tif r.Get(\"uint\") != nil {\n\t\t\tr.Response.Write(r.Get(\"uint\").Uint())\n\t\t}\n\t\tif r.Get(\"string\") != nil {\n\t\t\tr.Response.Write(r.Get(\"string\").String())\n\t\t}\n\t\tif r.Get(\"map\") != nil {\n\t\t\tr.Response.Write(r.GetMap()[\"map\"].(map[string]any)[\"b\"])\n\t\t}\n\t\tif r.Get(\"a\") != nil {\n\t\t\tr.Response.Write(r.GetMapStrStr()[\"a\"])\n\t\t}\n\t})\n\n\t// DELETE\n\ts.BindHandler(\"/delete\", func(r *ghttp.Request) {\n\t\tif r.Get(\"array\") != nil {\n\t\t\tr.Response.Write(r.Get(\"array\"))\n\t\t}\n\t\tif r.Get(\"slice\") != nil {\n\t\t\tr.Response.Write(r.Get(\"slice\"))\n\t\t}\n\t\tif r.Get(\"bool\") != nil {\n\t\t\tr.Response.Write(r.Get(\"bool\").Bool())\n\t\t}\n\t\tif r.Get(\"float32\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float32\").Float32())\n\t\t}\n\t\tif r.Get(\"float64\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float64\").Float64())\n\t\t}\n\t\tif r.Get(\"int\") != nil {\n\t\t\tr.Response.Write(r.Get(\"int\").Int())\n\t\t}\n\t\tif r.Get(\"uint\") != nil {\n\t\t\tr.Response.Write(r.Get(\"uint\").Uint())\n\t\t}\n\t\tif r.Get(\"string\") != nil {\n\t\t\tr.Response.Write(r.Get(\"string\").String())\n\t\t}\n\t\tif r.Get(\"map\") != nil {\n\t\t\tr.Response.Write(r.GetMap()[\"map\"].(map[string]any)[\"b\"])\n\t\t}\n\t\tif r.Get(\"a\") != nil {\n\t\t\tr.Response.Write(r.GetMapStrStr()[\"a\"])\n\t\t}\n\t})\n\t// PATCH\n\ts.BindHandler(\"/patch\", func(r *ghttp.Request) {\n\t\tif r.Get(\"array\") != nil {\n\t\t\tr.Response.Write(r.Get(\"array\"))\n\t\t}\n\t\tif r.Get(\"slice\") != nil {\n\t\t\tr.Response.Write(r.Get(\"slice\"))\n\t\t}\n\t\tif r.Get(\"bool\") != nil {\n\t\t\tr.Response.Write(r.Get(\"bool\").Bool())\n\t\t}\n\t\tif r.Get(\"float32\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float32\").Float32())\n\t\t}\n\t\tif r.Get(\"float64\") != nil {\n\t\t\tr.Response.Write(r.Get(\"float64\").Float64())\n\t\t}\n\t\tif r.Get(\"int\") != nil {\n\t\t\tr.Response.Write(r.Get(\"int\").Int())\n\t\t}\n\t\tif r.Get(\"uint\") != nil {\n\t\t\tr.Response.Write(r.Get(\"uint\").Uint())\n\t\t}\n\t\tif r.Get(\"string\") != nil {\n\t\t\tr.Response.Write(r.Get(\"string\").String())\n\t\t}\n\t\tif r.Get(\"map\") != nil {\n\t\t\tr.Response.Write(r.GetMap()[\"map\"].(map[string]any)[\"b\"])\n\t\t}\n\t\tif r.Get(\"a\") != nil {\n\t\t\tr.Response.Write(r.GetMapStrStr()[\"a\"])\n\t\t}\n\t})\n\t// Form\n\ts.BindHandler(\"/form\", func(r *ghttp.Request) {\n\t\tif r.Get(\"array\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"array\"))\n\t\t}\n\t\tif r.Get(\"slice\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"slice\"))\n\t\t}\n\t\tif r.Get(\"bool\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"bool\").Bool())\n\t\t}\n\t\tif r.Get(\"float32\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"float32\").Float32())\n\t\t}\n\t\tif r.Get(\"float64\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"float64\").Float64())\n\t\t}\n\t\tif r.Get(\"int\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"int\").Int())\n\t\t}\n\t\tif r.Get(\"uint\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"uint\").Uint())\n\t\t}\n\t\tif r.Get(\"string\") != nil {\n\t\t\tr.Response.Write(r.GetForm(\"string\").String())\n\t\t}\n\t\tif r.Get(\"map\") != nil {\n\t\t\tr.Response.Write(r.GetFormMap()[\"map\"].(map[string]any)[\"b\"])\n\t\t}\n\t\tif r.Get(\"a\") != nil {\n\t\t\tr.Response.Write(r.GetFormMapStrStr()[\"a\"])\n\t\t}\n\t})\n\ts.BindHandler(\"/map\", func(r *ghttp.Request) {\n\t\tif m := r.GetQueryMap(); len(m) > 0 {\n\t\t\tr.Response.Write(m[\"name\"])\n\t\t\treturn\n\t\t}\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tr.Response.Write(m[\"name\"])\n\t\t\treturn\n\t\t}\n\t})\n\ts.BindHandler(\"/raw\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetBody())\n\t})\n\ts.BindHandler(\"/json\", func(r *ghttp.Request) {\n\t\tj, err := r.GetJson()\n\t\tif err != nil {\n\t\t\tr.Response.Write(err)\n\t\t\treturn\n\t\t}\n\t\tr.Response.Write(j.Get(\"name\"))\n\t})\n\ts.BindHandler(\"/struct\", func(r *ghttp.Request) {\n\t\tif m := r.GetQueryMap(); len(m) > 0 {\n\t\t\tuser := new(User)\n\t\t\tr.GetQueryStruct(user)\n\t\t\tr.Response.Write(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t\treturn\n\t\t}\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tuser := new(User)\n\t\t\tr.GetStruct(user)\n\t\t\tr.Response.Write(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t\treturn\n\t\t}\n\t})\n\ts.BindHandler(\"/struct-with-nil\", func(r *ghttp.Request) {\n\t\tuser := (*User)(nil)\n\t\terr := r.GetStruct(&user)\n\t\tr.Response.Write(err)\n\t})\n\ts.BindHandler(\"/struct-with-base\", func(r *ghttp.Request) {\n\t\ttype Base struct {\n\t\t\tPass1 string `p:\"password1\"`\n\t\t\tPass2 string `p:\"password2\"`\n\t\t}\n\t\ttype UserWithBase1 struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t\tBase\n\t\t}\n\t\ttype UserWithBase2 struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t\tPass Base\n\t\t}\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tuser1 := new(UserWithBase1)\n\t\t\tuser2 := new(UserWithBase2)\n\t\t\tr.GetStruct(user1)\n\t\t\tr.GetStruct(user2)\n\t\t\tr.Response.Write(user1.Id, user1.Name, user1.Pass1, user1.Pass2)\n\t\t\tr.Response.Write(user2.Id, user2.Name, user2.Pass.Pass1, user2.Pass.Pass2)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\t// GET\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"array[]=1&array[]=2\"), `[\"1\",\"2\"]`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"slice=1&slice=2\"), `2`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"bool=1\"), `true`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"bool=0\"), `false`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"float32=0.11\"), `0.11`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"float64=0.22\"), `0.22`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"int=-10000\"), `-10000`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"int=10000\"), `10000`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"uint=10000\"), `10000`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"uint=9\"), `9`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"string=key\"), `key`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"map[a]=1&map[b]=2\"), `2`)\n\t\tt.Assert(client.GetContent(ctx, \"/get\", \"a=1&b=2\"), `1`)\n\n\t\t// PUT\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"array[]=1&array[]=2\"), `[\"1\",\"2\"]`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"slice=1&slice=2\"), `2`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"bool=1\"), `true`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"bool=0\"), `false`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"float32=0.11\"), `0.11`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"float64=0.22\"), `0.22`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"int=-10000\"), `-10000`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"int=10000\"), `10000`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"uint=10000\"), `10000`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"uint=9\"), `9`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"string=key\"), `key`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"map[a]=1&map[b]=2\"), `2`)\n\t\tt.Assert(client.PutContent(ctx, \"/put\", \"a=1&b=2\"), `1`)\n\n\t\t// DELETE\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"array[]=1&array[]=2\"), `[\"1\",\"2\"]`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"slice=1&slice=2\"), `2`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"bool=1\"), `true`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"bool=0\"), `false`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"float32=0.11\"), `0.11`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"float64=0.22\"), `0.22`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"int=-10000\"), `-10000`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"int=10000\"), `10000`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"uint=10000\"), `10000`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"uint=9\"), `9`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"string=key\"), `key`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"map[a]=1&map[b]=2\"), `2`)\n\t\tt.Assert(client.DeleteContent(ctx, \"/delete\", \"a=1&b=2\"), `1`)\n\n\t\t// PATCH\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"array[]=1&array[]=2\"), `[\"1\",\"2\"]`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"slice=1&slice=2\"), `2`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"bool=1\"), `true`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"bool=0\"), `false`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"float32=0.11\"), `0.11`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"float64=0.22\"), `0.22`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"int=-10000\"), `-10000`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"int=10000\"), `10000`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"uint=10000\"), `10000`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"uint=9\"), `9`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"string=key\"), `key`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"map[a]=1&map[b]=2\"), `2`)\n\t\tt.Assert(client.PatchContent(ctx, \"/patch\", \"a=1&b=2\"), `1`)\n\n\t\t// Form\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"array[]=1&array[]=2\"), `[\"1\",\"2\"]`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"slice=1&slice=2\"), `2`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"bool=1\"), `true`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"bool=0\"), `false`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"float32=0.11\"), `0.11`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"float64=0.22\"), `0.22`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"int=-10000\"), `-10000`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"int=10000\"), `10000`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"uint=10000\"), `10000`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"uint=9\"), `9`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"string=key\"), `key`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"map[a]=1&map[b]=2\"), `2`)\n\t\tt.Assert(client.PostContent(ctx, \"/form\", \"a=1&b=2\"), `1`)\n\n\t\t// Map\n\t\tt.Assert(client.GetContent(ctx, \"/map\", \"id=1&name=john\"), `john`)\n\t\tt.Assert(client.PostContent(ctx, \"/map\", \"id=1&name=john\"), `john`)\n\n\t\t// Raw\n\t\tt.Assert(client.PutContent(ctx, \"/raw\", \"id=1&name=john\"), `id=1&name=john`)\n\n\t\t// Json\n\t\tt.Assert(client.PostContent(ctx, \"/json\", `{\"id\":1, \"name\":\"john\"}`), `john`)\n\n\t\t// Struct\n\t\tt.Assert(client.GetContent(ctx, \"/struct\", `id=1&name=john&password1=123&password2=456`), `1john123456`)\n\t\tt.Assert(client.PostContent(ctx, \"/struct\", `id=1&name=john&password1=123&password2=456`), `1john123456`)\n\t\tt.Assert(client.PostContent(ctx, \"/struct-with-nil\", ``), ``)\n\t\tt.Assert(client.PostContent(ctx, \"/struct-with-base\", `id=1&name=john&password1=123&password2=456`), \"1john1234561john\")\n\t})\n}\n\nfunc Test_Params_Header(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/header\", func(r *ghttp.Request) {\n\t\tr.Response.Write(map[string]any{\n\t\t\t\"without-def\":   r.GetHeader(\"no-header\"),\n\t\t\t\"with-def\":      r.GetHeader(\"no-header\", \"my-default\"),\n\t\t\t\"x-custom-with\": r.GetHeader(\"x-custom\", \"my-default\"),\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tclient.SetHeader(\"x-custom\", \"custom-value\")\n\n\t\tresp := client.GetContent(ctx, \"/header\")\n\t\tt.Assert(gjson.New(resp).Map(), g.Map{\n\t\t\t\"without-def\":   \"\",\n\t\t\t\"with-def\":      \"my-default\",\n\t\t\t\"x-custom-with\": \"custom-value\",\n\t\t})\n\t})\n}\n\nfunc Test_Params_SupportChars(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/form-value\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetForm(\"test-value\"))\n\t})\n\ts.BindHandler(\"/form-array\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetForm(\"test-array\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.PostContent(ctx, \"/form-value\", \"test-value=100\"), \"100\")\n\t\tt.Assert(c.PostContent(ctx, \"/form-array\", \"test-array[]=1&test-array[]=2\"), `[\"1\",\"2\"]`)\n\t})\n}\n\nfunc Test_Params_Priority(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/query\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetQuery(\"a\"))\n\t})\n\ts.BindHandler(\"/form\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetForm(\"a\"))\n\t})\n\ts.BindHandler(\"/request\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"a\"))\n\t})\n\ts.BindHandler(\"/request-map\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetMap(g.Map{\n\t\t\t\"a\": 1,\n\t\t\t\"b\": 2,\n\t\t}))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/query?a=1\", \"a=100\"), \"100\")\n\t\tt.Assert(client.PostContent(ctx, \"/form?a=1\", \"a=100\"), \"100\")\n\t\tt.Assert(client.PutContent(ctx, \"/form?a=1\", \"a=100\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/request?a=1\", \"a=100\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/request-map?a=1&b=2&c=3\", \"a=100&b=200&c=300\"), `{\"a\":\"100\",\"b\":\"200\"}`)\n\t})\n}\n\nfunc Test_Params_GetRequestMap(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/map\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRequestMap())\n\t})\n\ts.BindHandler(\"/withKVMap\", func(r *ghttp.Request) {\n\t\tm := r.GetRequestMap(map[string]any{\"id\": 2})\n\t\tr.Response.Write(m[\"id\"])\n\t})\n\ts.BindHandler(\"/paramsMapWithKVMap\", func(r *ghttp.Request) {\n\t\tr.SetParam(\"name\", \"john\")\n\t\tm := r.GetRequestMap(map[string]any{\"id\": 2})\n\t\tr.Response.Write(m[\"id\"])\n\t})\n\ts.BindHandler(\"/{name}.map\", func(r *ghttp.Request) {\n\t\tm := r.GetRequestMap(map[string]any{\"id\": 2})\n\t\tr.Response.Write(m[\"id\"])\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(\n\t\t\tclient.PostContent(ctx,\n\t\t\t\t\"/map\",\n\t\t\t\t\"time_end2020-04-18 16:11:58&returnmsg=Success&attach=\",\n\t\t\t),\n\t\t\t`{\"attach\":\"\",\"returnmsg\":\"Success\"}`,\n\t\t)\n\n\t\tt.Assert(client.PostContent(ctx, \"/john.map\", \"name=john\"), 2)\n\n\t\tt.Assert(client.PostContent(ctx, \"/withKVMap\", \"name=john\"), 2)\n\n\t\tt.Assert(client.PostContent(ctx, \"/paramsMapWithKVMap\"), 2)\n\n\t\tclient.SetContentType(\"application/json\")\n\t\tt.Assert(client.GetContent(ctx, \"/withKVMap\", \"name=john\"), 2)\n\t})\n}\n\nfunc Test_Params_Modify(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/param/modify\", func(r *ghttp.Request) {\n\t\tparam := r.GetMap()\n\t\tparam[\"id\"] = 2\n\t\tparamBytes, err := gjson.Encode(param)\n\t\tif err != nil {\n\t\t\tr.Response.Write(err)\n\t\t\treturn\n\t\t}\n\t\tr.Request.Body = io.NopCloser(bytes.NewReader(paramBytes))\n\t\tr.ReloadParam()\n\t\tr.Response.Write(r.GetMap())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(\n\t\t\tclient.PostContent(ctx,\n\t\t\t\t\"/param/modify\",\n\t\t\t\t`{\"id\":1}`,\n\t\t\t),\n\t\t\t`{\"id\":2}`,\n\t\t)\n\t})\n}\n\nfunc Test_Params_Parse_DefaultValueTag(t *testing.T) {\n\ttype T struct {\n\t\tName  string  `d:\"john\"`\n\t\tScore float32 `d:\"60\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar t *T\n\t\tif err := r.Parse(&t); err != nil {\n\t\t\tr.Response.WriteExit(err)\n\t\t}\n\t\tr.Response.WriteExit(t)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.PostContent(ctx, \"/parse\"), `{\"Name\":\"john\",\"Score\":60}`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"name\":\"smith\"}`), `{\"Name\":\"smith\",\"Score\":60}`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", `{\"name\":\"smith\", \"score\":100}`), `{\"Name\":\"smith\",\"Score\":100}`)\n\t})\n}\n\nfunc Test_Params_Parse_Validation(t *testing.T) {\n\ttype RegisterReq struct {\n\t\tName  string `p:\"username\"  v:\"required|length:6,30#请输入账号|账号长度为{min}到{max}位\"`\n\t\tPass  string `p:\"password1\" v:\"required|length:6,30#请输入密码|密码长度不够\"`\n\t\tPass2 string `p:\"password2\" v:\"required|length:6,30|same:password1#请确认密码|密码长度不够|两次密码不一致\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar req *RegisterReq\n\t\tif err := r.Parse(&req); err != nil {\n\t\t\tr.Response.Write(err)\n\t\t} else {\n\t\t\tr.Response.Write(\"ok\")\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/parse\"), `请输入账号`)\n\t\tt.Assert(client.GetContent(ctx, \"/parse?name=john11&password1=123456&password2=123\"), `密码长度不够`)\n\t\tt.Assert(client.GetContent(ctx, \"/parse?name=john&password1=123456&password2=123456\"), `账号长度为6到30位`)\n\t\tt.Assert(client.GetContent(ctx, \"/parse?name=john11&password1=123456&password2=123456\"), `ok`)\n\t})\n}\n\nfunc Test_Params_Parse_EmbeddedWithAliasName1(t *testing.T) {\n\t// 获取内容列表\n\ttype ContentGetListInput struct {\n\t\tType       string\n\t\tCategoryId uint\n\t\tPage       int\n\t\tSize       int\n\t\tSort       int\n\t\tUserId     uint\n\t}\n\t// 获取内容列表\n\ttype ContentGetListReq struct {\n\t\tContentGetListInput\n\t\tCategoryId uint `p:\"cate\"`\n\t\tPage       int  `d:\"1\"  v:\"min:0#分页号码错误\"`\n\t\tSize       int  `d:\"10\" v:\"max:50#分页数量最大50条\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar req *ContentGetListReq\n\t\tif err := r.Parse(&req); err != nil {\n\t\t\tr.Response.Write(err)\n\t\t} else {\n\t\t\tr.Response.Write(req.ContentGetListInput)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/parse?cate=1&page=2&size=10\"), `{\"Type\":\"\",\"CategoryId\":0,\"Page\":2,\"Size\":10,\"Sort\":0,\"UserId\":0}`)\n\t})\n}\n\nfunc Test_Params_Parse_EmbeddedWithAliasName2(t *testing.T) {\n\t// 获取内容列表\n\ttype ContentGetListInput struct {\n\t\tType       string\n\t\tCategoryId uint `p:\"cate\"`\n\t\tPage       int\n\t\tSize       int\n\t\tSort       int\n\t\tUserId     uint\n\t}\n\t// 获取内容列表\n\ttype ContentGetListReq struct {\n\t\tContentGetListInput\n\t\tCategoryId uint `p:\"cate\"`\n\t\tPage       int  `d:\"1\"  v:\"min:0#分页号码错误\"`\n\t\tSize       int  `d:\"10\" v:\"max:50#分页数量最大50条\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tvar req *ContentGetListReq\n\t\tif err := r.Parse(&req); err != nil {\n\t\t\tr.Response.Write(err)\n\t\t} else {\n\t\t\tr.Response.Write(req.ContentGetListInput)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/parse?cate=1&page=2&size=10\"), `{\"Type\":\"\",\"CategoryId\":1,\"Page\":2,\"Size\":10,\"Sort\":0,\"UserId\":0}`)\n\t})\n}\n\nfunc Test_Params_GetParam(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetParam(\"key\", \"val\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.PostContent(ctx, \"/\"), \"val\")\n\t})\n}\n\nfunc Test_Params_SetQuery(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/SetQuery\", func(r *ghttp.Request) {\n\t\tr.SetQuery(\"a\", 100)\n\t\tr.Response.Write(r.GetQuery(\"a\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/SetQuery\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/SetQuery?a=1\"), \"100\")\n\t})\n}\n\nfunc Test_Params_GetQuery(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetQuery\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetQuery(\"a\", 200))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetQuery\"), 200)\n\t\tt.Assert(client.SetContentType(\"application/json\").GetContent(ctx, \"/GetQuery\", \"a=100\"), 100)\n\t})\n}\n\nfunc Test_Params_GetQueryMap(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetQueryMap\", func(r *ghttp.Request) {\n\t\tif m := r.GetQueryMap(); len(m) > 0 {\n\t\t\tr.Response.Write(m[\"name\"])\n\t\t}\n\t})\n\ts.BindHandler(\"/GetQueryMapWithKVMap\", func(r *ghttp.Request) {\n\t\tif m := r.GetQueryMap(map[string]any{\"id\": 1}); len(m) > 0 {\n\t\t\tr.Response.Write(m[\"id\"])\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tclient.SetContentType(\"application/json\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMap\", \"id=1&name=john\"), `john`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapWithKVMap\"), 1)\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapWithKVMap\", \"name=john\"), 1)\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapWithKVMap\", \"id=2&name=john\"), 2)\n\t\tclient.SetContentType(\"application/json\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapWithKVMap\", \"name=john\"), 1)\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapWithKVMap\", \"id=2&name=john\"), 2)\n\t})\n}\n\nfunc Test_Params_GetQueryMapStrStr(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetQueryMapStrStr\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetQueryMapStrStr())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapStrStr\"), \"\")\n\t})\n}\n\nfunc Test_Params_GetQueryMapStrVar(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetQueryMapStrVar\", func(r *ghttp.Request) {\n\t\tm := r.GetQueryMapStrVar()\n\t\tr.Response.Write(m[\"id\"])\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapStrVar\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetQueryMapStrVar\", \"id=1\"), 1)\n\t})\n}\n\nfunc Test_Params_GetRequest(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetRequest\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRequest(\"id\"))\n\t})\n\ts.BindHandler(\"/GetRequestWithDef\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRequest(\"id\", 2))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetRequestWithDef\"), 2)\n\n\t\tclient.SetContentType(\"application/json\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetRequest\", \"id=1\"), 1)\n\t})\n}\n\nfunc Test_Params_GetRequestMapStrStr(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetRequestMapStrStr\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRequestMapStrStr())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetRequestMapStrStr\"), \"\")\n\t})\n}\n\nfunc Test_Params_GetRequestMapStrVar(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/GetRequestMapStrVar\", func(r *ghttp.Request) {\n\t\tm := r.GetRequestMapStrVar()\n\t\tr.Response.Write(m[\"id\"])\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/GetRequestMapStrVar\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetRequestMapStrVar\", \"id=1\"), 1)\n\t})\n}\n\ntype GetMetaTagReq struct {\n\tg.Meta `path:\"/test\" method:\"post\" summary:\"meta_tag\" tags:\"meta\"`\n\tName   string\n}\ntype GetMetaTagRes struct{}\n\ntype GetMetaTagSt struct{}\n\nfunc (r GetMetaTagSt) PostTest(ctx context.Context, req *GetMetaTagReq) (*GetMetaTagRes, error) {\n\treturn &GetMetaTagRes{}, nil\n}\n\nfunc TestRequest_GetServeHandler_GetMetaTag(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(func(r *ghttp.Request) {\n\t\tr.Response.Writef(\n\t\t\t\"summary:%s,method:%s\",\n\t\t\tr.GetServeHandler().GetMetaTag(\"summary\"),\n\t\t\tr.GetServeHandler().GetMetaTag(\"method\"),\n\t\t)\n\t})\n\ts.Group(\"/\", func(grp *ghttp.RouterGroup) {\n\t\tgrp.Bind(GetMetaTagSt{})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.PostContent(ctx, \"/test\", \"name=john\"), \"summary:meta_tag,method:post\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_request_xml_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Params_Xml_Request(t *testing.T) {\n\ttype User struct {\n\t\tId    int\n\t\tName  string\n\t\tTime  *time.Time\n\t\tPass1 string `p:\"password1\"`\n\t\tPass2 string `p:\"password2\" v:\"password2@required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.WriteExit(r.Get(\"id\"), r.Get(\"name\"))\n\t})\n\ts.BindHandler(\"/map\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tr.Response.WriteExit(m[\"id\"], m[\"name\"], m[\"password1\"], m[\"password2\"])\n\t\t}\n\t})\n\ts.BindHandler(\"/parse\", func(r *ghttp.Request) {\n\t\tif m := r.GetMap(); len(m) > 0 {\n\t\t\tvar user *User\n\t\t\tif err := r.Parse(&user); err != nil {\n\t\t\t\tr.Response.WriteExit(err)\n\t\t\t}\n\t\t\tr.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tcontent1 := `<doc><id>1</id><name>john</name><password1>123Abc!@#</password1><password2>123Abc!@#</password2></doc>`\n\t\tcontent2 := `<doc><id>1</id><name>john</name><password1>123Abc!@#</password1><password2>123</password2></doc>`\n\t\tt.Assert(client.GetContent(ctx, \"/get\", content1), ``)\n\t\tt.Assert(client.PostContent(ctx, \"/get\", content1), `1john`)\n\t\tt.Assert(client.GetContent(ctx, \"/map\", content1), ``)\n\t\tt.Assert(client.PostContent(ctx, \"/map\", content1), `1john123Abc!@#123Abc!@#`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", content1), `1john123Abc!@#123Abc!@#`)\n\t\tt.Assert(client.PostContent(ctx, \"/parse\", content2), `密码强度不足`)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_response_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gxml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Response_ServeFile(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/ServeFile\", func(r *ghttp.Request) {\n\t\tfilePath := r.GetQuery(\"filePath\")\n\t\tr.Response.ServeFile(filePath.String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tt.Assert(client.GetContent(ctx, \"/ServeFile\", \"filePath=file1.txt\"), \"Not Found\")\n\n\t\tt.Assert(\n\t\t\tclient.GetContent(ctx, \"/ServeFile\", \"filePath=\"+srcPath),\n\t\t\t\"file1.txt: This file is for uploading unit test case.\")\n\n\t\tt.Assert(\n\t\t\tstrings.Contains(\n\t\t\t\tclient.GetContent(ctx, \"/ServeFile\", \"filePath=files/server.key\"),\n\t\t\t\t\"BEGIN RSA PRIVATE KEY\"),\n\t\t\ttrue)\n\t})\n}\n\nfunc Test_Response_ServeFileDownload(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/ServeFileDownload\", func(r *ghttp.Request) {\n\t\tfilePath := r.GetQuery(\"filePath\")\n\t\tr.Response.ServeFileDownload(filePath.String())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tsrcPath := gtest.DataPath(\"upload\", \"file1.txt\")\n\t\tt.Assert(client.GetContent(ctx, \"/ServeFileDownload\", \"filePath=file1.txt\"), \"Not Found\")\n\n\t\tt.Assert(\n\t\t\tclient.GetContent(ctx, \"/ServeFileDownload\", \"filePath=\"+srcPath),\n\t\t\t\"file1.txt: This file is for uploading unit test case.\")\n\n\t\tt.Assert(\n\t\t\tstrings.Contains(\n\t\t\t\tclient.GetContent(ctx, \"/ServeFileDownload\", \"filePath=files/server.key\"),\n\t\t\t\t\"BEGIN RSA PRIVATE KEY\"),\n\t\t\ttrue)\n\n\t\tresp, err := client.Get(ctx, \"/ServeFileDownload\", \"filePath=\"+srcPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.ReadAllString(), \"file1.txt: This file is for uploading unit test case.\")\n\t\tt.Assert(resp.Header.Get(\"Content-Disposition\"), \"attachment;filename=file1.txt\")\n\n\t\tsrcPath = gtest.DataPath(\"upload\", \"中文.txt\")\n\t\tresp, err = client.Get(ctx, \"/ServeFileDownload\", \"filePath=\"+srcPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.ReadAllString(), \"中文.txt: This file is for uploading unit test case.\")\n\t\tt.Assert(resp.Header.Get(\"Content-Disposition\"), \"attachment;filename*=UTF-8''\"+url.QueryEscape(\"中文.txt\"))\n\t})\n}\n\nfunc Test_Response_Redirect(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"RedirectResult\")\n\t})\n\ts.BindHandler(\"/RedirectTo\", func(r *ghttp.Request) {\n\t\tr.Response.RedirectTo(\"/\")\n\t})\n\ts.BindHandler(\"/RedirectTo301\", func(r *ghttp.Request) {\n\t\tr.Response.RedirectTo(\"/\", http.StatusMovedPermanently)\n\t})\n\ts.BindHandler(\"/RedirectBack\", func(r *ghttp.Request) {\n\t\tr.Response.RedirectBack()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/RedirectTo\"), \"RedirectResult\")\n\t\tt.Assert(client.GetContent(ctx, \"/RedirectTo301\"), \"RedirectResult\")\n\t\tt.Assert(client.SetHeader(\"Referer\", \"/\").GetContent(ctx, \"/RedirectBack\"), \"RedirectResult\")\n\t})\n}\n\nfunc Test_Response_Buffer(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/Buffer\", func(r *ghttp.Request) {\n\t\tname := r.GetQuery(\"name\").Bytes()\n\t\tr.Response.SetBuffer(name)\n\t\tbuffer := r.Response.Buffer()\n\t\tr.Response.ClearBuffer()\n\t\tr.Response.Write(buffer)\n\t})\n\ts.BindHandler(\"/BufferString\", func(r *ghttp.Request) {\n\t\tname := r.GetQuery(\"name\").Bytes()\n\t\tr.Response.SetBuffer(name)\n\t\tbufferString := r.Response.BufferString()\n\t\tr.Response.ClearBuffer()\n\t\tr.Response.Write(bufferString)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/Buffer\", \"name=john\"), []byte(\"john\"))\n\t\tt.Assert(client.GetContent(ctx, \"/BufferString\", \"name=john\"), \"john\")\n\t})\n}\n\nfunc Test_Response_WriteTpl(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New(gtest.DataPath(\"template\", \"basic\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"noexist.html\", g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t})\n\t\t\tt.AssertNE(err, nil)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.AssertNE(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n}\n\nfunc Test_Response_WriteTplDefault(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetDefaultFile(gtest.DataPath(\"template\", \"basic\", \"index.html\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTplDefault(g.Map{\"name\": \"john\"})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetDefaultFile(gtest.DataPath(\"template\", \"basic\", \"noexit.html\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTplDefault(g.Map{\"name\": \"john\"})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.AssertNE(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n}\n\nfunc Test_Response_ParseTplDefault(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetDefaultFile(gtest.DataPath(\"template\", \"basic\", \"index.html\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\tres, err := r.Response.ParseTplDefault(g.Map{\"name\": \"john\"})\n\t\t\tt.AssertNil(err)\n\t\t\tr.Response.Write(res)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n}\n\nfunc Test_Response_Write(t *testing.T) {\n\ttype User struct {\n\t\tName string `json:\"name\"`\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write()\n\t})\n\ts.BindHandler(\"/WriteOverExit\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"WriteOverExit\")\n\t\tr.Response.WriteOverExit(\"\")\n\t})\n\ts.BindHandler(\"/WritefExit\", func(r *ghttp.Request) {\n\t\tr.Response.WritefExit(\"%s\", \"WritefExit\")\n\t})\n\ts.BindHandler(\"/Writeln\", func(r *ghttp.Request) {\n\t\tname := r.GetQuery(\"name\")\n\t\tr.Response.Writeln(name)\n\t})\n\ts.BindHandler(\"/WritelnNil\", func(r *ghttp.Request) {\n\t\tr.Response.Writeln()\n\t})\n\ts.BindHandler(\"/Writefln\", func(r *ghttp.Request) {\n\t\tname := r.GetQuery(\"name\")\n\t\tr.Response.Writefln(\"%s\", name)\n\t})\n\ts.BindHandler(\"/WriteJson\", func(r *ghttp.Request) {\n\t\tm := map[string]string{\"name\": \"john\"}\n\t\tif bytes, err := json.Marshal(m); err == nil {\n\t\t\tr.Response.WriteJson(bytes)\n\t\t}\n\t})\n\ts.BindHandler(\"/WriteJsonP\", func(r *ghttp.Request) {\n\t\tm := map[string]string{\"name\": \"john\"}\n\t\tif bytes, err := json.Marshal(m); err == nil {\n\t\t\tr.Response.WriteJsonP(bytes)\n\t\t}\n\t})\n\ts.BindHandler(\"/WriteJsonPWithStruct\", func(r *ghttp.Request) {\n\t\tuser := User{\"john\"}\n\t\tr.Response.WriteJsonP(user)\n\t})\n\ts.BindHandler(\"/WriteXml\", func(r *ghttp.Request) {\n\t\tm := map[string]any{\"name\": \"john\"}\n\t\tif bytes, err := gxml.Encode(m); err == nil {\n\t\t\tr.Response.WriteXml(bytes)\n\t\t}\n\t})\n\ts.BindHandler(\"/WriteXmlWithStruct\", func(r *ghttp.Request) {\n\t\tuser := User{\"john\"}\n\t\tr.Response.WriteXml(user)\n\t})\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteOverExit\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/WritefExit\"), \"WritefExit\")\n\t\tt.Assert(client.GetContent(ctx, \"/Writeln\"), \"\\n\")\n\t\tt.Assert(client.GetContent(ctx, \"/WritelnNil\"), \"\\n\")\n\t\tt.Assert(client.GetContent(ctx, \"/Writeln\", \"name=john\"), \"john\\n\")\n\t\tt.Assert(client.GetContent(ctx, \"/Writefln\", \"name=john\"), \"john\\n\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteJson\"), \"{\\\"name\\\":\\\"john\\\"}\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteJsonP\"), \"{\\\"name\\\":\\\"john\\\"}\")\n\t\tresp, _ := client.DoRequest(ctx, http.MethodGet, \"/WriteJsonP\", \"{\\\"name\\\":\\\"john\\\"}\", nil)\n\t\tt.Assert(resp.Header.Get(\"Content-Type\"), \"application/javascript\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteJsonPWithStruct\"), \"{\\\"name\\\":\\\"john\\\"}\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteJsonPWithStruct\", \"callback=callback\"),\n\t\t\t\"callback({\\\"name\\\":\\\"john\\\"})\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteXml\"), \"<name>john</name>\")\n\t\tt.Assert(client.GetContent(ctx, \"/WriteXmlWithStruct\"), \"<name>john</name>\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Basic1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/:name\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"/:name\")\n\t})\n\ts.BindHandler(\"/:name/update\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"name\"))\n\t})\n\ts.BindHandler(\"/:name/:action\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"action\"))\n\t})\n\ts.BindHandler(\"/:name/*any\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"any\"))\n\t})\n\ts.BindHandler(\"/user/list/{field}.html\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/update\"), \"john\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/edit\"), \"edit\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list/100.html\"), \"100\")\n\t})\n}\n\nfunc Test_Router_Basic2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/{hash}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"hash\"))\n\t})\n\ts.BindHandler(\"/{hash}.{type}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"type\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/data\"), \"data\")\n\t\tt.Assert(client.GetContent(ctx, \"/data.json\"), \"json\")\n\t})\n}\n\nfunc Test_Router_Value(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRouterMap()[\"hash\"])\n\t})\n\ts.BindHandler(\"/GetRouter\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRouter(\"name\", \"john\").String())\n\t})\n\ts.BindHandler(\"/{hash}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRouter(\"hash\").String())\n\t})\n\ts.BindHandler(\"/{hash}.{type}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRouter(\"type\").String())\n\t})\n\ts.BindHandler(\"/{hash}.{type}.map\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetRouterMap()[\"type\"])\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/GetRouter\"), \"john\")\n\t\tt.Assert(client.GetContent(ctx, \"/data\"), \"data\")\n\t\tt.Assert(client.GetContent(ctx, \"/data.json\"), \"json\")\n\t\tt.Assert(client.GetContent(ctx, \"/data.json.map\"), \"json\")\n\t})\n}\n\n// HTTP method register.\nfunc Test_Router_Method(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"GET:/get\", func(r *ghttp.Request) {\n\n\t})\n\ts.BindHandler(\"POST:/post\", func(r *ghttp.Request) {\n\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Post(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 404)\n\n\t\tresp3, err := client.Get(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 404)\n\n\t\tresp4, err := client.Post(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 200)\n\t})\n}\n\n// Extra char '/' of the router.\nfunc Test_Router_ExtraChar(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api\", func(group *ghttp.RouterGroup) {\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/test\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/test/\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/test//\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"//api/test//\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"//api//test//\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"///api///test///\"), \"test\")\n\t})\n}\n\n// Custom status handler.\nfunc Test_Router_Status(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/200\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(200)\n\t})\n\ts.BindHandler(\"/300\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(300)\n\t})\n\ts.BindHandler(\"/400\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(400)\n\t})\n\ts.BindHandler(\"/500\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(500)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/200\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Get(ctx, \"/300\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 300)\n\n\t\tresp3, err := client.Get(ctx, \"/400\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 400)\n\n\t\tresp4, err := client.Get(ctx, \"/500\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 500)\n\n\t\tresp5, err := client.Get(ctx, \"/404\")\n\t\tt.AssertNil(err)\n\t\tdefer resp5.Close()\n\t\tt.Assert(resp5.StatusCode, 404)\n\t})\n}\n\nfunc Test_Router_CustomStatusHandler(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\ts.BindStatusHandler(404, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"404 page\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t\tresp, err := client.Get(ctx, \"/ThisDoesNotExist\")\n\t\tt.AssertNil(err)\n\t\tdefer resp.Close()\n\t\tt.Assert(resp.StatusCode, 404)\n\t\tt.Assert(resp.ReadAllString(), \"404 page\")\n\t})\n}\n\n// 404 not found router.\nfunc Test_Router_404(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t\tresp, err := client.Get(ctx, \"/ThisDoesNotExist\")\n\t\tt.AssertNil(err)\n\t\tdefer resp.Close()\n\t\tt.Assert(resp.StatusCode, 404)\n\t})\n}\n\nfunc Test_Router_Priority(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/admin\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"admin\")\n\t})\n\ts.BindHandler(\"/admin-{page}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"admin-{page}\")\n\t})\n\ts.BindHandler(\"/admin-goods\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"admin-goods\")\n\t})\n\ts.BindHandler(\"/admin-goods-{page}\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"admin-goods-{page}\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/admin\"), \"admin\")\n\t\tt.Assert(client.GetContent(ctx, \"/admin-1\"), \"admin-{page}\")\n\t\tt.Assert(client.GetContent(ctx, \"/admin-goods\"), \"admin-goods\")\n\t\tt.Assert(client.GetContent(ctx, \"/admin-goods-2\"), \"admin-goods-{page}\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_domain_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_DomainBasic(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindHandler(\"/:name\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"/:name\")\n\t})\n\td.BindHandler(\"/:name/update\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"name\"))\n\t})\n\td.BindHandler(\"/:name/:action\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"action\"))\n\t})\n\td.BindHandler(\"/:name/*any\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"any\"))\n\t})\n\td.BindHandler(\"/user/list/{field}.html\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/update\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/edit\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list/100.html\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/update\"), \"john\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/edit\"), \"edit\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list/100.html\"), \"100\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/update\"), \"john\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/edit\"), \"edit\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list/100.html\"), \"100\")\n\t})\n}\n\nfunc Test_Router_DomainMethod(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindHandler(\"GET:/get\", func(r *ghttp.Request) {\n\n\t})\n\td.BindHandler(\"POST:/post\", func(r *ghttp.Request) {\n\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 404)\n\n\t\tresp2, err := client.Post(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 404)\n\n\t\tresp3, err := client.Get(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 404)\n\n\t\tresp4, err := client.Post(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 404)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Post(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 404)\n\n\t\tresp3, err := client.Get(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 404)\n\n\t\tresp4, err := client.Post(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 200)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Post(ctx, \"/get\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 404)\n\n\t\tresp3, err := client.Get(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 404)\n\n\t\tresp4, err := client.Post(ctx, \"/post\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 200)\n\t})\n}\n\nfunc Test_Router_DomainStatus(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindHandler(\"/200\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(200)\n\t})\n\td.BindHandler(\"/300\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(300)\n\t})\n\td.BindHandler(\"/400\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(400)\n\t})\n\td.BindHandler(\"/500\", func(r *ghttp.Request) {\n\t\tr.Response.WriteStatus(500)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/200\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 404)\n\n\t\tresp2, err := client.Get(ctx, \"/300\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 404)\n\n\t\tresp3, err := client.Get(ctx, \"/400\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 404)\n\n\t\tresp4, err := client.Get(ctx, \"/500\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 404)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/200\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Get(ctx, \"/300\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 300)\n\n\t\tresp3, err := client.Get(ctx, \"/400\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 400)\n\n\t\tresp4, err := client.Get(ctx, \"/500\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 500)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tresp1, err := client.Get(ctx, \"/200\")\n\t\tt.AssertNil(err)\n\t\tdefer resp1.Close()\n\t\tt.Assert(resp1.StatusCode, 200)\n\n\t\tresp2, err := client.Get(ctx, \"/300\")\n\t\tt.AssertNil(err)\n\t\tdefer resp2.Close()\n\t\tt.Assert(resp2.StatusCode, 300)\n\n\t\tresp3, err := client.Get(ctx, \"/400\")\n\t\tt.AssertNil(err)\n\t\tdefer resp3.Close()\n\t\tt.Assert(resp3.StatusCode, 400)\n\n\t\tresp4, err := client.Get(ctx, \"/500\")\n\t\tt.AssertNil(err)\n\t\tdefer resp4.Close()\n\t\tt.Assert(resp4.StatusCode, 500)\n\t})\n}\n\nfunc Test_Router_DomainCustomStatusHandler(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\td.BindStatusHandler(404, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"404 page\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/ThisDoesNotExist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t\tt.Assert(client.GetContent(ctx, \"/ThisDoesNotExist\"), \"404 page\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t\tt.Assert(client.GetContent(ctx, \"/ThisDoesNotExist\"), \"404 page\")\n\t})\n}\n\nfunc Test_Router_Domain404(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"hello\")\n\t})\n}\n\nfunc Test_Router_DomainGroup(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Group(\"/app\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.GET(\"/{table}/list/{page}.html\", func(r *ghttp.Request) {\n\t\t\t\tintlog.Print(r.Context(), \"/{table}/list/{page}.html\")\n\t\t\t\tr.Response.Write(r.Get(\"table\"), \"&\", r.Get(\"page\"))\n\t\t\t})\n\t\t\tgroup.GET(\"/order/info/{order_id}\", func(r *ghttp.Request) {\n\t\t\t\tintlog.Print(r.Context(), \"/order/info/{order_id}\")\n\t\t\t\tr.Response.Write(r.Get(\"order_id\"))\n\t\t\t})\n\t\t\tgroup.DELETE(\"/comment/{id}\", func(r *ghttp.Request) {\n\t\t\t\tintlog.Print(r.Context(), \"/comment/{id}\")\n\t\t\t\tr.Response.Write(r.Get(\"id\"))\n\t\t\t})\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient1 := g.Client()\n\t\tclient1.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tclient2 := g.Client()\n\t\tclient2.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client1.GetContent(ctx, \"/app/t/list/2.html\"), \"t&2\")\n\t\tt.Assert(client2.GetContent(ctx, \"/app/t/list/2.html\"), \"Not Found\")\n\n\t\tt.Assert(client1.GetContent(ctx, \"/app/order/info/2\"), \"2\")\n\t\tt.Assert(client2.GetContent(ctx, \"/app/order/info/2\"), \"Not Found\")\n\n\t\tt.Assert(client1.GetContent(ctx, \"/app/comment/20\"), \"Not Found\")\n\t\tt.Assert(client2.GetContent(ctx, \"/app/comment/20\"), \"Not Found\")\n\n\t\tt.Assert(client1.DeleteContent(ctx, \"/app/comment/20\"), \"20\")\n\t\tt.Assert(client2.DeleteContent(ctx, \"/app/comment/20\"), \"Not Found\")\n\t})\n}\n\n// issue#4100\nfunc TestIssue4100(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"\")\n\td.BindHandler(\"/:name\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"/:name\")\n\t})\n\td.BindHandler(\"/:name/update\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"name\"))\n\t})\n\td.BindHandler(\"/:name/:action\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"action\"))\n\t})\n\td.BindHandler(\"/:name/*any\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"any\"))\n\t})\n\td.BindHandler(\"/user/list/{field}.html\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"field\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/update\"), \"john\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/edit\"), \"edit\")\n\t\tt.Assert(client.GetContent(ctx, \"/user/list/100.html\"), \"100\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_domain_object_rest_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype DomainObjectRest struct{}\n\nfunc (o *DomainObjectRest) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *DomainObjectRest) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *DomainObjectRest) Get(r *ghttp.Request) {\n\tr.Response.Write(\"Object Get\")\n}\n\nfunc (o *DomainObjectRest) Put(r *ghttp.Request) {\n\tr.Response.Write(\"Object Put\")\n}\n\nfunc (o *DomainObjectRest) Post(r *ghttp.Request) {\n\tr.Response.Write(\"Object Post\")\n}\n\nfunc (o *DomainObjectRest) Delete(r *ghttp.Request) {\n\tr.Response.Write(\"Object Delete\")\n}\n\nfunc (o *DomainObjectRest) Patch(r *ghttp.Request) {\n\tr.Response.Write(\"Object Patch\")\n}\n\nfunc (o *DomainObjectRest) Options(r *ghttp.Request) {\n\tr.Response.Write(\"Object Options\")\n}\n\nfunc (o *DomainObjectRest) Head(r *ghttp.Request) {\n\tr.Response.Header().Set(\"head-ok\", \"1\")\n}\n\nfunc Test_Router_DomainObjectRest(t *testing.T) {\n\ts := g.Server(guid.S())\n\td := s.Domain(\"localhost, local\")\n\td.BindObjectRest(\"/\", new(DomainObjectRest))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.PostContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.PatchContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/\"), \"Not Found\")\n\t\tresp1, err := client.Head(ctx, \"/\")\n\t\tif err == nil {\n\t\t\tdefer resp1.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp1.Header.Get(\"head-ok\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/\"), \"1Object Options2\")\n\t\tresp1, err := client.Head(ctx, \"/\")\n\t\tif err == nil {\n\t\t\tdefer resp1.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp1.Header.Get(\"head-ok\"), \"1\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/\"), \"1Object Options2\")\n\t\tresp1, err := client.Head(ctx, \"/\")\n\t\tif err == nil {\n\t\t\tdefer resp1.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp1.Header.Get(\"head-ok\"), \"1\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_domain_object_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype DomainObject struct{}\n\nfunc (o *DomainObject) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *DomainObject) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *DomainObject) Index(r *ghttp.Request) {\n\tr.Response.Write(\"Object Index\")\n}\n\nfunc (o *DomainObject) Show(r *ghttp.Request) {\n\tr.Response.Write(\"Object Show\")\n}\n\nfunc (o *DomainObject) Info(r *ghttp.Request) {\n\tr.Response.Write(\"Object Info\")\n}\n\nfunc Test_Router_DomainObject1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Domain(\"localhost, local\").BindObject(\"/\", new(DomainObject))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_DomainObject2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Domain(\"localhost, local\").BindObject(\"/object\", new(DomainObject), \"Show, Info\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_DomainObjectMethod(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Domain(\"localhost, local\").BindObjectMethod(\"/object-info\", new(DomainObject), \"Info\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object-info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://localhost:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object-info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://local:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object-info\"), \"1Object Info2\")\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_exit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Exit(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHookHandlerByMap(\"/*\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe:  func(r *ghttp.Request) { r.Response.Write(\"1\") },\n\t\tghttp.HookAfterServe:   func(r *ghttp.Request) { r.Response.Write(\"2\") },\n\t\tghttp.HookBeforeOutput: func(r *ghttp.Request) { r.Response.Write(\"3\") },\n\t\tghttp.HookAfterOutput:  func(r *ghttp.Request) { r.Response.Write(\"4\") },\n\t})\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test-start\")\n\t\tr.Exit()\n\t\tr.Response.Write(\"test-end\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"123\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"1test-start23\")\n\t})\n}\n\nfunc Test_Router_ExitHook(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/priority/show\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"show\")\n\t})\n\n\ts.BindHookHandlerByMap(\"/priority/:name\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/*any\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/show\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"3\")\n\t\t\tr.ExitHook()\n\t\t},\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/priority/show\"), \"3show\")\n\t})\n}\n\nfunc Test_Router_ExitAll(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/priority/show\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"show\")\n\t})\n\n\ts.BindHookHandlerByMap(\"/priority/:name\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/*any\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/show\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"3\")\n\t\t\tr.ExitAll()\n\t\t},\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/priority/show\"), \"3\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_group_group_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Group_Group(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api.v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t\tr.Middleware.Next()\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t\tgroup.GET(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"test\")\n\t\t})\n\t\tgroup.Group(\"/order\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.GET(\"/list\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"list\")\n\t\t\t})\n\t\t\tgroup.PUT(\"/update\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"update\")\n\t\t\t})\n\t\t})\n\t\tgroup.Group(\"/user\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.GET(\"/info\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"info\")\n\t\t\t})\n\t\t\tgroup.POST(\"/edit\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"edit\")\n\t\t\t})\n\t\t\tgroup.DELETE(\"/drop\", func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"drop\")\n\t\t\t})\n\t\t})\n\t\tgroup.Group(\"/hook\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Hook(\"/*\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"hook any\")\n\t\t\t})\n\t\t\tgroup.Hook(\"/:name\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\t\t\tr.Response.Write(\"hook name\")\n\t\t\t})\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/test\"), \"1test2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/hook\"), \"hook any\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/hook/name\"), \"hook namehook any\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/hook/name/any\"), \"hook any\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/order/list\"), \"1list2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/order/update\"), \"Not Found\")\n\t\tt.Assert(client.PutContent(ctx, \"/api.v2/order/update\"), \"1update2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/user/drop\"), \"Not Found\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api.v2/user/drop\"), \"1drop2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/user/edit\"), \"Not Found\")\n\t\tt.Assert(client.PostContent(ctx, \"/api.v2/user/edit\"), \"1edit2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api.v2/user/info\"), \"1info2\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_group_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Group_Hook1(t *testing.T) {\n\ts := g.Server(guid.S())\n\tgroup := s.Group(\"/api\")\n\tgroup.GET(\"/handler\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t})\n\tgroup.ALL(\"/handler\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"0\")\n\t}, ghttp.HookBeforeServe)\n\tgroup.ALL(\"/handler\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"2\")\n\t}, ghttp.HookAfterServe)\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/api/handler\"), \"012\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/handler\"), \"02\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/ThisDoesNotExist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_Group_Hook2(t *testing.T) {\n\ts := g.Server(guid.S())\n\tgroup := s.Group(\"/api\")\n\tgroup.GET(\"/handler\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"1\")\n\t})\n\tgroup.GET(\"/*\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"0\")\n\t}, ghttp.HookBeforeServe)\n\tgroup.GET(\"/*\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"2\")\n\t}, ghttp.HookAfterServe)\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/api/handler\"), \"012\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/handler\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/ThisDoesNotExist\"), \"02\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/ThisDoesNotExist\"), \"Not Found\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_group_rest_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype GroupObjRest struct{}\n\nfunc (o *GroupObjRest) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *GroupObjRest) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *GroupObjRest) Get(r *ghttp.Request) {\n\tr.Response.Write(\"Object Get\")\n}\n\nfunc (o *GroupObjRest) Put(r *ghttp.Request) {\n\tr.Response.Write(\"Object Put\")\n}\n\nfunc (o *GroupObjRest) Post(r *ghttp.Request) {\n\tr.Response.Write(\"Object Post\")\n}\n\nfunc (o *GroupObjRest) Delete(r *ghttp.Request) {\n\tr.Response.Write(\"Object Delete\")\n}\n\nfunc (o *GroupObjRest) Patch(r *ghttp.Request) {\n\tr.Response.Write(\"Object Patch\")\n}\n\nfunc (o *GroupObjRest) Options(r *ghttp.Request) {\n\tr.Response.Write(\"Object Options\")\n}\n\nfunc (o *GroupObjRest) Head(r *ghttp.Request) {\n\tr.Response.Header().Set(\"head-ok\", \"1\")\n}\n\nfunc Test_Router_GroupRest1(t *testing.T) {\n\ts := g.Server(guid.S())\n\tgroup := s.Group(\"/api\")\n\tobj := new(GroupObjRest)\n\tgroup.REST(\"/obj\", obj)\n\tgroup.REST(\"/{.struct}/{.method}\", obj)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/api/obj\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/obj\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/obj\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/api/obj\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/api/obj\"), \"1Object Options2\")\n\t\tresp2, err := client.Head(ctx, \"/api/obj\")\n\t\tif err == nil {\n\t\t\tdefer resp2.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp2.Header.Get(\"head-ok\"), \"1\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-obj-rest\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-obj-rest/get\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/api/group-obj-rest/put\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/group-obj-rest/post\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/group-obj-rest/delete\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/api/group-obj-rest/patch\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/api/group-obj-rest/options\"), \"1Object Options2\")\n\t\tresp4, err := client.Head(ctx, \"/api/group-obj-rest/head\")\n\t\tif err == nil {\n\t\t\tdefer resp4.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp4.Header.Get(\"head-ok\"), \"1\")\n\t})\n}\n\nfunc Test_Router_GroupRest2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api\", func(group *ghttp.RouterGroup) {\n\t\tobj := new(GroupObjRest)\n\t\tgroup.REST(\"/obj\", obj)\n\t\tgroup.REST(\"/{.struct}/{.method}\", obj)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/api/obj\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/obj\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/obj\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/api/obj\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/api/obj\"), \"1Object Options2\")\n\t\tresp2, err := client.Head(ctx, \"/api/obj\")\n\t\tif err == nil {\n\t\t\tdefer resp2.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp2.Header.Get(\"head-ok\"), \"1\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-obj-rest\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-obj-rest/get\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/api/group-obj-rest/put\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/api/group-obj-rest/post\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/group-obj-rest/delete\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/api/group-obj-rest/patch\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/api/group-obj-rest/options\"), \"1Object Options2\")\n\t\tresp4, err := client.Head(ctx, \"/api/group-obj-rest/head\")\n\t\tif err == nil {\n\t\t\tdefer resp4.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp4.Header.Get(\"head-ok\"), \"1\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_group_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// 执行对象\ntype GroupObject struct{}\n\nfunc (o *GroupObject) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *GroupObject) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *GroupObject) Index(r *ghttp.Request) {\n\tr.Response.Write(\"Object Index\")\n}\n\nfunc (o *GroupObject) Show(r *ghttp.Request) {\n\tr.Response.Write(\"Object Show\")\n}\n\nfunc (o *GroupObject) Delete(r *ghttp.Request) {\n\tr.Response.Write(\"Object Delete\")\n}\n\nfunc Handler(r *ghttp.Request) {\n\tr.Response.Write(\"Handler\")\n}\n\nfunc Test_Router_GroupBasic1(t *testing.T) {\n\ts := g.Server(guid.S())\n\tobj := new(GroupObject)\n\t// 分组路由方法注册\n\tgroup := s.Group(\"/api\")\n\tgroup.ALL(\"/handler\", Handler)\n\tgroup.ALL(\"/obj\", obj)\n\tgroup.GET(\"/obj/my-show\", obj, \"Show\")\n\tgroup.REST(\"/obj/rest\", obj)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/handler\"), \"Handler\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj/\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj/delete\"), \"1Object Delete2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj/my-show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/obj/show\"), \"1Object Show2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/obj/rest\"), \"1Object Delete2\")\n\n\t\tt.Assert(client.DeleteContent(ctx, \"/ThisDoesNotExist\"), \"Not Found\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/ThisDoesNotExist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_GroupBuildInVar(t *testing.T) {\n\ts := g.Server(guid.S())\n\tobj := new(GroupObject)\n\t// 分组路由方法注册\n\tgroup := s.Group(\"/api\")\n\tgroup.ALL(\"/{.struct}/{.method}\", obj)\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-object/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-object/delete\"), \"1Object Delete2\")\n\t\tt.Assert(client.GetContent(ctx, \"/api/group-object/show\"), \"1Object Show2\")\n\n\t\tt.Assert(client.DeleteContent(ctx, \"/ThisDoesNotExist\"), \"Not Found\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/api/ThisDoesNotExist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_Group_Methods(t *testing.T) {\n\ts := g.Server(guid.S())\n\tobj := new(GroupObject)\n\tgroup := s.Group(\"/\")\n\tgroup.ALL(\"/obj\", obj, \"Show, Delete\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/obj/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/obj/delete\"), \"1Object Delete2\")\n\t})\n}\n\nfunc Test_Router_Group_MultiServer(t *testing.T) {\n\ts1 := g.Server(guid.S())\n\ts2 := g.Server(guid.S())\n\ts1.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.POST(\"/post\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"post1\")\n\t\t})\n\t})\n\ts2.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.POST(\"/post\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"post2\")\n\t\t})\n\t})\n\ts1.SetDumpRouterMap(false)\n\ts2.SetDumpRouterMap(false)\n\tgtest.Assert(s1.Start(), nil)\n\tgtest.Assert(s2.Start(), nil)\n\tdefer s1.Shutdown()\n\tdefer s2.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc1 := g.Client()\n\t\tc1.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s1.GetListenedPort()))\n\t\tc2 := g.Client()\n\t\tc2.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s2.GetListenedPort()))\n\t\tt.Assert(c1.PostContent(ctx, \"/post\"), \"post1\")\n\t\tt.Assert(c2.PostContent(ctx, \"/post\"), \"post2\")\n\t})\n}\n\nfunc Test_Router_Group_Map(t *testing.T) {\n\ttestFuncGet := func(r *ghttp.Request) {\n\t\tr.Response.Write(\"get\")\n\t}\n\ttestFuncPost := func(r *ghttp.Request) {\n\t\tr.Response.Write(\"post\")\n\t}\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Map(map[string]any{\n\t\t\t\"Get: /test\": testFuncGet,\n\t\t\t\"Post:/test\": testFuncPost,\n\t\t})\n\t})\n\t//s.SetDumpRouterMap(false)\n\tgtest.Assert(s.Start(), nil)\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), \"get\")\n\t\tt.Assert(c.PostContent(ctx, \"/test\"), \"post\")\n\t})\n}\n\ntype SafeBuffer struct {\n\tbuffer *bytes.Buffer\n\tmu     sync.Mutex\n}\n\nfunc (b *SafeBuffer) Write(p []byte) (n int, err error) {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\treturn b.buffer.Write(p)\n}\n\nfunc (b *SafeBuffer) String() string {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\treturn b.buffer.String()\n}\n\nfunc Test_Router_OverWritten(t *testing.T) {\n\tvar (\n\t\ts   = g.Server(guid.S())\n\t\tobj = new(GroupObject)\n\t\tbuf = &SafeBuffer{\n\t\t\tbuffer: bytes.NewBuffer(nil),\n\t\t\tmu:     sync.Mutex{},\n\t\t}\n\t\tlogger = glog.NewWithWriter(buf)\n\t)\n\tlogger.SetStdoutPrint(false)\n\ts.SetLogger(logger)\n\ts.SetRouteOverWrite(true)\n\ts.Group(\"/api\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALLMap(g.Map{\n\t\t\t\"/obj\": obj,\n\t\t})\n\t\tgroup.ALLMap(g.Map{\n\t\t\t\"/obj\": obj,\n\t\t})\n\t})\n\ts.Start()\n\tdefer s.Shutdown()\n\n\tdumpContent := buf.String()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Count(dumpContent, `/api/obj `), 1)\n\t\tt.Assert(gstr.Count(dumpContent, `/api/obj/index`), 1)\n\t\tt.Assert(gstr.Count(dumpContent, `/api/obj/show`), 1)\n\t\tt.Assert(gstr.Count(dumpContent, `/api/obj/delete`), 1)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_hook_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Hook_Basic(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHookHandlerByMap(\"/*\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe:  func(r *ghttp.Request) { r.Response.Write(\"1\") },\n\t\tghttp.HookAfterServe:   func(r *ghttp.Request) { r.Response.Write(\"2\") },\n\t\tghttp.HookBeforeOutput: func(r *ghttp.Request) { r.Response.Write(\"3\") },\n\t\tghttp.HookAfterOutput:  func(r *ghttp.Request) { r.Response.Write(\"4\") },\n\t})\n\ts.BindHandler(\"/test/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"123\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test\"), \"1test23\")\n\t})\n}\n\nfunc Test_Router_Hook_Fuzzy_Router(t *testing.T) {\n\ts := g.Server(guid.S())\n\ti := 1000\n\tpattern1 := \"/:name/info\"\n\ts.BindHookHandlerByMap(pattern1, map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.SetParam(\"uid\", i)\n\t\t\ti++\n\t\t},\n\t})\n\ts.BindHandler(pattern1, func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"uid\"))\n\t})\n\n\tpattern2 := \"/{object}/list/{page}.java\"\n\ts.BindHookHandlerByMap(pattern2, map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeOutput: func(r *ghttp.Request) {\n\t\t\tr.Response.SetBuffer([]byte(\n\t\t\t\tfmt.Sprint(r.Get(\"object\"), \"&\", r.Get(\"page\"), \"&\", i),\n\t\t\t))\n\t\t},\n\t})\n\ts.BindHandler(pattern2, func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Router.Uri)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/john\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/info\"), \"1000\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/info\"), \"1001\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/list/1.java\"), \"john&1&1002\")\n\t\tt.Assert(client.GetContent(ctx, \"/john/list/2.java\"), \"john&2&1002\")\n\t})\n}\n\nfunc Test_Router_Hook_Priority(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/priority/show\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"show\")\n\t})\n\n\ts.BindHookHandlerByMap(\"/priority/:name\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/*any\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/priority/show\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"3\")\n\t\t},\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/priority/show\"), \"312show\")\n\t\tt.Assert(client.GetContent(ctx, \"/priority/any/any\"), \"2\")\n\t\tt.Assert(client.GetContent(ctx, \"/priority/name\"), \"12\")\n\t})\n}\n\nfunc Test_Router_Hook_Multi(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/multi-hook\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"show\")\n\t})\n\n\ts.BindHookHandlerByMap(\"/multi-hook\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t},\n\t})\n\ts.BindHookHandlerByMap(\"/multi-hook\", map[ghttp.HookName]ghttp.HandlerFunc{\n\t\tghttp.HookBeforeServe: func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t},\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/multi-hook\"), \"12show\")\n\t})\n}\n\nfunc Test_Router_Hook_ExitAll(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"test\")\n\t})\n\ts.Group(\"/hook\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"1\")\n\t\t\tr.Middleware.Next()\n\t\t})\n\t\tgroup.ALL(\"/test\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t})\n\n\ts.BindHookHandler(\"/hook/*\", ghttp.HookBeforeServe, func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hook\")\n\t\tr.ExitAll()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/test\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/hook/test\"), \"hook\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_names_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype NamesObject struct{}\n\nfunc (o *NamesObject) ShowName(r *ghttp.Request) {\n\tr.Response.Write(\"Object Show Name\")\n}\n\nfunc Test_NameToUri_FullName(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetNameToUriType(ghttp.UriTypeFullName)\n\ts.BindObject(\"/{.struct}/{.method}\", new(NamesObject))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/NamesObject\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/NamesObject/ShowName\"), \"Object Show Name\")\n\t})\n}\n\nfunc Test_NameToUri_AllLower(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetNameToUriType(ghttp.UriTypeAllLower)\n\ts.BindObject(\"/{.struct}/{.method}\", new(NamesObject))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/NamesObject\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/namesobject/showname\"), \"Object Show Name\")\n\t})\n}\n\nfunc Test_NameToUri_Camel(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetNameToUriType(ghttp.UriTypeCamel)\n\ts.BindObject(\"/{.struct}/{.method}\", new(NamesObject))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/NamesObject\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/namesObject/showName\"), \"Object Show Name\")\n\t})\n}\n\nfunc Test_NameToUri_Default(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetNameToUriType(ghttp.UriTypeDefault)\n\ts.BindObject(\"/{.struct}/{.method}\", new(NamesObject))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/NamesObject\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/names-object/show-name\"), \"Object Show Name\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_object_rest1_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype ObjectRest struct{}\n\nfunc (o *ObjectRest) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *ObjectRest) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *ObjectRest) Get(r *ghttp.Request) {\n\tr.Response.Write(\"Object Get\")\n}\n\nfunc (o *ObjectRest) Put(r *ghttp.Request) {\n\tr.Response.Write(\"Object Put\")\n}\n\nfunc (o *ObjectRest) Post(r *ghttp.Request) {\n\tr.Response.Write(\"Object Post\")\n}\n\nfunc (o *ObjectRest) Delete(r *ghttp.Request) {\n\tr.Response.Write(\"Object Delete\")\n}\n\nfunc (o *ObjectRest) Patch(r *ghttp.Request) {\n\tr.Response.Write(\"Object Patch\")\n}\n\nfunc (o *ObjectRest) Options(r *ghttp.Request) {\n\tr.Response.Write(\"Object Options\")\n}\n\nfunc (o *ObjectRest) Head(r *ghttp.Request) {\n\tr.Response.Header().Set(\"head-ok\", \"1\")\n}\n\nfunc Test_Router_ObjectRest(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObjectRest(\"/\", new(ObjectRest))\n\ts.BindObjectRest(\"/{.struct}/{.method}\", new(ObjectRest))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/\"), \"1Object Options2\")\n\t\tresp1, err := client.Head(ctx, \"/\")\n\t\tif err == nil {\n\t\t\tdefer resp1.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp1.Header.Get(\"head-ok\"), \"1\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/object-rest/get\"), \"1Object Get2\")\n\t\tt.Assert(client.PutContent(ctx, \"/object-rest/put\"), \"1Object Put2\")\n\t\tt.Assert(client.PostContent(ctx, \"/object-rest/post\"), \"1Object Post2\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/object-rest/delete\"), \"1Object Delete2\")\n\t\tt.Assert(client.PatchContent(ctx, \"/object-rest/patch\"), \"1Object Patch2\")\n\t\tt.Assert(client.OptionsContent(ctx, \"/object-rest/options\"), \"1Object Options2\")\n\t\tresp2, err := client.Head(ctx, \"/object-rest/head\")\n\t\tif err == nil {\n\t\t\tdefer resp2.Close()\n\t\t}\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp2.Header.Get(\"head-ok\"), \"1\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_object_rest2_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype ObjectRest2 struct{}\n\nfunc (o *ObjectRest2) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *ObjectRest2) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *ObjectRest2) Get(r *ghttp.Request) {\n\tr.Response.Write(\"Object Get\", r.Get(\"id\"))\n}\n\nfunc (o *ObjectRest2) Put(r *ghttp.Request) {\n\tr.Response.Write(\"Object Put\", r.Get(\"id\"))\n}\n\nfunc (o *ObjectRest2) Post(r *ghttp.Request) {\n\tr.Response.Write(\"Object Post\", r.Get(\"id\"))\n}\n\nfunc (o *ObjectRest2) Delete(r *ghttp.Request) {\n\tr.Response.Write(\"Object Delete\", r.Get(\"id\"))\n}\n\nfunc Test_Router_ObjectRest_Id(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObjectRest(\"/object/:id\", new(ObjectRest2))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/object/99\"), \"1Object Get992\")\n\t\tt.Assert(client.PutContent(ctx, \"/object/99\"), \"1Object Put992\")\n\t\tt.Assert(client.PostContent(ctx, \"/object/99\"), \"1Object Post992\")\n\t\tt.Assert(client.DeleteContent(ctx, \"/object/99\"), \"1Object Delete992\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_object_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype Object struct{}\n\nfunc (o *Object) Init(r *ghttp.Request) {\n\tr.Response.Write(\"1\")\n}\n\nfunc (o *Object) Shut(r *ghttp.Request) {\n\tr.Response.Write(\"2\")\n}\n\nfunc (o *Object) Index(r *ghttp.Request) {\n\tr.Response.Write(\"Object Index\")\n}\n\nfunc (o *Object) Show(r *ghttp.Request) {\n\tr.Response.Write(\"Object Show\")\n}\n\nfunc (o *Object) Info(r *ghttp.Request) {\n\tr.Response.Write(\"Object Info\")\n}\n\nfunc Test_Router_Object1(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObject(\"/\", new(Object))\n\ts.BindObject(\"/{.struct}/{.method}\", new(Object))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/show\"), \"1Object Show2\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"1Object Index2\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"1Object Show2\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_Object2(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObject(\"/object\", new(Object), \"Show, Info\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"1Object Show2\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"1Object Info2\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Router_ObjectMethod(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindObjectMethod(\"/object-info\", new(Object), \"Info\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/init\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/shut\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/index\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/show\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object/info\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/object-info\"), \"1Object Info2\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/none-exist\"), \"Not Found\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_router_standard_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Router_Handler_Standard_WithObject(t *testing.T) {\n\ttype TestReq struct {\n\t\tAge  int\n\t\tName string\n\t}\n\ttype TestRes struct {\n\t\tId   int\n\t\tAge  int\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test/error\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{\n\t\t\tId:   1,\n\t\t\tAge:  req.Age,\n\t\t\tName: req.Name,\n\t\t}, gerror.New(\"error\")\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/test?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18,\"Name\":\"john\"}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test/error\"), `{\"code\":50,\"message\":\"error\",\"data\":{\"Id\":1,\"Age\":0,\"Name\":\"\"}}`)\n\t})\n}\n\ntype TestForHandlerWithObjectAndMeta1Req struct {\n\tg.Meta `path:\"/custom-test1\" method:\"get\"`\n\tAge    int\n\tName   string\n}\n\ntype TestForHandlerWithObjectAndMeta1Res struct {\n\tId  int\n\tAge int\n}\n\ntype TestForHandlerWithObjectAndMeta2Req struct {\n\tg.Meta `path:\"/custom-test2\" method:\"get\"`\n\tAge    int\n\tName   string\n}\n\ntype TestForHandlerWithObjectAndMeta2Res struct {\n\tId   int\n\tName string\n}\n\ntype ControllerForHandlerWithObjectAndMeta1 struct{}\n\nfunc (ControllerForHandlerWithObjectAndMeta1) Index(ctx context.Context, req *TestForHandlerWithObjectAndMeta1Req) (res *TestForHandlerWithObjectAndMeta1Res, err error) {\n\treturn &TestForHandlerWithObjectAndMeta1Res{\n\t\tId:  1,\n\t\tAge: req.Age,\n\t}, nil\n}\n\nfunc (ControllerForHandlerWithObjectAndMeta1) Test2(ctx context.Context, req *TestForHandlerWithObjectAndMeta2Req) (res *TestForHandlerWithObjectAndMeta2Res, err error) {\n\treturn &TestForHandlerWithObjectAndMeta2Res{\n\t\tId:   1,\n\t\tName: req.Name,\n\t}, nil\n}\n\ntype TestForHandlerWithObjectAndMeta3Req struct {\n\tg.Meta `path:\"/custom-test3\" method:\"get\"`\n\tAge    int\n\tName   string\n}\n\ntype TestForHandlerWithObjectAndMeta3Res struct {\n\tId  int\n\tAge int\n}\n\ntype TestForHandlerWithObjectAndMeta4Req struct {\n\tg.Meta `path:\"/custom-test4\" method:\"get\"`\n\tAge    int\n\tName   string\n}\n\ntype TestForHandlerWithObjectAndMeta4Res struct {\n\tId   int\n\tName string\n}\n\ntype ControllerForHandlerWithObjectAndMeta2 struct{}\n\nfunc (ControllerForHandlerWithObjectAndMeta2) Test3(ctx context.Context, req *TestForHandlerWithObjectAndMeta3Req) (res *TestForHandlerWithObjectAndMeta3Res, err error) {\n\treturn &TestForHandlerWithObjectAndMeta3Res{\n\t\tId:  1,\n\t\tAge: req.Age,\n\t}, nil\n}\n\nfunc (ControllerForHandlerWithObjectAndMeta2) Test4(ctx context.Context, req *TestForHandlerWithObjectAndMeta4Req) (res *TestForHandlerWithObjectAndMeta4Res, err error) {\n\treturn &TestForHandlerWithObjectAndMeta4Res{\n\t\tId:   1,\n\t\tName: req.Name,\n\t}, nil\n}\n\nfunc Test_Router_Handler_Standard_WithObjectAndMeta(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/\", new(ControllerForHandlerWithObjectAndMeta1))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\t\tt.Assert(client.GetContent(ctx, \"/custom-test1?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/custom-test2?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Name\":\"john\"}}`)\n\t\tt.Assert(client.PostContent(ctx, \"/custom-test2?age=18&name=john\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\t})\n}\n\nfunc Test_Router_Handler_Standard_Group_Bind(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/api/v1\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(\n\t\t\tnew(ControllerForHandlerWithObjectAndMeta1),\n\t\t\tnew(ControllerForHandlerWithObjectAndMeta2),\n\t\t)\n\t})\n\ts.Group(\"/api/v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(\n\t\t\tnew(ControllerForHandlerWithObjectAndMeta1),\n\t\t\tnew(ControllerForHandlerWithObjectAndMeta2),\n\t\t)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v1/custom-test1?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v1/custom-test2?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Name\":\"john\"}}`)\n\t\tt.Assert(client.PostContent(ctx, \"/api/v1/custom-test2?age=18&name=john\"), `{\"code\":65,\"message\":\"Not Found\",\"data\":null}`)\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/v1/custom-test3?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v1/custom-test4?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Name\":\"john\"}}`)\n\n\t\tt.Assert(client.GetContent(ctx, \"/api/v2/custom-test1?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v2/custom-test2?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Name\":\"john\"}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v2/custom-test3?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Age\":18}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/api/v2/custom-test4?age=18&name=john\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Id\":1,\"Name\":\"john\"}}`)\n\t})\n}\n\nfunc Test_Issue1708(t *testing.T) {\n\ttype Test struct {\n\t\tName string `json:\"name\"`\n\t}\n\ttype Req struct {\n\t\tPage       int      `json:\"page\"       dc:\"分页码\"`\n\t\tSize       int      `json:\"size\"       dc:\"分页数量\"`\n\t\tTargetType string   `json:\"targetType\" v:\"required#评论内容类型错误\" dc:\"评论类型: topic/ask/article/reply\"`\n\t\tTargetId   uint     `json:\"targetId\"   v:\"required#评论目标ID错误\" dc:\"对应内容ID\"`\n\t\tTest       [][]Test `json:\"test\"`\n\t}\n\ttype Res struct {\n\t\tPage       int      `json:\"page\"       dc:\"分页码\"`\n\t\tSize       int      `json:\"size\"       dc:\"分页数量\"`\n\t\tTargetType string   `json:\"targetType\" v:\"required#评论内容类型错误\" dc:\"评论类型: topic/ask/article/reply\"`\n\t\tTargetId   uint     `json:\"targetId\"   v:\"required#评论目标ID错误\" dc:\"对应内容ID\"`\n\t\tTest       [][]Test `json:\"test\"`\n\t}\n\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn &Res{\n\t\t\tPage:       req.Page,\n\t\t\tSize:       req.Size,\n\t\t\tTargetType: req.TargetType,\n\t\t\tTargetId:   req.TargetId,\n\t\t\tTest:       req.Test,\n\t\t}, nil\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tcontent := `\n{\n    \"targetType\":\"topic\",\n    \"targetId\":10785,\n    \"test\":[\n        [\n            {\n                \"name\":\"123\"\n            }\n        ]\n    ]\n}\n`\n\t\tt.Assert(\n\t\t\tclient.PostContent(ctx, \"/test\", content),\n\t\t\t`{\"code\":0,\"message\":\"OK\",\"data\":{\"page\":0,\"size\":0,\"targetType\":\"topic\",\"targetId\":10785,\"test\":[[{\"name\":\"123\"}]]}}`,\n\t\t)\n\t})\n}\n\nfunc Test_Custom_Slice_Type_Attribute(t *testing.T) {\n\ttype (\n\t\tWhiteListKey    string\n\t\tWhiteListValues []string\n\t\tWhiteList       map[WhiteListKey]WhiteListValues\n\t)\n\ttype Req struct {\n\t\tId   int\n\t\tList WhiteList\n\t}\n\ttype Res struct {\n\t\tContent string\n\t}\n\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn &Res{\n\t\t\tContent: gjson.MustEncodeString(req),\n\t\t}, nil\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tcontent := `\n{\n    \"id\":1,\n\t\"list\":{\n\t\t\"key\": [\"a\", \"b\", \"c\"]\n\t}\n}\n`\n\t\tt.Assert(\n\t\t\tclient.PostContent(ctx, \"/test\", content),\n\t\t\t`{\"code\":0,\"message\":\"OK\",\"data\":{\"Content\":\"{\\\"Id\\\":1,\\\"List\\\":{\\\"key\\\":[\\\"a\\\",\\\"b\\\",\\\"c\\\"]}}\"}}`,\n\t\t)\n\t})\n}\n\nfunc Test_Router_Handler_Standard_WithGeneric(t *testing.T) {\n\ttype TestReq struct {\n\t\tAge int\n\t}\n\ttype TestGeneric[T any] struct {\n\t\tTest T\n\t}\n\ttype Test1Res struct {\n\t\tAge TestGeneric[int]\n\t}\n\ttype Test2Res TestGeneric[int]\n\ttype TestGenericRes[T any] struct {\n\t\tTest T\n\t}\n\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.BindHandler(\"/test1\", func(ctx context.Context, req *TestReq) (res *Test1Res, err error) {\n\t\treturn &Test1Res{\n\t\t\tAge: TestGeneric[int]{\n\t\t\t\tTest: req.Age,\n\t\t\t},\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test1_slice\", func(ctx context.Context, req *TestReq) (res []Test1Res, err error) {\n\t\treturn []Test1Res{\n\t\t\t{\n\t\t\t\tAge: TestGeneric[int]{\n\t\t\t\t\tTest: req.Age,\n\t\t\t\t},\n\t\t\t},\n\t\t}, nil\n\t})\n\ts.BindHandler(\"/test2\", func(ctx context.Context, req *TestReq) (res *Test2Res, err error) {\n\t\treturn &Test2Res{\n\t\t\tTest: req.Age,\n\t\t}, nil\n\t})\n\n\ts.BindHandler(\"/test2_slice\", func(ctx context.Context, req *TestReq) (res []Test2Res, err error) {\n\t\treturn []Test2Res{\n\t\t\t{\n\t\t\t\tTest: req.Age,\n\t\t\t},\n\t\t}, nil\n\t})\n\n\ts.BindHandler(\"/test3\", func(ctx context.Context, req *TestReq) (res *TestGenericRes[int], err error) {\n\t\treturn &TestGenericRes[int]{\n\t\t\tTest: req.Age,\n\t\t}, nil\n\t})\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ts.BindHandler(\"/test3_slice\", func(ctx context.Context, req *TestReq) (res []TestGenericRes[int], err error) {\n\t\treturn []TestGenericRes[int]{\n\t\t\t{\n\t\t\t\tTest: req.Age,\n\t\t\t},\n\t\t}, nil\n\t})\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/test1?age=1\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Age\":{\"Test\":1}}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test1_slice?age=1\"), `{\"code\":0,\"message\":\"OK\",\"data\":[{\"Age\":{\"Test\":1}}]}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test2?age=2\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Test\":2}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test2_slice?age=2\"), `{\"code\":0,\"message\":\"OK\",\"data\":[{\"Test\":2}]}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test3?age=3\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Test\":3}}`)\n\t\tt.Assert(client.GetContent(ctx, \"/test3_slice?age=3\"), `{\"code\":0,\"message\":\"OK\",\"data\":[{\"Test\":3}]}`)\n\t})\n}\n\ntype ParameterCaseSensitiveController struct{}\n\ntype ParameterCaseSensitiveControllerPathReq struct {\n\tg.Meta `path:\"/api/*path\" method:\"post\"`\n\tPath   string\n}\n\ntype ParameterCaseSensitiveControllerPathRes struct {\n\tPath string\n}\n\nfunc (c *ParameterCaseSensitiveController) Path(\n\tctx context.Context,\n\treq *ParameterCaseSensitiveControllerPathReq,\n) (res *ParameterCaseSensitiveControllerPathRes, err error) {\n\treturn &ParameterCaseSensitiveControllerPathRes{Path: req.Path}, nil\n}\n\nfunc Test_Router_Handler_Standard_ParameterCaseSensitive(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(&ParameterCaseSensitiveController{})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tt.Assert(\n\t\t\t\tclient.PostContent(ctx, \"/api/111\", `{\"Path\":\"222\"}`),\n\t\t\t\t`{\"code\":0,\"message\":\"OK\",\"data\":{\"Path\":\"222\"}}`,\n\t\t\t)\n\t\t}\n\t})\n}\n\ntype testJsonRawMessageIssue3449Req struct {\n\tg.Meta `path:\"/test\" method:\"POST\" sm:\"hello\" tags:\"示例\"`\n\n\tName    string          `json:\"name\" v:\"required\" dc:\"名称\"`\n\tJSONRaw json.RawMessage `json:\"jsonRaw\" dc:\"原始JSON\"`\n}\ntype testJsonRawMessageIssue3449Res struct {\n\tName    string          `json:\"name\" v:\"required\" dc:\"名称\"`\n\tJSONRaw json.RawMessage `json:\"jsonRaw\" dc:\"原始JSON\"`\n}\n\ntype testJsonRawMessageIssue3449 struct {\n}\n\nfunc (t *testJsonRawMessageIssue3449) Test(ctx context.Context, req *testJsonRawMessageIssue3449Req) (res *testJsonRawMessageIssue3449Res, err error) {\n\treturn &testJsonRawMessageIssue3449Res{\n\t\tName:    req.Name,\n\t\tJSONRaw: req.JSONRaw,\n\t}, nil\n}\n\n// https://github.com/gogf/gf/issues/3449\nfunc Test_JsonRawMessage_Issue3449(t *testing.T) {\n\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(new(testJsonRawMessageIssue3449))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tv1 := map[string]any{\n\t\t\t\"jkey1\": \"11\",\n\t\t\t\"jkey2\": \"12\",\n\t\t}\n\n\t\tv2 := map[string]any{\n\t\t\t\"jkey1\": \"21\",\n\t\t\t\"jkey2\": \"22\",\n\t\t}\n\t\tdata := map[string]any{\n\t\t\t\"Name\": \"test\",\n\t\t\t\"jsonRaw\": []any{\n\t\t\t\tv1, v2,\n\t\t\t},\n\t\t}\n\n\t\texpect1 := `{\"code\":0,\"message\":\"OK\",\"data\":{\"name\":\"test\",\"jsonRaw\":[{\"jkey1\":\"11\",\"jkey2\":\"12\"},{\"jkey1\":\"21\",\"jkey2\":\"22\"}]}}`\n\t\tt.Assert(client.PostContent(ctx, \"/test\", data), expect1)\n\n\t\texpect2 := `{\"code\":0,\"message\":\"OK\",\"data\":{\"name\":\"test\",\"jsonRaw\":{\"jkey1\":\"11\",\"jkey2\":\"12\"}}}`\n\t\tt.Assert(client.PostContent(ctx, \"/test\", map[string]any{\n\t\t\t\"Name\":    \"test\",\n\t\t\t\"jsonRaw\": v1,\n\t\t}), expect2)\n\n\t})\n}\n\ntype testNullStringIssue3465Req struct {\n\tg.Meta `path:\"/test\" method:\"get\" sm:\"hello\" tags:\"示例\"`\n\tName   []string `json:\"name\" v:\"required\"`\n}\ntype testNullStringIssue3465Res struct {\n\tName []string `json:\"name\" v:\"required\" `\n}\n\ntype testNullStringIssue3465 struct {\n}\n\nfunc (t *testNullStringIssue3465) Test(ctx context.Context, req *testNullStringIssue3465Req) (res *testNullStringIssue3465Res, err error) {\n\treturn &testNullStringIssue3465Res{\n\t\tName: req.Name,\n\t}, nil\n}\n\n// https://github.com/gogf/gf/issues/3465\nfunc Test_NullString_Issue3465(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(new(testNullStringIssue3465))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tdata1 := map[string]any{\n\t\t\t\"name\": \"null\",\n\t\t}\n\n\t\texpect1 := `{\"code\":0,\"message\":\"OK\",\"data\":{\"name\":[\"null\"]}}`\n\t\tt.Assert(client.GetContent(ctx, \"/test\", data1), expect1)\n\n\t\tdata2 := map[string]any{\n\t\t\t\"name\": []string{\"null\", \"null\"},\n\t\t}\n\t\texpect2 := `{\"code\":0,\"message\":\"OK\",\"data\":{\"name\":[\"null\",\"null\"]}}`\n\t\tt.Assert(client.GetContent(ctx, \"/test\", data2), expect2)\n\n\t})\n}\n\ntype testHandlerItemGetMetaTagReq struct {\n\tg.Meta `path:\"/test\" method:\"get\" sm:\"hello\" tags:\"示例\"`\n}\ntype testHandlerItemGetMetaTagRes struct{}\n\ntype testHandlerItemGetMetaTag struct {\n}\n\nfunc (t *testHandlerItemGetMetaTag) Test(ctx context.Context, req *testHandlerItemGetMetaTagReq) (res *testHandlerItemGetMetaTagRes, err error) {\n\treturn nil, nil\n}\n\nfunc TestHandlerItem_GetMetaTag(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(new(testHandlerItemGetMetaTag))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\troutes := s.GetRoutes()\n\t\tfor _, route := range routes {\n\t\t\tif !route.IsServiceHandler {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tt.Assert(route.Handler.GetMetaTag(\"path\"), \"/test\")\n\t\t\tt.Assert(route.Handler.GetMetaTag(\"method\"), \"get\")\n\t\t\tt.Assert(route.Handler.GetMetaTag(\"sm\"), \"hello\")\n\t\t\tt.Assert(route.Handler.GetMetaTag(\"tags\"), \"示例\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_server_util_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\ntype testWrapStdHTTPStruct struct {\n\tT    *gtest.T\n\ttext string\n}\n\nfunc (t *testWrapStdHTTPStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tt.T.Assert(req.Method, \"POST\")\n\tt.T.Assert(req.URL.Path, \"/api/wraph\")\n\tw.WriteHeader(http.StatusInternalServerError)\n\tfmt.Fprint(w, t.text)\n}\n\nfunc Test_Server_Wrap_Handler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tstr1 := \"hello\"\n\t\tstr2 := \"hello again\"\n\t\ts.Group(\"/api\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.GET(\"/wrapf\", ghttp.WrapF(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t\tt.Assert(req.Method, \"GET\")\n\t\t\t\tt.Assert(req.URL.Path, \"/api/wrapf\")\n\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t\tfmt.Fprint(w, str1)\n\t\t\t}))\n\n\t\t\tgroup.POST(\"/wraph\", ghttp.WrapH(&testWrapStdHTTPStruct{t, str2}))\n\t\t})\n\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d/api\", s.GetListenedPort()))\n\n\t\tresponse, err := client.Get(ctx, \"/wrapf\")\n\t\tt.AssertNil(err)\n\t\tdefer response.Close()\n\t\tt.Assert(response.StatusCode, http.StatusBadRequest)\n\t\tt.Assert(response.ReadAllString(), str1)\n\n\t\tresponse2, err := client.Post(ctx, \"/wraph\")\n\t\tt.AssertNil(err)\n\t\tdefer response2.Close()\n\t\tt.Assert(response2.StatusCode, http.StatusInternalServerError)\n\t\tt.Assert(response2.ReadAllString(), str2)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_session_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Session_Cookie(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/set\", func(r *ghttp.Request) {\n\t\tr.Session.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t})\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Session.Get(r.Get(\"k\").String()))\n\t})\n\ts.BindHandler(\"/remove\", func(r *ghttp.Request) {\n\t\tr.Session.Remove(r.Get(\"k\").String())\n\t})\n\ts.BindHandler(\"/clear\", func(r *ghttp.Request) {\n\t\tr.Session.RemoveAll()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr1, e1 := client.Get(ctx, \"/set?k=key1&v=100\")\n\t\tif r1 != nil {\n\t\t\tdefer r1.Close()\n\t\t}\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(r1.ReadAllString(), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/set?k=key2&v=200\"), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key4\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\tt.Assert(client.GetContent(ctx, \"/clear\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"\")\n\t})\n}\n\nfunc Test_Session_Header(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/set\", func(r *ghttp.Request) {\n\t\tr.Session.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t})\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Session.Get(r.Get(\"k\").String()))\n\t})\n\ts.BindHandler(\"/remove\", func(r *ghttp.Request) {\n\t\tr.Session.Remove(r.Get(\"k\").String())\n\t})\n\ts.BindHandler(\"/clear\", func(r *ghttp.Request) {\n\t\tr.Session.RemoveAll()\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tresponse, e1 := client.Get(ctx, \"/set?k=key1&v=100\")\n\t\tif response != nil {\n\t\t\tdefer response.Close()\n\t\t}\n\t\tsessionId := response.GetCookie(s.GetSessionIdName())\n\t\tt.Assert(e1, nil)\n\t\tt.AssertNE(sessionId, nil)\n\t\tt.Assert(response.ReadAllString(), \"\")\n\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\n\t\tt.Assert(client.GetContent(ctx, \"/set?k=key2&v=200\"), \"\")\n\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key3\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/remove?k=key4\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"200\")\n\t\tt.Assert(client.GetContent(ctx, \"/clear\"), \"\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key2\"), \"\")\n\t})\n}\n\nfunc Test_Session_StorageFile(t *testing.T) {\n\tsessionId := \"\"\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/set\", func(r *ghttp.Request) {\n\t\tr.Session.Set(r.Get(\"k\").String(), r.Get(\"v\").String())\n\t\tr.Response.Write(r.Get(\"k\").String(), \"=\", r.Get(\"v\").String())\n\t})\n\ts.BindHandler(\"/get\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Session.Get(r.Get(\"k\").String()))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tresponse, e1 := client.Get(ctx, \"/set?k=key&v=100\")\n\t\tif response != nil {\n\t\t\tdefer response.Close()\n\t\t}\n\t\tsessionId = response.GetCookie(s.GetSessionIdName())\n\t\tt.Assert(e1, nil)\n\t\tt.AssertNE(sessionId, nil)\n\t\tt.Assert(response.ReadAllString(), \"key=100\")\n\t})\n\ttime.Sleep(time.Second)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key\"), \"100\")\n\t\tt.Assert(client.GetContent(ctx, \"/get?k=key1\"), \"\")\n\t})\n}\n\nfunc Test_Session_Custom_Id(t *testing.T) {\n\tvar (\n\t\tsessionId = \"1234567890\"\n\t\tkey       = \"key\"\n\t\tvalue     = \"value\"\n\t\ts         = g.Server(guid.S())\n\t)\n\ts.BindHandler(\"/id\", func(r *ghttp.Request) {\n\t\tif err := r.Session.SetId(sessionId); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tif err := r.Session.Set(key, value); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tr.Response.WriteExit(r.Session.Id())\n\t})\n\ts.BindHandler(\"/value\", func(r *ghttp.Request) {\n\t\tr.Response.WriteExit(r.Session.Get(key))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr, err := client.Get(ctx, \"/id\")\n\t\tt.AssertNil(err)\n\t\tdefer r.Close()\n\t\tt.Assert(r.ReadAllString(), sessionId)\n\t\tt.Assert(r.GetCookie(s.GetSessionIdName()), sessionId)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\t\tt.Assert(client.GetContent(ctx, \"/value\"), value)\n\t})\n}\n\nfunc Test_Session_New_Id(t *testing.T) {\n\tvar (\n\t\tsessionId     = \"1234567890\"\n\t\tnewSessionId  = \"0987654321\"\n\t\tnewSessionId2 = \"abcdefghij\"\n\t\tkey           = \"key\"\n\t\tvalue         = \"value\"\n\t\ts             = g.Server(guid.S())\n\t)\n\ts.BindHandler(\"/id\", func(r *ghttp.Request) {\n\t\tif err := r.Session.SetId(sessionId); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tif err := r.Session.Set(key, value); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tr.Response.WriteExit(r.Session.Id())\n\t})\n\n\ts.BindHandler(\"/newIdBySession\", func(r *ghttp.Request) {\n\t\t// Use before session init\n\t\tif err := r.Session.SetId(newSessionId); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tif err := r.Session.Set(key, value); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\t\tr.Response.WriteExit(r.Session.Id())\n\t})\n\n\ts.BindHandler(\"/newIdByCookie\", func(r *ghttp.Request) {\n\t\tif err := r.Session.Remove(\"someKey\"); err != nil {\n\t\t\tr.Response.WriteExit(err.Error())\n\t\t}\n\n\t\tr.Cookie.SetSessionId(newSessionId2)\n\t\t//r.Response.WriteExit(r.Session.Id())    // only change in cookie\n\n\t\tr.Response.WriteExit(newSessionId2)\n\t})\n\n\ts.BindHandler(\"/value\", func(r *ghttp.Request) {\n\t\tr.Response.WriteExit(r.Session.Get(key))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr, err := client.Get(ctx, \"/id\")\n\t\tt.AssertNil(err)\n\t\tdefer r.Close()\n\t\tt.Assert(r.ReadAllString(), sessionId)\n\t\tt.Assert(r.GetCookie(s.GetSessionIdName()), sessionId)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\t\tt.Assert(client.GetContent(ctx, \"/value\"), value)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\t\tr, err := client.Get(ctx, \"/newIdBySession\")\n\t\tt.AssertNil(err)\n\t\tdefer r.Close()\n\t\tt.Assert(r.ReadAllString(), newSessionId)\n\t\tt.Assert(r.GetCookie(s.GetSessionIdName()), newSessionId)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tr, err := client.Get(ctx, \"/newIdByCookie\")\n\t\tclient.SetHeader(s.GetSessionIdName(), sessionId)\n\t\tt.AssertNil(err)\n\t\tdefer r.Close()\n\t\tt.Assert(r.ReadAllString(), newSessionId2)\n\t\tt.Assert(r.GetCookie(s.GetSessionIdName()), newSessionId2)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_static_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Static_ServerRoot(t *testing.T) {\n\t// SetServerRoot with absolute path\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/index.htm\", \"index\")\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.htm\"), \"index\")\n\t})\n\n\t// SetServerRoot with relative path\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`static/test/%d`, s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/index.htm\", \"index\")\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.htm\"), \"index\")\n\t})\n}\n\nfunc Test_Static_ServerRoot_Security(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.SetServerRoot(gtest.DataPath(\"static1\"))\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.htm\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.html\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/../main.html\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/..%2Fmain.html\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Static_Folder_Forbidden(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/test.html\", \"test\")\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.html\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t})\n}\n\nfunc Test_Static_IndexFolder(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/test.html\", \"test\")\n\t\ts.SetIndexFolder(true)\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.AssertNE(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.AssertNE(gstr.Pos(client.GetContent(ctx, \"/\"), `<a href=\"/test.html\"`), -1)\n\t\tt.Assert(client.GetContent(ctx, \"/index.html\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t})\n}\n\nfunc Test_Static_IndexFiles1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/index.html\", \"index\")\n\t\tgfile.PutContents(path+\"/test.html\", \"test\")\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.html\"), \"index\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t})\n}\n\nfunc Test_Static_IndexFiles2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/test.html\", \"test\")\n\t\ts.SetIndexFiles([]string{\"index.html\", \"test.html\"})\n\t\ts.SetServerRoot(path)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"test\")\n\t\tt.Assert(client.GetContent(ctx, \"/index.html\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t})\n}\n\nfunc Test_Static_AddSearchPath1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tpath2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.Temp(), s.GetListenedPort(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path1)\n\t\tdefer gfile.Remove(path2)\n\t\tgfile.PutContents(path2+\"/test.html\", \"test\")\n\t\ts.SetServerRoot(path1)\n\t\ts.AddSearchPath(path2)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test\")\n\t})\n}\n\nfunc Test_Static_AddSearchPath2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tpath2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.Temp(), s.GetListenedPort(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path1)\n\t\tdefer gfile.Remove(path2)\n\t\tgfile.PutContents(path1+\"/test.html\", \"test1\")\n\t\tgfile.PutContents(path2+\"/test.html\", \"test2\")\n\t\ts.SetServerRoot(path1)\n\t\ts.AddSearchPath(path2)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test1\")\n\t})\n}\n\nfunc Test_Static_AddStaticPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath1 := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tpath2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d`, gfile.Temp(), s.GetListenedPort(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path1)\n\t\tdefer gfile.Remove(path2)\n\t\tgfile.PutContents(path1+\"/test.html\", \"test1\")\n\t\tgfile.PutContents(path2+\"/test.html\", \"test2\")\n\t\ts.SetServerRoot(path1)\n\t\ts.AddStaticPath(\"/my-test\", path2)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test1\")\n\t\tt.Assert(client.GetContent(ctx, \"/my-test/test.html\"), \"test2\")\n\t})\n}\n\nfunc Test_Static_AddStaticPath_Priority(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath1 := fmt.Sprintf(`%s/ghttp/static/test/%d/test`, gfile.Temp(), s.GetListenedPort())\n\t\tpath2 := fmt.Sprintf(`%s/ghttp/static/test/%d/%d/test`, gfile.Temp(), s.GetListenedPort(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path1)\n\t\tdefer gfile.Remove(path2)\n\t\tgfile.PutContents(path1+\"/test.html\", \"test1\")\n\t\tgfile.PutContents(path2+\"/test.html\", \"test2\")\n\t\ts.SetServerRoot(path1)\n\t\ts.AddStaticPath(\"/test\", path2)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test1\")\n\t\tt.Assert(client.GetContent(ctx, \"/test/test.html\"), \"test2\")\n\t})\n}\n\nfunc Test_Static_Rewrite(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\tpath := fmt.Sprintf(`%s/ghttp/static/test/%d`, gfile.Temp(), s.GetListenedPort())\n\t\tdefer gfile.Remove(path)\n\t\tgfile.PutContents(path+\"/test1.html\", \"test1\")\n\t\tgfile.PutContents(path+\"/test2.html\", \"test2\")\n\t\ts.SetServerRoot(path)\n\t\ts.SetRewrite(\"/test.html\", \"/test1.html\")\n\t\ts.SetRewriteMap(g.MapStrStr{\n\t\t\t\"/my-test1\": \"/test1.html\",\n\t\t\t\"/my-test2\": \"/test2.html\",\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Forbidden\")\n\t\tt.Assert(client.GetContent(ctx, \"/test.html\"), \"test1\")\n\t\tt.Assert(client.GetContent(ctx, \"/test1.html\"), \"test1\")\n\t\tt.Assert(client.GetContent(ctx, \"/test2.html\"), \"test2\")\n\t\tt.Assert(client.GetContent(ctx, \"/my-test1\"), \"test1\")\n\t\tt.Assert(client.GetContent(ctx, \"/my-test2\"), \"test2\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_status_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_StatusHandler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.BindStatusHandlerByMap(map[int]ghttp.HandlerFunc{\n\t\t\t404: func(r *ghttp.Request) { r.Response.WriteOver(\"404\") },\n\t\t\t502: func(r *ghttp.Request) { r.Response.WriteOver(\"502\") },\n\t\t})\n\t\ts.BindHandler(\"/502\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteStatusExit(502)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/404\"), \"404\")\n\t\tt.Assert(client.GetContent(ctx, \"/502\"), \"502\")\n\t})\n}\n\nfunc Test_StatusHandler_Multi(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.BindStatusHandler(502, func(r *ghttp.Request) {\n\t\t\tr.Response.WriteOver(\"1\")\n\t\t})\n\t\ts.BindStatusHandler(502, func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"2\")\n\t\t})\n\t\ts.BindHandler(\"/502\", func(r *ghttp.Request) {\n\t\t\tr.Response.WriteStatusExit(502)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/502\"), \"12\")\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_template_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// static service testing.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghtml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Template_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New(gtest.DataPath(\"template\", \"basic\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"index.html\", g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n}\n\nfunc Test_Template_Encode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New(gtest.DataPath(\"template\", \"basic\"))\n\t\tv.SetAutoEncode(true)\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"index.html\", g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Name:john\")\n\t})\n}\n\nfunc Test_Template_Layout1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New(gtest.DataPath(\"template\", \"layout1\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/layout\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"layout.html\", g.Map{\n\t\t\t\t\"mainTpl\": \"main/main1.html\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.BindHandler(\"/nil\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"layout.html\", nil)\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/layout\"), \"123\")\n\t\tt.Assert(client.GetContent(ctx, \"/nil\"), \"123\")\n\t})\n}\n\nfunc Test_Template_Layout2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New(gtest.DataPath(\"template\", \"layout2\"))\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/main1\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"layout.html\", g.Map{\n\t\t\t\t\"mainTpl\": \"main/main1.html\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.BindHandler(\"/main2\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"layout.html\", g.Map{\n\t\t\t\t\"mainTpl\": \"main/main2.html\",\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.BindHandler(\"/nil\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTpl(\"layout.html\", nil)\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), \"Not Found\")\n\t\tt.Assert(client.GetContent(ctx, \"/main1\"), \"a1b\")\n\t\tt.Assert(client.GetContent(ctx, \"/main2\"), \"a2b\")\n\t\tt.Assert(client.GetContent(ctx, \"/nil\"), \"ab\")\n\t})\n}\n\nfunc Test_Template_BuildInVarRequest(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.BindHandler(\"/:table/test\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTplContent(\"{{.Request.table}}\")\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/user/test\"), \"user\")\n\t\tt.Assert(client.GetContent(ctx, \"/order/test\"), \"order\")\n\t})\n}\n\nfunc Test_Template_XSS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetAutoEncode(true)\n\t\tc := \"<br>\"\n\t\ts := g.Server(guid.S())\n\t\ts.SetView(v)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\terr := r.Response.WriteTplContent(\"{{if eq 1 1}}{{.v}}{{end}}\", g.Map{\n\t\t\t\t\"v\": c,\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(client.GetContent(ctx, \"/\"), ghtml.Entities(c))\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_feature_websocket_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_WebSocket(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/ws\", func(r *ghttp.Request) {\n\t\tws, err := r.WebSocket()\n\t\tif err != nil {\n\t\t\tr.Exit()\n\t\t}\n\t\tfor {\n\t\t\tmsgType, msg, err := ws.ReadMessage()\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err = ws.WriteMessage(msgType, msg); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf(\n\t\t\t\"ws://127.0.0.1:%d/ws\", s.GetListenedPort(),\n\t\t), nil)\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\n\t\tmsg := []byte(\"hello\")\n\t\terr = conn.WriteMessage(websocket.TextMessage, msg)\n\t\tt.AssertNil(err)\n\n\t\tmt, data, err := conn.ReadMessage()\n\t\tt.AssertNil(err)\n\t\tt.Assert(mt, websocket.TextMessage)\n\t\tt.Assert(data, msg)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// https://github.com/gogf/gf/issues/1609\nfunc Test_Issue1609(t *testing.T) {\n\ts := g.Server(guid.S())\n\tgroup := s.Group(\"/api/get\")\n\tgroup.GET(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"get\")\n\t})\n\ts.SetDumpRouterMap(false)\n\tgtest.Assert(s.Start(), nil)\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/api/get\"), \"get\")\n\t\tt.Assert(c.PostContent(ctx, \"/test\"), \"Not Found\")\n\t})\n}\n\nfunc Test_Issue1611(t *testing.T) {\n\ts := g.Server(guid.S())\n\tv := g.View(guid.S())\n\tcontent := \"This is header\"\n\tgtest.AssertNil(v.SetPath(gtest.DataPath(\"issue1611\")))\n\ts.SetView(v)\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tgtest.AssertNil(r.Response.WriteTpl(\"index/layout.html\", g.Map{\n\t\t\t\"header\": content,\n\t\t}))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(gstr.Contains(c.GetContent(ctx, \"/\"), content), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1626\nfunc Test_Issue1626(t *testing.T) {\n\ttype TestReq struct {\n\t\tName string `v:\"required\"`\n\t}\n\ttype TestRes struct {\n\t\tName string\n\t}\n\ts := g.Server(guid.S())\n\ts.Use(\n\t\tghttp.MiddlewareHandlerResponse,\n\t\tfunc(r *ghttp.Request) {\n\t\t\tr.Middleware.Next()\n\t\t\tif err := r.GetError(); err != nil {\n\t\t\t\tr.Response.ClearBuffer()\n\t\t\t\tr.Response.Write(err.Error())\n\t\t\t}\n\t\t},\n\t)\n\ts.BindHandler(\"/test\", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {\n\t\treturn &TestRes{Name: req.Name}, nil\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/test\"), `The Name field is required`)\n\t\tt.Assert(\n\t\t\tgstr.Contains(c.GetContent(ctx, \"/test?name=john\"), `{\"Name\":\"john\"}`),\n\t\t\ttrue,\n\t\t)\n\t})\n}\n\ntype Issue1653TestReq struct {\n\tg.Meta    `path:\"/test\" method:\"post\" summary:\"执行报表查询\" tags:\"\"`\n\tUUID      string  `json:\"uuid\" v:\"required#菜单唯一码不可为空\" dc:\"\"`\n\tLimit     int     `json:\"limit\"`\n\tFilter    []g.Map `json:\"filter\"`\n\tFilterMap g.Map   `json:\"filter_map\"`\n}\n\ntype Issue1653TestRes struct {\n\tUUID     string `json:\"uuid\"`\n\tFeedBack any    `json:\"feed_back\"`\n}\n\ntype cIssue1653Foo struct{}\n\nvar Issue1653Foo = new(cIssue1653Foo)\n\nfunc (r cIssue1653Foo) PostTest(ctx context.Context, req *Issue1653TestReq) (*Issue1653TestRes, error) {\n\treturn &Issue1653TestRes{UUID: req.UUID, FeedBack: req.Filter[0][\"code\"]}, nil\n}\n\nfunc Test_Issue1653(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/boot\", func(grp *ghttp.RouterGroup) {\n\t\tgrp.Bind(Issue1653Foo)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\t// g.Client()测试：\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tdataReq := `\n{\"uuid\":\"28ee701c-7daf-4cdc-9a62-6d6704e6112b\",\"limit\":0,\"filter\":\n[\n{\n\"code\":\"P00001\",\"constraint\":\"\",\n\"created_at\":\"2022-03-08 04:56:15\",\"created_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"default_value\":\"MonthStart()\",\n\"expression\":\"AND A.DLVDAT_0>='%v'\",\"force\":false,\"frequent\":true,\"name\":\"发货日期起\",\n\"parent\":\"13109602-0da3-49b9-827f-2f44183ab756\",\"read_only\":false,\"reference\":null,\"type\":\"date\",\n\"updated_at\":\"2022-03-08 04:56:15\",\"updated_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"updated_tick\":1,\n\"uuid\":\"e6cd3268-1d75-42e0-83f9-f1f7b29976e8\"\n},\n{\n\"code\":\"P00002\",\"constraint\":\"\",\"created_at\":\"2022-03-08 04:56:15\",\"created_by\":\n\"3ed72aba-1622-4262-a61e-83581e020763\",\"default_value\":\"MonthEnd()\",\"expression\":\"AND A.DLVDAT_0<='%v'\",\"force\":false,\"frequent\":true,\n\"name\":\"发货日期止\",\"parent\":\"13109602-0da3-49b9-827f-2f44183ab756\",\"read_only\":false,\"reference\":null,\"type\":\"date\",\"updated_at\":\n\"2022-03-08 04:56:15\",\"updated_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"updated_tick\":1,\"uuid\":\"dba005b5-655e-4ac4-8b22-898aa3ad2294\"\n}\n],\n\"filter_map\":{\"P00001\":1646064000000,\"P00002\":1648742399999},\n\"selector_template\":\"\"\n}\n`\n\t\tresContent := c.PostContent(ctx, \"/boot/test\", dataReq)\n\t\tt.Assert(resContent, `{\"code\":0,\"message\":\"OK\",\"data\":{\"uuid\":\"28ee701c-7daf-4cdc-9a62-6d6704e6112b\",\"feed_back\":\"P00001\"}}`)\n\t})\n}\n\ntype LbseMasterHead struct {\n\tCode     string   `json:\"code\" v:\"code@required|min-length:1#The code is required\"`\n\tActive   bool     `json:\"active\"`\n\tPreset   bool     `json:\"preset\"`\n\tSuperior string   `json:\"superior\"`\n\tPath     []string `json:\"path\"`\n\tSort     int      `json:\"sort\"`\n\tFolder   bool     `json:\"folder\"`\n\tTest     string   `json:\"test\" v:\"required\"`\n}\n\ntype Template struct {\n\tLbseMasterHead\n\tDatasource string `json:\"datasource\" v:\"required|length:32,32#The datasource is required\"`\n\tSQLText    string `json:\"sql_text\"`\n}\n\ntype TemplateCreateReq struct {\n\tg.Meta `path:\"/test\" method:\"post\" summary:\"Create template\" tags:\"Template\"`\n\tMaster Template `json:\"master\"`\n}\n\ntype TemplateCreateRes struct{}\n\ntype cFoo1 struct{}\n\nvar Foo1 = new(cFoo1)\n\nfunc (r cFoo1) PostTest1(ctx context.Context, req *TemplateCreateReq) (res *TemplateCreateRes, err error) {\n\tg.Dump(req)\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/1662\nfunc Test_Issue662(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/boot\", func(grp *ghttp.RouterGroup) {\n\t\tgrp.Bind(Foo1)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\n\t// g.Client()测试：\n\t// code字段传入空字符串时，校验没有提示\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tdataReq := `\n{\"master\":{\"active\":true,\"code\":\"\",\"created_at\":\"\",\"created_by\":\"\",\"created_by_text\":\"\",\"datasource\":\"38b6f170-a584-43fc-8912-cc1e9bf1b1a9\",\"description\":\"币种\",\"folder\":false,\"path\":\"[\\\"XCUR\\\"]\",\"preset\":false,\"sort\":1000,\"sql_text\":\"SELECT!!!!\",\"superior\":null,\"updated_at\":\"\",\"updated_by\":\"\",\"updated_by_text\":\"\",\"updated_tick\":0,\"uuid\":\"\"},\"translation\":[{\"code\":\"zh_CN\",\"text\":\"币种\"},{\"code\":\"en_US\",\"text\":\"币种\"}],\"filters\":null,\"fields\":[{\"code\":\"F001\",\"created_at\":\"2022-01-18 23:37:38\",\"created_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"field\":\"value\",\"hide\":false,\"min_width\":120,\"name\":\"value\",\"parent\":\"296154bf-b718-4e8f-8b70-efb969b831ec\",\"updated_at\":\"2022-01-18 23:37:38\",\"updated_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"updated_tick\":1,\"uuid\":\"f2140b7a-044c-41c3-b70e-852e6160b21b\"},{\"code\":\"F002\",\"created_at\":\"2022-01-18 23:37:38\",\"created_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"field\":\"label\",\"hide\":false,\"min_width\":120,\"name\":\"label\",\"parent\":\"296154bf-b718-4e8f-8b70-efb969b831ec\",\"updated_at\":\"2022-01-18 23:37:38\",\"updated_by\":\"3ed72aba-1622-4262-a61e-83581e020763\",\"updated_tick\":1,\"uuid\":\"2d3bba5d-308b-4dba-bcac-f093e6556eca\"}],\"limit\":0}\n`\n\t\tt.Assert(c.PostContent(ctx, \"/boot/test\", dataReq), `{\"code\":51,\"message\":\"The code is required\",\"data\":null}`)\n\t})\n}\n\ntype DemoReq struct {\n\tg.Meta `path:\"/demo\" method:\"post\"`\n\tData   *gjson.Json\n}\n\ntype DemoRes struct {\n\tContent string\n}\n\ntype Api struct{}\n\nfunc (a *Api) Demo(ctx context.Context, req *DemoReq) (res *DemoRes, err error) {\n\treturn &DemoRes{\n\t\tContent: req.Data.MustToJsonString(),\n\t}, err\n}\n\nvar api = Api{}\n\n// https://github.com/gogf/gf/issues/2172\nfunc Test_Issue2172(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(api)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tdataReq := `{\"data\":{\"asd\":1}}`\n\t\tt.Assert(c.PostContent(ctx, \"/demo\", dataReq), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Content\":\"{\\\"asd\\\":1}\"}}`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2334\nfunc Test_Issue2334(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.SetServerRoot(gtest.DataPath(\"static1\"))\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/index.html\"), \"index\")\n\n\t\tc.SetHeader(\"If-Modified-Since\", \"Mon, 12 Dec 2040 05:53:35 GMT\")\n\t\tres, _ := c.Get(ctx, \"/index.html\")\n\t\tt.Assert(res.StatusCode, 304)\n\t})\n}\n\ntype CreateOrderReq struct {\n\tg.Meta  `path:\"/order\" tags:\"订单\" method:\"put\" summary:\"创建订单\"`\n\tDetails []*OrderDetail `p:\"detail\" v:\"required#请输入订单详情\" dc:\"订单详情\"`\n}\n\ntype OrderDetail struct {\n\tName   string  `p:\"name\" v:\"required#请输入物料名称\" dc:\"物料名称\"`\n\tSn     string  `p:\"sn\" v:\"required#请输入客户编号\" dc:\"客户编号\"`\n\tImages string  `p:\"images\" dc:\"图片\"`\n\tDesc   string  `p:\"desc\" dc:\"备注\"`\n\tNumber int     `p:\"number\" v:\"required#请输入数量\" dc:\"数量\"`\n\tPrice  float64 `p:\"price\" v:\"required\" dc:\"单价\"`\n}\n\ntype CreateOrderRes struct{}\ntype OrderController struct{}\n\nfunc (c *OrderController) CreateOrder(ctx context.Context, req *CreateOrderReq) (res *CreateOrderRes, err error) {\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/2482\nfunc Test_Issue2482(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/api/v2\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(OrderController{})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(1000 * time.Millisecond)\n\n\tc := g.Client()\n\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `\n{\n    \"detail\": [\n      {\n        \"images\": \"string\",\n        \"desc\": \"string\",\n        \"number\": 0,\n        \"price\": 0\n      }\n    ]\n  }\n`\n\t\tt.Assert(c.PutContent(ctx, \"/api/v2/order\", content), `{\"code\":51,\"message\":\"请输入物料名称\",\"data\":null}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `\n{\n    \"detail\": [\n      {\n        \"images\": \"string\",\n        \"desc\": \"string\",\n        \"number\": 0,\n\t\t\"name\": \"string\",\n        \"price\": 0\n      }\n    ]\n  }\n`\n\t\tt.Assert(c.PutContent(ctx, \"/api/v2/order\", content), `{\"code\":51,\"message\":\"请输入客户编号\",\"data\":null}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `\n{\n    \"detail\": [\n      {\n        \"images\": \"string\",\n        \"desc\": \"string\",\n        \"number\": 0,\n\t\t\"name\": \"string\",\n\t\t\"sn\": \"string\",\n        \"price\": 0\n      }\n    ]\n  }\n`\n\t\tt.Assert(c.PutContent(ctx, \"/api/v2/order\", content), `{\"code\":0,\"message\":\"OK\",\"data\":null}`)\n\t})\n}\n\ntype Issue2890Enum string\n\nconst (\n\tIssue2890EnumA Issue2890Enum = \"a\"\n\tIssue2890EnumB Issue2890Enum = \"b\"\n)\n\ntype Issue2890Req struct {\n\tg.Meta `path:\"/issue2890\" method:\"post\"`\n\tId     int\n\tEnums  Issue2890Enum `v:\"required|enums\"`\n}\n\ntype Issue2890Res struct{}\ntype Issue2890Controller struct{}\n\nfunc (c *Issue2890Controller) Post(ctx context.Context, req *Issue2890Req) (res *Issue2890Res, err error) {\n\tg.RequestFromCtx(ctx).Response.Write(req.Enums)\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/2890\nfunc Test_Issue2890(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldEnumsJson, err := gtag.GetGlobalEnums()\n\t\tt.AssertNil(err)\n\t\tdefer t.AssertNil(gtag.SetGlobalEnums(oldEnumsJson))\n\n\t\terr = gtag.SetGlobalEnums(`{\"github.com/gogf/gf/v2/net/ghttp_test.Issue2890Enum\": [\"a\",\"b\"]}`)\n\t\tt.AssertNil(err)\n\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/api/v2\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\t\tgroup.Bind(Issue2890Controller{})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(1000 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(\n\t\t\tc.PostContent(ctx, \"/api/v2/issue2890\", ``),\n\t\t\t`{\"code\":51,\"message\":\"The Enums field is required\",\"data\":null}`,\n\t\t)\n\t\tt.Assert(\n\t\t\tc.PostContent(ctx, \"/api/v2/issue2890\", `{\"Enums\":\"c\"}`),\n\t\t\t\"{\\\"code\\\":51,\\\"message\\\":\\\"The Enums value `c` should be in enums of: [\\\\\\\"a\\\\\\\",\\\\\\\"b\\\\\\\"]\\\",\\\"data\\\":null}\",\n\t\t)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2963\nfunc Test_Issue2963(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.SetServerRoot(gtest.DataPath(\"issue2963\"))\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/1.txt\"), `1`)\n\t\tt.Assert(c.GetContent(ctx, \"/中文G146(1)-icon.txt\"), `中文G146(1)-icon`)\n\t\tt.Assert(c.GetContent(ctx, \"/\"+gurl.Encode(\"中文G146(1)-icon.txt\")), `中文G146(1)-icon`)\n\t})\n}\n\ntype Issue3077Req struct {\n\tg.Meta `path:\"/echo\" method:\"get\"`\n\tA      string `default:\"a\"`\n\tB      string `default:\"\"`\n}\ntype Issue3077Res struct {\n\tg.Meta `mime:\"text/html\"`\n}\n\ntype Issue3077V1 struct{}\n\nfunc (c *Issue3077V1) Hello(ctx context.Context, req *Issue3077Req) (res *Issue3077Res, err error) {\n\tg.RequestFromCtx(ctx).Response.Write(fmt.Sprintf(\"%v\", req))\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3077\nfunc Test_Issue3077(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(Issue3077V1{})\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/echo?a=1&b=2\"), `&{{} 1 2}`)\n\t\tt.Assert(c.GetContent(ctx, \"/echo?\"), `&{{} a }`)\n\t})\n}\n\ntype ListMessageReq struct {\n\tg.Meta    `path:\"/list\" method:\"get\"`\n\tStartTime int64\n\tEndTime   int64\n}\ntype ListMessageRes struct {\n\tg.Meta\n\tTitle   string\n\tContent string\n}\ntype BaseRes[T any] struct {\n\tg.Meta\n\tCode int\n\tData T\n\tMsg  string\n}\ntype cMessage struct{}\n\nfunc (c *cMessage) List(ctx context.Context, req *ListMessageReq) (res *BaseRes[*ListMessageRes], err error) {\n\tres = &BaseRes[*ListMessageRes]{\n\t\tCode: 100,\n\t\tData: &ListMessageRes{\n\t\t\tTitle:   \"title\",\n\t\t\tContent: \"hello\",\n\t\t},\n\t}\n\treturn res, err\n}\n\n// https://github.com/gogf/gf/issues/2457\nfunc Test_Issue2457(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(cMessage),\n\t\t\t)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/list\"), `{\"code\":0,\"message\":\"OK\",\"data\":{\"Code\":100,\"Data\":{\"Title\":\"title\",\"Content\":\"hello\"},\"Msg\":\"\"}}`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3245\ntype Issue3245Req struct {\n\tg.Meta      `path:\"/hello\" method:\"get\"`\n\tName        string `p:\"nickname\" json:\"name\"`\n\tXHeaderName string `p:\"Header-Name\" in:\"header\" json:\"X-Header-Name\"`\n\tXHeaderAge  uint8  `p:\"Header-Age\" in:\"cookie\" json:\"X-Header-Age\"`\n}\ntype Issue3245Res struct {\n\tReply any\n}\n\ntype Issue3245V1 struct{}\n\nfunc (Issue3245V1) Hello(ctx context.Context, req *Issue3245Req) (res *Issue3245Res, err error) {\n\tres = &Issue3245Res{\n\t\tReply: req,\n\t}\n\treturn\n}\n\nfunc Test_Issue3245(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3245V1),\n\t\t\t)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tc.SetHeader(\"Header-Name\", \"oldme\")\n\t\tc.SetCookie(\"Header-Age\", \"25\")\n\n\t\texpect := `{\"code\":0,\"message\":\"OK\",\"data\":{\"Reply\":{\"name\":\"oldme\",\"X-Header-Name\":\"oldme\",\"X-Header-Age\":25}}}`\n\t\tt.Assert(c.GetContent(ctx, \"/hello?nickname=oldme\"), expect)\n\t})\n}\n\ntype ItemSecondThird struct {\n\tSecondID uint64 `json:\"secondId,string\"`\n\tThirdID  uint64 `json:\"thirdId,string\"`\n}\ntype ItemFirst struct {\n\tID uint64 `json:\"id,string\"`\n\tItemSecondThird\n}\ntype ItemInput struct {\n\tItemFirst\n}\ntype Issue3789Req struct {\n\tg.Meta `path:\"/hello\" method:\"GET\"`\n\tItemInput\n}\ntype Issue3789Res struct {\n\tItemInput\n}\n\ntype Issue3789 struct{}\n\nfunc (Issue3789) Say(ctx context.Context, req *Issue3789Req) (res *Issue3789Res, err error) {\n\tres = &Issue3789Res{\n\t\tItemInput: req.ItemInput,\n\t}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3789\nfunc Test_Issue3789(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server()\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3789),\n\t\t\t)\n\t\t})\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\texpect := `{\"code\":0,\"message\":\"OK\",\"data\":{\"id\":\"0\",\"secondId\":\"2\",\"thirdId\":\"3\"}}`\n\t\tt.Assert(c.GetContent(ctx, \"/hello?id=&secondId=2&thirdId=3\"), expect)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4108\nfunc Test_Issue4108(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.GET(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Writer.Write([]byte(\"hello\"))\n\t\t})\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\trsp, err := client.Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t\tt.Assert(rsp.ReadAllString(), \"hello\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4115\nfunc Test_Issue4115(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(func(r *ghttp.Request) {\n\t\tr.Response.Writer.Write([]byte(\"hello\"))\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\trsp, err := client.Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(rsp.StatusCode, http.StatusOK)\n\t\tt.Assert(rsp.ReadAllString(), \"hello\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4047\nfunc Test_Issue4047(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\terr := s.SetConfigWithMap(g.Map{\n\t\t\t\"logger\": nil,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Logger(), nil)\n\t})\n}\n\n// Issue4093Req\ntype Issue4093Req struct {\n\tg.Meta     `path:\"/test\" method:\"post\"`\n\tPage       int    `json:\"page\" example:\"10\" d:\"1\" v:\"min:1#页码最小值不能低于1\"  dc:\"当前页码\"`\n\tPerPage    int    `json:\"pageSize\" example:\"1\" d:\"10\" v:\"min:1|max:200#每页数量最小值不能低于1|最大值不能大于200\" dc:\"每页数量\"`\n\tPagination bool   `json:\"pagination\" d:\"true\" dc:\"是否需要进行分页\"`\n\tName       string `json:\"name\" d:\"john\"`\n\tNumber     int    `json:\"number\" d:\"1\"`\n}\n\ntype Issue4093Res struct {\n\tg.Meta `mime:\"text/html\" example:\"string\"`\n}\n\nvar (\n\tIssue4093 = cIssue4093{}\n)\n\ntype cIssue4093 struct{}\n\nfunc (c *cIssue4093) User(ctx context.Context, req *Issue4093Req) (res *Issue4093Res, err error) {\n\tg.RequestFromCtx(ctx).Response.WriteJson(req)\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/4093\nfunc Test_Issue4093(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(Issue4093)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client().ContentJson()\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.PostContent(ctx, \"/test\", `{\"pagination\":false,\"name\":\"\",\"number\":0}`), `{\"page\":1,\"pageSize\":10,\"pagination\":false,\"name\":\"\",\"number\":0}`)\n\t\tt.Assert(client.PostContent(ctx, \"/test\"), `{\"page\":1,\"pageSize\":10,\"pagination\":true,\"name\":\"john\",\"number\":1}`)\n\t})\n}\n\n// Issue4227Req\ntype Issue4227Req struct {\n\tg.Meta      `path:\"/hello/:path_param\" method:\"post\"`\n\tHeaderParam string `json:\"Authorization\" in:\"header\" default:\"Bearer token123\"`\n\tQueryParam  bool   `json:\"query_param\" in:\"query\" default:\"false\"`\n\tPathParam   int    `json:\"path_param\" in:\"path\" default:\"123\" v:\"required\"`\n\tCookieParam bool   `json:\"cookie_param\" in:\"cookie\" default:\"false\"`\n\tBodyParam   bool   `json:\"body_param\" default:\"false\"`\n}\n\ntype Issue4227Res struct {\n\tg.Meta `mime:\"application/json\"`\n}\n\nvar (\n\tIssue4227 = cIssue4227{}\n)\n\ntype cIssue4227 struct{}\n\nfunc (c *cIssue4227) Feature(ctx context.Context, req *Issue4227Req) (res *Issue4227Res, err error) {\n\tg.RequestFromCtx(ctx).Response.WriteJson(req)\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/4227\nfunc Test_Issue4227(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareHandlerResponse)\n\t\tgroup.Bind(Issue4227)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client().ContentJson()\n\t\tclient.SetPrefix(prefix)\n\n\t\tresp1 := client.PostContent(ctx, \"/hello/123\", `{}`)\n\t\tt.Assert(resp1, `{\"Authorization\":\"Bearer token123\",\"query_param\":false,\"path_param\":123,\"cookie_param\":false,\"body_param\":false}`)\n\n\t\tclient.SetHeader(\"Authorization\", \"Bearer token123\")\n\n\t\tresp2 := client.PostContent(ctx, \"/hello/123\", `{\"body_param\":\"true\"}`)\n\t\tt.Assert(resp2, `{\"Authorization\":\"Bearer token123\",\"query_param\":false,\"path_param\":123,\"cookie_param\":false,\"body_param\":true}`)\n\n\t\tclient.SetCookie(\"cookie_param\", \"true\")\n\t\tresp3 := client.PostContent(ctx, \"/hello/123\", `{}`)\n\t\tt.Assert(resp3, `{\"Authorization\":\"Bearer token123\",\"query_param\":false,\"path_param\":123,\"cookie_param\":true,\"body_param\":false}`)\n\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_middleware_gzip_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Middleware_Gzip(t *testing.T) {\n\ts := g.Server(guid.S())\n\t// Routes with GZIP enabled\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Middleware(ghttp.MiddlewareGzip)\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(strings.Repeat(\"Hello World! \", 1000))\n\t\t})\n\t\tgroup.ALL(\"/small\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(\"Small response\")\n\t\t})\n\t})\n\n\t// Routes without GZIP\n\ts.Group(\"/no-gzip\", func(group *ghttp.RouterGroup) {\n\t\tgroup.ALL(\"/\", func(r *ghttp.Request) {\n\t\t\tr.Response.Write(strings.Repeat(\"Hello World! \", 1000))\n\t\t})\n\t})\n\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\t// Test 1: Route with GZIP, client supports GZIP\n\t\tresp, err := client.Header(map[string]string{\n\t\t\t\"Accept-Encoding\": \"gzip\",\n\t\t}).Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.Header.Get(\"Content-Encoding\"), \"gzip\")\n\n\t\treader, err := gzip.NewReader(resp.Body)\n\t\tt.AssertNil(err)\n\t\tdefer reader.Close()\n\n\t\tcontent, err := io.ReadAll(reader)\n\t\tt.AssertNil(err)\n\t\texpected := strings.Repeat(\"Hello World! \", 1000)\n\t\tt.Assert(len(content), len(expected))\n\t\tt.Assert(string(content), expected)\n\n\t\t// Test 2: Route with GZIP, client doesn't support GZIP\n\t\tresp, err = client.Header(map[string]string{}).Get(ctx, \"/\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.Header.Get(\"Content-Encoding\"), \"\")\n\t\tcontent, err = io.ReadAll(resp.Body)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(content), len(expected))\n\t\tt.Assert(string(content), expected)\n\n\t\t// Test 3: Route with GZIP, response too small\n\t\tresp, err = client.Header(map[string]string{\n\t\t\t\"Accept-Encoding\": \"gzip\",\n\t\t}).Get(ctx, \"/small\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.Header.Get(\"Content-Encoding\"), \"\")\n\t\tcontent, err = io.ReadAll(resp.Body)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(content), \"Small response\")\n\n\t\t// Test 4: Route without GZIP\n\t\tresp, err = client.Header(map[string]string{\n\t\t\t\"Accept-Encoding\": \"gzip\",\n\t\t}).Get(ctx, \"/no-gzip/\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(resp.Header.Get(\"Content-Encoding\"), \"\")\n\t\tcontent, err = io.ReadAll(resp.Body)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(content), expected)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/ghttp_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage ghttp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/httputil\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc init() {\n\tgenv.Set(\"UNDER_TEST\", \"1\")\n}\n\nfunc Test_GetUrl(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/url\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.GetUrl())\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort())\n\t\tclient := g.Client()\n\t\tclient.SetBrowserMode(true)\n\t\tclient.SetPrefix(prefix)\n\n\t\tt.Assert(client.GetContent(ctx, \"/url\"), prefix+\"/url\")\n\t})\n}\n\nfunc Test_XUrlPath(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/test1\", func(r *ghttp.Request) {\n\t\tr.Response.Write(`test1`)\n\t})\n\ts.BindHandler(\"/test2\", func(r *ghttp.Request) {\n\t\tr.Response.Write(`test2`)\n\t})\n\ts.SetHandler(func(w http.ResponseWriter, r *http.Request) {\n\t\tr.Header.Set(ghttp.HeaderXUrlPath, \"/test2\")\n\t\ts.ServeHTTP(w, r)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"test2\")\n\t\tt.Assert(c.GetContent(ctx, \"/test/test\"), \"test2\")\n\t\tt.Assert(c.GetContent(ctx, \"/test1\"), \"test2\")\n\t})\n}\n\nfunc Test_GetListenedAddress(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(`test`)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"test\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(fmt.Sprintf(`:%d`, s.GetListenedPort()), s.GetListenedAddress())\n\t})\n}\n\nfunc Test_GetListenedAddressWithHost(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(`test`)\n\t})\n\ts.SetAddr(\"127.0.0.1:0\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(ctx, \"/\"), \"test\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(fmt.Sprintf(`127.0.0.1:%d`, s.GetListenedPort()), s.GetListenedAddress())\n\t})\n}\n\nfunc Test_RoutePathParams(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/:param\", func(r *ghttp.Request) {\n\t\tr.Response.Write(r.Get(\"param\"), \",\", r.Get(\"c\"))\n\t})\n\ts.SetAddr(\"127.0.0.1:0\")\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tparam := \"net/http/get\"\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(c.GetContent(\n\t\t\tctx,\n\t\t\t\"/\"+gurl.Encode(param)+\"?a=1&b=2&c=\"+gurl.Encode(param)),\n\t\t\t\"net/http/get,net/http/get\",\n\t\t)\n\t})\n}\n\nfunc Test_BuildParams(t *testing.T) {\n\t// normal && special cases\n\tparams := map[string]string{\n\t\t\"val\":   \"12345678\",\n\t\t\"code1\": \"x&a=1\", // for fix\n\t\t\"code2\": \"x&a=111\",\n\t\t\"id\":    \"1+- \", // for fix\n\t\t\"f\":     \"1#a=+- \",\n\t\t\"v\":     \"\",\n\t\t\"n\":     \"null\",\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tres1 := httputil.BuildParams(params)\n\t\tvs, _ := url.ParseQuery(res1)\n\t\tt.Assert(len(params), len(vs))\n\t\tfor k := range vs {\n\t\t\tvv := vs.Get(k)\n\t\t\t_, ok := params[k]\n\t\t\t// check no additional param\n\t\t\tt.Assert(ok, true)\n\t\t\t// check equal\n\t\t\tt.AssertEQ(params[k], vv)\n\t\t}\n\t})\n}\n\nfunc Test_ServerSignal(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Log(\"skip windows\")\n\t\treturn\n\t}\n\ts := g.Server(guid.S())\n\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\tr.Response.Write(\"hello world\")\n\t})\n\tgtest.Assert(s.Start(), nil)\n\tg.Wait()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(s.Shutdown(), nil)\n\t})\n}\n"
  },
  {
    "path": "net/ghttp/internal/graceful/graceful.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package graceful implements graceful reload/restart features for HTTP servers.\n// It provides the ability to gracefully shutdown or restart HTTP servers without\n// interrupting existing connections. This is particularly useful for zero-downtime\n// deployments and maintenance operations.\n//\n// The package wraps the standard net/http.Server and provides additional functionality\n// for graceful server management, including:\n// - Graceful server shutdown with timeout\n// - Support for both HTTP and HTTPS servers\n// - File descriptor inheritance for server reload/restart\n// - Connection management during shutdown\npackage graceful\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// ServerStatus is the server status enum type.\ntype ServerStatus = int\n\nconst (\n\t// FreePortAddress marks the server listens using random free port.\n\tFreePortAddress = \":0\"\n\t// ServerStatusStopped indicates the server is stopped.\n\tServerStatusStopped ServerStatus = 0\n\t// ServerStatusRunning indicates the server is running.\n\tServerStatusRunning ServerStatus = 1\n)\n\n// Server wraps the net/http.Server with graceful reload/restart feature.\ntype Server struct {\n\tfd          uintptr      // File descriptor for passing to the child process when graceful reload.\n\taddress     string       // Listening address like \":80\", \":8080\".\n\thttpServer  *http.Server // Underlying http.Server.\n\trawListener net.Listener // Underlying net.Listener.\n\trawLnMu     sync.RWMutex // Concurrent safety mutex for rawListener.\n\tlistener    net.Listener // Wrapped net.Listener with TLS support if necessary.\n\tisHttps     bool         // Whether server is running in HTTPS mode.\n\tstatus      *gtype.Int   // Server status using gtype for concurrent safety.\n\tconfig      ServerConfig // Server configuration.\n}\n\n// ServerConfig is the graceful Server configuration manager.\ntype ServerConfig struct {\n\t// Listeners specifies the custom listeners.\n\tListeners []net.Listener `json:\"listeners\"`\n\n\t// Handler the handler for HTTP request.\n\tHandler func(w http.ResponseWriter, r *http.Request) `json:\"-\"`\n\n\t// ReadTimeout is the maximum duration for reading the entire\n\t// request, including the body.\n\t//\n\t// Because ReadTimeout does not let Handlers make per-request\n\t// decisions on each request body's acceptable deadline or\n\t// upload rate, most users will prefer to use\n\t// ReadHeaderTimeout. It is valid to use them both.\n\tReadTimeout time.Duration `json:\"readTimeout\"`\n\n\t// WriteTimeout is the maximum duration before timing out\n\t// writes of the response. It is reset whenever a new\n\t// request's header is read. Like ReadTimeout, it does not\n\t// let Handlers make decisions on a per-request basis.\n\tWriteTimeout time.Duration `json:\"writeTimeout\"`\n\n\t// IdleTimeout is the maximum amount of time to wait for the\n\t// next request when keep-alive are enabled. If IdleTimeout\n\t// is zero, the value of ReadTimeout is used. If both are\n\t// zero, there is no timeout.\n\tIdleTimeout time.Duration `json:\"idleTimeout\"`\n\n\t// GracefulShutdownTimeout set the maximum survival time (seconds) before stopping the server.\n\tGracefulShutdownTimeout int `json:\"gracefulShutdownTimeout\"`\n\n\t// MaxHeaderBytes controls the maximum number of bytes the\n\t// server will read parsing the request header's keys and\n\t// values, including the request line. It does not limit the\n\t// size of the request body.\n\t//\n\t// It can be configured in configuration file using string like: 1m, 10m, 500kb etc.\n\t// It's 10240 bytes in default.\n\tMaxHeaderBytes int `json:\"maxHeaderBytes\"`\n\n\t// KeepAlive enables HTTP keep-alive.\n\tKeepAlive bool `json:\"keepAlive\"`\n\n\t// Logger specifies the logger for server.\n\tLogger *glog.Logger `json:\"logger\"`\n}\n\n// New creates and returns a graceful http server with a given address.\n// The optional parameter `fd` specifies the file descriptor which is passed from parent server.\nfunc New(\n\taddress string,\n\tfd int,\n\tloggerWriter io.Writer,\n\tconfig ServerConfig,\n) *Server {\n\t// Change port to address like: 80 -> :80\n\tif gstr.IsNumeric(address) {\n\t\taddress = \":\" + address\n\t}\n\tgs := &Server{\n\t\taddress:    address,\n\t\thttpServer: newHttpServer(address, loggerWriter, config),\n\t\tstatus:     gtype.NewInt(),\n\t\tconfig:     config,\n\t}\n\tif fd != 0 {\n\t\tgs.fd = uintptr(fd)\n\t}\n\tif len(config.Listeners) > 0 {\n\t\taddrArray := gstr.SplitAndTrim(address, \":\")\n\t\taddrPort, err := strconv.Atoi(addrArray[len(addrArray)-1])\n\t\tif err == nil {\n\t\t\tfor _, v := range config.Listeners {\n\t\t\t\tif listenerPort := (v.Addr().(*net.TCPAddr)).Port; listenerPort == addrPort {\n\t\t\t\t\tgs.rawListener = v\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn gs\n}\n\n// newHttpServer creates and returns an underlying http.Server with a given address.\nfunc newHttpServer(\n\taddress string,\n\tloggerWriter io.Writer,\n\tconfig ServerConfig,\n) *http.Server {\n\tserver := &http.Server{\n\t\tAddr:           address,\n\t\tHandler:        http.HandlerFunc(config.Handler),\n\t\tReadTimeout:    config.ReadTimeout,\n\t\tWriteTimeout:   config.WriteTimeout,\n\t\tIdleTimeout:    config.IdleTimeout,\n\t\tMaxHeaderBytes: config.MaxHeaderBytes,\n\t\tErrorLog:       log.New(loggerWriter, \"\", 0),\n\t}\n\tserver.SetKeepAlivesEnabled(config.KeepAlive)\n\treturn server\n}\n\n// Fd retrieves and returns the file descriptor of the current server.\n// It is available ony in *nix like operating systems like linux, unix, darwin.\nfunc (s *Server) Fd() uintptr {\n\tif ln := s.getRawListener(); ln != nil {\n\t\tfile, err := ln.(*net.TCPListener).File()\n\t\tif err == nil {\n\t\t\treturn file.Fd()\n\t\t}\n\t}\n\treturn 0\n}\n\n// CreateListener creates listener on configured address.\nfunc (s *Server) CreateListener() error {\n\tln, err := s.getNetListener()\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.listener = ln\n\ts.setRawListener(ln)\n\treturn nil\n}\n\n// IsHttps returns whether the server is running in HTTPS mode.\nfunc (s *Server) IsHttps() bool {\n\treturn s.isHttps\n}\n\n// GetAddress returns the server's configured address.\nfunc (s *Server) GetAddress() string {\n\treturn s.address\n}\n\n// SetIsHttps sets the HTTPS mode for the server.\n// The parameter isHttps determines whether to enable HTTPS mode.\nfunc (s *Server) SetIsHttps(isHttps bool) {\n\ts.isHttps = isHttps\n}\n\n// CreateListenerTLS creates listener on configured address with HTTPS.\n// The parameter `certFile` and `keyFile` specify the necessary certification and key files for HTTPS.\n// The optional parameter `tlsConfig` specifies the custom TLS configuration.\nfunc (s *Server) CreateListenerTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {\n\tvar config *tls.Config\n\tif len(tlsConfig) > 0 && tlsConfig[0] != nil {\n\t\tconfig = tlsConfig[0]\n\t} else if s.httpServer.TLSConfig != nil {\n\t\tconfig = s.httpServer.TLSConfig\n\t} else {\n\t\tconfig = &tls.Config{}\n\t}\n\tif config.NextProtos == nil {\n\t\tconfig.NextProtos = []string{\"http/1.1\"}\n\t}\n\tvar err error\n\tif len(config.Certificates) == 0 {\n\t\tconfig.Certificates = make([]tls.Certificate, 1)\n\t\tif gres.Contains(certFile) {\n\t\t\tconfig.Certificates[0], err = tls.X509KeyPair(\n\t\t\t\tgres.GetContent(certFile),\n\t\t\t\tgres.GetContent(keyFile),\n\t\t\t)\n\t\t} else {\n\t\t\tconfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `open certFile \"%s\" and keyFile \"%s\" failed`, certFile, keyFile)\n\t}\n\tln, err := s.getNetListener()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.listener = tls.NewListener(ln, config)\n\ts.setRawListener(ln)\n\treturn nil\n}\n\n// Serve starts the serving with blocking way.\nfunc (s *Server) Serve(ctx context.Context) error {\n\tif s.rawListener == nil {\n\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, `call CreateListener/CreateListenerTLS before Serve`)\n\t}\n\n\tvar action = \"started\"\n\tif s.fd != 0 {\n\t\taction = \"reloaded\"\n\t}\n\ts.config.Logger.Infof(\n\t\tctx,\n\t\t`pid[%d]: %s server %s listening on [%s]`,\n\t\tgproc.Pid(), s.getProto(), action, s.GetListenedAddress(),\n\t)\n\ts.status.Set(ServerStatusRunning)\n\terr := s.httpServer.Serve(s.listener)\n\ts.status.Set(ServerStatusStopped)\n\treturn err\n}\n\n// GetListenedAddress retrieves and returns the address string which are listened by current server.\nfunc (s *Server) GetListenedAddress() string {\n\tif !gstr.Contains(s.address, FreePortAddress) {\n\t\treturn s.address\n\t}\n\tvar (\n\t\taddress      = s.address\n\t\tlistenedPort = s.GetListenedPort()\n\t)\n\taddress = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort))\n\treturn address\n}\n\n// GetListenedPort retrieves and returns one port which is listened to by current server.\n// Note that this method is only available if the server is listening on one port.\nfunc (s *Server) GetListenedPort() int {\n\tif ln := s.getRawListener(); ln != nil {\n\t\treturn ln.Addr().(*net.TCPAddr).Port\n\t}\n\treturn -1\n}\n\n// Status returns the current status of the server.\n// It returns either ServerStatusStopped or ServerStatusRunning.\nfunc (s *Server) Status() ServerStatus {\n\treturn s.status.Val()\n}\n\n// getProto retrieves and returns the proto string of current server.\nfunc (s *Server) getProto() string {\n\tproto := \"http\"\n\tif s.isHttps {\n\t\tproto = \"https\"\n\t}\n\treturn proto\n}\n\n// getNetListener retrieves and returns the wrapped net.Listener.\nfunc (s *Server) getNetListener() (net.Listener, error) {\n\tif s.rawListener != nil {\n\t\treturn s.rawListener, nil\n\t}\n\tvar (\n\t\tln  net.Listener\n\t\terr error\n\t)\n\tif s.fd > 0 {\n\t\tf := os.NewFile(s.fd, \"\")\n\t\tln, err = net.FileListener(f)\n\t\tif err != nil {\n\t\t\terr = gerror.Wrap(err, \"net.FileListener failed\")\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tln, err = net.Listen(\"tcp\", s.httpServer.Addr)\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `net.Listen address \"%s\" failed`, s.httpServer.Addr)\n\t\t}\n\t}\n\treturn ln, err\n}\n\n// Shutdown shuts down the server gracefully.\nfunc (s *Server) Shutdown(ctx context.Context) {\n\tif s.status.Val() == ServerStatusStopped {\n\t\treturn\n\t}\n\ttimeoutCtx, cancelFunc := context.WithTimeout(\n\t\tctx,\n\t\ttime.Duration(s.config.GracefulShutdownTimeout)*time.Second,\n\t)\n\tdefer cancelFunc()\n\tif err := s.httpServer.Shutdown(timeoutCtx); err != nil {\n\t\ts.config.Logger.Errorf(\n\t\t\tctx,\n\t\t\t\"%d: %s server [%s] shutdown error: %v\",\n\t\t\tgproc.Pid(), s.getProto(), s.address, err,\n\t\t)\n\t}\n}\n\n// setRawListener sets `rawListener` with given net.Listener.\nfunc (s *Server) setRawListener(ln net.Listener) {\n\ts.rawLnMu.Lock()\n\tdefer s.rawLnMu.Unlock()\n\ts.rawListener = ln\n}\n\n// getRawListener returns the `rawListener` of current server.\nfunc (s *Server) getRawListener() net.Listener {\n\ts.rawLnMu.RLock()\n\tdefer s.rawLnMu.RUnlock()\n\treturn s.rawListener\n}\n\n// Close shuts down the server forcibly.\n// for graceful shutdown, please use Server.shutdown.\nfunc (s *Server) Close(ctx context.Context) {\n\tif s.status.Val() == ServerStatusStopped {\n\t\treturn\n\t}\n\tif err := s.httpServer.Close(); err != nil {\n\t\ts.config.Logger.Errorf(\n\t\t\tctx,\n\t\t\t\"%d: %s server [%s] closed error: %v\",\n\t\t\tgproc.Pid(), s.getProto(), s.address, err,\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/internal/response/response.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package response provides wrapper for http.response.\npackage response\n"
  },
  {
    "path": "net/ghttp/internal/response/response_buffer_writer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage response\n\nimport (\n\t\"bytes\"\n\t\"net/http\"\n)\n\n// BufferWriter is the custom writer for http response with buffer.\ntype BufferWriter struct {\n\t*Writer               // The underlying BufferWriter.\n\tStatus  int           // HTTP status.\n\tbuffer  *bytes.Buffer // The output buffer.\n}\n\nfunc NewBufferWriter(writer http.ResponseWriter) *BufferWriter {\n\treturn &BufferWriter{\n\t\tWriter: NewWriter(writer),\n\t\tbuffer: bytes.NewBuffer(nil),\n\t}\n}\n\n// RawWriter returns the underlying BufferWriter.\nfunc (w *BufferWriter) RawWriter() http.ResponseWriter {\n\treturn w.Writer\n}\n\n// Write implements the interface function of http.BufferWriter.Write.\nfunc (w *BufferWriter) Write(data []byte) (int, error) {\n\treturn w.buffer.Write(data)\n}\n\n// WriteString writes string content to internal buffer.\nfunc (w *BufferWriter) WriteString(data string) (int, error) {\n\treturn w.buffer.WriteString(data)\n}\n\n// Buffer returns the buffered content as []byte.\nfunc (w *BufferWriter) Buffer() []byte {\n\treturn w.buffer.Bytes()\n}\n\n// BufferString returns the buffered content as string.\nfunc (w *BufferWriter) BufferString() string {\n\treturn w.buffer.String()\n}\n\n// BufferLength returns the length of the buffered content.\nfunc (w *BufferWriter) BufferLength() int {\n\treturn w.buffer.Len()\n}\n\n// SetBuffer overwrites the buffer with `data`.\nfunc (w *BufferWriter) SetBuffer(data []byte) {\n\tw.buffer.Reset()\n\tw.buffer.Write(data)\n}\n\n// ClearBuffer clears the response buffer.\nfunc (w *BufferWriter) ClearBuffer() {\n\tw.buffer.Reset()\n}\n\n// WriteHeader implements the interface of http.BufferWriter.WriteHeader.\nfunc (w *BufferWriter) WriteHeader(status int) {\n\tw.Status = status\n}\n\n// Flush outputs the buffer to clients and clears the buffer.\nfunc (w *BufferWriter) Flush() {\n\tif w.IsHijacked() {\n\t\treturn\n\t}\n\n\tif w.Status != 0 && !w.IsHeaderWrote() {\n\t\tw.Writer.WriteHeader(w.Status)\n\t}\n\t// Default status text output.\n\tif w.Status != http.StatusOK && w.buffer.Len() == 0 && w.BytesWritten() == 0 {\n\t\tw.buffer.WriteString(http.StatusText(w.Status))\n\t}\n\tif w.buffer.Len() > 0 {\n\t\t_, _ = w.Writer.Write(w.buffer.Bytes())\n\t\tw.buffer.Reset()\n\t\tif flusher, ok := w.RawWriter().(http.Flusher); ok {\n\t\t\tflusher.Flush()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/internal/response/response_writer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage response\n\nimport (\n\t\"bufio\"\n\t\"net\"\n\t\"net/http\"\n)\n\n// Writer wraps http.ResponseWriter for extra features.\ntype Writer struct {\n\thttp.ResponseWriter       // The underlying ResponseWriter.\n\thijacked            bool  // Mark this request is hijacked or not.\n\twroteHeader         bool  // Is header wrote or not, avoiding error: superfluous/multiple response.WriteHeader call.\n\tbytesWritten        int64 // Bytes written to response.\n}\n\n// NewWriter creates and returns a new Writer.\nfunc NewWriter(writer http.ResponseWriter) *Writer {\n\treturn &Writer{\n\t\tResponseWriter: writer,\n\t}\n}\n\n// WriteHeader implements the interface of http.ResponseWriter.WriteHeader.\n// Note that the underlying `WriteHeader` can only be called once in a http response.\nfunc (w *Writer) WriteHeader(status int) {\n\tif w.wroteHeader {\n\t\treturn\n\t}\n\tw.ResponseWriter.WriteHeader(status)\n\tw.wroteHeader = true\n}\n\n// BytesWritten returns the length that was written to response.\nfunc (w *Writer) BytesWritten() int64 {\n\treturn w.bytesWritten\n}\n\n// Write implements the interface function of http.ResponseWriter.Write.\nfunc (w *Writer) Write(data []byte) (int, error) {\n\tn, err := w.ResponseWriter.Write(data)\n\tw.bytesWritten += int64(n)\n\tw.wroteHeader = true\n\treturn n, err\n}\n\n// Hijack implements the interface function of http.Hijacker.Hijack.\nfunc (w *Writer) Hijack() (conn net.Conn, writer *bufio.ReadWriter, err error) {\n\tconn, writer, err = w.ResponseWriter.(http.Hijacker).Hijack()\n\tw.hijacked = true\n\treturn\n}\n\n// IsHeaderWrote returns if the header status is written.\nfunc (w *Writer) IsHeaderWrote() bool {\n\treturn w.wroteHeader\n}\n\n// IsHijacked returns if the connection is hijacked.\nfunc (w *Writer) IsHijacked() bool {\n\treturn w.hijacked\n}\n\n// Flush sends any buffered data to the client.\nfunc (w *Writer) Flush() {\n\tflusher, ok := w.ResponseWriter.(http.Flusher)\n\tif ok {\n\t\tflusher.Flush()\n\t\tw.wroteHeader = true\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/internal/swaggerui/swaggerui-redoc.go",
    "content": "package swaggerui\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc Init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/wAKQPW/UEsDBBQACAAIAOVyXFQAAAAAAAAAAAAAAAAmAAkAL2dvZnJhbWUvc3dhZ2dlcnVpL3JlZG9jLnN0YW5kYWxvbmUuanNVVAUAAc/aHGLs/euW2ziWKAj//Nb6XmH+UCwXk0hBDElxNWVY4/Sl292ZtseRWdV9FCobQUIhpilQRUKOiJJ41vw5DzH/5lnOo8yTzMKVIEUpZKeru/pM5lrpEHHHxsbGvmHj6PuO8yrLnTSJCC2Ik9BZli8wSzLqLFOCC+IUhDg5ibMoKBimMU4zSoJfi+DH189fvrl8GbA75nx/9P/vzFY04vV8AhlYu9n1ryRiLkLsfkmymUPullnOCs/byllk8SolY/knUOUQ83Py11WSE9+lqzR1AQhd3UVVNyazhBLPk38DvIjH8qc/kdWmkIFw12DG6m/wns+vrUtiskjA00Dps3lSQL+aLVjnhK1y6pgksP6Mc4eh9fHZ+WlowwVSsHZXHKgsTyLmjnjBHPEmPY//G3z4gG9xwki+2dQrwtx0RMmtTzcbn6J3ebZICgKAXw0ogwlY6y8H8wGy/H6d+nlAyR3zCQBlhFk05zmJT0BZmtKFXZrN8+x2b/GUp4m5jkgQZ5SMM58En3G6IiD0GVK/IXMSypEn4rCnYxZScutQvwZE4jNQAgACNifUx7AAZer7OcoDvFym9xwIm81kCoCcBeCFy9FbsbCBXPN3ebYkObv3GXQ/fCDFTwKjXLgWowg7/RJAFlyvaJySF1m0WhDKkE5ALHiLiz+RvEgyij5nSez0R1FGC+ZkiPrD4/45gAmi/sngYgggRtS/6J+dAlgg6p8OTwYApoj6xxcXAEa8wln/AsCVyBz2AVwi6j8+OTkGMEbUH5wO+gDOEPXPT84uAJzzcv3jPoAL3sjJBYA3PPN8AASO3I8M0K8tlMslNsrR6j8GrN/7YC1msI7VbEMGo4zOkpuQwmhVsGzx8/2SFGEOyR0jOcXpezJ7T4os/UzyMIMxycmM5IRGJJyhzqBEBC5QHMSEkYi9XRL67N1rnwVLnBck5mOOg0ym/oR/zXJ/AeA1osENYe9XKSleZXkFZP8GwM9oFVBOcdLkb0SMxacBHwuN5ZfPd10H5eM8vEEIxXyRRNOqkUD9PQbjBULo3nx/GIwjXvj4w0DOsRBf8nfKfw/Fb7gAkAJ4i+ZBQhM5TP8aUuguc7LMs4gURZYXLi/3abtQTKIsx0yXeInWyzy7TsmiCCdTmJnJhosSvkW4muyfkiLh1fxJEAS3cF2QzyRP2H3okjzPchfmq5S8jkNXomfuws+yRnjn38AZZKCEQRB8msLPAF6i+4SksZMEuVw8jd7+Os8y9qJafv7J5x1+Dl7wTZNwRHmfZawdA0owUqi2DG5x+qlqNz6kTTPbWE83fAvVEOP3ZPYTXoaXMGJ34csSwLWcasiggeHLQP8MFnjp+wQ9pQGO43cy9efs9Q3NcsKpFICzJCUvyJLQmNAoIUWYccR7lfDFAiWnF2YTfZanVHGbcMrGwDriR91u7ApVSSJLupfRnCywG0rguIX4LNyRyHyHc7wgjOQmf6lTdJH3pFhmtCCmRK4SdIGXd3ixTKt8Ir+r+n9dkYL9kMX3VhM6LTHl/png2BrHXHzqzEsSrTjKNSdjJ5uWfkzoJ1MkTegnnfEcp+k1jqrMSCUU7igmM7xKWagPrlWalvshPXwA0rFBsG8E7bYhWkfcnT62U8KcXB0ICVrnZBauU4I/Ez+H4shNZn4nCdIsEtzTZiOpMUIoCWgWE6A6EMmLICec8/iFWpvBT2Cm0mFmGgKjZOZX7QZFtsojghDSPz2vLTdrpnmeW0Q4xbnb4bmcEQooXhDP6zA1NjW7FH32rQKQgFE6ZmO/8FOYwAxA7OfiBwjz4FFOZkjnhDqnLGGdEoRrQhnJ+U4je8n4OEcsiLLFMqOEcjbQ+ths1mW4t/rQ8/wcMVCW5chmgeQS3gRJ8S7FCZVcg8/kwoz9mKSEEYeI2UDFU+CiSG4E8yWLgZDyc45QNqHBJ3I/RTLD5p44n5aAdT5hU8T/4SNWUMWoyQiK9EkC8RRNSHO5AnxdZOmKkfdkBq3cZZZwQE5hIToYcbRMkeuqXiKEg4Iz8/4QBMUyTZjvHrkgmCUpB/8PWZYSTMFoluX+KApSQm/Y/Gl/BJKZn6IoWGZLH3T9dPyx92idlh9D1wWwU2w2nWKSTjebzOd/IVEgUTidjkT1WZCT2Q+4IG/wgviJbOeD3c7eNuQMVigVk1qioRwlL+x5nXqtEUjRx0frVdl7tF6WH+Gy29UHleyEqp3krxekKPANCT/+fJs5ilA7OOdCjWJtYuc2YXOHzYlT4AVxONY71yvmxMlMFGFOlFFGKAuc94Tnxg7v22GZw2cXfIR6fUJqlgrOsjwil+ZYv8U5dUsA09KnkMHEnKx8HSd4iqiYGnxgf3z8w1G1I44erVl59GiNy4/hxz9YX6Vqe39jnucnwYukiPJkkVDOxfyEl8uE3iBF2oTUwVdBMcJONnPU9vhE7gufAoXGToLoJJtCjHLNgvhrvpvCpBQUrIPbSCM+lDRimGvSmFebIZonaexnAFiUSx8YnGyxMadMGOYg5KND+qssSwCTslOTPwwNQW6Gi6ELScVL9kXa8Yd+LXWgUgdu6d/X5IfNxq+JE+sSVKIHapEdD2XkOUQZjLMopK0MW464aJUEfBfqRJ8EkunXKwPgNS5ImCFx2CEi1od5XocCIfNxAdN5yblQ39UMn5Pl1YZxksJRonIcXFEXGBonR95BiI5pKHnSfIsnzSCDnb5AC2xLhqJLNQSsd8e1X6fH9a+KDcUlJACulXhjppwmtJ21zUspQm5LhNclPD4/P98vuLPgBRcZr1/URcWcy3GD/gBALjSenZz3pdD4uN9XQqNM40Lj+WCohEYu5gmhUYqFKyFbnp6DkejADYT6Jb0Xk+klguMN7vEidUdRiovCWUrsyFcRy3Kf8MEKZUKOb58LMCACRYIECueIEZUpsjW0LuXnh1VBYiHeCES6JMxKV9jcyMpJlC0WnOmOXynOD3UGMm+Zrm4SWiCif41toCLXlWyTpgCTqQIjRQq9oETon/BS4wMxgoChPC5fFHpjqXfG1M8MHcqCOMk51fYZgPwcJxCjJEhijoC6bkfXxVt7gE8x9j++EzNwFquCKbWTc/Uxia8+Okuld3AS6jxaF8F1uiI+CVh2Kdr2ASiDj0Dgex7MceFjQzYZyrmM4mMw2t+tm8Su7PuaOCua/HVFAkfl7ejTWRWkcJLYcU0BDErXwWlOcHzvFITQ2pAZKD8CUOZBwUcEa60ZCrt3NyYx34eJwrNirLZjEZqkMlxz2ivYy5dczucYNV7XPsNGtqgj2WAuFBea1xYfASfBnmd/DreWUENRFJFgnOPPfAF57auPnLqJ38Orj6qQ+2hN+LKNUtkw3yL1Lv3U+kSxb+dCDIBdfFgvPqwXH/LipZhgTemgJ1pLrCa8lbx74lcfa4WvPj4EhFpxGxi1DAmUtuH5aUuymPV2sgLW9nTamxm2N2MBsVLKaAhWKRX46mn7YFeVfBhwVVkbalWqBNnWePy0mSZm2UhTkGqMvKX2sKW2BJBmt0tgpII0oBn7hUqiFoPSN+QaUhBOppKWx9mbjKnjU2knCtTpkNYMSJQWr+Cs0M5joq/pyhKZCmN/Xn3ABbIPEjivqL/UO0u2SGa/jkOq9JtcAgnzssZqJTOfBAmNyd3bmZCKnvYGWgpjkE4RsSQmddxULTO7ZVqWzXzXtQuQsvQJZwIWwSyhsRgxCZKYy+3yJOhk2wj3mn7GaRI7siFBmPkZQEAZOktN62nJ2S+aMSehUbqKScxRzHDhqzRFCPkMZZrkAovhZmP5M2STfCqGkWwNg44PHkickYJ+x5Q9RRcX0pQQoh6t8zL4GO5tj81JTuSUnGIVzZ3rVZKyXkJVaT47hbRJCQAIJ6tAKW2mQjc+h4uRTyQ13WxInTLwBIsceN4yWK6Kub8WxUNVDdbqhI02YNVAaLdWarDf1PBMn+yqi3UJ+eZ7b30cf+jXPwfmsz4QVfddS+Lxh3578mAr2Rq+avBFM+X4Q78lbVBLK4U8zmVzyuVAuaO0tr7Yxuarjyrr6qPG2GK15IhCYs53FHOcE40ThXNPWOg8Wv/L5ds3gWTKktm9TyHHaDgULNSozm4wtXhUsQWwmW3gDmn1G8BZI0thDmdMWlrQiyXb0F+mFSv7oXYGtXYGzXYGB7RTx0vaYBdaAfCuUWUrrQJIs2hjJ+0GUEsfzVQbYF/bz6C1n8GufraKH9BPtVcgtQlHK2hf2IXrCRVQX7S3uA+czXZrSTYgv7ztwXbbg9a2B/va1lwEK/0ll1z4+S6Z5Elk6T2MSmUa7hUbSnijt/CNvVFbGzv+0P/C5qo9u6PBwRc3qDavkpobPPFXw6Cxm2/a9upvgElb89vb9DfAqL2Dxv5UMLM54q8GmL1Bb7Z24G8A1VbDjS34G4DU0rS9A7W94B41NDZjS49RzwGhu9Lce6XIUCD3PPUjiG5jH2w2rguvURb8miXUv4csuH5RaSbe3lLjROGSu6RgxeU9jVzgeXlQffvXQGmYlPooCQo8Iz9mOPbzICc45sOSJaG7YrPehQuAMIZUymTSVCZbDdabn1S6HGxgcA0gAVNkFyNTq3m2p/kJmQJQ/56wqVZr+Vs5YKQsRPWcsiwL/JkoE7Rm/MiXLFxtbSDV60LkukCMaiDbNyejUqIIC4ClmCWfibBz18HEpvtWgQJAJ2SKnuU5vg9mebbw+Tco8+A2TxgxK0uh+wfn53lSOLMkJUKPm68iVjjvpbbyu8JJha3KYZkjuxYmFqleiTLKMEdYZ5blTrEkUTJLImeJc1bwId1nq9x59u51cEX/4FwS4swZWxbh0ZF0RUvvj+IsKo6iNDkSLSx485b3WnBF3a5EyxerxdLnoi+OY+MuYLh0CzKQosrSNukL+chITsb0VjeW5ohN2mx2013pYhf4+URKHq/jKbJ+bzYKB0GA49iv+ixbfR7MJHYPmzWG7RCjYq3hOds1VlCNDuaIeh4VKsyqXWPGGj9A+giAa9lbHOYlCElpO/oIfwwhXCDSxE9bBQDM7DoIkbqiEDT8OXbQ/3BP5iAUCul6u4JKA46yCV2REW32K/J9ChkY7Wx6uKvh4QMND2XD2k9hy0LzJmNOslimZEEoI7FrmDNaKrerS8JYQm8UjBt6foFoBLSo+UUOAwZfKjZvwqYTMt1s3Gw2c0fabaShhKfjyqeJlo1zccvdqYQU8PHavMK3HHeNNfni8bvC5xTRsRrtF0zIHO3fcjYVD/EfOZVfqBmvddpNppDxfyia2AdLzjeudYhszwwAInUxQRBsHWoSz/KpUVL6BD3tNKHGKREBQBhXdzZlAevw9uju9uqodHCTWqOoFE8NTQ+1tTSsLNs9JolxWSM2iWt3WasWSJNom44Gsyx/iaO57zOlTKWqmK91iBQ1FA62JpFqTaKijp6nVpO1aPiBsH9/ee9S6Dqs18r48rW9WZz5YV02tPOiXzLavy7DUB/aD60L2T1Wcui6DIHnqa1B2uxFuyG1t/cH1qXWa2Xl+treDlmXWpdNy47otyyLT8lSUi9ie7UIrpoI5/J2vli4jxe+faor8UFSKSEjeJ7fTEKCKAPRb00G/mb910lRbRwtWfZ4Konzmw3GorO1kTTT9TAqx7lYnonCDWWbT62JQHlTXiFcXvmoPJ/y8uMUkUludhatOpnJTmo67Bpt5+dRQwamwPN8MqGCm5+CUnh9CJ+LhscFk/cgKMxhpvRhe3wvlOcEXiaVl2SBSCOBc9+yIJejhHS69In4kFlAO2Aot5wXWcRbqX1XjSgRGq25JBWulStwKP3rkZ8Z01GOqs0nfxG91YhxIWrfiLxpOyvXWXmg+gOeZ7j3bJyFk6m6iPCKsGgeyryS/wcv+qd1J5yGC45avC+5+6GYaGOacbnE2ItJEeXJknfjKj89KHOElBoxNxQoqxLVXalGUZXaW+VplcPwTXvrDN8UPZwu5/iasCTCqenCOC83KspcmvWWmM17LMdJmtCbXpHiYu6aSwO8QBITKtoURYt6Jl5cJzerbFWYTDUi0WxMohTnQpDsLVYF6wmdj9WCKEUz1lO2x95fVyS/bxaoHLB7Wi1VleDrJHtom2CVO7y76+XGcVsPs8o3v17HbdnFarHAtaG1Vu1JX5qHi+Vpr8Cz9oLWfPc0J5FBg6M5Xe11vxdiRUJvVinOeVs2TqyMs2QvJ7PGkhO6WvS4JNBbJMUCs8jGl2vpEVxNobfMySy5I4WFkWxe9D6Ra3zdE+70KqNYkqgSETLbrCnQUNp8ewsSJ1j2by4xhJaMIVcuTgqcptntszgW1A+nakcnpOC7V8ykIPlnkutmgihbVCtfZe/bG2SxZPeqYBNMstWeIBg9TOOedhv8E0+pF14JUahXeeLWBmK0sXpIn3Ge4Ou00YgahhoUXya3Ac+BBc//D02+LOFp/7i/3wPzK8i/ubu17bQpbtrZJRq3LzPjqkuCWYrZT8oNpc6KSO+U3PJN5MwIxMgVB44UvFnQ1MvkMANh475ZVbRVJSKqiOxtBQPPE76NfJsKL2u92+q6ywIlPjZyqdmRVXF9By03d8+KsuSyrJZ484bnUAkHp4P+vkNbcUlfs3r2xUIhrVl3EKX3tS1vtd3nhN/Q4Zs+7PB9aG+yVbf08+1p6IZrU1Pu5HUINFyd9J1nYw8ie5y7tWPpv1y+fePIitC5yZjjdk3tkdRf8lXAy8TzOiQobvHNDcm3GxZmAeEc9P/8n/8Xc9Is++SkySfiYOqo8Trac1s6kAvnLNO2+RkUDOes+HPC5r57HPRdc1/EVugeWHvQWnsga6u5eJ47DPp811TTa9YZbvnqfvyFVq4teoKqdOg8WpsRbTam2fKjcD6vYXXLzQB51Uv3PM4rPYL5eVyW8Pzk7OLb08tC3Qd5T2aIfz5TxoFf8hQx+7ZPZWewU3BekHcyWX/KlkgR4aWVtaLNlB+VPUN0Kyv9miVUF9ii38KtvrrzlUnSo/ShYjm5JIfcPxy5ALpHImVC1AWo3mA6Jl0Wkq575HZZWe8rg3oMbcvjedvu5+IeWamc85NtUVHIY+qqnpIOl3rmpbzUQuzb/k7iW1Vg5ttVoC+1rEkh/voEjEk4IVN5GBVAWhTdIxcAUH4i975p+QF7De8EwLW8dvOW/iu5F3hR3hDmaCuRglHVpjVO25TU9TnkEUL2yMeuG9rftkoAWxCISZTF5Jf3r59rjsPngugyxRHxj/774OgGiktuVVKfJ/13177xW1QNunS1uCa5fV+AhHaLonbfbvHqSKQNXFBauJnAbdTFsIneBbRwf8tRsOF6+gfL93SVJyHbbIQDnAJRSMfUvtfHlxhvXe8LJ9OyhI0N2Ia8QbG6LljeuCwoGxUNNPZ0m5tji9eswyas2lq8IZtU7GskDwqybG9GdxO4YNIXjdbpUfv8rANA6D2OjlwgiHAjoxA5ZZPoPdjoH/Y118wJ2tJ0YsMzuSzhyeBi+Hv4kH+w8CGNy2yI1e7aIRYs8CeT+yrPFvIKDWLBv+NF+o7vSMEzIBZon3n1eSkPhNrRliHqHw8eq9Aj8u6YCD1yeq5Cj8ibZamJJBKZiCMrLda0XxJj5pqYRaf1cXSdxfdaTblIFiI0BxIG5WcFq5ZNYVTlbSBwEBdM6375b6RVjAwpDxjeOlzPklRcpg2bgyiBrSVkY6bUgtBqvtZb8Cmhsee5bi1RLJvnDTp2oth677JCKBnsUdZz0KDqLCA0rtK1CYPncHj8mFBhDm0HRcpzTTfiCxkQKIp2dJVf0c3kil7l06Mb074oXJYGL5ZqHWNHuVVL3rO+qmBdrJbiyqe69qxay/LkJqE4lbhGtG9owaXLjGX8HHw7k3dQ42CpkwDvvoalscLLGTrCzOFDdPyruAugE2XpakHlV3ikxjrfN1YRgKM+Wk3juUgw6U93DN5mn9i+qcytqciBTzglVO5Quk+hEvNngNMHqbvn80Li8HxNmU/hoA+0Dj+t0nOebpGzhc1zrpc5+RwSSLOYhIzDsbH953AnqaiLz9oMIvX/TNxrzu91NxIMIYUyBE9YVJ54xN5iJSgrOlyJL3NxW1QwCzUy1mLjaBoOOI+hCEhUN3TgaE70tc2yisBiM7SXhPlN5wBRT2pSgLiopG4Umbu7NnydtH78+wyMWUg8r5lOwBgb90HeQJhUn+PEuOZtOeMxUKYZjmv9f8F9bb5GyczfHo6+ys0pQMigpq4hLVUQn5XxoOQ4ISrZFiRpZBlZwFwqal420mRzGd8E/JgvTLs+qbwy27BC3MzhB6RAKnNvm0CGOgNl6TKyV43P1wxlPTHFBXut2ZvAVRegJm7wa5FRF1Z/7xep+IMXqTsNlI2h8HPgeZ2aSVhDbYcdSm7pI5+3u+GtbZT8DY742WKsjHr7EL19iCDMZcsOI207rHmSkfoxprccq285vofLsnkrXqyhgO/BOKaXQGDHjv0CM2TtrhvC/FyAP9NqjczcHZO0r4HzuWKpfIKeigJNnKCVb4tj9VTwnmACYMIRqTQ3pdYCUO6KfqLZLXXhslLzr8sS3usCKlhNI3+0zYC1sOgHQq4ZG6stTACtoltlJSKcDZOEjbNh6hp8gSYyEMtqZEJKOMRnMIMruLS4aWHntlTJD48zmfn100CERCEjdZuRny6c11Br2emPiPQN+axoQWdQ+plIgAxs6+kuSTrraXtxQm+cKMmjVYpzR0l+OrSDkEVzI4XiEqVGpvWZ0HcIdlRyermARiR2UYSKsSREdCsQBGkLdpODkKh9QysUX2sDV9gZwKR4TxYZI2EBTfwHBT1hQQhpCTPU1nrXDUO3KwdsbhUKXM1gDmBeimW0e+tXXUR2x+JgJyrynfhSgnbIZfgSLlGkMg3LhM0FOuFQMWvX0y7BeqmFgOuc4E+l7fG6nJApWIo/cBVY3aLUVlr5tTyY1lUS/BQakbQgwuUildotfwnael6pUyn2I7iECz+DS8CljFWg4bLZRHBrFrL/rQaXSGb85uGXpSyClrAaCYoUrOcHL35VWbIOEhCeZ827KlIBAECJNXO4al60WpdwJaTLihZwHjJXMcK2IEWlhkfcDJaDMpGQPj5a5yIGVxmGj9ZJ+VFF0pnjwl8BkMx8LNxDVwDWdYBVXB6C8iBhZFGIOx4dhG60aIUQ0nE3DF7mqD/Kn1CldBnl3S5gPp3kU0g2mxtYX6ME5gCUAo323ycQbt0ZonzRMcqDiqRPyHRkRoM9z+fZuMUEDGBL8FdZAfsZJADARjs3AHaiICne4AURLuY+5ssqQY01qyDuk5BIX19/VgDZZjMZZkiGM8pKALEFQqyDqHExUzOa+Dolop17ALfHsBWNNvM8Tn/wFnxb8F5EONCISq04IrGfQQql2CE0hoJA0VIf3ww9XZvDM/Y8osKfQVahN6vtupxj8ahQzo6gLEuf74CsbWetQGnCgEIGOQmEGRjF2VrvI6VrCnCa+gUob+ecDy0UpnUQWqmftcveZQmPT769XaMlwhRiwZusltJiJBahXxtGBj4ezhBXbBQJxCE0Smy1Vd6Q//iSm9Bk7iucpCR2WOYIEIaO2020fFrFFtOsaKINAfo4Vmef0GCE6yhLRbyVFHI5NkyEOFuWZRWlSXPSmR6rzUZnem9kegQj5q+rAGfQjPo5pt8xR4HM4dvD7fp47PLh49B1QQnKFrD6AD317QCKRBsZQmYFUithDtZmVLlATc/L/FzKOiVsC1xWa0v1GtKq1by0nR2TFmfCtQGSCmBGJslUhp8xh3AtbNko8zFkMFfRyBIgw4u1Y1lWwtPhcK+F/Cvw2aIwIiihHU9XaCSXbzmCp0nB3s60Ldx8bzPQkgUnXffDj0nBGjw4FMdJSITSQDa9r4Wf8LLZQBuBDzlWyDYb47dBhdZlpRDZfzVO+IWy6f54RSUkEzYFcK2VJDtuximnVwoAJ8JG9q5IQe7rACNtk/O8HRko25EBACTy3BZ1xS9RWPwSuRVM20EyyWEyraZAKMsTUvi1ioCf7SjzE+FO0BLHxfMSz0uCpFAJ/ATlVR6AaiLshvooDDsDfpLYPSNqKc4y7bKwZUiVPsHi/mGLyV1IkA4vK6ONzLIVjYW5vaxihvDKShhqYSHI2OfUBD3NfCJ+gZB4ngx8OvZzn6BtjOHQV8UaXMIhN+AaVUK+qE0eRFyOKxsbe3uTNeHlb3nr8mmIQ/Ti2x+iJoJ2SwQ8YX/I0NFfJv3e4yn/59/uputh+egIJiJCtqEGyhkiFBHAQj2jEiZ0loXuazrLXDjPCrZV4BoX5B1m862MQoYt1umYM8SuIlqNsiXkY14dXHqZZ/EqOrg0ZvMidPkgBRG0QheHrljXSxU2GlYOpCrnXRXCGJpgxSrvvQleDLXT6IvtphtBnE3RMFd03zfxn9/LWHucBXQBZPimsAr9jG9cYFQjL7KoCN2X1pdbQh0KMpy4ajm116hyjnanJcT1dRdHa3PpbggL3bfa29WFy1XjmyOCnSCvZdeSsqUCg5U2JziuN4RZNG+kmBWo5l6FluabqKjPQMDpIERQrshb07X8n7fy9gAcWn7JW/X+vgi9H0Y2phokFaj/RXsyJsucRJgRMzvlpMw396FY7N71oiwml9rhuCr/b89NelWuVzxQsIblVfjwaQnTOlroe7pV0PFdDA9n/dDTLGCkYD4DYytMuaSoJYyabe9GGBnZODThb7WZJpc8mq9DwfO9LOca6iDzjT1su+VPS7iqj0HesN/qniUsJV+E4RpQQlhdrFKWLFPy1hAF5aNTwgW+SxarxXZ6QlvTyV2UrorkM/mpXrFCoqpEvYmqxALf/Sik0bZed+QsMeObdGueC3z32kZ0u6n2DHmHoJZXG9o7mwpttbkn1yzyQfuQ0Ao0smQJxVe9pCw30VoNqFs1+bp/fhYwIk8HPR+oXukxUgV6uuXNZm11idugwnKcpm9n4XYJW+JQiRVc3PYNSdBTMy6LQWyuQNV5bAugW+ueExy/pen99hLeLdLQ/bdF6u6l8mqbhmvDfHPOS5hAKtZr3Qizn8Cf8U1Y27BCtPmSjXnoWc8b5itnlwgPplerPN1GOav1VS7QooW61/vYQV0PwfAScv6y3tyX0zFG8kXxdnZJ8s9JtF1VXSEL3efqLhlUN8VC90d1kQx+Vp7C++AhBuZCV5XlsFEtHrDcLcCGZIGT7SUooRrV17XaiiCKAz5o3dSpyGo+ckcuGAs+mtPE6nTUKSGGhgs5YNhJE9Cagsm7bFC9kqJ4WBe6/Mh7gRkWdCu+51PahxBNKmtxL40zeg81PYx4alI7S1IB6R2Hs7hZ9XKxZPfiNs/2wOT+qHg5cfa4MMrSlAih8VVbw3qsUfGZk3vxLxP/LpMlJ7OuONYlvOzDvn4w64kdcnQ3Dv22qgef6VXlrUO9yjr0VK81tiNn77nedtru5oosLCPoqdBFJHQs0VPcXUjoWG1Ajjl8eSTOTXXrSEfPaZTjSfy3wIBp2JJZTxT720abBj39Nii+G7d/R93/6qjbgpBbSCgRr4RGYg8LqKWXg86VBhcFpTR0OLvyOx7/jsffEI9t9UiYms8wgpI3CFfw3xbpAcwMTyyWuIXxlPe4t5IxY3lyvWItXMBtjpfLFr6lLGFThDpoz2k+p4S2trPSSBhhra7WrAoYhYgq8s5WQKkytv6pTfNpdVfLcAGsJ7SdW2p3XeMiifgeXib/Sji/leEVmw8fYgR/I/cZZdmnRLJ1aXZrBpMslmkSJUzwp0Vxm+WxGBpPVcpMF0cRKYrnWSyq88FmefI3kftLiyjAsk+kNaOIsmUlTGkJf5/AZQkS9vbYNk3w4mCsQdqyaSwWIxR3atoKScUiL6GWpCqz3SUHIxhXABRleWLVHv/i8GtATLBNFUy/oCJ0NXBFG9YqmUY2m2ohd7dsNVPP2vlt0xtLl1nH8xTTm61lT/E1aUEG6X2wtdBlCU+HJ4O/h4Hp+AEDk770krSamhomB+UCLA9A276kQhHUdMo8xQWH65u/1GqyZR2qoimE7vMqsgJ073q35HqeZZ8KN3T/rH7yKjVZW02uxfDSMFu0qQL2ETEdvaFGSDl0/qTDOoA2vU16gLlnD9wfNDV8jU3lP9G8xHJ+RFsp5ZZyf+dp8YB2ojomvk4psc/c8qDioGD3aXVOctaWE2URjtSFrqAjnAfFLE/ueA7nVF6QNFkkjMSKS7W/Y0KWklTwCZG7ZZrFLd2Kcb0nAoEO0LO0q1IrQ4jBbP3qLoDqwcfQ/YnECeZkaGvL1WTg1X8F4+DDu+pQcrdn61bPEN+HtXeKd5sH96GgeU24WiXz4vB/pJlv2fBb+O0oRmiUxQm9sfJUijA3x/UOFUKKmwjNdd1t6/uH3J9lCWeHGzZ/p1xfhlY7KFcJ57/NUJ3sM1QvDl/P3cjaPnIoHhuviouHyME+i/VNfTD7qGXdhOfWXErdHUbt323V/5Vs1d/GOr3TzozpfXtGRkl7Bs1Ytb/3m6m/0ib+bYzbe7bwDhVmTcPI/xHOn1tYsdswLh6YeNhm3koS9xwG8lrhAQorgp5mtfgfHNT1WcKm/6ZRcm0h5cgWYZuGevy/nqGe839hAevSYb2f7W262wlM4tI+eHAUa5wDotI/jt/ADsP+39mf4He/gQP9BlLLbyCybEsrqEWMg/quuiihJfAcvsV2s7gHiKGqCAeYXeiwkZsarlU7XGrbWr0RqZ1r0N3fIr/WWHMLlbQcFMbaTjerW0zmlcVkATlDGDY1fXIl37donbLDBGRxiNmyrEjY64EpKaCWhI3VJLz5X8qW03btKryvJ9ebVL/v37RNeqFacNvarWO63Y6kY0ZlWu9vnzd9oaxQDQ/8PU72lb+syDFOsxZ2JFY9K63ywpWZEpktZ3xto9rhsy8lH5nJsbxwLXWITNaEquD49h9pZnu5RwTdhoTdWaURUiX/eadE+IUGvQpQTXER1oFlz0uRbgBfK7vQK2FtsxEqJ7OcFPNvbCF70C5XQ/4Wy5LsW56U0n70Hzb0XRbDOuuhTVb2UJ+nCaHseU5ElHqcFv/g431mw/250OkcON6HlvfvP6F91kh7jvWNxJGosSraZBq69iZxobZbchaowkAXRluL7G6tu1sHkACtuwVtcYweaqc39nlhLjZmehFBn76On2eUKv3cbzfb64tmW8nXBOckb/XWkZZ8fphuA1xo7qtB7l/a/xyLes3OXIgiNbi2lGzO6T/eOg0tk+lBnI4P0FOLoy9LODzr/12uTx5/GDxo3z4dngxA89LkP7YlW5ur69bqnQbuX4uMShblRYJTEm1tmh12bmnfNnlvhb5tYszfkW1DNxb07YuIv1vq/ota6rY8G75ez7+4f5ZfJyzH+f2/kntxoG3N7j/NFtBSYEcLv1sC9lkC2tTorS1+E4tB+Y3a+btZHpKZdQ9lTqhlc0wLYtsBloRynq2SK1su25FZUscXDXr1znNhmTwkxm0vuAJUCW0536q4ooSfoJz4yK7aclpUFjsJ93Kr7H9h44tSAxrV2Y78Ssm3fYxZ1ptvY6PZwoYvt92IC+3sW22mR1G2kKaABtnQxhrNkT0QyCOrLDsArv8TrQG7UPsbWAm2bpYqbWbx2zT9UD5PN0u2g360GgF+V/LZSj7BbCvqp2atvo3+z6S0Krm+tSwN3cWKrXD684+Xv8vV/2hydWXRwiUo4fn5A07avz8nwf6jn5MQkarFW0q1kN/i2aN3KU6obFOEdateWkNMxGn+d7xIxctLy0uGo09IPoAsf9d0Cpl5KCIxD0pgRP3B4Hwgn5E4P++fW6EN01qsdaYDav9FvG0yDq+Oro6OwGbjE2S9m1PLha4LAMSindIeWD30XT1avgQNk4/X6FnZ61J7dqJ6V2Jrz/L2mo9ISHcBC3JfHznaYSqqZbI3uLoeaFaFDBdoJaPcWcvZMhIzdCIDgdnI0FJcwYK0hBclntdp8rDyTZ46yrUtzMEAaXummZlHfzk65RKJiAixSicysO0UmXnmAaGftdvIeF1OagnTzcZ1w1xtZ6MqE6vgs8B6Q3izKfQ7v8AnsHroWAZx7ORB9mk7mlwVgZOjh4ghFzqP1nlQMMxWRWn9/pncsSrAnIzjL7EhD5igBlVQf/PusYi8rm314jVUV4bYNzQgLeFF/+z0G4eGNMEU/yRfcCyq8I/bWfWuzcJies/ZAkbycDKFImaneP1hR7BE/Zo2nZApaqk3okFOZq05psG1enmSQfMsJTWPUOaliA2Y+W2lSpgL37NdoRx1UGI+ukAMISiynPm+8SCJyZLNe0T+BQCKkmKM9ZKqRI/pku1xISGDGUwgRpOpCGeIq3cNmH6PcITRJAgCDNnUvM2posuP2h4sV/EoWT2Wo3hSe2v7U89TxIH/UuGKCxE3moKQ70wMRmxH3MoqZKKJV72rqN+eISLKyl7Cihy3Fq2Nrb2IePdSx8VUv3b0IPIaTaromQamImqo9Q5JoSELRKRPvXTbB+MWpSu4fOUPRERNRdnMr82mBdehyVZYKMIsHxBAUuwCYaVYC8mZzcO+lO7vGBesLz8lyyWJfySfSRp2+rAghIb6qYIlzrn4mwjSU4vAyecJC9TX+z5F9e3MaWcfIVSAVA7VxfTeBVB/5WTmVkHlkwDT++33BjC994GTFI5wgyexk9H03smow7Klk/IRy6dAE04htqvnZPZg9bJamogvTVpNKJlEU7hCdBJNxUmQAg62hK6IeK9gCWM4MwHkt/ZRKp7U5dNECEWeN/e8NCg+Jctd41TkSryD6tCMOeqJUIdXcsGoJRxpOl6iNJx7nr9EqcQLGKNUUh84Q6pDNcgFWuOIJZ8xI/Fb6Q4pVZ2MT1QtNYZNlBiUIysOfdW353E0SOECFt2BiHLOtwAWkgcUTWIAl5vNXJCxZStxaAHGi5d/Cp1inq3S2LkmjqkDRquvwvzlZuNL7AeQQyOcqV1QmF2wKGWc9FiGld0eZvxlw5TE/8uGGbePSlyXfXxycvzNDYq3OP1kHkXZsijKe7KZDmIu5IBzzvxjbW4c1eUuwWnD6pkfxd6NxJMXhLIRMA/ycNFKJgYWPtoxxZnmzNXRFeiA3JwXzCemOl8eTT2t1372N269+9NoHBJTWZ/NedmAlM1LS9Yjrl6EMW+/UGi4pVizS2EKrdDeP+FlGMGI3YWrEhG4RJw6m0O8/i4MhTM4hwsJ5Bt4D6/hZ3gHb+En+BK+hZfwgyBIz5AiR2sRy/95Fcb8vXrn5OcS/eozAN+ZjpKZn6vXAZj1CETKCarcbhaTJTE11898ZxUblRisxZLZ4vQyFg9P8GbfifMUg1HuMxNw/U1wndBYRUnnBycwEdh/rYY+kySKavo0h5/IfbhQn/ppVWGez8x72uEqqD5KuAceoKw9l/Lc8957nn5MiPNAMiby+hl6X8nGCtXuza8btJzIklMb0240pt1wSNg59zrnPohwmvo38DkQa1igzkB1FKGUn4qK6EUZjTDzzSa6Rmlbl9e64WtZT7xSB+AKTabWQurFIlAvqaCMWK9sWq3skq9nBESs8vrJADptO22zaUtVO42SOybq8k3yTGeLJ04JoQpdNhtffQsmDMACdfpwJempfonGEQOSHXleW5fm8Q7kf0ZkFzH4rOH1WQ3xNmHzd6KxN1lMAJeR98xHvDFg+rnbW7Z17vZY7vRY7pTYyvFvs+lU8+xkYG0AMdKqhRb0bu9MHvn1GYZ68J8MNt+aadiju9Wju90Fy0+6xCcLPAKzlqrvDkL+JTLwemu6fNna5Uvd4MtdXb7VJd6qLlVvHIlo4+kW/zlcgNpToZeed1mOariBkkr15NdyIJM7NKvOCHHAZSOQHbzcteYPrwYpP4sz3S8nrkxP1fN8sUEkjSUAvvZz+BxyzmwJADAPMxWbTSfj+9iQqopobTaG4ddJorXnzYeCnlsvyNDqoaBKjAJG/ET9EX3yXD8NRLtdQPznEzqFDL5Xb19M6BTA55DKV4GcNi7zuZFGn+ues5qkQW2ZdkR3CJuZ3DRBENh1n5uXsH2CnnayStImAAAAq5NxVwus1oIr3jSRarWt1kaNd0Qy/c7R80kyhQV6X71slHmenyEm02cS7VJkz3SSWA8hpZ7n8+yDH0KSFVKhbAewg2tPDqXVs0ep3jtp27NHKdpKrj17lFrPHqX2s0dp/dmjdP8TfgC2jM86oWXTm41erIxvceJnMIWFxrNE4FkCylIuQKyOViknzVF1rH5oP1Y/aEh8kHXksaoP5XhLebQKcn6AFsQHrUenOuBkwBD/uX2mNYiR0mrXM8R7HpJcCiRiDZrERuDwI8ju5fBaADLEVKflbs6CaZaCViyF0MfNOftQh4rnvRMsAAGe99pngohRmAvR7Bmawd2MqliTr2ZUZa8YgPU/IntqJIHXQvLLxVDMq0Pbo1TUojPQIgyxJoXb5vDswDkUfg52zQImNzTLyRtyx7S885YK/kLI3ikSURS3TTNGabwlLtK9Yt5XyJCCG9mW8GjJp5UDmFag/lU8HvSs5eUy+cKMxkSiFbJrCyHkS4+lmRqT7wgS8Y4gTFAkdPtUWheSrQbUUopW5G/VVPXIJJa51muWae1FyZXCn2WJklGzfTzmZ30e6HX1U/082AqES9vWmTXeIGtWXOqKrgtqwy5M/xVI32i9hdExGLl73HiMsBLIx9XvcFL9noaTB/Qqz4BG+bf0X8m9eFFoOlrxE/Q6JYviAOWMoh3EshUEsyyPyKX63mxYyRmzdbG6uSEFC2mgfvHDwXpDLFjgpeAP9vV30BSgeNEPgNJ6PY/CxrIwsyx/OHL1O4d8jcoSPu73h4fY9Kl/cTw8BSMSkDs+hALlJeRJh1U+OTk9Vf7oF8f2E3iJZYI0LdmvHSvt2itdwe2SruskhVP5fDmYxk6EKc2Yc02cVUHigE/OjDUQ7x9RfzDsP+YnpU6Wfj18UCeP+3bGq2evf7x89urlh8vn//zyp2e8ar9/bpf4l8u3b6rcs/7xhZ37/O17q+5J/6zW7YuXr5798uPPH+o9nJw8bi316pcff7R6Gjyu9ZRmOEa5+NNIfZamKuNZmlp52pKMcvOzJVfWtr6sMvFqsUSZ+NOo+ULm6J9W7r8/++nHl3cREZ49iPrDi+OBPY+fXr95/dOzH3cD/DBg7YRTEWGKEsEmUtfOEJuG54gftSxxA0Bmqp+1bBzHzzPzvj0vVU9xQQmHg2N7ezV2h9kFrGGIR4hY2JsUbzI2T+gNYtBO3WnMb7Pga/t+aTXBMkFg29wBtnxWScgHOZ5MwwmZ2o3kZEkwa5h+xQvvMEeuK05xKfuxEe2iAci7iFTa1NqM3pAbzJLP5L+RPGsblXhz1vPeCFfN4M3Lf3r28+s/vfzw+s2r129e//zvCKHBUW2G5I4RGrcPjjNH/MiVIipFfZgjP2lYrYCRV5/kcvhkkqFkQqdTxCbZ1PBUZQk5aastdkUsLdJWlpAj/2FYwYcrKKDUCrJ5UgD5lj/nfpBb21YuVO+44yKjSL35v8D5J8TUb/nwJvKtcpuN66u31B2ZAlzQ9U3dseu4XfMVsOxSeL35IHRdAPXYlmyVEyEx/JzjiIx3pEtfEPnIe7VRQChSCuGs4xuiD2TKZuO6pTBUs4yjs16gKCeYEV/2ZHIBtIranXAYWDl6HtvOQciAt+uGjmtepu+iB6AGO0R5vXFIeZ7PumgX8ABkFpoiVkJ+Qh52lnKaIs9SSUQTTi3Pzk6lKUZSxsKQQGOGreY+x8XbW+0/fw8jdDS5uuv3e1d3/Yuru/4PV3f951d3/Ze9q7vBq6u781e9q7uLk6u7i7Pe1d3jV1erV69evRT/vppuJlerFxe88urFD69eTf1xh6c8lym8BNj443Dyl3qxzV9Ao9gRXIlxXJxerYb94YX49/H0CC7R0QReTa6mV+urcnoEY3T0F38cdjadzqYzwb2/XfWm3Q54dJTAmc6a/KWqAfxx+MdJv/cY92bT9bDcyN9/u+r9YXR1dDUO/3cPXXWvHsEPV0Hnv199/92VfwV47Sn4/tFRUm3HuUWItmCql1buUwIqPndhVRsIArbZDI7536rMjVXmsSxyPKwXud9VZLPZ1eq1VeXkRJZ5PFB/j1WdoflxWq/9ectd7uTiCae+5Ak6PR+T3slF+Pj8CZe8jocbLqKzJ2jQH45Z7/F5d9APe4OqsTt7KBe8o7F71XfDx+fy9//PDR/r5Gs3HAzO1DBVGuNpffVB+Ycu/dkNB/2h+pjxnBP1kfOcgfz439zwWBVy3PBYFvnO/S48UQM4csPHupUrNzxXzf/P/+GGj0/V7//bDc/PVBmBo2540be+H7uh61ZzvrXmTJ6gs9PT49OxwpJZni2ez3H+PIuJT0DYlnx6Onx81vVJj9c8e/p00Afw9Ox42Ddp3qA/PAbSY4Gv1CdhxZNH9vD0DMCXzYS3qD96+2R4ejZ62+2CT5O3U3TnvwXjQdiHL/VXhfKX8gQSFCyhyxXTp8osSYk4gZj5KV+hl9nSfR4x9WOzUUQ/o3/GORWcTPXbrpiSGxzdI6Z+bDadgcz4lR9pTPypEtOkYISSXD1NzH/ajelL5+oZ42pggrNLUhLry+iyPJOBb1pLqqA4epScJUBE/ZCJy6wQylbU14OjxP59yXDO7ITX4laUTtGSe4Em0wqHPtR8KfliZj4T8l3iEwN6SOTqQGJGAYnow0rpkWoYwKJPz/Qac4lL9ldlPpeZpFotz7M+JLUTEJc1Qcnx8D1ac8Zk6zgTJ5hguzQ3Gqj7Ip7Hh+HGKxPe3Mlmzh95K45UKSefOfc9EBZYCXZVp17GwRHnhgqH3OGICece4uD8ZqVus2p1Uc6PChHxuwuuAv3r0VFA7kjk00l/CoDqIEnT3izLF1zQVA0Jl605cbbGlyEhRrymzM8ngynkezax04Yyjc8jU+2vqBwzvk5ViwoouheNGkL6UHmIDxGSIJqT6NOPCSU/5AR/KlDyZCgaTzxvKP88l30o3yESP9BFCX9+9k+7Vm403Ib/z8/+aQ/42W1moFa4AOZy4BmiHDyxDAmag82mCWqGb5w5pnFKHH+W5AUzzQA96FrPwpNMHr4Bwzd8r+ZqBb9jc5IT4fblLHPyOclWRXrvxCRKcU5ip1jNZsmdM8tyx/2um3e/c63evwNwJkeZ7RilvLzo+AWJMho/PEw9PvFydllW1Pbn6moEh3cmPeqEiPKECj1jgdROV+6CfG1gLuSXDPVhgjRtGmVPklHGxRV+gvoYFUGkzpVnfCaAcw9PEPY8/AQNBoOTwWCgZkfuliTiePIZp0ns/Mvl2zcOr4sjcXFcGiYiCZJC7xE+z4LlBC8cfWHToRntLfOESsQ2TRS8jSAnxSplXVRYGsF3av6ZnL+YPYyEAJkbcdenehmUxmdB8hviqChQxUiAfJlnn5OYL61QfDlSHuYYYG82l/PJfRg1pT5aSX3Fk2hUcDBilEyKqUYxBjHYbHw2wVNEJ3gKM/6r0wdN5bwSM/lM5KQiuOILWhevMyCWMEJ9uEJ+hmRuxVyKxZY9Z9XYoierUcTH1mhsEk31slBSCP0YzygcnBPbjZDETkKLJCYOn7UL4JbaIPM8d6JgJwE0dRFCc92H+Iu2ioBW98DdjYmWWpqBGVLyUmYIN+NyFVqXALoM34T3eJEGWX4Dh/3+MBSowBvNwRaMExvGyRYMJe4JB0+qcFwlmW+iuA+FAxxPN5uOwYhM+qmIYx9vNlvnLyqEJ4w+n2vnHYk1AvO1cLl4OMmmKFEPCDjU0jSwmlVCs+iCORZGEEkfrN1edQrAuProdkMhMLCxbydCyWbvbUb415gaIBRzwQ6fsCPcC/hO03REUDye1UUDaPEgqGqjxSigWdoc9WH2wHBGfX6ajmSlEceWEWit0+3atThd9bxjzt1nIM7WD1cpb+dJSvxBX57eg2P5V3xK682Cb1ABAkG2+AI9OHyYd7sKMJolHAlhJRsBO7nbbW+qPkSJJb2BdNcX92L4clXNPKGKJ4jJLIkSzs0kIkOwXfyIrpbjR8uR01ovhYod/+S0swvrKOefTs46CLHNhnVaUYp2B2BP5lA47XTRMezv76Zz7zNg87SPJNs6EOhdHTZc9mNPB57nV2m5UmD6XK6ErDew23nRUBgicXbDBJEA02ie5eJWBhQ+ekKJqNlamSs6kj/5ea9/TxHmjNABSJ173gnHz9zz7v295bsDAEZAsAidPqxtaL6nOn3YG4AGIiAGsLR7ifsuDw9J+yRwXBDU7W9iux7DzgB2+gCq1jRwgdX1g41DTTuFi5s9zqcMKEQGgtBc49jGWM5mYacgf10RGhGHUJbfu7b/hDVjpvamwt9OIVaI4RuUQb06KIEk+JTQGLm6URfqKSEMa6f8T9YGkUc96gwg5viQzPxjTiD8h/a/NhnLOgaFGL5pl4qw4jql+s4F8EzQ/odpAxj7CceOA0qGx8fiVoyPeQWK3E7HPageL+pCm7jDBKy/hLoq4no2lFS1KvBEy9tjP9/ig21MergrdWStqGF2CY01v6742NuEzRPqYC4qXWOWLDjYXemZJk8aNdLOvThxJMQ8z8djyRLjGy1ZKE5VccYOuYtSvJDrucD5p8IFodhTtSn1BrC2vbWwZPhfLvnX5KRGN8UqmtfYbigW014bTjUOANdoP7yXWorTwsDOmc/S7JbvXY7NWV4bXKktQp7XmbU0yGf7wAxDx+3mACZjuaXzsCkQUqCyjAhGp908dDuuuAUg89yOK9LqidvMJi8lpMsVNZKktRjud13a/c79DsBOv6IXr+ybEZxCXHTUFYUDKUTrKdNKJagjs21K0dpRbalr6CEwnAoM50xf59qnYAQebsQYxUyS5NwN2tYHSLOYOItVUS0sZk5KcMGE9sYSPisivQ8fbYD/TcuUnAxxwAuZEq6guKwF5/AODeBbTrQvUYMAa5WiPDXlb18ETnAhUWK8cD+qRqW+xOmhfqtzQ3xhVKAIncgjjpMLCjPPs89n/608vu3Tb3yHBmGNP+RczR3qh/WzzfP8O8T5F8j5njsh7oz4AbXZcLQbgaqjsewnQvi39hVGCmyR5/kRervZJFK7ded5J9Jd3Z+hgZzyUOwoFrLuAM4tPLNVk3LwY94c577moBk5wlIjCgVBqpiyqGLKVmhdmgs0HPAz+Wcu/yz4cl9/Kc+2ArB4iEHi+6UYCVXNA/xOVxjuFBuF7ePyjDMNheedctJQbDadez8H0suMIzOFQ8VuKV7G8DgIoUTKQA+O88YvwAi0FtuSkU4vxKXN+/ZW68eqOpmwcztPmAxFXm1fWyh08Iyn8OP2E7nvCX88pyBLnIuDwZy912kWfdKysQvgwvP81z4x+1cyrjGaIbm2gK9rX65wxv+JFXbMkN6K5opp5xoYOsW3srWPI9jpj7SSSehMcoJjTrK0TcHI60uc5CMHO1GWZpRPcZEUBZd6y/I3dFSfuGRqeS8iXKCQsz+Re2eB7x3l9GQPTagQZPfOGSczxdg/HHCcP+z0QbgY+xqMfcUvJTTKFkuhkSB3O+DAxyUIugHFyMlyZ5apG7fX9w4WqkGGr1epUH2QxZLdC+2BoPBmi6ABLFDOcdDC8BbZwJdE/oQTN6FMWoyr5Q7nqJJHFptNDQpzcTm7BgZLZHloG4EG8ZRSSrFHSqmt5wNCimaIFp63vXDXRnCpIZMWXPSGqc6fFYDXJaencAYaJLXmECNJqj4hOTbM1A6aV/R1gdbiCrAwJvvLh8AEMvT4WAjJMEeTqdmAgyEndcuKucnQYHgqb3flaF2WX0KecwBbB1IABUD6v6dnfIGWkkCrhWYAPjwDoSLaYmqE2oavwaxag7leg2JsViFsEyRzvvNjRTDlRnGibLHAzjVht4QoZrl6vl0gTUI4H7+S51iCuKAJxRZfHqQh8DxfVGrXEDAgOURLtB9o0T5SWJCa3VTVagd8jSPDWvUgWQJxti03GymPPrxuVl+Nca2s3V2M+UbJ4QJGMIUrECZjdTecp8ujX2WBUOWkdtvCSeJhbBj78WHDBmGMOoPyC2TNxpq7gO/ZGRhfok4/9AvPa9u4FSc0gJwdgyv+zxIxGCO+fyWDNhieSFPQw7u1MzB7VIjh2N6inLvOct/oSNQdHYPYrit2GRbaqJPjnX02OQeh6MKAk5R0nCJRE4+Pw6E8e6SWTpLRaJ4tBB1diIPGxAO04kd0fD9BJxdPkF8gDDyvEE4rRe/kIuwNwFNk2Kc+P1TGhmSbc82m3bdJzOaya3kuy0mPnIRZfscpKQqHzTHlUosLwtW4OXDa0qo9+tBfItZNemIF++Kay424hhJn64dhqPQnooaQLSVAv6RuZ+FjpWzD0q1Er+XaqLPrmmr4ED6N/M6qfmY/WQLPEwpuvKXgfnikQs2+qmsyny5FwAs7CUA+FRB3uwYlGmNYHwtM26UJjsaDbhzGIBzIC3VRTWvMi4CRPKeF9XXMwT72Z5K27m8ShDNRcrCzZMyJdchRMx43OnZcEO6stjtL980JRF+glyAONa2+vfojcMBS/CzkEUt26QxAqfiWTl+Srp28hkDRx1+h/thDeerHWo6ypjLj4b4E2Tp+zCVVwSb8LI4Ue459APeMu07W9Mj7QoVm2qgN0x6kZNoXPgVj1XMmOnzkE3lODcQpXZ8ZX3X9GyFkCdOe96NPwHjPAaQdP6ojqEjoTUqcv64yXlQBGYT+zjGD0RcccO2tP4Aq+nwTKHPCQf8ga/6VKENRvoUyD/Yl+UnhVFhoLnF7a/RBvatOX7DQQ1FLY9pWlcUhYjcwqGEkiuLJ8PTM8z5NiimoaMLLSTGtjcKU9zEaDIUdIUUFGA/DweBc0MeT8OJU/LgI++BpXx4EGcIwQf1R9rQ/yno94GP0+aCBPkX9cYL85MmTE9DFYd3hZE7ucEyiZIHTuseJGf+tn9ShKPeLwj/pjk2KCC+JMQi5YFRfVL3FCrXFOIa1bLF6pW+7xeJsdf3gFqt1/yU8ZHvrNiO55fPOgcCx8YRzew+prpqbq7X4A0rlXCiVc6lUzsEIPNzIwUrlNMHFl+iUtywvNWWysSEYoRNqC8x3K2q4t1j1W6n9DY2x5VU6tRUM4owEY/9SGNmkg4sy/JkvWVcr1qq5qUhTnPec48/EwfTeqe7Ju5zJ2K82lTI+kqRR6MmUfiyZ+ff+6iEc2Gyu/RXYbASXudpsji/k35Oh+j6Wf6XYsdpsznTGY/VXpR+fq3z1/fiM/63ZRP0z1ZiQEVZcjL1/CEs5B7XZUM/j+PUFx0GGEvukFqZcjrErSeWFNnQlfn7hECSzqOmtBJtqZ28rvQGwK0tOdh8tUl2uLAXxgn9pB0Ih3qd2PSHdV8yxJoO9QUPDhRhYY8k/PsD067h4pTXURDWGipobUFqXKCLFVZfY8wR95gjbGUj6LEv2CtC2TADeCIz0k7qFs320bV4zjt1fp6PRQvh1CYxZVqgSC2aXE1VhsRCByFr2sdLSuWMXSB+2Q3RZRqUhZYA70XTkedIgYjck+nA7rv7gzKs7dnX/8rQ2pWWrtXBWcmLKT7bmiSyoDM8UjrGdJ+OnDsM3QuatotyZLSQIkftdV7YnKeAKKSWJ7YevPe9WT5ajVRcN+Ij9uFlqspqCQF1vr/xJwLoCf3W3y/I3kcCOhabqi4GtEU9s0cp0LB3/J3Jim407008STWV3Qh20t9xElJvCrXWIRdnGKrh7V8Htisa637WuxnfdWMO/dUXibZiO/Qdg+sVwVMYCpRhRHQqlf0wEl2JNw31aaVyEe4XxzJDMHMM3tdJVSOwHzLRRmhVE2GntvSJvh3Tsc/WyshX/sO3M0zwJ5OlhfPClibfpg0/U7RXj6Y3WJbSAhtallCwe9AzyPN9iFx4qDjs1HcfTPj9chRcNUAocfJj7zza/Vrm5PFxbMYWTKdx2arFZK+3I/GSgPRjMLQLBzgnurU23ZpsUqSMbcX+DF6hyAf0aLyXp8DkyMbUa/p+/DY65dqfbDcJSNSo0c4pmvYcUjN9P6FQKNyB8Lmm73FFGGqmgbXjW0kK2vmEtJDYpT8T9GHhIoe7gsGJDUHNMRscW5wxC3MSZQohEC5w3nY//ZvgGOZHeAJ5o64E1361t7Hkr6YZUh38C6xtUuNLSjPaeXT5//drygZb+9iL+yjInwuZdOPqtdd6fufHV9Jrcz96NT84egh0QRHoX6Koc41HX01twW6zMciFSKqSpTPQ1IFc09Bd1mwyxzWZdSsddot34idnznie9qEl9Ano0QDlX7872iVLCwrPT4bm4JmqX7YsiiFRhtYG4P01lnFMxSOWSGpO7tzPfveq7knIJ12l+zNFqGXL4zKfyFSjn+p4J4zanTDqMdEIdsRyCyZMrw4fXd6UjN91eLGrtc0BtJTgaQGqtnTxzRlXSE2rgMAI/+JVgTCuMqtbjr1r6Uwcfa3nfgVlx2USUTMSg9FgC6tI5X1VJK9viuWudl4wMK64uictI+dZlJObnk2xqocufLU0fkrjDe+lb18yE3CJYbJ2g5zvpT0dVoJjMrzRJRs9oEDehFlJD53rFnFm24hQjy0k9WIwOnvLXZpiVP++Ik9IUtOX42sBcLcIugEO5YLmKXOGv5T3UEJeQk/u2OC51pakCzp/FgxnbjTAAyhIOzs6+JNhAdUUtq241qWvB4hawuhV8vZrNSK6jTZjdQ60LsbmO/pCuFhRlZWZdc7oh7JImyyVpjyZi3YfrWN0BiyGU/Bkim80JFCTo/BRSKdXXhjTKnvY9r8exyr3qX+VX9H/+DzvsgGvogtWR2L7PmJ/1tK991kOD+lx72VN2NOwNwJoi1wmCwHFh1kWnlqko4ePBjfHgJ3ZHmkZ+5QCxGp6P+Z7r1XrSw0vM8HDPDE9BUt2VVo1KCppBDGBlUnI4a92l3aKbdDkZ7tazug2gdM3e7bp/cUuYHRSJQyydufakkY3vly76LqGcbzGp3e9c5zsAaRe5mMlT2FVRTPhHdwC6LnQk2pkc+dnlp/9m46vIHxUW+oIB502GfIpcFrKDdmQlPD153P+CfdQM2jHsP7b2Fq4p6tCkii2jA4cGsyx/iaN5/akpinTNEgBIJmy6o1xLsuiPCanZqBOY1HVUUqniQ2X7VEcblh862GkbERLom1eYKgKVmenKx7nEPX05O2TmKcKl1a7wW/qBKlNLjoiYn9s122EhzcEZjv9VzLCmENHJoHa2/FzdIebcnqzgcAzWZ4vxv+NSqLqVIoMIODrOgJKGE3rD84X7Om+h0PyEuZkZuAK+CkvrwQoQlmF0XN2hCyfTRtmXd42yGkAtZVVoAztGEcdAgVJoLScarkuoLSr8t3Jt4j+1niNc23eZc4FxShuiNSCIBrq0TiHSmQT1IUPmnrjmG8gTNiLi9q3OmZAKuXNgRWxshVQ7TEBp4oVJCb5QsYRaIDAqbhMWzf3m0MA6wgVxBiFBpjF7Bpw1kWKgKDcMSS2vVnSgi+oHVGt49+c8ozeOfJxUIJWuJxRClypKhRi/9eYEl0UJynWELy4dMuuTAdghAflM8vv6vtAUx476WJQA1PfC5ZJE0uihUb1YLUmu0L1wfCE0KBZMDlFdwQbV9XC5j2q5gbw63GGHDi05YGgi3IHcZbVxcbTfNSorL7BUTuTWKfy1IlIhgXpThay0WTNUlPCkf/b4sJNBxB604iqK4I1VLxMVXXDKuzgbPL74ulbzCuW32hcho6bVbCbUH54dXwBI/ZP+6ZD/Pe6fn8oh8MJfN4SWjvtnvGNNx3jSxUX/mHf4+GLYHNPZeX/Aswanwz7/OzwZiDE+fnxxLMc26PfPf9PY7O4GpxIE54PjU/73tH9yolahf/yVq7ANAhHmsA6CwXB4wjs8Oz8W8zw/Pz2V8z59rOY57B+4BpLZyNDE5XTYha5Sx7rQNbpe8fKo3FJvZy50lzkRF7SIKL7MSUEoL6TI0yW7Fy/9FvzvszTBBSncKUzQxBgDLH9X4wQ7HbVEw7O4eyzuYyu1QTOi+jbfIo5wwWBkFoNh0YLc/+4XpfLKRHQ8wS5yNjEpnAUREmFsXijmhML9rivYSEMwgu+qQ1jcGpM/BXfElJqfmmhDCrLiKU7xy3Jn0dSr0y8b0e8Qq37b/i8VvVM1qiVCzPqwR2AWDrHqd32IajXFINVvu4C9xIjVPmvhnaylR1x6raWokhitS618p55XD7Cxg0O1j/faYuOJUiExwHkGEfOWSyQCA5K6MMQXZgcmCEOKFhuUWYTjQ2FODRUEZhsRSsjpzwG7bsTy+7UImHt+dgKC9M/Ve7Ol1I3oQLQJcp/98PzFy1f/9M+v/+Vff/zpzdt3/8f7y59/+dOf/+3f/xu+jmIyu5knv35KFzRb/jUv2Orz7d393/qD4fHJ6dn5xePuEbqiV7nboDCZ33Jd8TqhOL934ZpPuwqtr6N/N5hjbcSs7ObGLqICMqjQVxglVoTPTDzrIN1vGcJmXYgWTYUP0NmJNEazJ/2q/byLzswd0D9eINRXT7fzndHqsZLZT8dOuIyMpkc30BUXXTM9wAIlMBVRXtSDNwz1R+wJHrFuF7A/niDU9zzmeX6kHMKfPh2ceUNOcquUi1rC8PTUSwGAKUqfPDnbFGaamZ4mq95y7AtHQfzHk+/PwPjLOwlFoDtaq9lv1hyKBBAOhlKhVOWcyKL5OBex5dQfPwKh3BkRCKMSGmIRthCgnAuASfGD0AaIl18N6Wh3JJL6FukZXC1CC+yPDezzLiom2dOngwvv7HgKzeew9nlWfZ0de9mUH2x+9uTJBehyqbcJ8WMw/tqGQ3lTsarer5U/sb6ePLHaOjuZSodhak1qWCt9UitdVYN5KXiL8+MDNQpSe9DkLdp2fpalv3Hfm5U0oSBVKB6X5SsRcYdsNu7P9u/3v7wUv8Fmc6oLz3BamBKvah/PfrxU5Xdte6VVfbDD/ehsogz9kGUpwVTEIHo4mqeF8+s0uyU5F+vadgsZyxGGarIlXC2Xe4uLgYcKAiWM8IKk+4rL1iX0yhLaZ3TomrG5gk88PT2UTzTqKX00cXR6T25e3i199y/+OJz0utOxPw77m8mg93g66fcef5h+D/xxeHUV6C9eYEJeTkVhFVNvvDEFuq3Z1Zdqxh+H4aTfO1WpoFv1IAtfXQX+OEzobPOa///mFdjIJIrp5g1+s3nz7A0Aj8RBcPQXqzdydMhROUszzA7aMQ1fBM/r+J1EWQ3BZuN+EBg5qSxX053obfkdGHkTuT1Xh3UyJ90HecYFLPuRL/ZzLN6UmfSn494gHHBefwrdbs/SEE/6U/CUk1rOX1cWMciLiMdI2VjQrLGKq/3u7eXrWlztcFfA7dANKKayiTf4Tcgqe1roCmdfnwXFMk2YSGjn+rJgRYt5MmO+iJP4ikPfJ3DQl1weE4G5BzBrr826iHyfw/x7dNYXKsnvGQjp91ZTjDd1IFWQEz2MKHieT/446KC+fGrIjl3uE7DjnDQCDxd3kuINfsPLKi0Tk2olaxeHanwCzEKX5Bp6UmW+efZGZRrqYWXiN65xO9y1woLyPjwKji87R/H6zavdo3hNZ1ujaIvffsAoenuH0ds7jl59IG3rpkv2g75b7cRq+f2BiHSkYrGMqdmZLhd3A+KCkO4ny1yg/yqy3P5shhWW+bRSr+P2EuflAQQwoYeRvwcEBcP+cW6wUNcQO3nNtdftuSq21ySbAs9zu64MGSaSul3O5bl9QWFEf1lXGBWqezW8jWtNJWUFdUeh2x1lT/JRJiUS94PdkXzXt+8qi/hA/KgGVqBO31jDPE/WZSWvc6fGclgXHV/cQaR17wTxIhnlq7HZnJ0+Ee+qP0Hn/c3m8bn+GvSH4MEBCdeAB0aQ+M2+H2xWtoRqIDmgKzeUdYzbcQcf1nfH7xT6tBQX+t1QYcHRX/w6K/DoSDvlKLskAA8fqYjADA1gUtnUpJNHdVp9cMVDwvLSXO2cBdCgaM4PUhtF5fHMRPjK3oAfVaIJc8Ly8gp783E/VHg8lviaTwbTcfZ9FRtY1RsCOAShxLOtMnBwBsJawgUIm5MJXS75PHjuJvVzlzdXnbq5uBw4gEl73ZyfuhRSfepm3+eNcf29zlzyx4EQGzsttLvGpkuFRysXzRkTt38t3Eo1Vecw722lmbUsYRYxnO5prlbzQrTWSLIaU9ecWpurnTQltG5F7en9rtbX4Izzh7/ww1Hyh3w0DxSpRtc8vVTvLrS1fAbAkyF0rxPqThWEJhfQzSLmTs0kJ4M+5I2409pkJoMz6M7JnTsVku9x//yQU9Go187P++eg0q25KyofO48rz6TbhMbZrdjY8mdAimWeLDCoa+IOEQp+LY704L7+bORjlwK164uHrIALKcrlI0TiVT5Mb+SD7IpQue/y7CbHCxGMTDiZe550hrrO4nvjKeK+vOOIXyQZvWSYERHL2xSb9Keqqu8+y/PsVr+mVdWqFyYmXdTjAvqX1bAWRk++fIBMWyDJDEioDRJJwPlBo4HSQShTIxQR1W2gbDatQDHFNFA2m50wqZVtzNDz2mCyrwbYftQMJymJHZYZL3mDYkZ/2NrcEud4Uewi68qdVLxTLiWo1kYErAR0oftDmkWfapizuwqfi3j5T8/fTyDV3smT/rQ7gGwymApf00YxV03K7doVRHFw6HGhmzvswNilrdwmtkBQoZP+6YHv4R2sf/u1OMrJDblbfj3dSGa+8se2PSAr7Ryk6OjqyJ/cJIvp9+YVAwLkC1x8xxwJ1oMzJKIHQRMpBzvU7mZPj+uM+ZHgciZM6y5yS4lh9rRmw/fu7YfGpxbYDNHzagO0lBawZTRc5q90VQzmhyKSrPHb0EgR8yN+tMpY8133yK0ct27S7Bqn6i2oG+H2bUJ4qdSFSJWvpfKTWCUnLoBMoOTw7FBz85egZHVcPoiVtvWyZZnB+gELgvF1Ja1gNAvjiume9k9OvvF0F7jaeyY01j4ts9HojUm4LsWwHl8MD9SlHj4sEa7+QfBXmPvkidJ2awpR/r/U/ft62za2MIxfyPuPxN1RiQiSSUmWbcmwdpomM5ndNJ0kbd8ZWZNNU5CNmgJVEvIhpuZ+frfxu7LvwcKBoETZbqf7/d7veRKLBEBg4bROWFhLWQP0/ugBk/U/C7AabBXsOTIIlajk/Uv3wR4hQGNai/+9+/zjd995+48EKnP1xAq04+UKCHHEU85il622I/0vb4Nr9Pw2H2Cu1e3bIgB+rT6/LAK1PKXD7/2WAyGcPhnvje1Hd89ZG6m7m0pDj9+2OkDRrXxWTWc4JtQcD2JOYrNwxCkfizYJtT/NeCqUq3W8EyqiSQhTqDrbuuodNRhvQDiIVBfAkb4KvaWKYAu/mVdIYEfFpjdydeRUnSgmK0JPUsBdhDJV8k5vEP4WtF43sb9l2lYRy/I/Zt7ADF9PWeREGLPGkVhNZL5nInM5kXVzmO7OIVv4cha2IrRk9iJRWTKaihmZMslPZvAzmz05Obsdnc6cjsKNA91R5nQ02upotNPRjEhwyjnTUGMGQKYKyBSANPiRwao4CvvPkYJ/CzLP6a818/4bV+vJyXH/N8D1NBp6HuRil27/1gVrcItEBNxBBBwLZG/k8KmYObYov3lPayYhPPzDWbVcZDuU+LlQaY7q+Dj4jXNXPfy1Z7POH9Tx97185e2eHz9ZxWTrzZ+Mpp/ErJg2zs/FrI0qmSO3ucqLOo5WKS+QOo+GGl74/yj8aac9Q9vNVL5HE4QmX3nPmhnBljQX0fJ5ct3W7EgZRz2mRhiyl9OZSXlas11x5RJod9fjcjv4oqwfwQFwWbkNqbSrmPg2EtTqJCB0v7LM5qQtZXWcyd/erBPiSD71Z7gppoOZvYpFbxuyCl/+6f746ZUPoCq3hLn8YjDDifw9lMS/LabDGRbTo5k6VlkR+axlvgD30XilEexpf4xWbeIF3nhF2itzdCGmJ1JonJMhHbzwh8ELCWUwazfavpiG4awoAqXHBwFTl+3MEXhSrYdVD+sKITxvtdbdnIpPbEn9dfdSP6HOHOH1Bpe2mCNZxdP6hrcf31dUDofDXr9S9pFo0DhFDxULeLXF4LKr3NopQljU5gvCIUiVutLJSKars+Sn1XrIRZSJEZBQyucjJqd6ldFRaueCwZHGRTq/t4kyqW2P+hiI7Ks0F06BcNY2gjty4r25x+FEdJdaY2gPXSd8GsxAFim/ySqXpBzXp7w0NkQ4dl4FTpQTGNgXCRhCxGeBugPknHFNExzPSt8FzN43Ha/hm2Y+RmtCkomv70OtUbVZvAavjSGxF18nOZlm3VW68hGOZyPfB8WmfEWnDHzxpjgi8Ta8UI8E+DRutSTAk2QUj8trgX5OpgxHM+u2JncOdQUWSqlHsg0+ORpUtVlbi0t0L+4F/Q7qrYmEncix5KCTwRmRO9/MTf+Fz9sZOhh0sg0WXZF+cy/objB5g6eYqioisLZyAisr1sr2bcpUNiHaXDbBN34AEfSMS5n8LJhEncEockxPV2PeJgMkSDatnDlyNDs9DY+L7eR2CBm93YyezBjupvfRDMfTdbs9I8LYbzoJx+577/CwZeMmg4s/2IJ1sNVAEKLZ2dmgUpcK6rC/ljDY08NBbQfPznqPgo5wLOd1kaXL+pk1N71F9Zw/+1MftPQ4IuGwf9yHAIsJyTrpOD9NxnmbREgrqGOf4hzn7egsmSSjvB2VNrOhij0kCJ1mnXCG9Rd8Ks7OerM2nwptR9n2CPGQMtdMYWx8+Ulvpo1Cd76WVAEe1OdQU0/X5CGEWfeXlHHf89DGXmbnsj+AE1JSd8r0I+PiGEZoUj6O4O8fYeLt4QjMJ2zMwug0H7fbEeLTaEbYNAJ5x53hCM1IVBKOxFHEmjrYwhd/GpwFu6T/LVdxP3Ol/2wo5KCcsVxQE4JglYC7vYFn3Co4nhSIPbzohOUFd4SnHIPLvkkwGnT4nwZOmOMY9n5WLisleUFoNTHOTzO5cvooldOby9U+bIXDozAcHgeoLdPaoZzy1vCwBylyDcvU3swGJeNTiW6RMQVu8ykzdsDqeagfh/0Wm9mlGJULIpt6Ha/qZGJGhj2cTb3Pu+n9De4PazSZltUOBsfKtEfSf1R7O8ax+/S9hw0ow7r5+iIXmR/gnvJx4Z2fP5yfb0ADrbJ6COH72rtzxibg/Pz83EOqawyVqQ8mMXISNyYxdxKxSUycxK5JjNFG4vtmgLrLaOWvEJJypOY8vPPg43cvP/7Fa7+LxJUkVvN06aO2dx7Ite6dB+9/eP19bW4uc1999/7j69rsBLLfv3v3sjY7ltk/vP7w9v23dfnljlk7Y1a1jZByVTVltOV3pFzUq5qRZ3qAPBh/lRaZtAeblJukjU1KTBK2SbFJ6roeWOZaIG5alYbnaaWG3FCcpLIl7G08TNV1S4621wf2jOcP3l1lFJghyfThiIAjEoFzkrmF82leHg+1iffgtVnb2yjJMiFzP3J2VMnHVL9KusocBWHlEqcbrVbJvZ/jRHK1bpLAOcJOINSFoyR/gFPkjROI3zmGPvhnZxKcz40RkTNsS991n0FPiVP9ZTXvzM27d5lY4Bt3xpcVxcH5V8ZyickRNRquKVVTE+GESNjO5+3z7nkXHqQsa57RpPxcToRkGQ/+OY06X152/jGTxczz41+tSFIUMb4gKqFE2hjMdQHcVatVRqxhMN2aNz/A3RfnmwM0ufcpgX60YaahrnbeVoXRSPaKLfwVikw7aqkcSMgOSifFoQoOMDfgld6BdM69H0mGsRkqPLLYVvv5t0QDqBnue1+9y09GcuGrD+uQoYI/Aullo8WiG3yn+oWfrFh1EOb9mqwBToRfw5OUgN4TQDDL6A6yDIckM63y8CPpE6s7nED56CL3ZRW9mZQk8GeyHL8+vW61/I8vSEe+XypAX5Kom6dL6l+h8Y252SQzXpHr8Wf/FX6Nxq/a5KMC8IMENkYS6chx/aD9MQF790ojL/8VKAg+EM+JS2NK+q8Qfqnq+kTedz44bMQnKUrJjB8cBemndmhwU+Ch8Qfy6jSYeB2v/UP7g7UzGv3Q/rDZ3Cjy/MEELLohmR/hugm7B6+kSM6V6e1bEozfnt4YcN6228hk/UKC8S+ntybrl3Zbgfk9uWvfTN/O2rfTX2ZjvymKYlUU36NWS3u2+N6KVXyzwcdHw2cerklZSxH04eAQLveZz0oXQB/vlxdp0mrtzeou0mxSPvoeT+f0l7y7FizpMp6vaCy68ToX6dJDIBqPRTf5mSRYdK965FBpPSPSCwdHg+P+cHBUUrVcEwZ6Fjls3wcpKyre7+tPV7ShQnGZK5AsbzDNEC7SzN6kzdkX6n2NNFWR1ZScryPBaxVwTsUPRgusBPJSK1xB44kZYLbwPeXyoBwgBbyn+FLHq5LTl0/3K7crpqz1mWC5WPnd/YpaJvcDjSm7oXOVqlr+2nZDEnKzJmIN4jbvyuuhMzS4URXCazvSanml7bO3FotjD+Fm0mX5ax6nc3X7tba3nrnfSnXBUcNrC8OaB4WibTgjuQ/hUbPubcYEhVRrZ9TUt9asAWsA2qRs4xuvXDC96h5gl+U/MXpb2ss33A3LFv43PsXlmkBGANm7VBa+0A6HsFJKvF8sciqwq6GwkyBZHMlglopOWj8uchUsWJaLmiXAt5cBbqi+4YbTUf2CG2mmnjoJu6ZmZW8tHK9tp32sx8CpChUFbbW+8anpqJtnh1GvJjDBqRE2P15FGZ07X7Za0M5O+k5ruyXqG93dd/s3GCCL7f2lXXaawVX17d1jCn3SLlT1ftFq2Uffzm+TZK1W1ixPdxqJuseaKbBBYiRbKzBxL62a9RcUV9aPIMKc5L5wb+panV9R0G6cru59jgMMsaG4WXzKmqVZWmNNzJDZSaK2lh/L1ia5H6CRXLojT8Gl5DllTAjz0mW53hfdeSQiNJmbp5Fq1Sx6G4ws3btONKVRw6cpikh/yNiSCXZDa2kQne4WnG0NeW0Zi82QmpD/yzbjpirZOau8+cQqV5RuPwGxy1jS1dPgD6Kr9TKkhB3nsplJMIKFjLbFPquVs4uzLLy16nFGgnF2KsZZm4SITzOl+aPTbFa6VXIFLEvkxGkgt0eJl0/Fnn57KSBx6G66Fjmbw8gphNS4SNd8nuuxq1TX9jkc2eypVXXkqVoBsZiuZMQaoVWcL052CNLokUwslEVrNQ1zhOs5nazK6WRbIinwYmQPM+a9FIIuV6IhUnAzGkeC6j3RSKLsEqKnRryxjO7Ycr1syKUzagR3XjuqGPm3PfBYmpcWxUFBd8TeHXxpNQIlp19L/otim8qVn5ZTOnYYnqe23BOc2yOYwmAFDeMWPvjaIc5GZ6mlsmzH9dhZr9VqykVQuunqgcjXzFotWBymm4Hj9LQZjsfb9xejPGbMG6m7jJFgPNQv2iHHyGw2faFRsn0j89g5tvnvfGqEX10yznumZJx3euVX4TChTh3qVVfTe6EbuqJ3ZdtnZ2ehSr6Icjoc2Jw3TqvGPZlLf7JJJxy5oAnie5L3rF5PhiCymy2FSqkN1VE+yi1aFOI0UOfVAcLiTPlxdCV/ZdZcfsKLgleKKa2zk4D5KQmqX8t+kwCdEl+opzIbvNIVhU8NJ17OLNUz647gJ+VmD4jf4/P4ebukXiA6+9V29mNr5sN24a3Z+7gD1e9aMz841TiLIHu+LELRmBKftnfureOsujDuqwsD3HrIP4RO+QzLP8TBoheqtPJGW28j3wnHdcIWn/gZ4ZiTAI34WSktT7gjOo/4ace+HcOCct4R/tHnpM3VSksnECIdmu6EcrEFkG7S2hxhflZC9+Dsok44Lgt2Qns7mZ+qU+pmpSBYKtZJj74gmkcTOEMIOwhdWKwM28swrp1wdOMMYS37b707i5ZkEHAN21iSQ8faS2sWJ+nksWxtXw9zPqotmES5eFtTWAI+FTMDeu1SvIkSSzgMsTCeFDNNNlzVuTsYsAIZjiAItaUUiR08OVhWFJBSmNpcBOJnafKbbXtpKAq97wghmXzRG6987dh3ZaVq+bheUQj7XK6HiPRwfkB6OJF/+AHpbWkmLPsYQjxVuZkgSGQ0//EtF+Hwm9e+eBGBw0jd6TXphMbkccxO8zFTN35ldQwRQmJfKMdb60kwYh0dWkiltFr+mjCEWWcNN7UTs3zWLyJY2GBUK4uxDpHfYtmcWvJwmN9OznLYOXknATuyMQPFdKdTsrcrHb5yPD9NxnMHuvYcNRV8c4QeVpKw2NAMK6vS3pjRK4fqzsw8euBEXUj1OSqKQMuWdnfycSZRhy6SIXSWgtIkRaOMpPqEy66R7Iwd9CCfHfRKtWVEgnF0msEpLgx5TuyhkrCneC8i3EM4HMK+/NHP7R6OxnTK29GM5EYmjcqe3JY90Zlf/HcQNcL0AGEVF6L85rrmG1eaLsUKOEAKxmXkgHG7zZEoXVZtWSZYplNspMyx3fDrmobf1BV8/yiEWJQwmsgtYIMgh9lA2mo1fV90SA+dBgiGPtu5mB8hdHZ2jFPC/9Q7HBrLgRSZp9LlLNs8MaYf/ao5ixY9uEOitDcua2AhpY+dJBv2g7vS3mdTO9fnDIxbVIF5udK02YIYp6d8bHGaMm6Dm/smlviKxGe9/slkMIrPer3+pD+Kz8KTcNIbAQFN26tTwg0HtLLub+PTsHcMez5GVYe3Ye+YED886bV8JltqhzM4YEiI3w9bMTo9HRbDfouhs7B3BDUklRr6I/MZjuChN8NlnQy1WuVbpCsOD6HisFf4ULVuI0JnvWAgG0lODw97J8OiSM4Oj/qDPqppeFDTcA4P/cchKN/yLXiOLTwatMiAlqOz4eFh/7DVSk7DMByEYU+DtNHWmeuJvyayTB+vSIhGa/OBv+5A+hAbe7QzcFQWBr1+Ad2UuPVw2O8FhUxrrREuLdfSNrHmk+5Wv9m1EzklLw3mqTk30ieyKgdT5JjNeJ5VMiDerjt02vpYr/UMZ23yErnunTO0Sbqf/v7D628/v/zw4eXfP3/88Ycf3n/45LpsNper6baWGTwzPCzStOby0KC32Tx1XFHHl+wT+UHRDjEQaXeRpn7tRWhfMmc1vZEsgFXlWfYqTnmeJrQoamJv6Lwu2OgWReXV9z5dsbxxkaW3OSgN4uscROF5I5KdafiOgt64Hm/cXrH4qsHyRkZ/XbOMzhsX943/VsqV/27cHHbvuo0fc+okDbp3DbZo3Kdr800jTea2XV1x17NDpnpoLgL4jo4Ee6soA2+zD5SvlzSLLhI6agb4klZuflXVFVI6scRRlKELNptnNamVVP9uk/bMQjabdFdpmnxkXyg5Dk96WDHmeyKFlIdKexaVC+5vWYyJewSDky7okfYBsScZtI70lASTvNSONcGNya5QJYt0FyxJgF6NnFf1srEd1cD8yPNoQetMnuDQrVrsY5LePlbUzE5dGaUHp1qrQ7ufTeFWi8ItLzuYsqY4XcqFuOWoePdYCwywjGIc065aSthVfSGEv6ngEFSV1IT5SFQ/alb0cUXRrIpz+1VnF+tF6GH47XmOu/g6DZrWJ6aZgy61QtaxjHZ0XBWlmWFzsQr3YxkRyQhBzJ92O5WsueQz4C55OpMMC7AdGbxW447wU1AnZad8Eo4CNaPm6LMyp5oNsVGltqQsRz2zRxfzPM1cRaXy+/UnzcBqTUoSAIuMx9F2qBsp7m+dBe2ZbC9huajRkEZcaUHlJKv51Tr2Gu1IQ+8vP9A60VKqhfkvL2Xu8vxt0MmYJMVsVrar5ONTEjg22pUKFDMKlajDUlY5ME7bxuD1zJrT603DkDqbk2J6vdIgp8Lc9mQ4VfYsMLTOJmJ/zLiWoGzStjXStZ6M5UQ7NvZL90SgREJSnnUz8ttoFQ534lG4+kzYpH/qNcmeQyd9xgjnAnusd8Nh54KJ3Ct5NuWfl45Fm/TQvVH7iXZYynFXLN/swNrvPQPWwb8Da7/3CKwDF9Y+wuatHWLR7j0B+3DwDNiP/x3Yh4NHYD92YT/agn3ovPewaB86730s2oNH+rYbV6mud450SieeN6qceZh9p3XWAaZodGlMMGWKLYm22/4ujaOEagjqwKqUp7+uoyTfPsGvksB6bfPLnW1q9Xru0CiXArJzlrirHtAtyLWN1e6geR7mRHSveta5hxpHe9YGBAcHmKPSh5zffeht0MEl9r4KGx7qiowtfR1RQCM3rmMZqmhcCHunekGBGeuZt8FMCpMliFM2IzUQo0o36hgYR1H+u9iYZ0yH4kBElF3SOhT6FOvx2JFdhTCZk6GtKHp0YijMyM3MQAPnpqTgsq9yOgSn2vysNN3IZEJaOVOqRwDpGuLMwKWrBui11WXJ7Ey2I87cs0KdXDmccEuoBL1gd9kvRvxUnVR1/Ew94IiYc6yOOcbCecmMMRwhHKu+GvE6VTHRS80SXpFgvIJ7JStQpk5XkmNbT1cz9MCIfMURvFY5NnYaSY4tOmWGY3PXJQQ5yffIG6AHFiqyhblAZ0SDnWOCfTLLhd7EsLibwdbHztHB8yoItyoAK7mdPQQ7yGGSMn1EiCvnjVjieHOS467TGgvGjIg9HwMaZPkbxpmgVb6/Qn60QZ855DBnb7ihtvIU6zDJM6RCjTWSlF+Wwjmde2isFg+2rXE00StreyvpI1E00odoKts41XP60RE1p7SpPjFDVn96Bmdlcr+J0wAVhXjGrnPMI6Dv1hSkYgciqUBRlCA7O8k9rM9qjnTvnKXx1KHu7W7ZJ6UL/en17qdbp7ivawD5PXJI432lIucklz3/JDdD4wyO+LfPtjCDk9wtNuCvH99/T3a0bg8y11rB4XkkotEOCy+Rk2LiYTF8jrKsKBQfgjYbbQU/CE6GpYXzq+rpseeNn1CPG824FFSzWg2lH/aOWuDi1poSlVr4D/8D7e1r69PWybhh4MCC3bWW8JtylylqlqmtlrkQeB5mRIwZgMFQ2ia/TiVTYc2+0rLRH0yj5XlChWzo2oIxOy0dso2ZlB7S+u5lUzZr9w6HL7Ipa4dlT51G35pGgfNWDtb32tZp7Z0JoLhmXCjqS9vijO/55lN2z/glWFbFMc3zxgW9T/ncoA7VEfdg+JeSf8Lsubzp156qr06WNOyPuamvJHRxlsq5ZPsM37bNbZUBHBi/ObZ0vJ1ZNmbPAABVbLiMi9vb73d6+zurHGsjhud/UQLxnQWCWWotSFtgTZJYUUg4A8zxAOG0tGiHb3p9mcrbg7LCr55f4fFuhYc9mcrbx5tkG0nVhTOryFg+Jf/6F0WnwURy+hyBaQglARpRxf4TjrAvHBPFCR/9618CvhD2C7m7RwK+EPILcQq+Agk1RtSKx1tfRNZa8fGTjR3zxAryBhMBxsV3r8lO8ltI3uapqBpIzUfwolA72aXlzsGkTJ7SmfbMHUhkdAqutF+Q3uEQjSWCVGXabPYiHbsalV0ov6mH8ps/Bsp2pwPenMKxAF6lBkZZ4kkoj2uBPN5aQUbA1IAqCENcFVfU6NU3Ew73TBpkPKOxXm1jhe4q3LXe1/KeiYCM393y6elx2Xh9y/3enj5DxjNaHlRb9us6bV56cAcdtcPh0dFRLxy+0On9vcDtGRbI+O3AbbU7a/sOlOHQBdPC3J+hXeD+39zIZ0QWCXvH4Hq/ozinVXrr9/DxC4FqEdIfsqU1pHbjZrNxVt3WrO3mljCzCsysBmZWC/Pv2eFh77ilh3bSCV/4vcPDjpnuEI32IoD6bf7YLhuXJGt7wZuO93tHw+MWnwx6J4OTIDwaBgUf8T2N7yzpZzfeDk3zv7Px37nZn97r5S46Pe0N9rT9u/ay7W9vUDxnF++2DWGOfle/U/jeiIXNQPFNe1r4Xb3baiHc18K36foioc/rxPETnQBebV8Tz+vF402EdU0Av1jDMKn0OkSLM/RASZtaxKV+sqL4xVVLVXAMR50QB+bKm0K4cEonl4fQd3gABXMXoansNpsRepC2eoeHVjne5nu68c2ebuzg33+/G7wjOxI6HWmnpiudTqpil7GtvqSyL+x5fTmu78rxPrVgpTuVfoS4d3iIA71tzYBj0Q73NL3Di9nWd7D0swDoYbD/qgFBDUs4I3IpH2PR7u0Fad/c7uDu3wuSBsGCZEZpH0g73JsFaQejPwukAQZiMTzqnThwtfsKst7AJPRUQjjcHb6t+R3shXzfYO7Qg38D8m24w224e1tj3n8c8n3oCCw/StCamZJn0yqjwzshGlc2d9oJcSdVGmAGsV9DnD+KmiKznakUbgPl3CzQZwISVXXCGbi6C+3ssRnx6UF0dhagTv70xt+Hq/6YPnJwfrndSwmjwVtM4a0nO9r+Azr6uzBZ2DvCHcnLYqpVEr3DwzZth8/Dbv8GCpMc3RHuAGP3+/DYv4Gs6hv/LRjr30BL5e0iXLlL9MQY7MFWDj7bt81/LxbaB6hZKiWWqq6YPxZP1bG2Tge+KyFuBjuHh2UN+4fArSGsr6GWNXWq+OppIGpZzz1V7EIRp6v7ejz2DC20Z7XF+VW6TuZbNhJs4fOi8DkJkOTYAnUTyc+2DsfLm2tK5VjmgLcS+bGUoLNTHbgF4ax6SXbL/ky15LbhlhR7dcbKtOCjiDJRVX1bZXNR8LNKxc9XPsPp/N6mVXiX13y+03DmHldC/yuDZ2+JiNOso8anTGpb9xVZh29brNQ6aag1eJNL5GcmrhifQNvlu69WyxN2cgrllMpj+QkWCKfVlbhgSVK/Ems839R7uZnI4dF+891hGu2aE6ultFUOu5fudu6U77mTak4wnQMY47Ci9npo1mpVHe9kv8HxTgZ1hq61pWYwtlwFjn11oqzO1dPTsHdcFOawGK4AAqZNtWusXc8sEwp3MkfehQpm7mTBl/qWGlWOt8HCxRnKU1F93Xda9n6PfQs/LS2EZT3q8ps6x1IkhTi+FJyWRlJCDLC6Xh0gXONyRl0/LE8pgVpI6VVZRdzAJboK8pvQkbVgyhDOy6AMGvXk+y2WHvXNYfGnPn77GunLkYGEriMc+NpiRqIp+1M+2zjjos6qvyUH03+2D4LOycvOP6LOl87n2cFleXT9zi8Pj8aCiKIID4Kxe+yqeoNTdV/LueCm7xHChfbd62yHh72Tw1aLnx4e9QcDc58YDvXODof98AQ9+KJD+uisE7Za+p5br3+Cw5MQh8cnaBynXDC+phu28CMdfvfZ36SEVyrgp3Aj6akKcOU7ri46tf20AxebwN0x76ia1N1R8P77KEhs4eux43KnqQETHRKi08CErNWuYpFzBbsXDMqyvd2yZ2fDIjzp4WG/xQtZr/MtQG0/7td9HPaKXm+AufI/KyvYqgkmzOfmdliNBZDx2Bunc9pYpfYEXLY5qG3zuOgNQE8D/m+h0XoArJ1XeYz6xrlUkbmOv6tBCBe+T4lPiXUpSjwIh6tNIK2J5LcQY9egoF7VAcPYrHqwHR4j2iYeKaOrbaoecL6UBKm0dgjG6anE5n7alnyBZT9S5y4+mGOIadrmM7icUGOT8E1VV+h62BcmbgM13pYkOdZRG9KsNhFiM7Zau2lwO18+lE3/6LqRbRIK8uevJRUue0uJVzqOVs6lPSwct4xSDtW2/OEQjPBLBBMOX3Csxgvy5IhkoGSb8lnbHRax8dEGDwbHz4tL1b2UDERM87zV0g9dTu/EJxZfF4XMzql4u1zSOYsELQp3GemoC+la+BQHaFPrJdmdmAlQHNEVV5Q7Xj9lCecVPVDwK4YF2iC0QfjRkroQGonNBg/C48GWR32Fs5vONzXD8LDZjn9jJzitTOF0hpV1+LYV9lgYF5bc8Uoj4PKEvU1hWKcqV0NYUZREljBEDaKzForVOydcXennFf4lIqm2/VZYFI0juYRNICyL9zwV2Em1BLVYU/RHIi3apZirQD2ZidKTo1aLT/OZbSvXUJtOOCE8S4xFtfvRhofK4AgTP+1qszeS4nItpY7XJ5+7W8tiAut4eDpDSDIuZXwYBPvhKOyFWwsjoaLBSdP3vn//+dX7795/8Bh/2EB88zfvP7x67SQWRTMEqpmLRkZgO2U4ReSMkTM+oW3/Xz5rE89DTpiIAZowi0fhLgxDbTFiOIUKEDnL/P/+X9OvHuhm+d8YnoR84mVknv8+P78LL87PTRaEqLTfoLHoKs9kOam/R/mwwR7l0UUCYSQvqRj5iJxxnFMxouSME7pBWHQzmlNBUj8AhWb3Ik3mJPO9/zUNlx72/te011t6+ABAkc8HlzoRCsgv5mypPug99UFPfcBElLCYpH4f9/oyYc3nNEsYpyT1B7g3gEL8hma5TDnCvSOZcsXmc8pJ6h/j3rFMkFvomkqSu768Iql/gnsn0IUkiq9l9QHun6guzuVrqF8vMwr19Hs64Z4mSXorU/o65SJZy6b7A/2+jC4pF5FMOtRJ8X0ElQz1++0VE/DNkW0mupdQGSguLr/RgA0CPNBJHwC0QWgT/qyBG/Rs0t8NeIO+TftGATgY2JR3FsTBoU18pYAcDG3KzxrMwZFJkkB9k7HLK+FCm9F5mVgZuTK5On5lujuKZerWWJYZ7oiWqZVxLZOPqqNpM8KgMqhO+tbYOjnbQ+xkVUfaydgZcCevOu5OxtbwOzkwCxscBoPjSpihWlpasfUE3xGSI7DWpqmhQYxwMFUF3zs+Q5PM9c+eYYZG2tkAQ+VlOO0wuEJsqhRf838mOCCUeGaI3g0+6Q2HOzwJ93u9Xg9h7oeHcl653zvsDeF3MOhD+nF4pN6DUP4eH6nyvXB4KH9PggDyh8EQvusfhoH6bgC/w5NjXf4Q6h8OB/B70h9AfYeqmf5RAJ8PgmP4undyYr3s+8eHR24MiKyrvGxucD84OXly2pSuxeqKdlzslfKuvTPb9ozNbFQTdZzK0Rwe7XJ4Bt4wDPfFrAAveaU68vG2eUNzC5Wmw35NbEzT9OFQsrEp4f7RQE6IXIrhIICrMLtLqbzXLmUD428HJyTzBcKSRCRWtbQmzI9wrOyHWy3eJHo7jOOz9VjyMn5OEgiTg5rEBgsNSvdFUHCtPBL5tCjWkplJUKuVTNczVyMq84oi0J1u0larE25c/vbB3J8ZRX4zQFjTffkWyrXeC052A5WbITo5ORqoITruD0M1REcnct1FdthyOZQDufITMp3BXsVxZQDVZg0JxO/uyZ+Y9OXPmgzkz4oM5c+cHMmfBTmES3ar8fbAX+ElvsT3JWa5wOBo379CWNKcO4SvSebLQn2EX5PIv7VT8p4E+CO5L4ocfyZi8tG/wq/RiBfFHJ4Dw7mNX5+9H7/XA78oivdy4G8lr3VDrv0Lcjt9P8Pv8R3CFMkyAn2evp+Rm/KKzpZ7v0a/vL4N74fmGsWFeh/aaxXG5U2iUNFnfKGVAFs1Duz9b/XFUeULXdtq0glHcVGsJ+vR5+qK0OH+R7EfILyMVqPYDxFesETQbBT7PYTzdElHsd9HmN7Q7H4U+wNZgM9HsX+onkDxPYr9ofny/VqMYv9IrqkwPNkfsOaod9LXAWvCsKfXVP+kJ9dU6nv5isYM3Iw+GsmGnZHDsCiaVSHrRjuX0kvHF65gTB42aBrNdtlycOkSSrjBuwCd+d8oPSjqLtJUCm0bLFf4o0gMetQPD49Uj6BvT/WmlPqMfOBTYOt3MLDSyJV9QUXBm0QRwFarmfq8pGhokvlchyRVggifspm6waFvWI3sk+TinXtVE6hxxJEf6BBLQvZ+0O8NdwNHSmG0JnRwzWyZ0wGkL30c4w4gn+FgP3oOhyca98jWK6NqGv0USTkjIvb2bu4Rkvq7cpeVczc+qpDHSVofD9NMSBlyfuL9aF3qjEyQ2IkKvb1z5uAKfzDLIru3uoWpmJXOfDYbX2iexKcIM4QmfBRNUl+gkffeCMB+RmQKqj3IUYNL6cQZhlEmCe9JTchvM7xDS/36x8d60Ya9/lCh9n5wFOxfswvrxUNCBTryBU4I6y5wTIJxfGpDHsaGz1sTPo1n48yneI2KIpe/OPEFXsvttcHHxzVqIEuGjo7NBpNwAawnYTioTuX212ZPddWVUOaH4PtspxVnXgjHwLGE4eBJXqlUF1Uc/vhhiyIcp3zBLtcmrSfTbjMm9PtAvsMxwEjI3g+fHa356NBgz/1DUTeMEfApYwhjTidqTCLM/ECOyYhKvMg3G3zUqwHE5S1VYBJYO7LpYSDZArtiuos9eEDhC8ONFoVvHiVSHqe+wBQVRSR/8YMaGCZhRBvgx4+Ow8fpidPsFknQs3vU3K96CJXKoeajzQZNw5mkALj/CP4/Oj7UqAooASNZd57GsBWBqDHUaqU+68YZjQR9nVCZ8wSBiyZb5X2KIDw0Pg7D3TDMlqkNgsPKtvA9Ht2wy0ikmYflkspeSlnQQ0XheRssKW99ZeD90PRNzrBsF0EAQa1+xQnJW628e0OznKU8xzFJWq2ke3M8jiepRFqx0dp3PYSmwex0MAlH2TSYtbNpOBtFrZbf9DMSmbhQr+eX9PzAP5+30QFCRSFLnZGjAVj2l8VeXWXp0ikIt/AziJfkKONarXa6wUd7pdWp5xBUD3tVvaqHPZY7t5w87K101tv8td3wHvaqTiogwT7qEBTebIN7YXDynBUkcXB3AWMvkaIa+7DfCxSr3T8MDiFgrC/RO4R89QdH1Umv4TDwGq/wHC/wFaFdZf2Al4R2L5P0IkrwJaHdXERwzZqT5SQbXU6y6dVMYuor/LBBI1+9PmyQw2lIQgCiifI4NCdiup7hFaFdnn6CRv5MxcRfkNTnEtO3WgsVlWPEZcFm7C8n69FV27+ceF1v5P2Hh9prTLuLNIvpHBkP+01CVtCApnhzS/tWyBzujRN/jldo49NufhUti2LVaq3gEbVazJ9jTz57WMpAkYQGzzEF0iMRyJPY3iXhzSat8ccXbIDkHu3nfKUI/hieZgtfyrvY9QmgadNYiwBciwDBaFs4KumYvuyMNko6CHeK8p2ymJvSvd3SjrPUsjzOzBf9ui9wWvsNTkvNeh3kRjnu+IORvHcQPIMoqS3EanBpXYSSCTWhUJ46C9o+PzntTZifTekMFQXzU/kwkq+tlvw7FbOiSOE1Va9yhR0f7lsVNZgfDvTeReKKgCVpq0U3VYRuz0V0Z9Qe/nTF8larfJboc7fsLePz9LbVUr/1ZXKaLFot+bc+n3cvWy3evUSOyq1k9a+Y5LKL4o3J8pwcD/logyX/sB8Vgn4hrTnpKgdBk3KV7yr+nHlLtecuuaNAiOkfBuGeff4gZZyT/QxoDVU1BN7D9lETag9t8GBYE+5tl51VsjADyfGoysSAVPdbGBnme3N24yHsRd5jDE03An7muD98gqeqyF6ep0h5ZRB2wWtqUcb74gGd2KGXfoA2CE1qNulHI0JJIVgyP8qezPPQyMpHG/24wb2j40c0e4PhoQTfLMFSSq3RbWbG89FHMMyTnEY1pW6PplZb7LIcWx9KcrCP5quI84C/+lqJphBYYrjI2DIAa8tyr2zn5jKtFwQILxRTECJ8RbTE2IiSjEbz+wbjTLAoYV/o3MNLknd/ptH1u2glyXxUFCug+Zo9vyT6tSh8/QRH/kuE78llVzIMF+RS7jl8Q+CwfZxtYUy28C/UwFziPWakV6U7re4iiqM5JRTf2I+wQFhscFo35vdl1ZIP2dTi+oYDgDpKhs7dkbnvQZ88NF5M72akGeAa8Nc+xXe/AfJYln8MaFXhhAAAQP+/Tu9mo70wq0IbJ/r+Q07FKAPfsSm+ivIRw5QDVzSq+Z7JHZOC22+fSm5tI78UNHuTZnXlbZLVP4ENsC8QmPCCqgHiiTXLiHiOseJbDm7BBLtIaCNTnrYyrByNWXe/nuN2WRLxfni4X4ACLOOglqcPdiDHIyRTJzaSA34Smx38R3FeMq/n3YPKbJQ+F/Jp5FNUhq8iJAZ1W1JRzTmmqFK0HjWbAm1wRFiXp9kSNl3dXJfORs2Re4qleFT1grMBOWseiYg8bEC18v3LT29/ek287z0cE9b94f13f3/z9rvviPeD5wwc2+Aw3EflaoZxm7TTibIyInRUxzVtNjg8Cfdxy81wg8P+ftlUaXnTOpld0w2JZRyKr1QE+Q4pvAELF5Xrm3XWtCNbFE3fkgzHwkp9ILN16DkpEbRaWauVnQ5CRRUP+49wJlZIk9RHyfkGoZZ9qRk31mod8EiwGwrGdTqWcuozUCzsYTugoZOhUfIMIc67OnY5tqJgqAjG4ERLgpKNUPRC0gbfe/v68w8f3n9670na4YzgBs/rlsNpHmdsJc5gK5+eH5jXDV64X4MoRAzb052ny4jxVgsMxGLZzf9t2IArsUwWLKGeIy+B4RnFYryoKO3kSlK+Uua+5yFJV+MklZtBn/bSrnLq/TOwrl3VROlFURlibfwMjXxfkNj32CKLltRDqJuL+4R25yxfJdE98XjKqYcTKW5QPn91xZK5L3F4N89iE3PF+yW6iVT/Rx7CPiVwmCBKAEz/UTddUe5LgC38dmzeaG6t0iFMu29cB/fWxJh3OmM0pwkVtLEoUdU0mvLSr9LCR5txPl0DDdvhiZXOaJsnvnFPGcwWn/irsg1guzAHkr/Cboay0pLtUTTiZOG7EuqEj5jPFYM9DB5R59fqcGF1g37j5HBY1ebWMbmM5qMtku27kQJwRiKlkDZepHBCgnF+loyRUnlykk2TdnuGxZTPKkfFEqpnAC8Z+23glU52j23TWHTlOs936mYLn4FsImEGtQSDqLrIOSvIdWFn87CF711S4THe4EXh5fpxl0q/BJdUaaYOyF0HfXqzKzN0+XGr5Svtt1LOIFCCh71HUGE5ICpAhFVDw4Cok/XcDk1iGdjYDuGa1KL8b6nac2mmB269PeMLn5JIDVyuBy52x2wN5aojBhdTrJ995jfTbhkFCmHZeXVu+YhcWpoLHAeBVtE5B2A4Ik8I261WbY+/j5Y0n+zP8rWoPprOyg3SXdTqjFsta/GikNTMI8SIUlWpyxkxufO31VmNSB/Voc1GMpYpCNJykGTv9w7SsN8bGJuKY6Rdk/sm0iaoUBVW8RDM7/5u13F9DcnepnAcGx5vW0nurU5zERssgdsPuZ3eQ3u6EfbDY2spqU45JMl9QtOaK1SakADHJqQ+bzDeyFEz8yPMUauV+Tn8xtaAFqw+jF25RFhQhAhAV6jV8v/F/BhzVBT2G4u/YuDLHlm71WnZVaRc0/unBrx3Mtwa8J3zKS73Q53Qj7OnNjtOSdZqNblaqg/hqLfBoVoiaWXZKlYg0/ccLe/XFK2W6JbncJsR3+BejYqg9lCtPGoeVocnmzg7fFefYjeb104BItT2Zp4kJsfH+4UdUCaViEQfbB/rczQgK1VV0we6SCRewV56y/+L3uceqk6WGhRJ4SRilFScdReW2k+E2YeysDI/P35EGAM214VAcvWPnCSXbLFSVzC7myJ7XpFbplmdXAQnkhYkoFVYk6SrhVu8MuyXNuY250cfzS07f5/6HOcKogTHpNmUMkMz764hgACelynlEsGLMtU5rRjX8O+SQO5cERRFITkfjwOPWRSpfZEkxU/IWm7RrrruWRR+oh/JSpuU715pFCPJ+CIs5e5s4seT5qLVksSp1fLnpBmgkeYNZRqeTxTRHqV6RtDIJkVKp498qwKzmNc9n9pV4NXJt6BYjtUCt/3J1TtITYPB8dMmoeomQCXKvsOtvIr416Ihd39jScVVOm+kXAX8dHm0w8ek/Ooy3IukJeFL/Qw7XAJHD9mUzoiw1+0UndsvyurT7q3T8DrzlEfOeygItpTwCR1RZ4IYEAiKGX6o2hEE1mYA2O1esH9T9vqBuv3mnxzpM2nfuwbc8YRh1ZTOisKXP0DHlPHT8DnjrrY6I97nz3Ga0c4v+ef8Ksro/PNnD0ckm7KZ3CYMP2xcIKINltDubSA8CY3B2GB4uBcFlLpZ1QP5Q5wwQ2L0sJE7wjPH1R6ezpCipQ86beT1u+GgG3h4mc7pKJt4q3VGvZGnjlU8HKere7CIHnn///9foxf0wsa3lLO88cM6v7qOMnrT8L8kKcvS+LqbrZG3QRscDh6ZqJOTQzjuUP5+ozsnAM7jfAaoviySPw0mqc/bAgeoFMgOHztnURadINMMjo+fWBWZb9aChHe0S3wA5piyBGvXxYskTbMnllr+ffQ9+FBBk2Dk07NgwkcCKY3e0aDGBrt+0PaMVHmgdiYHBw6CToLgKDw56R0OjgbByUmIRoFs6yTYL7g+Y3S0tsNwyFLo2b+a9xk8a+GmWQmbrvgqnMJt6DrrLzAMtHefWq1m5qeEG47fVgQV7Pla2yg88XHz32t+H8JP+Q3NhDbeboi0scrYkoGqTMmnIJcN99qTPmzG2bQe886I98VzFCSWW/sCFwE0o5GhDZYosmZNB2YtZxGfp0v/8VXgaX2k19Y1u7aD3oiitoc+e22/3RZtjsrLZv0hHE72g0fsS/sVbanklCsaTC+Ht5Jk61wmaBaJNNvgYfDIaR8MnhK3pWQV7rcHdzSgQF+qrJ6iNLkGGDg92S1lHe/dXueeFPuN5RdekWSyHq1brXX3lomrdC0+wqFFUURP4A0/xmAnmxfFDhcVq5N5P2+1mL/GFE1kCllP6WwETytfz1RXshcIy8TNBvd6vd1+10oLvdCQVvf49vBIa7LMGKhz7MTaycdyrML+odLPKov5FXwghY+5tYdeWE35FZn7HstfAfP+cZXRaA4mRwgvyTYiw5fEexfdseV62YiSJL2lc+VjoUHvYkrndO7he7LQVtN16nRrNd2g06sZaYaYGrkBTYNZkxC6QQhfyAFU6R7CN9sMXjMq0VczNJrb6dWsalELFLnZFCMmsf048x+UTdJIH+xg4IYkx6NMgUbN+6JoXmyAI4ojsbtbjZ9xHBHNmuIVWfsRDhCEeAbfWqQT4mwnLtFYnGZwK5Yt/BufEYhALSbRyL0eq26yztt+ShLfhOdC6Gy5w8teIidUWTrm7Taet9sIVABMMtIrPMdsymflxfz5GamtB8q227i8+7TSLZM5Xm0kc9E/ekQdo0Q5EDT7yM+6f/34/nvsyb+eCnMyqCF8prhEfdiTf3Xh8LD/CJdmZWhlqyZ3RU9SzkzyfNu3rlwhhOEHJaeNmgGwS72T/c04m0/b+2hw5RpSXJqsBj9ooXn0sNkgzPy0qxNwKU5Dp3qDwS6xllu7f4h8L8rvefxWo1FPAndcYwf6BJpQytKqMeXQqkgBYSSOTBFb2741YRpZgteJWuvvNdhQenOtSpF5jDfWjpFeUdg9t/ZR1ymJ1LiuSPU8yGCEHcun0FTlBveaBjN1Wz4YaYrmZiEswO2O6+lgPuH0FgKCjhwaufbRaF2ytJ6nPBf5KynRNgOExWYc+3O8VudBCzJ3ziic/o4XlUsfcyh9RRalpnZJDK0WNBfIs7zA2vdkiocQviQH/1SFzn2/+wKdo+k/0az91cE48Re4Mty7UtqW8Y0aTY2VlAMbzXP5yv8yFuTK8ExgmuGvsMWinlGuLSdC62SPcCdEI2FPkCEumFcZOW7mhMv17+4Ni1HlLlFdHM1BoOwNgl0mwW6Fqyh/q+dQboTjoxp6aQvXUa0N7oU1cmT5jbPNeoe9Xaz2FDW2CEFp2CIrO+Z2EyaGOYktc7K2hHxl9+XckvSF2aFX9shnaYn7pdUW39uzjgt7EnIDexrhO3O+hW+tzu8aqpVpr6327729gfHRnpJ9ticsL61+7ZXFsR8sI/bJmgP9YA+G31qW7BfLXHxvbfa/I3rg8VcGheJvrW7unaw5OOmhrr4sht+QT76n7rV7CH8xW8jD35BfJOP9g+HbPYR/JN92cyrwr+TbrjVE8b8g/PPO9Vv8E0kNQ/gXwnxNnDRbxxb3HsJ/J++7C/w38rG7wH8m190F/t/kc3eB/4t88DXrK1nLf8jXdNUpU/4KBaCmjkh1RiejlywXmayZ0rIKKKHKOiUElFC8K6ck7f5N9QBnlDQ5LYomd1Q3W6/dBdPHyzilJG+11nss+m78v4EPhP2We39TGm8ooZRAR2DKt0HKoG/n9ovaH3/3f4bwHa2W1hz+PBUz/DddCOuoxT+3Wn+TBXGGNqO/YVYfiuS/QKHi/+SQFsPU/ehzrIIxfcEiuhxR7CDIkdggnBeFz13aQwTCfIMjSuI6a8BtiYZuRjWSQJ2Vx08bnG8HW0MPlEA3c+r/Q3X9yrfxTu7VMaLpzJXPEV75/4UzNPG5ozGe+Cuf4jeo1aLTN7NpNoNzU3gizRBhTm7kODi3gS78AKLBITTS3xaFHPw3+MIP8YPkp20FAcIp9SnOQJP7N/20wcn2bFjIObn0BcIZufO5PWubU/dk6J2fVZ3S5K1W08TD4ligosh1cBo4A5UAbfCWzaNi4u99CoetnPzvMpxWGRum6Wtvgz+3WnLwBGq1mis52nA/o+nzomiuzEfw/F/woNPksIL3szczCUlRyL6v61fipU9lt828sYXP5SrWlWZQ6T9wptmblPxdhZLWgKaVchxa5moWisJPnQlXk7LZ4FXdgPzZv9SnLaXo9M4XuOLASjZEoaEf4JcrhSOFoeYbPK+rGRYr5uTPvpj8Y6RaySqt8GorTdOMgEH/GZ613wS5baG1bDNOisJ/5fs/ubyeDhTpMmg/7ernFYour/q7V2fUatzlF53rGxVusY5N1JwgFuStskNxu1euLK1a+gemcovahaMep29msOz8ch3Bvkx1jFYBu44iKXCqgcxbrYy2WikF7LfDx+VUjLgUHyhcUHOvvjx+itL4VZ+WiOhSDv0r/yfsVZQcXnUCjWaD+tB9tTw+dxckpvhjd0Fyit93F2RN8W13IUkgWVH8ursgc4q/rzcGYNT/RdeF81bL/5uLuX8jB7vVK+dbyV1GRfHK/3nf/aiYVuQ7tMWN3mbRyuVKE5xfRctRMym50582CL/z73xBUXXUvtP7qFQffMG5iESlvg1+WGyZwapdZu0FJQJZ+X91LET+OhUzjWJ/8svwV3/VV0TplM+IkNv3mt5v29iCEoTW+a2grq8MTeB045RiR+tLISDLOqdqrVRngkjGXeax5Sqh23mhZveNOkVbn+0Oix7mfIMflMnYqIppK+oa0IfcSIEtof6NvlGBq4ZOo5ziHWuthOJ9R/6jNX0mqBtgirYNREar7bq1ocdo/ryKq8zY6+7CD9Vx5kN9tTV7TH60VFp/hP/SajmNKj52py9Fsa7Rvf1krVi9KV8nycxrkr/4SpPpPWzg7SEa0Y3zbnkfDbTlmHfkJuuIB6dkSmcQImMbV5+xMUq1DzaLl1m7PVPejIkka2AfblE6lQReLXQ9GnNlQC52DzVq9BYZOIDOHFYCTLSwrLLciJJ1TKeh3G1/cZ3GpTDiDkKbfjMripcVFPeNm29POfBX/k/4C8I/TN/MYCsNg1pnP1oohRunL5NECqUnQY2OvlpSFusfhrvHfbaYltmVLmnwSMGcRpmqcHhy/IiobV1MSPn6cFdz5hRMGFxOGg4HjxSriHIbfNIfPKIUqBy4bPDhY7q0Nc/jdCWJggK2d/LMO++DIFQGM13uZ1rfPhwoCb/LfYZ85Kc+QuNILeAp7bI59rqr/CG9odkiSW9HSnJtsuUqzUTExdjkdCIeX6XZiKecjjvLvGMzwGhYpYt0HV91IgB1FK1FCiV3UjfdVf75cxaxpHP3oK2NVQXpKoqZuB8FY5FFPGfwyUUUX19m6ZrPO3GapFmj28sbCeM0yrD+wEkad27pxTUTnd9fwxWFo+vwcHU3vkiFSJejYLxKdWXRRZ4ma0GdXtz/39iLWzYXV6oT6ih+Tx86MDU3tHN35swLdnPuz+r6epGk8fV4G6oRQKxM0GX1oyu5Urar3km9Vw0u0nid78KxnaxL53GWJgnjl3Wwl5lV8M3sdIcSvIbznQIKV1Pva1PvRgDSTtm61DsAJ05YfM345fYnlcyHndH8D0rLBdU9UYtOXK2XF527mtJRFI0v0mxOs04Wzdk6Hw1Xd89dhmrdQwqNctphvJOuxW9dintq0ZtqWO6p3upu365SHbz/ozsIW+Lf7V99JWq3De1me6Rz7mI7c+cT76yvvdmVVdN4YlGcnJxYnBau7jY7i9tt5h7vrOe92XuhqJs5CYXGSRKI/9Sm9nnDryEnDYlI0UOFNknSUVKmzeY/wYdxI48zSnkj4nNV0xW7vOrEKRdZlItRQ6EwhOvyntHIOfew52Fr+dTHyrIvH029W3qxiuLr0cFB94Cnc/p5mc7XCc0PVjRb0FhoFHQRZQdxXpPajfPcm2EObPp0hpfRasX4ZT7yXr7880v89uWr1/j+m5cvX+JXL1+9xGn5uC4fWfn4q3589wb/XX77d5vz0T7df1t++do+/qyeXr/Ef7NPpuI//+bafrR1vK+rLf325evXOLLFB07WX1++e22+//MbfA3vv36zXfW7NziSMJkc/vqNbeHX16/xsITr1zq4fqyDq1LjgVMje/MaD8oa09fbI/HafXJ7+ueXf66A//P+LA3S2zf411cSEJh9M88q66/49nVNlmeW5Ct172o09Q5enGfnvPGiIZMixmnWgH2lUg/kjyRDD/DesIu/odi/hsP/VUsYLhB2js7bt3t1doX7awBTWH63J3Mj/8j/th8fzZ5pSMyjOpNXe2NQo+mVYVNcYAwhbQQGuhLnNx5D+o0aBkt3Y5d6/M6aNIpuAMumkg5eNMQVzagNpPK1op1fN9Ks8bVIV19DzAyn82o4Gg1NYxuBW9cqkSSrMU/BpuwKIox8bajU1/ZbS7cahnBVZ8WhAP+fHWxFiR4fa6DkaqgTuhBbY31vx0tRfNvNP3SgS+68cebylHg7/76SvzsxilvXi2ObODccpn0HBMUj1Ddfk3dfggbcwz64dzOdLx3Oft/3Dn9f3/Vy/XWHO52q4ft3c+735hj+v+6bfTlbckDNp1V+6mHfZIFMsNPHkydRJ/Bme3Cn5h4faVRy3jqzwn83hnYLPXtb7pERzn/fJn+0NoNVh89AqmZ/m8HYRqa9/ylkqrnm/0OjXy/B/M7Bf6wyjWQfG3qNY6sjv4Na/8cG3kUABosYcWu7UAVh7Sm0Xy57ZG6lZFRdrFJC2ktz66C9x9uFaqDdKbRffnsWtIaG7gB78KLx7mPDCnhqRp4j8JlmHebUZU8lg7jLnG4qbf82qbA2848AxZtprvxDmoqR521mCIvuP0i0wf3h4LBySlLR5tabdN9UPTY3RBnkZff8EUznltGqGpFHndNR55xOTHuziacHzDOWETIVe40Hz9pKcOxtPDTiG4T0nTwPbbDoVtzCgP+73bCEEBhvCqc1mGLPm81MAMaHDRyZ2EA0KsKbE7duzIxX3IjogHTTYDZWbhmiVstPpxEYhGxsLBsSjPMyekJuvgeP67ozdJrPwNInnSbTYDYrCp+3Wn4ix0L+IZ7n9BsWUDkSsgAaQTEu5xP06AncZoFoRUH4yMyajIZQBz76lp8oCnFmg2NV4306zi8CnDmhpQQa81Mx5u02yqZcRY0y05pt9q8hsP4mfkYGeOswthqRyDll3ficUFTrKQMMT721dfjcrF6saLXodOuKxawo6NT7z/+0Rozq4EzNaenSxcTbawY4J81wLLL7B2Usbi/NjJt+JDvCIbqVj1B3Lrdtq+XryGuZ8dLQFEVhLNGbhAg0lhWjcXmXP5cNpYRuFoxHSXIPlx8jFWiMEN5VQ1EU5slHtiRb+CbSYerEb9uAKU1l0JQviz1xOqk9yYOS+kxn2wpwJwiH6yfcnIy+N94VSLYV8kzHQt0Ogoaw9y5aeSoUrfeRqm+Vi3Md4hGNKr7DZcGDf/qT0Y+seIu48Cej4yIcFv0e8iejV0m0XNE5UjV8pd34ZGii+mYcSu4MEXqojflp4u1FQtDlCi4/zanqwDqjEll3YDVdJGWcuO45f8sbwCjJ8he0YYpg+ACirurbVLliRq6iG9qIGjsL1kf6pm3XQxsfIcxIOg3l4kyn/Vn9fbHGhUhN6Asin/01p3kcragPkUvpjx/evkqXq5RTLvy/fnz/fdceS/sRQgjhhOgIuO+UUvDHD9+ReSSiUbRaJSyOZHsHv+QpH8dXUZZTQdZi0TkeX0Q5HQ6wxWE5wjHxDl78R4ngE+w1XhzAJaNI31PeJhelgaH8UpWRENg6zIeSuhWFV2JIqivfWOO6KbO4d22LTeOZoSXn3DPXNmRRJ3GDw+PDbf8VGouNywhiWY0vKb9qGbVFYT9/pvk70NWSZqAv3zxsMN/dcFXXmnWu8Opuglv0OKYQfJdv1H4G7wtzmkT3RSGKQuIcbc/FzEOkH6wXo3J3GFogdizIMCeGLGBFAwUQPz7NZ45NWT4bp4RjBtQUR0XhR8QJ+VcJw6etCBhOEU4JIxH4N9ognAG1S3csR/UptEK6Gvqn7KWUVUfWvWB8rmymTLfrfXdq8zRt2UvxdvWl6/hgA955NpiRpLquFZw7dzZI/aWNcDYRI/cVp2CMEV/RonjY/LZZYuUsqVCyYhy124hJNqZsI1ImVbkxvGLTwLpgakI42G4c5fQjBfnsRpLgnORVv3gIazqZ4hxN0mk+G8k/xLoOlgPJ0GaDJCiJDxF8KwPlRnnU81ON3FjeI5db3fI2SWWXEh9i69LunMZpppxmckJxDaLZ3UZ0IvPL9aJi9D2kaokR7usniOOufCYjZC2E6uaE785JSkwIRqxDDAPbmU6ZOydMzUlEUsNbakYgOu3JBXLWm2QjivTo6q0MgaS7S7pM2RdKGJajcJGueUxJhNWgkhxSVYjEB110xLApOIqwLDbKNxs04WVQRDFDI16Ni5ghcKBcjT9SwwjWGI/QqqNgi+1MxI1uToXj4r3Ekyx/k6VfKK84rnFLpk86tGGmxCKj9AvFUdlmlOAtd22SKtZwm/qmWqtl7q7FJFFjBU5TLL8zjovCj3cwl13mZni5XOmsKPxaL6RUmXL6tdGvZOa6KPw1qd1KnN7WuBqBpaBbp1hZthlC+RSX7uCbwJKBUn4QpTQkgCAIKSuI0mmnYVkr3N7GF5IJ2Sg+dIXn5NrfjmWvL7wgvKjJXKUrhK/qMtb5FcJLcq0911R4W4vAEL6sKwGmYwjf1+VpezGEL+pytW8qhG9qW87YEuE7cu2rOJ1uFs0FwrfEXxHLkuIazLJr1Y2FmQwTA5iCuCakuFZillJsW/srCJBb4tJrv94X7SPoLDPo7Cyc8E44CiT1DsfpKYdYgtk07YRu82WY4Ri2Q4Y2ZSjk1xDb/UFyLZJzXydJKZCm1nfgOO10xgrjM5LJGusEHGYk+aXP0DhqEsJaLZ/7UgLw5Vckkhg4QhsqUW8zsJFlS3jel2qMHERGhDPDLkm4MhViQfVkmqlYTtNsRoR8KZe8rfCj2pzgU8x4exybJsBdENLhfiGu7iW1kQau9ese/t94CHRKq4QNVa54t2e1nGiJrdKEdm+jjPveIkqSiyi+1jHzF2nmYbmgJC8GTOVnwvypF3nYiy4uMvkTZym/X8qn+TyjeS6fMgolMsFiiMUR5WwOv+s5Sz3sXcj/cwZ/4Z1dyr8J49fwm8bXv65TIT+5SOf38ke2dbEWIuUe9uKI30Q5PGhTeS+mHOz3vZjBd1LsgZ9E/b3M0vUKHuHQ2sOeFG/0T8JySJnLP4p1gNgjc5rAXxGxRDY3X8im5ixK0kt4gELsRv6FkrIWqv3NY4/KYVkwmsxzKuDxsgQYOEkJ4iKFwos0VR1YpJn87iqUf3ryT1/+Gcg/h/LPUP6h0Vz/wEdXpn9X8CaWEhw5wGwpIWV8tRbwK7txfSG/TaIL6F5CLymHBFl+GTEOPyv4m12rn1/XVMK6pHytf5iA7i2pgppHchR4ChMFg56uhAEqNZ1O10IBIlNXDERq8D+o/qaXegX96mEvk2UyWThbX8g1IDPyaCmTcxrrGnOqnbDlV9E8vZUPyyiR7SuJUT6sohhgzFcR15cYr6l6SCEeDOiE5e/6Av4ul1EGLQL0wkSU0WtRyMESdLlKIlhqgt4JveSFnEX5ewV/1CQJtoRiGfyJYjmkQpaSQ7lOIB6NzLthcyp3w+1F5s0QfglbLb+RAMJ2SsRlcr+6ch4hBLx90zMScbaMBAX9efm6TPWA6Xc4cNFLLWaZ2qdxwlYr8CzgzekCVjzNY1jTCVvlsFohqmC5bCV0Biz4zQCmq2uacVh+0SWFtcXNT5RdZtGcqS0iVxhUt4zya7WcIr0xlxqS8keoOldpcn+Zmidds6wySpyaM70sRLpyZxgCtsgHfU8WZk//6JYEE2q+VVeEXjY3jMrldQM9myH8CuZnQb9J1PZZ0FdyyN9FImN3+l3rXD7BYKthU6m5wlLyjd+kyQ11PvuWLRbrnH7HLq+Eilck03JgOCRmeQd7E9JExAWUg4Q3SZoqSCTT99I+fWOf/myfPsDTn6N1nrOIf5OsFXDvaHZJy6fvFRZd0HdptrpKk/TyHl7fLxYapdEfUubC8HFF43USZRXoP65Sp8gnlqhKP62zi3VCeUzleH5QpEUtT4W006yzytKFKh+vs1xhZZbHUaY6Os/Sld35C2qWm1ycnUUUV547crlHopKkPAM6CXkWV97XGVM4mbJLrj3JYu8qUqsIfvWyWdLc/LgLnOayQGyyMoB0yfKc8cuO2TlKPgF0Bn/ThM3NBl7za57echUmTA7UJxiopWmVg/tqeJTsonxYyDGdw1MWyf4sTUNLwPGA+ukcMNJyuU4EUwDIHb8E9J/Cnxu1NVfRfK6qW11FXKSA9zOF6Za6Q/ApYFp4+BUQ99Jsu6XCrEuFUOWbfjK4dQlIdak341JBBlHd7QNAM0P4B919QwGWUcIuuSE16s0QriTll4o+L+WayRjN7fM9PNnvcqEw8zLXGGWZq67ldBlxwWLgbDhPRWQxqXnp3AG9Xa4yWg4kuDOfIfwW4P0P6NoM4V/UMo9jChNuuwFwK2wOnJJI42gFge6/UJOQLlcJFeZV00/GS0IKyUkEHJM9SpUvl2Y1qeN8zTqpj2KaJHKK1W6Vb3Ie9dsVja9h7g1flURAoeOEAtEy9cYpcEjyR6FLON80iepRs1lxmmZzSM/SPE8zdgksx1xSJUUqJQ+mwdHaCofbyuWSmZePNcOgczJJ9aSgdn+h5nae3vIkBaI8z6LLS734KI8lIw1PgmbX9P6KKZ7MYJDM8lo5PGlcph0vyIdLQAea+GV0kUQAPpsb7mupUCnjgl5mTEeyU2zWNeMVhkx9qkdLwquGIkmBlCVqw0V36q914gznqvArroAMLBUnx3hZRG71ldpwawGDqBEgTyUWVU9w/qFwME9vs0hxcNBPycgt18sqOZZ06SpN1LKSo50zrvfQKs0Vt7DKqB741fpCVy6RZGr2X0ajecqTe3hM4K+OWCIfb9RfmuUqIYU+ZOltrn80Z7eiSQJLFnBqCnOqOET4Lr+KVJLaU/Ind/jCLNZDn4sI8JciBnkWa7QsaIWXsHyiiC5A5K8wDxHPDYOoFtdaYpKVCj+o9rrypYc9sGzwsHe3TIBBz5MUcMX3Fldw0bGrLorj9XKt65b7Fi6FaQwiGYTORZRTPQNRHitCFAmRsYu1oHrG7buGLvrClmuAQn69kMNPeXyv32VtnfyKLWRVF1Tt2AsGQhgw5yVeYCuHk1xzJkxyRxNKeM7WiqiX6CPNOnJzZKs0MRi2JrWjGNC8jkGA94xKYqGxl5wR6ANsefkGHPxccVigqYu4Ri5WpNA2jEq0Y5rnAP6Izi+p3sc0oTcGTM3/MRA75E9H28mZV93ZkneGBzM2C8m2dcxIqDenAsWKLFli3/Tytc+daP7LOreMTS4yqhgO/aqWK7zcRBmLuC16a9bUAlhP2cKllDsve4adNxySw9sb7sbAb95dkaJEkeobhQcld1aZIFhGjMvW5Ja9lm1fw5uUea+lzCvZbVX4mt6vJLOZq+d8JRelfpGEI3dwJ2A8OywJXNjulGRNVkqTpeG51avsj0WVieZf7bwkaRwBkQeJpaPmXL8smfNikId6tQOhXs2YqTez76XwoxUTZYH8uny+8xwJaRvNqwWpsL1B5+tlGovoBsYkNcx6uqJGs1GuL8MPpJnmWNWDWduWPBtbJMD9jIuO+dAR08qAAoo6bPVJp7rrRCfZEmZ+JSdFsxsaJauryH2HQG6ZhA5S9ZVY872EJ5ODBWhZ2SwC6YD1ndGFoi8rGok4XWs5Ub6p/Z1RM3kZzRXXkaVCIdo8jhTWpyUpqazlXEs+DlYxSfROyYGQJCmdnTxoz05QLuZzesPM2OdCCquCJYpKiXRlVyO8lJOYiyy9pp15lF9FylOjm+TUD2ly38TRqprwS8p4mbJkgmaJHN0ybbu5Mses45IyZpJ1skN2nwu6lFtzrcQzl17Cxfzy6d7QTr1AJNusr4GYN62hU2MEKe40yAS7Dg3llXhl3QNhimnNINDeXMv1F+kdPOXsgiWqj/oGlnoSnWh+07k3L2pTdO623u8dUn6bZnMH4Wg26jZjgFT0nr2LryLOaaJYFOjh/W6SbOZO9uCu5/AIsrF7mXovU7/I/2m6jPhcMjMzhL9zeAfFNMBOVHvWMCAX9IYmips2UmScJuslz00J9Wowrc5U/NKc8nRpys3pSumNDJduSSg8mZUB9ihGLcAVd50pnFVLMhK5KBTbW2JmTsUVi6+50hUmRupMjM5YisYV8UcmmJ0jnzUBlY8lQVxGdyadcfOU3kgZATaCkuksYuRr23fNHGfprUnJ0lszZIo71cugZFUzA3VmoFaSYyJnxL6VkGi5kn2hmolnSqUJy8SoQleRwe/2WWEOYAiURvNC16R5uXy92kq4Xy6pyJjkfG8s5qhyqDOEv4LldZcwfj3SE3a3TEYwaSrVcMIy2XQWPh9BvqzkWxL5B+cP5w/T8/z84+xFoX/PN+ebg8slwu9kgdM/bWX/6Qwy38jMf84jEXWm553z2+75Ogi+Oeqcr9+8efNmdoDwFyghZ1iVmLW/OkD4G0j1JyP1b1FcCSRW+aRYRiwRaSFoUsRRIh9jNi/ulqsVGhXTf0adL7NiGnW+tLvnnVnbn4wgTb6NZsVXCB0whH80lZ/fttXAFhJCNJKZv8rMqQQzCDrypxfIvy+D83U4PJZ/j4PX5+ueyu4FvRP59/DN+bofBMHs4BLhn+si2Rn7x6c8Tte4dGuIxzy50VrnptbcsuLSkxCb3jTP5dHmxMA2sg2WJ48//Z89bpYV/mXXkNk569+KFQXhF0fqeYP/XmOVpTWDTUIqDsbLGkc/y/4URU2oW6rNDX5IExbfm0M82aR2dgTWzBmBo6qOEJ0VFOzk68WC3Xlj0Y3XWUa5+AjrrdXaSuheRflLI+35GRxTku0yl1S4ZYzVtDdPl6t1xhb3XtvnE+8/vDYfeR4aO4GqqvD7qXFd9JdP776rXVSbzW5gq+o55KdsnQs6/3S/onlDdbfhtdO214jTdTIHZ00XtKHamXc9c0S5bYzToL4xZt9xrRPsc4Tmvoz+4lfcnjlmShDLHQ5qNatAvF631z3xMO9mdJne0DmZzsAcuClsWMKiOGkSUr53eTqnsp923rss/2jCwpFmiLm2zi2/wan7EhHR/Va/vMmiy/+HvDftbiPJDkTPe3/DX4BsdXaEEAQBSbUlGMKwJKpKXZKoFllV3Q2gOEkgQKaYyERlBriImT5je2Y8m+2xPTPPyyxuL+N9X8YW7fE5Q8nHf4P/5J24sWRkIkGpqvvNeec9HR0iMzLWGzdu3Hvjxr2QmFLeFvDfVcdUKgg2CSlvP4knjIwpb+vEhUp8AGIpmYtXf8YmIu2xPydH1OD0vF/+lmW8/Th+AUkCfx77c29OvkN5e5edcvIR5e178Qxa+a7o5/bjp36SsoR8QnmbW7NMvk/Hlpegb9Md9H1gSiJ5CAFeQSEtYqd8J9gPIfIQ4Sp1fBiE0CnlEhQS5Q1DWX7F0bmKT5QwGis0VlBBxREf7iVMR5l03eK5HZ9ELNGwd10U01UfJdGJGf0euDgkAaMxc90brB/r5SOmCzkO9hyH+IzGJGXUZ23wJzbTEhkJIVGWEAPTXrDJ2PqwhA4LRpO2vD0Csz9n9DyHNTxndBvF2KDT43jC+nHp1TvPK2FCJ1C8jKl1ZgnMdVNmLbPUHmsBN7Ei5jKoxpTR++SQ0cdkxugDcsDoC3LG6Kdkn9EvyTGjH5JTFfvyhNEtdJ6T4q7FZ2gPk8/QpvhzT/zZFX8eYozJkSq0VVPoucj1RPx5JP7cEPm3Vf4d9bvHaLNDNuHvPSaW5TP4uwt/n8Lfh/D3Ofx9An8fQf4b8Hwfnh/D3weQ8kJAkXyoe7R8nqDNJSzzBXUeu3QeJU+aA81L68MhOO0BLTAc6IAyQZ2xRDGb7UsVcAzFJH9rTqLmoZDyZd7ieEoLeMcHlTNwc9YtmT59ln06mwtG71MFxi+Lwaqx6YzSTsGc2euDPHlePsLkc1XDZ0UNIJ9rvaPU0Qe2Hl3pQlZpqi31re60UsfqURpm92NGnUPO5976+snJSfvkdjtODta7H3zw/vpjnx/Cn8ePHPK92nyCnVsHiH1nVT0frJ9Km42PGP0OI98F/PhEDfn7NbQJpGNMvl32U/oJc91PmGA9sgwJ3s2EvnwTW4IELmIiiAHDYok5m48ebX++dX9vd/OjHSeIGqwPcGdt+wP2TphYWyb35u7us9rc4gP2tpiYSGfz/v29T5893NvZfLBVKrKNPmNYlKpmwN5nTGARFL2/ubsJn+2+baMvTdFSBux9ycR6dh5sP/vwYc2ArHTsnedizeu8S8Ox0iHvC0adT3cgnPODh4+2ZMWCM7YTgXp0m5QqcOxtPnu4CXUARbG/QM/hyz1mEj998smT7c+fyJjR97Yf7WSZJECsDQB6sP1sb3fr8dNHm7tb8tuu+Pb5x9uPtvbub9/79PHWk11Ify7Sn23tfvrsyd797ceQ9qSctvfg2eZHpsAj0z8rx8PHT7ef7Qq6ZpJ3n326syuQ4ntPt6DgQ/Hxwfaze1t7H27f/x6k3TeV7Ww+ebj78Puid4+BJsrkT7a2nu7d236yu/VkVxBJ1n74ZO/po817ss5jA5ItiR7Ptj7a+u7TLDtmYuGw9pPNx1s7TyH7dxh5xlwXAYAxeSKen0vXwS/E82nNRqB3CsG1iZXygrXFqnRdtIVOGdnDZAsdMfIcY/M9PT7QnzfV5yfq90Y5m2SuUp373jW5BfV+bJrdVTkeFTk1nguUlWOh9ESNahudMiyynjIrlykicMt10ZEossXk0zY6kkWOmJUL1y5E191Cn7PaJUoeyy6Yw26A9i4TRU4ZGWizNLVVgDXVSBCbNlgB6PEOlKHVCBPlHX2btSEJk8B1ITrzJ4wynBPG9WYgd7rYbHfFTjfChJts1X1Tbad6A6jswCNMIlV0E/e2UMTltEWcPFN35tTnXfE54eSpkpt4zW3aiCGGeyCecf9AcMzglfMc/DHN/TH79NlD7zuMqI9esb3m2rH4DDFdFpOEzpCpCthb1rbropR+r7jnV/30HSGRHx9AUApv6evH1lfXRVXAyCt5DOxcvQ/jOGR+hCIZvLuuHx9f3w/gVuo78j37s+ty0aRpMVnd4nekQqGmPtdtQi1FNKS6fB+LfKycT0rECpM0ytina8pQT3FLxS0a6CdcII5GWdaUgMp1vTkJyuhyiIwASc6VNanHcilz63D7go1XuWSkfBMsWgXTZO14wVkiOG0asOKbLoVwnufEr7qFFUVLHTDnxF5ZSSA6IJbiNIlnEPrSiAgrigMvY3ID0GWuQu/AMHGCVIWYaR6xARvhYIqesyx7wiCaeMBRKYo4C1PWEB/g1ohVE3EcO19O0ro1qa7ORNqsO5iihwwz6mzIrt3dWFcPTov1IC6UFMYPECPrXwzACwBvjFrruBfRxHWTQWeUS9v0uCrbMewx0cJHTCIodJuiiJ00vovFtKbsQRLP9D0seZSxDkSzEji9olNQXCE+54WEpaUr9BGzGXVpVS8BVineDqJI4ct3ITZeYMNPWtPztqDDQuivFO4VCsPIdf12EKUs4R8yQXCR5l532SngLYow8duFxD7ojOTlZ7Fb9Jfq9vychLzu+kuoQiawsrCdZYwwsmjvfLz9+d7Woy3gZtTrve3H9uvu1nd3ASgQEIKM65ppIma74f9OlpXeP6oJd8dArSMIs+vWfBQTe0/rE+quotkrW3CTZhWVAgIcXVvYLIYVuez1UttLmySuqMOeZpyTRR34aoWQsCKEhBj3S1ANva8gv7iuEy1m+yypzsDu2XzF2NT05GRepoAkwecTQXhcd4LgoezcvgjSQRLyCZNevieraQs4kufI2QcY7fhRwIMXWo5LHaIuuhDpM1zhdSBeSBMKH6Cit0QeHrzfKc44lopI+jSzSmHdh8U8jio9EB041xxHQlSMwl3/IPVOWY5Jc8ERa0+DJNWrEXASYofAJ6XtwllWeq8pgl33FK1vDNaHJ6P1A8IKerP0xVoftTBpnjIIC7ItfmCjF6xn80P5KvdpYLeyzN4vSUC5Ti2oj6gwcN3YeAbxqXbfsNbt+Xdpp7e25uO4TNO+jYKBP4LQKwy8reeVfpoLRTZWj123GYsMfaTzYa/QujTBiYJRzTSBzWoK2AzXoxip8yT4iNeDEgj7SIg7t8X6sDAfnHtY0CQcwrNMGXEaDlZvh+qtlLNJKXddVM+LtI1eFuG8UpByjInANn/KWbIa4Ztd7BVAyMmUL92UDKboPrj8CCaCBPAskzod8QynGI0gasRZBr/ftwNcBlO0yQRWzcB9PezcjWCK9iDxoEiEuBBHbMBHWbYjfkp1fA4ppvQpOmbkDEVkH9gLq16wFJQgs89EVYp5FjuFnGmpo+k0Kd1HkbyE5DliEX2qmZ57AqNP0dmKFiPTUc1IdnJyeA2Po6+uLTsB6C3TJ7MxFBOmbiTbexEExdN+J4DTk4KLQ8TzZ3Br3nHIEWNzUaHX7GgCU9TvHbEcbtMF1DeOeMwNv5By6g+CEVyxFXMPN2ztjUnGQThGXLtfiekMjTFJ27o/NFYv0CGakLStewQOX9oQBeITnaSAU6WXpscCIKmQvqxKSbNSi+sin0M8XKs1jAGH1ofrd9cDkmCsskhEBG1FQs9QYpanfFPLU12OpQVdL9/BF4CYcjQnsahacHiLfnmTf7KDFmRMEuyV05FII9NipZcY53xpLdcgR56TWYF7cDamrjUa7AsF5w4zvYxuO3CD4/72Y0csfMC2iCbgaUcSmR6uzocsIu+nRIqkTDiCW+qR3oVs0uu7Liu+YHLIISLX0uiW+2JOFaN2qjLZpCrWl1HVUFP9MNYPC4NUFlOAvstoExwIMeoMT2+Pm2trw9PbzME6zJ51Quy6sLviigsQ6wjZRPuWTm1OiiAQRXAbUw7bd2Z1JYhZQcMRxkVNkyDhZ1aMHBmvs+Hvxwlc8QFprlk6DiqdilNKP0fShZjPgzHsV/ZJeOHJpJznDa6LSplVwKCFzUZVcxQSMS6u+wZT9JRl2bcZinH55LbWu9gDqU98wApSXOZbcVdwqylFAU050jOr5xaXJRXrTE7GccM22/rh9v3vCeClZslnmSO6X07sBzT1grY/nzMV1xCl1u72XGCPoC7NXea6EEXZ3FBHzoZThIOvO5DUQmtTjseKHv+cSbOIgOWB6z5krhtwFEjGT3J85vb2RKz+B6zPvAD3xnRSWtmCZxlbwx5TShdZNuFoLBbzeMVinvHiE6zmMSYLOpZYIA9OHrAiYj+oEQCjnjDg9OZUB9wLKke1PXsQPTwvQbY8QECBOQ00hXgEoXHpQtWckDlMKpmD/Dylu6wfFFjoBQUDp2uAbWBKz9DUbAPyTW8DpHaaptib5iQSdP0eeKkpMQLfBtXKUxmkKmrD3Z1qNnyuz5vgNFPkC9LP/DAoNuslBu0TuXDOc1yIHXIHLrz+TTlKSAwxE6O2P5l8HMdHFZ1THSVwXSl9UfibZYMROVTyGMdQl1ypleqM8DaVmSs507qsqqGBnXkzDCv5RXZ6nuckyhEW/8kHnYpjxcL9icj37nu3PljtnU/yZm9yABVR58ctT34JwueFO4FYTwM4MZxGlBF4gkVxyimXr3E0ZjTKsma3KBpIUZcExF+1pSS41j3a7iFrhEHKWcQS41a1tLVIdlAUi1FCgixjxIcQv/2oxb1CU9TeY8dgZROO+vZLexqV3unAfiPpyCvlBud7KfZQqUxKzOu9eBHxVgsTy7WDLxGvQ+naWjlj0TQMIfHUGURROx8V9aRIQb9UhthJUCvt5CXPMoLVs+Jkl74pVxOgF0xwe28P8u3tgS+jZhcLlrJAGGgEIq/ZqCrmgIHvxQH4x4BQcdVOGbpfeLNgpVyYK/UaSbDrqjhkUT9RbgC72EuqHrRqY7T1Y33Gdl0usbd4cV4anca0Ou+kAp+Yx0hS6vOAw4CbiRqdHH/SnmqBaSCeR5ZjESEIaecixLecXga4F28E4MjEH8QjcDbSnkZ6xH59V+V8f5XuqvqSvuhZv+vpznidcgtsFlR1VSSWS1itOdkEjL/USFo5xQjJmCxoJQuZL9nIwV4qQHcu782jBVATGRJWUcpHatyIEZGVKFa32cFkjs/HfsoaXU8NUWSQKLXQVApUOpDr1jW5iJXv9rX5hCijc955Q04SF3nfeWNeEhS5332L3ILqNTvgLHZMu4IAGsyar3Vxb7wx741bLRwOxmUnOeNRD6qVHpqKekOcmxOICZnShZ4l2USnN96YQo16sgbj0fXzJTKsmjL1UQ1OvOgZ6+0nzD/Sk7YyHynnvH1dTpKU8t65Pi+JdW51O9gTGB8CWzepA/VkY96bAKgnZVBPRj3dkoK23ZSQawvlir0U42iVW6/ARE0kkTxTKJcbL3NRtSU7lZLlyVsiA1oGXUkCgpGRig6DVH7XKb520Acbl9rAK6VFCcFkYPFH6rJi121K9iLLEtc1jIdUW5pKpSSi6W1IhWA8GJEFNVQm3Fj0wlYLI7X9W9WLhKKFQTiyG8GuO1b7/yAc4d5YVdiv9J12QcRQH8eDzsgbe6Z/uQWXOphvhuGj1duQYWf6qKDxFQrvur6OsI099Hb8gpyLCvZMp3Q1TpSy+pOJwZUyAkI2Ng1O2YSKly3R6tYs4FxkJQUPm+bkzp2VHG5CEuNJUDynYMNBffO4oz3MUl8xu4ORDMptsbOCR9GuuoCMxXBySwYjRZTAdSWlNNKzV/FeKyvwllLBx2SAex0wtlZ4pvdJ3p7Hc4R7d0CMVhXXuwBNB50RAUec6eD2CHvifSDeRzQd3BrlhhcoceWJtSv3SoqQQpOgHYDJOw7SjWpguxIPpigYpCMKeeTSeYN3Q+QX8dQhRDAylrehKNQH54TGhWkf1Y/ZJ4n2eeoM7gUJXGEcObnxQD4QORgJRxh7kQ7uSZIR9pA/SEbULlUuM8IYlEWBjrdOlq58FNAoOVaPwZM6SUlgNKYCJmMNkyN2JjjIXlF8vOSXfUHH4JQWscFiRBZQVZ4HEhvyinRUGPpv8P5a12N3eb/rdcoyREF5iU/TKu5mGVOq7etQ2IdaqijsSxSOa1F4XELh8fUoLOgdGQsUHgMKi/fBGFB4bKFwYEs1MDKNwuHboXBIO71ww3gsDSUKx0IaMyg8/iFQeAwoPP6RovD466Nw7Xk4j8U0qn1VgC2+HtElzJgNsxQxIeaGJC4h+oKe52RewfZ2GidcyClFXXO7Lskq0vkgHPVEvZMRmUC9ZDGYjKhIEEMpHBFrjmDRq4yZAFQWeby0WEL7Zg81s8X6K0KX87xwaAmn7XCFRt/JwZZc1os3IuP0UY8moJHy+RgMugKzuOsGg454SvB5Up64qJ3OQVSNSVexjMZpPrNiXEtHlDn54P3OnZqQ9G/W0qz0nF8bX0OSDYFDA7mqGtpJ68hpUh1zIMH1Ghh9mW+19iUwER0ATpTSVmCdbnd6/kYArqAT7bWZDfwR8TXCNXTeFHQChRogxa5rlQF6LEgoef/d95ZjV9dGje7e+uBdTGJ6Dgfw9yQzBzeAvGaHjIv3yit8VgyHALx8l5eL4dRRuvu+X8kBSUlwzCY73OdgXwVgXPHNlJsFp0EET/MknpsOcNmxnATSblOkKWFdZpXTD333w5Al5gnSjOAhXwJ+BpX59PzGDUlD5Khncz9hbzHg+r6l9Dzv1a7PpB2kj9ksRgz3fS8dsLZud5RlcZ4OkvaDODnxk8kzNh2VeyXv2H/FTuVE1CmaHCk20OwAZYpNFvU7A2i2CrpXqzgikzftKmS6wmH04dLKrVmwDYa4jDdTc2rWkHYKh9rsZIoi3ItdN25Seui6omgsqItcegvxde66yKe+1onNUYRxcVaS0hBxTGY0RBEmB7TTO9gwJ+Ot1oFs6Iz6g4OROpgZnI1APkrgYea6M3hIhcR0NsKyxD6doIicSeO/MeLkjOyXD3qNIJTn5N1u53aFfi8t5+i6q8jq/u80TkhCo37xipyE+WPe1m5Ssfdup9u5TeLaXBDvKFSZ3iVBbaapuuamsr1H/Npssu974HtB5nyfpPWtSp9CiczWvQPa69psx8FEZ+t8QMa12RQVU5V1yKI2l5+eRWOrc90uma+qTl3dLeee1MNGrue9hE1VzltkWg+eRTpnUaorvE0Or822B/7JIO+tDpnV5p2xWayqe4cc1GYJ/RdnKsu75Kw2C/gDVi11yX79MBfRxIdbkgpZuu+R49qcCUvncWRmrfs+Oa0fJ7gPk3k+KMjpCWKVs+06fljyDQV57SmVHFfqtcRTCXDmfjZnKn3hwc9c/gTyJ5U/vvyZatUjM9qvoi7XLdpUVY5lsYn8OZA/M/kTLtdV0ADIEVsJBc9newoXAKGUznPe3hQo/DieMLogvH3P4CkkzWWSshRLFzOW0HGR9lStJRoSczGZJoRbGxKdiFe11mlAePuR/+KMHhAOOwydEd5+CvSCxuJRLWKaEt7egbUPHfHFq0JiOiVc8OSm4zbzpwZ4BBaDapgLCESWVsZ2pBNLo6upS9Uyzu0CZuirC4SygIbLcsbr0NFGCsEmy7osuK5ud6LyaqCvzhnInDAjq3MdyFwwXatzzWQuNZer88Uqn57o1TlTmdPCgtV5fZXXoMjKnFOZEw7J1dQIxqduepZMSWrtX1iWMQFL+TOXP6n88eXPVP4cZtn1U45Kc36QZaX3WeU9rLyPK++Tyvt+5f248n5aeT+DAH6S6aInORFSwPXyQsGGRUgwIzgn5TiGcFmlnTB/UlGol5QyJKXv34zXkrUuCSnqbmykeK1LxjS8e7dLFnTtPdhk47Wu14ENdK3rdcmUsgFvzeUh4bxFJySgU1eUXluI4tO7d+nagixaNO0t7nZ6Ab31zrs3g5YsRaDEYo2+L5k6nwZW2cCUTaCsD2X9mrLq2DbAAe2ujY09jxDnQqO57z/xn3jd9c5NNIW+457foo99ftiexyfoFrgaWKNjxdrpTDf9m1aeYC2B6TlJgiUbD3XwJTW0JCUhGdP3bwZr8ZoAnxjWWIxqThcCoBN667ZYl32r9rVbd/Ca/f7ee9jrkClN+h0vWOuSQwAMQPO/mvS73lqXzCjf6GRZRwr13XW+0el3PRlrgctB+fupYI6D9In/BHGcZZxS2l3v9FFKdaIoQ3y6wB7yZalpGMcJgscwPkAcw4Xt9qMntzDhN1FoA2zNx3ijKzj0tTUS3qS3MEG8Rf3W/C7t9ifroTexYdddm2N8M7xLb4kirRYJ10URyL4QvVJdUeVRShG/Ga51sV1JLArQOfZQSrn9YV6TkXYw7sV36fs9Noha0xG99c47bkqmLXpI0nWBTSS2cM/f2IizlIxbNO6N73bsQr4s5MtCYygEn9cORxnt3nr/5izPye133rv9dqL9B+937ljhRGLLjPu2HeVKu+9ROBy3U8ZVXoH0t67NeyDzaoOjWAaLAl2ZlqACMAvHcUVNgwLsuigZBCMaD4KRLJgQZiLHlSJZxgTaqlgqTU0olLI6j+M+92J5h0sgaEI7vaTQXrVaSaG9Ska9kseggvY3USAVLpbipxKVMGFTlrBozBo8PmKR13BaAe4xygbBqLBpJADTpYNGCbLrex7QZNAxNiPaFEF1SHXmnh+BKWjKeIMfskYSx1xFN3SKaZCKpqS4StFqGUuFZOCPekuidFrc47HTkIlNlmJMHGMQ4zQpFUUsJ1Q6yYjzKgE5a2Az6bpVNSxUbzxKwfD9VndEpOory1Ag4wCh9S/QcNLK1vCNddxng3REByMPfqXjBAj0qqZAthbUthZYrUHsmUid9MXqPK+Ccm+HbtEgMoCG2TM63WQJmb6lkenbO9tPGuBykyUQElt2wGs432rx1recb2l1ol52kbL86ZC1LobFWu5XoHQNPm0lgOQqLKgkzf4yXpuuyAiZYJUKzSey+Wo8J6nOVWabxCddaRLRUEZawSAZCUBOgnF15UowFiH04vaJHx4hRipB6KQPsRwTjkkk6hLZaldSQAejXkQjO+rqSo1xNZKqjp6qFcCywEhfc9HJMH6ZWqjNGwz5+DxBvtX3BAz5pM5eLRYfYxKhBPcZSrAHVpjtcTybByETE0X0uRfGOWJYDPXQTytQ48nZeUFzq067SndP4rYMOVrHL9t25Tp0Flr/8fUD4vx4x7GShuuQ1nWgPzqKaX2VRT1dUWjdrufHO1CPrAaWSakOjZqsZCTmrDvghWJ86CebHHWuIcP2yhE02Exog7XTxb4kbKiLAWE5jAtDzNNiUNA1NR91A4Srjvpkz3E8Z91pMVWHqkEFL12H2KW3bnfeW9qnGY3a0WwiEE4Sf2dvL4wnfnq4dyj+mIuUe3sOiekHnc573Q8+uPXOnffudD74oEsCaqGi2pJHDvFpFUNJWiSp6/kjh4RF4n2fs5FDxkUKgHTkkAWtOQYh8yL1sT8fOWRSJDyBPWLkkCldWkDksEh7msSzIBXNzopEGXNt5JCDIm2HiZJnVgJM4Mgh+0Xa58w/kl05rgz/w8V0Cv05LY3X/yxgJyOHnND1L4Y6vd3q3yv2q+Hoxjo5ouAwspMNumsfjIaTm/jGOtkStGprUIAmjH1++5YC94hWP717p+7Tw4i/vyK9++6KD/WNfBqsqAo+qBjMq77XtyW+WI01O2RL7IdbA1/8ORZ/UvHnVPwJxZ+x+LMQf+biz0T8mYo/M/HnQPw5E3/2R1RZOm7TJTE5ah+4rv7TlnhDqSLZkEh2lkulLJy6bvF3uaBIJXt0O8t2skxjMnK0/uwwSB2MMNkUwk2TWxceOLlHN10XPE5YyYw8o/dc955hSSndJLv0metui41lzNKUPC0ohyTWqrVd190FBjeIDqxH5Cx4UPYmkCNMHtKnrvu0HaSiYTmJBRv/vMr5rnUFvwGhylm/47GCyY02kh4OpogjNohGJCLFlcyOiShbaBGflM0sxPaDOC6+Pyr207Wu5f0zDV7Y9FZFhixFk03ERt5q8REdJISNcrEVFhXf+NoVm2qZrFJUcp88Jg/IC1rhVciHdDn0Jvl0iTUgX9K9gbO3N44TtvY83UsP/QTo8Yh8Tj80Gyf5jH5aPXf+mKL7dH3wRXvUurHeZqdsjL503S/BOkD/th9uSb9REDYb9x2p6UZpMsZ73bbTuu85Dvke/bRo6TtU0kjkfOG0Ppccy2fW5joYDr+40b7Z6iM8GI7O82wkNtvh8IZrb8HlvmYGiLh9s4/6dDgcIpwB19luqYQRFhXd6LZv9h3ccm44mHxEn/X32pLAqkju5Lt0ry1HQT6he+2CMpHv008FYKHFh+lWtJipKOzfpi8U70gYo9/tf9eMdtc/0PVydv0xY8ToR/2P2kFa7k7CKHpsG2aQB+qtJu5w4zF6ALfFMYkZfcbQHnH0VuGAW0iZ9tifO5j4+lXtZA4mqU7aYdzBJNSvandyMBlDkuqBI+8UOJgsGH3OUMwwmcNTwDCZwJPPMJnCU8owOYSnkGEyk5AqTrXVgA8YnbH+jMkbt9tTlV6QjDNWWWA11AKUOnBbJWR+gnCv1eIbUU8LqeDFF76njCMhkpJk0B3Zhif7/1taOf7f0srpV2llb2/ic39vD4xHj5luDb75kwmCS+tF3SdW3cvl96VXKuhd8IJRDj/WUQ+r0n/ToWhtDcj9Ewb0XoyrcNegr0msWQR/i1kLQY/Q9uthOAPNlo4cz+L6wnDkeExsjUxI5xLFEcP9ZQHsM22ywiAeLhswNpL+k8STvoYr56fZqbg3jen3KnJaI3FdxPuycGTuBIlXTOK8FDe8GKKpBQQsA4ZtGwwfMlALAGgotYzwdpitztabkpQPkQKe9JoDSU1VkfjluM+aVHAWTcorMgEodBcSTIf0BlwM3Be/EHf4sO97TyHtiO7LZ47JFkUn9ITSoD/1TjClU7JN0RE9kilHkLIjMhwJMWrHde8zfVe5eV/UUNw+OQQ2jza7uczZ3DImZxDGWqDkiaBCWfapqKS/x0r9rhsN2NqqM9BInXqeeuAVbP+Ms0eArU3Krbcsk99kHEP9Tb4VnWWUtfeB1hMussCjvKFwrM5Fm9c20gzgFtcnEJQZHjjGuGef6ob6eFaB4QlDLUZaXOUamxNa8HpAqfRU5rqsPWNp6h9Aknrs2We7Z16BM7zlOD11snwMxoSPeuo4+BjupXZd0NfIObiBieSFmooauG5zWr5AdEh9qRUAJZBRzx5SyntJRm8RXyt1peC5T/cYWggwLEBfpWbNXKVqyxUFyAg9KyQx2HxHjpjPA3Of90A7fsKU6mduuVQD7DgxWCPtZLpupPRTe3TLdQ2JcPb2ThJ/PgeuSzDo2+Yjr3wUFe1l2aas5h7d66tdEGFP8OubfW7ezdWAMmbH6B55Bj1bFNdLmjuui8r56hBda9e6bkRSugnwCql9WytsimSOVZLrNv1i5jQNH9OwNzY+NhYUrhwBiPz+AoJae2b8C1ysXiCOcxpYUz93XflaUP65QIJjMDxtdnqBQQQiH7mtqp9Sv9dqjTfCnqZIbCD7MyIzygcLeXsPi28H1O8naEYOyYJwwkiAvQQdkhlZwJ2ZQM2y2U8O+ofypDOGXJG8KXCA8flESIfSGnSaZWhKSypkShdg4DsBtFfWVqVQB2Sfcvu9dwYnok1Uqgc0+XWpvN75wZnrntl33M9qfW7tu+6+nWs/y5AYT+F/yFpL5pljMslLhBQXrzuMxNjan0okt4JzevMHR/IF2qVNGrpuE/muG95NcZlYjEsYM17GmLHGmAWFs8Rmh0zoLTfqi7Vwygx/GSeoHp1arcVGqlBoSsG6/7CCPTPAnkMytbFnCshUYI+xXp7B5jXD4zjiQbRgvXmBMgI15N72HPGq+lgkP0ETAv6JptLLT4ymhCn8M2OeSF0txznG+NyqPtduJabSgrAZQzdV8VLON8z4vJjSTZvlqCoJJRfELW4H2IJ+Ujltr6gA9PyTmFZ1AGwQt6IR5YPI3G5lOUpIBKIPYuRLRnZtluges7T0cG+ZGTZV1WB5AkGJdlkSUQ5BNYz3tyTLiiAo4mVfKiPFW798dBR5knmiEe7HgyULDd7XSZ5z6KeHzsiL2zPfAuozu9MVxXktk+sJzjyXu+LSXBilOmq+kE7Kar41P3bdj+FkKpd+79BjmKrveCe4zVnK0XPpjAxFuB+phZOfMeskAmSUktqoJBOMWX+srqB75zkpBINOTkr1SDxbvhAnZYxDPwV2VHHKpTYGzGCFqX6Nwu0awiutlI9ga8UYICpMTwO3ao+omHUFexMLxmxtDPdFbg2lcsPls5D6hjX50vPbpNC8Z7VQqbV6Kmt6XVevAU7Lhmm/43VJNGAjOjahFYRU0E88rk4S97/CfA9G5Tnef/s51nWQiB4xSYg1CkcbHXBXYIjEWrevrix539bQiUgXk7U10zzpYFzpwFtM/1LrjWijoyddUKBBd1SptTq3qpyoplQzw3fXupWybzWDJBF9iqw+JRudPmq1irEWl4443EEaJKKjVE/h8ZunUM4YKU/nuSBVntg3zxiZ+XPxiAKWZfsME0nP1Ne80sjKub7H1MVkXOwz163f4+smUJWz6pScQaXYihmyisnFUCm2anKKciShEXTYIEvBUFjrTeahYKPUVVNyysr3a2kpQcxmXZdL06PaSnBdlSvGXK5AD/vkzfhRUfOUl/nJW019daHxazBAyYokqlS+AgPKw9JIcPKjAchbLVKxb0QlVpppXigqZWqK9aPtWDa6H3ygebjEXsMWfFstiT/yOn1Uo3U7ZigxHHsdClKrhhx4411GOasL4KZ5jMHIQ1qDjWwBEpg8zbwlgnmLlX6R9zueYeMCsFUbjHqtVrIRF5elB8moF9KUfF/Ly6HgO/xB0GqNaCpvtoSFUxQE6IGxFU9Od3UwyslTRrdYoSp+yGx+qdlE3HQt9oCJXvbsm2VHktcBDojdXeu6Lvtml9KO67INXjBowAvB/UIwi2WlI7LPjXKuUP7ZQc1ajmMfk8lkx7GOr1j5/Eqq5grFW45i5rpPGaiAYvljHRejLsa4SU+zLCiyBQw36TzLfJnks3bC0jg8ZkjkPcyytMibirwHWRYWSaFI2hdQe1q3nEHJKJYxpdN+SaI1Zxk06j9nKMKe40jZSenVEn1BgWm10qlSKJmEuUyYmIRDmTA1CQcy4dAk7BdXjqSe6BGj2wwtIU7D2APmCOP+NqvTtioFaKHWkffuHOy6ze8vJebkBitbVZH7jEbMYrstM5cCYR9rnJJcelnSVSA2tBEc2RlV1kcskjc3CzOHirVPehaNV318msSnYApkIfgDS6xbXifLa4PGRdkX9rGAKtGzSArgsX3NpaK0sKS3D6t6fSi7bJ8OpOJTRh/WkbGCXBVLSojHOXpYq1xX0y1AoO3pXLfZ3BrAFIysKftyuXuIU1WYW4Ufg+q8buOQevKENiPXfcSkkzvx3EyUspsE5r0Zuy7orolPoyxLsizOsoCk1K9UXZGntY0gCNGsh5OBEKFRZJmnmqES5ezTG4xsBaBR8Ekz0iZ33aZZD2OcZb6YUpnZASv/GOZYRnmFBBUzT7zgLAvEZ6n3Vp8L9baVsG0qwFn2kKExCYVYnsr9cWxGkC6dlAjirGejpFMjvElp3SX7yHWtA/Us+9SoVBKm7ZxAeQWuRvRt8tJ5ETYwifGS/Wjsumpfj0uQVzXntRe6C5yVxzY4z8md9z54f4XzFIvE5Dl5v3v7zfmWLK7Z/3cCwZIqtwaK3JJbVb7iMvw9iEzTENPZ8BsQDK7hp6Ur8bkdvxOfG7KwdLDZ6UUbRqkZaYcDiVJjtZkxJ6D2C0SmSkpeKWizo4PJBfLoMIHLFeobJvVOKxhJ2kfsDHwRLBFFeQFZEzG4WGzZkESYJPKysZAtwKgn0SYJfpoGBxUr1akJq9vt8Y0lt29cDz6yfGXxYjmBr8AIv8EvglxkETgPRGyQjMD4Hdtm6ismxiglm2gpbGu3NmxrdySom/VK4uWIr7dqi96yI77eGgmSGiyXvV1b9rZd9vbIe4fd7nEjawI3P+anysS7LcMzplQ5fGKn43AxYTQufd0NZixecBoY8QAxMjg/Ymeec8C4ujOYOkS6N7EAKKnCQKu/Cm227ofyAzfmp/0n8QQcR1mTBxfp5PP2FOmcuL9kg12YYJtMXsU+3RTWT96yflV35Zr6TZDcLxcsOdtRIfE37ZaxN9DPYupwjdWW2cVZewpB2MoWXRod4Z62H0SpVMrrie/01mRwOu0ymeMsiyCwhFHgE5bnxEzRQ5hIFQ5heaIstuJrYqi9fRi//mDdAHsdNVE4PoeI1cDI0yKmK2nGWdZcvhegwoc2gsgfj1maBvshs20FI4TzxHW5EF31cINUjvbD0I+OloeqGUzH348X3NuXucRMlOJNQ/gE3OZJMEOWAV5pFO0wHkMEsvZhwqbyjlgkAyxEpjvxfsqSYyb79Cj2J3XQt848xEKNabNLAun62DcEqeEjuQ/F+DwWBB2ULGpxokAFwG6Xxg9ae6T9soFjNeNt0QmhNz4mSXsJR1SvKrDO8x4omlZVFNCUcd0jv46IFPMUR7LFZ8yfnK0CihiSM45n85BxiLJRnQKzHhNRDXhNkSu8CgaZujQbqiEPvq6Cgndt2SqI1PhO/IA/iJOHOpLt6jUHc57QjrR5UtRClivdBjHSXyfH5RBASatFona5RcTKNArJYIe4VOHaWpJlXF65qNTJzAc9olLPlgak+AG53mFIX3vPKlETn9YQWx1XGAshpjgA7vT8qtGrTbx9rE5/SxBIN4QoGqAQ5700y8YIE7+eZjN58YqliJNYb5a4P0bYi9slfC4fwwrMAM1R2GqRRLD7ZAxhasYl+ErDSB0+e9WSULTIIP5y4G11Vt7sLlWtuNftaNUcFvwcOxHC7goUshe21Yj0EgRdqa+/uH7J2iq39nH/NE4DyBNhFyIJ6iixe0+3dx7uPtx+svf02da9rfsPn3xkNGgQdkcvih4E8Pvq1T7YfvRo+3NRrVleRsti76EKujLAx6pthbXnCTsO4kWqggnIqs5FqkjxOInEj+m+2LaL2ANYSC7Fa0FNxodsfCShKsO21sO2WIGwgzS7Rl6sNUoHnD72QxVUM6acBFQwzdEkZBPgIyQrU51ZNZN9BGFy4ywL+s0ulU9ZhsAvtapFiBeekl/Pj/3Qi4j64gEhE5+RLGzk3Gq+bo5L6Cw/bM9ZdA15rdKj3gr7eTPeLIvrtgABoPJq1tEDq+sJMcPswfzJLgBttfgTwCO2e5jEiwPIt7L3JC7kokDSVF+xziVSgTiBI5yUgvJlMFoO9NKbFxFfwNjFRmfkY7Kg87ZGUjKmc7j2oUx41UpXzHp5g6oQOoVuQXsJYdEYDFvS8kYjROtV0ORlaLLalkLtzjDHEtYkNDoeAbd5L1xxbQLKlGmZGuESeqFUmstgEqOl/bCeINQwdT+K3VCiQdsSu8R2ZcLD9fwsixEmQc2YA31+YjMU7Rp0RIwEgIBlTsGHfTKWPEEv0TDrJ1XGIyAp9lLFO4y0pKi2zusYoRqLlwEfeZwk1Gy9gl6qR70tQVL6uCYxflGTGteknbD9o4BXPsjjBkNPi/NZdsySszJroHaMRKvxhEiGgEsXdAtjElubykiIZ2KWapUNgcBOXnKADSK7Oi8NmL5JFtETyQRH/nFwIBZze5GyZPOARbyHoiKizuOdh1sOvrvWzTIrdTcJJuCi7O5aVzAnpvZOcQ6IAj19YXxQxy6skBpXqUT69ovnTNj+4sDRAQjiOW+H8UHPvMDnFTE3k1LMTYYSiLmpu1agUAKBjsVf5Mz85Kj9PPUaTssSROTV1R1es6Vaorh112htOBiOhuvD82E+REM8vDlsDfvD9nA4/GJ4Y2jfParwX/IS0+pmnEmQ+vuhjLNooHAShJOxn0xSCMwFySnji/nnOl3djRJspfpuhoSYUe2Bg1ZTaXoWxdHZLC3McnXdsqs76rtVd1E4OIjihH07DiKWpFlWSX8qxrWQgrE5ySj1/KFd3mqhmPjAHycBD8ZptV/3zZflUcscj1lywCYg9hV5fjSdlw0s9/ut501WUDdx1ufN8XiR+OMz87WCReWpWc2KLs01iYq0sZ+yHRYJ5vgYQis7QWkdflUo9Z1hx/Ecp3y+weHuZdXrSaxs3gPKB/GI+PQN8OuvxvlYyeYFwseCDfr6FQZLFQa454hqfNd1tO8ORguCICQlfTsROa1KaR+3nGwpNcUtBzvEOZg5rQiTpGVKqmu0Yo5nZ7O0VL76TdbSSrClwNaoUsm7mub8SBbGtau66FQdxK/pmQ3lddT3hkN8c9hfP6jjA53hUKmHtKuEvtN3POf/cHKM8XI1N9++mpuO5/yfzrKg/hYDUarGk4Af7sz9MYNA8sv42FveZYaLTqfTXT8gvO8MhsOd4TAdifEMhzv9knsKke9WOd9NlfGmtQGtmqG33PO+QBkeDkdloNksbqQhxltdLfSuD1QpaRuT4CyT7lf6zGMtQTCWgfrGzh0XgRtWY6gGaPkMIMKuG5n9TrkTr6zMSHmwcLC9H5WWhinqDAX0/clwuLjV6ezLn7H8mTiY6JO7PjNON8RsdVrr2k/GwGlx02DLGd10sMcqEKnueG9B8GuJ+0riP3D8y1+7/MHVy9+4/I2rlz949VNXL//06uUfX73886uXf3n18n9c/vrVy9++evlbVy9/9+rl71+9/MPL37z8rVc/8epfOMTZvPxnlz9x9fLXL3/q6uWvvfrJq5d/cvXyj65e/tnVy7+4evlXlz959fK/X738zauXv3P18veuXv7B5T+//Bev/tmrf+4QZ3z5269++tXPOMS5d/nTr/7lq3/nEGfy6udf/ZxDnPuv/v2rn3WIwy5/5/J3r15eXL38u6uXf3P5e1cXP3H18u+vLn7q6uJfXF389OXvv/rVV7/46pcd4mxd/qvLf3318uXVy7+9evnXl//m6uKfXb38n1cXP3l18c+vLv7l5b999SuvfuHVLznECS7/4PIPry7+9avfvbr4t5d/dPnHr37fIc7Dy393+TNXF//q1e9cXfyby5+9/LlXv+cQJ3z9kw5xHr3+CYc40eWfvv5Xr0XPn1z+/Ouffv1TDnHiyz+7/POri5+7/Muri5+5/Iuri1+8uvj5q4v/eHXxf11d/PI//ODq4r9dXfzg6uJXry7+y9XFb1z+1eVfvxYj3r78hctfvLr42cv/eHXx7y7/w9XFL1xd/Puri/9wdfGfri5+6R9+7eriv15d/NrVxa9cXfznq4tfv/xPl7/0WsAneS3G+uy1GEf6+gevf/Uff/n1f3OIs/P6117/yj/+0uv/6hCHv/6tf/zV17/hEGf39W/+46+8/nWHOIvLv7l8eXXx269/9+rit/7hT64ufv/q4nevLv7w6uKPry7+9PLi8m9f//FrAYZPL3/58leuLv7769+5uvjNf/jjq4vfu7r4nauLP7i6+KOriz+5/NXL//z6j14LyJxd/t3VxZ9fXfyPq4u/ubr4y8u/d4jzvcv/cnXxZ1cXf3V18ddXF3/x+q8d4rx4/T9f/+3rlw5xvv/6715fvP4bZ+R9bXz7oZGtgmlfEc1+KBxbiWAl7PohUeuHwKsKUtVg1FdFp6+PS9cgksEiaUxjdipJXx2n7rA1xufLIrvUQsM5aiESx/KGcGISIpCNteDeW8X2DZxW1HJGiqHjmJgUTJRGM8KFYypcOaBdJbe85d48TEet9YNgRgQDkI5aS2JnWaC4fv+wtwlflSPJsmYm6kdeJC+Wkrju82DkRe0wmAWcJSkJqONoj9NxvT4uaFHgdEvCqwCUMvR05n7CAz8Mzxyv7BraQRg5LSaYYXlTVx4YzljE/eTMsXINvnBaKKDOcJiKB8XkFg06zaHzjRvfdL+F8M0WWWuve70Nerf/TwbD4eiLvX96nuU//r9+8L/+XjAHsFuLRkWdgXjTrbNTf8xDq90vMmgvaDm6n6hPbxSJTm6fM+ywuZ/4nE0+YWcncTKp5d1LE2YvhFrQcikGqoo/j5PJDvOTccGYOI3alQPKcXkErsI0F2uFATNldK/Ye+ucMFQYmRfJcDGVIwk1GHNRR5sYgnIXnjzNxuXWsf+TxYwlwfiaVSO9dCHwvgYuqoR8Qikrn7I886ODOj2lDXUwwi9zlwxbprHa91eTvtHx3qAzwnYgPHAIC6oq2RGEGydBGDbiKDxr+OMxm/OGHyn3hPFUeblMHYtdjaSKEzFMBiOlKhyMpAtQQzFXA561U+4nfI3L3xyvwA11tALjeCKb3I6UPzrVdziWCGgsayI+jdssmvTiNmQCn9DwhQZEzzL11wJi8IUk1MfSs5GZpJXNXadbNubk6sHW6DJLW6k61EcJRREFVHkYcd1P0u1g3LJS1dFzt6MPEjQa6hJYnSnYH4z8nKzxux3xE93t9GPa7KhYfIACIK1BtHzl4i9OGvExS0J/PhfJiRiz13Ba1VBzuBYVTKC/+sq/am3kHIbnRYRFEy8hUIsXV04sPz8MOEuF6Lt6hgohspiaDglMdDLiU74WkLR2MtZ8bVuWUJTS9G7QD7x0xRThu4HrooQGpADEVqTG3vAXPJ75PBD4dSY9ycbgTHbmnzag22K5Oa0AY5JudLIsWYOf9G6QZcndoI/g1NWC8dcErQdScmS5bUxJYsv8aWv9gDgOhiPbUpM7R4FEjhMDeEk4vmof9PSmq6b3gPFddU795h3KcSS/JleCOnksHe6JP/KcsL3z8fbne7tb392tKGjU0bBCOz2tonsoalHWVpEOIPq+/gpn7SxfMm4xW4w6StqSthyItaWxuegO7ludevDw0e7Ws71nW9/eurfrLX/YvHdv6+luXrauYUhFfIugI6mX5KWj4HLj12xcsTE8YcVsKfsTHbRn4MjYQoKN52chE5x7wOH3kPkT8cNnoTOy2j9J/Dmsy4eRnss3H2TKtiV71a8meLBxOXBbHlgLUa904hxbCdEax8SnFRsWFbAAJZYXlrRklDfxub8mWnieiuElC2Zve2Br/QR80VQLwienJismvo04NLbfpKdWhQ56/d07DMIJ8kmMSVAHycfgmuV6eNrxcbk0TQAEWRJTfJLKfCFVWQZpq+JOOcyyUBLEu8pQPUE+ZF7yesHXfEU6FxRFd32xGffhrxdh821OlQsZRYFQh6hPmEyq3xYt/U10SrZLg3YNaqmPZEwWmKha6Lw1IXrwNTZXAvWiu1LnrsYfjdRgO9Lasu7bGoUmTCKLJiIJ+Ig1uiCx6osx1tkJ9sMgOijG2dTgsWDIKaSUBDkbAR6vPuFennIVRRbuO7a6kjLaNLV8vMxXgwifcyo/WxHkldGHCr6BxHIEZ4y8RCWxOtKIB/4I/KZFSDwSjrWpQCy5eHC+3qTUNzH7QtrthRu+jA/ZovEgHBlT/RXTz0lK0pZoQDNAJIErA6UpEPMW+il/KNqlnRzOzst2iBasN8dJnOogNP+PQH5qgqBVYJoWMIVWDTRTgKZatekqAI5ptzfe8GW89RY4GNIAPAa/M2ErLUDVK4G0TGIQJyFZ1O5vERJ1EFaxuQE/zBaUIzERAOIaSEObD5J4BnnfytDqOpAa7z2BoiNqgCu9pmpErOUnESM+UTVJx1OShI1pCoJGqgWN+Br4BSQkY1LSDWn+AEWE6fotfiwkY2ltVLZkiqSDDanfScqgXETXkgj7AozNhJCouktqy0YdAQlhAbsgSTnsTD0MgeNZNJEblbb91m9FTox7vLypReaKSKCsqKM4mflh8IIVyIY9XiRb1lBLWesGGUzV39twyqZdC8Oq6EnLR0UHXFdlKZJM9h6WRT8T9bdqMsEHwsq7tw0Fq4AKMLpiuCWA9VZmsuvLLf4uOVqldCubfxubF+VuA7j5b0ktDbDzAT9ssNN5wtI0iKOG860WK8IhJFQITaU9qDCi8UskEkSGayionP9BPLI5TXn89VESL+Zp1b2UpjSQUV1mkeaI9UbqwCz6Y2WxZ3PLHRmZIaqqMGTCJI7AQ0GJfU5qLnisBOwqUFk2dUu6N7QcJqs/YCOPSaM7rcgiqbHAI+H153Bff2IEfNKC41YAMSOHu8lqm7OU01Hbtj0SrDgoqUNMxrTTi94C0QJANBIJpAhIt4QAcT0CxISTBKzbyygwbrXI26DBuIoGQlwYpGsyvHK/hBEeQ/7At+5CtbojGULCH3RGZWx5s5poNc5AoqUgRExGVdWHvJZyZUfsQQKaPG6IZiVU+SFrTOMwjE+M9iatkchjLZEvb74orhy/J6smQH8sTwCs1wr4Ca9OQHW96esvVmKxqdWvwZKq1ECT9QoYv0GKvOn0ohZ1BpbAN6oT31xXyP5OW1nIVES7gpI+E9TfDxupMu0UeB1JvJb73dvoJLYebT3eelJRS/B2aWev4rNx4GKL8JGQh5d1D8ZZVZJlwddSPpQmyrpqNecOSRkvzRDk3RPzkqDznJwb2DvEgFC8KDUDXEKVBr5es0vKt7q8d9htsny+IEMxa/MF8aZN0bzznOjjJc862SFloihaKhFRaNo2xigS5PbkdciSNYjourG18QrbMCJWgGdhfk4UvSknyjVlpxkJkAhAl3OD0aroVhgfeMpAdxxHaRyyHNyvHdgTUbCaejoqFwXixFlRApy4mGun1m4tp2ZJUbSUo7iSN8IkyFGtC8CSHg8cwlRdLYnlScs8uyFJ4ptyL6U89xU80XVltPnYUkmgmteWtA4edElJpuo8N0Xqm+AzVO48Rzgn3e573SUlWOEGYUIm7cdBFMASplO1TZynbO45604ur2LSCL17570OXvLlPWl/9Gj7w53dzWd0WjyCdX+Ebr97547gLs6dpuOdx3MWeQ7qe6jfRH1PrM04ZZ6D8eCL9dHNPnZy4vTtjEWWvvjWqv/WEt9u1n+7Kb79k/pvTp5DYJ0v1lUwHegFRNFBuH3zPG/1B6MvbgyHTcc6lE/YZDFmq46bBhxCrbAck/MckwVdH6631gtvKXN1U4myLDvPCadc/KrNpIifVbJzXnFkBV4K+UDG37ALsBXXtGXwrQGvBuyYWHfZlqLG8XrPEAdhvN+Y+5yzJGrIMo2EfbkIEjZxCl+B4KZQAKKJmlE7isfxTBBD13W+AeaDVjQo15VRo7g6e+3LGFLgT28Kcr4KFcdsb7pTVLi0EBhve7WYFu7yoQ7wDFo3Rva1xsizDHEdnk51msgoV0k7ZXNlWysxB1KskFLF/hbEUaolpZRx4zJSNayvSiTsgJ3O5T1qSIjYgc+ZOTJRkDXvbDbnZ+Zt5h8J+daA7dCATY5iCXR9u3ueGKTR0SJGzbMSrVVfPbbCj4i53aDBWaCI4Iv3E3/MsqzJdDDA4Xn75jBfxyCfCCKdTxQ3WO8WRi2jwilb2a8/aAOk25hJW9lblJ3fCfwRPagsI6Xb09UoL1QT2+VJuSXenmlKCl/mSHp/Lu7bWJTWqqK0EfIiE4qI3DlwTqKcTOt7r4mP69b2v18MWiSayr2pqNF2VLi/OKBldsH6LHDI/ipgJnf6mT9Ru6uyoVazTAo7ToFG8lKrIQJZ5nyjGhJO6lRUHUnKngCSI2xz22JZ7jBVNaDO1uncjyYI98w1G8lKyAEphqXNBC6qdQdfUKmvESZWA099CI4MEeHqtJF6XS+Ke3er6lyqpHT3WQadK0YMdWHF/76x5tUeN8BwpXCroW5uXVOdIUBRXiiRFBXpWHolQ2g6eRk/rAmz0aQWLZpdElG45dy0MaQdxZKs2R4VO7YL7GQjdl2nWTJsT3AvabUwp01OolarF+n5NyRUH/BEGgSKeHKgCBYO1ZMXJVqWRmsXOlyGw7LLJT2Eu+++887td+vppN5sgrTB47gRxtGBgyuSpl5JsJ8KVE25n7iuc/OmHXOxEfeqYRgdFUsYDNjIgjbljuynjMzFhEzE1jMVfw7F6wFd65Iz8WdfCKXVmwSOF7UnMe87kpn7IhsO1/Fw2D7vkls56ns3IAE7gudqDodt7JBjKUObTehUEpHEhBfR1nE3HS9o0VD0sSO9sUtrtD6kp3a6tp4LWtQZDp1Wkh8r/HbApQh40bh36CeNbz5vfPO5A37eSUKb3TzXKHZCjmiHbBVIdrSx5bropBjwEca9o1YLbgAVK8j5Zjrk30wb4v9zhzByRAJygsncdceDkxHWfToB+MolpEZ6oka6ri3rml05xOHQ8U4RBjf9PeMfX49eQwd+W+r3n6jfJkTxWNW/xsbaWiPV0LB6e6jorSrTaASR9PTlYCIX2onrHlFKz1pdgIrzhYNJ0KInpn8WzP0wbCwB3hECzCl4zTohAunYKXfdU4QrI0QwgkNpP4mcon44CJbJw6H9Qfn5PxcLz0uItKc4WuuShIHiyjOqTOD//UEyaosnJQPAOzzmMCQ53qRvCSlKZrBBNA/Fkl1CqMpgsBxMljUnmo9QA8DWAARUAJ2PIZziRHrx7gUtui07puZgG8L7u+5UDngbk+12wraiSXFdutx8ttR8ls11DzJHomSpG9JotVLNAKoRn033nZY18xBx6IwekYNCa1zCDVmNjDCjsCjLmnZlla5IDBDg2KH2OdVZq0uOpGMgy1Z5ByyTC6n0GOLPFNsp2iEz3AtoUJz/H+CWMxwOnNbeoDMSjxAldZFle4OupH1FZ3IxN5Ielkel6Q6s1b4YgdcUiz7LnC/UmjnMMqQGKdcLEJxD10XFwMSoMFnqMFnd4aKrmBT4st0zzxIGm6ICiCYt8ATWQmsbUF8jY89G6ZRxqeT1g9AhAdnGZJNuWlfN4K7Z+a0cn3fIu3dyjIbDPh5mdZeoSrKfHD1v8VbUcjKnwoM4oj36zefDqNFofDN1yCbZJNskkHvePercLHC/H3pO33pNPUAf+dZbSDu7wITQNsPGrXstoBqtTUBzIZfJaRFdg4aeiTlXlDmwuFFJo9uKvg7UL3K8Z4L70dvHLp1q695ub/eu+LO2JmfhKZ0OdkfkodWvp6Zf5LlJNonweSuarL2PyZPSZ0jUnzF5VP2Ie09a9BEM5wZ9qPUVyMGmb+Q+fQRmFUe00zvauAE72n163zLGw4PWzf6ov04cBZnH1HF6wEWgR/Q+BtfLdOa66DGFAJIBfdh63nrUetx6kgO/0YTA7AuIxO6gPm1jpxVg8gwS9sUjp5TOdGTogMgoMs0FNvxw0Z0haquYlao7D6hmWfpOAFd0tVu2F/Y5kSPN2G845MFSVO2Gne9G2zH3TV+09wQ3RRl50d5LkzENyAupmJnR87w3AfnnWZWxqyoYhBiKVVaElwWoZ1URClaDFO6zDFzHWCklW2qZ1LP46ZRxAB6rCKpWdqMBsEqXpTJwPF9wkv3Q45qxU3vgcLiefYHhQbJ3GCnuro3hfmYlp+D24AuEsSnNF7jkWS1TrfxCKY370bKbQ9a3b4+sQcBUhG+2+m0yHH5xI/vGMLVcGHgMZjbHWhEzHK47uHjNHLFVOF+IHR9uM9xwbHFBIvUXqN+UX9s3bzhyQ7IBbuFXQBIL/8qzki/PlZBFKqqB8r1UrQmjEaCZMfm+3vViYvRmYMphy1qLMISwyBJ9XNd4XSSsirrVbhXIq0g5ZBF8pS164ZJyqjA/02VBvjTyiZAxejJUvHh0XcshVo0Q9Pa6tuLbYrUM7EAOhyhfxBBDr1hnJj5obUnGlc9AVmwFwV3acd0miikbBCPcC9bWZGi2QEi+G74xh9LuYFPqD4IRCSUQIgn0D/2Uua6gC6mZJhTSQaxjIkCu7YihkKRFhFAh3E3DYC7l8SxrWnisjf7sHMqyX2VYnvvtiK3AytKULCHEdsQcAqgPJ69kGoTMY0QrDHle5geKMsbW3bgQ7xXuozrEp51V8dI2Utf1N0IBV+IL2NY10AjjeK52lTFZUD7wR2QOM9UrIzYnCzLHBEjzooTBC0GVytXrAxCHDKDcSLYwoQGZUr8FxaaU0lAqOOyiN282fA4H6yyaCEK0kQJqiPUgxe9BINjLtvXSTASpdt0ig8W9mK7qNQQcS29iYrkdUjaYVIfrDCO9FTRODoNQTAWZEE6m5LCKccohIZpgwtXjFJOofAVIVWsqncaLaNKAOpoOmZBU1Cs93slhHJpBHlZHeGgzZ3btk5g3JoyzMWeTpukxVqHcavuRnvhhGJ80/EbKwPiMNPxo0tAcvoPJpNXSSwU1BTtbBtPdu3cbUSxHQhrq3LdfNE4mTUpTDNEOlzauRR+NaaI3x3mbx4/iE5bc81OGsMC0coo3F2mlpaIOJBTZXZA5GWPsoTGdK3pfJnVGt1QuQJrjIgBlMEUBBStkH3DUEF/9wZyngH20lacBn9e6rutoTOwtOcA94dM+XOi8ffvOraUDyZILdnB4LrY8dOfOnXcwiel53n6yfX9r7/7Dnc0PH23t3dt+tP1sp3+esIngK86YmEzxdJAwFokHadvmOU7uyVw/NrjdnRVZf2xw+3ZPJKgSPza4fWtWFPuxQWfmWHEOArnrmfcyA5iU7qFQ2JZMQslVODrP4TAC2x6oOXZdZXFpGvDFHh4y3uC05D7EGYwc4sBFPQdjzemvW0cqg86Iij+204vNte/7ay86ax/sDdeG7VErg5s3M+LsgXcHs1nm6kKffcfvnj9joUDEkrs1a42XcNVmyPYaw/VheyT5+PojU97m8afzuS6dY5yT4nD6fByH8SLxYrKIgi8XbDsKz5ZQRwPSuqYp+OicHPrp/cU8DMY+Z2ndZRSBnTsQHUmF5DVbSk78MNzxZ7V3WCrFNmg3J5Mg5UE05jAxdYXMpUBaOryRM6yiKYiXqCGPJNvTIJpUzg2Kg6IAbG9yjLOM62vZBgHy4vAnJ2D0eX8xX3H5utJK2RW+7Zd7I4K5gRBoSwPQ6nw4FKyII5EZGtza3CiU+aC1l1rWe/GEgS6fRBRFGxvv4LWoxUmUFRc9o5zM/cSfMc6S3bO5du0fsNQbOFOxbLlDHDiAW8zEk3+qnsBqJA2O2WPzsUgyuWZBpGJvQNnieRHyYB6y7anM9JCzWSrz6EeJnOZDEBV9kxlL7/5kAo5c/bCUrM9GicMi6JBSMjkjAjdkS+MNirbe0J8ROeR8/pjxw3giSh4IZtWZxyn8LDg0BD6poQtic9C3rBRbB/eT/DFzRiT1o4AHKfN887gZhnWY5SNm0SZFYPYcDDbFd95/59233QE+6MgdQFmggGHJ+++89w5EgEHvvdd5D5PUPIXiqfPObdx+PucJGYvMdzpdQZXGiyRlZCE2lXffv43b4zCOGJmL93c+uI3bE5awKUtYNGZkQiN0650PbuF2kD5jUzKlERLbFi42hENkrmQQXy6DlPptdiom0Q+fsWk6iFrJSIgJh+mgMwJ3pVLJF2NySM9zMqMybnRv1sMz2iFjxMg5uDIM+Nl9YGiCOPKanbxEPWGJBlM0ASIAp6bmvlD6ecAPkfMNB9IPB+LLKMtY+8Y0OGUqtm7xpjaYtOWsOy2Vu9hUvlFMHWwwygp9kLTnR+xsRM9vJGzqceKcrs2CJHY8UZ7IuqHXfvuYJftxyu52XVefxJ74SYScZ7BNaENdh3BMZq2WjNAL3YrpAkGcz0E0wupK1qralNfd/rQtN4y22PHNC+zwuOXoewYNiPu1ENB0oHpissrtX/H7sfKhUR21GNfU536o4WdxOaYNARqrocbUD0I2aTgtGA8obnyxzc6CVBug8J5JaScM4ulwrGIWz1otstSTmKgpowmgWcEkrH/z1p2ECYrlYBP0eC639XFsOh6YEGixhLO50o9wbzW4DbgkM9VynrGTJAAVssb/xiIJG9ADALDjp45gi6twZgONOyMKGSsrCEbnuqiSzEdZtpxWXX4Sm6tV8lFbzkVtdvUNQ7cpN7BrWj19G+jJM6EVo0mubzqBwf0wwP8agJfjxXmODSMB5ChfVvFPFMtqeRqQa96EJNYJOcbX0YAHQRSkh2zSmNasTExYwQ3PCkMvbRmeZlnxXOE5WJmdMtkwo5L9NMqzookDRdB9KR6PDbWO2mm8SMYMi81CPWsSORzaFNLmxufyPCbL1ENP9GZCHYdMKdcZv+Hgnj4+EOBBE+p8w2lNB90R4XQ66IxEo3OLBotaDig6M73j2Kxqsk/HxcuZ657pqm/1z7x9190v3vc9B5QxSglyRvah6mO4j0vVNwj0Hxssn/fnYp8Q0hXHXlCfTqL22B8fssHxCJ9Heu6rM39v897HW/cdckwmckyMLpBVEkLJWktEKsUmsHZClJCJItEQ/0lQ5EhRZCwXJ7Np8j1R62Q1RT5uTbCyqSgTZNaLqgSZGcEtoYcogfj2E3IMQaLoDCXiwUcLwclC4lNTXMIqAYXASrh8tLUrgUIi5bs7SV23eB4cjAxfbSeiOfQjwm1+yKJaRXAFnoTRmTTgL8BOGfERkx1nOcZtqb0u3xKQcv2KATBZUEDzwHUPSjyJ4EMdjM8lb8foklwctaeMjw+31cnEuX/AIu5FbfgtFN4qGzomrG64wRTd6hj/J3yRyhgL6urXw21AikKXsWomHmw+fCQwFDB6xQbS7JBvnTsCrxzP+VaLt77l5N9a0nz802dszIJjNmnI/jTG8YQ1bpzr/uVe48b5cf5PC9+ncLUZhOGa8fHk7FxKU/rMmJHzdHzIZr7njOOEOWSeMM7P5EAhNIGYD1ZZUYk98QsxcxPXhUWFGA0RIxMs/aLaq2t5cT1js5izH9niAqykgrlOipVlR6a5ZvUwTIpWsqype/0Wi/mNaH99sxYkz/Ov3gmMc7MqahBK9bG8DZOYBCWNhKI0VZcLCcQTehCEMtJFRQvD+tWF4bpBfzV90qsiXloVsb0qfBRg7KWIYc9X97ExztGxKBSN40kQHWSZs+DT9x0SEV6/kP9fhugChP8/R/Ov3KwQ9w2DdVZRoS0jLHCXtXvX6uym+kQrr4Ip4uAqfwK/RK4nNaUBRJxsiySYrmBJbIZsPpUxmpvxIDD8vm1eHeM6BV2hjSzVy1qOPGnucXDxsWpxwdnIPOYs4oEfNtLFvkT3hs9hI/KpENNRYLGPg+4oyxzLjzKv+Uh86hvetIg1gI3DXhII1j+YohgOluCHniueZeI1uwS0GN5gRNgpT3y49TZh0k1PEEceANVKyDERdWi2Z4JV3VrG6Wm5SmCLEF+YICJYrfdS0U3eY9epEbTwAzJPAJelBtHIEm8CYqacJi1f2TcLcWch+zTxua96BO8wVqlVlXK1Gowc+kCmjaif57lUVLASKeypYUH3k/aEzfnh3Y7rMiU7gI7UfN73U2O1y1GMe2PEwFLLnwcyiGmg2KE6xRDMi+d8Y93K6eQCCHY143g2jyMW8TfVUmRcqmSVYkrAG8WSxKNlOq78jkhRTPvRb8KEGNxQs16FWS8Bj3KtFrG++FBtOkhGcoLs674KigdWpyNSirUjb2us6EFAz/NeIKPynXKgEySQaBORoB0nwUEQ+aHcQoL2Yj7xOZtQRgI9sQnEUpOYoBAokOhomqLNTi4bW2J/Y3Iu6xGClB6wd65G7MVLQCAAppoPhdGXwC47g3jPc9yL26Drdd3qwgWDkNL7cqhxoGFWHlqtRI1ZrCvKepKeolRmg8VFBu12Wx+jpFidk6c9oFM17hwlcxRpl4aaWlv4uu7gLKt+thbFuoPBHuna8tXP5fJG/nDdZtJf63qJ6zajftfrCMpuDjka8bThY7UJWVTMdZMmpcuJRRib07VZusZO/dk8ZKLBjQ6OV1O+ewnzgfDN4yDiLGnwuCEgDptFgkmIYrMMEqJUteXWW/Cuydqo0ONGlS+5JI/nlfL9a7q3eRwHgs9rjINkvAj9pGHU6w72qsCBpfPmocJs+GEDdPcC0NaApR4hgOXZKw8+wHmHUrq8UAZBheaMjJXNW2VeRYLOUKCZXgwqtSVeS8arq+UDhMQpmeaeJIzn+iIey3umN7SGKFYp6Ihw5WjEcEn7yNwAXqIaMJrBCJOzGkKu/SL1UEwLChSbC7GwUOldpsoxepcjVUk1jqV089feF/wTw+LfkppkMMLLwq+6SFPZWWsAUdEGVjgGP2rE06m2tRFYpMs3VHlH7GnNDu5VG6vfi5bArtrvWyFk7VHsI2OGJ8OuYtLBHlrN5SypfI3i1NL4apmk6dRoe3UPH0Yyv82Gvrk54wUkiN6yObX26Nzai5nZQsm5atoznVjr5uBK7227ZCDwdl2qsDI5WTrynoA4AXCZJwzi4z4OkjjLlEqbW/p/sGOHm8hfd2V//YJmJR8reY1J4RaCI8OTvJQslWSQCk/UF4lKk20OMJRcrdN7qMmNBhlMC9SzwugNekuCSDE8hW7YVIHzghuGKI5l5lgI2SWeH+7LmwWkP9vLidoZgIOhurWa1UgHg9Eot0xI5EoTrUPGusPqY9DhrJYxTSt9TT49Ld5qRm2lVYq5Ax+ZRcGIPkagnES6bgGIYxSt6gjwQfv6KrM8R+++37lTGk/pDN1gCjcb07nkGDskZSyCu/WfM//osT8nPJ4LQWAcz/aDCJyTgH3cMzZVzsBSr9nNbbgeMH5fWijAZS+PkxM/PNqR+hnTNpNXpEkAuGpujsdyamWkVoQxkUFko5KJmTlfioAL1zoZycrINHO1Om5X++u6UZmRrTCtUZljDZR0QOAOUtxWkHBdFImqt6euW4nBI5OxNM9Vb4Z9kFQDRXVabsg56IxIhLF8EYnRWW0bIrloQ7y9XRsip2lDvAgEjFhdG5Bs2oC3t2oDcuo2ZCUkUFfiSdwWONY+9FNUmITCtC4JFJHrKleU/zd5/8KdJtY9gMNfxdBMAhE16XRuJoTahKb+x2geNdPpA8RBwcgUwQLm0mzns79r73O4qkk7z2+971rvf7VRhMO57rNvZ1985LvovciJRV/eOcSK4oAcGYKUBucAgwxhEIwQVVFSNiUxjnFE/pgrS3ELZrY3bfbiemfWyxQqLz1lzZRubmwws995odV8wS1N5w2Hiu1nT3KdWKQ3pURMiVEYLzzhUnj+nh6bx/kOZE8aQjWWHTHkjbAzLW7BdLW9tbUCWaPlR2ttlwts7ALbkqVm2c20Kbb9StXTzc1V0g4sV0k3syppt5WrxJsbq2R7pVQlu5lWyTZXqUq6Wa4yPcnyg7gEMX4QMwDxgziFB76PajXZRyLyy5ujX7cTEeYxxDf/rRPnsh8OHufjwItkfz0xRDFNohyul0j62I40fzl3QmvsORnFChJdNFGFLQFaChipMrF8P4grY6cysTzPsVmkOqygEoSVnNKzGGSHlPEpUcsx6XH4SIqiQivFKNTseIBbfAjWeCKw8wf9J1MRbEeQhZ/IY3HT5HUpv7Aj6YdmVmkWOBXxq3J47J8cHR771aoU68JIqHLj3GkYzM+40aToS6bC0Orh0esf3/z08y+//pZL1rGp1Vja6mrFAwplqeMKAw6zGEU4XNuZ3s7cvz97cz9YfAmjWHg2exG2ojum4iD7vPn9bLZIyb5Gc8Jc18qufcieiJJaeCfPlblZVAlLjmRPQSCTefDiUtZfimWcFl/iBrV4z8Qs7+/ElCSf5T6x5CUyxp6+NBVLXzIDr1h6ipRYtDLflYVyeLw4SVtZVKtSmFQQ6QuT1YFXWA19S6tkg3urlfzzm18Ov4njczbHc9qyla6seFaZLyPaPxaPdlSvpAfXm5ItZJIIZ06TQfpyqAiCHCiHsqvUjrizzuFxdJLFWKhW2bF8lJoDS37RFDjiKid3Kr75BRkTiYV88JU3v6yym0+Jc0LtCAAZGCs7W3B3uFfCa7rPjPm4IPMa4DXL9//mZ3Ijy1shp/pT6dnHr8nGMkyNapJI2WEWkLo3ZWY77lT0qJ605icK0eKpYjJZUjNQxFAJU19hT8q8d2vrdcquQgHAc+7qycBfK1lTbFaSX9JTbm1KryPxSAdzqIZVRWjU60IzVIR6Hd95zU0Jy4WEauIK5FaP5EhqhkrxhhwoUc2tHR3zNlk1b35WiAADQPy/46PUZZZarVpNS6mlrpHhiqOcNQkrAzUnAbWdI9ldy93NvPAQAHYC8r9j8brJNU+1ctm8XbOZiSak3lZ41tn65N5G8cRSHBT5LUmm2OcpeyyGikW2s6EcKASSVh5UDqWcuZAvhvIOcsZqbgLp3SZFAsnNalOoCys5Dc9cDjyN21veYGsv1HmQF9YVp9iVpIeF25nHYkoYcYQiM5TbCVMYBAgBREcR6oKUuuedHu7tBThfBAaSHNJ4nKazkt2oNSaFzEaJm0aQr2VTh1cy4vpmUf+Hwy4vdG74GWQw+rmG2atVP4nwngGAbx7HIgktWY9yEKE6StBkY6wG6Yrmngu4TXKxxB1SDHgWBfrM0SA/W74YRX1HyWReduAsOkqYKVUkSVEU0c/d8iUpKz9NsyQcHQcnmSPv+mQG0nG1GuSdKFPnSUtxa4EcKUfH0YlfrMIvIWTE2mkVXprWqBbJE8U68VSr6clLRPmMzimT42p1QUNeKIoyoSvvlH1vaKC6yARFjj+i6qJ6JCWuJYsNjzlOsk4ne3vihoFXF5K6VBZNen9vT1wqh1LiGcicM9fKk6nhzqbeMRJErdhU10KiSqYKX42FElSX1SMcvEuDX7CQCG9+2Sl1bCEB0KASWVudVgnRNqcc8WZBTDPMMK1mQ19KTTGqKkt501rt7VWrkZwWlqSVPJpbn51O4N9u9ARaybYb+mWPpxeQTUry13ANR0G+HCA8uGQUlHePtk6Vo+NajQ7KqKRYqsOSWArLHVd6ChSLrxgncVnGsxoz/CfE06RtyPQYgSo0GkLTSalpIK3oNLQ0RL4lM43C3t4a0+RvZJr2BechFioJElljn/alY5w6HnUrxw0xj8p8i34O7STXGbPErXLYj9w67O356/G9omxXHsmeUmNCRZif+vBUOTyu1cLEzrnkgXWcrAjbpzsWzn9YPcqvAONd9vZECymvh48lOSKPd3GyDowqlq/VIgqhECLYMqDwMvIYKIriqq7iNalul4qmMyAn60gC7/YRJV0vDemFgbjJQFwaSB6yXFXIgIgal52HeG2b0EJnm6F2JLPAdRno5/3Va0fHEetxLiVSEdPSQHYUxZMYgNN07BwhI4VTTayTp7L0lKqvRM0jltdftJQjqcmSwdIvpOupD4OL7F+UzUBuoD4AawmAKCxnphmMBchD4UVYPcpPiE+7ivneldEGE90VByBRdr0ghOwPZ05FWFjxjAlaG7ZWMK1gFUl83Ew+obv71bT+TSaTaVz8uu2GAHE9DIKYbAIQLQCIcR3XlQymqmJcdx5iuk6P/VWf4tPia6pfDZs+Y/ya4Uo8pHDYdJiyDhes2Sd8rykIiGbxiywzKCg53fVZjPLVdi/KBI+UMa3LMG1wTHab2AryKXKIgBAqhylYIiygHEZYQZ4gWC5zIEk0e3mqhMe12lJK4E8stbeUJCnd/BO2+ZcpRAYMIi3VUpYEkUhwFylEWvSrAJETFJGXKUTmANLiAOkxgFwwgFxw53QESLyIqkcq1e2Rop4Oh3xaR8qMRNasCbQeyZ6Ugm6E4lVTTAuJ/K2ssCXJfnralFYgNcslow0lqXZmIZves+hedHqo+giBSkaaotqR1HRpAPiAOGl/JfMQ3LLt8OTDTaEpyPeu/+PrJgUCXgSR+0CXq+OwTr+UMOc9Ha7kX3795U2egd7JQydTNQmGMRbV5rvW4APgR+9qOKCLUavTbg205Ef/4iy9+oNdnV2e86dnvcurjjZs97p02RqOztt99qjT7mrdHrvua5et4RlrZzToXffPNHb9h9YftLvve7lfvS6Ql/9Q61/i1fVldwBY+ehjr3/+rq+1fh/A+bvrwWigDbD4CK9b5+d9bTCAc+1967ozHIyuWsMPcK4Nfh/2rpKScN7uD4ats9/hvD246rQ+gXbdPoeL88ukwMX55ajT6l7ARbd3qY1+1z71292L0VmvO+z3OqW7V/ju1cWodaF1hyMaxkW/d301gA/twTB5B6/ftztaejFo/5f9YBe9S/wYDLstfjH8dKVB+/0A2t3BsNU90+D/6b0D6hV+XLcuNOicpSPGy04Hv9rnWnfYft8+a+GC4J1LrTW47lPOB/rZ62rDVv8TXlNz+H19qfXbZ3h51brS+ngx1Dra1YdelwoM21hQGwzOOr0Bu+pdaV3A9R1Ap3fBahrw2Axw2Tr7QEO4bLU7Zx+0s9/hstU9bw17/U9sVbq9UWs4etdvn19o0OucX308h97VUOv38avdPYde/117OBr0zn7XhghQvQHVSB2kWaN6rtpX2mDYGl4P4ArX4mpwBFeD13A1+BGuBm8A6+23uue9S+hrV51PMNDOet3zAQy0Trt7/eeo3W0PIVl6/k0NJZB12eq2LrQ+DD5onQ77pG0y+ND5owMD3BTXww/UUSB4RXC6vhoMW/3hSPtD6w4H6c90NZMbuKrJddKJ64HWh4/t7nnvY/sc/sTae/328BP8eU5Q+L59gTtswH5f9/sIeRzK6d55a9jKSlz0NW2o9dO7dPNS616Prvra+/af9Lt/3cU1Tp8PtNYwvWArxn6xOcm3ltzDvuZ+rr1Dk4o3/hh2+/DnZe+8/b6t9QeSYYwF2VeekshADfFG1IV9U5WM+6rxWtIrRmxWjUH9oCF7QfB57Mxc324ia+W5VtQUFss0SYYgu37k2g7DjHKoPI2taEbpfe/cMPApN0jaUhIMzjB2KeE9r48sDi0/FlbynRW61thzmnrWPWNXNURD1I3IGJhV1ZAMqUGRROxH7BTvwNOmV8UbYzf3rsTeLQxqJTd4oYYp+5Tqu9kwxocPumG3au+t2tSsGmMQ1aYxNuwqftcN+0BSwXiHV1VJVJu65pg1FX+oDTlYsAwczUatBkbVqIJxYBwoKpycKCqcnioq7O2BAQaAruxUjdpB44eT05s9MBUVdPWfptmQc1PcbGDnVMC+qyDDcWO1kvOzY1DISFG/kcyqIYF+I0qmhFd/6Td/mdW/np0sNni4+QsMaRf+2l2r/Em/WZlVY7WplmykTb2mqFVTBX3HaJjw6pUKP/yggnFj3Kggy2ppRLqhG6bZeB5KRMN4kghONkJhBjWrldwwdnES7qugv1IPdt7umlLDlJkNdbNhGLhG1njiaFM/jO8MQzChp+qHtV/MpyP5xxU86Ie136zatFV7b1LgPVjm77xZwXX+968rqbE6duqe5d8urVsnQpZkpjxFM2ds+bfZWBo3r3aM6MBo4GbiHXfnyDIweOfh2pp5kAX9RngyjF1TerW2BVeykHAVNeSMhAK0G+PkoRFVJd24r5lVUVVwZqIDg39JkopfT+WNkHQvqUIoAMI4rY2qooqSatZeNGVhGoS1IKyxzElCs9BJUW1OgxDYMwm7atyzmquub0RZjQmUCmuTwI6cap4zLVZ+A7oRHcOeCfrJqWmISc1VVZEaKdw+D3ZYR74SQ/w2KHyx10xXUVgxiuet35yY0slJDddFEo37qmREDGMdqLhooWr4YISS8bq8ZGtbMswv2qbaEdHzNl5vaeXHF1vhSL6AKghuDcOk2JSGIR1IAl2yJgCxTIKhcK/uGGKKoBDgDeOvXVM6EF5sO1xrdNcwTGlfv9k3D/a3vl7EavuID272DcOEpIcSvrw+Uo5Cwjq7WK3MF0mb+hJtC+vJZZpG41kYFtWmZdtgLcJgEURgLWL8c+Ol7eBFjdkk4tWtE4MVLRzPA8pL/xh98cbW5PNyAdb9Z0h0cngxg/EExtzyEca3MP7qLl7DxPJgYsUwmdpu9Bkms9twAZPZ50ngT91bmMzmgQ2TWXDvw2SGAjBMPkfLOVAkcpjMFzAJvOXcB8RsQDb/kRPCZAGTMPDpI7bGMKHDa5gsQw8myxhsK3bAnoBtg22HTjRZOmA74yCIozi0FmBPwXan7ONHsN1bsN0Q/yaBF4QRcH0qfkdgz53oFuwlOLehswDykAPHvwMnnsVB4IFDyQTwi548LEKY2ky1Amzc01uY0stT13Ng6vo2TOcxTAPPhqRg6DgwjSafYRovYLrEYd7iLN+6MdwurDB2bKA6bsNgucAVpAvb8dgFziRdRHAbLse1eTLJt1/dBcwsL4aZY9kwu4WZG8VB+AizIIrpgwY7i4MFuJPAvwPXBnfKX3enNi6PO10ugNEaoHwzngfuAv4OxhH8Hbg+fHY9jz7wiedEEXiu/xk8H7xgguvhBbfUjhfchkHM7gSfwVtMwFuE+Of6Mf+y+fcX/J6DF4EXBVPwHv0HmFufHZhbPswnMLctew7pUOefcR3nn53X0wjmn6fuNMAvvHajgL79wIb55+jeWsB8fgfzIHRgjvMwD5Z+DHNc0QjmcQjzZRzD/A58yw/An4DvxFFsxeC7Ewd8D/xgtlyAH8Tu9LEWOb4N/mIOfoSjWi4gwP+OD3zpFlYU3dNX7MDCimeT2WdYuP4tLGjmFvjyIljYsAiBxj6xFuwCYW0RwWIZzWxY3MGXZRBb7JNSQfLL2IPQmkNohRBOFhASvEPozKNHfwIh26qhQ90PnTsI5xDOcb7CxRxCKhRNFhBNQsfxIaINEjk24NDmlutB5HyByAnvsIIIoTSaQTRzPI/1Ipotp/gRE7xEnuMsIOJrHyHYsE0a4Vs4jxGFpoJoCdHSDgC3fbSMFjiRuDyBD9Sn2MI/14PYCiF2HIjdOfsIljEgzMbBcjKDOASqMAyWsQMxtRjHj7BkC7uk4S99vlmXvvsFP+IIlj5O2dKPZvSFu4U5iNVwH8FyQQ3ihsRNh9+45/Abtxx+R7Bc2s4ksB1YLslL2oE7uMO5vXPhzp3DnRtGM7ib08DvLRc/4skM7idwj1j2fuaEjhvB/czFu7MA/6y5C2RsDQ9WeBvBg31bI5B6tEIfHp0Ivjq+Gz8CdvlrNIOvj4uFE0qiquyCLjGsvy6g8HyxL9EIdwrxzPHB8SIHHM+dwtRFZAUUXBRcHyYWPomsCSR0hzNhYAdgBz5Od+x6L/VnvHS92H2RZhl1aALpGmFiQ2L6AM6dhRjYmYDz4BL2xYW/deJgEUcwQ8q0uLchdCw78L1HYHpKiGbuNIbYiWICpQiILiznVvQZQQEJH1JcGCOu5j0EMk8LiRYhDNnOxLNCB5zJLADHRwoMM8dbgOfEhPQ8xHUIpXNrQZiftvOUOkMfFB0OmEE5xI8L9oGtL0lxiFBL3cBb0SxYxM9PZsomeFYUMY5+JY+DwHOsF+c3DpcOTC0vcl5aMAoxU0tMsIMwzzIb7/YM2xhvlE5S+S5X3FZPTuHUADCqCii68o+pwg4Jt/pJDQXAPcM21dNTMGzs6p5KPdb3FFOFPf10z1TBAH0PTDXjx5/r341hb+rbalWSkZmSIBGTjbpRB/1ppRvmsWGYjUSyL0ypEZHsflT7zTTsAzikX3XZJDkep6Q4jSvZr7MeK2XJL2cdoAtcphPKolpZKCpKMXJyFCoLOQYzV4kgCxwRCLLAARyvGLAI64ssC8n6UfTBnM5GYLMhmLKrZMyofmTy8ZGtknWSWGgcW9Wq5OqBbpnm2tDZ7YIsTCRmreBKvArdaC6t5Devf/ktryin+7nSE6V8x3mIHd8WhYnnfnYE+WldbDYaRoOYeiM0fMbXk1Bj+CoYPojqjo4/TEmSDsBoGAd50efAaMBuXqm0kvM7ck16dXwkfXG4ZOKrqDZHIyuOQ3e8jJ3RiEnIYtICQiTKXqRfA2OsW7WvpnF/MIrXYSzF9Q1qqFAtjFqee+tbEb8IpjBqxcHcncDoHbK1o7NgvvCcBxhdOL4T4v323Lp1fSt8hFE34Jh0NIit2J2MrChywhhGwxlithHDf1Y0B3a0B67vub5DgkSCxpF+TJDqkliT4XQePpORkSWiVUaEcJ6YRxJMvQCZ5iCE2yAOwMX6Een6txA6t24UO2GG6on5cG99ZGbcr9iZiPrMJx1YBhHqqO1MkS0IfKQC7JW7wMUPz4oRhRP1k3CqU2GrwRZhhKuQaDSkhpuq/0jZd/iA8GTYpAEkcsZ/kO4v+UHqv4VerZlM/feCotDJSkr6dOmZT4fym1XDzSkNSUFIqsLaKYh6rboHTVMyjkBXm/+YoNeqB40f9uBmRzk5NRW1sZLk8nZxfVzZd840CB1RmORwy9PcmoRBAQ3qRlwxD6RXRnRAkJnbRQ0TcFftGAcS7Rl6dGACXu0YDUk6oK2TbjXgorR00HDnWwX5RIvM7aRTFfLTun7kRsRuuT5lIsY9dKLfnJrV07Vts4ZCuP2smWrY1kvwJ7JAc7JBnXaDjTNbdq6kwk25w2Cl1IEXX1M2vLZJc2a7oTMhW7byNEi0PNUtHERCG1aykFZRQ25KaDZuXpX0r69e0aIpHCc25Cx3fx6nDjgKSyn12iQiHU5UHCnOet/uaIiu6DiSLs5bQ3ZBhx7JxWDYuryiXzgBoxFovffQve50YKBpv4/OrvvsQuues4uBNoQotl0fP5FNi2LbCUPc3CtJ5s6j6wvNSeRK/unNjz8+S3iQvCgpddHXtVvSNtLxDWonXkeTKmmsn65kL5mJqjD3MlPcqc21zYa0zTiSsGq2mgfG0beTMnoG5Ng7ReGOUdoIXKQkZLCJjLbLVQiUshZ85x7JHhhjcgswoqohSrpxXzcMs7oG48nuLh4AYNnGqkzv3CkjHExisQOiF5wquH6+D6kA4zv3EIePQGYuQB2CqetbnvcI/tLzEtLFSRURgoTBZo3m+OgyleDaY1FqlI+Gvu1cKIfuCzheJ9QN+o5iKipi+ppKJ0Uq7O2pdDSkgq4eNP65+aF8GMSZWlGS602awZ9fH/34gtlB4xXCyJNUrzYKB3+vcqc7ZeV18XhjEkynDmctC5xdwpn9bd1Z7HGOPYs3qLz381phBNr9kuo1v2WEcmGB6YjX9bQEwQui+YHf9FcrswRaKP8xUBg/cjBhsJ9jYsbL21sn5F7oCH6ONZlxVobGmW4PApcUzhBKiaHJQ6gbgRshi0OyZbAA3IDRAjcZwqwfgB/EDESDKQTTKQQ+BCEE937KCC0XTpgyOyjbxzM34qBOYEuQz9i11O0Klj5p80iWh3t8je2ne9e3g3u4d+MZKSMeXcezCeY5ipg7JBbkkMRbBBwbadgGCCHX961cRw5iBDkTip5YkHdkLWvJzVyDr169Sg56X7161cjU6KzkShbGXjD5XKM8TgU5tvH04yplufFH+jIrm4JKBp1rQPM9I0pZKoExyrXcFsj1668yCP9lSgd/ZbJvZnGUo/d/wV+7jU3H7SuZtZArzKcrLZ50P9+fpLX84LLHSMRzq8IHVti0+/vJ1O7vF85JeKP8ncLeFYTkHUEQtr/zzBb+nuVIZeOnhLFsNlLgZUx+U1R3mpKU4xW2oThdiJ35wrPidDZMeb2ssu31TNR9/cuPRy8hZ4aeuGhncckO5TAmeaFklxe/GOoiIWxmhb+OYvo++plf/PgaLzhmmy88xG8TZxFnIlsUkwqOXT0suDDn+i5/OppYedluEowsUoBOghHHS5NgRLiDFGqkBUsFwBR1cjnQfvStuTthdeaFwoXnTjL1XyIkIkLNiYrT0EWsm0qMyWkGCaYoP7p+jDPg+jFNgOvHNH7Xj39+M4phyZ8vkwLLpMQyKUIS6Dywl54D82VMOsEypnYeaAYRVy/iEBI6DsGdE4auTWrCOyvG74BlRoLFcuy5k7xoy8A7dPj8hs6XpRs60TcJvXl5nf+iSkriMIfZlEpkYn1CMh5TmRm/XZu+uKK9IEMvI9e/hTs3jJeWV5aoEc5GcU6y9hkU75zwXXjKNh3ZG9Tx474qHRjjRhLRO81bk75QSFqTy1jDXlhJUpEdWSw2ciETRMd5dlcvH9AW2N5ka+T0OemEkF1CeUj/ywCkNbsjY6y3av/NlBDNJpsqro9ICoxKJf7JirhyxqRGByckn5+cmpC7oq+DU4n+rzeSsUnxBh0p6UHG+uHRvonsfk4lsl/QiewXlCL7ea2Ibtj4mytG2K/kTf7aO/4jxzInbxWVJDkecYu+JLG4Sg2sSGdyopyu6U0g5Qot3x45X2DsxsQjuriziTULYryP+zzEi4cgxL+R8+VFIeJ5wrVYFDQyhHvWLAk4oHLMxDAfwWQCg1VKl13lPHJZKCSTCi4PCgwK6NfBafY+CNXGyTywaa+csu2Kf9k9SYXijQ0bIHu2cQf4K0mqCpJQtp9ZZ+G5rNC40U8EM+VqcjZmZbO4Ooo/QmjdpyxLBrp9QdRvRMkwKgg9Rz+vpIJC9kholNmQDLi+YfUybkO4ZbrWWqrEyTOliBSTERhjKdU6Fndrtkfz2shkXjKB9Ib4cN5grpmTMg+YQ4GbWL/JYrF6idmlYWYHCE8CI+i1SeAVx9hsbuZUv6H6fDefhLEVObWJZy2jrXqKTOfOMFiT1GI3x08rYd+IGGKJqrkbEkec+vHT+tnbGghuJCnY06eV9Px4WAWCXJylEjHKq52ZJhHRsdRwV3JpdfTCZJhSxlD+dnj081aGMrmuxIW8b/ndeiIadlU6PS0liUuDaDGkEutV38RduyrHHsinLOOYKmapDULy4MlKh6VIBeQiHFOEjXyOvcbJSeR409PN6IN1x+FdOd40oPRtAaWryDAGpsA8RQOFTscq48fYqSDPUrGdiTu3vApbpQpnTivEcFZcP64gN1hhPlSViN4jvoy7GVaQa6wsqdCSPcB2kDsSZFdhi11BbqKSatQqoTMJQrvCQFeQLYotVKEdQ2kwrWji+BS904oe/UmFmO3K+LFiO+mTaRjMEZCN6ICw/T3sSlLl1okrt14wtrwK2RFhowHF7eRlj6XK34HrVygisDUn/8ogxj8Wq8WvBGElCG0nHD8maTUroTMP7pwKO6SsRE5cWfpzy7duHbtyZ3lLp3I/c/wKGUBQ4Bfe2JMkyJEiWGMyE4krVlRBIK6Q7FJB2aVCskuFjE8cyv8ZxWkW0AoXISooQtxasVOxgwr5Ljl3jh9XEomBh2GscN1LhXLfVKZBiH+ONZlVUFqouNOKO+dvuH4WudCNKl4w+VxJWXzyjGPTwZFdJVjGlYS1r1AevKjCOfxKyuFXGIdfSewUKixaPcFn5FieY1cYF1+JYmvy2fK8YFJhvHuF8euU0LHC01GFj5UkX6mfTNDSj6ypUyFWvMJZ8UrChbOUsRWSw3LRSLzMz5g7GwlVpx6H7jyfLrKC2wUEJMyGMRZWzDnVE11JXip8W3tiUBUqlH+7IlQt+owkSV5gucI92VaKhSNJniqh2EhI3LHCrNz34MaEZMdKGSsiv5bkGb5ApuxkwJ4rZkj5cnOl8VZljHGGS9MCt0qMOOHwlLMzJydHp6eSmj7X5/LUlORHLIbMPZaUqFBOWmEvHWQvLeRbU5LHSsPQ2Q6Uke4cGGZa5K7ULn6Swa3KK+PVq/m+PMpjU5If8FX9Rhalk1PdMEtzdXh6ClQFnJy8Ps1mTJ/KM3r9Hl83RCqJ9E9mV1I1N236gynJn9mYm7k6pfXOvt7W2XuZdVdTnhKJYVnSTJ+cipIq15tk27+Se0pjPz1M5La2dTAM/Xr5YDJJgZvb/7qS9tOWBgpnaetM45swsWmBkdJ4S3RBgHXdsKjuCOnAizJjNLPCLWIjNytY01b7Ys7EmCYum5CRuZWlzanBkhrebqpi8E1V8P3Yk9ZVaEjUrEnshGRzv1nw9UmUICRiRFWGgVCO4NCqEJ3IAeVanzhzpJVGldVJNRnRgUIntGwzlaudy5+/v+J8H5V8ZeWq1mrgXaqy7mRvTmgnf2M3+OkWc3cor913zBORynQ43zMMUW26EWNq/SCWVLAiaUNFd9/YFz4vzNWC0B8iFqThzJWDtj/b/LoiHzefJMM0gVm4uD4dJUjGWMqtxGfZlnEYaXuZPmFZMqcQ1SY/OBuZB/wEDcb64RH+PDyig8wmPzsT1eaoiozqASSna/w3P2fL3ZFUpjaoVemkrfxg6YG3BN2eevOlSWZdm40t9JpiJvYWZG7xDxiqodKTksVFSQxVjboKzSaUTuaeFX8IF2WGWPJTaPm3+SN/o27UU7kqFcNeEKqSWgvGXk8CYgS7lib0zQlXCGW6KJspfHM103N77V8Ie0m/CvJeyoE114E+U8ASKpByuCBHpQ8Zrcrku2c6vfEUmmsQkPGqZRYQwoYOJfptftbGODspwQ0kykkS512MCPcMuweFXhr5rTPbNrEbhHdtJQvcXx97UOxhYU83aU8zoq6cgi4+mUDThcwmdkGXILss7OTH3D7eaJfKnFlQjAnCmuvfBRMr3jRfvnNfQt469iPf2FaEtbnhRMcyp9TKG4afcG2Z/qTE8a0pU3yxcbMBH68pVzj1nUrPLk8KRp4bxcX+GWMx4bqIViLKZTJh8pM6/xNiYk4oGBuW6Dfo7R+JZ3uTcG7pKycnP6d8nMyWvVgYHyfwJ6pNagL0p2MTlFOUIgu0UZ7Ln+VlcmcmN/hiJh5/SeGt20tgI6ul4b5KwHEjqjtJjVKycmUifSuv741ndTUMwaxypGezzQtfy8/SenVayZ5Yl0WJzCsWocPj0wXhRru5+kGjbOu21cJtk3GX+EpKUIzrc8N9flBm46Vvh86tG/jghCGzM6DTLxRZ6bBqEVq3cwt4IbICgHsr9Alvlg1M16zFVqsVi5rSUgakEe7JZyRRoHikHzRMsvxrMCYe6TZ+PWcMWNpTLVOS+0ookowj7DeYaIcSCMosTMTLS3j6mSmhmDdMzkWjyJmPvUcgLQBM6diRoYHk1I4IGySTnZyn4W6UcpLhVUlCw+aPqO2iSNY3i0dN30LKUiPdIrBz90sjMu5PJdUkcqGnO5rBfjMTErNNnMqMhMzyiHMoX728NZ5iK7x14kJnbraQ96EpbbAgTAe0bSNzgbOwcv0MzW7anM9uyUfpOQpd3JlNGTcmB9u20mjqNysCy/R4Tv77X0Bcl8D+iVlKiWoT4X/V5DKbxNZENVbZe3/LbVOSO6WmvsVg9tnutFh3dr+3Ox3sTqYIOhfjTFVbsq3YBKVPzLrwyXiS1mSdeDu+Z86Q6wcwhOyx++WOZwLiajc36pAm8xt4tpvmGkTcGE9grHa3WLFutY9J9vJ2mF2lPttpLavVNyCHvGlQbt43WNYk6gHDYNO/+xbeGrtSWb2By8KhBss+CQWFiN59GSeci135b2mTYoKsWncTlUupJeGp2NLut7S0K3eklblKTy3WrLPtIPadeM3LYxJtuMWQxy+Hb35+znL3NnjRZ2SjSe1f3KaWz3NmSrtuRls0Jyw6RPhbHSKcqRMycj61PC+ehcHydsZsW5b+BG4DUW3GgaQWzFsSY9y5tYCFNfls3TpAAmJqLMK89ta9IeDOCjecTo/ADWILfNeDkrVryeVBt2pTwzarL9q1cmlbUiW3ZNp6YDR+uCHDVjCqulI1VajpSo35fSlgqrCHsgnsgXGjqJIKSPhQDFcklQwXUBpXoCap0FTIkQsl4cTnkM8+GUU9xg6zcXIeRLX58xs4ev2rxNkkOtIR1eaPr+HnNxKES98BBgGwVF0fH/0KRz8De66SPdAiDsFakD/rxFrAxAuitAGYBIvHxLzJnVu34Dk+82z2nXtYWL47Yd6Cotr0fEmF0LE8YvTvnBcs1G8DPU8czZX80y9bz/jy6GcWxwsFee4vSyeKa8gXFlznRLV5oQ3hg9Y6h6veYAhX10M41zraUIOzXrernQ0p+lOvO4Bhv3VGMZ7OPsBVvw0DrdU/+yChINvEdiK1iYwgGA3JGBwY0Yfh8Mpo6Ie13+pmtTFPkTXjzfK9ICOXas7FMOWLSaplfWcsS7H3zD9vvXHiYrZ5Ui5DbyNKX4buSqa86LU7JyzJ+ayx4pBe4OlJ5AudaBH4kVNj2cULNRZqqxh2tVLPz9P2rpS6sWHSWGu1SWA7a4OgPfvM/HCNE3XeigK/tpiFVrReT33bDCSmnjj+mWPZTrjmWnDDgsU0RVWpS435utDBUl3Ifl4bL4fKk2AtFp7L1AqNvD2tnzNXlYulIpw+v47fANvLPcw9LPYw92Qhdh7i9RuzmN3Bb35rEkV4ZxJFKzkod48a3jnc0MzO4SpjxNzM1DN3bn3DnHmMRkPO4l6mp91gGPdV8mc0jPt6zawaRlWqCtW4KiA7VWV3JUlYpREnK65foaCsoW6Z0lOsxABPKx6nNtAtU3VFS2pax7FuZd0wGo1bWagJkqmUWXJBpOysfkwqp6ZhRAdCNSKrIyKZoUG+lYYv1avSASOjoWoYPhhGKD29Xun8NP5AkAV3zf6H7wPs7WoV7+1tZ6twowhFWJPjnEnE658OX3SAYLIkP5oGbknJaWTqFoDkpGxim9gJfru3I8WDzBwFmEVr4iiw7gSZ+dnkY3VwFwI/zw3kLVV9CnfOzVP9Gjtw5s4EC8enjyjlHRZOOHfjaJOZahjcubYTZfaqkyC0141TWf3cRjV1xXQn8XRR9FKIHv3JLAx896tjF7wV8DOCOIA4tPzIRWGeXdFA4vARlpETIf+yyX+TOy2kDgu+wvnm+zpxcIlPbaIcpoOCxLoyu5kysuEauPvVBpVnFo4jvDxIaqVjA/7qNiFlgzqbb3Ky3kzV1mmd6U0p5wn/kvBLt47LZvzPHmoWjwXDtXPFZOCJkSk3rdKPZUWUMt3Dtv3LXcZXeUPSVMmqF4Qq7FA9eZZ3jGs2E/dGOs8ve3cW4vKN9cMjk50adVRjnFilJrano0W1ZlYhOWiqrj2SVClz28KVNg+SMiMzY3P5z5wPV1JAt6eeWeB581pB0G8YRPJgf6fqZsPUZnOLP69U1iY+f7aCy1+QOOPQXXhO7csyiB17g2GkIAgU4JGr8hg2F0AQJDU9dRdQ/pEOnnXb+KZuFbVkvh/EJQVEOmNvNxiMf0P4yVWisI9ydZLZiXFvRHJdNVHa2NmT4H+7KSUW1NLBaS5uRX5rhbkNsG4XQWeCeTFJ3QPSL2/AG0UL4ISiMPLADoMZCpbUhBxswvkJZk9xeYp7CeMStkWsum7onsda9QxfGfVUUfp/YP/+DMpb5Yj7z7++OXpO8PeWVuaw27h5tVOvQq2GPddF5UAy9NTo1zSODBPqB7jBtrvXlpxpwTC+ity02oikvKv7zVfcI8YRbGjptWEWdAcF51EuYieziz8OaPPlwggQYkvF73eQieFFr1JjLEF2Zl540HC3ekDaQRIkKHLYEUPi0Mj1EjjZuTgNPDaO73pkGE8+uQvHilNdO7kmhksn9TlcD7lQ8sXCPSY+mZKU2xR6A5HhDzd78IqOGBoqnOgniqnCqX6KX7ryD52/r6MPo27UsYX6WvAbc0PkUVF6WsnHJhj1KjSr5ET760/bY3dvNqsVRqMR2dYF14uFE55ZkSNKyKHj/RUPm88OdbJEimIOZerC3Ao/Lxc17rdDbmbK00p+Gi9dz77CDTYLPNsJo+YTWV5mPcwnevXTKhVF4ZkmLMWvx8Fnxx/E1uSzopvHfh3FRYV9pfs3kAs549ypmAUjSBNmunt7OyjFJPHxnSzcjRylCZqOWSYEVn+SZz9QYjGUI0k6lqrVKLHftfTIVBw5WFHg9tvQms+tsMDEsJlBGZNG4X51XpqODVOxt5efBOlpY1N6aB4zY+FD2S1kxCu8fJxCRMUSo8ys2VMOj700y9ze3o4YnCpuklDg2KtWk9Qfke6Zx7k8cen0TgAmdS5rZRlRssfJM1bRUnH1wJQXhQXWl6ZsK+uvqpNm+ro8pbVYSvJMsdMFmlL+i9lp7Uh6qlYDmoq5Ytej5ZjVJh7KM0m+pfSLTn2ITYqh7NSTdREX2RJKcqZdF6qhvJDkx0Jds+o0TTMyRqic7+2NKRd+HYXoR3EsW6I+NyVJZrfFW0l+3FTmEctsGHBEaREnDi8bybonH5k8Db44lqRsQpQxT3GTm31LzKY7SZcSrRJQiKRVkTq9+fHHn56jTgyMlQ3xik52iEoh3d2p1aQkBqlaq50WKMciDLwgT6lODDVxkDbUYlk7mJConm/lvHc2/HSl0UHUqbCvG6YJgn4jmAcC8JipUpWRS7LVFfY3lECWaAe7Cbzb+k3NhJqo7tROJemgVjuVDgwyIlJP825aGaOU2F/XEBacUsxe/cbQzQND57NAFMI8fSaqRlIvCzq+RsxLvS/OZ+Hg6GQHTndBZ8GoBT5/tdi6FZqNGz51DZclDGnoN0Z0crov0CmQPLGt2CpMtaGfnbeGrQIjYJ4W3dZiq7iWDZXRRaz71Ggouyc/cC8Wxgwn9/nNA046y+uDxfaFUyqm6EZ0akoSsMsGXktVFvS5UYCY3HlxIWQ1dos3bFa3yKZUqJHjXhs3/JWmWaUjOiFaOBPX8mpWHIdCUzfZsXKNUHceAF4ck7S5D/k4QUqqJ6U2nC9Ly4uEldwQYL9hrknRNA+saFl3uWHg2we5WiUxxnOd2SNx8yszbD5uuKnmlczwWHns2t6rB5XbQSZFzfVIRgyF1GPrlkvaen4ak4htPDzx2iEYf5s93VY3h/u0/vJmTRrZUjuvdhYEn6O6ZduicB9aC6HIWQh83JRuB1ujHPGpnUFUj93YcxQnwb6ZhLFnzRfHDVnYEyQJGYZNnNWjuH3aZMGy7Ta5jNuCXOYccsmKnlbHvp4nYLFZSJKQ2+EJplIJVTFktSXuTaljemyuZL9O2ENp5OsEVlHDTdL/CjzulV2j0sK3IZsENa5Wx+H20aSH4tt7ybmip9VxoDvr6uGGeDIa6TfktyiqzVyPmM2/aYJhInIzkURQ74CoXXkSpQOcxROjMRqdSusC5mi0WbJkmY3X9cpr2C1c31NFXQUDFUEW2DTLAfn6/SswayXwvAXQvmFzF7CmyZig9bm/AZ0cHMvewOQpV218H6VItaLb1fRPeWTJsKCC4LMNpZfhi89GfjtRB1HspuCMKH5LUhpxDPfV63UOgGFSPZaLgP3cXvu3FGPFXD7LKzaL597zeDB/O559e+no7vZbiz5sqDVR+ybQ/LSh81G04cWHubdW0IqD+TcVDKN1m42HubeSj968ftZgg/lYunfOM8E+M6ONhijA/jdHP4O33+AT3yhrR/7/M/AluGQtMmWnNFz1/TY7VHrr+Da8TU+haJ/A20UYxMEk8OAtOwB7y4+H3mYnR2+Tw6S3qeXl2zh8hLfs9OxtcuT1lp3/vI0e/Xjm4KDgLfe7hbfMjiVgJiu5vDl67dRMIqKx4MIqadPxU1EKUdL+uflBPTAab81nDCwyYCsaWqyBczD+ex0es7dX8q+vn7dDWjihtyWAIIpHinGf0GtlsozXTYc3xAvcnAfG3BBajeD4C3z5Al8e4Mu9RAj2xqp9bdX+e1j7zYieREM/Kak58xkwShZPz9VcFfW04v+bGg9S589SFdJ3VPFEVTytSlWsvqMKxr/ohlmqw/z2OhK/12INp1sqEAX461/MYJrDJFFU10tx9EyZAp+tQcgcvoT/Bjb0eeQ+LAJ7aXn+7cQ8eG4+eBvfDCX/ou7t8PKvKtsGOf+qsq0w9G9q2wJN31gVYZGaaYxx+iOIQ3h8afFfry/Q62ceFTvihOYzkU1f7NhGiPn/ZYe2g9m3g+D/3IVtwPntgPs/d2ErSH8HvP+vndiyE751j3xz80ko+UYBuRqN8pZLj7J2gU7T5frxStoDo1Y9+OfkdEe9Qdmm6cVwG4PnwK0DzhfwHUqT5AcxWL4NLKgUPDDH2gL6zjIaNvS9g923P5jGk5GYU64acnr3hoUJy+68IsXEk1S80xTVZrMpHewnSkfjfhflwB26kEgPjM8bbla1XW3IDVHd+UGRdLyh7wivdn/Y2xelg6ps1OpGo3l8opyqb3XDMMyb0V9PsPrHbJjy1PWcmeXbnlM8md/RTxRTMgYHp2CMRzmr0OhxPg48YSXfrSl07zJDZHIJzv16ei2vyqGcVpvSakXLccW4r+biKqX8f7Qcr4citvzHUujgtSCHrpM/SXWnLLUJnaGyUCRw69452UGqZ0VJmpH5I/jOQwzBMsyd2KNgEDp2kJzZp3KB9UhygAPRcpzIAMzTqxDrdUmhk5N4rwX7bhpTPqmlqDZHavZTOgBmWsPuHx7hHW7qZ9M9w5YOJNWoS2ruhshyX+ai2pc5+fD+Ieh//LPnfI2mtrcYjCfx8vbz8N1l68w0xmBU9apCJuI1hXj+A+MAuXw6/kVuX1f+wfv/6P8oJmf6mQCgMGtx5VSFE2ZHTuLBDiuo/3BDFuh1sjU36kYdi+iGoZpgjB/Y3bHEosB9yw6lgW2JxMwCMf/225ufXrRDzIUPZ7HzKRQ4UIBmXUI+31fKDBs7m49DFr061ScnmT9W66ZUGwJNsZhimXZsu9jB4m2RxIvCLkvQWE6YoB8r5rMVsq77S89jnU6DGeqMuI/MQtdMOVRS8y5y4qcL6YCZeAWUq5Pfx6vkwUMuQ8MozclwUIzMPSK8YdTJwil359lg3UrjRFVOkyAARv3pxxUYqlo7zcJ2N5tJateyedfJCZyegq7+Y4LeuIEfDvZOTuvVGlkvuAqCDrNDkJvHZqNgz7eYLZSNQYEN9XQXbk4MshSZLZiRNyjUWQ4RmzKLxhkZaRi7hDjvWeByJBC4hBz/5JVz6YmHEVURqzDX8gSeESBUpo1Rc4Ah8fQIxlZdeMnWx6Bjokwgr5Gy1Y1LBvH5AHCkWMm0FxSafh1AsQ8EdBvtx4qu5cmgtjeeH/bGtCEbW0nNKDLCUkjVKrJ9mjqzcFvkxOT31uE+LInXCtNCACWgoveSgALp6tPZ5cSK4mI4w2d2ui7KqlnsB7a/td10u8LcfaBEc16qoJpY3B8ZwZYu+PbPUlThuyBlnd8td37m+vH39Vw37sE0gDvV5pr7v2jESFzwxTRA0jfMFCnh/k+nKxtAPgbEvx3CM1P27xv6X6blu2aAlpDlcePxTTYLEC8N8Jl6XhjlwgodP84vJu8qhXLMWFF8UqPTzId4ay/HZNKOmGUaBvN1nEV0lBAWPcu9mjqXnzZJymASk3SaXDdNqSmle3s0mllePJoE84XrOSFkrhA+XxWwolTZzUEz7wzhBb6zrvxm6fRSvpgzxJRdL29fOF/Ej+D4dpp/z7eRS2ZfLMdCEuuAM7eObzP1NdOks5SBbrzNrcIvcN2ZBSMFR9zoa8GOVpPvUeBPnKLnRRQ7ls18MDixcaPIicFzozgXIHxO0+M798gmctBgjPwzMcET5p6+WduZY2em8k/yPrDQ3ZYbMzcJSnaIrP6dleR2RAkydY4og5ApC4kX/3oSGBb9ZwODlwTLXwPILWHGUmvltfwxxcwxtPurNM7MkLmYTgZxw2Z6/g17lO/8f/3+hhdTTFS05dmEbdY5ogwl5Bid6dLzHmtflpbnTl3H3op8nmOccs1v5sSyTn9XB76tye9dbOTW0+hz4w0L/jw7+V0j+BdTuJ4Qbo1v+Aaisz6E9cr0Zwex3pT5vUuzvpO/ny5tG0i+qhcGUmrou4eRMacvrsy3c3Rpnf9nS0Vtm/8b8G1hNDchsH/Jnm1s4Vt23AtTkO/Hv5kEM0se52/LhX9jGMa9KRmGyjrKvXMM88C4l9TtctgzU59miMm1VKNIVBRgvTSNXIUWZmqtoKAIcpmplJUzrzKejF2c3if60G+eKMkWsAspuZLwHh/ikyml0jmZ4/IcjLphmlXDhNqpcY9Sd1l/zUdZ0iCs5CivRTo5OdkX9Zt9syrtp25fde4BJh2oxtFxqkP1g3s7mNTWouKn87kxYRG2QA3sQwpOx7s5tMOUu9tsSU9O9lXQ94/NXWZUWei6qDYFUb8RzKokbOk9iBkQbyzy+jiHNGZO6Py7MSYGVVUhG6b0L0csqKALbMSlRFRWYQa2JZBKtIDW5HPsTj6XPP42I/ZtydeSPrv+7Zrv4OaatmVm4zXxMPjbakpnZW3g5jPBtxazhSBn+cdS66BI3hCAq/GKn0oJ+0bjFY/LlAU0qx/sZkrX3eeCNW0eKWyeSqlqmFxBatW+7r4ypYY73zDuXIQtbvBaDMDwqmQNv24Kl9S0lmsvyofv2saro3wIN88Tmbzz5rfQGF7nBrKykZwU3EPXaMv/TE1extoreeM2f0WmuFvSr/GsGTlb5zEBZy1xh8mbPcfSU+PEUBv12IliMSbPKKkQ6WCjC1h9zf1LjGUG/A2m/qVgY0WYzgzkOEiKxVBGpA5vGI0E6Mlp/kY1fCM0ASvd4WEid8FQT4FjTqDJ2Lg3xDT5qcQyoaqnsCs1bl0y0i5MkTWNnXDbDL04G5scwJIJwbYyb5wff37eNusxngX+JmecNATXBkOrxMmoVkBVBRlabU4hnMI0JHsFQRBgf39fSo95jnKLU4fMaCGxV3wtbfSZ2RKybXPAtlygOGIt4MUbyHwkf9twSxrdbeFMCiNuSvpNU5SQmxF5JLd1NUHg8+g2tWBRnrMdPQotxJR6c0XIbdNmk0MnipmTz6ZAbPKLvu441nA5NiEcwziU1A1rU5j6VEbix8jrbsJrFRYXtpyGt6Av2MTf0loakWQ7U/LKZycMxaRfyNzePquFKcjlTFvIEk+va29sZxKsRy3gsUwTJ/w6c79fy+GdIPHMk78UbNrcgp3rm87XbbCiJBQLpT4BlmeQayG9UnLWKdiOlw+PypLyOQ/OpJCIdRoG80Tzlw+qBm4EnjUf2xb4gc89mpk38wKb4sfvlhul2rg4fNwcfqQYjWw0Yo2MRmCNI7A8Dyz/EcgDEaxo4rowtiKH68PHrs+TOi6nUyekuDNMA4tXUU79OuPxZ3i408l8AZPACScsKBl2KwlOZjse0nyw3UkMtosXd/PAJu0pUj8nUaE6kym+l3zE6SkT2+k4eV8dUjDeOjFVyWYygpkV0e+ZFc1g5ngLmDkP4Nrg+otlnIWqwXlOlEDgRtGSASRp+SlmGilQafojHtLGWsDceoC5Mw/CxzvXuYe563P7CHZ4EOAfxTgIbVgE97lorywsnnU/Yv0IHXtJ6lQvsGwInUUIoYN4yLEhDJa+DTi4iA8u8tyJA1EQxo7N1a58siN8upzz4DbxcuE5LMDe0ndxYfArsEkHG8ED68VXd7Eh9t4wXDrwno7wu4Fftso4FNXmOLO5qELAf9R+wV8P7JdVm5I9XFXadLBNW1YsH21nh9vZzfwpd67o3+Ww+Hqt+gNF8NtR1iwyTvQTstQ41elL34Obf15IUr1mZ81Isb6ZtKY+bYXbyU2kCWsm2qy+Dc1sKbmSX//242/PMQtflNT3IMtGUnAf2GTkjXhUMsyVKT2f4L1o6maEquGDEUpGgyFibneT3CZZNncDKY0vJXwXy+PPX0vfkWBXAmNQP/i23PQ3yDeW60hI7XzLO6926sWHpsykXia0No1BFXTjvm5iJ2wrdmJ3npfQDrv63P66vItNOPyo2/FXEwz76c0KgZZsjOaQXg4Jvumy/K3XmyZeGjYCPfun219NVQK8+XxxHZtXM+1HEh0vbze1g1uzictwqN/71NnZ36YKh1199reDFw9ZOpsqFKJmFu1K9NnfU2dsqlLe+8RgBhmMKiL9mAQRWH8fqpyS2IyaRBOwItcHKwqmYMWWD4TCrLvbSEWiEqqU2dxxPaQyk8BD6hkCVjYJln4Mk+AOJmGAVDW6g8kyM2RzvNiKwHaiCdjOHdguESbbjWLXJ4JyRw4ukXXngPM3OD7hcE5SMirMT+gWMB0/InXxIpi6YRTD9LPzGMHUcxdIbVIazaiM498BpS+DW4QPmLG4mzPW6RkS/Rnh/ln0OAcX58G1mTcpXuDPKbh/8+zrThJAFVz/DrBdldvduZ8dTnv+nqpA5MELbsEL7pEwRV/Ao+a9OHTnMLfukDA9RCrMWUfm9k8wx9mZOxSA3EIihY+JdCHBms+XgER3jnTDd24ZBcuSvLN8wbCwwsiBBZ1ULv6GBfVpEdqRCovQuUM+JAiRrtn48RnoHCCC0PqKZM2yD+nzCEJn4i5CYmNCWgpO5yBkpC8gg8GQFi2kQdFlNLF8iBAWIhxNEkmWEUVci2gW3JMPElI/14foSxhDFIVqcqAfLcfU52g5j1SI7iC6s0KIHqPYmQMlUI4AwTOmaLPuHOKHKaedf8PSZ2vNPZcWiBZguUAiu1zQ6pGnIIsD5zr3kQp3EdzjcrDUBRk/5vpw//eRCvc43/f38ICg8TC2QnhA6FfhgaDjASHygbX68Nl5hAdc9geaayTcn4kiW/adE47zfuD7RsMwzKYKxhjXKmepmjPtKb0k8gw278AgQ7YmnDAqeaqooDerRu3gB3lH/UeB3b1Xb29MiaofGeOmuiHZS4mmorxlIFmtM3PDH3/dbm6YV6KFy/HjsxHiUkrWIPk3h+GVsXPr+kaUyEs3iuPbJZS/XRJJrLaKh31VQ5SQKhiGuSafbBYfdCy7QYLA+SL8+E67aHeB+lpw2CPGk0kOU9d3Rpy3Y79sslUg44PMglfrnlM4JMePlqHDzQ1IrGCBkBK7gSQMo3PPd3kWGmkROhRCOB9kkVsC8PN/LmIU7HyjyZLEjvCxaArA2E+Kr0R2ABusfjOL30xC4dHxYyWvD33Sb1bMcvxZPferJJx6csZm3SayeBmsVqvjDZn08UkW52+7PhfLFXLplv2VEnfnH8KSm7Pe+F7npdTHubHdzSwrwnwqXjGnilf8EIfmDrnqvF9Z9g73e9/kOJYW2uYYlqRVqf8duL7IMzMK1Ybu3LpzP4iWD+bTofzzKgvG+JK+KF6VmEz9poFcKVPf5U+Y2PkSY3D1xONBqhprjW/0dnhFIby2cJjb+5Zzbmjob3fNalHt0dTVHROMsdRIOMrSWJqm1Nz6SllVwrb9dgNP25mSbSeyqmtRj5MhpNqbhnFf3W1s2w/PRkXkAJ8m/SqqEVqkBHjHKO87lzK/whnhsDOmBqHpg3M3BI3YLvxFkiUr9R5RwCC2YnjvPmAl70m0/4ASe5vblLZ7cIl4+NyKLbhk+PCSIbOu67F6usu5E7oTYCEQ4CoMJtAnCbePG3QBA8YIDJhP8vByAANaJRjOkDe5IFrLrmGITBXKwGeMFIwbmZa+kAE/W8DSHBI6YbyHsgE36F/+47bvPz5Epvr/Sizx3biA6ywzesDOBJ4K0Q1Zozml5qtMq/mdDZ6c6LV/TPWFI1omfpLO9H89pqXm0tay49nvOJ2lKtZPZjcObD83so3H6//XQ9tP29v/94Pbh3122G4WN9tYWUNqWaTtX3999oQlmlietTWeA4sJ+20Rajm/+XwE2g36+Rf08XlFRspMntRAOU3Fb2YWWzB9TbnIxKx1sxEqs0AdBHMnMTZ1J26cKKA96+tjzlqUiYRcu8lzTec9wUqmo6U43HnWMAuxnZqI8kwgXs5CtBw/OxeQlAxqyHGGglEnTjQvpQBhCo0kGHKRlHEC0fZj6ARIKSiwxbvH2IF33NHhnIXLYCTqbGaF0PIf8a/vTPHrD8uDa9+NoRugqMdymSXqpX39xrCNyDAQ8p8J/EAAWYr58FzRlGtdyT+9fv40MfriPXuUyM5bi85eotqs1YAdw0rrqrlVzuMzq/HtC3lqqiW4brxFRmbXrDbMDRskTfmz8cA49aZ+bbyWDozXje0H/zl+iJiXPy7grHfdHcL7dn8whPe9/mVrCJ3WYAids9ZAg47WhcvWn3DZPofLdhcue+fQ7X2Efu+6ew6D60u4xnJS3qKrKPC1zobtXhda5+fQej/U+tDqXPT67eGHS2h1OtDq0L1uq/Ppvxq0up+gdXXV+QStAbQGZ9C6Hn7o9dv/bbFKroe9Ubt71tcute4Q3rXOfr++gnfn77gw+U7r/651tE94o33RxiLtbqv/Cd61h/Cu03sH73q9Dn1orS6862ut3+Fdv/dxoMG7YV/T4N1153d49wnOsG9nrQAAQP+/wVnrXDtXgebi7EOr3cXPPhuW1oeBNpRUOPugnf0uqs2rXrtLvzs9LN65Hgy1vnYOZ71WRxucaXDW63RalMalc33ZHahw1rukkeB3eyiqzaF2LtHtq+tcupezXnfQHgxZye5g2G+12eWw1e4O8LXWu45GL3aH7e41vfmH1h/CWV+jBvu9wQDOrvt9rYvNjM7x7mjYvuSfg2Hr8gpG1wOtj9Vc9we9Ppx9OutocN4atkS1+a410AaqpOJvDZtsX2r06xOcvzs7g3Ot1en0zrDecw1/nrUvWx387rT6eO9967ozxO92V+vDudZpfdLOk8Q251qnfdkeav2BCuda9xOca4Mz+ui33+Hjoda/bHfbg2H7DM7bAxwvfp+1+uf4/Tt+DNvds2F60e99pOt++931EFvqwXnvmt7r967g/Pry8hN+Xolq832bpu/8+qrTpiFonQEOsv1eUkHrUmtal9b1nNQNWvei3cV715eg9fudPzr41esPQBucta4QZrQ/z7SrIWh/amei2rweYgPan+3BcIBf+OCqgwCl/TnUuufaObzXhmcf4H1b65wPAHuEH533rbNhr59s0PafWLDTa+Fm7XR6H9vdC9y2otqsaK2zD5V+76Ok4p0zDT+19kUX3vc1baj9OcwByvt+7xLeX3c68P66y3bohda71Ib9T6LaRDjV6K6kwkWn967VgYvesAcX/VZ3CBf93vUVfGh1zztaHz60Bh/gQ+sP7MmHXue80zv7HT70rvvQPte6w/YQaxy1uwOCx15HUqH9HtoX3V5fg/blVa8/hHb3XPsT2l0adbuLANLudnvn76Dd7V3jc3obob7dHWoX9ByhBXcHXf3R6uBFD9rdP3q/4/NBr8OwBoIVrun/02t34Xft00CF39udDnRa3Yvr1oXG8Z3W+gPx3Xu8/EPrAAEkdNpdrdujrwH7HPZxpJ1e6xwQ3jtAA+70uhe4SxDJ4FxL0On1ruCyNTz7IKpN2taX2nn7+jIphYNhJS+1/oWGKPa8o+Hdy3YXd/9l75w+2u/b2oBdfILLXnf4AS6vO8O2qDZzHSLkA1e9zqeLXleCLo291cGL6z5+I+KCrvbnELo96Pa6GX7qXnc67ffQvb7U+u0z6L1/r+LHQBsOVOh1oXeldUW1iYhg0LtGyPrPtdb/BIQ4EeH1robty/Z/NZ6XCtFjp/MJH/TPtT70rhH0tD7wbdb7Q+vDVas/bLc67JvW6UrrnyGKu2r/0RvCVafVLQ4KrvramXZOg+1rZ+1Bm927Qvxy1df+gKt++xLR/VWfXuu3/2h3tAttAFf93hmtwnUfO3B1/a7TPoOra5z3/1y3z36Hfqs9oB0Mfa11PlDxqwN97azXfd++uO5r0Nfea32te6YNoK91NKQIfa3busSvK62FQ+Sbq69ddVpndJ/QCfazr/3nuk21DNoXXap6MOyxG8N++2wIfW143ce5G0C7e0HVICRDv33xYQj9XqeD9A4p7xBRT7/3kXYqUu+L6/b5Wa8DA3yL6Fj/uqPBoPWHliNLg7MP2mULBjimcxhouMVhoPXbrQ6iuv/y3g+0wYAtYkIOBhoOLvnxAad78KH3EQYfrofnvY9dGLQvr7C9y1angzM/6LauBh96Qxj0LjUY9GiWBv/pwGDY6mNdbICDYWtIGH1Al9f41W9faecw+DQYapfUPhDKGqj8+wondqgR1u71cbETlMYoRAtRPUd2g/Z/6cEHrQtIrvAW0jm81+5+Wt+Iw96VCsN+i1aBMS5E8ob99gXinGH/ukvkYTjQ/nPd6sDw0xV27br7Dvkh7Ryuu4yUD+maETu8QhC47rb/c63BdZcQxnWXwfl1FwECC10llBX7osL1AHHT9YD++nA9QMD/o9W5xhb/ICaEcze0s/GDMSWfcHbhj7b2ET622sP3vT58bPW77e7FAD7iXHz8oPU1+PgBke3H9hDxUwXh6/oK2ojxP/b6v8PHfjvfm09aq88MTUuGEv1rDd63OgON0AgrUsicwCWTYnKEvGCybsZwYDSUH27+MXMh43bykSPgVErTCzAms3sO77ThR03rwnn7D2h3od1p/65BG5H27xp0e0OgvX2h/XkFfbo3wDUbVOj6zx4fXfEM45j8/f+S2eHNr7+8eVa4uHen8TPiRTORLxr1g8w+s3GQTz/LLTWfMW3mn88YCCQGGh756HrCBt089Uh4tRaJtJHFYExUaSYYIn0fGNgDCXgiDZFiMzI5vZDZlBJSNwThG6rKahFMEER1RxB4Bpu0Lkmokr1svrMvRo/dboZpGMxrbb07KMGsa8V5hSxmeSkxbN6GLq/wwTkyDHGLMXIpqDUzBCFdR2OTueT2pRNfVbcv36vqiwv4KreApnSgbl/A5yrL6qE6CktnGK9fjvT73Fphw/9fWS1saNt6rS+KKW9ICZ+sz6vymohqk7tUu1MpS0lGj1lSJ1Zoh/1gGZ3GZF6Sltg6/4hFtz5LXxfVJo9xksubXhWkKmT9Y97chQ5KQppmfD0rvpDOQRpg+BU5YhXpw5bMtXlSQJFf8vGHdtKILDpl1yrbqYkSJROXOYLLu4+IanMSeEHYYY9gEnjLuQ92FLCwVmREiQzIOSRFrqx4JqmZ/7k7t26d5KHncuO/xL2Cn4IIK1kI4pkT1tJpyEPVK1q+TWlANzm9vKV542WtOFx63xHkJDEa3mj1m7d68Kyxk58rYywWQ2VJLI0cMC+Qojkz90KcZlmEkmhV21KW5sPalDRC/iNcJbFqB443heHjwgFrEgchty52b32koXgZTFwrdmzSjiY/3Ts3ftxkflxWAKeWyGTX7ruOPymnebYdnFuwXXvgsJDAPM5tMSawHyFsFNJBu56T6Hy5UjlNEO3EcLu0Qhtm7u3MCYczyy+ZNfsMbsD1p+4DUBdcP1gm9riWxyyfvz6C50xj8JyYGT1RVfNlTI4W4Ae+gx9uhGjOsfE6fZjkF6NdBcyc3/JyiusgirHxRehMHBunhtnbLEKH3c702bRUaSQEnkWKrCBIy83SRHJ1d+jezmKIrKnDVd5ODFEwd8pBkZdjlvG1mIqymHiSq8WZ0cjSD+59x4alT5WTmhxXvWhi5HkDJ95g0VtGRG5xL/iut2WbU3znWhKMQWg2jF3GtMrB3I0LleQj46V5c4vR3CghYZrg0BmZVYlMEZmx8CiXYeyw9tuCPx5T6sQqsIhaeJN41YIRT3IsK7IUmiPDLqXCLCh/y+7ZpLjNH/Em1ZhPr+UVfKaq8YPeq5YCxrF0iMrOyeke3PyjmlUw6nrdKN/daG8sSsdyvUm2Quuhz5Gj1sv8rFmfBqFmTWaiWLSeesYCee18i6peSdJK/vHHn359KQKcfrBn6jdGpBvm00rGkfhKY0dUmye6cW/Ufnh13FCbb/eU6q5c3/nnYF+UyAWY4rpwZGrYNfNghyL5FF6oU3Fc54YcKoxn8Nd4hKpQjTO6rEL+Z66MnysjCXKg8JiYkfFweFgzHg5/NR4OnZrxcDTdEV79sLd/IBu1JgWCNP96gpXx8Mu0Zjz8+sZ4+PXnmvHw29RY2r/iq0t7Op0ay+l06tDn1ARdbdbME1JinhZ4DeTXXzVNiT+DZlIoy+Way0XInm3MF9HY3HWZluF7+po0u5Ik2VWITc4Mw1mgUOYcuh6bmb+ZpYa2WFaIWBFjAEGQsqHMG7eyIEhVYS4cs+wkDVFvGjVZfzK5F390coLMwOkpdxwih/6TEzKfPMVZVNJZ3AUZDBOMFQER9YlCALySNiTcSKrdnHYjXElSvixvbnuOjiTnW5JtVo6lVf6E+dGae8oTnb6F6yywqBu15tYR63BqShmsFGzXWRFjwKycmGH7a/6jKh38q4GXJZDyeXSah5LsKD87jxsGxLz32FJiZ9TcCNZW9OTks/N4epoyTv+q1/myVN3GogxdBCSxuciwbxjv2kl8ymFukGIa4g0XQ34gN4EXWbt1DwFLbJBDQM2wDVtlnwjB8dCEZIHxXtOwn16v2GfB9D6d2f+CXquaSQWspKSSzMMbeHrNPyFXZVo2qzWTerZAQ+pCkDAN+eFkrMNzSVc2TA4KooWayIDgn++spXwebInu1jVOuY18q+TKkESSZWYCSWxOshcoKuU2RNYEo+76UzDqvuU/l3iGpUrz5bT35ay6tVoN9CZD3zUZTlWTorwa9caqYNDyOPeUMr7JLFp++vnnw0KOHtlnlDpUNtBuY4z1iGoTq5LUmqgb97WEhfKVQzlUnlZyoDzNLX9peU2nTu3s7fGLOrsv225kjT3nYxB+dsJLJ4qsW+cDCZXh+jvPFJaXMfKejj8J7CzVUMUR4ywBbyWLyFRxVd+5r7hiTBm4ZId80lmyQzmuE7xIzAyx7kb0LcaSGtfn1kJ0pGY+KRfSJ8rMladaJ3TXiws3jeXhoXWITyqCtJIpQ2F+bnlHeb4lEhEoG1kcMCuS+sTyPNGR6uSsJ/4q146klRyM/27bm+px6qORawNszt/kyAI+TtMzVas+WRvizZVMUe4K85iCg+weM7FC9BUfAJe5jrNPMynGkvSEEqPAWhWa7lR0FV6CuirGkuzrrpnkUMXrNI2qVXH9CsEO3lZCOZbi+syKevd+2nNL2tsTQ90yFUeMdcuU/Yy2hsfUOK2Y0OQ3N7ev4kdTDBXdTBvbwATHciA9hXpArck++fSH0jGXd5Mm4tVKvnXiDt9cheXAsR07e3s7MQt/4NRJxOhac0c6lhzFqbNoeRqLHJYMxVHzJetkMCXGEoAuCyiiCqakH5n1/w9zf7rdNq4sjuKvIvHkMEQLkiXbmSgj+qUduzvdSZwdJz3Jig8tQRJjClCDkIeY2uv/FP9P9/N9sN+T3IXCQJCSk+x9zh3WSiwQ81AoFAo1SP5aXWG1091Yp6zxeCVUladwGfQJ8XQaBSA5D07gnLvQCR/DTcwtyirLwEVrpaIgZRs57XenkrMvxe0dXDgbaqMdCcHFGpgIkfHLS0m0k8jG8FOkqZKzKOr8gOLhp3jU0n/P0IOdtENv6DgSnRx8zxbFEEatuuaQkevBjNo5zH+8/ZDM1LxFgb4QB8jBGFMwJlE6jeSQjTq5GBNC7XBU1NqbhPUap/kLfaDXsaOtUJCA8XbQkn3a153ixCzd6zSXqrMc0EuSslztEF1/s1tLES6l198AC9OpZpOt19gh8fhumSUpiwWGX0lvZCyw/YG/WkZvq58/sy1gs0fcMz9BR+V0CT1dbChGRA7FyMInW2Nfprs2O9gsc0oiQURReLWjIR3hhNytXRO5aiJVK5LWN3uOAGZzQiRynoZVdoZYPW+mEEMyzEaEDbMR6m9kyFFRROByOR3mI7TW7ojFkLpBqTBJsNfbzsvjU39ufJsdCggYIWQchrJJaBhGcp7mQzkiCeCJZI1fHp/W0CgW4K2apAp3GntZPn6qzoqG022zwvRxIHGO5TAfYVEUudZ1yQhEjImPmDPUtzi5Sci4KNJhEmVoNDDIshJZFJEJkWYX0yjDDOc4RSjejFe7RCWt12u8zFazlOXx3RrP09k8S2dz+SLLasDHO37iRzahIrKbGKsc1dKQ4R7S5E7NwUUyvowZNvtIUQ7YutOKHyqCYAh78Qfi+cob4ca22IbKjhsbhTYL2MwP131uTLyIFXNWcNwAkiwLsEBYdKjBTUTTFeX5nntumkXHDaPz94qK21MzkhdZptCgdROG8LZWkyxr22bKLqj2HVSlOCHdfkrK/gyTVmvUR96qGJQTpbjZJYRILDp2nv21MdmqvthT63bdAJ93KkYM4Zz4eCYBb+z2jCNe2FFNElfYAWd5yxBQraBRLlwrMZDPaodpFobBUtCAEJJ1GJ9QqLxyaIZhlHmdyP4bndD7b0zuzNzGzKHqOMHGN3icY6BSWUfh6UNNdq5LXshKHW3jcjXo5JBPKKFbV1yj4ACPER7bFe2kjFHx84c3r8lGNdVKtD0iD1DGNbjSZjUkhZQ0DFONdFxTaA1H2Ga/8oSl8rY9ntPxJRSOMlJ2sLJG6HuWqJkpHOi8ikaBTC7Ac3uAwjDr5FRuS8NBN0C4OdYGpwyOv3+AVzydRNtGifr3DLM6dWPn/j2dRkJdXPRdRW+JJXiO1zER70zTjDKgAZcdzhb6OlO5a60i2pkkMkFrvOwseS7NnSf65fTkrdEDSqe30Z2DsbHbWxrE9MBxuljQSZpIepjxnKo7JULa4fsq8rZ9ZLK7YeCyPoT6rgDsa33VMkWQjxbuRdWqR9TtAlluDbbub1ubDYNigEa1/3nCS7/7QndblM73twB5pZbUm73qeGz9qiU39jW2pbeSURJMcSgQ8YlCTaQoioko2smqh+rMa00lKoDI7NjHEVcdp8kEU4TziGKOpY3pIly/U2jqV91eCIVMHUZvZJ81wbF0kmZ9JLXXXNaBOx7CjDCdyV1bIq6WTk1WfJdkmTq5k8l91KKxZJZlfaboJPVHUeRYBXRL6uwWK/at8oriUtMVhqyTUTaTc0fcCZySbl8QNkzhWBKqzjX+oBYgTj00mZaEpqK6gMohFEPY3OWJ1J9wnydMf+j2SLeIhGY164h1lRetK6adLMnlK4VLiOxbyh6uJEzjhDAUYciHvZEld1XYVNnnHUBDLZJiPuyOiPpjLu8psrcMXrac25ZxhpflIk80KKkJqxOCExSGbDgxrU+JCvenpMq5mKLBNB5Oy1v2nHT784Op7WarNQciexmGy844WeWUkEkrwEFrbnAmDH1BpsP5CM/Iwrz/4FvSbC46JbcKX0CEZpzhK7LQM68m6iIMm4uO4Z91tCkl3ekbUsZbTkeEzH13Z5gu8tXt6IcHO2jYHfVdVmLYyGVZw0C7aQWzAK3tUK/L2otigS+JgA2Aj0jWv2wSImGnhGFTjf7oOVl2wHI+6h+1yKXeNmaa8CW5hLK62yc2uQ8Eus7z3Ga285ZOo2Z0UuE8IV3+FJ+THswMzH0zOiVJdI2PMMW3CCF4e4dpf0FONRjhQxtqnSpAMt16T45gYd/XO9x/8Zy876P3LRK5rlczpNPoiLxvbwxUf1Z7bV/9HRB9IJf9D94MRu8PDovCPgE4zsIHg3v6H8gH3YfzVgu/b5EP1b6ct9v4hBhiODrC7xE2o22TI31YedPUxScwTa5XbpZgzt4RNUP4FTkx9XXxC4Q/u88XrXd2ofBbctQ6sb1YhuHb5wYGwjAyIfJWE3avyWVnKeiVmrhXYRi9JuNI4tf4FcJHLfLKVbmC2HOEL00GzWyc4NnAO7be4RmK3+Er/A4h/DkMVdZL/Bnh8+c9DSMP1P1mldPY7EYMvYnfrvsWU+j+4CP8AOFlGD7Q/d0yApOibmnrdYlxsshyYwwbEG5zqk4dUgtmRL/kZhbqpfcprK5Fueo8sthYwYeNt9i37MK4SiZIvT+5a003JXVTwlEKOh/hWMAUEI4tKLVa2MOpq01ujWui2+cHLAxFeWLyVgsJgyP6pglhm5CuiTbhivA1jGnCfYKC1Lmm6TTa2BWOfQZkQ53RbOciCMrRbuFMojvR8rmSa30C3QFj2XC2zUkYexxuzBA8KQT5MmEBhtsOzeNhAJAZYF1yVEpVwX3eI9ZwQgyPvJ+EYa33CRrU77eKMjDX27RjmsMJit2Hph2S+qX2WiTLAKd67+VqNiocoLRT9hDlLRI0glbWekiCh63ITxtmo9qbcgDc+b9XXPYD1HoYPDTTHBwErbQjk1nrYQO6puoqe6mVzRu6SCtvBc9VdjOrreBgx5YOngdr3KSdOq+UdpLJ5OiKMvk6zSVlVAwi/rVnjaLYLBIF5q5QMx+riSy4GoBhpUjqywMWhJXXglRdshW1nBDWqd4L+rRyyfAvBqnPERuKERYI4URdcMBEVYTWCDd7CHMU876+61jeos8VjlBJvk0idMfNM1BRVFlCEVwrl2HoXZPIspOLMV7WroFqiG1di7oJRrZK0uwihJv209JHjlcsaDK5PZWJpP0g48lE704yLQot4ppo8UMVFYZAGIFk28BVsLksL0/emMv8a55M6CTAExRfp2zCrzuC/r2iuXzB0gW82h2LZEEHX0uMysI5lR/SBeUrGU1w77FHOfq8/KbFLbqUqTzelkOD2k9AhJ2O+ZKGYU6zqX/gb2QZqBzx3Rr1FQG85ELmYRi5MBH6+tzoNglhnVkYRqwzM/hR+LepvKNtG28T6j9ottta1kWFkDX4MGi3qy7Dl4Jn3NfmPTgbGFHiwdmgmnfCx4AQ/VZenhx++PPdEcimPA8eDs9GowLM2f8QFGC9/4eHSDsf0AYogodbchQH0aCpulmYbg8/tUdFOxo0288R+qHdfm6cAqPB8612jQMrltjOVxc5rRg+jz4NP50NRz/UrJ8/3zR/vlGvPq43FJ5rva/O56piF6FZPH9QDNWs7ODAzF9bJrMg3vlkpm4nxWpXxiBNdPD8YaAl68dqP1am+mx4+PLFhxdnQ6f/PTobPa/aA1ankb+WO9Yt76ez/PnZDnlw8J9ahi+HPz/YeBP5g7HGU18fle1h8ByykeFZ/nyEUKGDOyqMWmhwlv9wtlOBGLc81V59Ut0yDY9aO/eZlDjbGexg5xQr3vlkisSjVgyWmvMlHadJ1lbnUxAPR9pGfRuIHR8AvjkmtL0Pnr78J+IJQEvRpn+vkiwP1ngnKB7ujNZ1tQmYB521bsNsy8DvH+R6jbVVQr8zIYhJfBnd9fDTdb800aGqmbR1ftW18D9urOEFm3W03oI+1EFr7qFDfwqdzVRdJdlSUqdsq9PAuqu3vkFt5VtqxcI39K5Jl4ooZWDGSIDYvFVIN6IemdKRqcwooZag8EQMksWyv4ODMEBA6G1/0N8+RThIJpNXLIMDwL71b+PO3K37bOg9hbTkiPjoyNvJFiOBy5mRRkr3mK/zOjWUozVmHcAQZMevr9CV7KSGw6IQIxiXm7Qhd/B9CMWiv/W6z+8fidU4uaeHfUNDr/vpkHrlnNTawfn58NPz0Q8gnen1RsuEjkbF2Ughr5E6AqBnBZxm9ckDk7Xk4Gzn/Pz5Flm28/P75Qi3SThtYC9e3TNV61saPAIc6OnFKVqv/w2wcmTYPYD1jU1bwYSGf7g535+KYfDwLN/QqjNqbP8a9v+akJg7lT0EqDEbUeByH5quw5OZCX/rQAeHwUOwLKJ+EUJnpwZ81R7a3TzVNXYcSlwF5Pv21b97AqzXsPT+Ss3lItuO3/woOf92rvxq9q0sN7VarIUkC6F3tc7lea3AzSKrZEgkX3w1g8jzjXQfTWuu+g64WrK6lr4dsIrta+P7ZjPPQ5fnIap6tR7neUn5bnhB38FakNRXZALROkAv/buzfFSAC+rm8Cy/G2nvI/3CKBzcIY8ogGp2PuniCoDt23HbDtfTv/DA9ezCZgQdBthcqjU0QlZtsNILNEJfUZdrle6Z7xEZNo15Gk3+3lHb+LoNSr4Jm2jLoiy7LbhA0LxKqxsPWq/xSmQbEsfB2dnFSmRn0Flf1t8o7Fm9zQiprVqam6soX6JA445NctHOarzzaSWyutbzp7OoOEMPdjboctu5T36PHpRKgiuRBWpETqJho6SapLv1mcKRw086EGnXJv2z4OEZLJZdLQCaiqKDVvtUS3R2hzZlT+vdlbVr2Ib3OPC+e3Z9dvOi2z5bHR8fH6vFa57laNg+T9pf/ARjf1Al1UpYDbktXldLOdidpguD3KlbgXp3kvYXcBowtCGAyk1PedvsDPdjPKoJ0o5zhWfU/qqY4q9lMdoKdAMB9hlcjtVRWNJmUZDL2wxcQeV5gLBL93gdlRxoHdWu1WDEuMQtw/o2OhshH91Ezm3Rd9nFL/XttbL9/YW2GduCU28rrvyWcbpvG1X2HBNvccOqbcFVnbH+32SG2fpj0VpzE15ozU5FuBmb7LYPFlLBAB4o5IGGntaytGb0QK69rk36LRW8EguBurOB8/uMR0RfN2xXCqtXjUmAAnExbJIRGZBB0W4PirPWWWvgmZYYDn7Y+een//yWOwwffj8nV4kW1txKElgb3VWvyxsboGbjrgbAD7ZjpvMHL9p/bcdM9RKAmTrRIHb8be0MXKy0XFb9MBo5IPE3pPZ2tAa35BoMLzZM4NW63rFi/c6VuXMa5I5/rb7rzBNbYDi7KM6ioj6U4gFCWzR9rY5v1b/5xWo2A8Veq+ar/SXwikYvKOJWbEJmt64zZ3fQoHVM5OKHDwPdFbcpokE801b4UZnrP8629r/mzNzTBfY8mFv0kFHpmZycfsXKpFPLhc1rlWyrOrWeuUmtUcunhWO2arP9PJ1stzpZh5Fy2/7HwMGk0XH8frDU89zRv9rp0kXKJuBICUBtUEMG2r1Kd3jzh3YmO3nRPla4IRrE5+UXGqBW0R1e/AiZuj2d3O3ZBH6iE9pPTEr7CSQhNtCqMNrBjopixdvkbfGKge79rfPhU8t11hlUY34AtFTLBdToER1ZTZxK2sBXpW23AT+BAx8yKMjzIgyJxlQWj5Hi4IAMiufPnyuMpnVvw+JTk2hcd9a521sXZ4Mz8P8zOOsMiuE/FQZD96CwKhoadkdOcOH7j67NQ6s8p75yuy87scWkfB0H1VFiJ3io6ARFM6pemg2gARdA6Gyn5IufjSp6nc54+s6Zop6d9fTJLF3crvLRXRc/WUcDAkzbr1rjqZhWj9cI+Co7KsM3ud93AQy0renbqi/Rsx2fmb4Dmtw/3Hf3Li/eUGGw5erdgZQ1Nk06S8WBovd3irOdBzs2bZolsxwYCqrRFvi6LY1ROE+uXnf/e4hgSKyyKBwJsPlhq3lnQvQ1M0L/XuMKRMhzhLZ5CFkmIllQSUXlJHR3bwUUrX+z1YG9qpoD/f57qhvj/RfTLetcbqmNY/leiuLeu849K0aefw8X9b6u/LujNw3/2+0CTBVnObi7bVqi5HtsiPwP0Relp0NHPyji4f8ZukBRKf+jtIFarDp8oBJ0/sV9AfhaAUYB75D/DRg5u/sXYWS06dvAWb8oziY3A7BPVDs+v3KOWfvwd/Mkn18kldvlp/9oqvvohk62uQkHaxwYP7p0i5H1ilfxswfGl4F1FOuCw0/r0Q9na/SDdhQL+PHB2R3y/JBvOYtcu/dZyvqv4r9KG1lOff5bHm+tWe2zu921Qrrf2+t73dt+p1mvBzWHOFuc1N4DD9tMfq23iQWE4T1PDlVmiYULD0i21bbJRdmBoya5UPjgIluJYjwHhx7jLB1fghtRnqfmQKIMfGEKadxzoWJykemMVAiwcj9e5ermzwq+kmhQXNLbaBBP+DUrVkukfast+CqnNpYy7f0zuaLFgl9RVU57Q1P5BVUoRdA8/UKLfCx4ljm/ZBmXpqv56mKRymLFoPrrOaWZ97Lhz0iNOq1yvsuM2HtoSqeRk+MQYbhNfMSJNd0dWX0OJ+sFYrs0L4ro3jSyJSV/o9OstlNRbGa6pheXqaxl1MJhlNx9zuMKxljexoF2cRlgcREbjzPLvBcHS35NRT6nWaYiFrWYfB4HF0k+D/BFIlVQjucBnsfBOMCS3ii6UNKbYI0l0dJHuRi31SmwygPMyMOloEMbP4oZl9Gwlo2AxBGdBCP0lXTw+Y0eYv51bfu+2OKDvap9VrPoYznJLRLgRtBiIDu4pZKqCk9ZCXei7lY/pg+am2Z5I4bQHQchMxIEOK3q5kjsBmfl+tJOslxSNjmcp9kkKvWJBU0ktapoweHJy6MAoX7ua02R4LWu7H////7PwGiApZ1ZRRnITm6AQCPSwj9oN4O2NCFkrIe0ItHOWSc6u26hBztazD+rK1z3x4QOV6OiWK2TKMdjhJMoxWNkxN5Ex+hAdpKV5LDOog/yYypsNeHyyBSYgArIH29e/yzl8r2WA+tPOnxJWRT8dPQhwBludhGedDgDkTUFIVTjAeLt2n1CJp5MWxhGk44GpoP9bjcMVWK+5CynH+iNHETbV4VOAoSrE1wtqOCkriSYg1boRn3TJM2gPtuR52S/2x3Ulu9//x//f60c3ghaNmMraABd1JhSOZ6nbNaYphmNvRyqK/F9NcWNY1V4wmneYFw26E2aywYXjTRv0MVS3gYIrVWvKJtEiuJDa70D7MKp1n62oyR32/SaPAUczElEi8LhxE2tTYZApUUSblVaNidRorUVPWj2+qLWBx89F0WkKCue0c51IlgUaNsYlQJqqBO6FHScSDrpND7mtPFfOt/WQZb9+S+QAaTJpBOoXivQu2diyjJGtFcRvdi+KOZoXVOosXImnk2DPiPMiTzwLfqUEtOKdugWBcyOFOkiQut1hNZ490l3b0P7LFjltKGIj7HUKEIQFu339j1ZVB6hu7K7qfpKO3AW/54IlrLZYTKeUxAxt+KO3pK4gtQI5XOc4gRO0kQdonrkOXGGEKLgMMkyBdjvBF9+uF3SvHGVZOkkkVzkDW1BKLtVq6gAOF8tl+CXu3Fx25Bz2vivpeDLtjoT8/9qmLuKXmRXXwewtvuMUEPyxjjJMlXBotN4T5NJY8EFbSSyMZdyGe/sTC86C7qzyqlG+e2ylQD1tS2HvAOiuMErBhwLJhu/pdZZNc69JZe+yArtpPl7Y9mQUPMudgee3mMKzxkxBRIkppY3SbH2CBRTSzdS6/KG4oSpclD+ZBpLbJVtqQ2pMccU27seZGJa+1BXCzGc0fIXikiczxP4pTfJWMYSV6cxTvEGVMTcqSSwjstJGGbrNX70+NmTDYAsgYhFCmKRAt393n4Fv1SgtiwRnB4dvj/6cP7y5PztyYfzdy9OT88//Pzq9Pzk/fmfJx/Pf3/1+vX5j0fnx6/eH70M1nj30dMn99frLZcW2NHj2DBAU1U6M2ZotPmyjf1AQX+NozuwDhOEAQb7DwEJPNGqUiPCEZW0KLogGldRoGqkxkLCzllrZwZWMfJllsqIWeqhR/f6PAytsSmnYcE7i+TmV3qbh2GUE/dlLSQ4vaP8eTcMs+cqW0byUk9+TLr98UHWb7UscYCXeIKneE7ocDxyuCjBwX/udgOEF2SuNZBOppFA/cVz0h1EKzLv5KuLXIqoixcIL8vvRaunTs4VmeMlCdRBSSZUUU0f3786VNcQpg6GFcLTbfFLhGWU4onVtrDqF+lwMkID9VcLVE1RrD7IUP3F05H+mloR8nS9xrt7j3v3w4iWh/GTjfUfu27G3o+9WNtdrw3xmLfKMnoQSLGiQRzAk2Wgc5m1c/Z68uOUpZJGFA1oHAQ1YztBsF73vwZ5djvWARBMVSgYC8OIEn3LQTjQKKGEHDowG+CS3uYRRWD0aQv5qzWGK6siI45QS1iEUF0aOuQjNFB/azWWJpvS1tZKKch9av0ThuL7cqn6Kxn54P4+3ttSrOYXP3n85BtHqexosCRS65sobPbo6ROEpdGlJtJTimKRAjOF6Pb3n37fGf1k99k+wlyF9ntPFTnCor2n+11UMRvp60IH6iTL450dQZOx/Jx3uJjtTPg434Hrelt3WICI2yC1ZxgJWhQz0uuzA0e+WOzAWi0kWyQIEzHLhyOVdXPaXKkhG1lLVMGblKXTlE7UUTuWDehA4z9AbrHfuErzVDaClmwFjSkXcKpPV1nWMKo9ilxVU6LiGWftha1sQq8alF2lgoMtZygMBaH+vJGwSSOZTICBkWSNOc2W01XWuNYHVt4J1uk0agqkj3NNjSTR7u4TZPGpolJOqcQZGOixEz3WBwQo0yG8imgrOEyWciVooM4Bl09ngCXJhnREJKak26cHVkG2T1stpK+ZckiNCZ4laW41SqU1WIpC71RCiNGHsbT2/SnVy6NCrTufhvGL9l8ggbTqdg+7bfXz8jH8fQofx/BxDB+7x8dnq+7eE8i29+Ql/D1un616xyplt9s9bMPPS/UXsu32nqqUQzCWunt8dHy22ut2e+2z1csnqszxM0g5fnmoPl4eGz7ty9H/Vzt21u50289U0z8+Uc10dZuPoZm9Y2hmvzv64cEOnpJv0Ax4Tu7WeFGBqZnTdjcEs9bVH4/pUubGOWJOdgkhsij29M8+mKPRGe1tEy4HYkskaCcQrlMWq1x+zJ1cs7UGYEXYoBKrr3q7pLYVYIKkX+jH969JqqMEXfAreqSuklpbnSQAxrdqdMF4nmYTQVljou7ogq/y7PaUylfWJEvDHGa/gYq1+ThUZCadNJzhFiD6Bc1zc789mqQSlAT1RnbJP99OBJDfLgFkxAyRBBekrXadb8F+A72GRejiZg9Tbcip2cPNHmgZDIeBXovDuULvMsDmuz02ESNsXrnV5AVGUgtiFYI95iLAwZQLEyOXR3+v0qsAQ7hN4WN0j91pjc/psDvq3w6l7arEPejqsDfa6G0wrs5UgIOJSGYzE86XNMsONSsrsJoi356aXWivaoxms+lkJfl7ekVFrpqiNxKURt5TzZJ1dx+YjvEqN11SC0jFFX2RLefJv9CbevtBkmX8+niVZadjQSlrwPtbQ3XqWDUHoXdZcttQUyR4lluwa4BOY8MooE5s4F06Vpj9FTMBG/+eLrikqqaLZHypzp7FW/6bvrjSxjydTChrZJwvG4xrT9oNVqbzJWWNZZbc5pqL3xA0mZyw7LZhrd43hJ7DSSMf86X6ockio3neSCVdgBbivwjZe9+1fGO9+wIcLFaZTJewOouVhCjNLaWT71qgPdzsbtlJwdielcGEXwPb/ruq29++MYMxz/IAB4Jfq58crNpobe7vqfXxPbUKfn0KGuEBvHl8V12Pvj3BQFdckB2wXw0OokdoZ1YeA1e+yVJt0fLjcmkrK0mLm6phQU5u68ZQJBooZAEKkH1g7TUJ4QNFH3BA6nFThOGuI0bCMAp4oE6UYXdUFMGJDSOVwvRXT6W8tWGEiiKqUq+qQ+k00ncLWRT3pjYJYWGoesOgN6Wxx+qNSpobla0oiPUFS/uyNpegZnfrBUsN0DU2aLL6cRprdnjQJCRSl+nKwjlbGY8QCsNAUceQk9bNnTZ767UbXsWapSgH5Y0aWYOxetwwvMaerUzCSBr7rnI11zruUXklfJu8jSTS0Y/r0UXRe+4sZPbWkebCCbWOjACPF4uiMNc/Pti8eTWbU83WWGCKisJ+zTFFwEvXhlvRYKGAv9mNo7kOKBhH60giM+1qcQfUkAgePxzFdINDHrQYQjGvUybqhlghS0bE1bzXtKAchkEQsziShFeJHizqMUAG4a/3LmJEUVgRN9UjTWrxMAQLgGwQBLHqMBaD6kDenkYC7nCbA2QIIbQGooHJ9pwCZzrJjBua9kWSUzgHEpFcpOO2Ok4aNrKdz9OpbIyTpS04ztJle5nIuQ4JdbqAV6J25e16W1x7mmaSitykLQWfpq60oGxCFRXXmPBFyhK/Z5SpY6+tTruZ4Cs2aUzTLGvzZTJO5a3+gI5MM84nbajQhF0ezmR7mizSzIQVti5D7WTyeZVLEyEFleO5/bjNTEbLa4WPaz0ds+x2OQfpQhPkIqVM6vHOuUi/cCaTbEviFRUyHavLocrVTiZX7RsT5iKdpax90wB3Td7UZFRKKtoKkuBTdSFlMzPiRSIuqWhTNrHBReqCcJY0+BUVsK72db2MkfN0fMnUKb9MUibbXEyoaCwTxnPa7jWWHNayTa/UDbvh+gRLzGQDOLZeV3PJl6ZfELQLkUuRXlLjZ6jsRjW67EsuBb+k7UmSz4HR7Efw6TSn0saoQYyTpf/5mafMfoNAIMgF2hivR+rzOp3IeUPSG9lO2HjOhQ5P6Jhr0l5/lyNUN+XaZJZR5QhWLB3zCW1fpJPUfQh1KVFfMm8v1awuGlftRBGgF1Sm48ZVe56wmWrlqp1OKJ+JZDmH+EUi53SRaNC50opkdDqlY9lQEAVwdKuDDoz8r9vGNRcTB0LXIgUIWvAJbdwsMpbHN1nKLhs3ZsN/m9IzdwTHib3AV2jbbWGDXoaG4gQkV2jDfImx4Jn98oL5nF+bICho2/Dt9xCj393FwLzBXF9fd673gG/Ve/bs2Q40FlTItJtFFisMFWAIZgmbmSAg+vvItv9OV/5481p15+mO0/mvdkkmF6+Mvc2x4Hl+Akv+XQRk79sEJL7twDT8LOjUlAtcRKBrMGs6h5hvTSac2ngY5GKsMusyiaa14Ma6eKE//psD6OJm11HA10R0zs/N8w1413774vWpfcj5eHq09QkHX5LH3V53Dx/B72N8Ar9P8Cn8PsXn6re3j1/A9zN8CN9d/B5+d/EH+N3D79Tvbhe/gu9H+DP8PsZvIb6HX8PvU/wAfp/hl+p3r4vfwC9QcyVB6jh0p0CThqH+VbOlAe2YlDH9S3IcBcCRtfIiAcJHZSSo8GUBwidl3FQkM5PztIzVHOJzhTMChM+9KvSRLgKEX1Rir9IJxB6WscAnuFE1v/fa4+I6EZNzBQsIf/CaXOVLynLV3rvN2PMszVVNr8qkBV3wAOHPZUyWfLkNEH5bxlxkfHwZIFzWB3dbhF+Xefgy+XtFO+kkQPhBGQ2SsudSJGNq5+GlV2g6zYEHECD8xusBnSXj23N9Qw800/UL/pF8e0XBO5jkoryuffSua/Y9pSjsI0r5nDdQifFmCxElP4YhHf44Kgo6DP7X/7JNBCM0MMZrXGN/q8acRBoh5AsqHQto7jUybgU8FAe+AoxggLUjecaixg9RIhtogHZQ/wuRYWgud4G5OARnLGh9aVGYnt9Js1cO+jfN1k6nUZMWxe/IPkT1fyfNrnnQhu50loIuE0FPVRc+qFXq3xNv3p/AUUI6jbSdd1+soDrIe6wzeBxXDB4x8wDf5bTi8qFa0XrLi9d7Os3oWIahCXScRhu6U/3biI4kHo5qMy8IXW9mpHg4gpfiLKdQl9Q3K6+wKkiNMftyOH6R7csN5dSIXEw6jSgYZN2wt2eAonws4g5OzBl+xkDiRWyJTQi3dv96OCep++j3DkgSht0DkochHyajJgHPAn2Ut9vwkuzl6CftNs7bbbXQXl7oda9JSFIU6idHEw6iI+027j5vt/Oi8HN7oKqi3XEeNBIJrjYCDMEArUGIKio7gPogjL9er43o/J0CcnwffDKzLSJK6IB2Jmm+zBK4kBYFBTmQOAjQQG3ROAjKPfuz90ZMOzKZmfu+u8v/HWn7N+Yy33tcJgSvAVeahD0v4dThYZP4bEvia8DGOkMXuCaNXf3Tc63/ZlpXNICpqldP62hiu8yyu7uR5byeZ6MWdfpvebp2E/WnAVmNRemG65VN5ExLQ4JblkMzOPrbzE2WBS2vyXJhTmzPju2Jq0dzZOPf6dNZx567WHvg6vhTG38KJ/QbdTDplA8uxS6gjn9Xj4e1W6vOb7zHIwdNDx7oONP5w9iCaHU+gkN7xreCziFn+WrhuvqiLHNuSIGvFH5nSQhd+H1cktFq9Z15TlKrRJoVCQJc61sUBE1C5CA41iTHezqN4CEYBbEXZ8H4lYWqP6u75q0fb2DRJH2OVQfPl8ltxpMJpuojZan2yVOWiiTykOm64vTGweg/7hf4cJzHiggHfJgVNHxLIxgCH+Urbyko8pUt8pN/rKv2+yVOcq4CUBgGKVuupDGtVfPtoNn7F/wm0E+IgUgmqWb7etzlPyKQjT6HpyGFAC+pKIqoFrPFFZrq4sA9IcTmbQkz+yI6o9LjUb+kWj6di4h2PL1x7xiXCAsSBC06lGAkvVl/SwVuY2lrMQy3YAqm2r0nJafSstAhG9gEzakzCn+fvzCJ78acTdPZSiQXGQXtyyqlYSrg5jCfpzla4wo1Ase2GhxOy0yYfsX+FLRLmdrB0CrrlB9rhO9mVD+lbumHgMZrqa4Ha5xLvoSFTdnML15fdLjNGfP9alXW6/UaZHIc9PxqUHnTY+pbsK3UBQsqS5b5lXEgYEcR6cV3PsDCMBIaxGjHwFhNgiqm1rh/RIlAGiIi2bEjjyiCa6jr6191mlptJoWXvqLp4cyexkZqClVOKw+x0I62nGpEL9TZdMEntwbRSM85HUSX3fql6lHBDNb5hYju1goQqu/lpjfYf1K3cVf+h6kt1g8SbMBi2jm/FslySQUIzHfAF3ySmYrX3nxR6vfMPPN0/CYHQRBXY7AGmmY5kIELlVlNY31G/hHZ7NDtgfmNGXjk8ztK7qo9jQU2Eb8Zc9nmkTejk7iK+gCBVvAfxAxqPY0rXfFles1E6PRIlkVQGN5EFJcPqRJYN64kMyVNDQbq/xFJC7rC9KV8NGKolOgkYhDBK0QYBhrHQzEFWxBQucGYInwReFiJXRp815P71qB8oJWpoBU1NzSn+sMCOEDQ5puJwfOov+Gby6YMOIxWk4IMxZsZfYgJUBj6BdTk+OkIYQt6ZpbD0C5UFZxgqNUo0mzWc3mrI6gVw9vmaswOR9E0Xx9AacHdLmXTTa9RJtPT24S5dieYgQI7HvttUUxfArrevl/1bmNFIX24cGst1f7xe0nkGuiviBFNNGvA0VLtgZe7nLmvYwoM1bGyFubNLHcz6wGzDMO/Itrh14yKl1ZrRHNRzFWADWqd/sb442p2H+Tr1TD/1EppReybEh7dWfElgznXihyJ5Ba6pzykROfQFHLsUlrVOdMLC/7xWoQCT1euIwXJuhzSq2A/Ydk89RFaeUpXpB9fqpRcuwz3HAkak/7O/0qrheQweBC02JCPRqTZhZyMdPvsgPoynpxsQvcDRYOxkcVRELbSIE14G40qcYQjrP3B6Hgz96c2WZ3CwNPQfQiC1j8ihrDU9IXuOvW7DqMdctMDhQDdNU7F5mXF2nOVbplvbRn17e4qCp3HCP0URSQJiA6vbQ5DP3jd9lzUUMcKc+hnu6BbTcb0Wa/00mpP88oZve0Qd9D4jR3gn9cZrVIS0Ejf3bM1mtMkhq4cy9p5ju0R5I2yPppd7ROsKuHNkPHl0ntOnGOjesk9tRaEDbujtSRsbbC6mnPAQIzI9X1nvp4bBTXeiowr460cqhuHiAEChRs0BDLUdHjTOyNZedr45cNwA9NsQTPMnFVNIrbiIOHLC9PKDa9U6OtrhH7/kitaQAOrB7Yl3teCxZTc+xY0l4vM04CZUJ9tZXUarpxCw5Z6drvd7o7KoiVxFomcfyU3vJ+9SeQc/rx5vaHV8NWOeus9rWJtwz0qiq9XoGZzMAFZj68NRWtHBFMuaDpjJ5YTQ+Tg69XHmms+p3hB8YySaOG7sjMI42sNAxi658WP71+BIwaDSoKUNSiinl9D2XeYNJpTMvc0MOuKw5P0KkDIKxsc5Fez50HLbJSTaYQ8x1Ot4GAH0rEkc9qZpiKXcL71Kx/IkoRaa9lP0zpEfVnL7is5+2lovcbb7l5vTl8sl2EIP6CL/JHlyZS+5uMkOzZTO/DnWJ+QX80fbTEpvdDwtEZoHS+op1xxW6J6T3vTG5Tx4Ka1thITG4Z7IOHG+IR+KKXcgI6OdPRvdo9WdjzRTvEuKLlLrCeMV/A2lHJ2yFdMxs0uvgDxkFeLZEZPVjKn9cjTLB3TWtzv6UTOddzNcUZvvOBPgq+W5vtETFKWZC5qzLPVomxZf+YqODWVTHUN1zb8DuQxrqj9Pp2LlF3ar7d0lvipJ6qD2oZVOnkhaGLD73WNJnhkDV3B1+kyYf6nTIS034fQw+qXV1pH+BWYGFvHlDP5OwhfqK8sZfQwSxZL+/GzSzISLBC0g+BiOU/09Mjk4jT9AuO8Tif8GiK/gIQAhDhfQHNplp2UNYHclPedS76sfAp+SV9aeZxqlJbIKePeOKGbMm6jLgsWa3xFyTD4HcxLBDhY5AEO3vAvAQ5OglG5H24cNV9BvbIoHC+09O9UFIHBm0HMisLS/00vQ1fzIy82+HvqUnJBh3Q0iIKgJa2OcyxbwfLGe2m5pqW2zZV1bA4qkvI2Uynb7nPM3dO0JKpVWQza7QBhTm5oxLAcshEWqB9MM57AAQA2a0kwzvNjiEJWErCsGHMUK8KX8PXa16C7oPdJx9DtXq0kkS11G0jECxl1UVUguEWNAqXC1j2EL+hQjghM1xo5aYtLuMwsKFulki60Oc3EbLGLJNcYAuB2zDP1QxcXFHbKHGLTxQx+2HIFIHRJb2eUmZ0AO3pBJdQGVs0AqEDYH+BfJGPIcw1NrD2celTBqek0ulQddzK7JVGqH3O+Rl7X6Mre3hNMNVH6rZI+8e6uYNXaHnd1VRvv+vfWWhTNKDg/B2ogZffnq/f7cQ+BtyfbIYDdMNzSMKTUS+8inxY+Kae33YNzqQTvwDIUNp2xddK89i4WJIxxIzB5o+gbiKzIj5o4I+A53vgGmyP1uJVIN+KmXCwSuRGtDdxq0jLN85TN2iDM6US9e3Wp7K43E6e0lNPQkt6JmFHgx+Zi7LizWm8OdcZcaDsfk5TNPuaWegJFWXpfKsJ7MMf2qB9Q49j5Lejaw3F+TvX19oX5PdS/5Y54T+3LPflLRFTfoMp3C7f+5/Wl333aNZvdyHxIqtrt66sU5ZFE+JxGXhI277KyAjMfoAMv6OBQ/dNa0xTFh5QM6Sh+QYnHinhHtYWkF+bSQskLiiU5hPvlofrSo4RBYQlObbcoQL6nRvuxrPlVjRcT+Y9Tn2mpKudnMTFlxreqfzDvryl5RfEDSpo9/JJWhFneqEz67CIvDNuNEHJIiyJSFWA1Sq/S48oF059qd6kuOROwuEYchBsnuSaPqORhRAzlqE9j+7poNh5nh1k6vrQvifrL6prayJd8dZHRakYvrp79DV/l9CW/ZpsxW7O+4VdbYrZm/bisf2/NdsTALGgkSFM41gsqChURBRcrKeGNzihlaAF871GzKIwekv1SdLM6z+AbIUxJU2jxDu9BVS07uKmsixZU3gzdDqufAbt7PSyxS3TcG6blxwCo0mm0BJEsFfUjJXfr/vZnvB8pDpZJnqdXNIBHO//BTdXVXa8RNmq8m771JM1lgH+k+Efqchk9zPszmkenBdUt9EqQ/uhtKJziBOfYuAgck7r3SlCK0Y+VTtEb76G+FmbStm8YHntv6aAlypmeR4rWMF9/w1b83SCI3+DrZ/P1JyV3Jn/loVKV6aoydO3pzf5ja+er9X+kpmd/Ut8mj6vjJ5/vghmBvUw7SQaqi5Iic4U1LHgkiQvDxZsS2Z/wu26TRL3u7mPAuKgDRm610o3NrkDTho1EEnUODPf0I1QyG7Ca4N8f9lTo6SMGxIgsrl/QBU+/0Il231gimJIXBNuoHIw+EarlLI+KlK5YOxM6B31aOtkuDfGr7RVMH2hG1Yiwp099zPlXnUD3e+UYsn1NDuqdLT1k2uz2y3kvtZtUTb9QTCWWEjOJhVQrz8EVfGq4yYn5zc1vJkFg+U2yxOMyuIIyS0kCsFE44desAaHVsiH5ajwfJ2xMMx2mbKIDWqMjWd2AJcSGNYloNTVMGfMFdZrwatmYiGSmKlK/up6J4MuGZ3ZRpXqfOtMlvYWKLuktqD2rwGrZAAQJ6hGvIDTmy9vGeCUbyySXtKG7pY2lNYysj7oSNOAZqmGepjwhfo8dKDdP3DsQ26WTExZTPOELwDxvkwXYC1Lh09tc0sWx2gRx73HBMIP7PuSLOdYU2CFnMkkZFXk8FCOfr2eM8NQIUdAYTpkjD8ernK9kEJuV1khfcyD15EonhqO+wdJkECebuWGh+ZXLrb9V1flmZrOCXnYbowpkautkVNJIdkz8qwnyy8+4dODhH48ZzzcTttbmzdRc+ghwizQy7Xgz3yQkHUSUTGRUlnGbv0QZUtGfEqEwpFLRjhTFEe3UF7YgAktHTpeLaSvkYQg3D+luHhyFodRkJVe1luNYyBIJ/yoiW6l3hyOO7PpJUYQVnUqLHCNJwFkM8hVNI0n+oOquX0oMOuglUntqZTIC5zT0nUi5SOVtxeFc2lmpzXeR0XOxYr+ncm6zRbSz3FZCyggcUat/9nl9z6DlkmjsGBRb4QAAQP+/C/q90+xDOBS8UmM706/YlMNhgdZ+qSqinklPthJYyy5nKaBT2o3ZXM5+t6TY7RL8qubL3/d4EzywHHZHuAJ/1VXzYNUBHfOAzh8Sbvb6sgOakJE9M5ue5/RbaRlSMF41zXbjeFB2ISN9AsE50e8e8NrIKOGq1/3t03VXHqnqfualoDD8RZ2DRqz4/5XpvKtMmOlJOWcWJZSZwpBXkxV6kGE4k1EKWrwGrzoMkejEBBKTWmKuE3NIzG1iVnprv5UIjyuf5cJcGYTvD8E+Y1UBGwuprgpSUYPevszHczpZZfQwybKLZHwZeWlvuVgkmdvZFxL5hMkN7A/3KT3BrCuFJimwZDxQQXdXMuJ6NUobadpoUglPrNWyzEUuh2zUF5WhgTRbbWgKr3MReStxpVYC08oCXKkF8OJyHZdDnDfd1dmWCOun/lWlh5EgK9U79O3O6ZecblmBuy1HTFXS9Svpo4XCgE7T2ge6VQl0btavpX+vvivNCA5rQqwjRSRX9cscu7pFRyS4NmGpEt7wLzp2oQIS6+vapfSeVSibxNcyCpzH8QCX4SM2CRB2eVP7BHN/CfdK45cDwu3+MvDoECAsRcIc4QfZP7iYAHsf0K01PpLkbo1PZMWS0KlF90fAVjHzCB8ghnTpR2sDlBIzAtGwxLKRsgYcqWybsC0kn8hKxYQN5cjJaa6XYRidSPLVR0jDl/emWiG0IGXO0lVkpEwvZcdfrPIDb8ngVujr2WBByk9Umdx6R8rylQXyvjTr7VySUxkFfmcDhF/UYlMPQA5rabkBhPc6vtJcgPCH8rbyrgy+kmQYgA33ANvfc4nLWhW04Bd+TAmk+NCP14CIg3HClllyq0PvXEjFGe3wMumDi5isdKX6kuFFHNoIuljKFCzJeCE2FrdLuSU8qf6qa6X3u0lFQ9w7HecMsoEt5+oPnWhPv+bjpf+xoDKppL6pRuRmhlT41IU36HYdudEXNYHgucEPCT5T17hqMKf0Uqd7IZlkmbbDU4ZAY6QakumCahv95uOj+XgvsQdTABbBdQK6517Ie+X7LOt39pqwGNl1+m5DNsJc/bR6oz4nAWdBK+LDbs2GTYsbyyo9hPA7EM2OBJYKuE2YIzyOOB6KEVqvo8ohz/g1ivRmeyvJ07Kjry3SAyZM6OQlVbbeIwy8OZW0W0vax7s2ab+WtIf3DUN9dz+0uhZaRnMQqQy7WKJYldxTteq4Ht7b1ZGS9J6V8V2bd/fRYxv5DO8+emwz7z16um8TntrM+91nLvcTrL5s9v3e08e9nqv/sS0hyePdZ739R4+7NumRSnr8pNd9+vTxfkghbh/bCF2qt7e/23vyZPepLbSHXZSt92n30V738d5jl8cNv9d9svdkv/d01w2gh8s4FOsh+Xe9B7LKRFdwm7LZ64TRHJbDZ6K/laRrmOhdzEkXpwTsnaaCTqAETgg1SsgTG5WrWlM2M99mjUmKBEkxJwAVTuxZDSIldsRPQvsqnJE0/GfSVwWzQSTIaxllCErrgechSREoJbyWUW5S9G1PV8nCfybIlEy9kiSvl7Kjds8C2oAQYWEUdZ9Hguz12h9lJBAadOPewYFABwc91O7hrr63Sy1T3FW3qDDRt9/XcIniB6p+y9Xrv5WEr81sAB+QMpmwWWYmCplXmjJes3hlSIS6t/QRJ72Dg4iZDkmEsCj05pch+Sd3crDlar+U5esbTAwlbQcfj8Lq8qMBjX2AGpQfsXfbe7OVP+RpNvaMHqI1pNTYNRFOedFoexzLaHc//KdEaPBGRnqjUpO3u5lXbWqb+amX9+lmVtjS/wQmShlpN66Ojyh51NtF2FRS7ZtU+cttZ0pIsvv46f7eo/1HjxGW6yrLde+R2mj+c5U/9zRse893X/S1x11UhyO4IOz1njNt6dW+/jm9vrLsj+6yXV29gkizVWW716/vypAIXNmWKkIDmyK5PqQLmqOhdKA1Ippc/yjJm0TOO+Psy97uoAxW9ZjKmaODvd14r9eO/lZD3PldFl1UdNf4b1NPxmf4dxN+/XYX/yaJd8Z8zKn4UV1WUjZzV8afK1lqPCD8pwRpavcmIUsJtAe0KN5Sc2Zx8ofEKXlA+w+oKiHF7d1nGnFssztl5OgBJSkqijeg012+VHg1/yyj3yT+Q3YuUuO7wVXjq/J5JaALCq/8CdIwEScKX+yHGkTLq2sYtnsHy5JpRxECjmGlDcxLAIFXkCuwA/1r2Z73GJEiHobA0xUmdzqNuBFNqDVlgVW1mJbNAZfOazOdbpiew7xUz6wzjE2tqSRzfaV2RbC1HudxjE3uBHInW3N7HGOTO4fc+dbcFZbxlXEY4/i5dodlmgRK8VxGGejBRQoI/HnHHJW1bmEk23H61eOxV+/4q/V6ZuPKube6J2YB1x8EzLjQll0YWnsQ+msd3sgpjYTPp4o4+VVEHJlDNiU/0YjXgEWz3B1YJSTtyGTWt1zepMLd5eQPGqUld5f3dfkK31UXSe9nvapM0Mog/SqntVq5UX3gln1jKnMzxLHhgQAi+8s8QP1ifimryX9I43SKlsoNTPt0UnNKfpFYOFl6zIlRR0pZ4y85+Mvqyf0lfUlSnDqDDf1SAkOEIVP3dkK4uvbTVgsZ3wKiTTUXgPT6EswlsKFoS501bctRX6rMrnvE0vMU9w7koNd2apElULCK0aVLenvIJ5aiDsbzRKhvkGseWB3Mjo1GYdjbs6xA0ttDMSUS97rOdH1vD+G93QNCi0K/jw6oTymIUrrXZxd7Qr/+W3jC6rzA8mXFHpVJI2UNeNY+B4syYC3ZWEg+18zeVyyX1gqzvF1Sa2DZY91aU8y6gDWnPF4JoY5CHamBBG3IRCbmEXeYjKDYMBkROZARRzEfJqPyxFZVpvlLLQLxTsAxSyfEbB1utRFcymAzKgYTlNw8vGrNiYFgMTdDSnPVrWRm+Ad8uaQTYhLtduAV0yx3S1236VbVOkuab/TAWpWhpD6Hfa2mUa1vUI+IUBys2CXj1558B/UHBLV436TZQ/i+yRMMaW1pb9z+GL7a1Vq5wUbMPZ3V78g/ri4uMl2RHwGeie5fDOjwkoo8zSuTvcZp/k5HUyZjwdaKoFTdzxnOGB4zvGLkDsb9bp7kNO7iC2gwj7tYdwC00LtYpgt6KpPFchtJRjsuuSheJpJ2GL+O0BpvgFoXp/kHscohvMZLRhIWrRjCE0ZATWrF8N1VSq/jLp5QmaRZ3F0jPIV8E4bw3OSbMHynbT/9EXexDv2pOp2llMk/XEjFLZMZ/cP8Qh4psl/prSo3T6dSB5PMBBZUJjo0o/INn6TT1CjkxKcMa9klmCcVUPMkaJZIOtE7etv0ONVzBYJe3gHtTAVfGK4ppJfCigPakfzIuvrxM8a1atZ4wa8g5Y8trQcuUaNf2ilzR7RJyJiFYaT+aIJHpRrLErdLOohykIHTM90eMxvEWRn/Zxn/J4ozRnJGunjMCEU4V6BpW/zza/37s96/P+OMrdcIL2Dx5wzhGYRg/ecM300SmQBTd0qFAhOEb8sMCkCqKwM5LsocCtQcXxQEG7qYZskypxN1UVEAk9PVxC0ClL+qlh9n6fKCJwJYjNtGV8lgR1gtZeS7KpHgo+2m2pYaru7ENSN3R/k4Do7ycbKkAT5dJmN6kYg4aAT4NZ3KOHghBL9WwQB/XJrPj8sAvwetBv0N4QC/5NfMxIDUIH5Jszh4CTzxAP+esjg4OQ3wG8pWsTUXoz4C/GK5zGtRp+DGMw7072s+vgzwG/7lnUgZXK3U1go+snRCmQQnH8EaXzJy9zQOfkzGl8bc4rM4+JBcBLi3GweHGU1EgHt7caDlCnHvcRycqq0b4N4T3b7gWYB7T+PgRaZin8XBu2SV0wDvduPgMFnmuie7T8pJ29uF6drbU3lnVE3O3r4O62nYe6RanAR473Ec/MwXqsyTyszuPfVmdu9ZdVr3u5VJ3X8UB6/A42+A9x+X89tTYzzuqcBeHBzvqsB+HBzvqcCjODjeV4HHcXD8SAWexMHxYxV4GgfHT1TgWRwcP1VT1Y2D42cq0FMVdlUIqlZ176q6e6ry/f04eLta6PnoqV75S7W7ux8Hb6hMgjU+YuTuRSbjQOPGAJuJjgODQRVMyCQODMoMMCxKHFi0GniPVicehbhxdFpqplNHuYPNqIiiuNmMKDlS9C0Kw2ZTDumopPBOPW2vE81fOK/ihUt6W9mrIAx4SW9t/67ZEL5HRQG/oBpQgdmKIJ01qGfFtTz0qUVWKAH6GA0MAMda+w6Q+qGhgsGumBH8KisoigBkv7wqL03nVKFRUVT7FQfBGo/5RGGvjI816fL9J56gS5pIUxbO/W1noCXct+G7LXMAY1enven0PcW+OXA3alXX9Twdz/+lDvzLbShM+6J64rgLdwy6XnIed7G236tOC9XsSgC1lLCZWpMke+dFphkQJupXkSHyWpFrXWwqBZd8ij56J9JFIm41qj+sQq4WTcyhCXWofXDf+kluUkZsWd6tYLBlhVXD76uHj2+h/XvOyQ+1o5pmMtlKnugUezKafAF4eX7pJbVpx4tTEABZt1IUOqVS5Z9+lX9uqbKSYUu6a/EvoEwzmbzRUIIQfsfI8Bnu7eHdJ3hvd4RfMbIMw+CwFOusPTjjz4YtoLLZN/Q35oZsv8Mw+szKF3Y/m3kf0818oDeyVn8YNj8z/BrSo+YrVhSfWRg+PVB/e73n5DND+AEj27DQ3i7CL1lVgYJtldTUW8ewo9q9JiHvSvU6afeRNtLm9p7j1e8+A9MnllNgM+mt60loTko1hlIY1F72t/hpKPniPkTUbOwB+0FfL5BaAY80AyLLsXO+qJnAPzJyB7pQcbOLJ2qLmF9161HhwH60AW8GWsNOXV6aXbzgTKvjGl+foESX59dcgAIemCgHhTqaiDFklDTTPzegjGdbWQmIvqb0Mm52vaP1o898CcPSVJwfrorUWNaM07mQg2bzRxDFuV3SUVzRuPCeBf72VK8/0Egg3D2IJHklIokDJwaAUOlyhIEUw5JFgSclYOUHNHsRC4SNJpK+i8YMZ0bFIY/lGmnzBr8b6bDf6jy1n2H8JyKi2OdJ/WnP9l+jX0DVynHcyjz/8NT1TaeIZ5xSX5Z/Yk73A2b5D+Z9/MpIwJmeR2/3giDOr0zn+Yt9XVKm/xerepNwNeJA96QfIKxash0vtfn+Yh2Tef0HI78yzbb8A7r8EyN/qNtdcysWKYpnB9vRSzk/vyha6ndVx+8Mdsx4DrhG9dAeCXYxqUBqbX63km6uEirMQhhuJhy3/oEShn+y6Df7KCvJEOSY/maRxL8xTDFo9yFMyc8MP6AIZIOBdVw+shiFMve8olXB9OOKb9RL2Gct93AADMVIDRQgC0e/MyJRJ5HfGiyKS5SkeZWqEo8n6oatlZlKuRmj1VQSH/rDUScW/PSseJxO4UEraIPVcvvyltzLXFGt2gLnuigw68U2IDNKTmk+cKGKU0vPqJLm43ab0FZvhxLS25GoKChYRJJNItc4Ed9yoFdu7rwcRqqDpbrINo1d6hzfbLPTLV2qLCWjr0BIoeoFFYtKhJHDNWitSYioOu418tWCdPuiNMgkWi2k8EAijPVHzIZihIqiqYYyVB8jLPUvKmuy4yvXMhP2JbcPSL1iaqNqpWITx42FJ4uBBYHK3EuB0Po46p4iSisW8PpCaEv4Dw32WYIegJD7czeHd+BtWmBjl0C26bpPCVvTWPfZtCE6jN7I0/QiS9kM3QlSibD6fGsVXyrWroUxHb6Gngv/sXQlfOBrgrXyptSv7mBsAGL2mr7WLjDWtdUOWary6pq8ZlEcmJeh3HFtzHck1QVUfS9UfmvU7J2h9dSFNOo9Du/NEElUkU5eiqh8eqDGtyeW5K8I9WXDevUGJvHPH968fnUskoU9QPraYrmG4C2a3sZL4O+axWRvhJ25oNNSgY8ZxckmQ1qHRbUdUVIrjtwh4TTaPMpgIv5dIqShEIZHiagvsEjsX9Q0dVSJkjSrfK9E9dtSWWUkqqmSSvUt7IlU86io8eFUkK8T6Yqe3nqK4rkxpbowvzPzeysq5PWFO5KutCfgjoYA8EPFXJXxs4qdmQGLWdWoXv/W+fyai6KYiyYhf0VCa92WR5AWaUxZJMhcoDCcqD01uNPyy6JTzYcpm/iRR2yyju+03x7Qeo8EiUS1H2FYi3AWsVJ6Xargz6gx2AZPFahTVop18EQjE9HxPzGcuNC06LiwjnUFvK81nokwzEU0EximYiaIUDSrUDTrQiiiVXejQrRKj2g1ydY1oiFa1YLViFbpEa1ijbC0L39zofb7ZxkFRlnQ/miFPfOX59T+9XT3xiVv1ej7WaU/9d9pJSarm8OqeuKk1A+vqCEe1dQRk9lpqZgIfwxhpH8blsRpXGQrYVQQ7d+rJEsn7tfTWnxZ115856kxXtLbj8tGTQXzpa+MudCq5Uav0f5d5e5vltyaP9uUMA/vVcl8WVXPNKGPy4ZIJDWakyp4aIKgOGnUJym9BB+d+geUKe3PhvLo4TZF0qOqRikE9dxf8Wy1sO3rD3NV8rQ1cRdhBUNqyRruD4izmIW1IXqT6pU9sgFQi4TQaxfiVyb7iQq4tx8deuNCaukhcGID3OWHkmYSoawJv/HCqrwJnpRB7pWEWnLgQdsfyWezjJY/q/Ec6ocQ1A6cGf23Mkk9mKRXEu+WejtXghiit1GjxCvKtDUl3PuVdI3ktd/sjaL8bsTBlaUL+zeK+DPSz1dieCNGuIv6q6hqIgEPS0VU7EkcjRAus8KafTOrEUV39Xoaq7ginVQr4Gr/WoHxluu7wVwVdMEddvCwwWpZn3d/7kzlDs26enw0aDGYbaxa+6Y697fb+5FOuaCv9C17GFRXO8AlMwoHDkgCMOogaTkjHosPStWAxo3lHo3uksW12UGvbqe0UYfR/6H6rfZAsAHk/2YL2gWYIFpZpWEUSxpVBZNGVZukYRRGGk5FpAGCpdrXf6NU62hU9TgaTmmjfjqkbNawChc+hvdQuXahCKoWDSPK2iiVK6qI2WpP+Pv+UgClcEq9wx3OcHsoqs5VsVrFjd6Ys3Eio2uBfKtZNYqwpHC12Ih2Dhn0aV2YCPt3cmcxI8cZHsMF7B/WTAa4ISgNZeC/jT3/vzcsPDx7alZzRX6n/bpVj6KIfgOjHT9TskLrNThHNcZsqaKPNqWdyhvDibm9SaKVM6SvablhsriqhCK0QHFf3RUd1dWnsRE4NM6mwOyYE+pyd/Z2r989IEk/abd1tTkRw2SEM5J37HULj0lNVkvVlpPcNYdBgzMM+VaZnAgha5/mSEQc53iMcEqMVKHqU0K6/eTAnReJsYCckUh3B32lL/h/oCNrdeX7zS44JT/TmpkWj4Vw6rMQiARjU4LQVnB+ruWFgj5oEurrxnsRSazdtyPMOslkEgnDwz0XJNAyddqGjdpPLRDTFgmb8IVvm3TvsXXRvOttjhdwz6TDczEqigh+FQDm223rXQrolkRFcah65RxkIqy/rf9ytK7cyQ9FXch1/8DtF3dPcDbdXdJwfzTwP+IuTgmwi7cyAcPwWdO/1YVhlJLavc5pAYswbMowNEOypsM0btF+qw2vmBdkF6dErDXYSx6lCOd6uYJWJAfOQXscmOVD/QRqzdX6qRs4L8g+wu8FCAlzLBFOYCFzf5beb8zSOy17LJE1MOdkn/hgN+ZGiaMbc/IP6RnMaPRiTn6yMfZVh5M/5JoR7sm/q8YowtzscNz8ApwAR1UbG8mBIxlthKYUtUHwiIM8nRi49eMDummFSbV1Z2bKvtqkVzTmaxTfk73ZRfF3VPo9NfkOJT4IXwBeozhhFIqiXii1/km0CyELLYjGwHzrO1FqT/vIigJboWsQoNZOsBOHE++TktaYkBBeFE8JIbkHvrnHQlM5DEMpnUa6ao34hDWuZPqa9K06VmI7BD3KdI8yFIZRpBLv6RAqO5N5ncnqnbGDT0hizQzBFJlu5JWpihLyq1Dwbkul0+iRije9REXxGDp3J0hKkr7qUcpWtEHXCjt7HEzgaJr2mtUjGhp8Wfori1D/pXvTeG0tsLpXjZfeq0bFuLE+HFMMwvgM4YQMR/Y4zMkHvSu1ToWDz9xO+pLhMam7SvNeY62+HotYeZhUn3X9F+GMnDPfGE5p0ofocIAzcruZBZ52xyS4yFZiM8sF0OuQpltLppIK/V3Pq99GVL93tWUCkNWsdt2yTqzxIMM3ueftuRSN9L5Xyw1bQnXFEd2d8iKj+rpgdStGngEjdfmI68oq5fdNKjetHblvr03H4nHfHJZmVmncY1yYfJZl4X964/YwbZyRQ7+yxrmEPI0X5vdQxhm5qGR5r6LeV7pgzq84I9NKvEbYcUY+VJeWL2/ttLoJ15eyOCNX7N+2wpSUOjyVCfG4SNUYb1a8m3M1YsN+lN4fL7RU2soRvnhJmqswtJOhSAM8IauBRUyDvBU4Q4sqMs77K7XFLXE7xXMiLB6zRmcWJJqSOapasFQobKrwlzspFmEYTcnCkhnO0060IMc0muMJQmG40qzOdyKa4wWeIoTw0iD3OZlb7NY9WJVM1ByuRlmU47F96OeKjPB5prnHM12tEQKiVJ1lT0KJDD1cbi/zqOdNN8xU1Ixy4u26WjYbhYoClJkfh4ocbEZjwqqC1EXBfDlrlelXEY1RGDbHw5/ESB1DWVGAyb+c8JJPzwc8hpgq4TbIq6xveyjo5xQj94uzQZQRYWc/GpPtHXPC4GgAndJGocIwGqtSS/ITjcYIFcWjJiFjvb6PbRCy6Vd5FEeZJu/HRCC4Ooz1RK/IguEFqTGdJqTGsJqbmfZ4RCsgu2gYVqZcvwBHK/LCVFvlN03IBs9qTmwFgdoR+hzOBnn8i4gyhKcmZqxjxggbEFtFCzxvBRobYg1nyDLflzivTiaZ4oWeAVBSI0BYR9HKVDVRVWm8q+DWr2qKV7WqlnhBVqqvC5yF4RiZB88JGeM56eIpWZGsP+1PyWcRTRGat1qwY6ekixdk0l/0FyplgdDUpPS7B/P2tI9WKn6F8Nw61u0eTNvzPpqo+AnCUxuvMpjlI2RizWirTQwRnlVIe/rZqk1V65Wn7abDFo9kYfhWRGBwE6/0ZU4njB3uWJosSzxWWbpgSMkz3mqus4NfRCRQbN9+yqfB/J6nwYo92CwMAzBBDcQmPOQp9DYj/2BOw/8jU6RaOo1+YmhGuNDyITPCBJC6t0QKGGKUkXy7K83s66408w1/cqYrYRjNiBDuxjODiBkoUqLB3yxK8AzgKI5uw/A2ojjHAuG67Eh0S/Kq/xcUhred0r1dGHpetXTb4EMtxzYe59aVGL6tzTnesK+oZuwWeQ+gtxsPoGEYzQW5xQtBhH29RNvJtpkgC0HMi+eG2UV9eN4KRdhWznKPLipzO7LK0UPwYoovFKCpiayQD7VbtSL6pgJ5ObbSqK4u7YRDHYyvmNq+NSK4znHVqr1XZBt/tl+hL2sM5bhe5ohN7i9hXhg2ChlGrROVuLKyEbANvrAByGqCe8Bt7dWEoMNwd1e/KhsxzC3FjOGq/lUYRq9ZGAaXHDzAdbSEeBhGX1hRbCvTJORqsNkHQshVGH5hYRhdEMkidSL9IktF1+gvSTi6V9f1CwP3Xrh7EN2SVyIS+Mp/uL0CLH7DoivD19lGdFx5RMftGuHowuHN6IIcwzUHphCkQcmFInaiC/K26n9mQyC2vuLmTnfMIonqAq4mbW8XpGBBmB2IvTh6qQaIHzBTpHx7cI6cwdWBTNTJ9YCF4UumS9Y9C2tjvmuAh5qwVjqNvlj943q3NfHUfMXC0Aj+DlSTLEKYMvKLJFbFWcvGUk2I1C+PhiL3elKfAXAcJjtGJL0oZEcLrKuQkVgHJ4wmQxjaDNp8MGgPh2HvQIeq0lgNHQn8Xz25NmGbyLPNst7o7T0r6u0DafaBXgK9MF9ZB7DCoGUPQPTAf4TywZhbMK4/VJlrsBEOvQ/AeU0SgVtAXp8ovKe9Hznu0jv33GCkuSzfOaaunljiCgM6Zr4xf8MdLrn3sryuYKHuKWZ70b5lFFLQWi9vJo9ABdm/lqQwD6mhOaKUgGF+mEPRWTFtXxD6noJpg2o+qfPZS4vJhMA9uLmsmOXx7Nh8thKbzEgQIh8kJvzOK22Me4fho6a12O1k7zQ6Ket9W+Hf2WlKifT0yzXLxoydhSFrEiL6lhfH4HHCEXPwIrDhmECTbJrNpw/AR5pU8GZ1DHeXMebmbhllar4YTtV8Jf68MpzhHKGYW+RYy2qn1uRDmMG1Rd8Dm4QkDpzvF5NJfE+Gr4X15vDASEq9FDVJ7zdiK+Y1DgX0Ca/3RuxRB5Z3YSW/rLpAU3aSleTHioopzWK4xo4r0oVVHwTqyAOnnPaLce3p3H5vEcVzrm5KOm5bYk1X4X7XMp4H2W/kuDdDR3uw0boOWyV/cwpWe/hKDsqg9Vf549Yi44wmwhbyP0wxT3EB9lukXddYvm1RPKt8O3aE2nwXfHJr3Kf6vtSCwIOjv0thWV2S9sF/vi97emUsVdhGwPCIlggEyVC9fyyK8F7CftfPT0SbIEj5Krfiq6WdpW6f6jvZ08pASmtocEqoi9IDBS5q0R80XWgAIW3qzpNTbtC+bLeB0At2dLkwlK3WektfKub8VaO/CdLFPwvyHS9t+E9BgnONl47TCyoeBK2fBf5HGftO8GWuY38qY531Y53yR5kCjxu6QLn0v/riosM/xUg/1trz23sJ9r3s9Jn1HsCGP4lRUTBV1EgrSw8/up0BG8uRd8ztGaZTjDE0WFX/kNLiz1C5ncu+yVbKvjLQ7EQVYWVv4t1YwdGPE1Kmut6ioMBT0hwbWnJsTLC3V4Zd0FB6nn6GPbEeEZNFv0roA8lCju8uqGpNbM8nBCiPPJsOw3/ABFdGIrm/an8IZxHWPfMZd0QqzUpGWJsTjJPhCAtO2p70K/favDMkRuy7YU8hQ/e54ODo2mQhjA8FH2H9o08LwdttbzQJN+ibt1o2nytfiiYYP4w5J3drnHHCeZRzhMcQavYQXnGS87LDSx5VLBuC8oK5yapdDpYIm866T86te6DqeS0UdWI2yCsGYJu9MQ47PrJFkl9S7TzTKNf7mODegm82immjZDi1XqO5sfw75CMih9ytH7DAqN9J9C/1Tk3od3eKpAin5UJNfbAzGFvvzkNvWsv8cx6hu5RHY45wyqPM9wi14N67WsbtIjcJyXldtOXx/8Xdnze3jTOL4vBXsVQpXuAG0ZW8xaaCUWWyTSbJJJNtFh+Xi5YgGxMaUADKy1h6PvtbaCwESMrJPOc59771yx8xBYJYGo1Go9cDjMeFaQDU26ZBEnvbnMmmGU6ygsxTl3iUpCPRkBqcsSqef01SAitolkXRVk0EIq0egveslQNveED+ANuG/icXUMYwZ0naaRtzzk/pJtnhtLHihlPbtIhMnaWLuFppafZGDWRiYck8LKfhDcQdC4M4vRuuPdVaqEOMx8JcQ92SLCUmmzdBa6jmshGjSxgozl15WHyQ7thYX+Ta/b2Sd0UG/JK8bcaoJ8+S11azFF6+Tb89l8ty9gdn5Yx8SPtkX5dMV+8KLipykrwS8oo8TkoMClmw+zG+ZpesJE+SWi8vLtiMF1WdDeO9/GaMxI9JlUbM/XfJy9fyKrx5mfY8K+tO/wKy+4u35+hR+kFOPsg0iNFrtxD33N+nErTgkp5IhMlzSUds94c3cnKSfOew3NR58EZG7rJ/G/rhbhCPJcLOKOWJ9Bf2w0OnraxLDmzJx7rkoS15V5fs25KXdcleEAU0j900j+OPsC0bkU4PD307T6Rt+TCEIH3vSx76ko++ZN+XvPMlIWLqS/md4/kkG059MEByZYsjTlumkoNQ84sMlguBcZYoXK17lN6TPo7WPTn2C/vMfLz+LGMvys/uu95TGZi31xLfGiTwUcOsuYRlS17L8SeJDg+TXC3Wcy7NSuiN2Y7YsbnaCypQb4jdvd5ziRiiQDgEdB5TFb614AujyTL0WtLXIU7e/REGGDyR5Ddp2J9gv2Ewd20zpP0k6dXgPbDOdrv+aFp/IsWcn9XI+ocMIrs4Hz3w4I1UuJWNjFVZIUdSsWbPjsSx4dCOxDGYUkahX8ODafBXYH8EGMq9cKvzu/v7SjZu5X+aJXol6e+SuroRgxpxjL+GA2HMJfpVYpehcnDi+KfBiXvvUmZHrCmvRUxNYVKaZozPEXLsg41AW2HgnSKxjlitkOioYmUm8ZsVraxonaWFpL5PoEZ9PI6ERBHn7CbwQlJGLKwAmK4hF5EAQumKKWe6NuTy3p0WRNa31mUy0mDwhV4WYM+WVmw6YQseEOmVtOra3sgax0GEacNotAUTWRaiM+8447lXZgYVrcsxqeitW8GcEXmqmbpksx95pfOKmGu3DajgM4X8LuPFeNHky3aGhi/7XdKKvJAJTOgtTDofkniieUVctlamtO3J+cAbKMO1n4YIQyxFMcB1xRN/PMnhhj+wOphfl2zJ6O1poZmNjtLIq2eH8mOhXQh+GAApi3aZPi8Um+W3Lpqygwmbz9m08uOubz1utQxaRAMhVTIsqzisNg81PLeG6ZClLmmO2ea4j9678bOBfQgjZwP3FMvyCh6fILch+nNu+hEsr0hVnEFIvptSFjMLoanji+yvGnHqZnWNxPHGieaPPU2wvC0MFfsI1mNPACaVw4scuScBf4hw5eDbZz+iVTSAkqe3v3htVJMOuSGqLBOUUmT4+/ZIHR3glqZGExNUNNcI49uZhK8KGsFU1NG1LXQFUAcAMaQWq8E8cE8RrAf+MYK4BxSfSMppkXPKLWAKkPKax+ZBmX5S1Z84CgqlIedPjKbqDjSVTbTkHg9VEw9VwEPikqzF20KE7FiIUdHAbTxpgZpWOXPjJ83q8cE05akJNE+RYmyJy6ULcdzcc5ry5jYrKXczC1gbiffxbfOtxZtLyOVakiWdwqjHU4fW/oyhlOpJQZe5ti+WRNMpfLbYgLYuvsmMogVdJIjbGPJ45vIduH5mk0ULmst85vtdNKE5tVZfrtsCOxMaHqGFpkOyoEtqjZjGY3xb0gKQHKYwp0W9BYADUFmJrXGun02WwTxgENHemdsdM4TNUiSbpWhvlqJrs2BvaHtOGbmghdeFlrQicyrIhU3nOrV27km67xCQ6Jxe+N7MJqfnNmDEnMyIN7nYYusZPU9MBrZ28nObhZY+2B0ePszcr9X+rn0/zMNBi8oOWX3S7yTpND+vbX1nLuZqNBbb/nZu8Hu49qnlaviAiN4Ohu5sexREBrvdNsWT8EiPiuO8tFqiwqdTnHcsU/nfWCY/hsUELemCzsmUznAecGJO9IoGAmztvwt4hROr8Pb+dHAaF7S0h0gZ7b3m/qamqGMHrz15WoCt3gyTCP/plLRoB122216QX/SKauK4Q3hKuBU6i6Nn8EhWxmjlV4OEp4RFtUmSK3PZqj2zqtgzq7KeWR72ES2RLv6Hf+UEtlR0yctagrrDEZEYj6VFT4XdBWrBKRLsaksNwMREMFHhgWJzHeW1jaizcOaD5mBFNqtpmiEZT6rc3qCsb38KOUFsBF/Ld2fp8RItlRMizTm95fqNXELY43AVrfUAoAgYpCIsw/VDrmXT05ow8dU0/oFV9qCsW7HL1tGAEzbzEmEiaVGayzinBYekS2Put0q4wZgLDI+WBRNgsTgmukSMSKJwGMd7tiiLKfuPjaUqzuiI/PfG9FyqqWcN4iFtHpCwA1JuQNIMCHJZgPUB3XaDAB+oehCVG4R0g1CQFKFGtHOOYpfLImiN2yS3IWW3Ur+AwXYuE9ZdjhQ0nvficOuQbzfEUeL63VIxK1fwH0MEDDNJeJCEx1qfC56KY3sjIqmWhPv4L1a07SPGNdXTvDbYmHAqOOI4R5LOJarwZCnzSD7MDQ9sKyOVtq4xnoBmReJcS3OjNDu7AmuD9lb0yj0AY+SG50om7q+9R/jrkaJzTiLQ04pUTQyhjPx3NSHyn2pCImbyLCJXzM+GdKjYK4gtBGv7Gy/L92zK+CUDWY/Bho0vAQm6G/z0y4fHz5+d3Nnut+rY5t24rYxhzgcd5ANVvpZzvgwguGnw0zJRD0gIG6epIM52qEnEiYQTgC44gXv8+NIZ2sSYfCcOS1/V4zLvxOW6GqAtx5jAVUAAfdo4vA56YEZ3xqqnTPFLV+25khdWcJdlyJ1h3BxKG5rdsKSbWl2tOqpLiMgjioU+l5W1ObM0J65dn9GduADHXZZ11m9XXK1Q5W3AuibQ9U2WdZWiTgDcOcY7XiJMKsOzePKyAYWlXw3nT/wdy79hmGEIT/nMDa9mnnediTKnj5UqbgZcw9/66LmM2TgRpCLCbATcuRgsy9ph8+zngxNwYXEGEMnPUc8lKm/J6w5diABFoxTm605V3u5DwrBPldXv3w9ZFz1Nj4yaFJvHw48QG97An8GJNbR6z+bghwOFOUIVjVkuK35WljmsDJPNwUzBltDbdchizCYuFWx1JI9z8x9laxz3IknlnByshVcEwXSu2we7GFtjAA/GRoXDIaRy86LJmghe12Ku2uysF6KYNeA/Iv0ju5wuTuNxn9J2gEVv7eNCEeKJw4GtK16db31hN3rrtn8/DXo4+Etygfpkq4/v99f9vIoZhysQlIafkEnH3iU8K1HBBeUZXCa81F5NXBxAW0wFiWtRgfPKXnVcQfrWCej8T7ieuBvwQXS1EXASgdooteGM9QdqjCt7YimqBtqZcUW16/YiA1fms/L6ZqoxDij7hd0Y1o1VNgAyZA90PyEyMqkMa1M1O4uWPtG8IUbflFCA7fd0aDgY+7GdffQpR+7c9Joc940izDsSAttVuwRNQCYJtfAjMUGVA+U2EThXefpbRGLYKIE6CznCo5ZBKu2+TTicsj7dI0Bbw7t9AGFVnE3M/v1UImE4PzkDRxqnUaEGGLC/JaBbUh5J5Tq7cYk0B8w60hleALwfKkh0gpRt07IY0PKcBuJKVN2TMiNQ9HmJ7LcEHCj8l9YqOxn5xnaiy/gdgNn1gFmtqk0u8NakLS5JK/OLhZ01xAaB2mkRAP3r9wA9MlY9Ot60AotwH+IdM3qYLPXfca+Glfpniz2Lzr+23W2Xua0jCRbL+v37le897SOOLxurxDwu1bkIB/fu2ddOzPfFO2sIgyWVxRJHEjqwRMRYYi8tmIh6JMJK257lYdxfS7Rh0OZsOuVgFfQJhWC5Fsr1J5ZnSSbrDp1uE8Z5kyv3MJjArKwPSBf8u8ydBU43pbVFzy1t6Pfv+9SSLdhH5psB9mIT7LdgVwJXYLepORQnDi/tIgRMBsP8vKYadj4J0KPmlmk9B3EBEBe4e3L1fgDIW2iLDdA+R5G7QBdUVQdUQ2JhWGfKIOSD8Ekg+/37VuzSAVYVBQ3xYFUbwRqadhFF4NATOfz1vakY4BVhRDUBLon9IJ/a92ZsKbyX8TTu6otI7JZAwRKEdJZbiy5IQMpGvwaVIcKda3CBJAHX19rKwmofiHWSJQtakAta0CFxOhgRNA0Xj3yMoPHF/fv4dmHP2B8uJuiMLpxrM87P6CJwApfgpDpHkiyIPro4JmWcMPPG6jGo12OcOTn8mmXZIhzAN/EBXJmmMCkoRzekIBeBxV1OpvQmXwY24oYs6Q1Z0DMDxAtwGEmdqYRtaRqNZ+EsMRoTdRBACzpD0k/D3GHNKBatUSyiUSzIki6CNcoU4rIsqIKuN3VzRs/RgkhyEXcV/AXoWQyOxcAy9n4GZ4BKFzn8tWA6aw3wLBrgGVnSyMXHtNiOOFUbVxrwM7zGmEwj+Q7E34JobJcQ/+ETssvccUlbNq9Oe0McoQQq6dJy8iVu2YXujXAdS21BHcJeUE3OqKZDcmMLTp3CAgXT94ss650OZlKw8dn9+1EFfHvhcPhsgm7ohXOhx/kNvUhw+BJw+IKcWvdNMo3R+DKg8UWWoQt6E6HxRUDjyyYaX2CiKUeXRJMzXKtxlvQyDxuIXpIFvSQX9AZoAcwhRuALTJbRSC4cAm+YrcewU0Dkei428gNHp62hnEZDOSULehpQZQm4fAG4fIG/3eM5uiCSnDV6rdH6NAbPRQOtTwGtz/JTi9b/dKzQ4veh9dKTzbqWYd4MvbS08i4pW5bxcEKEdeeQamsKMdB447zwMQjvatQs7xK784u3zy8XnGFpOyLTOmDK1Hp8TN0Jvwyn4DRS3T7MIb2wHza+NTOeekBiAveHKWmNPGKyGFVBl2t1ht4eE3pP7yW2q290EzOOU8KT60Xc2xpa8dutgh9kSkO763picBP6u0TNiXjesSQAv8a8DJ9eGmbXNmTr+FEmzG4Zj9mw+6SMWyrDeawRCzyBW7upQxIRbvBWr2jXzQa53AVGAfxmNkYwA/AmJWnl9GoEtdMiuyyqsSyK8I2Xo3g1hE2TXi9GKoNYI2UYfJ5CrG4nBtC6iz3kHewh99SQ037/vnerpSrL9j3AJmjDpNprbWdgKny6Y6CYaBd07JQjHtiyi0AqzKtP0Zuz5M0yy66d5i8YsPIs6039JmeJZYW1SNjOneWDLXXFo728eUZukz9QnRYg6Mr6tUTOTtIqm79wesVRb4jJM/s0wuQtp7dr8oFTKdFbjslJeHrsn2ox7RPuPLVgk/Hmkf1wt3bciGQ6750k0E24kOgxd94qJ9y5WnzgxPTJonwW3oQ8AKGiqKJ1foIQSqgaiOKCQdLNT+9f5nN7kJB+HzdiMVZ0zlBFEaPg1DiJc2XkFU6a8XnnrRcaBFpZczNOP9z49v6RW28e85abWcGfxzx2UAfQPeHoMQ8eJWMr033C0Ye6kAgYpTMrxuPKmeg2oCViKeZLaPwkNOKMKpMRWRH8X7Cow2hNf+He09SOhkUywVufyr6ySGp1z1WqEIhMJERtQAWS9xlz6etnuPYKBc/R2l3UxoEITpMhHf7o0PebKEd916AEGih2yYryrZo5+f6wR9H+bubkdh2t+rk5z8lb9+B3fAWSTSgKsRDX4KtJqYs+VItfYXyeb4ztayrX3Grln1p++FWotA5thEG4h1jK2vKGfc2dP4n7+zQ1AH6T2HjeK9GeC7Rg/hvisUgO6v7TZ6+ffXz2tE+clCEuiJXNsTzHi6yDbU0k5J6g+FcqKmcNUTlLROXp2xrFn6dEJKaae/ll5MfYUMagioKFeOSaLdIgSeFtO4KTi4iBXVL0Gg69oTvV9/NWd32bicUZRjll5U4yhm+3O9rJ78gL+Lenw0+5Vwzd49b52O9RUNo4oFklAqroV4VE4kOOV6tQyRNub4w3Gm7vZV6Ft20RzFqlvuaU4fEbjl4bOrQ2Pw0eflWoirI4Ye91cFd75tvYiSgQo9oBIbhKRGEqInfi2MvYJpJyn0HToeVP4ejqUfraMxI2JV7vaWAsYAAwtiFxNq+VRyw+R2EAq1X/nBUzH5n3VM5u3HPvubIyyphQYWd3do+PqzF2m5NUFmTxgphO7BiA7jo0h+ULNiOorZOFFKGe1tqoei0N20MMRp4euFGv5J+4+zu/fUturVeKXfs0OkHgE4PD/72+PSEM4fdPE3harXwMgKiFtaNszhHiHqev+QS6qVncuEMr7nTLGnlqfjVnM3wdEUqbi5FD9Elf8TNPUlgNx+zRbzx2tvqNH7HjwcmVVF9eincuJv9npjSXwuW7tUK08BkdWi8p3vCSesr1oqim50yRP5rvIg8q8iunQ/LCDfx39/eV+/snbKCfU7rPCuQ9u8LKb49iXqEqUOx+kGaRmyex66sQ/aQRx97go83+Bqnf7s77JgoUmZVBx79yys28KlJ1mEU1HERckbUGHZKfai7HjT/Klpe2NnlS5O8LwsBWUmLys+mdDsczaQYBkCM9tL33A2/tluEI4zG/T0cG3B7yHeOKRvOx7sn5FfzM4WoT1XlckMpv49/ra//v1s3Arrft8EWyylVrfMNOVlsVyLsk3iagsGZktb9C+AlzsT+/1o+RF0V0vlFKX/HJC95Ys1ecsvwVp6+cswQjryLPeFmgGNl+536AL3hksh+IG5s0FtEOwx4lHlCOLm8eU+7GEvGmFX5lEO53TpmNqxiHSGrSSgPdFgiR+RY3jKFqkP4eG/vXoHXF1r3mqy+Chw7D7u+Cr2cGYzDzIla6d1mcTCrEcB7psYuitisxq0QM6wkDi4SMogUbszOsN8l7JmZMsdl7NltOmaLMWdD8zsGGup42p6LDEYTH1j7OlVZT6+02dk5vbmO4met11CqFwFqpAXrSnnRtgVgiLA2MsaSaug02pXLsHJKWdGr9MfgcoV95tsQgSHMtllmGSifstF58+ZAUAMp8OrAPhBVnTDl45NNB/NO+s7ji3lhcibwwiKLpR3BPjWvnDCniu3MZZK2E3A5p+R8ekr/plBOkaUkXhFOF8wCHBXnBLWle0SVY7i/XU+e/k3pXTbNsCutSt8ipyl07mnCFVPM4wKuVdwxtHhSmbm2wzt0vixglSfHTfeG2zVGjKSIGM3ceH0fmIf9Tm6Pujch6W4Cl8qZrtcS3ou0qpalHcDjQKEOcaI8YkFwlWgRtQc8V4v8AyNyTpQi6YBYTQR53Apt7YHOiIqiWBUrstKvByRmrHA81VtSwwydaLtWUeQO76m6OKwbTxNAESlVuOeQlxGp4zwrr10wQo2ZXW88ESKH6DWZOkd+4deipIOxerYuJRmkxoK5IAjLsDWO+a1o0zQ9OdIRKLQ/iXW+RyFMogT6k7p+UtOYvyJSWg6VbmiS3ght5WSBpYxpgTJZ0ejQ6Jgs6PRoej6f0FYf+Zi2D3zmdgZEhOafz2MKWXNDZwI5jPDOPy1M9VfzUovoZfcFrl+UUsW5Nc/mc2I/zioRPc7UmMAcrAkgmkXROBZkPdPR76QIpxNAZO05VE4bxrWHPIshxhRYE0H9pLlyMFiU6w0S2MGdFWSb9BoQSU7tdj8gBE1UhzkoWPgwstaL1W8isQwrKxsNHdd6QndGDTxUqMJnS0aNH5VgdlccrykiR0X9N1+s1JkeCVEQd440QcuCOthFpZthgjTUUNAEjRKEQiEWA8oaxAJ5xF3hUAzxRWt5keC5NE8TIx9hMyE6HK3QOEX+5Qheksg8zm+wUMZq4mxNPPmsv9QapzXlBWhQpX6xxoLx0SU+KKCPPCxCsTi19p4xMo8NEWDuJsHPItIHL04gaLjBZRPZwgdq5dZkWCM6SZlyRRXTYGBZ+vJGLY5AXmiHcJtYxVWYEAiO5E+s/A0AWA7ADfK1zlUWEf1a0bAMZva2Ks5yRqWKm/YrMmK6UvMkFmbGFzlUHf4wqc2+IHXknCLgxLzN01dNKcNGM5IrOK9rF/bXS6rgCnnRWz5Fq+Ngz4t6pRgc4NmqdF0nEqihEHDGr3VjH6MPzot7TslUzsvNpnS2ARS+4N8BnhqolvcwKNFqZT1wYzKCcUlY4Gdt1nrWal4CktPWRO7Dq1HXCX3Cxc/n/nbfZHE6LgVv7SKVXFUgR82JRC/Kh4VkBRsKcKLz+rinyNH5YclMysNsb7ZNdkhpknqa1zrprXbZq7ZLtRp3rb9/M7JYm5oJGYnIJ4MNri6Y9WlcMAgWW1E8kI2ufxqseylWTIAl37RYT4dM4HrFj2x9xs7kuktxlDCek64tB0frnsyLWOwCaVDWaVE7wHVjhFBVSUXpt0VcBMlREHY2O8UQdDY9z1PiWHjFSHRMWjezt/62h2DX59oA+JAP6WyIMUZ4OfhCTw4NcJCc1gzhOGBNT4+EjMTl82KhhW/mDDypVCBvfe5z8oiM4yxmoeStUJ+BKa4l1Ekj7pMGhNzxf7SVT+ktm43YJKBLdKUUqSyIFrZpyAEppMXHXe54jH6LDUtnClRuM9/cfbvimKEoqo5S+4CE6apFlBZTgnzn9k9PeMEh7Ut9n3/lqZcptIIYoYhEq3InQOBsx9mG6dKOCPfRKWiBNBHCePL3KF4RHd2xaGrYHwk5bZKuZpnXtIwzy48eFYZgL73CZC06WOoTny1kBP33wIvjlDkP74+XFgqmi4pfsp0LMSuaKXxc3clklNd+wC+ke/Zr6X3P35JgBeH7KTpdnEIQoFMyZUmwWl30MuOY7sfzjB8v727K3i+Lrkr2cMVHxOXfd+mh7XP/Crt4zQ6B4yVTeG63Jk7thEjZKTJ47DtsjRlok4ZiwdQxR27SD0003ROP+vpe+XtxBX1vr0zmhi+i8CcuX1rRkImIqtzqIILmThK1jdGhO1FKJrvZ71EwbVTiviGpKbyJetbK8qvo3eVXWwapW32JVVZtV9Vg+j7B80cTyLx1YXkPEs/DAzhNBq6PhMVG0OhqFGLU3RSvlYfUdRBxiNnfT7wouhuwYE7FubLfWzW9R2MOAMnPjd0My3Cn9EAOJmcPNNEoqC5d0x34bBZrLba/7t9G101z5o1/2eHDSABZJA8SaTA0f6G5MnaQimmakEocsk6kLpR3drTeqzF8T70+YMwKGqm/nOWtkpXR31tUKQZJogfoq799Hn9X9+2n0cRyLfvYwnN7CgLzCEQLYHKcvOBib4SxDNQdrGMxZgfaSY/6O/tbepMw5wpAQ/9B0Sjd+R6r13bT1/d209VmxkTqedlPHq/Z5c1mfN2+T86YI5815tBMjiLg5FgXihcWIf7xB7bfdO/T0/+kOtSOrd+eRuQLWAb+7tuOy+wDdBLGj4fE3lv/j/8vl19+5/Pq/sfz6/2+XX/8PLr/+zuV/VzQsEt5eCabIyyIxNPgrkgk4i7mgj588AzdeYP6JwvkXDhYxUKkRzPuXInYTs9lXzEkeJN+KzQNjYZqRmCgamRRwUyKCIcDLIngAr+iIuFGC9t/b/OWNYJPN4JTwcUYf7I0e+iBUGf2XJH/atmR8W3rdtm3wY/ECDxFbpXX4yBSr1dMSFXi1qjOxJ4Fv68QPEGShUCyqKpKqE4RY7NK7BFcxsLKQM+ZsoOcWqoRFRo9uARkAB2Ia7RHr8UkLcs9OsnCTDKbFhQ9xT8yhJjOOIdtREQ5/GBNBIhguiXoOeCJyrTCSENGHwbhcwAQ8caDmOI8X03qSF8Ef+Y5p1Ct0r3uFrD2ZVqhhqNUxGvMJID9Mk2eyNit1RikOS0gY9tjmaN052PUGb3WIWw+95xEOR+N92tKQxYaENjaZd2bgdxtNgLnWOZ/NGGT4UYAEq1Xf7/4HM0MnH1zx6lwuqwfnfGYN8F1N7LLY7mYWfTBuSpwh/uVrG852Tc5LNCReJe3zuvsAu7tZ7VQabD34xNpGWC2CyEUw86mieMR1lN7dlsw7GgFzI2CWHIy/Z7Adw8iFs1sML5GiyTA7bZZwrqiwrarABjvqI4kI1Kde6DeJNMgSukA8ah/hsPuZw0twHK5jE6zoaPsgwp/nCUG1VHQukWjE/vFD5HQhkUFZ4qmr+MfUVfxPUde/k7nwOYKJ+Fn1huMbiSq3XGAGx+coTCMYaFc+BFYNSBQJkLxpV6vATXMbkwsflYLcuCd7DDnZ0lYH1Y/6Jbpptj4uXAgo7YxRCh+IiUxdBAQf5qnDBa1OXDudCI6mOIclnHYts3c5ExvjKJFFV/qrZWd4pWJTeKXxojPAUvHNYFudoX2KzbG/ViuwZFCrFcwfZ9mZWRFzNE0xqePUzlrWFIWLZjQjU/CYJoVZw7JZj7jmZz1Ky9WqTv+xWik+6Yh6urW04a0MWiwNirSahBTPiq9W57aWJorMwIEWT9A/AdzmyFRFd2SqziXsarKrtDse1Z0ju+Mlwhua64obVdVxo3D+jVl0f0YaO462TItoCQkn3UuPHSUJW5FOiaL63+1f0d7IUqbblBi4oOhtokCmtPL+i0l4l4nO/5A+/oauRz0liyZ3MIsoSdmiHKhMiQALQPS/Sy3sLg0hKR0hKTcTkvkdhGSMll2UZP7PKAn+B/vhP0BIFm6nx4SkdISEtIgI6SQiAJnzFsGJmj//LkIyrwnJ3BCSVpOYoGlMSKZASM5JaQjJ8h8AzoL6e0Dmo+d9BynxjXYWIwXj/H6KUre2+a1r9DsIi28t2aL/BC3jT7f39lOy1AW80OlqpRPDdIets7a1+mq1YXi9bw7v3+vETOQ7COV5F6E8jwhlSRSd/n8HIpZ0O/74x5QXrnnTHxv3SsfOjy371/BDBDM0lWW9wt+BZJadQkAo0hvh6OKoksPiXVFn+HM2n0Xntu0kyyCNdoYZTqwSaWlqNr7mi4G9t3foVGZjOGIemHz7Ego14Rjn7iKgbZ2mqscGmIxmPOy4Dn2KTKCSXI/+hHMCx8mFREPSLG0VWB9P+4zz8Jhl7nN/ShroW//k1JXeest+LchvBflckJ8KettwsCKKVermNZiBR0GU/0jv70Q2z2hO/6rtNUGmZlcEqSbW4NUKKYpE4uXSayEwhuQ3aDvjGBM1QQXtDaOL1v6eNx+hdZi71h4IKkE5mDtB72rVswVBWliYWh/PuX4eqiC+oiPwSf6Lk1HGoyCUKAip6jaz7G+OKms9GYkx6gqkmCBGfy0goBKPLs6bb/Ni3cK5nwrCcN4KHxBNhV0v2LRis9eymH3kF+w/1KuXX+zs7O3t7u5sm2EgJOiPJbq9kDOW9y+55qcl6xM//ZytvXyuGdGslmgJc+I0zXKLCZKRfqt563eNBindmNEiCXOjqRuTkxHVQxLrVF3FMURkNq97lBYTBPZy9sIfS2qGtT+GPU20Jy6ocAlLvIEdSiNkivhXaktXODOQKF7m3fE1oYKwskKNA3mbKBuIUuHcBgcBku5B7k+AOvhI5O1sHn2wGVUvClFrK7SIQoLVmCww2LtYCsr9KrQ4yrYsCRLQJKiWR78SWdTaHMM1/JOcYf9qS6p+MvxqjkQLa7xdn0eVIKmTft4EACrJRjQWa0wstlRBtyncdlC4G5ZARxOxTGOhCQte5nesOKtPJtFaEdE+kmy3saTp16INCSsyb4Kk2rhpqrWbv8RRKG7E0w3C0w1S4Zwb6lARSZwelwgbTFL6OHuEx1734ZHXYPQHNeUkcpl/4SSMzDvoVC55QJwrxw1U1Ku1gsxRHLEQhiAC1O8NtseyOw3K5D18iqZYmt5y/WMx/XJVqJmGnGeGKQnGHuHnh6pQNmfKEKw7ckWqgpe5gD9vDPxtUiWnTeTrHBWDqG1akWIQmrMLHhWE9umQFIBJwNqaxqlwD6YXKt1rh2ixoP7VtwX1UXQKwiE8DQehvNdKJUhqz3CkIvYAY6zoKFOr7Vocub+beC/ajeMYB69rwCy3Xt4+lIWvGUX0sJ7l3RxFlgHqOFl+CMZhP2m+Ck3Y4+DW07mApyxsoTiiBquzFW6xJKYG64ypwUJMDVbH1KgbiPIVsmY8jYDIrG57rTI6MuOwnItq0K6WqsOMwk7ZBaCQNvhEfy4VYFwfQB6OReLyS/rtFeIrQ1TzOnpx4MggDAvozwTI4AMQRLBQl9gc+L6DWOkK2SpETaoTAovJ74ax6Y3MYUd4crj6CDkwlVO/e/xcYNt09+gnJsexSg2ZA2PT5Go9sfQR86LjRUbUTFBJJGVrO+6h44vuGnolz1h1zlQ/93MNR4u3ken6NgQG6ljtkEu0eVP5M2z8ZA+iKs3z2EiFCb6Rjj2EvS6yWMmFG63V3JbfWM3QTzt1JMU4oI1dOcPohHVLY5FEZ2V0KAcSUW++aLeADjcsEHBRjUZx1FKCfU0wup8iTbDqTioXiyOK8WLpsNtr7sjNISKHoaV1uIIYJ+Ng5nE0b0EbkcsddooJc6TfXJXT4cdINpVlWSw0m/Vz0RyB2rDdRTICtWFzq0kVxTAwDSdDss/JuHKVQrmGJdN3nUvjEO25jp/joo2N9kOYsa7oYw/tnwNX6j7y0bl24zg4LoSNL5p76TXOsnOJnH4W6uyE1M8c4UaC88+mCCUCEdy45RuQBjGUasoEmgWOGorkMlzvsNUKfTKX00ktc8rVwN35m1KieBJ7+UvznTNZaYT4MlvUCfZbPccz+63mQInX87okEamqNxz/PZXGnKrbaqae369jRQjnJc+aUcdg6vg2lT/5kbvrYlON6cMsH/2hjmlF1NGv6thc+dx2nfGilGf9/INCfZs0vm9mBz9LqVk/xA+0+4vPVXHB+oBRXndhf7CLU7PrzJelLGbNDy/5jElXtVjOuOw7/mc4Zo+uVBzD5YNCV+qIHTdasJantgdm4NYa28WZ64BfFGd+kCUXXxofkU2DnDGzibWtXsmzs7INALFYVv2cMaTMxdVU5OKyKHmrMc1KgI4anFypYrHwPgW3V4V+sywrvihZ3uvpwYX7sb6rtZCeIy+7u16H6NFbXGw9Y0gQcIGF81VjPTgv9NsrYbCCqeoGTTEEQNVH02PS90xun1I6nbTjPE7UwAwANqmobGRVxOhR/SHhxx3SHJ5lzS/7/fvtj03hMc7LrkHafcizrC/Fh6mSZQmjzDIDAG0LiMLYo7pHbbdSvyOFiQKYQeiuTphCpSVD3StokX0B4tw85Uo6FBR6IMWTkkNqSjWQYmqe6WuF14o2EyuryJculqNbraQPDksPITJoiEzGcz6ARC9PXZhFcLBZWL/TGUMCY1cyMQDiiwrCQYHl2XRgXTldZEbUn/HLPqT9EEz99PHNa9p/ZL/54dF//R/31CeWd7+QlwzihiEWBxHDeTtw/IDrSbs3QW65zs3LNc47RiMw8VCn9sI7pYyosEUm0/BIe0M4YP82057CA7W/McZ5q+lfPsCViDBHCBkQQkW+WraGRCSVMjKlb5lN2XIXoWQJoQTfK/VvEsv2xxsIJqfDMY8IJg8Ekx8ThseNVjqIZsc4v49wsphwtlvpJJ4dnQUCCpFdOf3ZPiTkjCX70G89TjmLItqmm5TdTWZVRGa5TTOryC04FHgXzDvHkNBfN3LN7hp6CLlM1RrIMfeWPhxYUm3o9BLzOVo2yZ52BlQLujzSx+O+rm5K1ofUylemzwXO+7NCnDEll7q8+cCql3772lqWqqAFXUwWg5OT8+qidLPEWXbmm4ipvm5T/cUkzQolVqt+HxI2Z9mNb6NJ8RfuXb9/37zWy8VCMa0d/X824yDb/61Qwia1ojrLQq2fgJHjUjTeF8tKPpfTpXYFqHVQaOzmvGicEzo9J5hXtCyy7BoxosmCTDFebzo7GJwdjCjSG208OxicHd04a3tTNsZ6lkGWpsdVpfjpsmKoD8Vw/v2KXCW8Ab1rwhchszs/kPZd4ElhxpvU0WbwYSQOLz/bAbVrpzWiM/OOM49HZx5Lzrw3PiFocryFu18H87xu3VL2c8MNd3Hknws0JK1IjoZCeA68lT5NRXmk7mbHReOeQLrY8Qlqs+ONwXjWGw5wAKoT5qY2VEhRdAjRdusQpLlID3rsDrWP7BoiIiOFsWs+PsBUBxBH4R7HJfqLY6JapjMN3eYEeVWZgPxIPqeq4VqoE9+AFnFj6N9apQiwyoOVeVNNprKsJ7yONNJNBFPbXlfzdyk9wbo7i+S0kyGl9J0hHu803cE5Mi2a3zvwd7Uy5btBN3qiwekYjXZ2t0cPH24/zH7ROMvSotcar1aLEp1o8kRjbK7Cq5VoILtVENhF2E3u0vX0Hiu0MeNWfI0dDX0DP0tUJW8efsdVfnQIuQXs+rveUQsPksxC5nKsm1rv8O2Uqlpij81ZpvHPBbLUMhiZOwCLjbLwuyTh7heaOgmlFZ9FsnbiOwx6TE2nSfgRWI+Y7dakuT5gUV8LH+0KxrpPEEskGq24PqQYF80ZiDE2LD7SVGCv698muqVA062uiG5qSyOQ6ySznk51V9r7OxAdiYKJbpgQNQojnZtuB9DUqdTUldXkRljxdjKSafQjDGrqZKt+aK5Sa3TTBgltDrQR3qcx5mTxibYGm1Mr3jEP8WS65gY0zTzkEElB5953xF55vA//IP65TmWGbgN5k4uaDK22a7uaWNXhKStIEbPsuUT4h+c6JiT7u0TT3rDG9qYdg7s08jnqaZzI+3/haIqt9LrVnK8lUi+A9p4RyZ6xoxhGm8cOPPFl8aLhLOtNYxlrFMvZd9/QFsd7yw6laV0AHVu3gu3/bcD1QHXoDgGGtW9K89z9NkzHKlZZTlBIZNLSuExxjmpg2gngSS2pnuahJrFv6TQ5psPyT+B780RUrCAlysmbg8g/BlMCQNIFDPocToNUs18lpk6Ar3oyyqrVdj7KzAkT56jb3nHJL8I5dlGiTmltsj97tFaBNM2ivuHp1POeTh1n6rqpbtknVmQeR1LWiHUGpB/lc+nTcthzMgQSh178Ft4dHu5nECvfGjk82B0ePsyq1f6uv0t4KTmfo00ScnfeodB6K5XW9sFeFCy4oy8vxnZVIJtEfLI3uTsYd9Tht2cwOmw0Ub9qsy0d7EgynjswZZwGzbfi7nrFhLZ6Jh/CRdB+3/Cq45m8FffpT8jlsHGaZBs6U/lIlFGEFkn7/yUAvltnTIC3szjb0lUx/ZJv9e8bHNW6OGP3+/8lzE944zakEwywKPghfCejgapooFMptCzZACQlqHJXsXosmsEOlMtqY6y9r0Vi8VOHOe9iKwwp36MuT/Zqte8fMRsUC3OcWSldlBiiNgbY9fm1awc2r5gUqV2AgDPN9h3bBURq/cQqQHRaBYhgFSBiqwD7OBbh/Vo0jQL8m/hoXa/Jb8UG2yjeNCaGAD823SRLbmnpTc4aBBN7+m8QI1s5FVybnMBK06PjO6RUUNXJq1p1/a3eSaJ4SxKlNomomi3Vcggnj4J+dbvf9u2913F777jbq413e8idGLQNClgga4UMqq+mjGaBs4x3FVo05EeLY2xv7E7atbDLOoVXgGmF6W2Kp81WCrgtrlZI2CTrR8Ux7fctR7RRUmZzaNZSMPf72yKrxTdEVoumyGrRJbJa4Am4uNCjY8M8Uw2ZvGyI2oW9NNrkigBih+JLqgws+BxN3V2aTwx0HIKQTqAvbWhndwgv/U1sipvgNs1awuMA3euA9Gq1zLKWyNKUd6xAvWpL3PFNlk2PiuMepcuj4ri9hKbUu/oaUHlwER3ABAFcluM7FxrSEaIlXU6WqTCUTOl0Mm2UOSjZUNhLSMSYLs0SN2Sni0lLyrTMMi8arctg+Glb/f795XeJSb8D5zpRDIXpJGLRRVMsSvRqNaWULj2Mcd7yal2GEwMwwMfooZS+nizr+DUd2LzEeC1aoHSoR1zWxQXV48alY9EUHK7J5y7qLzpUaJYj0F0Ob7+x4subYjFxf/M3xaL2DuDBOAMJWnD0YASZr6vijO4QMVgUN6UsZvTWuf+5EOzekAPIddDkQ+bU02L6hUan/leDx1/h4vEb2N0qjYYQHiwyDC3uGIXrzHKvG71Kxkm+15qce+tZP9Z6StEY3QTcyIhC0sW544nnR3p94Z3nB0/8i54YlggMWbtA03E4qVoO+FlPPmsq2NXWB1aho+qc62Ocf9aDYjZD5lcAJXZxpivL1Y3Ny/YwPKNGbsOrD8Dm+WvMhOX9/hobcgST1xux6QOrJu5v/oFVNTaVOvaZUWyepLvoXqIK4hf6yKKWiazw7UtIXO7oYSOOaOhv6rjSDhuidqpCy6JvO07c8fTmIrO9t++FffWlzsdBaEnbW7bFlQ1sHNkEbXABQ1UjGamVXE5E5E4rsLW3OTlRrJhWLwXIEcqu5qiPruXvZA4/ISNWMqdPdwlcsb9sOe2DuwOlctbm7XN/J753LsP2Denjv2chIrFNyEFjntJoyvFNP7eMguFvaVVnGpijHUrRTmavvN7OjDn1wZj5WL5UIRyyOrnLFAPUXP+nxuJs9cfKp/owt+HdDEkq7eCsPHgENvnofYmEOY6e2L8Y8pAm40qR1V+ZaXTXIbuZ8AsdbK8mrO0QjqxWo4GDNjLPpKFtMBjpYvY03hjkbLtQtjNlfB8OY2xDxqFNIM+yJUcColDiSPawqbrLBSoiNw5/3wuoaW99cbY+5itFxL6+dWyNuiqsw7iSNdrrXqMwRwoRe6Mle6NCcKQGoLOMDeaGqUY45PZLNmeDlKUEINxHG4b0YDhbB6v1QHIv0iVsvKz9DaM31xUS2PwLchVPOew2d9t/22eSbYpK7qYsC90UD7BxQyDgt3sEbpt4sH3WIEgHbNgwPNCs8pzjRMW/UH/G9aIsbvqkL6RgfdLnFwupqkJUfZyrgXtN7Vur+Em7d9KZhgIPOh5LR11klskmBxt6xhPpu3GOKPbr0Pc1i4ZpuBUv76iFI9GAal0srSb9ft4YWRCWoO2dWlyyHUQnwRK4gR+rlXCJS8S/L1rpSmL6D0Qr7N8XrQQkm+lg7H0tO7m6azmQ4om8uODVc37K1CdxYSgqcC4b3qFLadiXKITyt3mU3buOSMNjpJSxfhPnKMWBc3EHnT+WFBXgBOQOQ7NJlE1RTWrHWOxy1u5mCuP3JapCAC1FbSoOiaJZvSyRMiRwLVweAp9iCViodUJE+RyVGlVdcQ6aDFQaWyECNnN+/02zA8emt5T8rLOpxgyAiEdD3cthnPERsJufWiSJ0GYOzG4rcBOLNZGsQ5nI2gpQ1lKAsi4VZtN5zRUm/nuuzGO+/dVUctaTONdRJog9GpKJ7tSPu/6x/urCTj2PszT7LKcOK12y5nMDyeAUFScZbpD9ocsHLWgVXAKSI1S0Euwq2hvFi7Tjj8eKNpznbWisVDTYHMAI4/VoP+KlbhiqSL+PfWLhjD4YPcRjllfOGwmOon9Ct8418j8wxJYM/hxbbB0RMGj+e4jYeK+m1/v14+jAP9uBbPtZYU99t6o4aZh3N9gNh0dUbzMtX0MW2LpxGy6zwUJtsfVaTc7M7gHDmhv/VGPTWcNBBJCNSGrQUVl5P9zvJWZUTqIbeR6nXuVCV4WYMlJNDhqGRVFWdVONKceDwo7ORUcZajQBuFi3gpufCJybKjhRSDCvLATuyTLD76UELTqgJg5mIpUXNYNbRyR2TjUZKiX69rQFg5IAw9inMDIu6XxfL8HNf3oJuoAqGtD5zqndfGNqne/rqZ02WUgCMTAIhGaz+6MHaVilp2DWWXWcbGLeMpobRkb4lEeEiieEqiZSW6xBpoSLftVFprbYmlPvZr3mtDdcO6ZX1lowe6W8teMFkQ1lpKSSTGk5HpujfKaRJtOgtHYmKFm2Cz9gp6fbe0qmvlYwaZpSSstOz9hpJ8GbBoI3rRm1uoFpqLCeNomcfwOj8EupJkhTYSYWQdlsUF1vUB3v8dh2v8S5bhQYTIxLomZxYKR3a/hGCf0CgxuPpWMRvb+/n5ck0n9cc8ChL2BAZVil0Mv3NGI25QYNpexcHRlWR3ZoKM20QVjhjil7oCAOIYhkc7l8NRhYm7G+/H7xXJv19drgiHeJpIl1DF8xER1SGcfwOq7UsMBWRAT8LqS5rzlhEp5oknvKxThF2OrgI/ZWQczTTuGMZyHDUMHbrkYw69GW3r/cfTHIYRuyGDVmsdsbbwOlIw+0a407B1znAOIUvNYOs6+KGZfOeulmESxa1EAUFyzLKqfofMsselb0rdO0Sjocy0chF7m8T7ctyDXlR/KYlObP/VHLmF+Q8lvG/Ge+Vqxz0pMbV3yNBNGkNPyDt3NJVdfCDrpbazxtvwwm5+aIjn0qBpFLBbnjXaeFOk8s1EVqc87BQp31aPJpUFmmJukd37dt1vOuSsGN6Og47/dNn3i9TnB2P/8+d83t2loHZEtVt2ihIb/qEks3NoN3ZgUViXumvRG5rpBoiqm9gGmT1CtwUk2B1xttbcEW2scSMyBzqSqu4aY3LRKToNabh0mfbXMf+MC0T7pHge+Wcl0napNuggdhU5q7PIRPqZluz9ODzI7FdqvsakuDs/1cqmfF9Dwyzqk8wfyljLOukAqPxeC8MJBYrZCwqifTRHXOBFJEQVKRiOJfOYqfrgmrJdM2EW4CmyiMWC1hjMQbVYchXUDa+gu4PX7R9E1RnQ+mjJfkmW7kDXjqMvAwRd4239mcAh80HZITd4t+7P4+MYXvzX8fNZUSDTF5Z369dO//Mj9+Mf+9Nv/dM/89de/emB/PNR39n2GtJvtbI3z73KLl/b3hEIb+oyaf3EdftdkEv7lfn93fn6D0D/frV00Ph+SFpkfH5Hf4/5V786fp8mcvCSjpgxGpSjokwvynrAc/kWWSPIGXtRoUxD8H2QeNJ2aA+YORWZtywsqclTDmSHFbGsx1sdW3M7u6cMx5m1eIgW2jtte29oeHlEK+ucko33YVaFVmGapK+pcGG0L6k4ySVuBbSC5gqojSH5VP9eSpTvK85kNzC6hKZ964OzrYH422s3+JMo4fVmX0QeX8G0B7F+oxnD2w5sD0YHS4HWWwYTBewuibygnIPmicZYcHYEA92s5ZktknPZy2DgNtGe1ZInJ4EEqGrsSJzA/3/ZsD9yIoFbab5oTD9dpcM6syWhPI1ebDgewNH/2pHUFPECOQIrDFrM8BxGhpVa+pZ8SPVX3LovREZxl6rVe0IrvO02RhvnqiQ3JeSCc4AmWUgdeBhRdggkWumcGdHE1L66tqUOCDadbsDvKbRBjj3GHOB41Xq8MDe008PLQRsf2IX+nJq0hRzo5x/spqyRnGxDWPzY6MEpS6Od4digo4p0gHEoWj8nGE3Lkgwm00jnhmwCMCv8qSQDReEfV6U5MO+DteJjOJRCvWDKNWg5ctLUkwOIDLkrnQ66UGSaTPDE3ZYMHFmf/NKRuw6wW3tjYf+QXTRFOW7K7x8JFuJIfWPjk0WVJ+VIKx1gOz6stAFqaZwtZFaZpJjG+XtCKvKzT1djC/VGPzJR0NH9HFZHl/e2+Y79vHPbaTPxi5i9LyEa3AKg+GGRJaT/FYQz5qkGffM2hqMXTyBMhBRX+pALkUjteyR+lfMsueSSRApRmBK8hxXdk7xaXi1Q0d4maoK7vJOqrGRp9xV+vRHmwJJOgsOWuDc8FrOUGvJT0Sx+SepF8keiLJZ4lx/lpaQyKI2PKXxLmgo11o7KtEh4ek0R7Ov8oksF6LKPnLVh0r5fAwcFWe2UqvacEE+tDTJvvCBWF52GVEEKjX4cNEAOLbDq8dZaz7GG4Q1u7sHZgJrteGGVk2pt21cFVrhSOeZenPMHtWipLCcVkfg81E+NsPcW0/HzdrkP9xiUBzG5f3amywxNRu0hau+pNQtCpb3c0HPf6gV3S07+6BpyWyNocn2t7onmgrr7M09MwGl8TjMehOrkxtuPnUVjY3zsqGz9Gf5nh7poOlDTfMkPT067GeKDrM0UnMEyn6zp7V6C+dvdYYQ4/DWrA3tObIfI62qbVZ+2AdUVjE+bOY8/+kUMtABbgBJOjTylB0iFp06ag6JiPY2XaFKvpSEzcGsnDnChBHw7VgEjQLbDDngutzNvtNqi9mFe2k4yyuocpr5xWqGqKLJlLu7vk7ynb+tkw9pK3Vgh8S2t8+HO3u7Q8zgS2vPho+Qoq+0YYbfACDxd6ZELBk6HQoBkMQki1yjjOBHTkqDZcSk/ZVq3YW4p0NKmuob/Oi0b8VetugSv62vG5NaTeZkmeh7IwiaZQ5e9glE5U9UyR9MBoPH4mxFxjYc0TgMTfniIbcFEf6GP8gIficxkRk9F/c6oslMZASFI22hz8gAdzoA4Eno+1hvnsw/EFMdg+G+WgIj+ZPPjrchufD7WG+w3Z+EJMdtpPv7kCp+ZOPDveH//uLRuL/mCds2jN8wTchIzZCZi9Z/w00bPvQUDC30SMkbVAqQ98bJK5x+i+i07/K6L/uaWL+vAataLLuKyCEEWpk9F+QarV58o+Hj6qx1yPbBaowUWaBxJgdiWO4VGT0XypWo4e7wN2U0xHJwEea6umhnj3xMSEq+kQTYbd7ZbNYWVID11tbbHeI4Ved8XRSPrQ9gjDPGTa46/G/T4qqmhSFsTlSJNyURYsUVQkpEpH70z8lRRUB9EqaSzBi7jDCrp8/NWxaQNcrqursgObIQR+0zeJUc9/R0p67BguJPmryXmPyHpDpL/N/pBY2t8j3mn4Mpwjh5otY1xf47mTawivG43kOA0ue7EXLYjo+rrlPH4zIjwpiAoWDC1tt7WPdYNY9CVJUhMBhg9hnztazRhI3C8fYP6nTlWjvS5fQ+Q1ucSl9eMnT6Etbu/BdYnXmebDD3LqoJS+H+c+y0UQkljILESuUTzRl5LGGQIlhaQR4lj7R9L2mfxmsSoQa9zR9rekvmkbZ+m8iSjMO9OGxBszyLMRPwdWIPi7In7y+lij6gjdsZ91SqLG303ZJl0M0T3MGhEzrdsRBFv8npz0Imforp0PyitPfOX1hU9CRnyFhyludGA57FltEFk0WQvj2naYjM/nKi338EZl7bytS1Dp4q48CJTqQKO1N8beHuwcNF/du7/YepWWWtbwOyk77oxIEbt5BqBwHgYt20hbnLhM5y4+XE5R6ii8bnuKpLcmy5WVunYOXLg99jjp95dsGKdaMY0FbMSnIjBbeFgkMw+cUAv/Oaiu+c9oIRx4JQM/x3Mt9ziOxn72RmY8voo+tXmVeJ/6+iMJzoJ4tuSuiRm+B1wa15nZgZ3TWJZellLqR33gBxPgGRA9TTJIv6I09nM7c23oJZ34J+RzNYl/tECZmf+cg/Mzog+3DgxGcNRoAVw8lDpUA7+joYQ2eU+dYMcLjU3i5TTRHmpzitfaCjaCpXpdeFaadZOSScuAcnhTT83j+lxOUvAI4SE1KDxByOdCsQlNSYpyHrA6opJeDM1MOx2hnbdIDHx8IEFUC3LS9d13Tv2KOiJMp0Xg8tVLpa3KN1wGQu8PDfTLzSRzD9GbUa1W9wZrFrBkel9SyK+gPZKMp4NWq/3gLZMVbwZqsj+/3twJ3tQWNbAUvdLJ1uqy2hNzySLf16eXWVaG39IJN+Zyz2eC/xH+Jx7PZVrH16AM0o1moTQeDwQ91X1vn/OycqS0utqpztlUpxrYqubVQ8pLP2FaxVcrC0MctLmZ8WlRSbUm1tSiLKTuX5YwpU9tZiw76eL3Xq2PDbGOzUhqVRIcN6g7D2EZ6J+e0JClUQYrqYWu4gZKjGeEaDQkHr5TE6mFkWoDVuzI7/mbByBc6S212zYbY381cNwYvOmjh1UYfoKBI6Hbt/NLtmuO9bVar3meIG4m+YHP9+p7JFtrMOJ7s+g7UWj8rkYhMDyt7KAMjI2rRlDl/6oOp1vTb8ygybClDlub62u7Zyugi/7jw5x6bPC7ySAh62ckn7juJQ7d0oVqtHA/nxArX3yFWMMxlLFtQEXfWCA2wP6qVjYmw4Z2OFGZm6sHUAdoZ4y8lehyzmlftSlnWe2sYtlbdL2WtgftRx9k4CTP87rhpj5laXXoAV5NnINR+DEy63uC19CzqjPkTUcSxocfcmsQ6bgMOiuHuQZ2I5zaxhGAaXBHe61pmD9pWg0lw0oAtN4SbdlegnW/bdsP5XWfLfa+xjRG1mwl/YtWM3ZDIYOHtWbcxVisq3Y6RkbQ7thYZx2JwqnxoGGY1BTDpKGGxx+OYv4JLQJqJI/qFa41sEvDI95OWxj/jICyNJtmmSCSYjB5ViTNOo4/Jxh7yxiQaneA64E297hUY1wZhoecQtoe7D0mEADVMG5DqMjuO+NiGV1QIU95CsgqPzf+UpRTPXNijMGR70X57G20BUBS5Fj+BJPtDUwvdvOB+cIRrJm8fm6tO0u0f2t/4vyW/FTS9hsY2sc2wYN91YSXgkhA43obS/6Hpt0PV4CW8bquIdKsoUM3EapjsX3KcllDZkvXQYSrqgd+JkAU+urCp+9+zIi5loirEWRnVlLQuvWCi0uPI5jCW75Wd0iQ+9pcXK03imCzp6NGj6VgeTY/pkGjz58GIlO4vz+i/lhH+vdKOIuxmCmfZK3tSM/s4YyWrGGKRbvKxpvHpYTam2x8Tf9TG2xKJDftSEJWmgoK82nmj0BMZK+uW9IMm5ijd2W7dQO8p+kdFZgppulBezOuMkLgUEL6oz8WWxiW91eZXrgfpa8LELC58JmZrK3Fn4GNheGvdiKSYZWUwGuLsarW64mImrwha0hLcVX1jpmL8GzmPRbocqEKcsSfginFb0uWgENNzqazJa/j5dj7XrCJTurS+a/B66X/ZtyAuKIPtJpmGx5o3KqM7+BbzV0oyM7gxN/+d0yG5oENyRjW5sZWrYLfrcfN0fGbTJg+tw7Y59s5Cb6sVmtHFfY6JqTW1tZYdteZ0cX+Jibms1uVZhhb33W8wgHLWcHVkvlN6FgeOHuMbekbO6Ok4Mi8+M/c2ZxoL4oQbCoKB+/fPqQ08PqMLTG5sEPD79y+oDdMwN6VxRwZnP3j6bKVCNxSd0RscWcauz+jpuqSgoJ2tVvB37qK/WWSbAXbNncrVrUJpQOgqDKHCMK3wVNFbWGA2e1ayi1yTgJ3vDdbk5Zr8UdHeKLU/IZ80VYYBMghxUsZuOTUl/tRkEXd2hhiPX5bokyYMmzY+xVEG1+lp8Enjse807s6sgaZB0PTJK7YvTWs2KBafo9F+dgkxfj9FIQDBKWS0fZBd2k+uzScJ7+Yavbbvr+g1+MK70qsN95rJFXyH86uEZOC1t3QcDXegT6djutDokzbzD5KBnVgcuN9VgVyasoi7NeBJ5Irbu3n0wWi4vdd4f9B8/602d/NvVDjITzUyJ8cnd7//QsvYCkOjOknGlyybmxvaur3s/zO4w+foij5V5BroNbmkV4MI04mmV4MU18l1j9LLzODNZUqFs2ypUKNsMHMPLnI7ucT41nWvs2ym0KVhfK8p4J+qSC1BuaJ6wMTMvL6i1yGWfHyKXE7QZeP0oNfkMjk7rMHcBRfoilxao1VPyXCOrii6po0xr1az+ly57jpXcONMQVf0qnGskJJexskSXJ/kSz0eP+USE03DvGHSky95VI2JmanUuxqw64qJWZZ9+QECZ1NNNP1CvtDS9DdV6JJ8wYTbJ41JmWWGxI7MrozOt9XqKjrdzAkCVL4utucYvJDwaF6F867n8xeE0lCfu/pm0dA1vXYhCgBxEAavZFglZHskvn1MrpzLwuOyhNoaYfLlBz1BV4NiNrMNXJtqFgTIjoCEDnGOrk3zzzrekaQN849c0yMbhOqKXo7N6tWHyBibY+MqOgivrWFKCBJzRUo2r/KrgY2485rNK1LJRSj4KBdrK1rooIOXFmRm9zjvd3JJh+PLR9fe3Pzy/n1sUP7o8hj7aAZRV/RqYLo3oEjefZQLejWo5GJtjqLePUWeKnpPBWsfT3Nbx8RlxzHxLDkmdvazZ1m21OiSNAkdHBTP8O21w2AgcG/N12l4lLe23Q80Pmm8XuqTTnyKrumHhm75mn5Yd8Dy7eQtusb52zC56/X/NcLpjVl/cQIgaTmGCNBm9j9pHOxaGflV08qysgbusA4R4Ku0T/KpHVz4IAuHU4aQWSScRgB9FltEgzrpk7Z6nKEND51erMw+dfa3ztRkYq4YP+vJn/r+/Rx5k0qG8z/t/S92Wf1Ob/L3Una7kpsX6FIS4VPG7e9aCakIWmInD4r8zPkcRYrhr34hrU0xo7/pYFgcIhoF+8zV6jcfQ7u+bJ805WhhE7CU8ZFlkCapcrVCtlm/IHjyp2GjiCohq2BJe0OcgwLIYneWgfH4JwPzdk1vcBV2HURP39vPDCmdug9BULY32s4qvFr9pFcr9BMEnvoq0eFDEseidBN/7MN0rg3NayN1gIGpaLbHobki/Kr99A8fPvpVTw4f5r+GEKrWLvuTRIx8LL2LUG9UN/XEyS5euLBuldlP/3iwdXvvXXu//4fa++im6lbyD439HFyYqT+A5Hk79M1ilp1RWDUnWt7ZdmKX3/UYbNajbHXDsXokPIVXwaFIUnGkjgk3f+6PjommMg5gIJueW10pimBv6e7bRdOvM9A5DmENrOnAC+0M7TuH2Rji2MdyLan0EYjqYW645HzHMMrINiQSPfhNWY4xM3xKTR7LDupYBuKYZu8jZYsuljTQhw+aVmATQnqRNcC70tuZa8hXT0H1U1EB0mhMRhibwihmsrctH4HODyzKR8EupoqR0EX/urWhnVyiV+gQNA/hiPBSvLZlh/vSRQ14BwGWiA/qYIjk6BsBZDowSdwdg2616gwo+p1aJ4WxR/nCQJAZQMJmHsEtRHMkiMREpiAVBqTCgBT/WJkHU2cK6ZprO8z/7rjAcqgrpByJ4/56DVVkeFKv6F8BWy6dh3mtTXZzUVmmvCyvCrjzLVtGQbx+Cj3RwaASWbcEG8gCJNDB5vKJNnWe6CzbGw5/AAvCN3ribLXye3pFRUDJevy/JLqypseVVd2JaPTWt2RoEN35xlTBN2ZS0VFudSmV+ZG4w+RtZxgKbT2v6jn8qyqxdVPZHR3u7gx3MYQG7dpsVb3ZqmAPm+Qaf+2Whih8C7EDq+KMMgKPX9gNFfYxxIKH8IIQ4wQe7VLb55qI2IZuFu4pDjoGBAdKuZixazokrp159CpNSm7LklgqUJKan0BRbHSR1Inio9hySB5jn4Eq+oHEehd4GetlTEGTrtYQcQZ6thUrdYcfaYyYGvT3ItB7hQO7ilekrvu0rEO19FAPfK0WSlbSGSn02IBr69LmN2r09ZsG/tZsW6TooDZxnqBmXBACoiLM4ADxqJssJIt/EUsdXaBOElHTeLeQKPgYZSSJnoNzJJrr3mzUL5RoLYJoh9URTf0WJom6MfbVIcLnEnH5L1xNX6kZnq0VGLKhQG1l/UkC1aVunqRqJGcmojNRR5Uk6qi6EnVUaaKOKAFCnTtZuH3H7F9Iujy38TrjoKzPAxLWmfU1BXc9RVkXp8Uw4CiEvh1Fp08z1xrDmu55lUXDKeWt9/74u/QuUooJMwLi3XHv5ZoeEAmmCpEY8UMojktPXHuIGaQebRNBKnKwkg1UPiEWxeDBIgL3eQg+pk3sQBOmAfjgI0m2AfxuNPAubeAwNBB/96793VMPix/hPI9A8CZpcXu3s8U3SYshQ98ctawOo2QWda5rH/HYLczjXNPRMDXqeZJrepgWvTfVGhFPXpqy3bTsL1O2T1Si57Gvfsk13d4Oup+GFnVn6Kwt2ITlfvyk38f+soUqAxPdCRJGbCAFQ/cDbCIL5r9b9NhC+CFhRJmjNOQIi8xoftzw0fZO+Coew9OwLEkrnwKDFLexT2xMgU19f21+BZPf9UwACztoUj/mR8eOqseNxinVbhOz97wZ4cRnsfbtwQD5xcJOEhS/ORukBesYzL+FUQd+wx3xSUeeCUk075Y7COaG9isnUoo5Bz+66IhumYon9V1O7jAMn6Db1vKOAY4ZavsLJsW1y6AtrxXk9O8KDbErTfXk5tWDkX+XqOBpAoeoqKm/p3XDSb3YEgAKGtYCMSRex5xLovSPB+96/gA5Q54VZ0yFSO1Pi6poMDqfoz1y6SJyBx8By7dqWpTIXFogKgW+rXJziXvBouhZPpSsxjZD58ibMbVMLbzEqKQiMmksE5PGkpaNID7s2puIVsFqcY7m0nxomCx8m37TiHD7xh34b5g6YzbM1ZO01fXaNOAuR4nItMTj5hxGGHdcVKcuZO/YjmwKYdfOJBJkSsrIDlHQ0vvDaNlg8io/20lVo3petdLTE1TRgiNONMbtWPBsHe4aqtbPKMukuCyYIe65wkRzJM11X5dIEk04JpFJ30/ee8gytt6ExoVCio1xwgFlgyPFgvGGd7yvEhYsuo/+UUsY6gtTMzRFlOMpCk1xG0kd1I3ZLePomQ7dZfBRNRF5LET81XXpuibQYewT/kfz0vmicWm2ownmoj5mCpfiLeRj0eYO2ixLd6pLTQiaBzC69rTYN90DD1RP78w1/F6JduwhBP9tAyf6MLe+/Tv5ELhqT4GTc0QQyc1lmB29UMc01CKPFQTYY3X8LhYpmHJwO5yHhPlJvnxHPVBF1RE7xoOTM1Z9ZkpzKcaSSlQNTmwaI+9QLb5FqSbfrEGPKiKP82/W8wJYiddAIk+4IwzvpaxoxFr/nl7lmKVkLFKpHTZ+j5oV0EFSsFr1t4AWPYAIpw8Wkovqgfdw2OqHyp9t1t16LK8iNt9Cl3dHKzQo464BBeXp5DYIzKS/NcixjDMfWEHyTyUq8Ngemojh9fpziSpSEGYA6K0dNwymkT6Kz1G1WqGKmotxRdnksIleDT17Hud0t0HD7CJUEUh71eC80FEC41lRFQ9gMErKqo8xJr0KB0HkWDiTSmh1jNNIdCJYOZptB1t7SKrJrdtpeW+49mmr1zbwVgvMXZcuB+PyLhiXNYx7KeAua9PvjD7YBrO1AxBhf5+LYJLhK16/wI5vwRDWP+pGJhNP0xwfHqlCGQZ7y+R6DSsTywZWq6kMp8TLgvaGdQpWSpHIFA4BD8zrEamSw/9TYQjT15Zn3jveCP0LufNCjtkb2YoM/J6jhOo1fEYbbnut6G8uMYlnikDCfOKZkUKiXyWRgxM3U7t7mwVJzvmtURwhvxk6KdL4icyFw4qkIHjyR+GWJ0fthJ61cLGif/qKeBIsg+1GGnd8mAwQEvMqmgzCdk+ayXLNeio/6le+y3GU1DI2UpYdoaKQjNNKgu2Zyyxpn1siIjv6eNLKGdTFXIg1wmpFAquC3O+pH6zfBwFg65eF9Y7b3zmop2qZNUDVEAC5FiJGuLttoecThrg9A8bdjVDUVbvAm3dDmKTUh0HShUQVKettRSoOAcCJpKKw1tgVUWZ/m8I6jzlpCRRk4Jy6VeB+TbIs8I0yEjhASENwYGumlfDzaLkiziVS2J9fveEYNqqLsGlA2tUOxNqEfevHUZdM3F97uQU2ZmzPMtWlALIOh13axyybGSgqAoYT0o1c0TlPWCXY5eklh1bkxn4KIRYq+mO0CL0h4QaXXH4cA6wh+StUsCsUkil67HQbcD83OyUSSoxZHnK3/AcRCnEqzQnGK4zk4MTdILAXwkjCqR16fTRYg+gu2aKbA4gYJ6N8WJ8Y9iNgpwMOUUrfhxhkI+tQQ+nLULTrt+X2Gkkz+D8kkmaFeAjzUdHnETxZCPhQu7RV9O+7a5gqv9xdZTev6OuoihmHS9+MiYrqNwRhO8N9ImO5l1/dED8n0AjZXJnnlhRBIORGPhg1kfkfEimIR+vjH367xb//WYtwRNkjWKXhTIOvWm1L0soeu21jOqg2wm0+CCZyEOcwI5zbS9jU7jAoE5i0E8T7zwxGSWwYBhIdfoHpQNz22g5uac6ge5x+vSMJU2wmTl5ziE791JAxQMc6lCyj8lt3EBsz2wZoZUmAVsQpO5LmynQl1ZeX4p2SZ4pp7W5P7xS/KNSNqXN/dEx+4/Y2w62hnqDPuAtvCUgZMkGLsRhjr5d5sOODwa9Gw+3dJN8GEKq/PJoIx3sFEtVA4hA0CvixgBRZ9jf3SNONiNzjQDuOLgxe+xDKignyXAFaTqyGxWdC41kGL3iSj2+0j8mbwiKNm4aOAGGHvZ+ngpYwYNGRvDiwWp6TdOXfYChJC+99ZxO/KF+StcpjqCfDHX3Hzv7ln+1sHyrVL3VzqI0RHIRAY3d9Vq9YawbDnOW3qsk4t6fRzhlizqaa9y5bvDefI8t+l032u1FAuefCIBV9SR1PDzYAnHKFSsLxZJgPV92WGCfTopwuy6JiT84LccZmP/JKTzaUQ2N58MzccT5ENYwojVA8y3rRPek2plxBUhisaTz1LP2mBNf8oODHka2RE0WWiZ4yusNN8a2mpVspf0Fe0mminvTtLa29zjLIIsEWxLDIy4E81Uxd2qlnHOPbEaW0dGHJ0dJni8we+ISRENagJEts1sm5a4twb1nGrgVmestQBxPGw2zBUiK8clZDS7q0kUcsyDQdDevBWBFxlNXPUBQPgRowGgeLibK2Y9K09MDQFhjga22AKOpYJNFNxyBZcMe8DWuk6wAl/iMdCtcl1Wu3v2S6pTZQ4RC11N9MiTIYnW4tXDfl7wuKmiNIcCQJr8NsxEuJk/vDZgIViCIHBs0PozEC8trNithqthJ3/JNtKZwo9zyF6Wgp/uDht2njN0jiv8tJ+7sP3GkmiNHekMB9BucQmcqD+cLyLhL7ewJw/Y1bAqtnFJbzVXrytK+x9eW1oZTY23d3UbwmL8ra/sTd5xJG3up8WoLQWpTcbGNp0zO1pVgdjUDsxfhcHH8u7bydwjRJPW/lz9bWdU1+TmP1joKJYZYhiJ67S3iJMCYgsd81n7DqG5/sPxwNDw72ky99mWmgqpqXnLoN7wltzbcoBFUeQ6tgSPmrtdhar0kMGxbF2a4QXpMT1pKweTlCI7v7HAmbtIZUVECwf1LnArDaJX9/d9GeBLWpc2sfEJEkxHE8ohh8XTJ1Y918pHpclsh2emQ6of37P394+8vAmoPw+Q3q9+9X+P7/Oj4C0unGcPy/zLiG46o2tK284F9RcVRBkFlld5YazKW6sDEBpLrw6gEGwbH4HPVk4/ZwOMR4/AopTASDbbpeR7m/0lwB9W3NvvS5Ahw3boBng/xnWWFq93qiDsBfkd7IrNlLRucl+au5OLG43ZlH78YR2j5JdHhAWOQI7z9qS2V5UypLfmHxJgJTw0MbgDneFrF7td9qr/T4VZ2orBUpHjKepQF4t3ez1GkiCkxntpsZ0xph8thsjDV5zehGEfSKbv/zKHXAvv1Z0ts5FzPwm/jx5iepq5cuG1H+SpHTpZiVINXPh+TSXnjy/ujhYDjY7hNLu5h6V0y/FGfsl+KC5X2rTZnJi/6a/FzS26iJP8tB/Ss092c5cI+dDf5ZDjqKQ9UnUsz5WVzLlhB5yZTiM/aTlF8+RBKpZvFTMD19V1TnGyq8Z2YTtitEl6OkaFOD8LLZmGaVD2NkzSuUK5+es9mydOlebZnjRuto/O/ZPN8Yqd+sarycP97AGucxSqaXLsSapLbXKLp0wXsTp91eFVvko4q+YIjhplvD6OCgDlBTwT0TOD22juzRzRVtHGLaeWvoKLyEdBJlu/9l23sYfAJi5bSqc/LgW0FVMy4QOEPY2x+l3LHvQLt5SBrELWvJ4/gWrxiIv8auXKXl1ZhTHq7wHZAAntQNrEep8mMUVBJFuRWP1KEieiNI42SHU9rh2HAbt+Cs4j8Lc7ICIPtSUUlEeAmWGG5gZvW0nW3pJ9/dPDetbGqem/43Nt+cPcRvhemH1eu1pVUjc+CYajubbFVihIqTtnqVOqViwvJqjVgjJP+8Tr4YJcWtBiE/mOXUAksPUnWLGF7z4692kajYC7SqZnLWXpXmk+pVIZNUVWeSYskQ44SPzeRRIbxRFFomBMQFXs3M2O2uyIaDbKLzf5aDDa9Wq+jUi3toURf9XBpypJg+TwlYd6GUVaB/rkZC/s6Yp2iWaEGnoCxfihmbc8FmdfL/k5P3zx4/+Xjy9Nnnj2/fvv5w8uL12x8fvz756e3bVycn7oCe0rurASVj0wHXT7k2165ZlrHpQC8XC6kqDcMAf45LSU018RebVujnEpNrU+C8OS4Yvl2vq2D11mQsTSe/l+ZG0pDNDoc1Mr8KDHllLiLCcMHte8K/2+DINRiul6dwYLiE5JrOyzXZOdzZy5td9Zfm7l4pPq3646AO32KWIfrnC9Op4Lr7k8H0nE2/PH3yDFbiO+ui2NdmKoWWJRswgBPD6zW4yrBrWGUq0O7u7gFek8PD7VGe8lvJ/O2BtT8cDXeIgr/7RMLfh4TD3wNSmL+jXaLh9yEp4feQTOHvNlnC3x2yMH+3h2QGv/fIHP7uk3MoH5EL+LtNzqD8IbmB34fk1PzdGW2wIflwc3Eqyyyzfw1LanfCJa1LxoJeIsux+ft4HxNVF0L+7rKPiazL5qo4czV5XWoBc3IhZ6yPSRE1oeScl0z1IRpBVHrJZ1Ba1qVOjtXHZBr1J9VVoWYnis37mCyjLh3j1Mdk0S49Kbk2Lc3qVxfsQvYxmdclZfH3TR+T87rktJTTL31MLqIWmbpkKrw5i4a2FLMCTHUNjG7qFzN2ujw7qVQxZR4kp1Gv7KyY3pyc89mMiT5eVwOuPxclnz2LZCJtPq3tD9DpOcdWK2ZYJfunsH9u7B9u/yztn4X9c7pa3WXZDmIYrx+klM5Xq+T3rPFbN36Xjd/Txu+zxu/z1YodDY8ppRdAqMyLt/OWqvMuW/zAqPpmx+mNfksE9wnnIuPKpRXoFPYPt3+W9s8imEcGn4C6kSxrGf6X9rOp/TO3f2b2j2635dmN9RpqqKhgvSaHB/u7d1PkmIgZ6oXXZPv/R9ubN7mRHIejXwVTu8J2LQoYYHhugzUQRXItvh93ySC5P1kCsXQPUJjpnZ5uuLswxwLtsERJluVL8iFrJVu3bB3W5UvyriVH2Lu2X7wIiit/gUdH/P5+X+FFZh1d3egZDlcygzGozrqzsrKysrKyznYvnpxJ6wa8C2d7F6lmYGc0Azvfl50X9VzXnE127mDGl5KJ0ExOdm7pCa64HRYZaI6XaY6nON9GX3bMZkexvr7Shiu2p9jh+adkZzOXnSV8tsrOwgJo2ZnTs1kNXyv1c1bP4pyOz2p4XVCCGl6XFdCC10VOG0q8zkHXrIbpjQuo5mzzAqI4GzoAm/An4zOUIg1kkhZPm01hohWiMtmRcpb56+tY/GtZJ0m31yfJOFvHpbQ9EeNkItLOjtyLBmG8H6RhEEtOWoLFvNePLwXpNhoSZkY5FbdaVLY4aQbpdjYcQdIYynjl9nV7Ec+zuYbxyMgz5KUwRmfA2rkwNqDxDGmJFuk39sMslA3Ski3SmCYpuv6dzqOosSeyLNgWjSRtwBQAeJzE7T1T2ETsN0S8H6ZJDDViZsyI5WeNIJ40gskEn1ULosaOiGbTedQ4CNI4jLezDkFk7/BFmL2UzGMpJv6K9LzWy5mI0VX7i0k6Ntt7J52Nvy3QE7FSXdQluIM+byqROdvji7wYxW0z7dVFBXUDj5Xuakh7jTTjeypsbG3i5XKnsHg9ggrs19YvX/K2o8OuXsHki5y58Znu7aoBq1kJ1pyVoCD4tZX1ofxO59TDh9zcxnUqCPYgEoVnYlpBaLl102IwSwtVXbHOwJuSiZMfij4qiuZONdqh+JYTG4uDxlF/H1CeyXQ+lknKt1jq7bvNo2y/E2a35qmo4Hitq/2CL/SmWW202AG/iTh1ergTZDcP4ltpMhOpPGK7fLErjnzY/osp/Ny/n4nIhNDGwl/rOoR4zZALLjkshPFVl12YPquzShtlGYx+u611GWyApnhBEkOUOTG74qjZ9AJOSAs/KJP0QFnuSpbSZnNtt9J8D29ZhMN0xOUwHZkrL1UW1cZLm3hwSsPinDi2NzR7l6KCR4755TQNjrwI+HC3P78U9eetFh0P56Oi5OG8tTHqO4Xh+2soPmhBQJ3MWQxEvBJjDf+g+aYXEfZC8ZiFkUP8hEHAFwyGKsCRyhjOVD9k99E3mX9o9CXOhYubjsx5omBYktsS5H93+Pq99db6djHy990jl5PL0xMUBnGwqndcEE58wruEER8CGyQ3K8KzpCU6qeKY3vqQ+6P1beatitANORSjnNLcI5ADiMWXHZncQcnaO3PeMfC/bA8cAmOOb9rcL+12edZskq0kiUQQ4+dy6WlvIJqw1nqOflLQyFhdN7QAmemDJi3go4xI4vnelkiJH9nH7dVpisagf9yF08QIr5ARNW2R0S0FPPAijv5eCb5fPSAd0rrvRaxL/ZQh/XbCTNFxQAdezAnR57FCv4xrsHyHkWeb64S2yDqh7LIXILIIqUW7yCml+vwnaDa9m15Acc6WuflxBKyOkYGKJVKxunOtKFmotcfQs+ioQJ57AYtb3loAo7xcRs1mhF4ZOEfIgBAfiAA/aH2vWgKPAAlA9r/b0Z4roJThKOJrsA76/LRFfFLBnaC0YAvd/rgwKRubI7k5T1v3vYyL4XjExrQftfhlL0MkzllQPKi/Krt585rNobWcKjZzxdKnlIE1JQk+aTbFcDKCPRd5//uNGEhGdKBfy0T1qbpUNDfXIRh0ag0aj3YdHqWdSRKLPlWdsIY82BnVTwYdZ4Fzu91yAp7Zd+hgVjKzMJ/pMTJUqRpqPRoRvDulszYOQrnT2BVHWWNBWnrFgk9P0M5rSRh7hDVgKHPiy0Ib5tyuvOKo0RT+rBpW6L3RcISvtmso8IQUiPwYOlcX99BnTtJq0ZxSljoup/TeFf3His79TAZynhW71fupyOaR7EsuUSulE6ALah2HF8XwvY7SK9Rdt0D0byLNquGU03PLoTllJ5ZR5Nuo5LPXK4s+GKwVfcARtd+4NtytyBnFGnHLmizctS8yuByzLLGd2XAeO1BOjq/zRf05mH+XuREfAKg+M1wUzyT73ZytvGrtH7Lr2Z1kT9zWJ4uXxzKMt33bCZDmgywLt2M/zfuyY69OL/aCmX+F6WPglS04kF3JzKITzGbRkZIGragAAxTTnI1hM+GvLoeWKFeKa7WA8GTOZILsqO7Mr5ypzKmXy+EoZ0kclXOGU28NRIPKaPTOnnFHI2eyU0iY27BPnqeigGwx2bl//861K7ev3b1//eW7126/fPnGnftXb95/+ebd+6/cuXb/5u37H775yv0PXb9x4/4Hrt1/8frta1f5dSY74yiJhdaR1WnCzRQut2/j/AUm9LXmkKce7KDUmgG7dHWhP9NuPEDaUuuHK45C2cdJoizih8XFjxOlUqEtRNRvRarDlaImBs+Q5viGTSHUzmuF2rkSauej4lKxHM5Hzh2N8QCkUR+gSjUwP0HmnR8n887pwsi6c2pP02a8259dmvdnKPPOXJl3tiLzPnmhP0ZcjZC+lHs4c926ToZoFChAdojSGPMEL+rMWK2dqC9ZyUrVF+XvDQDInVQEE3R663fZLa3gUWdXV5I4m++ZQyvaMbFO1QEz1rK+AGo0Wbgoemfo/JqFvBjA9u6o5kT+WumdS3vKriwrBXIC4zFXTF0LFz0OJa4MibUeqpRarMpnkTbD8NW0L2ux+U2m1FAnFjFn5nqLv9CLid/uMb1sAHrwHox/G2vYE3vJE2TGsdn0jJO9WZCK4u0s7QZIYknzTFwxd+xrCeiWR91EGGcynkR4Jp9K42a7Krbm28ry2RkCHamv0p1UpErilnh9bwbyWrivjUdWmGK5gGpyY6uoCrsRHCVzeYp2uAnd1rx03OCYjJDAzXBbTObjmkPNci6dqtzYesosskw9YZJW1UbVxErHo5JrQyRuTJxydmHjhadQvG+c7V6kOTt7/uKZ0tJ5TIZFnMzqFmeRM1zr6uLQFHAWpJnwKlaBgtKcZTtBFCUHV1ayR0LCHjpHhg0fMSwqglZVOx4aislhPOLCUbo2ZM4mQszKBaOpGRYd8/IOSNLBcOQ71al32KgnV3Uxy2U1Lz5aNExHfEVfIIfpaCA8VNv40lF7NOKcTYNMrvZcx+sNghLYUAoA4SpMYQVIV7tlZIrl0jh8EMHuS8GMMlWQJ+kaPuslG6E2gkimjRd1CSXrkRgdQkrnxaFtAfmty9MUK5CuFq84sk6NMk5xcE9/bQsQEJR27uYUSrc2IPgUoGSpaarpc8o6nY67T5K0sxfMPC/lm95imI58hViYZpRSmuc5O3vuhTMn0z82Gk+RLp7t9mArPZ6nmWAJjz2YCLTj0iQLeexd6J47QzuvzWTKApg1517YoKgBnrqTA2TuqUhFPK6ODMvoIlsuvYwvcsqyzjgY7wj4ViENRdMXhGLIhXbCiYhlKI+uCqk86/O1LkNPiXKH69+B/m31/F4fSDgyMZu9gfQTT8JGeDEJZOBHOZs7sbGfeDHtZ529IJMixUaoII8oljWr40goHO6LdCvJxGBxEKSxq9xXGyQ1VRzFeBSO1eNIxWEJvn6Hdg5Qht5daBA6xvVXCs/z3MOnDHvKammy2e3TCe+y1BsbrLn7ReWSKJx6AU4VxQQSDnwDSH7SaplxGSYjFSt4AcGLpZ1UZEm0LyZ0hg31yC0g+jDebrwvw/OX92WEJSCuB3KHslRbTg/TzmxXHI246ADyWdZ5FmXyFWZRzdBselXQUGUe8aS4k5jg1hbr1K9SC7Od+I274faObADbiEQjkI1nFypl/hu0b3rxSmw61lAHeSsNDz3RUVpy27k1dJP+5AaX88LGgr43BBQdV/dyihVCYpOwMXKnk82iUHpk/Vnsy7A7Ysg9eMJMf6/CRJ3qYQukHjWpOyZ1a/mcSRwvHnoGxvTWCDuvYvHuoE5mJo1JZosyEZWcpkEvhVkGzYEmN2SQbgtJTBkFDaIuBWtaJSxvtY32O3uPCF+lOLTrUpSCutq82EiPsWXAgYE7nkqYQAbq1wlgBMdObYbW1kSzuWpKMpQjqAw48/GVWS4sXaZVKN7v/VZvfZuRdVIoVNd/qwug3yI0d5oKrN9tqWEmVlYXhff0cOqtxculabLVagLsGeLa5Np9bjpIfWUSrFx13px65BlCN3nXcKLYkPUzBO87iGF3VFQZczHsjVjM1al26UQ6VhzX61FTRIsYdWODUJrH6vmV7EOh3PEAF6g4L7Ip/p8UTVgntBDKeLcfX0rcM/JFArKY9BKUxiBRWLzPnDabMecmfbvHAo6y4fVYZWC9rrrPUdVPL5dh9nLwshfQ5TIoTkBApoF8g4BXczSbpA3oxuj2ht/u+diyeLM7SIZxuzfyCWHt3hraHMFKVhH0sAMUlgwYiLDZ9MQwGPGUMsEhZPlve4NzHphRDQfealOE0sqnlKXmdeS+KhFqsYXih/WJVPhaq1OSV6VQQQuCMMWGg9QnXY2FVm+0XFqctHojJfE6FeeFPP/aTGTjYFYrmZZmEM6WrjuD7q0jrEcoFDOPdUGwjwWJ67TSmRG6VHaXcWiJrSpkJY4AvEDJxu/mVPnYlTsIXpGpF8DzffIMYToDA54HhKGYIODH7vdzlgkR+45wzYxc5q/12IqMhgrXmFK2MnhSD5WeHjEuPXZSBWrrgb3BpStgKoVO2CLrtcYnKZ76xFZYvKWyQKOVBD8MRm58MS3LedjKniegzWaCTp9iuuoFBsptNteKQugiXpVYm83KpMbm2ONUVYhubaZbq/ut2EgKa71ZnbhkqYsTlmphWA/3IC6EYaZWMh5gFuXdMDYhlmKVGk8sLbCz1nO+CsG7pmtMqNbiPTM9VCHawZ0780SrXOV3uV9nIzgT6TRJ92CvVmt97MR34uTAOG1zwH3HcDpODlZ1aY0AcnpGplLnxldBeIbdA0Y9uQydsB3h8a1z2Gxbqt4Lc+0/7Vx4Sdk5XdkJ4lhE5sY56gbn6mfmVunePTf7UcHLTfRof+ytdRme/KGSsHiMGwXkTKCX1mQuvRnrUibyvB+XdjimjoGTNGZQpO+NuWCVEmjOqr7q5txJo7RIJcdt40gEqYmfl23cs51kHk0+HIposopu4Cqh22O0xnkxDfbE7ZLqCHZJdlQnXI1Bp2gVmxqY25bjri3o/ZgaoB2bE6gsuhyHe+iaBFvRrxllnTwVvzkXmSynbzbLZu7k7k6YNbbS5CATaWOSiCx+Tjb01YZGbRGdxkvBrmhk81Q05E4gG0fJHN/LbwSNWRIdTcMoAq6q3snXRWedRp2VYBTGuwrQNlkzQllNp3aeruV1uPqfbzgenOwBN9N+0Y54u8e2+Dl8b+20RNeozrBNvg9k6BIbOwVNCrroborlsrdx7pIYVLBXztSQwa7IEA9ZKMN90Qhj2dgS8kCIuNFFA8fexjkGO+8xbJ+mkLORBlJkjZ1we0ekgNIYEjWms6wRZo04scMhJoT6W7x7SQzwjcFplCSp1xNn1gX1z+Xa0gwW+zKHYgf8EC1zN/rqt9dJYm2sWc+otulxXGqfi9YWqtW2Fb8aHHRmSSZ1jVgA9T1n9GiVldVkYMbZB+TLWZmxbXPB9pZLKLPLajJXOVlMF0d8UvL/KLxqR8zZb4nBTb0jisTmmGqpcwl9F9gamWjpWNK+sG/7aj1ju7e5udljCRfDFLUwa8XRZtJsdi/dQWfD+i3chugLtJJjAkT9hMU8dWq/5gixxQObIP92R9Te7zSpbxYHVpCgXzpVLfowS2Ye7lliBcfLALHuyb59Nt92Nr2U9M2N8I3nvbTVo7gPEsNwxDIetnos4mKYlSsMms3u5h0PBDBqgZECRiygAw87HjHIic9ZZ9RXsIBB0QgLC6WRg0dbTFzFo1tcbrcHsnR7z+LrTnlssySV12E325ZF2HmKjscDdB8/actOOEEudZ8PR+wy/LnCe+y2Yld3+Rl2CybAdfjzGl/rFfv6l72S0fc177J1XiP77jXfwkM1vQmJCixItf2Fxe8SF+ZNZUjEnHZzWfHizna9+7Cmq0odGruhTQ+goQzax9au04IXXPPuU3odL6l6z+p21DS+2Uy9G8xpW1u4lTyrJqbCSLOpKsOHAG8ZI9mQ3+2bly1f9mLKbmPdpobbzaa35t2u9GozprgXXqtfFjxK+0bIvG0xeswNiIAuijRmKG93Ztpl/g2xLyLtajFYacglHtN+vMIwa999GzjVZP5trpDcbN707lMGXVfMED77CgmOh53baMpgLRy19OmOxViNxdgZi5iyCFirJubIOi+wJBsiyeZI1Vd56C6z1yeRsO8GnHPXzOt7e2ISBrKI7rnRN5IDG3HWjXgZhP3Ixp1x49SlD+sT1Yl5JRPpB6JkvItubnTeDTeFkldqjp3pQpRHtrT0mxvr1w7FeA4Z3EXh+nJ5a7n07Awoy73FPdpbLpnUiCN3q/leRIdT7nMNq5lw7N18cflY3HpSuattU3vaYY76OeOrmWre3zZXoSS/myuud7d/l8uya4vCs8VdHuel2mfBPKvHUimZFnhvBWEs+dVSzDz+UCh37OiVNyCVF3eqfcGfs+rnnF/ukeBnnB4Jt0fypB6ZC9N1pgqhY5dclYN0U4PV89PAKgiCZtPYGFt70IAHnYmIgiMKokAwyFqBn7Gix2put0svBW34Ed841y27g4544Wmt7PY54j1xtjLgET8nzlhlGV+EE/9Kq8XMlPBDVuJyvmCWd/gBK3M6P+JBK2J2pfHbvZwFm9nAc5ZQHrBd7zKzzu41hxMYukxhBRgkHvVfQwcH3g0WtDNKQQBwyohwzRKUrcxBkBjdYTxIg1nttFf0f9es4g7FHkf/x5gKligoz9mZi2e7pzdbOHeG5uz8hQtn/TJPMinKBRVvkcSDWJ08pvhIpFXEOnJWYpSoa0lfO5M1yrq1br/2+s5yuVZnxSyXyzVZflQ15GWrXxbw8vE2uufQgiKQvHmh3ZZSuNh4wo0XZWElYaHq9qNLptB+ZOy5xzwcRkqizrwxLTd0rsy8Z1wOxypNj6O7VQeDczZjY4NDulwWHp6bzfka5zNbpHkdt5vnrHeme3bVOLRf4wzMMRx5bkGeJT6ZJFEUpISR9xGfzEQ6FrEkjDSJT4J4Qhi5RHwSiSwjjGwSn2yjAQJkWBKfJBD4168Rn+h8//p1KCaZY9Z//QZE4NozPoLvbxKfHIkYgt8mPvHGFILfgbog8H2ApQh7EwonjPzbbxOfXIbAR03gYybwwAQ+bgKfMIFPQuAahH6H+OQKBD5FfIKQ3zWBT5vA75nA7xOfXIfAH5jAH5rAH5nAZ4hPrkLgs8QnL0Pgj4lPbkLgT0zgT03gz0zgcybweRN4g/jkFQh8wQS+aAJ/YQJ/SXzyYQh8ifjk7gch9GXiExyMf/uKRtu/fdUEvmYCXzeBb5jAN03gryAgIPTXMDgQ+BbxCUK+bQLfMYHvmsDfEJ+EEPieCXzfBH5gAj8EcoLAj4hPYJD/7W/NKP6dCfy9CfyDCfyjCfzEBP6J+GQOgTdN4C0T+GcT+ClQEgR+RnwidyD0Lxr0tiGZtz+qO/22IZm3HxiIIZm3P2Egn9SE8vbvaLy8/fsG8gcG8od67N/+I93Vt5Ea/i8IATlMXoPQH2tyevtPNPbe/pyB/LmBfN4E3jCBL5g0XzQQGPRfgwCM+TYEvmYgXzeQb2myfPvbehTe/o4JfNcEvm/SmJF6+4cG8iMDgVHYhcCPTQBwfgMCgPMIAj81kJ9pyDsf1ZB3PmYgD/SkeOfjmgbe+YSBfNJAfsdAPmUgv68nxTt/oGngnc8YyGcNBGcZIOgdQGsCGHoH5tltCMA8A1b0zucN5A0DAbzegQDgFSbOO18ykC8byFcM5KsGApi+CwHANDC2d75hIN80kG/pafrOtzVVvvMdE/iuCXzfpPmBgfzQQH5kIH9rIH9nIDBLPgQBmCUHEPhHzQne+bGm8nd+YiAwXT4CAZgur0PgLQP5ZwP5qYH8TEP+/Y80uf074HUKga9olP/7VzXK//0HumH//kPdsP+AEbsB5P4fwEUjIPf/AO75MsJgGGOA/efnNUL/8w2N0P/8gkbff35Ro+//NpT//3xB1/fwk3pSPjS8+iHUAmzv4ac1xT40pPLwD3X/H/6RRtbDz2hifvhZUw707QMQ+BM9cR7+qZ7BD//MVPE5jZqHf27qgsZfhMAbplJo4f+CwBc1wT8EFv0SBP5SE/NDoKozEPiyaSEg9BYEvqqJ8uHXNVoeGmJ6+E3TC+DLL0IA2PKvQwDI6xam/rbp4XdMg75rsv2NZl8Pv6ex+RAoDvjhQzPbH/5Qk8zDH5nEQHFbEPg7zUce/r1maA//wZTzj5pSHv7YFPgTg5d/MiW/qZnFw7f0/H8IFLcHgZ/quf3wZwYv/6KH+efAn2cQ+Kieoz//mKaSnz8wgY9rKvn5J3Tjf/5JTac/B/ZxCAGgkhmm/l09TX7+ad2yn/+eyfb7ptY/MJA/1IkfQfUfhrhHHzNc/BHU+2Ho/6NPalw/gvo+DIU+ggox1e+aafDo04b4H/2eXi0eAT1eBYp69BlNh48+q+nwERDk/4aAIchHhiAfGYJ8hAQJCH/055o0H33etOUN0wJDkY8MRT4yFPnIUOSjL2lCfPRlTYiPvqIJ8dFXNSE+Mnzu0df1XH/0DU2Ij76p58OjvzI9A9K8gi0D2ryDoW/b0HdMCYY4HwFxwu/3TNeANj8MjOQREOeHgRYf/VAT5aMfaaJ8BNS5DwFDnY8MdT4y1PkIqROr/bGm00c/0WP/CMgTuNAjQ56PDHk+MuT5yJDno59p+nj0L5oq3/1tTZXvflQT47sf08T47gPNB9/9uCbGdz+hJ8e7n9QywrsoPiAIyCXD0O/a0KdNCYZA3/19haR3/0B37V2gzyNMA5R0BLh5FwjoCJr57h8bMePdP0VhGkKf0z1/FwjmCEOf1zh49w3Dp9/9guHO737RtPUvTWuAQiaAxV98RhPmLz6rkf8LqPHXgBB+AUS7Dd34BZIfwqCsXYQBKb2MWYGWYsyLyx8M/S9w/YPW/sIsgL8wC+Av3tSU9ou3NDb/6/NGfv+vN4y8+l/fMgLAf33bCAD/709g1LaCHRidxw8+o0np8YPPalp6/OCPdTceP/gTTUSPH/ypRvXjB3+mSe3xg89pMnr84M/1aD9+8HmN18cP3tCU9PjBFzQpPX7wRU1Ljx/8hSamxw/+UlPT4wdf0uT0+MGXDak+fvAVTVqPHxhB4/GDr9nqvq7x8fjBNzR5PX7wTVvxXxnkP34A8/A3MfQtQ1iPH3zb0N3jBzATpSr9u2ZgHz/4mwL6vSLt9834PX7wA00zjx/8UI/D4zd/Wy89j9/8qGabj9/8mIU9sLCPW9gnLAzlrDsY/IrmhI/fNJuVx29+zcK+bmHfsLBvWthfWdhfW9i3LOzbFvYdC/uuhf2NhX3Pwr5vYT+wsB9a2I8s7G8t7O8s7O8t7B8s7B8t7McW9hPN8R6/+U+G1t5808LesrB/trCfWtjPLOxfDOyt3zawtz5qYR+zsAcW9nEL+4SFfdLCfsfCPqUXlMdv/a6h8bc+bWG/Z2FG2nr8lpHMH7/1hxb2Rxb2GQv7rIX9sYX9iYX9qYX9mYV9zsL+3MI+b2FvWNgXLOyLFvYXFmZn3ltfsrAvW9hXLOyrFvY1C/u6hX1D86bHb33TTMa3/srC/trCvmVh37aw71jYdy3sbyzsexb2fQv7gYX90MJ+ZGF/q5fRx2/9nV4rHr/19xb2Dxb2jxb2Ywv7iYX9k4b9928DTu89h8E3iiBg8N49guG/dMKAsRaGAE/PYwgw0el0IPwxiBfjOYZR/5POXxdhmiAAEDpNRTzeaUzTIB4jEHAbhWmAH4DevTCK8APKjQMT9deoiMqEVJ+A6nQ+EwK/AN0HSYxhQHgsDhrZjvjNuVBFIb9LcPH5748B9sVctwkGYDecYRiGQM6303AXP2EcJmkw3tlTVf4QWxDHiLeP/Ui1R5UCg7I9D9IgDvEbWcM8k2mg6ocB2kmP9uNQFfUPqBqbqMQwKrvB68HuTiaDOGxIEW+rbqFEHU/CIG4UfX0TW5nuhtlOwyLup4iOLFNJtyKVFJfBUI6TEFHzcRidbA+DuL5g8FMf0yvgf38KeMJERArFn4I5m81Vmi9hS6ZhHErs/hswUlGyD/X8n088QNkkgEr+zyc/abV5/9+PgZGlYRCRHD3Ql/WME0H8hVbTXbNqKdQrfc4s6koPhLC/MEKDUvcIo5xMk9cL5aTSMKIOcoLqSNuNPWE7Mo9FPIlCXOp0T0KxJUjOyH4IbXrbaPOU+gYipilEvE+pMV11qJBaGzqL5lljJmQotU4UAdtpUDRp7qpFQ2wRakajcD8VRjM6EfthpsZPTRg9U1RHErcjakRsL4K9ZJ6SPH+OFsf2sWcM6Fet5FeusJAsmm+H0yO/odI2zDFCQxzOxBjteMyzmkMv5St3BdLBQtsm47Ngae6ny+Uip50oGQeRGMEHC52XrTtO8gFpE78EYUFhCo9mz5P5WHilq0aF0VQLrciXS4F/48JKOtVvxi6X68NX7x3cy559/n7rtzoefY6s3Wv77x+11rcZITSn8Lcj03DPK3IDdm6L7WuHM48M793LSCtskRHwwG1CWWhvZaSdKDkQKV7sDzoyuQFfV4JMeJSyVHsI1LG1Zb8atF+/3P5It/2CqkLXQMjp20JZUNz0E4dSxI55mSzMN2Jl9YyGO3IYj3IW546rW+k6vjUuBzi+iHGu1zvNSRBdCPR0ZJ4Ipky9JaxME2lhjcuHIxbyNTTKqT4ozLLyOW3EifaLysac7IdZuBVGoTwa4w190rcHS6JzILZ2Q/lBTN1sehEnLgTzK8BKKZTh/ckryd5sLsXkjjyKxHI59ajz5NIQ1sK2KqANwb3kdfWbtcmIzWy3y/f1PTIJ99Ht7NxeyuhPNnm3P2m36UKmR4tZJ4MKO8oML4n5fDgZtUgmw/HuESns0XJC1ng1cbM59RwnVVOPLu7yG/wWv85f4y9z52X4Hcc4C9nxi1ESSLz60S1S7Xl0EfOFTGa+7MyCbfHhm9NpJiSLxFRq0K8rkGMvs63s8UrRazzuQCZzb2PP0/4wbqHJs1M2pJTJrNn0IM2W5z6rfYRWA4Whb9lPSm0h+MvLrd9SNnRd6josLOaGcK7M9AWMjmi36b6XDMXIybKvbY9EB9ZE84S9VDVf4qIThXuhNioadH0Eb1qwiCeDDb/XF529ZCLWuGw2y9PHWHbFyUSoYa76qYUyLZmQYCtLorkUhClMc9FJsLv41SKzQ4hJw+0dJwo/TRwgysbIZGbgW4mUyR4nwVwm8H0QTuRO8bkXpNthfAOq7NrP21hP8X03mfFu+QVot/HT8FBMnJZvJYe1zQZ4TZvHWQah/6m2bvwPINo2Sbe4+3SNzRXdcJkra/eCLA+RLPH6ljuxO2PNz6B2SpdL0QmzKyKKgEtrCuZrXSaUIx3Hub8yQALgyVytv689VSHFxuJQ3lHvD0BdAGNAzliQpue4syM0mlTAIEghQqhfAywGx+mMBdoEH1D4XEmj4GW0riQCaAXVK2kQjHdlJhM09epsJelEpDZwZxaMIQIGbZrE8k74uuCkJ/agFwUdZTKQ4Rhg4yzDUXLrMjCm8Vk8C9UJ40yk8gNimqTC0xgFGvAEZQV1rnGTqSi0WCdIKiJ09vGEdJ6NLPiQ0wdbCmXADplNbQfWza3mwgcxiuFirxgyjOkd0xOX3x8UZjBr3b5O4DJKS5oufpSsh/62bKGGrrXgibgq81vg/rviSMlFK3eydsURxRuEeANY4g9g3EELQz5USAmxu4zEsIzE7TYNpyikYj4UVCDQbCLMwZW+ZG6/6ULyNW1ZlcsnjUsxollmoYAD5Bntnmsi/qR177C67l17YpaDahbHuLsqWcFAFA2G8WPpaiJ8Lr3azf4J9KgtgLToAmuD5RS+dLiGyxtshGYVBUuwMcgfHDZgIxRTMJPWl3b+5ixTrdjxsB20XCVAXQBlmq1gtTsoRNlvG6nqdmIRQJniP5D0Q8A5MUUFZhJhjmqqAkjzVewm2mHpwkD8ahIGHTVAQLpa3CxIfSrp0cDgg+HyaEH4xZD5Wxh+OYNo4NWhvOGWfcyglaMRlrMxvw+0OOf3gdpmfAETy49hTP2ix3GlxzkzTNNJlDrR8XxPpOHYX6yOTXqqsUlXx0Ynu5vMqokMyCRRRFVN5UBpbtzkqv4KtpUc+gscoXHnIIzd8Qk64ygUsWpFW0WnCnuKtftI6SpCJrP23IZmHY2ISkNZpSadBYPVPBZPujluC1rzIrySsUBdjsMZMSX6+AQtMNtjEUUEHUWE2SwKjooxDe34ZZoenTrbDoLUeqdjFZm3LR4YsF2/3WNKzPLXeubC84zhbsBf4C7BH8OaiPhS8qyIJ/7cwFpxaQFd6aUzqu3yWqtKa2clTpPnpcsk7s2Obl/0qWxZ6RVml7Bft7DphecnW8p9w+WBn28L+YFkju8XXkGiuS3G0rNuqCfJWBELIqhVs7tUiG2VN5nsIIz9OHf9MNNFyjMhr8dSpPtBVNoTrjnhk5csXJbFqLKVw6tqwVbm3VGxSpZoY9iVXmAJs2kx9jixp+3GKqJBO1S5yTeWy3iTb9QYcnq02bzlwZb1XNfdtF4xF1tt51PqOpSli7DZ9IzQPoxGgyse9S+XttR3IdVyiZvtXY8y2Qkmk2v7IpY3wkyKWKQeycZpEkWEbddHH+wIERF2VB+biix8XRB2qz46SYE40EBb618gpVhNOWa3KbvsUYZP+BcduKW0DSFdXHNUNPWjDMjnN9UIoVTV3/XcvdN11CMo+fEkHNSmcNFQm6CEidoUxyGjLjHi44rChyPQvebRxXWPsmuuIuhlTf+vebRv3YfQRN2mq9ymKtiAg0EJGJRmnsiRlVGNawU17UHO6yfqfmFMWTg49GLq3/Ws9zGgsgXqskKR+QkLJhP/BlPdKykVT25FqQnNpneAjaIsQVXxWHiS9SjNkd/6d1kqtuZhNPFvMbwE4l9nGbCe19huGEX+y2gSf/bMEzyZxZ3Uk9Q+inPmzIUXQCiNO7GXUuW47MIL5ygqrGMvpAxt58+/QFmEkAyvx3tnzp0/B1IGgMYgZ8TeCxu985RNEDSjbMpj7+y5iy9QtoOgKWV7PPY2NqD0bb7I+9tKCLkbbN9NgzjDx3p3PMq2O5mQl6VMw625FBmfI0xtF3nkUccRKNkRwYRA9CTZu3zrOg+ctChzG0edE4+yxKPeXucjiviNNniv85Fmc6/zEaXZzwZFUJup5wyQdLzDIDW+w5F7VOEMfczbPZbybj+9JO11zlYLSFAO05F2DDENRYqEiO93qv2RUYAXlJ16gqVF0fqBieGIZbzbzwoH7Jkx2FeXQtmYp52tIBODaNgdtVTYhzCb83A4Hi2XXTbjhHTGSTwOpDdmpEGo+ZrTPiTi85Yy9J9wPcALlEKGvRHDO2h+NNwYMeVA6qVg5kfDMyNmHhf0o+HZEYuCI5H60fDcCF86bPfWOJ9QOZyMOtYPXtZqMYToN0W8qXPlcYcn3pSltJ92to7UFZWMSTNfMtZliwKh/ozpMvwdVpTv93KaB2p6z+ycDgo0J67qUmrSglljjyRUsaXdt/K9ov/Cvgn3vuMsazZlB/GDAAwByOIJwfYLozTOVIz+gAhEH0IxZLhW0R4u9cXFWDNbdNJRd7JhH5hOPcHFcok+4BM841q5qSPoQqexC1PAu/2guCESGIIDbhEOgxHty2HmDmq7bR/BjaBOligP++OiEOfZAChkPKJ949/ZKQgdd84L6qDF8M+RXYY8Qi8q5584Zxd5vxY35gWX0jUm17eSHIqRoQ+rTCw9bw4rSDj1tAeLD9596cZ19FGg2VGzGbseNY9Lhs5KYh6r14ZiedXUBWyvOESJ1X1KaBWP7YXroRjluhlr6eoJ6ZVkHk3i52RjGsaTRtBAXqwdyXUa6JNiliZbwVZ01NgTQZwpVxNyRzTw4QP78NRzits+15gF0HQp0kaYNcJ4P4jCSYfAVA1mMxFPlCoLH6uHteI0/t7cJGrMjtPdYvNJ4aO9vIZ4EmQx+wnCiGo1RiQzqCOjTMISeu78E94FPal5cSce92WzWa7fI3ESjwVBFTeDBfa9dV7UrGyedYa9mFde2ordrYP7NBEnIAgUnMVLW5y833w3PLsQFIkYoY0FQVdRmoWpTPjRcDIggBFMrI/YHZdRyLf6icmNn05m/Nb8YLM7II1qHEVjUtWStMVR6cxMcTmpNk9BKh3NiXGUHxd8tx82m3UebLZkYgq7F68//0zD5piF8fYrt29w9I0azIAFoci7/lqWxH1YYs+fZbb9UI5n/Jp5NY64Ko6OQ0opZaTx/DrBB1pWRCV1H9HSbg6UjP40qmJoiQhc/wauttJxA3esDhrqoLlymHvxBOZ63Ek6LozYjzs7QkjqfsA43hWHkoviWfC+7Ezxgja+PU1lqTVuHO3LEoup8AgoF3qDzqPznF18YeMJM7xwKPdC9+w5lI+9i+cunAMB2Yu982cvdCmLvbNnL3YpisrehQvdC0pWVqHIOKNjYx4pL8DzshdglJmV72B19DEpvl2HzShIl70O70DKi+fOK4m6d7F7FiRqEObPblB2BPVc6PVoR7mav5JMRMa2sAvdLu2EF9k+J2c63U6XoI+0w/44CrKscdBQlhaZWiIWjqdmPLCezwQE1CN3cbAnOLmzcRPTklV3LcrTIyw4B3oVig2xcsnW8BbqXpiZlyzivoV0UoHOp+OStl6PU4zuT2/G0dFADtWHOd1YLslhO9tI2vq5QjLiwt/F9bykw4fW7XUOgmj3znhH7AWeYIsc/nuuDACC9toKAYshOWyn4jfnYSomZNRsVvwplqPxrKVjvvGI0nzw4UhtifVnETQco1oWm4hISNFYgSMgiI9uTqFBnuhgmLvgUl4N0xmTWNiMGOYuuJRRw3TGOJE6W5xIXoBKWRBCmX06zHHGCrHzKAq2ImHK0Z+8Elku0YJrvApiikmYjdNwL4zVK0+1nmBXk+FzKUBGLwd7eCBXiud1WUrtqsRZx4wSXdCXS+vsqeXDzJJjoody1C97Wn1mHRcoVMpnyu3q8Xl5bO2tqhkZeWZ9bJaebD3DeQAFAoOsHipqL/HF+DSb6K9wvIN7tUoD6tBdTVFtNF+4yPcrsTmKa1LsZSvTTYEBDeplJ/zU8sNAf/JF7veOj9W/w+7ItxlwhpjPvHjVplo7QNHbq8aHdr9Z4Ea1Cq/a61v5hmQQqNY6Pe+QPagZOBxRh34Qg1iVJpcFbp4JDAc6PKbO1DE+aWL1MIosl7PdCaDpmmOGIqOOrRmMAb5JIEdcDKVD3nJE89i+7INtNNqxvNQh3WGVQiPaJkCoX469tIHUgG3VMcPuSJVV8ntg46gRD3vN5jWP3Egy2ZjZ/jSmabLXUIwK5SFWrp7mJ45ls9mrjpjbPviBJqg99q5HPHTmDoinDTWJGpCmsTfPJPqN2xKNIG4g0gmLad/UbgfPALwyHksjShlRJayZ9Gj3AsSpzF40mVNGpmEkSsXqtps5yfAd171AcrIVxkF6RGqZs12MSgsYDH6MvhedrbCbVJaXt4rrVhtJm83iQxGSKpg6w2UTM9E53Itq2crhXoT5slkwVp0tQZZLW1oJ7rxhJTr4bMO1vZk8wmdr0NaumMC2gEoymqOMoF6Ks8LFHcMuletZ6y/WCD4wbecoS2hhQo4q7N1hyrB/sg8JQgy+n5Th6MKMdGYnmvGg//VYO3efeWknmYk4mIUdk7NU3CxNJvPxeynO5CyKq+lHeZmy6xwkPH5NItR1F66E8ATFZ7tximH6aQ/Ihx29bg1rXJgndNQPB5Cch/41re7AKam90TesSqlBWthrwVIQbeSIH7M6tmLtA32dFG9X1nTeKkKw7zUlugla250sACRkwqvix00H6DkR5anIZkmcieMqdeJPqtNJ9qQqi4GdeWqTU5AJIpJS6wcmptc8MglTMZbqyQIYimkyjycu+m1laScV071gNoSokepOGda37zmESFf9kIdFP9aLJWF9RwQTi0J2bLJKx49PWB2V41NayoFkSLUBJxpIWMbDThRkytPSzalHdHrlrT/gYeHYv+gD3cwGRH8R303ijj8kst/lZOIw2JtFQqXRH5Ukh20TK0Wcwewsx5foGxIWAOIX/bMhjo64buIFDua0SzvocqoBCNWDGnSy+VYmU6/LAnt4RvtFZVBuCLKoWpPUL+fcIW4FwzcDeY3ORUerocn0szAoze+FaYK7koR7CXdAtPrawiBxnlkY9kYOC1MHk36yAjKAjnprpLZtTi8SSlnGkYSqs6yyZLQC9PMetjLap5l6wTcbbPitVoZ9HPNjM7A5J6RfUIQaNC/mC1T3+nEOKdbxg1C20pIxCFvlKcrHrbliqOPWPEc/3+6OSSGUVR61NdIdXZgFALmDcXjvkKGZLZu82yezVGQi3UfhB1uhrXZBQgqbTRJE0c3pSuSgELuAKa0ufAvM5w8XEO0nOROjnPqryXQ0Vd4b0Q0Y9DBrJ5NABvpZktoXSZrNGl7+NEumE1m3aFWWVZacvG7iAjvqJ2rpTP5Hls6KrU15p0ynpbfbYBXR4pQ7r2k/Vi+D4LI0TNWOZRiXNi3DeERLRjZGi0O2giwc18rJO1LOQErGlguuU1JGkmAudzaKPMVmjKVcdKZRctAnjhpYpQRws+mlnCibsyupwOPJQLkHD8ZjkaGGrpocakvS8HUsCxOUpVY3+pU0QrG1CqxJZyhhgJxHXxFbLpEyagRsmewKW7z54AX8pOLiTjZOZgJ22CqAd+ZUH2G3YoIweHEhaAPMEbsr7S9iTBMKiKrFxZLerEgl0A9MoCzZ4xLgVzZzarQbmRjP01AeoaJQZA3l1xbnwk6wLxqQ1+w+jwjI9blr11R69WwNmV62kbRV1WTkGjlZBSMyIqp+uPo5Vjw7Tr6jRrGgiHtNk3OAdK6CuF10qF9B3Y2uo3Vxt59KiWLzqc9xEkXqWYsXcXeJKatA3K+/LDIpJo1qXNYIUlHxtI7+Fotxqq/J7o3txBx4JMv21Xc19eCaR6owP8v2lZv3RpTE2yItmoBnnEbYUu4fySyc6V3T6UrH9E9R/t48kuEx5ePJSpRMBF/r+kQe20uvriHy2G5qTCN9VrOREceKqDE35iQLUYAsRmZlTPy6wX/CNFwtpDIlqwmgM0kcHTU0092KREMmGp1ICUbvIl29AkRUlWJWpLx7NBO1yjFcqO00qdWQnV7TdorCcte0scwbHAG0Iombp7+k4RtGMC2n62vmIofdUet0G1M57I1ovlp/eZu/ybs4x69aaGOeiUkjyArbAEVrrt2j9rfKEuXtF0VxFsECMefKfapsNqXVYtSIUUWkesA90NpYzXurrF09EJzENpdS15VUdQHtBw6VFjXwYREe5WUNl6NqsaqnAoYC+IR7nhwUReBz1HS5LJItl8MR7UzDSIrU2+7M4/A35+JmHB2pN9yaTWHe5VtdrnHpWADBBGpPI+ted1tdVI6hANz/sxgfNeJhp0hVTJgMd95TL20219Lq+rZcrhlCrEi3y6W3shqiZ2HUdsZlMmYxH3sh093rr8VoI1UpcfBEQVUyQIuPt8F4THE7otYwWMVRoxpTujjmqGoiZqkYB1Kd+nmiUwD4SoLywZAT4cpwEGc246pI/VWJKhVmoai2nehlL4yh+Uox7AWGzQalQ5qSGniFudoBVYwzzBp7QTwJZJIe4SIVJ3Eb6ms4W30W0EKEWD2Ks+cF8Ktp1ojZajxtBK3VXBsCSdJwO4yDCJgzGekELHPElInIxmmIOtbalpTiS59Fuxygbl41GbWetCsl2rXFgfYNBVeXLdwarqjzlVcBMoaVlsFiWU3SbNYP7K98/cQBLi2fMMzYMvUWNEFDNy0MAr7HSbIbCgPAEwktKUyTdI8wR2rplUuCDb1TkFq66wrSIgfsUZTQgyhSDdEzYFAkngVjcVXglRQxIf5TynzicCxmEqk+jH2so0T1QiHEyoEnNQUSPaElJ8qHp2yLlRml5iNGSKTMSIkQ8/RSYfAkqfAE+itYAzIqh5KRLq4GMjBDTZX/AbXZMHIRveYVur7GTpApemSYDB9y0gogbKfZ8ZiNTpn5GWgNb1BRitjcndHqhqjYDxX7pdIZcmWvwqaVdMg+HCsTlHroYmVQUE1Vs8DHwxQWCtlsQkg9+fLUW6rAjhkUgo+g/6rEYeqKsHmB9Zs2pSWovayd7Yaz9jyN2qj8RHudZrM8kZQ1SxQlB7eVdg/v9pd0iLXlUL22F4SmC6SLOUgzkTGo5YtcM2pXdbN+2D44OGhDZihYKWcnBDj3xJ4KTwo5GKffLEjlOmZBjZ8ShoGn18YWTQDkoTJEU70bYSjSos/Sk162IrNGgghDRvXSnpPlNMpCfeSzqGvIImc1YC1b6LlVm6I4FDmujCLFUElkIzM4Ma9Jz9I6aE0p/cpi7aWlpb4Uq7wFoYSFCa1AZkKOyiQt6Ure6xRK7dzprynbCec4PXZNx+Ly2Xpcf4DOoiIZsH9HGaYvvGgMqMsvForvt9tmqhe9iyETzgfeaouim1NMhCGuIau6GODmhmemFWaZHqPRsfLUcQmMsLjGOewGTfgYeXG5NENlbSDSVRuI63izRj+BJ0ypZQWxMzJRneEeLfEVh8hLvCUZSyHbmUxFsEdGp05YOwOfnL7S86fKWkES4iiiZhta2n7QRanrVvNa5U9qK2934Ncng0LJcDmKvFIc9QmhLY/cJy1N3R2ZXAn2RGS8kVWndnTy1H7yAEoQHNIt1fpCfzw0wBE386xY3UoMdvA/wpF9R4JxZpgzxE4zKmKUnkTvYcEoMp6qkS2CWhCQCfUiuVxq5kSq5vGkwjAntLoe1q0+M68Q10BIu+nVLQwB7StKBSHAPVyM7OFi191euvoHSa0Vk8jkB5LJUbM5H5Qhls3sizRKApAMMO81j9w0xNsgrTItL5cJbRGUYpU8EIlGUWYoMsIkyPJ+uS7cFYKcVjGlt3aABospYLF8kkpjdSyWjph7QK9kS72c6Go4Ph5m6N6Lh9LSO5qA2HtvlTxx7mGrWanRZkyMlVcFPKyViEZPl9rOh/eQqbTQRU9s1pNS2KacMqFTfYWynjp/5W36X64w9vTtP2bgn5Dfct731OBCJBqO7BXV0za9lPmXanzB4pSw8suURf2nmz9P3qocP5tOkfdJc+v0RRw3005RwtOmr5uFp892mjn5nko73Qx9T0UfJ8yduoBjJ8BTlPbEufweyjpuZr/Xon6F3TzlrH8PJVdX/pMIh0WVPpWFOhAaSu2qn8+6ASi1nlBanYh4bEGnEhRdczhlFESAAzrSUlUIq7TopD0D/mO15hZ08Z4OgR2dVr+ksTbPF66Vt+2VffzxJzKps1FfPY+RO46m155Qmjy+TOeiMTQ7oxZphCB0JuhuOaA0X/VrdL1wEFiYV9Hy/aLDNqHN5loVmG0keNdIDmOQKGPXKd5rxQGuOn117pLaM+vjTytPcaY8uOaRyeqRsrF38RuABTwoFCyBvVLNkaNrHIObeTwBP5WB9KlOUKtW07R4Lry4K1HakC6XdYdJyyUhqwdMiT7QbjY9HRzUPSlaudJCl0uT3FzUcnbHR0MxgtpWSM90xU1dOhAkLKElzZKa3jj6jqo3oVV1ZQ0NlOLLG+MnDKCT9JcYx2N41+pwshhvvem7D3XK+eJiBE6D5JRGCCZXjRFCgl6I7PgVafmwCI/y1GnWWpkGiijqqNUMTKu+PS8eFOUZi4Qi2QkWCdIuiFLv9J9ff56gm1K1Frp71Bj4rLFkMWtlrLXfxbceE2e376hlUbFhwsCItKXAIu/LDtom81J8uWQTsVKlieiYgeeyOMxxissdveBKiwtN4WpnFhDnWz2cUq35RrWWO9foVIa8cn3UtIHawvHEqsCyg/OhHLmRSqFSjj8GE7IOE09MsYp3ZROygkAmOtrYjVa6Z8BEXVlvjLVFrCy/PzAw3K/E12w9upShHAFTe86db+SOKhgtadWBp2wEDfRRok3GnoPF47bnFsMS1xDrZbvShcUyGqhlVJktcTEMRv2s2cxA9pBpMEbTjpVTx3K0l3UwzF2w6ZULo8wUnc339oBw6i43VxN4WUd/8XJUqQoLLSpx+P/xFVUSeVlpkVlNUqq0FOP0TqT7Is1Wr9eXY6nqm/rk5bhy32wOy4sEDFtGw6m33dmRcvaSkDvJJLNyiADBAx0KBHvB60ncDmbhdiDFQXDUDuKj9h6mR0agxn7Os6FAsp83m3PHQKraBzdOXQN0zaloSSgtxdSYvWml7l18P4RJtFuRxlbFragzDeOJt+LfwDrL0TdnZMdovsMYP8M4p3S5LB3YS2WsYQ719ac5hZHGDGnOb3mSzVnGBAtYCA2MrYoRhZz50ABGdnFyYBUVcQlvbuGiRXzSUlX0n64KFncmYmu+vVyWR6w0SLyCSFwGr1BUL+NYGyPxZvO+V3zVeCeYK8lgbjlnpmhH8IUzE3xyVZ3JWUmM5H0nDyTGeF/keYme3YJf85yvoRixLpsjikyzT5xo5VhK53aazWunWRlqb/Ep9IzRdt4JmrvwReNxfHUsTEpvLTSfy6UNOrPzUpfiMOk6gd5sE1evHocmjtLyBCsi7EVGSVnKYXlJ8f7YPI1oP1VP5o+TiAuGMG7OED2YaLoQeycevQAgZUEjzT7U3uAd8XnHNfdkNom9lQtJSvIXU8Rj8G3z2xGwyQuIRpsqfi9r27tdo2L9UoRTk0DJVasxQEtxZQuu/LvIOj6mXuhxY/RtHhc2jEelyV6afyV1UFaNoJYLSu1ox+WBiqGtcR6DhKo7gfoR06HSB8pJxedQjMzttzTHUZXODCuOXrCHzpwuJxymoxWxR1TyuGk0JdbHwhpTkp3m9YVIrlyK1kc7YhyPqx2DdFt48uWVbH4dMdhgZVaXj+asXCvM/FIqLUxSelJPTCJER8LrY0HSTNyxTMpjmZTHEqjCL28WTfw6acV5nucuQyvRPfLN0ioBW/rS2mBNg+yUtHGIEqvPMmM8P+EofF4+Cq9MuFZQOQxniXs/bn6SdhCVDLRvW3lsUn3PvuKZrNwTlvHtzk6Q7XihdjU4zEZ2Wcv7WrZImEDi4KXcqASbAsdmkI2LPDKXVElL4s3UmpuxMM21O4CAUpWqRdadckk/1d4nNU8eU3X9FCTMEi8qy4Nu1K0Sr0GuN48ipo34tLixZtl8RVB1S0Ix1ZEnsmPkibziwri4OiZgyanVn8zTaODhD8e/Rre6WFjl6gL34ysp8tymyE0KqwJZv7fwOq0BvZevb7PKM3Ww30tD2FYp7yP2S+8y7TcyCiOrkHm8GycHMclzSpmgvih6+6zjZchRloXxNHG0ZPCpBChZVq3EnvIyVlKwQOqGEsDKyiuqHuoqlGKQki9g/UbhizAZykj4hCDFrOrZdLtWPBFB81aahM1wNDu6NGVFU+lrByuu9FgBn67fKk9jHMTaBQ06m6ntuErKCclr2qNxUm2RBj9lm3Su07VKJ9btWnnw8VfSEDsqDXMp4sSmlD87MrmDuTxaYG7NoihKtp+WVqtXS6GI4mppbduAW0MyvBRh63WskA2orolSpHvZzekdke6H44pfyOMSnLo3lcynG/RyHhh7dH8rDhqv3L7h1bdKO8FNf7nmFaTwyu0b1daV0VnO6fLsq/VcbBbInez0zcPkp2NcmJQv3Da8ZNqgqwi9mEElt5RnRa9ke640sfi8pZJ7jeEkF0x2pDjESykY4JkjAAiqhGQp0jiIcPUuPm/Deq7MicRBGkqBgLUukx3jouGlME0MBJul0hfeH/HuFo9Z1SMkT5nFAIf842C8o8R5DOluKA+teIaI4KEBjXjRx+q7WcrZhHJY+SER7N4Rsj/1hHEnLo+uCqmMUP21btlVpDLiX3VFCJIvkDvapqLlfgySkgcfdCA7QTzeSdJsAN98psD+rkc+fPmlGw0V2UjSxp5It0VjVxw1AtkgLdR87jBJ/bgTTCYqG7qh8tQtXuORo1ZesHE2WDpnOdMhdg2TJgWfeIKyZz0LYJKllF2tApDod7SvK6AEHEdP0o7cEXHpRRNbhfIINIiLsqgfe+hWq6Omtuf6mYVRSiKBbj+hUaknICkKnqKTHQTb2yJdLslGp4svwmmI6VJqZtwrcXHHRqdZvzkT8eVb1xtGEmiQlmexNLAhvyhVO45JeIEq5Zovsd81SjvlYvt/q1qazQpgZTgGlQT+vp2pdIFLgPrAc//SN7oRjIyloFJbmKkA22GVDl/3U4a+ul+Exc6qp4EMr8vui1SKFE3/ik8sGB1nZP76+nYod+ZbsHFc3xPpXjAR60mQtXdDSUqZTA1brNRoV4eSVIwgEjbxHB9xiW3b1Euq/luVs1i9oKGt/ZqsOeomWj4l6jbNio8Zc9+SXuoW9/yGcoRCbGcnyWRZoVSVCo1Oa2CD/pAY9Yp2HuIJfJDhViB3cGfmSOHrz66j6yg1eJ4cyBbxCdpFk3XY92ATWim7gW/LOeqwpKQOS1ZUVNarl627dJSmtgsmit3w5FMUL6nj6ifBJhZjZstMTtRAJiuq/qLKpFYHWclh7xnZzVb4upi0oTGFeuukNKw0bQB2V+zNokCKloO1QRGEYYGp4+yHCk/SuL3aQ462fm9x76AFW6vKecSqmiwsq8nEqB8adVfIZ97YS1iodV142l6h7+XSjEJorU2YheCdNvsVxsxKLaFzWSTsiHi+N7AgrgDD7sgvYCROYkEoC/Vdak8FeDoUjveiRcVhUW5umDt7xlDf/QmLlqHBfX489aF/OdmZZ0K5abmViml4OFihed/OQeB41wJYXATfXFQSlnkOsDq2mKeRL1rEX0dPRvM0ynHJLZHeMWSUP+slZsHUgZVFIekU3g284oMPi/CoNltx8O8ljnVAEcbJWai7gOFgY8dBFG0F491MOTlz9Xw2ildTlrrrwMt1lM6WSxFa+2gbEYVxXQMQzN0UpYo1rFKpo19JSjriaiOKc5SkCNclM9qksKYnFb9APLGQwvdFTaHaDo4nnUklmWWPTkQBtO0sQI5qsVgOV9vATiePecdcLzjkC91mf5HjJUXnrKv4ov2yVdkJqHqCM68TcqIIveuRq3NlXCkapoRJxU+TcstEWqmSh08skp8Y7/gTOzkZZZef1Hh0e3I8mhSaV9FzOYrUu7EEL6AippTesl9XwDBtJaM+TXgyaLUSf+P4RLw25rge2+j80PngaSthN71j64A+S+0TECYR7qi0U1x/ob3i+jLP2Z26h4ydAyRVBtVHPAKYMmrzTQy0TG+BTiDG1WOoU9ChswCfQII21fHUVyqIHxd1zAiUUlB264Q2KhV18SfVAARA+78+d45FS+U8+lRYKZ/wHIMUk+h4nLjF8GNijsGIm8DsxI4tG+bOa17CugoluFVO6s/lkmPNkUTFHOkkj1aJc2T33syRJPVve24x7iDKmkF0ViwzkMenQPOm6tkOPgGoz3MSygJYAwIlykkWqBOclAX21CYehiMegLT/sqcVUgxtpPE+W8yEK4YDdNRsvuxVQMz9MtnWpDpZqVqK1U/m4+aCHA0rRuCOt5bjsvSlPbsXNWf3onx2L2rO7kXl7N6psnxqL1ZO7a2M2lcDOBz1tb3k8aLJmjRKM3xBNQ4is7/pWV6YAPpis6uIhwmWG6ozssLnqlr5CcF8VWmeuEdsLOay1aL91O6WVapWjA5ZaczjQasV+xt9ndtEs1TJ2aG9SXssiZrNwMwL1dFy+exbtd4RV+J6c2CnyHXSUoUyu5KoUtDtOb5uVM9C1HFv+UmCWg5aPQWuT3bcwvCEahySP7EeRzoswQsr2hOrsdamJ1bimHUeN4JPxJrLsp6AOSfpiULdE+qsyqMn1lpJXK5XM+Yn1GfWkhPr0Ykq/VKC1JP6owXHk/uhEpXKP7ncE8vLqav7xddUfyV63Jy6rym8+HSHGUoAwNU9xJ++TI8WeolT5lyC6oON6rqXKKlgw5wnxXQR8lgXkJncTG+GfDJOUkHYLBVSHuEDWJm/1nUOHz4c7EXqiANrE8VbjSEXeZ4MXvISZjdigm8CFgpUCb6ZIsA3GutwEHb2RJYF28J3/Nxhw4rzS8Rf8fzawjzP5R+wqg5ZK2L9l0zo5tZrxccrabTyQtrpRsGolVXvjbLZM0GOQ7Av0q0kE81miQ7Ir1272yAtTDEVcryD+TDEg+I9iBX9jE5zU+0m2CLYFrH0ZQd/c9rX8fjmaHXrq64jbHS7aLqqxD3nrcwD7zdui7EI92GPWciCjWcXJnHuN55diPw37CV5NeQeUn6lMkEXSNNPHvdjpo07TcxQ3ZGp/6L5eDGMxHsZuIQu0k4qggkUAPk6xpnScknmcnqROMp1tH9PB4mX4qVFNbCQkQv2ohee3L8EAXW9EMHee2m6nfmE9EUniT2Cl6xZCXFJiwvAKUSLeOLGwpicai6aJuc527jQ6532BcHzvQsXqPMm4sJ5lc9foeXCXmbFCJiR3q//OvHJ9Vid16BSh7Be94xPrgVpdNTYCWOZEUY2MN2dOToXn84jwsgZBN0Wik+HSUwYOYuwK+iXXD35Rxg5p/KiQtQCLyDwqtgXUTKz8JylnTt3L9995c79KzevXrtD85xdPNftnuZlyEV40ScXOt3OeZLn7Oz57gvug5WZiKaWBRQfFScYZsJxiSq0EwhEPUMKCX79pRsflHJ2W0kTLIRNjH5Be5GziK+cUS6SXX+Dcy/R83291+0uu5Spr7viUPomCj403MLYPI38QoH3yu0bDNiDv3oWeqt8/O0VmaBcmrPXsiR++nyKrIs1kOZsK0q2TlEQoOsDUbLlDYsiRzhloyQWfsS00OIvQHioKTDMmYhlGoq6yCBn20KWSEXHZMPKNnuUs50gq0taSRjGjQwkePtK9Vht50Ei8WRH3dlYLsm2kIQJttalLOkkcZQEE3fgk862kJej6Lbu9AdVPz3nYO5Vr/P8gPrDV+/duRePnveG97J7d0bPD+iz69t7q+eQoT4Xq95nokw/Qz6ULB5RBrsQDn8G8KdFGGnFfpxTymIv8gD30F4Bs4+nLOkchHLHeVGAkzAeR3PUVeDjpyaCSSuGJp1MSE3+qmPeuIjGR7chSTzxJG65lPGXYn45O3PuwsXSQNS89UoXVoITHl3kdqzQhl4ezYRaXIT16Vc7sspMcd1737DbfuFy+8WgPR0tNnK6vk07e8GssjBirnU37XpHikyqW7CieGDFE84wvu/cB9a3GRmSEuwqwEaEUoZrhrminrPVLrwSpyd1YtV21a19uPacR58flSwsbWbyPtISnfFOkMJKcVl6XVrYnPXOw8crs5khJBiemubhU2X8mEVVctJCpdZySZ7BwABfdi0Pjiep74CLDnuSsnhQHxXTFuGkJX1ZblWYXVXvK9dhS5nKiGqO/yWOlFulJK3JRfqmC00TGGCgXAyIvoCLrIKMYnEQw3iEywHeZIBe2cZ6CW02CVnjPKGONWJxDLdckni+t4UvEjmwFUfSCU144lgOsrTZJM8TrV2FOPXiEUR2GbLr67H0UtbrUkqZ4SIFyrFPnmQJ0y12kOVJOojVZV7n4bfn0f8TrZy100FiDJHLXafFSamL++NbIp7Qklw9H0x9d9+ZHFNNdRiGYkSbzRPQMBQjJopK1BV8GF9Y4vu/ZKeD4zv9K+mXt1qBM6VEsVgc03OHsGjRoGPGYxWJq9M30KyPEUp92CAFViegs7sp0KJETUc5qJlAT6iR+mqG4UxWxjhkgIEB3uRLbAmEUP8UzbcbsrDMCnBa1bytD2WxmA8JLLvPEEY6hJF1wkifMDIgjDTJyDy0Lw5nQTwpFkL3KqVrQj989d7iXj5q0Xv5svgoM3yWwHYqnHoJ1aSq7hloVtTu4bv5Rsea4JKAywGSDHcArOAgXo+iVY5aQxmsmbWUCBXGfN0bvurfe370PPUGvu/dm7To0rv3PKWD9Y44FGNP0L4yjugEs1l05IFAYVmql7KAxcPeiMXDjdFyGQ/PKINEFjSbpKXfdIOaIg7o1Iwb2XQwiDhpEp88ox+D8yIeUOYBtdmXegO0d8oUrUXWtUlWEJ/1dlJdvEJcGXO1ORC5R3O2ca5m7watS/uCx514b1J6/zihC3TEFScTcRedQKNjSP3Vh4whXzH+jDvbzWbc2e6Hne0o2QqiNXyqLuwchPEkOTBfsLXBIgKW8Y3e2QtnL545f/YCi/iZ82zM1189jNvtdTbn68NX7x1udNv3Di9cG62zGV8f3jvcuHZvfqbb3bg3f/HF7jX4e74H0sSEL5J9kU6j5MAnN02oEcazuWzEQkyyxkE4EWkjjKXYFmmGbt/TBHaLhJE4kW316pVPrkeR2A4inXeTN7qHF7sNT51WYSKlD5klYSwpYSSM8QyrjRlws6rOtNR3zqb8pUDudKZRkqRshyuG1Zmmyd4VLer0rfS4p3hlmhw0bgfxtsBdpzcBblkoCbeL02JFzObdXoZnJ3G73afpMB5x6aHjGsMV0qKII1WEya7vx7yfUJZyQgrnh8W7w17KY3w85f2ECQ60T1na2vZA0LQMYAYshLpv/TFppMkOcbqwZR5BQ0YEQglsSBPeZaHtTT+5FPaphw8KFDJh0mpRusnPndt44XyzKS/xc+fP9F5oNpNL4eDc+TMbXc6982fP9TaaXlyTkw70UYzn9bobZ5qSXrrU69KW+opp6/y5c2fOU99LjV0fS9pt6tvPGmTuOxIdjM0Ku5EOTsUm1HCu2fRki+94nmhzVeXm5mav24RmLLFzlAmOHVpi0wRlsrWjlGGFfG7bcFjSD4jWxkbrwrnnPXFp4zxte8BcoKfnnBwHJUbAu+ohSB4Ppp5Yv9DtUl9sbvaYaHEASNoXm2fPneunLR5RgbAz5yw2pl7aOnP+ebHuidaZi65Ge9cioXjxho3ZnM3YhO2wbRj3o4KCt3iXHfLexkW2yy9sYJtwHEuPhrYJReNUL+ZdoNhuP70U91utlJYGPKWbUFKzuec5M5yybeM+upRWHbQlPN7sDuJWz+/2k0tHfUWlId9iAe+xMY/6ySY/wiLL854yz5tzb6eG5tpnL17qdQc77Y0Nf6d9/tyljfMD+PV32i9cUB8vXPAjusmj5XK+OfW8rL1F1wNY7vY8YhgboWyrxefPB2zNm1/yZnx8ie8Oev54k++2Ns4PNs774/Yupf0xDFGwOfWydW/Co/ZstaDgeT7p7/IDb6sdMsm3NfpbPdblPKRs6m2tS7qZtQ+rOQ+BHiCSbb2PS7aNc30svK1Wi3XZoV2X9r1thwqunUQF2+yI7bNddo3dBP4FCD/inuDAJMyZDJNIFDFyiAsbLODdfnDpqN9qBdTbRick9BIO9k01ujveth7SlCf8pikmsQmAivqpHeIxz2oL3QSxbPvSuNn0xlxbr47bUo1STNe9fZ62eqsYjlsc0tHn95nk41LR4dSzTZbNZqsVb2bV7NucaxY/5zGb8aiPgz7hs0s8HPT82SYP9aDP2iGl/RkM+jU+b0/YLo/aE2bxcOhNWtfet8twQzXnU+/a+i7tO9FzFRXyAy9m+yyFTR9iutVK81YrZq2WNMN6s+A9gXODsNc509kgbD7ONvyF8jrlbzElmfj7OdOgXQO6xmRy+c6V69frVFxHVR6q4XOj3hgQEBJIC6jKF6gIkMkrcYhFP0WBY1vgric6GdLxWVrRV6kK8sJS2EtXVaaNIEcjUg/oG3dHeE/UKIpSinLYxXMXzp2sQ1e8OPZAYgPhFkLdDVoICKGn91LWOwOKzgjKoiDbEZkDCeZyx/ncSTLpfELbKrFoteCAgszNn4kgHbsAfLnCLTGQO5UiAOSWmIopfuZSb0v2mTXlqFd273uCrfXYWpdaPa2keZFLbT/r84rBam6VHpU8eJCmboLUkEfSCTO9vcT3lAXfxz2paIRxJoN4DGJvOBDWLYYfOpsuBVRUIbC9r6QRD5Xsy9df9YZB+/Vu+4VOqz1q+XQ9ZBlf94fd9guj559dZxEkubd+b33gDdburdPhq/cG9zLYr9wbDF/F0ODZdTbmQ7QxzwkjS8LIvXuEkVcJI79BRsaBxJBcIoxsEvYceQ4iGGlAyhT+xPBHkhFwhiF5rsg0pmzGh+R9ekc40LvCZ4oUc8omfGhjnyEjNuXrrw5bql+X2x+53x4tuuz8mfzZdbaDXa6Jo17nefrsOtvji9eC/UD5hPHXuow4nwRvoG0/OckRX+xIOYNIdTtnrcum6ns7me2IFAFhJDA7JiU2mOnw1EJ1Hg2GbKqaLR57F85fOOPMzH3nLqRoNoF4NKUB8ZRpxlzOEmbCi4NGaCVLe/aOLo7SPDxhK2+rXCtRq3OeC3s2tY0gt6y95nPzNHpu5TowwwN20jJX56je64nidtCAUJZx3KHDdu6SKL0NPiAD3Niysd1UZLQ/HnZHHP44ioJ769tAWKqGfS74WC0smbolzvf1w7psLW42e8r1v31y3DjTQYnikEdqx76PWQ/tXT7LffYd1rNfYVSHsIk/HG6MBp7L4gDisjg52NKj4qRyFA/+cWCQ851yCXFLXWiNFT6gfcADtx8Hqne73DvgB8PuqLIs9cuLwC4DlOmKDwx+0CnPcnmwXO6bezivAksZvvr+e+uj1vv17zpVdV3jZH2dcF6U1GUbtL92bbk8aDa3hwej5dJz6tmg5XVnrYs1rkHKZtNT2daOhgcjWmz2brI77D5v99hl3u1fvmTcC/cvt1oUycq7wvctUU2Gl0eo9WkDDdxfLq9cug+f9/kVJYqpLHe4ih/slzcK7yfUXwGx+1jiTegILvlddocq/OHnnVaPOstnjQ/Nm5S6fZi5fUBMXumvdmV2QldyBcOvfTN6zppdtPS+29L71FBzmokPJpn0aGUpL30tl0RJGLc5GaLS0o0ddkfNJhmtwktfunHtHmrq1m5TM653y7mMHu5eZ52yW9y7zLvsrulZ//KlWwWyrvO7w8tY3PVmc+26ptSpQzOvwbx5mXfZDX7d4PrlSzf+f/bevb1tG2kc/SoS3x4tUcGKlG7bLRVEx0mc1tvcaidp92W5fmgJsthQoEJCvsTS+eznweDOi+3u7nl/5znn94ctEsR1MBjMDGYG0zfDITp2xa036Onk8fezP4YkuA6iP4bkOH4jO/qHU62o8ivy3sD0EOEX5vVQzP5roruxQtPXg0H4leSWX4Pa48Voy6pVtuTh6/hxgkSCVhKHlyR4FAxfWJ3H8LI+J1/Zj9Pzkqaf9vt9G4yfPv7225lfNAiiO+bXpxD4ZLcL/dzlSHHdfjqSVPilrE1whYKKD81bFAT4SwsqWfz8MnxpaezQZsUnmv519FiTStyKZI+R2CP6hFwCcirgXso4dP11/CkB9BO49Y5szSp0kesZ2SrkghVpl+MzhQgfSMuR5TM0/UAIeTYYhB+IirvzDKmlB4j9TClhPqA9UO/PTtVii5IE4LMZvmCkDeH87C7iMf6sJuBXt45ZgEyvf/U3J1PPr8jdTWwyEDDdtPzobV+QhPxO/Pqg3epS5zAb6CXCN/GnZDDwZnAw6HvZGsXgunwvabdzmka3GhvNV0W7PhInm0VD2OhfDj/u3d0fdnx4MoHrxNseN/l0V6QTzShEFTsANAJBbol7qu4ecLtn6d8cPspwEAUI0yERO9D00hy2mA1b1IlZc4i4JAZf4D0j/QlOibvaZhmhQ/MW1eAeiq9yj/HXlMGsKEA+WYmCOBh6KcMgMdNTlOASOyQeTUAu6nncroNhg4F7NOh8sPQyJeeOTaqLnQC2yp/tFE7IhilMiZ7pwSCIZBhOhf8HEyTVqzALsgLJoux2YZ/vdjcxT9Bg0AcudhZmwPcMwwxc0TEbDCTVYfacCXSNgvgwhKJstxNlAnmYDcc4pZe1JMF/BcMSorvKE73K+14RMYoKYT7MhiEjzDGQmP1Xh3VEu2nFHiE0DCtSOaG8Axz8H4+/CRAalj6qN8VsaxkhoOQLyFZyRmb9tNbXEMDl2Z4njyg9uBR0uJFwZP2YEr63xxmQCZekjjxIadFKTelTTeUrUsZpMmVxlQDCxFUiA1IC3aXwg1WUeUEUTDgapY+w9IFJ1xOFL4NBn5o1a/mR3DchR3hOxtP5k1z3a677tSV5PE+mga5CoMIWbpvaJoTG28SoS29keHPIlQwGzKWkzCWjTGlUaqS0ZSRwIaipdDCwz4DbdlhiM72J7efEjnRTH+mCjKcLy/Eu9EiXZBMvxAwsxcCWyb4bwnJmbHRR86iiS+x2F15nnKFS8yjtHHQ3VySkHh11L9yYrgy56YeyCbIaSQYOoSma6mb1xyDQgS5kdSF1OTCE4dR+BSzJyrCC4oNu6Mnj+hdnDCvF/j0KVNBUtdlS9YCZ2m+p/MUSF4jupdg4pGRC4QdbXCFur+WzaLkoRWnx4/Rjt2NmrxUgXBPm70TnhLm7rMK79fDcTq1ROFr6apZOK0ZKYd/F5wAETpviHO1fmyHTRgHaVuCKXO92l2JgohggvMqEP5ErfOQ17DRpUQW8297KUxyblXZmZc7y6ntLGJi3tzL+kcUdPRvST1V1MwTCdBSPk5n4R2R6dGQQSCZA0AiFn9hd1y56SkdPpxHqNSKQdib+KdBGFkupbkQtArBdwlfkyi2rruoQ3UQIX6MGakoKK5gU1QDTWNiKo04BkTCzj5Etge9fIkdkZey99CJER7tdeATRMo5Gm2ITInxEjrTycoXur9ZUCbq1N9s8f1t+YAtl4KNLmeBRtdlWsDnSlAaHJ6TfD/Wsy1/Llf2fAXoqmAOVbk/kgfeQC/7E1KUqd5oz39ADRob1gEK7DJDk4lSqGhtcwgsL38k5s4/yulKdfaYfIhXjpHV37R/pGTKEZOOdGzjVQdPAd+ma9f6nVlCjAb0lnArIg2xzMEHxOMFnRMFek8bd7sjYNwggByOBjae7XTCST0gh6CkWEuZzorNPnz8l4+nzgwMki4Sn5Ch+nqDZkT4MfY4nKNLVzEIvHQvZNDocDOrJBwcyqNfVYND/BILt9PDgYHqILCUQVaJp/8pZh7vdkdTcPNIpliKKEbq70JnmbI/sHuQxzUfG3EzqifB78qCGpncugfezIIg08GZmQURB8D+4JsIrcmW3BoOCg0H/vXh1wWS66iCmA7EobCKswUn0P7W0HA5ADEtxAn96R8aNw4WfBBDbpWEg5ZxUxkIONhYQvkJOuNgVjKAvdiDumuYJym/UykbFo2/TkReY1XRFFO33+PG348cPc69R4kbLCXAzKuAea4G1LXsjsKGNaigKiolsO2dmKvaazuNsF93Z6X6/x9/98Ldxu4UeYeF330z+inBB4iBdLAIcLApGAxzw4u+nAQ6WZbE+UpEoISEvUsiVVZsCfKgk4gQ4+LUoP9EySKatLgxyoiEYJOQLP5y8Gs1LmnIl4X04eeV4yPzl0df93sui7AkSxsRGaZ20epucpmKWKO39bXG+ePy3v377/XL5w99+OP/rt9/9LR1dQQujP6rRq+PnR29Oj0b8mve+fvQ76zd6dPvNN9/5sFEW7Axn03r2Chc4xVuc4zle4QVe4g2+wWt8ga/xJb7Cv+BP+BQf4Vf4HT7H7/FbfIxPWkxjxThPRs+2Wb6gpfVz3GQbmmeMQhjKEzijWtMSn4wqXmx+LcrFS7CuhgQqPoF/LMD/nV/UfKfacACcis9FiyHaT09sQODHo29GPwT4ZLTlWQ5OW+oRfEhJKJUk2B1ENVJupr6/ac37lKI9MnWlavl0+SkQQgUdp24YYFMY/KPqGgBVyh52GoM/LVVK7Aol4SzrsiYj4ymz0j7TsmZGypgluCI0zkC1WwtEjhCPs4RUav+319I1gipXg4F2Y/DStBuDTWw/UIVh61gmC0o3vZQteouCyhQVcLPHaMXpQkW4rQI0lf3b2xsL8cnoZUbzxQldkjqqA01cFHPxTfkaLEXeNzJECSScyZFJ55fSrQ72LVoKJspNFVSjZb7l7FhlYaMepZQmhHAJkmCd5mLd00UPetUr6VJ7Z6vTbWqUzFxMqn7lw4m9ZhuWm24rZLjEFHnDsLuUxr8WKxyJcQ2I6I3Fg5IPyGFjpEMH7qgJZdG5U9rQekE+mtM1ZbxqRXPtDCGx2lq72sUxnvInTpYpHw6RV29MY54kpD+WIS3d6saqXxC5IKecktuMcVpW7Tud2Ai3LGv1suSgKp8XjKcZa/Fn7I/3ujG63vCb1pZqtdXa8vpxR0sT05JFA529hV71+zVwJc3ipq9N/MclZsYvihJCfIi6BgZ+DgCDJXfOvDzR0zwLldtFSSiKQk6oUvmLleEpPE33kUGNioyn1RNtlT2tNEEsCIurZArxbkpTzniPFEbLKJfZKeVhhpoggclpdeprwGDmv0Y1GMD5QmRbaxwDmLFpedyPyWE+I+hmtljWzLsuHZtlYAXklXTBGRCuoE/YYBCWQ39HiVliTEeUZUvID8rh6Fv0KIQfTY7AYD8vLsLJEB7T8yrMZF/eF58oq/VGHjHwkkjNGbyuKU8XKU+lp7Yp+TA6pitsK7bdLFLercOHboT60e+LPv5qVtrcv83U092ufb3K6YWawrtbtK+ibS5KZF9oWYOi5Rj07Qt6qcUtuzw1ehfa5Rvbc3tYZ3NCiurn5S4vE3Lw5zEIVhKX8amVZEQzKdK7viJjXMBaJcyu0pRUB4UYiDksqpCyMnCAMqroJgWfNbTbVYRI66706VifKNS7KdBruh1tigrCX5K4wGmCt3ILJ5npmAoJ64CkVBtxgSuEtwjtC1INJ4YrybzJsv0ij+Lff69+//0gGT7CJyPN17porHfLdP6JxEB8Dfdb0ous4rSki5cqf/s22VJEF6ivPoiWKM+vGnUPBi6vHIJv0FWZ8Yxd9Oh1VsGDLdfTVUe9YAhx+/L0nOaE3zOEWGVMCPVGKxo9Xupsbwp+Ysp6q00VHwzUw11D2u38IekPmg91RnOV8VXPyCy99yu4XeGmN0+FDL0pi/Ocrqve1YqyXkXLLM2zSgCEr4Q4t6DXo99/Z4Fixcyg/OABNZFJ5zL+Lt1eeCW5D6jSdqd0mG/FeD+Xl2uInvS2rGP+KJpykLZKcM3j3iAs7UsXi6YYLImNzQQrRUpqaXmxVRtzx+AehgAQmskuFOWUYrxYu3q75A3K+cD2OFIMuduqvV9Qc/bd4F5mbGFWzUsWoGk5JBNvEEqjWWLB7HcM4Zwui7Ju7P2/bgx/tvslXReXXe60LV06mPQJV/YxfjMcTzob2fqcmJUO3HoUbZceUHxaiq3GnqM7OeMyMVvTtDLcqMdChjSuElxhCUWp7yrcKAB1Z3Jj+yeP5Qv3WF6znnGaaFd8w4xSku0tG9E1/IZ0avk+j/PA1idPUswtC+My6YyY0fM0GKh7livKH7inuTzd30/fvuni6NSsdXXsgUuAmm1J9f4jndcjRcjm1ukFy/h2QckYe2y3YLHkGGRZVwes+IiXRQk2s3UBd6zka11V7Sxn7Mqx2pqplvfRY8ExHXCcOZ6xIXv0GOHKLxA//jpLpgz8T6snIMeTDOHqKQUrG/HYJxRNka6PDx9Uo+psBbxm9ZTOHn+dRdUT8RtmwwmKpLNPK4AyVtGy7m4CbWw34guobUIPccriKliYUMFSRPHmzmPvG9UbJZA7oVNnjdfnDFTz3qhZYmOdmLThJCFl2EzEJv6JnjdFrxgey7DKbR23fXPGrjUitueeeb5NNmgDuNqKNrgkE0XmyGOlAa5NbplM6ZCwr9m+vRWJb9XnEkyn2kaxKHgH3W1gM6iyzEtmZYCKaBEdPJpTMsZbMsY5GU+3T7LBIH9STVFYkDLeJuhJmBIW5wmabYfkcVQ8TWc5PMjYAHwosg0nydcszsXciFxY5LBUr3UgVbbO8rTM+E2nqLgoBBgewbMBUYh2u3bE5wUQfnd67aQJkiz3hfYVjzAnE9iolG6rlmPKxbjEBgZXQ/nTys2KpR09u4vq6mr2VitPwoLcqnByUZByGmD9wiFQHGXzLAoom9MAp/CcwrOQhKIg+0IDfJ5nUXCeiwy5eExzUYznUI4HmMJTgIttJZ6KbSWKQ6OqBvUMzQvBSj/mWbWW9WWXlNGqioLskgZ4uc3lG8S3K7aVfIOa0zzjmS4Ej1DkPJPp0M+8uMiiIC8ugj1OyS1QoyjI5tCTSxoFUM0XqqqZy2rm4lFARjwtt7nIJhsO9nhLgjilWbG9SQKckyD+J7wl6vcm+TrAc7lf04uj600Y/DNs5kEzXYn8Tb5uqQfh1X+kovtzBAgv/iNNhfUsaPZVgPDyT1QeILwhj/4JN5OGVbXLEK2+eoRvTFr8zypBFfjPqSRKF189whcmB13sMnaBvnqEr8mj0VeP8CV5FKZ8d57vsi8i+crrj+7OTV59SdDvv//++0R0+he/08EwH26Her6vrm8SkemTalSPCN189Qifmp6oFbdTP2KR7cTq2olltTvPs51YSjtYRTuaZztYOzu1anb6f1HuYI3s1PLYqYWxU0tiB4thB+tgJ1fATuC+GOuR6Qyg/w4wfwdovwOM3wlkFzXuRFWiyCvb/1x0l4qO0x0td9l8l57ndJeJfynjOyA0O/gn/ortTnRTtCNqLraV6LIYraj3nZ3XHUdhVjCRem6m8atH+D15lOdfPcJvHwL84y5NNq7wFufSsFWpo7+xWupsGQY3ASEQZsEc0INHe0gJ84OuDal7pF+RGxxmZIOMH7UbDCTDwVeTrx4HKKr0d6jS5qh0DrhSWVS1NlVp36DMGBuEGZmrz8fxBEwNMnKNa03qsEw9t1FOwmNrtoDiSYLDiixVbRzu1SdXOCe/iPRL3QnC0YwOSUCDyPqedzQa5e4goRBCeo8OM/IJeUCQXcrcLqFhkAVIQOEU1fvuZcQlOY4fJ9gBCJe18mEBVyOKT0f/eiWprKQi78TnV3Z62+oJM7KqVYD8KW9CfyibrlpKivrO7+l6RRZ4S97i0Gt7t6tsZf2tfrY1V2Qlan/v1O52s31eMSwOZhaDo/f1FwPd41ZhU+rrw2N51t6p1LQmAThQD4EocEEZLVNOTz0Dgxbtg6hysZ27gWA9T/iYJ4Rjukf4dm/jtvjCHR0MeOzKx0mfeIpvQzb2+4bRA+nqbBgHaYCDFJiQID0vtlz8zssCgi+BRkv85jn8XxcVfM+rQvys4V/BLsQvg38L+H8j/pdQJVQjCp1T+Af6TXiiosQ5NHguCsyhCnk3r3gotjkYy9C0BJsZaV8D/6iolWZ8Bb2DUG84oJfy7ZKWorolxApeloXoJcRYDS6g4hXY4KygZ6tUsGLBSv4r5X/4kK3hPzwXV/K/aiETf0sILwX/uOgU5Mw4/BOPf2wBVDlN1S/8zz5R9ZOLPq5T+C/S1tnFSmRRIF7L4mvxnZmRsgL+yUfxvVjCP/mfA0QL+Q/qh5yFKlxs4f+V+F6mKrFKAa4VdKRKb0TXKwCHvAFaPGTAXwcw51UBveUrmCy+gqnlK5lGs1L+ruWPzEJL9bVSvzfwAwDj8n8B/+D/FcyL4JuDq1QGkJZJVxT+QWVXst0r2cTVSqdmYEt1tcpy+V7I/2v4Ec1eZYDJVxmHjGqENzA5N8VW/i+D5H564NkUBf47UAdlgNR6cqcpT7sOzMb1/f33X4ePsH8J5++/DuU1nHUFWUs3tRFUoB6gY6CcO23RoC3htuW+0hrTxYW8zwXesgWxJUdnjF7z4wVuJg3JZN+STCZuoliUNYHVk+cdJaLIrky9hIiKbUQ1CCwlpFKu9D7y7mFrELbMWFatQoT5qCwKvq/34HkuSFHL/AR0kfEXmYwJEWSsR2e1oi+3X77c6MNKuIQb05FbCkW1El5m1OiLU2FNfWVPOX2oYEbiW1YsaFRi0XJ1QtdpxjJ2EXFc8TKi+2Rq7BG0dRaT5vbysp2Ka72IPsKscEFkurUfLuTdNqIpiROzirivcZFEYVXvXS0HqRCeEOK2ORiEBuXG4IazrVahHFJVH1I28hNghLI2eVA6QXvw2Rn3ST0vbJ/B10FtGEiqx72OBl8HiVSJp3cOSOQj6VTqXGuDSrsGld43qIOJHdYeYW+CJuAWYyuT3fkzNTqAapkKNTzbda91MrkLiNsuIG7vB+J22uzLtguC239xvPs6uk8kuud4Xkd3vPJTJmi6aiyA3B/wKonC/M6hrhKSt0E97xpp/sCRzofuWB+LsRojgbJBZVqsCruILi4JVyHdDMFlTzJr6VnJGNUFYYRkB5OpDudcIa4GXQmmlqsRFm70Y7+pqV4xBXaKppiTtGMsD1R8xgnmJL7dwAW8oBsToBXb2T6Zcp80loQrTyTf1qt0kR1nRn08LZ0FMxiE5Ug242ASlROqv6C6sVjWsBLjCgVUj22d0hCrQHIEpU9bxZy7OthWMDXtmYz+v+Ilqh2FlY7O37IGs2ASRME4wLzh/6sANKqKkodIII9WsytLYddEmMcsmVJCh9nQlo2zZJQt7htIu2ngHUgsT4tgs/z8RgCP4mLLN1secQ8dnJ2yNLukrjeroQTUpHGisoY8xR2okxJ9CIu3cNpQTbfDIbJ+y1m8TZS3cmrdlFekiOdga7EiJN/tYI3l8tuClD6RwUvidS7OE7whC42kS/mAbxRUJGUrRxIgiraFN8RPiVcJUgv0Rv7udpsoDG9qwNaZNrhRntxY8iZnYaln4UbOwsIlXD6rpri/Bre6KellVmwrwXabcBiC0asjgTwAZPMVnX+iC9E8XBYpz1Yylq2zLzrZsQZ0mr7rhNFo88gYtHhPGn1rmju83cLl/EW5oGXvqigXPVltVrDAIp1cONRsFqxZtflG4RSx8V2sM7HuyuEQqvWGHJYIc6LPjH34qIpnBqZRS6a4u+DBJBnNV1m+wIyUzihcKlCbJbmfTJ0dIGubOU0h0xJu1cKC3EYVhsaibC+GlO252VZxE1XoPVMsxYYGuhmwjdE9FeicdxmJdEBtyp8SOuUHB2ZTagN7AlaNMGRH/zNlxjLNx+oZRK2jTINW8jbqIM/PGrMkCnXVYh8grG2dwFXLMhdqnyRBPmEtNQ0VpDgJ12zRhfxM/XfHkUKeJ1aEeq8yA9dyLDWPTklTRuXWpnaEmkfTP/dsVnrndp3Lgouuf2GbxONfxId3aVnREuQ2FUZDC+n1ZqTL7117GFQYOuNxvHA8a0zWmpq1prbbcxatqdJyyOmAXsPpcIhY7HyI0yRRvZYTJONVO85Tqq7RHERuryZpOotzYr7GqdgHHZP16Zbko21FtaZj5k2oNUgKcymK38puRbnq3x5FsfyUTG1YivF09cQEplrpnizINl4lU5mdLMCUY0laNQdhjvCGeKho+ZNwiTRzKsXtMSFkYwh2LmhSRdlcWufDZJuk0cnRLx+OT45eWKy4IePpzZO8NhM3wyGq4pdEp8c3SeIBTsYw05WsyXi6tgFC1nrMF2QTrxN8TZpLM75I8CW5HknjfRX/uasrUNkVua71CP/isUVXCH8iF8PgUTB8iU8V3pxSHv4CcHIh0wkYiPg8l14R4SmyAYCr+GUyGITip+4agrCtut+s+t3J25+Onx2/F1DPliGLXybaaugS56Pzoqg47tDfD/keIdzP4k9OfJYjMp4ePflFA+hIA+gVfkd+iY8SfK7Gblyr3uGXCL8nV/G7ZGpDGr8iZXyeoJn4r0q8Tvl89SLlaXiBX+L3KHoFtrTyZS+6QfrjvTxrMxUVEjSFBY30icGQUsB4FTz3+31tJu7A0btxooGeYmqcZTJHEHnkbW228LGHx6KNO+kRQPblVLRWI0wQTvKt06LoAJKjHgzCY3Kshl1AOvTmuc/HI/xGMIx/tJFJgbJ8lFVv6EXK6SKUlpfPmwKSu39pgvjcG8I5eR6nCVCcM9LqDxieo2kbGuwtfJ43oPKChF3VifYQUo50EBXFuG6FLxBEfHTeZXWH+BlpDCg+S/AXwuIz67WXOGZO4TMZOhZQsU9IeEj+iF8kCB2OqnlR0iH5gg+lv4UYjsCC84zRsIzPEufapI/ktqTL6AWGQtEXbEpEIud+KiolH/EbySR+dESKN1IybV+/XPbigMrfji27ackk5ePGTHsEVIvEXZalsb6iyqO6NEnsjUn34NJ9NXvzBPcyiXGEyLSgrxHSEeONezNW+6izorBbW8Sx1+2IYr0pR/4Wrdu0LGGXp8LtHpfiH6uzfF0MTZ13LLpOD1JS85MILSeIplQPWmwN6rHuoKKuK+6tswowTzpniKoydmGcNOhC+Wf0nm9LwXb3VHVC5su3rOz9/pdgaBoZBr//xboly3pVVV90VVCCuiUcOVFqE4z+YqvXfU7CFWHxNoEQK3OyiifJtIxzn1UTBHgJVxmATqJRywovRD2Vrmcp6yn0mcsC4SxeJGSpV1rhnrs0OHGfqy8xr0kCGeaWry9A9MTWtZ+kyrNNmtJKa9cu/cAZ3L2fLZRm4Ez1pQ2LZIZFMd92+wa3iC2d2aCp97Rcv4R74tk8c07S4OMrALNNtI53jl9XTXBhnhOP/OjHL2jNoof1vNgyrq3Nz87J6Ptv1fOnCZmMHquO0HItR6dyav/AX1cZp3lWcWVh35R7S89B3p0F2l4AIFE77sqWEIHcXJfpaE+cW5cC2M3ksoAFpLepXqauiBIibjrnVKy2R7BeXCyIaWKdP5sdO28ZxzmhT8azcUSfTmaTqGNEnyYtJT9NugDguTc5ThQqsLOAXVL3PXZGocdkEBfMc+H24ebMD8nE0WeOp5klGZnV6bM4S3BBPFhVyYhecwHNQlDRYlbA3R5xleAt8bE3TI3wFVdig8mJvxGUWxZukbY7taxviSuEV60MVueKiucJWTXXlEgetyYPiQkDqSEhYyaaZCdmYh4vkqnxe13FS8Etih8yRlj8DskEO0EN/A18mch6Nq1D2ih5ivhLrrYC3RmTDDZzOetNzICh7oRZvUdks7+jv3GVxGWiwzG0f21ry25EUrxsJxotMmd7RimILs2H+CKZ3tvr+OKejscXCUSbuzuLZBuvBdvYvl7naT7f5imnh5e0TC/oS5eUtx5BtbNuqojg7Zz74YDrud1juTq5uyzb2XcaZwnCBXFiZUxZXCS7XSh+BKKKX4GopUwuVXIJyc01UiUg/6R3kJwl3Lklepg26MeWpHEmmIxtAh4UjwT7IQOopw2IyVgoLUAG5Hrp8gmtoBVUrgO+NUJRO49qV5eJEZVyKPaYrh3uvAl3nLZCE289ZkuTw1ZqVgkmzR1PLijiXPd74RPlIpEqid1uglUgbWcf0MFRnEwbMp5unqymGz1ZKvQSmcebBF+SPL5O8FXbKrtOtPrH6BJYfJ3MwhsC8R/aFt510rIFCXS8TsgNim6gBrwmN1+HCr8+TYYT9PUlemTevw4nB/L5fKh+vw7TRx3oFBcJgoj+66/JQvxb4gvpU1QWW7YIJ/Sbr9fo0YR+Aw74wLxe4Qu0FxsZ2e7txBid81342WlEZbjXNnunZrSNVmERdbAlIqXLleYu2qTvnmguLf+L7nCIPD771pfymv2uSYV1SGINk8iDkBYvO2lNTZr0ed19B5DqJl1SrHyIzzieoCk30QY5CN9UXTEr3pR3ndG6eKwbLl333js18lKpJNg0pHx+9QGyaxCQxVUC1JwIYq3jZUk0NQFM2toxWhYTW8nspbR1B8f1TDFPCPPH6uK/VM50HF64Y6ROrBHlB60HWuqBMsKlA3R7Qbgj1dn/nfTG6Ng9/MndsMZpdxcEbenoRVy0dURM2519keJ22iK0p/E26W4rzpNZezKp9zjOk6gja3uyNjNpqUizRG34UBdixErIlmE/pPY8UqOBZ2dyH1oKRG4gsMBNGemMN6qPaYIaa1CrcO+WeaZVW20xr0Mb0nQo+2ayBmEZVwmKOoqKj050sPrgBJx/aRwPSiotD8iM9UKa50DM1V4lNfRXWb6Yp6V0k1McS/A1WP76GUZv3r45IuNm+qujwxfHb34Em93ap/cnh8evxLfHuH4iQG7fvnt//PbN4atogvXpQPQY24OV6Ju9U8rQk04zXLkNgAEuRHpXGhx/6AgHwOPYbPBKJggHzpmh/ewkgt1doAdnsxgQtoJM7Ao6YdAFvMFAmvpae7B+ozaIDw7njMHXwVCZBt9ZuQa/qd2EUb6rdvkzBCQI9HTZ0ZoJbJzx6AnVTII6vVXRUCCxbUbNaUg74z6eKiuZ2mkwHQ6RNkrTR8E0eeCZnUSZ/kQps/vjto4BNBr6pu7gVa0RZCQPQ8t1SNviUmmt/SqrdDgUCAOlDRnNlBjDDRe4YJTjghVMCkDp1SCyUExGr69lNXHOqiq9oDoyZcXTkuuolJQtHFJji1poEWOxpHO9ote0JZZFTq/p2qFKEOYMq0/MDaSoFJpFpRU0sks6AgZc5vR8lZbvVNCESukabeuuutENw+Lil5c/p9fv6TWf0imiKvga6qwSVlPTUnLpW5TanuuwA5uiUnaOXQPROA7WWKQrV8wSbTWqIakDcuISIcxJOZzY6E3tGXWP9DVA3b0hY0ztncFdQKHrjHdOujLHEhkjChbJsj8WkCHCAKvIARtli0h3c4887NSpnb0xowHtbkP8ahuthdOmqA4m5vakSjmrtDbE6LUn3GnKtCmqp8RBbk0tvGqO3p5OL631rGNPbmbHC4wj+4JpZ2+usgVfdYl+YlQWhp11ZBfMi+1kgiMKwBvI2yjhokt/bnLO0/mn7abRgujfHZBO53O64S+yi4yf+GsaQIj5dFHcchIqYIqJCRFy7xYcoz34fIX86V+/Hwz4k2//hqZ2wzBzoiI9yW6G3Si/rsGpBmw3AmytjqO3pyQ4ensa+Mkvj49evSAB/NQ+vT86eU0C8b/24ejF8fuzF8en7w/fPD8igfday/rs7dvT9ySAn9qndydHp0dQgX6qZcjpNTBSLQxYjxpQYUkHwuaoxCeJWSFq1CxI774l1duGpXurRPEQQUChexoW0EJew3LOrBPswzpy5HhstY/facBH046eebP0UHg8K7y4/v9O+4ACD21XIKvbqp2DsWAwO+Beq0ewM6cm/mRrVMrW7jT0B9OpVtZQtcZByiONVdw1x4LoZsvwh8d9wn3qIJ2XooAQ3lUY1gA4sfxfbjYPER8CnTtxDOr/53+2fkAeqHgoKtY3Mqu6bDvN+jRBaEcXqPLgP14lN2FVu3DojjVcrqXc3GADlGUJ5JdGuDU23/AspWteC1WbWI/qOmnFjkvbDeUjqk9UJddzvLgm41p7zu5RuwfcbRzOP5FbV0Wcrypp2uBldRviR3bJY2inDRPlO3pH6adX0E7XDqd6EfsjTrqrnBes2q5ps1aHBbLNhn53TQM+A9RoRJCEuseu14I3Y1MLCi1Z6Wmuz2yjSQvkFkUy9UdiojFyVF1lArH5SHQX3c7TivZaF0fk47fb7Dsl2U6bpWGzvaOoJGDNcoJq3FFMLKrpgi7Tbc4jKa8G9HpD55wuejLuQC9V1wcU4hEsrHvLYssWvWAoRzuVRhrcdxmVYb4DGen2Ms23FAw2IJe0YcJ123lp3VFirgQFLuTUxtr2YdU6SR5K+vN0ayaq4qWcp+AgiKiPGHdoRazWQdpXA9CD4Z+pQqvHVAU1+G9ZSefFBQNbMl2mV2wo0EcfhlPHPuZ+QErNaDsOE8KUsY1BAYg3TMu1mHlAAT3xrOCrjF0ED5zAqQI561wb/xPY/dDBCQDLngKEO8fI1BiZQtJWLG3y1g9BURUqV/mJWGWniV0rkdfYCzXyddiEBsZiKtgjdU12gHtiJdbQTq54D9dwb1NUVXae0546uesFw/JOBGR1BKwvEaXSjaGRREX+78LPTBuD1afwgWhZ741Gy6wTLf88enX2TYAyuxerGPjdiy5md2FVQ4J6CFLVYQ+KSEmz/Zj5EBUZ0s11b18HEKupVoOnSp8gc6dM+xZZ6i2yfBC83S3fipYN8N9DS+6vpYu0eKLcHUjgMfjNakAiu6O45N/v5xbuH4hhHtzthJHgAzMbumS2egL8gJClRch71nGpNZ5qHUs23O1SO6Z2itgPwViJT1DPMeOS6OHJWIYvqd6kb0JNA8WyW2S8t1BN9dbbivfOaY9t17TM5vcN7x4y5YZ2IeWdZKpPMvSn6Mr9E/u/8fxuPDeU9w5M/xdI74NxvKm/+Y8jN5xp/oeRWp6T/m9s/v8zNls3w4wEGoPN5Zoha9ERnOzRjGnf3hJzTFHEEJwk65srM7SH2jm53U91Db0yVBdnqgggrkdYppU+ma5kKo0zRE5yq9Ki2705SKUxS8IKVzo/LpF92Zcj1rYgBwM6Ojuj1etisc3prDk4OlLTsG+5J406p7iLkOPbNOJ7uLykHNUN+Y0dCtiVoHJUhBwzNBj0xSOFR2WhIq8hfVcKAY/fiG/4lsIST89zGvXH+ILySABij0RTRa0p1SdVm9WYrNLq7RXT9coZgxDxKj797d67otO7u1UMkOHbdLFogUO+x4uC0ZYv8z3mxd9PW76s9ti/DbUlz2KP8yJta3G5x+rO1JaPmz1W9+82v93s90idxJXhN998hzAn6vycPBUr511ZrLOKhqFYMYg8VTZBlDy95eXNbRqWUhlNEdrPQXNJ0W0WwvW3hZcN1m1rvlTkoyMBsxkL6Qh0IShSTY9KWhX5JTUfRnxFWVjhAk3TMCxJqWwQxdwhffy1R2iaU97LMFyrSuLELrRtiG5lfA1qvN8yKWqFAc94TgNkExa0mpfZBha+SC7pMgxKuoQX71JVauIJ0noARGovTZUOeAauAkQVAadK08FcmzCI/ZH3GElVqCR0MMEVuYU+wnWmrljidDTitW8lXUZsP82gn5XT1NxRbkorTrGtWUfur0N0W4WZvtwVef1cPaCw/H5b8aKkUYpBYorCG6kwQ47no1vxIqRi+PfVLVBLcANrQdROYfBw+2q/ovkyLpNmaJlnZfGJMuU1uMyEqA4X/wZougx1KYug+spZqryq0iynix4v5O1NclXJyuDSJm1RUhvNMnzAWFIiRIiipLgKqeMDGiopswb6zQNAL7Aeb0O/4E1YYkbG95dWMRlKQOoQ+cf5cQKrixM7kyr0BydPb00ZDwnVJeiPfv+9Gj5C1nioJE9FYxNozGtlqvFf1CptwNQyCuXqBYNssdPsEQL7rbBEUy6tj5hI3UtKoMbKno4hKjM3t7oyhDCX2iBKnoa3a8rTKI3BWS9RftTW7Rmqo+0Xy8GoBLRxulgcXVLGX2UVp4yWYaDQIsCNe8Q4LgkdLVKewi0cYl/CFSlHa8pXxQIXpBxlCyxwQzS0rqbBybvnASEkGwyqwUCAm8VVgmZ1YqmoZNgk+VyRS4ZTMR6HzIr9MQzeFL1qO1/1ZBcC1KiJottNUfHXclDKuAX6hbNFVOCSVoJPowD9kVxLzYGTWwWViO6nYl7T+ScxOdYqSz9JPn3+iahcmEurLgo/CN/ZGVi5gg2RmNCZWY42CkqaLm6CPTBoIZr+zh49+q9eVWzLOX2dbjYZu/hw8orcczH4Ot38JUEI38rL8OPlNs9XabVKbJ7ABrIuQ4oLhOl+j7/7ZvJX74rZltvOjR8kg3tdbgX0HoRyphgHhIMDTIVNSvEshJpRttBm32Us3pJpMRiEC5pTTnsqCTNJEmdFPEm000ZaVdkFCxV/LTMYiqhLIBQV8TgJ2UiiiQp5r/he7Q6jDJ1hTGEAPwGaZqOMZVwmMr1E+hPcn4itGAz+mVonmI4EQyRwT+bPgCZj3mKzyNEtRBh3loocv/F8cK96Nhu3yZ7hVJtKD4dsWsZVQuIMp2Cr1o2blcY5jmWfozhx/S4KJJEW/vD334+/j9wue+woN2hC9/jbyXjisnp7/M3kh+/9lO8m3/sp0rfOFUaoBgNTlxkaYaTQwkjhCSMZ5CS32SKiwKjSRdSf4BbZhMc0kYM04gzOcOaKKtlI1kD6Y/vh/9NiSz34ZCDvXDfCZu8iL87T/P0qqzT8bcpUsEIauqus2u0ErppI14HzKUChy4K3NHSVsUVxpRuRb/u94CL/fdkKlyPfRDbYMgmphb2y/vRmfV7kg4H8NabA79OLbug28+JbkBeiQKJFsEe4q3BgsSfQxfpjOS9s3WH7tUn5Cqx6qQz1VlIGUr5+AY9aKqXJglgTZ2eafZky/Ot34x8QLsMfHn/3ndh+cGfWURkWYj4WYYFvDzebU2Cvm7h9dbPHJ3RRzNvEyes9Xt0sypS3lXx7vceC3LZ8Orre45JeZlX75etX13usY6U0v15fW5FTwGQEBiZiJBTfntLykpan/CanpytK2xqfp3tsMzyXCsSyJePzrJaR0+u2Cg+9fK9Tll601vcm2+P3K7qmd7TJU5unozmqs7wri8ts0VoNS/f47OzdyfHHw/dHZ2dtc5fusdwjfwQaAANoyVeJfFXLvfS9z9kea5Va8+sy3eOsgloXz4v1pmCUteX7tdjjT/RmWaZr2tZKnu7xtqIw4DbVRHoXqvxU7PFVxlddpbepRiWuUYlLVOL4tntsvy10MUbK8PvHP/wVCeY7/OaHb75FdgdMfcc9wwxYR2lmL457Opnxg0k0Rs5Nf0PE4vJgktiicZlMGyIp267PaWmpL50F8evi/Lekt85YtszoogecU4+VIGQOQ+2kNQt6wZCB9CKJnjmxDlAUBGgYjHovM7aAO5EFD6oqSnnUW3G+qaJHjy4yvtqej+bF+tG6OL/+o4KfR+d5cf5onWbs0Sadf0ovqEqvyvkjqKQa8SqIdE+DIZXGE5XHROQG6G1U3u5eM/sYteWUW9BM/kSGDylHF7NydNFaRMjyM/EvqqBjxnVccql4q98vKHd2qhdKh1KU2ISm8HcLvCD13Q4vSZxMVeqypPQLDZcSw1YCHv4XdYH/mrR1+11ZXN/gC92EE73UAPUmRLfr3S4NA8gMYZHSyzTL4ZIaR9I/txyS8ftxN59sGfaNoSUXjJbnzWvvit4DBC9d/sSZ5GvXI00lOths+3MlMmrjIvVV2RdVMMogki+wk6sXtTrUeUF/rMIo9Se23k/OrizPZARH2OBqnJ4cGcgIvrb/yTo19SeKMFjseKenWV6J7DREiNjw5ZMQxOE4i5fbOS9KNJNoGrmTiAghF7Ybb+0EyUqoLkTdqrTLVp8PBmHwo7ynqDDXmAj5TUrEu13XVyEL5enNGyEv2/ZPQc3I0O0GHjzudIKvyoxrTnVesGV2sTWcq+SQ2N6p7OyBlQADQPy/TR5S2aEr5QZZJahMMKT27hKz9mKWCMw1qGlR4RNcjdUfEwKRk/e29ucuG9fLmDzlKpa91+nG5jrpynVKOSyI98RQolZaIjnSCr9rXekndJnTOR8M1MOouGI/05tqVnuP3s9aBtfaoJjeKqRIe9ne1StQxEfd1dj1fVxbXgKeM/EQNZfYLAiGNHJW2h+emLDolgsEQN/cR5Or3c6Fhd35ZfXvxNib8j1Dt3BKtgX5TF6nb4f3qibYSTc11x9NnUTDmVw5snhN3Jfdrj/B5cjFbYGXASB3kLFeCZcg6HUAnrVd0kg5+kRvcIkclP1Kry69AgaDV6FzezfmCDNIw0wIHabgC7MFhy/8LdCHpWV0JlP+pM7sTLmNR2C5GW7DBZdCHmboQXIgwyUYS8VlQhjo2/Uq26OODcgM57WcLWfkNdd4p3G4YcIzwlYElVBMR2dn8O3sjHBb/UslEptjX+rGV6NLWlI21zHWRCd7q7Rif+G9cwqnChnXIQ4PetV2Q8sQeTnE+OkiQPZOYNP0FzkytZ3w3Y4/1W6h8ipB8+ZGwMely4UigbrSh1IgPASMVy2VtqVnDnEFJaClTsSXwHc7tS/FSrrOuNxdklbHYLEZ1vQD2VIrGdQWb2mF5jzkwP1t13FJVpunIhVIae7/hg8mGorBW02GCBsMvJkeDOBqUCdF6YyD1+kGCux2wSmVZWdyPMuyWIcURcGhxj+V8dE/w1n0IdsdI8bDWfS33eS73TePUTiLnufpekMXSNbwlQrOx9BMjk1fyb4XRHe344OB4E8afL+e31t1Y6O2Fxy38G56Vp8atJjdwplzf7yP1NNE7aw0LofDZL/fW1R+f7PRWHzMLtM8W/RSzul6w3u86MlZpj1WsAN4Ps/tBjj6nR0zdTcDL3rntKezYCiQChD05M5QSYucVXpJe2mvgUQhUocMo0DTADFdLfnkse7oPGOLkMnN4gOR2cJACCYHcHS2OIDLEeGy3SpweObPza1TaasdNbAgr7+KH0zRHmGXU/pVk1+xn31Au51gnT7gF+HtHtP4Q4JQ+wWatjsC4meEkP/eh9IYJP6g48hcQuhedzS9dCFkv4qXUDZA+CeX+TbdorALGloFaBMc8mIdKF8Ogexn+o4XSMmqd5QtMnbxgRXnFS0voYUzc6tdVj2jGbt4C9/own6QuWlZncnAGfoygUW2XH4UeHam/dTztOKH8zmtKrp4dmOTiytacVVxecpTTs/Ir3T05u37s/cnh89/Pn7z45lqiz17+8rrdsGefaglybHR/aX2O9E0w3KJop6GoxFUrjxd4bk9jIGeQ3VFAZddaKvtg1vdhwfXV9JNUWp4tIWt0kGWbObnq5Rd+Hk3PER4pcMxLXgI2dvuM9JQMbDbY7oPEf4HOQwl0uCfnCXzi0Z5g18ctqFLJ5o8A/p6qQmVwIufHBmJ9wm5HAz+4OE7aQllNhqEmfx2zMNScCwlTOOP5DZbUMYzfhP5+4iGnujGHktivi3TvD3bP5hSNjeUQC1K66xSmatVmufF1V1V4gnaO7zjbzWu7Fd5kXRU3xhnz+kolc/qTJDtUXSkvkhaGVIFVyfHc5VjnW68kicqvaLcS7fytxEz6G53wmFv/qw6J6TO2TPxEj3nIfPo3M8upsKU/DcJiktaltmCBnbgf3dhc1ujchHFBVihVGcRx+v0k0iimF5zyhZnEacOX0upBCEu1WmT9WYIVZhVXZeRqIvRebFlC+TLJJBXtaHq7E/QbBzB1WsleGjytLyg/OyhJR+Lkic8ZMrwSJeb6OMu6DxEPpNlNOJvQoHtGcKP7Uh5faR+ccsS1uSBs5DjQggDpiZmasKFMhjEKa5wjud4a2MQFoNBWJCcj6p0SR0ZCuEtBJauzRreylHC2DZ4QUr1rjdmOSkZ4c0ZydSMDAbhgizUNg2amHAjKfP1zRmabSI7BUgfs7ymOmuqtCBh1daGJFpolkbMjQ2zwKp0rkvP20rPR+mWF4cAQDQY5KimhSh2Oyr2xjzNmKQLZ7hLg1E4+FvSP7sSCrsSMnclFG0r4V9H24cuosGgLwiDbiPmCRoM7mxBdwPu8/rcvTpSg95jKHjfAsnqAMD1Oh44pLtWUuatpNRZSTiTzaZ2BWVws3rbCkpbV1DqrKAK57UV1BMLMie5tzwqZ3lUbcvjGQ8byJr9CWTNHBSr/jSy5hZZ5y6y5rS2892Hk466du7Ms4aMvkarDtFidEE51hP5vFhvtpwu3AkFFtzDB3x7QXnEoGQFTxXle4RLyaYUtifbPw2PjYXHwoXH5t+Ax6KJ954DeB0mGhqScxSz7MJDrUZNFQti6XbroslGlK2EXFeiWRH9JpaH6MSSkhV1Tx1W1LIGDUgFvNzSwIKLKnCtLbguXHCtm0MWOxjs/WLeNCk5FqzPJ3pmcsscFVXqi5y8pqGrYMfyo1F6uORzppWXLWTh1l9gzSXfsuIEbuV7ILhRKAnabV21rfLgx3DFbtl3ujMYtJyWaFqqOVRDXGeGoFcdE1nBDvcsYwvB3UlSGD3jqAbByFSUdlSUOhU91xU9b1QEi2mOt6Q/IYTcv90sKN0A01rSZfRcE8VuGAjR4j7UNR0VmWUxon49Kjt3qOzco7Lb2qgsjl604ag5/RFYOjumtbVdIkltZv9JHGtH8T3M5UPA1z0lDwVf6oAv9cAXepPfPVG1yUcNuEmqc0PJrcgqlg4INUoiUmLcCzovQCOk06FTUX/siGTn1BVhdrsbuvePX2+oRN1LSrY0DApDRQOEr+tpor8BvtUkMvp5j/BVI5MSHN2MrgzZ2BbobvcHA5nsQv4cyZ8z9mDxEUswTe4XI52creKk871VrHS+azUmwp+aMACRvAsEdcl8xiMq6jmi5HN4SZ195q0zf/LsDpBn9lvUn9i3nyNQiNfxQrGufRIyve+VbdJA6Wx6LPpNmpAIPHTORs2Oni3D/lXIDX+rhfwG3EXuO+eO16eA12HOUcuhmh4UoTMaPaej8+Iask6lVvKSor2v0zyl+Ehh+RnFhxQ/p2QuUm/Pi+vavEi1+zkN7a7J6FXvsxj+WxoyQW8EImCxJEf08zbNK7THMKR7q5LkIefgCF8W1xmtdjtIY5KgzD6wqGKo1hba43W6ubd26Ogn1ixc0brGp6PwaUthCf6uBewnW1n+TcgRzsh7Bo4r8cdkuuEhAqvMd2HRdipJ0W3mkMEipgnus91OxYVmaLdjMU2k80bG0jy/uQX1nqZt+27o6nglGt8VtNHsPRPsMkNt4MHa0KB3I3YZuY5KsZRCKgfGkRgZMntBqSs+0y5N1wLNf+FoL5vBUrEmiP7n8Joio2L7HF5RJCnLEVXqvOhz+AkU7yeUBHPF6gf4PSUVDU8owu/gyXxySA5gZfTjyOoF9wgf0+ZZlLeOYQ7fU2Aqj5y4tp9DaBBTpE+ljkIgWfakGfZ/QhXW7HYhc10SdrtAxe75SeCWMQBSy/OYilbxsSaa5HP4Ti3XPyh+Q8kYv6Jkgr+iRM3CGdXk7JCSrefUsUc4EG0GyFC3Q+odQ6PB4IziF5Roc9hUcgwNOwzXRsMTJ53t9bXDFVnVhdUuvwSnGsxxudvx2iGuylLTHvcnCBcjMPG4lvoZ0h/jrwQD80J5/BHacVReqLHjFxQh7Eh2L5sqMtK1dHM+4mU6/5Sxixe0zOSBCM5In+92/UKuY1AMiJyAvnB2IXXx1TQbDEK4ESIlX2jYHyukqchtuWWHlRzSWZThTUkvbQNnUQEph/UKz6K09uGEpovqLGJc1I5ZwbPlzenm5kzME7gwv8/W9CwaYzmxx4uz6BUdDrG81PrQJL6xhu5vKKlGJjuu9uFYbCiOETlTJ/ECgNZaXJ4gZtKV44xQTA1t6ruU7Q0FUce0MBik4TdjJJAb4r+5/XIuZFD1Dgah4I63m01Jq+qEymrgvLICw4lnVIblboEewiVvfJQQlMcjGCIjm4kZDLjO70wOwnd0YLIHbxKDbF+oNUZpRREF0rZvhGLH/OAZ1NSeb/8HJcbG/V2ZrTOeXUpd0weKP9fum9A18rCh3qovQzBMIYFVJ8BpXuAc80hNsgB8TTX2o+bAEAYhQTq9i2VfIrn+keG09Nld6h9KpoqnsO+rtPrA5HkXXcjhwylkKu+onVMQlpwK5pBHuz65Xy7luaR5X9B6X0zvmOlYafuU2TpYyDVjXSKc7l+HHFO9P/Dm4SPTjQE02xwIDNqD0KS7NvPe4CK5vRT5vDogl+wa1oF/NyUVS+sNvZLnsWJL6wOD8OHN858O3/x49EKdU1aUu7lEA/XCXmvZMvxRHTFqRP9Z+Y3eKn5JnmPcbGhUMrH1fZSmB3vYXa2ZqduZKSV8pLMatkbpzJgGAHaHys3hpQ7eDRMVunkomrmtGPi1D02Oxik/dZ51mHbv9DVE+L8VMAYDyhQY9NBdcFgw4CJfyEe+B3Bf+Dcjufo+/1xYR8N0sckdLtRmFsZZG6L9pqZKTrQ6xz9rd+ThgwENb61c93PGFpEyYsMLer69kDvxGyEb2tnAd2KBOzsGEEqYRPjvXvfK9KoLMLIGkal51bCb74LCKTh72Cn4MIiDoVP/MEiCvVajvl22lD0ObTOinfgPmtzZ57dLOJXfhz+h6YdOKv4rxR8p/ol2W3ooRNhQtpB3ot1tRAGTmLGLM3PzAKNXb22qYCnvMfq4z1rk4UYh5Vbs9f+iiciHd2fv3569OHx/pMa2ZaCWfEE3FdycZmrQ1Jpe9X7xrm9qWsLwMru4oKXsgPshq+RBAwDJQuJky1jGLk4p57S0HxaGa/AqqVQ2v+L3ZTqHaj9SuCpF5Z0Xm1rnJF3z00r6eZuV1PAj/tdPlG4O8+yyVtF9pjRU4PFul4bfTFBjQPDRhZ+Rb/RRjOQVMOgvdGR8PfTXNPTzHcgvKjtC/lCpepI+dMVabEenRqDb7bS4NHPlvMhhQVxYggjE6TXvAl2/TxupDUCKTOb1HkMjOi/W9JSnuUta5f5Cp2qLRu0YTmo4DpEEu9bCu7enp8fPXv3j7PT94aujM0ydRdiuZqBtNKO1zXba0tKiN1wZFUTbSP2/1+CqtufqCyvc5Q5yymMH4+tLAuGxZKky9kwIRbud4eCcaaiyL1Tyvw42QYvm4rzfqMtPUVcKVb6D01r5waBPpWRUyyhRSxO1dP7pkC3UuguRjBHRjXx9QAQ5sxB+oQvv1OTzfwPdaog060I4+Tl6KN5299nJBygKYl0denQvY3/pGdFk7Cot2eF5seUfGBShCyFGnoUIg80d5FHbDTwrvZTiqvsTKW4irVz2eEzBUNOQmdu7R3MIyq1lB4GtdY5fo6uirmo11LclQOBvHARGXdvXGKR9t0orvikqCqZhSrzvqGWigJeG3/zVbRWMEH1cbFBFFyL62qCuGff5G9YKcXC+5LvdjxROUwDAu12fO5sMuEeY02E905ppQLgU/faqbUpdPnswNvP7hYpJn4LFOyc/S2yq0w93k0JTAJ2Qj8ZSkbvIKsF0g6LhmWBw0jKjFTKw0bU0ZkpVBTN6f2ZHn6M5JWrUc89AHd4y0gnmgJfbSkzRWYMwW0q124X/rRaTt0wkyyFpe7sUosRp0CCQ/hgXqkzDAt5TWxuthLRQVQ6WBc5Iy2mQcwgkDcpYFBxueVFuWSAvYKjmK7rY5rTc7fhoQfP0RqlO2oQrarPPnGcgXnl6Y323rIxVUdDYFVseStsW0cI+es/3IUe4Iv3JVMYIW/Mww66yV/BGlYBL6umARRHQob6QMeAWZ7tdIZdfmMu9GcF+Km8r44bxsTofFf+wo11uthao7766fAdgGhYGuQoDIUFHwbpH9bk8C9HeG5XU2jIpZ4EWQUyIngpIbBFV7cFBXVplekf3JXVHTs2sdFqIUfIwRfsSgEsyxUR07AruaniwAbYVPZ3Vak/6pSTKHy6J8vjDgyRRafZNyWFY5+N/omjqKXJpXKO95GCSkMBLCrDI5ey1ZJyQwHmXGWq7PxH11NJkRvX9cUIClbwPf6W7XfgrJbf7mquF7OCbI2hTPMg6Xr39ERp49fZHmfDs5OjwZ6gTnoJ9+FFU+VFWCQTjF9ok9rAve+KTTKHOmciPnsmB6yn6i+Pf9RvkUu7PbayNihzrsy3a73ky1R890Ec6VbFMKvfY5K4BOLJufvo4AVYSRCGzCgOIO6bCHMh7YQt7IWxKyjiDgED/oGEq7w7q3rtStX7N/qQS7B6kkZSLfafkggb2x3u48qqLG5CDQe0lDa3hcKWJ+3HiaO1/Ngf8l9J5AeAxlaVoXVVifOxcMCkQDSfjsSjSppSgWvExHOZcPpvNqfXgaSqh2fxAKLZix3CI7+EZCsKVt6UDeyfRwr9o8gC2oYMD3N6bzFuFFq08NGLeK6lBFZd13U5BxjgjLZDEKRlP0yfZNHWvJU6TqQCCq24aDEJP+zTBRZ+QdDAI4arwCuFiOES4jdF8Kg9C2j6h/RJCmqlrIYsmfmzzHGfEuA1nBwdTbaLIxWqByfL6OedhjinCuacsg4amhSk+J6Lf0wkhZO4Pc+4r2TaE4nBL5siVz9LFItwgvG0VkJ5uWkY6GITtuUlbbmW2tcWbadl/qEahbFUgQBAgHpbeMe5/OydrLiZNqa/ddDxiree2gOGchxwuDUXTLmHTo6e26b+7TWtTDkelYOQiQVlchxYetoj0zvq2S6xlVQEeOZsG5+pAsI0eOB4hvOMEEg4+W88f4Yt/+ljyxumjyuV4KfBQ30fYBGcDBTqUAX6maSfx8OdSTORDJH0ZrSTjDQFFBRoi38mN3JwQmdvLuibE+6jVBvYLUHWtgF4X59c/bjPzruioft20qNPtzcDqq9ZH2g9G8LaftP65eVTc/CKnsa91y2xZlHN6qCvSGuvNjTlDNQ3LwDzeCfhPKVvkbh7Ncp/U1KmmI6VKOGmICrWDBJHUWUv7Rmc+d57Wy8/WRsoM+JKW2fLGpOp6fKNc0h/vcQrRcSouMuW8qcjIQ8fp5OxM4MCx4gJh/3o6Hgz6+osM2FUNBqGodoJw40MtQSNunxAIe5txpJNsJSmf1YrNwta+wDVytQbMUgDde8c3wSjXS6KovZFmG0T1PAod8dcTYuUpxLdCvpxI66mMQwxWQ3yklaUgKs4eJwOTCvZOWovW1LCDwVaQLMfpAyiYMibtON+Cravz7GssWKLWhaxvfnfjNIv9wGXcHMcPbqIsHxzYLOj2Ruw39o7DrtYwJ+Mpf0JbYnTQmCdTdtfxHRhgNYEVssZhYGuiqIJJ9XuIEGau1PMTHQyY0ROJzb1rBCR2w/Is/V2se+9U5rB8FiqW+gyMh2qHivIUpXbQqAtg7nNwMW8yncNhQiju0xaINNXICmXqUBpLZkcASQgnKAo7sNTOvyAWgKS4P3FjrXOpXH+AEr/78Og/fWbU5OTw3Up9UEaJKV7zrnNuY52ntXoqroEm7K5lkmTZ+5POQ96CqfgW0A3vhNXZy9rPWe02VavTZT1Vw540oFMfwHDqre3u4/LO425H5eecVJ8qHZuX+F7gqyIHLcfa9azNU2p1AtwGV94GUtYNzfJfO0uV+7NVIII6Wr82Mrpw2O3CFti4hNwwVvY2fIRvlF7NLdelX3OrhogNW2ZPm50yYA5VmzsVxqFt+qYNWUIfD/qKAvcs0DlcbJ985+zHm8jQM/U0tkhH13MKLhTHzLGRhLs72s7TZBQKcwJUP8W6Z/QWH9XRStvYOwauzPH02Yt2hUGt+e9ZAG1rxXR5MDAHHHDMpI6j7wSXOuRDFjx3ZfegdmmM1Kb6GNBba6iZpAznpPLnbhWdPIOkCnhBLLi2pLdl83R7seIqZmjGen+Ryuph8Jdg2mkeu9v5d2Yw0HHwuwSJ9pBteq8Hlk/GQJdxDIuWy6O9o4+wnmQ4fjvZu10ISGemEc5qtZmAOZPoOLNU3ZBOcty9YZrGHxO5BundxwBmO9NHAOpEQKr8BbLWrgP0d0Ox5Tl1pmEARULUyyo/IqiYuU1ZLLZyg4V7XCA2kuEvBX7fE94WYQhDZcPa1oLaBudFkdPUdUOMtbrsYJLIeFajTbHRB+IF+chDJo91TDj5NAz+IocB1/7O0F9685T1Cpbf9M5pb1vRheAzswXtpT11+tLT0qe6QRnuYNawHfWeF5C/7G3SqsrYBYRtX9GWUlpI7dHrTZ7NM57fBGhauNsh0RviYKCRPC8uQrli5JwlYpUUejL/Ar0UzVIm5mIRSF8HUyOdfVRHE9FHOLTYW1tIOKW54K2HjiFyzh9ufBHj6Xi3E28NlcFud8HDc+5GiNUlW9QL41YJxGQA4UOLHk/HU3Q7GY8JGQ4FJ1y7NkdRlPnNXKKjBjWEM47HiWAaq428kQW54e2cZIGAuCAaqablk8LgorfXhiButCpMZBhbTg5Dy0ziNUf4mhPjFXMlnk2skAB/4uTv4TVH+Eg8qGzSKzrAt9I7uj/eI/xWfL/i+NaWlh9OZUGTagp7GbGtyk7tGXdm3SCC65B2HXI0AxdhZZn3ZMvE06Ine/o0kDfQXYdM5oPwZtGVeFXBzmZvefSJizSOZp/Dv4d0dsWja648QDl2+kn3yPqBCnAecnLGwfDBd3I65PiTiur3XGYZO+M6ccd17QRq9RyBam6Nzzl+yxE+VD7p5HN4xBF+bl9PVYPvuxeN+PyOk0DIZE48o2Ne8/P7g4cBSLcBlh/sovmD1z2IWrywy9lnOU+R+EU4I9dhCR5zOCV0GLwKTFSQOE1m4h9o6zMUiWdtTRvGWeIRerkeRZYpVQp2UH9kWv0hpUl1W4vIp6I3vxFonV+lN5Uz7FdSF6IhX+ROPPmU08HA51vDNnZZrkdJcrRNXOsCRGCb9B0CPdoYp9zVnoEOpFWVBKP0VUmKq8M5V1ql/T5E1omXUEfbhwtCaxpP7y6TUprUOerBkhDyhu92AaOXtAxkns5Y3QgH2dKG3yamxpp20TjPwP0pyrihgKZmb3ikXKkhBCcpBHtV09JmuNUtqA+XQw4GWV/UtI+DLmVsgINuNWyAg24FbICDdsYxwEFNWRok7dfrcEH1pfFizBPS79OYg2crbjlt6Of8DnUwpkadrOWkUoVHbaRjRi54xxbK267GEhngnii72r+ySinMiKSIVMXPszpfqxIAnYh5M/sjKNFcfQAJa8cdTvBRvfg5Qgg8xb/iCGEG6/iF2HdN715zzQHrW7OCl6/e/nr2/PDN86NXr45eBPvXvDNWLsynEy8XltBLTkoaBsu8uAoQ/mLf2va8Z5x0hdPsdrl9aaK9UlwS1ti4RGNPA1w0mG9lJIidm5lwRobDFxyn5JCH5TDoHfTKLcsWgrXI4DVjGQ8wM5GFcYGw8TbLSfuVTsYuoHChnRtUmOoapCDd2bi8HC8YFsMhTiGGKZIH8Klg8eomEIB+25B71zP+e02CbPcn29xqQf1a+ZE7Yen5ijIznerKTm6v7Awr0nVrp7pGLsdzNJX1hFuxr1LCcB5q00B7V18+mos9IO8cqPwc+IZq5c1tNRh84GGlLwZJR7JC3QRmjS4qEys0ZbJfl/gS4Q9gOEJhMb7mGnAc3VI48BW0yxAA5b/828u8uAKzxT0CLDcg/QBU5DqkalAI4hTDY+hA/rPDFsGu3JwA25AbnraVTXT8uvpgOm42ID7r9yECyWAgBFY5/OpstEqrkKNIBScRZPpjstv9A94uZRTJf1A43/COVD5C88a0SYcxBhukcXTXgbe0U5roPJ9ZCPKATH5cS8Y0niTuWftP6jyoZv+pJ3pTP7bXJKAWUMFW+A8XjmLw+2eWu/yiyNYvnNyu0qojvomoQcDxTDQDN3zdke+CcpmvHrHCmCVN9fwJMmpj+pREVlBBBZjh/hih3a6EkKeC9dMu8m2BHjrqZKpOWYGoVlbKZBxVx+/+zq72al1sBkJi0NU91hcctOzOsqjKAJreTUkvKeNH15yySnBEXrE0nHzjRWb90Z1Jg/fUdyEWi9BLMNu1Y7bHXcvkWn44LvW9kuPERhhRqmSEzxuGrZQwea3r22XI0fRgIi8tYVrgpXjiX9v6s98Pjdom/j6JE33tQ6OTcYKUaZW26psWTzLpGVLGRSJ26MGgz+ESSMGlT/6KMEfTYji0sXxdixfmLpr/7gB13S0bSF4trQXgf68BvF5EXbFWc/n+fwrslNXBDvJFvX2I1WnN4CSw4WpqGa4eIQfwAFcF92kdmtxfVDLwCvMjysjzT77bha2sbXeMcvEDQejxu5B3BKVRlZQ2MNrdUWgAMowEEoIBLhkJtptFymmAC0ZumyRQwVIMSSMXIeTjjEWBBBLcWTMDy2/gil9B6lmIIn2LgJHB+G6XVW/SNyFHsz/CnGGOZjmLeRIJEUNGgTwLN2lZ0WMGHPUdxNbtk9uVwaAUlNbrC0NYX1RE2joDN4qyqJQk2ukAZmClehdBA3r2LdyMzv7sKakV6qC7OhB8ccXowj/GzOlFOr95XSxqx5spL9Z+imIPrDVSWxwG+NIVikGeTyiffj+1HpMBElVUIa+7acV/ZsUVUzOgj0DVyFhzUKU7Hh2bvN4VBxGc21Xgts46LOPRKAmUOqXj7NL10m/1xbcs2Oq+oA9+bdWfqE5QWk1YZzLWmPddVf/wqAGd/jpeNwwDBufxrYEEIGxY4EYLUFPdHlsAps512zBURt65PsbpYkEXkYulmuLKT6BC8r+r842SrotLuojiRD/KvPWQBLxOhroOgGVn26M3+G0r9772Sim6NXcCulHc6ZMxaNCCt1veK5a9Uqw00KBrSaelJfBGE+iBxMNT754jx6b9wBzw0APniEfLmyuwDhRg/TXjKygj+LgxiG9gW96ag2J+ICEo94OO8YJFl0bh+ioHbuQ71E4ChvoQ11n1gwFY2z1jIR3y4UTaCNR6RtqpP4d7dM1UqnOqDqhaujujZBzRp8WMkiKiT8ZAh1+nfDVap9fhGBdDseFyMiGkcco2Kw5oJBlmPhtHTin5mLGQ4+JAVGAalGGzlgj7IVmy1pAsennB6mFMrRvqozxXy4ipaC2ZFvCXU06ykZsXM5KNIPc+W4aMSDMyNRgWycso2/kJQ3NNiEp5F1dtAuVoUlPrgXKEbuJQWOBU3zrpYOAxp+vqmPFC0U01yZpIKzLldly5asvIWtDCKdQE7qK4aonAUp2FlYNa9SbbEUwGL5ZNPpnQvyooh6WHY0jVaeJvxRRzw9szc37aQvMopkM4a2j7NhTMZhOXCR06kNbUQbpbmMO2dDhEbtmYDtNEOmDoEhUZT6snmS5RNUvo2oZVQrK4MsxfIeDowP75KssXHzbSsqh9pUoTErnzDwbgn6dD8uCMFLtdOfsTW492CLx3C9KLxwa2sQ6DbA/reNrYCmzUoMKGC8pQbdAK4f5HxnvvODuIRcT0duuTDz2x3o6rt7o/DxXBsddthuiTFtRFD919Pa4s9NEyQVN9Wn2Vlkwf5gP0kt6hvRSrpOmil7KevN8KQNMLgyEdBqjHVynvZVWvkFszaIwq8bWl18MAjXrvcppWtDdf0fmnnkzvLbOy4qPeW6cO0Uw2p1XvKstzMOs4p8bw4fymB9diIsVOdPtS6x4AN2BWtTo4sHtdaW7693eWwu4sLVGuNFY1F8feN++YclLYcF8qKIWzK3BcQrwyuLQtpone3DtIA6yQEikOhLr7EF+1syNjHPMERWk4+R5TbOAgTS2s7qhiLeKV3HVbxCuTw9qi3oSaSAseK2UhBMSE+y/OwkLPBv6IC5kvc8Kn2s+FNI8ptDCUYWoZe71LypCT06I53DEeYwqhElMjrWewW+aM3M5zmrZeYG5BF44hdOsmT+fUU7ZZbtMV4dt6wOtMN7CDELyrs23Jve+xrK6mOrDca8Neyb0IkT19PGMHj6MxwgV5PC2eMK1zOXjsWi4ViYK/HozSYdcrr+my46Smt85asK2uxG7Lg7mdmtbPuDSQMB+6QhOrMbTXw9Aeb7bVygW7te9RRf9tMzCtFGrpQx0TxhAeuCEYbYrNPVhpeGQ9Xr+KgwkeIzxB8TjZ42qVLdtugPewXGfeskb2/0kIjbtAUtJLWlZt99+3HqmAlcX3OFDFtAJILeTQXWQjlSdUbPgeV0XpAeDOFkTmAE0tgHS9ziiLkitGljqhgP0uUd265Cq6aQ24BNbYcG75Zq3YdS7pfnowMVHJ5HQzPAFHDPewYK6oS4sdjzyVt7dN02QwCHO5PfmOPlvWdgZXp5a8g1ExgUQ7h2fGFNNEgZR5d7Sbnmxae1ITdHFRp+BFFw9V1Dtl9igU08Q78i/sEtN3/VJ5exlye7i4F1YqxI/oHrsLZCVh9d4x0zvXUCAem4G6aZ7+z72RSL7L8OUW4qUH8TkLAymXBXjLEBbvy9x9y9g83y5o5aYAktqEP4qM2bc8rfhxPUsldV76VRsVuymvinma03q6WN43Ad7ovmU5hN+z72zhv0HTTlKe8tfpxkmQJwY2Ye1+rYo1tW8lXWxFtxfe+0l2seKQCPO3ZHjF8JqRw7DOWx36d6DilDk82oWLQfKm9zULafwxUTeJMHK7x+eMBOliEeBLRgJ5rhlMl4zULpjFK2aDckoYvk8voH/XDF8x/OlONXzjAPq3hrbGGZuAZ0ML7Sq6G05M8ceE3Cj99iLlqZ99lVav0009FuRNddhQ4/+LavtWBb3tuhcfkuHr8HW6QbtdGk7+huq9+SX0AQGfQqThIQcHBhfpxh+dl7im5QWEq7js1sSv0naNuW0IrB2kfnKVVnf4W/Rbd0FP+oQDfxsO2uk5RDuRdwz0bawRou7YcAvjn3ETOrMAxAavRnlVSIkwXJ7aYsbGTVZlHSqt2vQGogPk1mPM1YRGPaaGPFjW5EE2K1l03hH6mMuLfHQg6NIF25STshEAmknxTar7lMguuqbUFIuFk6b4Bq7GeZ/PjEFEozodDPr+WC5rw1B9V73uT0xdCjoaYkYdUxLW1MUAlbwjenJb0zZitMVYiUtyfzvTnZMaFgW9n3y7Rm7H3FC8aLX8T4ArR4yXICvA4Y3fnhcuXFvX6DwuimFmlTklHHNquO1bm7sT+dzVw+CM3u0Gdw4WGsdttcrcwcDdmJw0A56HvBEtXaO7mdyCtCjaHjS5ZcfkMn8yXe2JnNfGsHFpYVxIryizKDpBMK3hfw1NLs31zZ/BQ8CS9xaSJCkSU1A1xIjr6y7PMOvArDHCrBshdRiu/wi86+SoA7o+LOsxYmu7htwvvLNaV6XoLRkZki1qyauPPvB/+rRYALbrbLIO9IaGFPoud2MTcq5qGOBK1lxp7mRuTXh+Y+Eto9ee9KhlGpEOhjMMDEbBjQdaUIVvRWpUYkiLSmvsKKAocHwPnaKMQ8SP/7W9igusO5aonsVL1hl2T3VaglWxz7VlapRauCTPlDthP2SkDBGCrk21HlZf7pmRIh4nOCVFPEmm+t4NnOIMplNSBeCSurZE1cUjaQQaUs1ggXFQjTrARWfNepThNwBcMTjvze6uOCGV54Lyt1dM2wBKVrty5XStubVGbIIKSXnFdyVQJRaC54Pajqsjc1eRBIRyGEUR34uleJd3KbBAQkiNGdg4Na9vo+1WUpfKhmmc4JJQMQu1GkHklde9QThzJmOWF2WfkNfpBs61f8AQaq6lAdzSRTkmafsFVnqPxzLRcEGg1G1fHtPanP6deq8mBBNm5FlI1SoSaMgJq6FhSRR9mBrvoxIMolWETKXWuQfzav1x14BbMFuGz+0VicbwXGBbfarM9dgGk83FXqp99cU6GIJbCvKQwNo7am1B+Hgi4Cw49MLIIRnpT3AllqtHO+XCrWoQyw1lARYYNpIcIQg2qyAoXkl/LL21LyHwm8uE5aDiFw94jvZ7PYAt3pBnYWmJjGh/+3/z9ibsbdvI4/BXkdmsSoaQRMmWDyqIfs7Vpptr7SRtV1a9EAlJqClCASEfMfV+9vfBRYKU5KR7/JunFgniGAwGgxlgMAOXtfZjqGO7gymMBcnOYTzqjsGiaENANPW0+1vM3SmYlxKe+qiqmlXAmhqwpmDmgUWeu6IT3nqtrAhUB5WYQL7iPQipfPAeEEuVs0LTwTtYxS+YQGoer+Gd4eG3cKIfB3vXpudk6l6rbu9BeKueHpSIB/LW8XprvWsNB6T2hHvgevdIiR+NivikL3fvil6iKFpeAVJs/JuGV1VDpe836HrkYjC6v8J3oSMGxKkaqv87soOoZr0Gss55ur0+5y1aOuv12FN3m1/Wdn3kTtNV6oH3KbxfD24392ludu7TnP8Xd2jOMXd2OZQZfR7D92l9u6KIe7JpO/ng1sruHZlvbLps7hel4NY9x1zuvPR6ng3OP9wy30P2j+XupxTp5ZkRLj1b6L36/3fmj/+95UyRqBJq/91l7b8ku5XSGgXUktZQHH9r+wI9vHWxawem3L5omOqUPYnSZ7z7jT0DhS4Uxy7fZrUlVoatthzrImDmw9shGeZ/XYMru6MVY3urYW118Lv2g753A6hQ1HdtAn33HtB3dXp36w/v8mw3rfnrWzT1jVB7HXjQwqYQFPimxou9h9W3AHBYW/qMOAXSjS/lLP6GjsdgwZmwD7uAFZYvQx0JdcRHbAzSERuPgVT29rrrUKl9e4HROh9Sqw0s21XmB7BmHZoCDoMt3ayzrAc6ayDa6B+uDUQ64r4/9nb39ftE98uK0nguNzw2lMa6dJ7nMtK1q9m6u0PxsdQewX82lR7nOUpTyuW1XoIS8hU3MswbAnHSFtoWz/43stNfFOD+kox4jrmUEUe3u3cUSqL7K1Lct2evLcHd7JLghGxUSnCXNQlOfAXnqQdO09pVcxWJ7XkKHXXI74Cz77/aomQ2rXptWFxNzaUOjpi0HbSFI30U/PABmwkhdiooS7vf+vZx2r8p2W252kKyDwkiqcJY7TLOcpkQHJeQ1WtT7jjkNcnKB4MMXMVD7bRuV+9ZvePq+ow11Nbuj+Nt7cZL1wbkQblxhnlZ8wdGl7slSLs3lc1WfZ71jXq2G0ZaZwM1T6bFpoJUc2WAgW8fiG01kNRG5hodW3akawdkym7WPiD7yycXVSvhoQVcVTRRwH5vfM/t/flPTjSqJsBaHgnW22yBNXJ22CXt/VmhOYCNYz5zxGp/HeHxepvlrLX3VtMR97oe2GhhWCEk+4xgBzWq08x0eIaniZhCkrAqdYrvbg1UKK9jqwHAt1x61sVAL/S8Eq/djuQe1KO8r3fNeanubTk3/+YBOFY+1UpoBxucyfjkq3Arw8/t20t2BjMpzcSX1131GdVGm9XD85I5qfPzTV6pz61kEMqSf8grrzVuYcJzqUVoB/I8sNeV16xk9k3wjI4gOYy5bl8Z4U/jIjBVOsJjYzON3K7QtoqWPt4tK2GQfaft+NgKGuStyyvhlUFhzSbbgzAuFNKVy4DieYU/Io0BLetIw62BclANzZ0g8d6V72q3jFl7/B8MZ38/FbrzOz2n5Ta11AAU3dZmm1jq7QtVpR31Xjn1HsC7yFMxxqh7HFB2tMYiu5g9upPymy5Om00baECVLlmpboNXbDIJeUlb3ta2xsG4VcA1Ps8eNLj/Jt/VXNaozCW3VSypZoOvVhU12KUx/oAX+6REUrm8M84Nd5GhrwThKuo2fKuKl00WVqjLykJ/uZlDMQpl32/qOY1jwpV7WaNUbb15rtYHBUOVy24bpYo4WRBYdZzo1nEqMEc3x+nBK3ffO071O3d63Sflun8tLf1fC24MMnhfZegJr0cs0A1XpbHaAiGEexmISV6GR4IbrgfKh8H3D3H2zSHWTngSy7RgO5u2rJzMSqoYdBG+eSeRJFre+CaVmFBn/29msr2x9G8ThwKo3L9TtKEdZmmXj3A7Qj0ZyLJ0jby1YU33irTIf4O0upK0aEFatCCtv8Q9yDdJi2wlF6mmYLeILb2bbPRe5kNEI0d5UxqoqaVyodqQCg34wX+FJp6ndRpgd/d623lQMjBASoEfbVNwCsdnknBRsynYfWaCYwqRoN4NI5Nok2/PSETlMNrehnZhQQ+i9kppZ9IXzlAlFGtmbVkCZCtkX7AEGJk5D+bcRV7dznRjI7QqctlyoJfnhb+iVGPJy3Om6GlDjAPEnOje64HZqUx9c4Af0raMMlVYIA5IqSMl3no32f6v9rx2zKRtqjVg1v3UinxpdNDJ/0YH3aVxVvXLf5MY9oJvkZlEv3ZZtWvz7oHD1A+V2VPsPf87VdmmObVKq1cdP9rjJobqTxeDz5adhVr20moYXW64Ai9D6NYXIUcbS5ylmi2/RUuglRRWDeEp9b9iq36oG+MQG4H/BY6oPAD2hjycC65gVkbB6U3JcwE6oB5QEtOH2t6kAqt+qeDMvlTw2ib/U6GG5bkrf2tujCoDMfo83rWBJc3LK+6G+EbRh3YJ1rYn0j8t6Pb21J2HD+bOQ5HrXc3nQEHQ2FY181zzYjZKxxJdb1LwKAUvUhiAt5Wd2fXgTQrfiq+wdhnKkFlW0fyGW1PdN6lV8FFqRnAPQvtL+/JSPl9eDrcnw0dpaH+Bj1LltTStsLACHdKQTDAkzYIGNS3goQu9tNl0qVzfCcRlFG1PcZ2BEsv1DV8GUkDBXiD5HTKbvK9c4oFLV/58Bkh6xeGVG7yZucG7cf9TXgjk8gJvZl3gfetyUF402NxMTbUBXf0gSpDajrOo8pbjxt1GbnuJ8UAKg0H6BA9S35fh+KzrVWlhAVejEg2P8b04L68Jyg2X7d5C5PWeITY55emrtwbpqGYRMt48TeT6TO27Tsxw/cRMnpBtHpBpI1DNdeRp2SOXm8MXVcdDxy+aR0jUFN7M6p7IyoGqOxuT+yeyrU3zlx0HNYqa5VENX7tvbTb3Vba1dF/ZU9JxfAw2R+K+KtzXNhO/3ePtLNDqp2F06+ptymdm7xE/fZHa8WVfpAP+BPvdIJDxzr6K+gYvUoit64Wf6vu4gohfmUTL3Wop1Bv5o7j4iZtNtRBBBcfMtj8szVikHea+B3AxvwQDuKwYK44+SxlXWTBWNYgiT7ma66mNLTM77uU5rlyJ4KXprDT46QMOPsv6QboWy3jR1l7RBnJ7h0aPrXh9rVbIZIVHZYVMVPh76fxVu4ItQFeyPZm6yo+/+CiWpEr3kds7tv3VVqVSLJs8sTyk8+GvqauHxws3G9f2oHl+qRhFKFoZij9qjiK3dwAqLmrrgk7ZlJdC3VIRK+es0kEp5AxSqN3iVloWPZE+/rF1v0qKqyZ4gbHNTNIdDhcVXUtT4lSZEptLpYrAzqsTVZKw54FnqdvF+2pAf05hXPCEcqL//o3zjFbXA//YnBb/KDbNxLIp5qBNqtK5Z553OxjCboeXO9rYSM+8YiiD92Bxisb3IDceF/Q0GyhH08RrNs0cVNuQ5ZvOalWrlt6fU23vrRbdPVikWJuPhUsH5cOhOHM/w7OXt8uxE1ZSFQbHjnbaIJgihI7j80El2zvpnq3I5uM96OOhz/egz8MAipdux1cICsVvvYIXiON6289UCB2r1s1yiv2X8G2JSqCyNJt6pZCT/P3UYApCuO0D96rtSFvVGmowHzth+hQGzWbq+2sMf5LbRlz8atfIGSyyy/Vn7EAIkRzirMJmbcd23xroBFbs50EEuf0uahdsOmo299xbN/GazcTeMkiazVs38prNyE4VCY5Vi6MCFNSTSlDW+hwkLYFLpa83NY0opHluBaJeSe+v0vWucYm1arUGHpm6bLQaQ1hOCqre5UxiJoIooIUXW4U5dwUL3y+CL1R9IO11ZctFG3tiDo9WY8DFn7TVlXO5uh0jGc8SxFsucqxgbCTAiipp+rIH4WpXy3+6HCxhPFoJLUPBsRRwLLfBYdYcFRpKdFr+7ln+gH96SC58bnPkM4svW5Y42DKPD61Q1r/ZFeNNyfLvqR2J++81+cbyf1x+cf+ZVuMh5HlFKymkmO6AP6kL23b81lKu5iVNySBsqacbKAXsOcqs2zXG7wKTJlojNobpiI0th72eJYrb7gyKDv1SWZ3dX4o+VVU6u2/2Ym4paxzgtacEvKJ2aeBr6sZse93DrYeK4RZNwWouz7cfRWJPAGGBwJmKZ2Oxz0Lu0xubeV5scRYsobKsbXxtZ3O0qGTZ4k5EhYzRmQLbOb3m/tawVhj0RnOuLgBG48oV8LUKNFuP87DXteTjlFXlAjdlUOBkuNHKDj/JI7HQjweKWxWuMbjl9cp9pQvKGHmFCxhWbtekzeYvqUuB1WUP0II6RQtbqZOxUmjaguG3aDnU201aXdMNumzjZpESV4Tg4qYQg1YXQljAbcQpPZ9K9zLOKEWcXONGRGM8drzabllaHfpypdNxFgVwH++WKpiO65yvlpg18K0MpSj6t1hlvIEJn2PWmGC53a+C2hVVejX59V7es9G2yIZFGesJXtzQtVBoRbxhtmMegJna4rAXWM/i0jsCyVhGXeDeKhpqtZrVzogesk9Ze+CXVJomqFk7chRndoC8PgKkCSIwidsCDtnREhPXkz57kOu8pZPfGiYabUPFo2z8KD34/djgVCC7DJpIWWNJk7spSWTUPiFwb6iIl5dv3z/77fLFy88f379/c37505v3z07fXP78/v3fLy+bzQc/t0kqKntLJ7fufba828batvklzJZ348brrIEaKW3R5Y7gjnbEsPUa4FvOUBbezzB/gSermdxY/5yuwSNRZ/h5rScu2zT8BenAIpuSy9dmUoFvm8rP8BQznEaG1AVlNeYoS3/kjQnGaWHDm+G40WpkYia4XiWHmHsC/8Xu8Nq1duKAc5rq8KQ0ilaM4bjdOMe4Med8mYWdzozw+WrSjuiik/G7BMetiC6WNBW03lnShGRzHHcmCZ10FoiknYxFHXkokqLkZ5wsMcs6sv6svYh/cHzuO40pZY0FZbhB0illC7mP3Hb0pmCpBEIMXA6Zt3POVPger+6XmfkDuZgLgvECtnYZUxGbPGsvh1iraUO6RmN0lcZur99/bC95qMbyVUHfAY5PxLiaJ1sPzNhDBjqIqZBzhWLI3BSkIDWLgIv/tn8Y+PuHgSceOocyJEK3JYFEk8ztPU5bXc97zAGC5LH9hf6tJ76ADAYggQGIYDCgUvGgT7pDVwZDg8gL6VPYFWk9kYZAAolM64m0/aGbQAIinW9fpB2INAQine9ApPVVWZPWF2mH8pBRFR4oaT5tkU6v2CJxM38FEn8FIn+lDFsTBu+REEongt8502B6PJ06AKWcfFnhmznhIhXhSXzkAPRlhUInCKZTmefLCi0QIykOnaPpdBofOAB9XTFVjcwywWQmXvvTfhw5YEKyL7KVKT6IDhwwSVB0JSoM5HMazXGMkgVNY5lnEsUiXZQIAtGqersmNME8dI5Rb4J7DpgwepOGDur3UA85YLJiyd0NpXHoxHhyfHzkgAjFmKuK+tMTjAIHRHPEOMOrTAMfyDQayVCCoRP3Dk+62AERZSgRwBxN+4F8TacJvcFM1XZ4cNLHsUrPSHIlck6PRVcjRhYZTUMnjroH+yLhDqUl7mLErsqeHU9UislzPDEpM5rEOGWiM5Pj48PAJDN0FzroRPwzKRjLsocHois6qZbpao6uSOhM4snRoa5pgWY45Sh0jiclHDQh11jX2O8fTnoaYqp8tzvT6XFkWqEsmpM4dE5O9ntRpNIYjlWFJlMmRzV08MnJ4RHSaRjpJo6nk+hYN5EJ/CvMHBzvxwYimax63ZseTA+mlWRcS+Yr9mVFSSbRG+G4q5IN4ZwcBEG874AY4+WSpHLUugcnOiW7ujMjM1FjRRaq5cMT8U8nYDuBxjNDEl18Iil1ShieMCLoe9IT/zlgmghqMnNqOkXTwAFTynDGNSZ6veOJzLmK5hlBIpei+xkiaTahjAqCEv8cMJvTjJvKjtW0FeQiCsVHAvMW8cQI9XsiSXbkOBD/xJsmmmM5UvL1DicJvQkdFE+nYtxVT02JOU3xXYxv9BSXKdzg8PBkciAjHBCUShKI4n7Uj1TSjIbOgaCxngPINWV3EgWyCk2W0wAfHkcOSNA1TmPMQgcf4sMpKlMmySqby3LBtC+Sb1LdhaNoKikywQuaRnMynQpyEzgWPCQhs7me/yiOj/GhTjKzW3dOpck5iPU8lUkFHg1upmiK4p75KlEa74t/RZIE6iTA+CQo0+rZDN4mh1FXJ5mJMp2iQEwUlVjMlF4w6aEi2RDq8VGEp0VqOVOOjk+qibiayDFOVA2TIDqIsU4vejmdTrEEfyFmw1Q/alD2e1G8L3GQildBzAKvBT+ZBlPxxqjojqAvMTwLHJPVwl44Dg+jWPRIfSlZohg2lWYYzAT1+wJ1KnW5YssEh87J/lEQT0xqian9aLJ/1C3SS65yNDk8xrj4sBSqUjEPpuikgMViIgfHcVfwNvVBsRFF4Efd/nHfAQsSpyWNdU+6J0eityTlQmhayBVwKoZoQTJ+x2imF0EsIKRRhDKSqpRJ3wEpukZ/0oJPxBjFMvFOrxaBA2gSS/fGzjSe9gXeJctW8zQI9GvM0CR0DifHuLfvgJJ5o77MIt9lN6bTA52kUB2joyA+dMASJdhiIhjjYzFWMlmT+PF0cnKskiyEoSnGAski2UJXPDkKBJtdoiW6QzdzspSdnsZ9BywxiubL1XQqu4wmJyKJrQQTOe7vTx1gZksURBMHLJPVInTiGAVx7IAlvYkNA54EWFKioZBjjTKGJziKkEk+3D8RaaL3ouuMZndakBCLkViOGL1Den4cdA9PxFhlKI4TrPMdTw763X2RqOcsOg6OeuI9jU1d0wN0cBg4wJrC+HjSP5Ip2RwnUriY9gWyMoLTFIUOCvq9Xizek2vBBaNA/HNAZb7jiQMsqj5Efcnp7NkfHAeC+9hz3ySlen4jQZP1OTA9mjrAYg4Hh8c9wdi5YIxxb3IgmDTHgnMGmnMKFYILrMbHk2l87ABOF4hTuSjsHxw5wJ5MAQ7iwAFmNcb4uCe6fzPHiIuZEuPJvng1y6R+zhb0SsuSgvmXXCowL4YmkeRMaxAx2PnjhxFqTU9br4LWyfj+cP2oA1YbycciebmRvC+S443kA5E8FclsNrlwL7LH7kV83wX7a+8iewy+8X7hPeoQMNfF0V8uL99HLX88HAloHo/a+skva1+I2udZUlQegP11NaNdbfFl6P3t4U+q+pmuHv3X6/+OzpUq5B3TSvxGcDVbmafM3TdXdWrK/5ZylR0xDnGb0zdC3H+OMss/dMJGfDx0fnB8+RQK7V47oVnI7cuImQ2te8FiiihqjuPzUXfs81FvDLqHnpbAqt/3xfcD9V3OwOrnvvh8KD+v7TZXrLjQLwu8SijirlstfCQKH8vCnV6/77U5fUVucez2ig3O/ynEACXLOQpT6WnHQL78Jra6u9vuWbBtaVuCtr+JrZgVdyB3Y+ug7NdfxdZ/BWKNLaZCt1E4ZW18iyOXa+vUHSBQ2XqwrXUqGw62NExlm4G31ufcc9NWO1tN1ERxA9APPNk22dU22d022dk20W3r/loDIj8ejDVUCC4qGEDGFs1hs4nr+BmrDCAysFQTFRSdbhDUPuwXHzzf8RyQFAhX5sB7SZWvHAAOsp2EkOzGRLITE4kZBTniEZw9OAqR6v9qR/+jbf2PdvU/2uj/suj/SvV/udn/1c7+L3f3f7mz/8uHKCGSlLCuwNC39v0m9p7ilh1hGWo/FjNZxkKVcMk3CnFbgCJfSBkDTVmSAASLoGY6JYMu8ZHX6cm5ACFEGxZWuC27MLyfr3AYgAzxlbLdDQOlZqU4y8JMd1TnXoffyL7WlgWkhUAEs6ft/jDpuL0WaSEvTDoSKmM5QnT0jzTk0GUt6nUS32VP6PAwDLTPMBXqg4kMtJWKDD39QVswiy9pi4kvB4WvmgAAQP+/x/AwANs7ym3Io292dHf29dqV67vapbxm2wz9jyAsbAuaTTzqSvOEUW8sXvbVy4F86auXQ7Voi5y+yOGLLyG2IircWod01u3U7mGx9ndhacQwdALH5yEvSfDGJsFb5m7sbFvkelXf2r5mrgBP1iH+cvk3tcu8rJcp9rqv7IOy90U2IebooIy2ieBGGt+SVtxO1YBJ5Ii/XP5NFRPaZoFoXzUqbbe2VCcmpKee5HTUzxMZeH9QmemHVv/Oqzv8RpB7uIfmjqqkKz2cgnEi1/GpAESeJVAFiH4WgMhHLjji+j/C5pa08greU9gdFqMWGrCKtoHjK5CYgOOvod16ZqVtoJyGplXRe6CHAGj0l0AUuMEWbnCJG12ZhKwyZEfWkF0W0vqGKVV1VTmWVLU53TcRL+DaglQN5dYvAuatHxRXsg6iz5mW6f+nkGyJmKpAyfPyaFKleDZ07/8SdPMdnS6Z79bPBTv+PoxVTS7M1PzfTZeXG9PFMEPvfzRVRIsCmcBGHbAQVQXl4awPT52et/5/O8L/LiVWR/0/HHNTaTG0f2347OIPI7+K7K5Cdo0NlbzrtL7qWmYK1zqYj3b/XL9EIg3+1Ml/aRRU2qxrQeIp5ENsm7cxL9SNMjv+0HNbvJAZjPwDRvZlqrM6wIVIi+0AvRXR4iMrLxVwhtJsiRhOuWMflRv32BNmGd5fMvefqXu/Bim4LyW4M+YGoAvSEuktS5rHyj2lqO0Dg8+Z+5HZ99n+G6BYkmUBS5m2A5g/JTCvbWDeFQtXDZRityjQu0VSsAAprJmebtwVUoDzER4LhaOwK3sC28H+Se94mHa6vfZJT0VVXtIb1039dtDve52u+AG99oE07GEwHQVjQGEqVC0C01GvuMxkb2q0e93e4WPmt4+6/d5j6reDo17vMSm3M/ZtOnjz30D+Q3Tgb0f9I4n6N8wDLxh0fpDHGG/F03Q6dcrheGWJfjYXcDl8wTa8475lm4Eug+LWOUAgg3J8n7a7RycggdmQh6nu0B7Lc5fCBBCVByDxS7U6rXFLnqKhS8TweB0Xyd9Q/3Z0emXb6Ck8aPe9YRJmwxcsfMtKvH/9C3i/s/F+buFdKVka577bDYLHm+w41Rqb/g27XktkrA6LBbTcETDD9EwO01emws/yxicG77Mlikg6C+9XKeFhH2RYdulnyshXmnKUhG6RB689+PT4MW6LvCbnZ8w4iXbnWwOplS4pSXkW3mcLlCSh0w8YXphTudA56svXBLEZDp1uIF/XIKIJZVl4z2mKkvfTaYZ52O6BJSMLxO7C+wUiaej8sN/b752YE9/QvdfFJBiPxHpilQe4rYu3RWlPWhfUynz4VpmIppyhjH/Et/X2BI1Xc69BtooiMZ8MvN34uNs72glv73G9dV3BX4K4WuZbEFdyr8ENYqmkCg2xOXj8Tgzr4n8J3mqZCrySjwhWsgbSMq4AKz7oTrvRd4MlC/8loOwS30KhlXetjDXu+0Ho/PDqVPxzQDeQb33xz1kDLqq5N6Ts/LAv/3PEtKJpLNK+2R9RhaE1bw0mlMWYhfeya0qYDYD41wjaXc9gyUImw9mSphkW09KQqGyy1nSVPMAERVczuTHyfEvmZ8xtn+xvECBHE4G4bSWECqYBKQrJ78VwbweqRPj3gmQP53cCpIpocBiOCcMR3wWRTcPfAxOwWzKVq8a+G8BqsTUg6ZQa+JwfzHnzXwVG1PIXASmLrNdgzvlSGv+Gzg+9V8fd/Z4DljQTr93jw1enrxywXIm3k34/OIocQJdiMclEysFR0D1wwBLxaB46P0ym/eNu7ADlPSB0fogiNVMmKCNR6PxwFIh/0pzlKnR+CI6Ou8evHDDHKA6dH057+y9OXzjrNciiOV6g8D4hKc5Ub7CeV6pPlen15470IrHC5D1Q+I3giCTZryTmc7Gu/c2R7nTeoQUumizrFRO4mPAy40fCEzunArpdqQNoi/I3aIKTzVqteZGIHJkYvXPyFYdO0D4R62yKM07S2bler52uScTxs4JQBKdAyswAMUZvwvtM1tFty+zRN3qzXov+0BlDy/ldeD+lqYahe7C8VbZHP2PFkbrtvqhRZPlVJp3h2SpBLHSkQWSZ/kzayB1WE9+oSvZN6iu0IMld6JzRCeUUNDKUZq0MMzJ1QLaglM9ln1Eq7cBRhmNFfQvyFZ8vMY7DvUASD0lnmQLcVPmWpjzDjCFerbYERoNc7d2hFmZiXMHDvsCDXf1zumIEM9BY0JQKYQpXanLvLYTq6Vd+toHYlnMDu8DwCNzfP9nvb/IItYTsH4NGPwCN/qFYR4K+54AbhpbhXnctZ9zONcOeH+CaZITjeFcfrjTHB3N6jdmWXI+Y2+6BSl5PTGkS4wli4f2Nmm+9w0AgdaMnBSXzgpGVKy6KOLnGJYtT807V3C4K7EH4iW0mD7dkDbfyCCAgWr7meCEkWnzLPwpNYUrZInRWyyVm8urrGiT4Gifd7flSmoostfnYr83HDYDWa5DQGRVy021BTAZ3Zu0SGAQLdKtY147vsxXnmIVOb3krBAhR1QeU4iS838R573C/t3/sAD02B8Hfqvgv5BAxM54lNLrarMW9t9owUlq7C3C7ltNbq/O1Lwx+Ylq/+ZXBbbeVb0ga05tm0/n549s3LxO8EKoaSXV6qa5+tnZsttUT00huCg3NQ/vLCrO7c5zgiFMZUyRdJUmpJv4s1UShxaoLS9LlglIV39FYXUs3G2G6CwwqqNozzI0zwXN+l2A3Ne7kAIXFMSzT9xDlrUzp1Md1lFjY4nTZkiPhePKUlnxXqQRPeaUYgrhN5Ur4kS5bafn8JG1nEaNJ8pEuQbYrl4/bUUJwyhUZtuhTq5ifVj6CpKjljQAjtV6K1sQLiHZnLBqUZN0iT+2CRYPyI1hB1GzuZQMX5XnmNZu82XQt8Hb1qVUFu9Nr0Vo3Oz0PuEmeR7VKBQy7QW9VoOv0WqTaGVmrADXPdd17vNnEuu7XKaefCb5x9W2R3xlkbnc/OPDAPxhk7dT9nXngJ5F63D/qe+C34l5s1U8i+Pv2DwRn4J9se7g9y38j+GVHHh2SD2AKv3G9GPAtWbbF4gMphXr3FD7lMtLa8De16XRfdUZadypj3w5U9wfTtRfiER9D+zYaVfs8Zvbqy/cJFhM1GLDCt0+rO2C+76X6Qr28Ew32uuXusTp9N+ffVr6yhjHYC6RvlaJ5Wmv+fi2b15xCBZar486Vd7LTERtDDQYD2LoRW9ZOaOWKM07j7FfC567TceT1d8uIpQSycrsdWTXskewdeudWN6aaTZK9IilRgWEU3Jkcsna7zT34VHmPqfoZaOCB6TBvZ3My5aU1X7llOMShm1DpDSahbuo1m/ZWru0HhcOn9yLLiI+9oSuGOM/lD7xfeyCj8hnIz4YCRny89tQ3BaknFlSI4VMXw6fGZ0/pP6Q87vAkRHv1yCQlSUU21v/BXE86FLC9a1ftGIuoWJ2LzO/MgNNyrLSmTEFpXEm9aLU2s/7R8jvAsVNa/iOZUg7oShOcIPBUmeBlHDFuCKPjeJoa7+XEjGgSsjV0A/ATa8uh92QkZfivR/cszx11R9JZP7rn638VPnw2T8k67jD8Y4RaX8fiT9A68dut8eMwv+hcdLwOaXOcCXqSrvhSyAemphp4BXQNtgUmlaLuU3quK3sKn/5dsIt/MlFzmXhfid6ovMLfrz0PUxNYSxBcKrCVAi5DOpKp+wvzynJ02vhF1sp3lzH0vvbc+zVgHrhfIj6XHib52vMUwlIoJ6rvdBy/8GBIaOUW5ZJulVwKsvx09kZeWNesv/3p7I2UVvBNQz3quTmlUPLN0BE81pE3qs9JOktUdJ/QkT8qXZJ26Ei51THacOi8UA8iZclwhIQS4Lwonh2Ab9FCWvW/VA9FSlYkZQ5gOFqxTN6TODOPUi9Fd++nofI8JnDsgBs8mVN6FTovr4VcB2RPCkhTeoazVcKzV0rFfUcbTCU0piLFATG9SROKBJT6qUw7X+KITEmkjqaKDI33S5yefnjdyOzvjrW/5pyZRweI0RfC61n59blOarAym9DxccbPDS7O1HsjK1Gi8lo5VEKRxTKOmteWjikd4XGVi0oXWILVhakUGBZ0hzww2/5ByAN39NvywGRHHiMPXH9bHrj9XnngZlMeWND/VB4AV6rWBxjDdWWS39QYw4RWGcOECsZwu7tMwRjAS9G0WHba56uFUC3fp8kddDL10qJpcucA3P6A+Fx9ERzEJHue+5Lm+f3aWn/ea8KoL6h4yPN8rxtu2mcNnSlKMuyIJc9e/c9tprNZqtA2sNAjwk1Dg2Hh6zBKUJY1Lul9xhEnUSMVPDohX/HL2yVK42LimMNdlCT2oa58H2y1LTMTQIxSgVXpBZO7DnAsKQHDp/d8hNuckYXrjeFeIKN8retTBjebFZ8J/8JVGJVvjQluoIaCpjFZ8QbDESbXOG5I2mo4j+7x2hGkIABtPLo38K7/5YH79bqOh59JjH+mGRdLgyVy7eGNnOdSF/hd7V3W7k7YRhl7UnYr0SN13wHP86pDiMyuTgNPMtE3rfQ2OG2kNG3hWyK3GBtY6dftxqdMvCrtphE0JncNvUY4XinfNZuSKzwTrJiks+dS2TnDEXe99oRyThd5XjhX8eDTVI/HJjXluezRUOTaSmsVyTTc4tUFy7IFRso7JBvWNrxOA1U0ZXO6SuKGkbhlYU0FIsWmAr6NCrigAr4O3Z1E5/zKaDrT1Uwpa1QBOMMvaNRQO+yhAWeCNUECAxJllr8XIDofeJsENac3L285TjNC02zTFYcmReWMyJ6Vyi39Q/d2tO0z1l7zOFth43RuL1C+4hTnCYtGjJixbSpL2w25H6bmsOdtTqRzEuN36FrtqFjcocpQHwac1wBvlOAooEsWbFzolSn1HvBNGD+gOyl7yEX9dXz7kDHZsDAWCoCg6i0z3dLA6jw52Gj7l4ymqmHFet/ga5xYABjOO+x2glBpfMpPoWAmQ20GE2GSWMkbjfyEU8yEMFjpafYW3b7AS245lGpstNANQqvHVhuWQxO553a/thzFAwKQ5jmZWE6vqHtFZfgZD0jziTle4GYTqwcVvEeS+8+UXikrfhANyqBKOmMZTKm9wOlK6H2u7Qq7kqfYShbqeWUy//hRZGxkmEsG6oi6HMFlSwm63TjDgvcLbuvoepwfPWAg1kmmUQUOcIuYC3VgaDuisRYkbbDJRk7SLjZrvwl4WedD4Bf12R0oEqGdogHUEdVEcuVqgbW0S4UVBsUmqksBEczc3hOg1mqPCkafQZcMie+0ndBxPB+BBNIRGg+2LBDJcKt87FKAwL2M76W2M0bZWLn+8n2QPu3ifctoWrkp+pfC3JLRCZokd42IphyRNGtEhEWrBDGBPJzGOI3uGog3Ht1n67Dx6D6xtgnW//IGoimYWH5hRcK6Godn7YUb2xRJs8ncBGTSUqj0OIOB43jgl/P375Ti7MpHxVPI9E5ONDeTM+cLA24E1SwyNANm1I3AHXXvqzOoDDHjefZg1iYazOQGsDrCBBUXh+6UFlF6KksdvKTtXbJPNacuPbckqUrhqohVyWfimVcFvUrpDUG1nlvXoQ9yZXyg7BVhGYdCIN+SbnpLmdypz06T5RxNsDS9Su5UqR0fraJCNZKa8M7yu3JYlbxfYmWIubOSXTmsSj6i2c7im9+K0DqnKy7+n6vM5XsRO5+Taz3wE8Qyna2WamLzIT5/nb4lcZxgecCkcm8k6+yrlLNVxrHcBVBZK0kWRZmNgWcrzmmq8m6mm0i4JEMyji1ike5XJUlnE+LCmSaL13pR1v3b+snguiKvVedHTZSr5TUVWCJStXhFdqrks1ChtovO7M2Mj2hSomT7d12BWLc+0tkswapA+Q6K0Ch/bhNRKoDuEGK2lzSTO10tzq/I8h8ryg2aq2l2H6WNhrTcyKyeWakFLkVr71P8fvrxbqnsNzTZb/lSkGlV/qv0bVM43MhfYVcK3Qq0VwQnse7a9o8FixUpEkmCMhSG7csDMNguEcotgTznaxdvrcSiUcXfz3Umm7p3fS2mZSZ3ai7JLKUMvyUL/AExtMAcm/n/YBZdDUoSeoPjt/HzwlufvDOxkZrn92sbo3qD8xyza8w+I0ZES5mN1u05DImj2xckWyboDscl74Xnkty3fjPq8grWThXaqnvv0ALHClWZN9yWGmrxDsHtZbSshx7WplQstM3yRYT21cYU+YA4xyytzxGdrLPPHlYHKuT/TdXhW7Xp29qnFDynkLknx4cHHjgTj4dHRwce+EjlUekZ9cAHuivcCwYMJCACcelueQrmYAFm4BZcwQC8hAF4DwNwDgNwCQPwGgbgHVzAKQzAIxiAFzAAb2EAXsEAfIWJuRfyDH5tdcEn6Djgi/jzq/jzGTrO4NGTrwMpU85h0o7miD2nMT7l7iMPPIIQPms2gz0IX/rn/nv/qtl05Vuz6c7hwRGE8KVQnA6OPHAO30MB4FffB898X3lX1MVk/bo2N3jyotl0P8FPxXHRUgiHHgiefNIUYU7tvHutD8+1Przfk17dGyfqp69/u/v6Nwir95Y/+bpTskPrOeyfrGtVdnv7oUD1FEqYNEnamAg8sIBd8Ar6/iONLlNHHWVWnQvft29Xd3v9cNFq2UkHR+GOevyuqelAd/jgKJQWX8x9Bx/53cG7J88Gvv/O0xVUir8rCh+FZOoe9CCE82ZT/lYztrpes/nI7+1B+M67fwTf+V0FYAOvbdgDWY8Y7nk92/oRfLe2M590w7nv6x4G5fP+gerJ/olE9+CR7z951mzWELgH4XzgDYy7+oUK0ysym3FbwMQ6QH4FHilKmzabZggNWa3kmeTWAfXAVOPo8MAMwk66nMNPdulibLpBYMjO0GG3r4erH76ArHaJ/gX8IPr1CroLyF0GXoAFmINYDLaZpsGTP5tN9xZm7j5YgBcwdT+AT+CtBxh4Dk7BK5EfRB74BF+0/6QkdR3HCjty22wKVKgWboue68kk52wAFlBPtldefSZ0+6Hd/RuAvMGOnh70wwX85Dv3jr/wnbVTIfXgKFxUh+IOOI+6jUc9x/PKMmJWQQg/5rmgzI/NJnGd/3P8Bdj3hs7/tW7w5IrwlswskkP5t4ZTAcQCdLuihqjZdL/4cKG6qI44xeNGEYH81GUKswvBbf2ut/5VFX0LX8B3kp1Kblmbmr7/yKtPa8OKyNTtPhHI/wQFMQ1rhBR+8upDYkZAjNo7ScCfaoznoC9oO89PDp9Mm81ub//pVAzkqyp6nYYDnNApK1aEVBCGpKgu+AQYwJKQvhiCiyQ9eSXhfNpKOJ+gcxFcBI4HNkHcmB7F3DLc2Ew0gaBAdGie5ycnipt89uEn3+LRCrlrM1j94z1Yrf+VZFpioKn7CYjFsfK553ne+ttjuN5YBsolRK9rL2EQCqx0fYH54EgF6RCLlLG1cV/ALvjkC9w4EuWP3zSbmRvsRjQ4hV3wvLoyFItYrx9qtlcsm6cma4EQDfap74OZvbYB0xFd237PVHbuX/kvDaVdmqVBc+P+cVgrNducMftigRD9nUGn4Xg2tw9E/ouLoMoAeip1Wk3tqtTrSur+caiAfCmlixfwLewCkW/q+LPqVAuOyy699K/8MzEaxRL4qPVO960XKn5w2Wz2j+tr3qPWviCfM3ipedtx2O0KNvRapr6u9K5fBe4drE7+g4NQjdZ7/1xD3wUzQQ/MqWS01j5ZoNl0z+G5mABDRWPnw3l4Xily0i2aft9sXlVJ5mS/8rEmVnRtoN/XPgYVHErBTC6fBo29x5f+/uPXGpX9/f2aRDWF3fV7319XZ7aFBv+dv2g23QXsVnFVCjJk6u65wROR933BAl8WPKMAZO7vP94lF/X2++FLeHBkN9HrBeEr+Ai8hAe9dbVpJbtoGeiy2XwlZZ5Hzaa7v1+nkFd+TzOYmqAhWhek6Qgh3FuvzVB+8uHMW7+Gl+ASzoEQVQRSxUrwpRRkydR9Adk2vtwDX8ALzS5e1RjyF3jr1UzYPvtf/F8HZOp+KWQA4KhV9YtcVYM9+PHxWSGjio5+zHPifgE9L8/dMxh44KxY8rvhF/ilWEiugRO2FvRr61HX8fwv1enbq2SdACcMzSJN0uWK60K1HGVtlQ+tRVYptT6DwXpt99EK+OFa4Tso5EZLUDrlwhtwSLW/Mmr4LSpsImshtBpGlAmvpdOwQBo+YijwjYaOE+JRMPadhjPInpCB72ee3AqXZz+jbAxSs4rXmKTyyGTq43A0LiowmlwEg0H0BA18P/L4KPF9We0oks0BWqm92Ha3415Uopjw6jpsurm//1TdcHZ5gakN6ZcZfeq4OC0sRmcmZDXHL7TzghUWJ6Pqg/9AEYMUORG6j1PBqXkZguRi6lihPspaXMmvcRVaMSaOJJKi/iIakG+hh1o3wqWXOOw7AwdksPeY+/uPU//gsYy2dXJwACHMvHsMUQlS6IATzzchu5A18zFApY2qGXsNQDVnALDJ4Cey8bp8m4CuN3RK0TbxkzAxyk6ZcY+4CHQLFCEztlmheXT7ZjhOBGtDFQksqLSBfBQivW70u6ZYt3tYL7e/s9jhflksqBfr7yrWDQIlFAeC11XKHHievZwdavHj5KBnzrUrNepsR8fbvjqSxVj5ukHX1He8/3AJR7Ahq+jx8b5Udfv1Th6bwagBJgncIiOyQDPcyjB3HdC1RrAg8ksxVUwdQiHyUXVl720H4KBYKWvIL0hio6sTeiugLLWE1ozRG0foIn4dH1k1p864pBnh5BpLKPUq0N+B0VoN2ZyR9MoBTopnqFrHya5hrFUxQRnJBBQMTzFjOG5l5KusZ/1A+aKVw4OdzUwTfFulmJ4c95OTOqEeG0Ldgtsliq4c363ygCpL6fa90iraUc1WLKUdeTevNcH8BuPUAc6fq4yT6Z1UlLfDrZpNStiDghdMlTkz8oYlGmOx2JqKPL/2QU4Ez5qzeN8IYBzWutbdLxXYopOidBckVZbtV955IbT1DkNRpYHgFjh8UpWUe/u9zSwtltRy9YJ6rqQUuWt2MA9Ri4XFrhRMZRAtawwzTqKrO7E2VBjWUd/CEoLYK1aIAGQCb0quRFU0DKuLBfdC5NkLTYV0jjy/u2P3yneDvILhI69AcSAJudvtPk220nExi5GFvwTYa5Inlq4qW+oFR0Y97u0u6XaD3pNs6JA0ISluKbMHZ0JvHV3lww1WvurhsUubVR+JV8Muj7ezy/52dnlYssti0tiE5LSIMjp3HA/UCKbCVZMKI0m+hz3KvKL6Cpd7KdkxqhHtjtISrWr+WzCjhMzSVkRTLq3Ubfaia6/szx7tm8XxROGuzvP2vTzv9npbVqDKQtXV1fQlxe1JndJcp/AKcUGMjJtAvIvOPbn9WRX4lNmCYZCcYR7NHeBMSZK0ihhnjqelvTJrWMsBnNCU9sLdxFcjPCkaJBbXFpVKtNbX6kO5ViNYGS0xCbaKSGp50qZAPbnnkPqs2VRbYlUJbl8ogLZcwc3FXQd0A0ussPmJlX3ggJ5iIKYb8025o5hP1sUttwwzDctxkt5Oh07ohM6940m3uXbD+8reP+wG5WWwSpbU79oXvcA7qZXyIQtZAeB7qUN4IK2E20Q2QNTloKb1VN+7tfeedTtNNCgYxzAtmrwCToOyhvuo6zk2Iz7wQsc1zj4LUDK3CCutfEaBBKzKY7oliGEAppAP4id/Dnw/NgxoCV+P4rEyyI8ABtONOjRP0mel4nlPTa49raumqyTZ2IdZCr1humf5hZqWwFqWlaWBuYshbgtpitx6cjtLRqnEw23hHocfYTd0P8IeeAexF36EgQes+8eRi0tNVF43FnpndWykFsrMEgYYHLExCJ78afT4zG11JS7U4YZyMBN4gwJe2mxumJ1S6dCLqouoBHL3A2AgVQV1f2t7LLKhHiBFQ6Q4bZHFBJwEUg+cwQCcwuewC4isfQU7f1wEfmcGlrAzuggu2MV03JmBGHbCxuPODExh5yul+YyhDpjDjjsCYWPsucVc9TozsIAdcMH8YWcGZiLLBb9gF2lj7D2+mA6bnRm4g53/c68ubmRsA/fi/LH47YAJ7IShK+lUVHMNO6HLMIqlra9IuYWdUXY9H1/c+K0RnyRsfN9bd8AN7Kh4DO3HKlhCZwauZMPZxfn48dAbdGbgJey0MpxMc7mqdGbgPeyM/hg/HrrhiC3HI5yM0ejipjX2PZHcAeewozlpHopab/yLljsM5ZqTS4brdcClaOaP1thzCy3owvU6as8bdiV+P8Iu+ABHY/Ba/PlTHl5LKnwDjTF+I2qvstIcs4FdXmxm8c2poibHn/C1HlUY1MTA7aFsufd69Kfvj60rfxu2jLy8WwMDwAqHz4P0CRv4fuphV12qkTW8gUG+t8fLSMUgameYwwTYxvZiYoJoDV5TeI9SogIwvubayO05XaU87Gr/S68FGt+veIZraecJiXA1SblaEEm3rxJ8Wz79xOhqqV7fs5ikKDEpEU1Wi6JJ9ZaFXTBV5aeq8I1+/KB1Qf16LvU7/fJO63j69b10HtUFM0biM1mBfnqZxuXL+RKl1htHjOvX5xKUyktZUr1bhXWCLr/IfipaLZ51bvVe1G6/6hyW45Ou7S+lC+gSRYTfiSfdO8qWcyQRxtFE+mHpghsS0xuR9PW1WDrFA6WLsAt+lQvvG5Li5wlaCOwLseJ9Uek0oTQuXzNOl/Ybo1f4Bcrm8pZiJUXdgimS3hKOWUIWpEyq16MpZQ3+pLDzh+tGc5LEDKd5LCNB0VWW3J1j/jpNMfv549s3+RW+yxme5mjF6SsarbJcTy1pRGRens9xdIXjnBTlstVShgV+riTTl7G6B/er8mxVfP75LlbEbz7IuydvSHqVoyjCS65/ns8Ry7B6y7K/47scyTmdS8sq9fdThtlbHBOkXj+gu4W89SNNAlXaq1WSnEcMY13wY+FkMbrLUcJzlN2lkezsc7pYJlhwuBWnHxJ0l0doyVcM5xFOkg8ojgW44lm7P8qjOUoEj8DiiZ1jnkcaLRHhOJe30V6/UL/v0ALnEU0y8UfQX65FePNrEKbeb/lbnK7kM1OF1MMbkokSlMVZHjGaZe8ZmRExmhyJP/gjWYhBiqiEVo+W+MUsj4n4X1qIxubhA4lEH1+n+iE3V1bzmKHZTEKE0+jj3RLnYpWTf07VUIjHl9a3t5jPaSwf39HPKCECIPn6EbEZ5vmUoQV+JqdUPscoxizL53LO5XMSxzjN52Q2z+eC/sSfNyid5XO+SF5Rls85X778siLXORF0t1zxtzTGOUk5njHC73KSCeKVBnryScJ1RdI4l6bgeSJqSwQCRf8EehJKl7kgpwViM5Kq6a9f5MTJF+hW/P9GrgT5QhKb/CvZar5QPV6QVPxvcq0STpYJzhcrjuM8FSOf0jQSfwus0CVOc+k9arXIl8qOLZcCwJwmAj/LBN1lr6VunS9pxkUSw3JkloxOSYJzhmJCFSBCWHifJnLqYsYw+0ATEonXJDc24TnD15hl4oGK0vQmE38kMWYojSf0Ns8iusTqb5wru3c5ezFaJDjLcnVdT3ybI5GRfFV/sjxLKM8zWdcSJ4lkEHnGIvH/Cyp/5HBmLBIzRd63zzOOl7mMdpzri1M5RxPJTXOuaIYTnuBcrNH5KsNv0VJxjFz6lslvFoIGbhha5mhCV1xOBJmZpHKolQCcm0u+OcMZXbFI1Uin+TWN0ETNf7QkXBoHanbAGI64fD5H13LyUpaTFDOeC8X+A6NL+XAucSaeJMWJh9cv5M8ZnuY0zfVF8TzD0UpS6ipVeJSzS3A44+9FvKwWq0RQiGA4YpnNpcYvONszlGFJD5KVnWE1kVBh8J6jxTIhfBXjHDE0IdErMWFRJurPEeeMTFZcmlyWbxJk0cczRRw5+koWKz7PJyjDr+RdcsEqJ7rp8zmZcvn2QRPhRJDNBAsmNCEoyyeCbyaRnJsRWup+RQlZyj8fEJ9/SgnPijf5cLZKNIZfpxyzJU3kIrEl6RVJuOAb8osBQr6cyXihkjErlnour47LHpoUQWoqYcUyyvLoNo/u8lhwTJxIe888xgphMZlOVxl+TtOMI/nOlONawTrF7Mxjck1EJTFdkBRZ4xOvWB7f5vFdjuMZlqjACb5WXcKpGPbSXV6Oxf+3yko4x7cqoveZptPM2OfnQoTILTlCPku8TSVK9M8ZzvSTQrOUNaSnq9wWO/KpWNslAZae5HLjZK54OI3/XGVcvWqVQD3f6YLSLDlVOZQslSvPGPmU0UU+Zfn0Np/e5bNuPuvls+RuOZcEKJ/eM4JTLtFS+g3e+GQcBasPYk7NBOfDaengrEhRfZ6jdCboYC4qPY2vf1NPaq38LScxVj7iSJRL5aWkHJLmJO3JRYVJaeQqv+rmV738aj+/OsivMEtx8hZxRm71i2hRM36RICoRq5D0WiyezpfSbaRckMgCZ7nSKjRiEyw4vxEopKNVks7UcEnBTr6l+DSdJThPqEDDArErzF6msX56S8yTFIv1c7mYXRlSUM9mYcuu5B8tr5kc2ZV54nMs9BXZoqDgdLV4H3F0jbNciaG5lpLFWsYQpyxXDInKodM/iuapklLoNWZTsd6KB4EWpWbQtEj4OCfRVSpWmiVKaYa7+RKRlEsdQyyTc41qvWJWgNdpJVHoBP2VykGVzj30m/k55b8VT78XT/8Ua0eG2TWWV4rKt2yJI34mOpYvmRyja6zaYHJJXmViFf5N/Pk9Z4a0Xitpj+ElRlyqYfr5xYoVS3R5iaZIeoWRkMtEgloz1WqSM8oFt2K3ObvLswiJJRSbhbkk6CyRC7omMAH6KkGsYGom4aXhP9lSVrIUAoWW52Sz6vJbnvH4Bb4malQzjhdz+fc6z7hQ2T+SRIgCnC4VCVuaTZ5xRq4wnzO6ms2Lga+klqOvNoJypcPkNZUorytEOkEoXBFaWm9/UpLmdV0pr2hKuaUn5dmKTVGEzxU670TXhNCyQjOcy9Va3aTQsslv+vf3XAjsp2k0p0w+vsARVVqOfC1HQ7xpCuY0L7aO8lU3X/XylchWmRZFSomZVUoiMR317zMSE/N8JlQ68cKzD5i9XOTX5WW4/PpnzRSvX1vs7/qtPc+vVe+upUeGl9OpkH+EVCBAucaMn8bXv8sHw0nL59/za4JvntFb+avl/WuSkQlJBJaluJblN5TFhtvdMMne5PJ4m2v/kvltN7/t5bfP5yhNcWJ8Iua3CUmvTiO+EkSvXlgk5Vj58rNQGeTTWZF2Pqc36knepdKPYvG/XSRirRa/aab+/iY+ikcppN4upJKH87v8rpvf9fK7Ojxfc6Hrn6bxByQVIaXlSUlKrqxe7rqjF/F4dIrGo49c/uby5YyNR6+JSrj1Wu3HnveoA95R6J5SeL8Gm16tSucqp3SEx82mK3+hyyEGf1J1DMO9PFe2jby+MavMOGp7581mbfP8yUnX84CsWcW2WHvgDYXMPT48OvHAI3Wh5Q21fMC8oK6B0X1RuNZRV23zvHLpRW+tcdgd8CdFVBSzxcZ932z7F99GXDnJk7vODZI2Uu8b7n3UrnsK5NV4PGJjmI7YuLQfWnt2uJUyNIvc/31LKzfTSpBTOMKjYDwGDAaAltuC7AkdMB92C2d9IzYGeMT87tjykgde0W1h7B5y/dZsOiOV2FAdHjsQQrd07Ta0vbyFG0gx3xQ6pPe8PTcAz6l0Bv1+6rnYW4OvxXhNGcZfsTsae+BZPbHi8ueT7ahni9+T8sDgS9UloBaYpeCX47bUiHOnuBpnHbv8Wim45UQAt6W6WN6rex3L4ftMt7psXTIaqVBH9+v22cvT5x8vTz98uDx/fnn68eNZnt+v2/rZy3NHKI8tVb8DfqbQ6bf324EDft9e+cP+YME/KHxGaYJR6joT9VD24/z55YvX56fP3ry8PP/w8uWL34cbKeGDHSq2mesdq1bSbDrONzNZnpm+VdvD378f5AcA3fbJhm87VBupHviJSk+XhrZ+o1VOVOdCIJU3ENWlSP60O+Stbhh4gMHugD3hyjHniLW6Y4tJsfGg7pTBOU0b0pV6g0bRijEctxvnGDeUE8NOZ0Z4m9DOL59eo5c/yHh/0vXOgjLcIKnSnghN247vpiZWVDB0GqdsloUNx0+NIXDD8ULH0TFa/m7xGeuSofROo65HMrpaCp1OXbT8RFK+31Od7Xd7+g6lPlXpd3vqnaMZxOtrHRuz4DGGvxVWnnIXCm7n+AFIYTBIn+BB6vse92ENnFFaOJTjayCqzDDjQrPNaiyZTF38tF7cWExbDLuWAzBoEAkoZAP8FNKB59InT2DXexI0m79Rt3sIHMfH+nLqA7ii5rZpCUCGuZtWEUiLpYtANiBP6ICIvtc6TsYwWJuMSIFtI9TFftcDGQxAUq472ZNkkJnKOJpZ+HKRtFoWy1+9KTz2fYB83xMYjhKM2OaQCfQ+sXphgqJu1gXSbcDK6FQ+r6NQiCpBgQ8K0wF9wgbU7oIK0SC7kHprAeIM800AFTiO9KtkCEGBmudSxNlouPS1tJM6RHfY9u5QyPwUVEZQU68AeoYV0onnO53He1n0uHOROhYp47XrgX9SSUJv0RL8Uj5iAruAkzr6/0mFSGOZ1PyTimak41fK3MEv+jvxBh4mvm9C1ovHsoT0WgK4B35RzxxgD/A1SMk2UeQX08QaMFKbcDsqWwNKoCMXypHjf6b+j+ORtXa2tM5g1s/xj4AQ2fUzPHt5u3SdP1Spi4v2zL24iH3v4mJEYui4o4uLm4uLuDX2PefiYtx+PHTc0R/O+LH3owdQFTyQlnOeAQpT69o5IDAAqLggMCBPkBw/l0E6ImKG4DbDM5JxzIRY4sqgeyCrI8CimnZx1mXaKQdd2juMAYUBIAWvGdAnRJK5tlBPR3RsLMrtQOZIh6cnRKZnKj2BQV642cpMXO0IZqPeeCAW0aTZdBlxI5AIzLgYRCAb7Y89gMV4fkQz17NZqZsA5nmAFQfn6sokU8Ir8tbrNUiIvYZoQe8BwadY0LWv+cvLGzxZoujqUp53XF4Od31QDu5BRLbM78Ir/hyjGKQQ5zkHrEyOGEYca3nLVWToiMm6ffnBbXnm+Y7GOBN8qzjWfypWpVaruGEh1iEydVmzKbQo1k5pLPeKm00mZt2p2TJ3P9NifrL1WrB+AkszliFtpzJuyiQh6Ux2dMDE1LErAI4KHiEop/rN2TKRHKBnkqdD4iekvJWABHzVKiSSHYA8kGoSeIanlGGXAeIBtgYrsltYsHi+9sEIIyKdOgrtCafxc4FOtzYcH/GtjEXgyvvGXHnnwJhvLDAquQy0Kl8H5XAV9UoUnIuvYtg2LDJSM7FoMXK0TW9SzAQYdqhGuhbr+5H0+lxZpIOHBRszdWosgbM7wzrLbtqLsGK3ZTu+D/aCdYS0qz9Vdq8rl7ly4asgyqrYWhqr1bZaep3cKG2NoKojyjLJA7a67t2iZMkSYkSHxVPoOHpBW/5btDOXXphinMl9iGI+/ufDIYUWWxRoNvFTGJjthF1kyj2z6EuoLMzY0FdnTwpYnov5vGV4i1H9xqCaihle0GusplIFjO8cYzN/bHltWKlIR3GR287l6MUPjJ4szqTcPRr/F4amgLE6PG7ZjlxJI+xiEAC+iVXvW9isVdL9j5HH9DQpETYl8HcK5gTek0x54gn3fqdgleHn5+fv375O/1SnguHeP+gaLHaiV1/mKxyeNpsuhs+oFapUBTS9Xxu/XSqwGXwhfePNCbhfF4xllkGunlK00ErKW7QUS9GeXbhtYG42f6fN5pQ0m+6UwL0u2L5Wbg9Ic5okLiXe93Bh2myalU2shQL7lXWz2XQzIatQD1Argk2zab9VJgf1vPVakoznrUuh7XW8bUS5YDbrwQPEynDh4fNXwufvNZKLuuwAymWQCGmGuhd4QCAau2pIbEQD5QRUDw5Im81ydEwwbUnNKElohDj+6fy1PIKJtlKmrkdt8hbPeR54flcT9Uc02xTWVEGOZnnumkfopvJ2qAWtV9CFHM8NWpbbnOpsA2CYSpf/MXGpFzL5vJLP4mkpniRW/i79QCsBpTCdFrDOkTR+ekWrY2YxiBJVWvuxsaeVE/mFSxTacvvmYiBJAGxU6W3WiOLY5cqcUy8W2gHVINXf7GqUHqS1011bFIJ4FB+xdQtcksY2wVxBnJaa+Ts5pzeY3bcwJMu6ZTV18Mw+kIGh3AVQIGgYSxCkTqgrq5FbQVzaJSfgxbbzFqrcJZgbUCyxHDDoOEKRGtAnaak9EZgKShsUPqP3ICTF1V8LD8QDQsQw2wf1Mkg5uKrucCTwM/Wd9szxqf+j1EN/9In/o9BbI+g4A7s0Kn2/2r3CxUZds+lGPsS+0EJlwG4fOo6f+Yn/431kVuMf/cj/0VkXCuSP6+I2PNPMTi8/MwI7LvLc2OvMCLjbqsHr7f4po4vn+kTHxb6Ln/b6w/2T8OTI86xt0AkpJDWQiu6pG+zSHTKaZFJae9rvDTjknX4vD7wU3hGX/63f83wTJtstU8pLJzMib5086jlqR/L6IWXarCEDD8P9/cf4j8ppVKuV2sELbrd2+5q4/f3jLsB2725IbfNxwIvgSgPuw25x32XEpdLwSQX92ftV/BZeyI08pwSfKwJviWt0MPDyG4t8KUlArFUh6blaTsjXsSBwmUqyc5kOSz/oaZ6nRbrXbN6U3CwqTzzM4j9BGf4ZZXN4TdwrUnAZkazcbqZgQawlUzDQQvEqD4yMq7vTNFZLgCy8ydm0nlwDBlA4kpisti2XdHkuVkne1Zhuw6tiptncSwXHm3um/gomm83q8uKyLej2PBuQ6qeS+RP4iViCKVDglG63EJwQ95q4FbwXl0u8p0+fBpLT7G1AhDyz0ZO6BDhtx0da5gNMKNX2UsAAApm3pmZTZhv1ILlxU5B4AkuoDQ+N4AakGo1gJahvCYPB8kkyWBr2GluVjJbjrTEwYm/lw7i4PxGrklOBt1ijC8xrriWn3nBa4DCcDiRgEZj7Sw+sfDhfr8nUXamaFgLD0QOIXGhEzmDqriQiFw8gcgFmBSIXXsFeqQan4RgO+57Azh8X2eOLzkWn/fhRZ7YA5wSOnNABzsgR7QDnB2dcsphLm4Gqy12wlOuHz2iIAYKkEA2z8isSXxFIIGkvk9WMpJkYK/M1GX6lYQJWUg75QN3MA0uhiVVF3QIO7mqJx+Ps7h673HfWjlduNBR9LkpXr6JFYAWWxWWb1NyVNS6DVs3m4YHcCKu6EzEMxGW+M3A84FQ8PBWOqKJii8x3Oo/zx52qIyhzozoqruj2jFe9XuF7xKWjYOwz2UbtnjfzZSvLoa48dGTXM9zqhazcoM0fd9ZWdBburdfr6sq9VCSC5WI9tXkeA6RYa0RbrNlsdfcgPCfFVUkyMpu9Yy/Pid7Ipd4Qh4I+uR1IycUK85YSmAl1CDpNva+XwPIm7HsibyVHkDSbaIh8p+H4xHca9w15HbmxdsKk0GpgBlJIAKvssV9cOH7qOxcXEwc4M7lBan92y+/efQ+sHQ+sXJTne2ToOCEBUbFUrISC4I7G7YimEeJuBEaVlYF69z2l0dJCxxcD105Qxl9rTKWeFI1EOpQfTUcZmHreGsQVjZRM3Zas02wpLU1f5YTg6/XY88Bc8jQYGQ0+ajMcryJsD7CtZmjDg9+o2+174Fpef5Vp3toDQpTwbLsKxwFz5eOVwFRvHz1XdzNcDzwn8JS0n9M0Wy0wA2fb8nwk0D2zMgn0L4gHPhB4SVzLsOI1Ke1oApC2ldmxqMVzT4mX5x9JaSLx5wOZz0TmD1bmdyWvgia3WFqx5ypLCpJ9UIxI7oeNgrHQ/UbdMSBQQAVQUewtXlDPQq2plljxkOYY86GQ7OVTiLUSKTc2dune7r3KVORey4CXoPBmXtVNv1HXln2ZrgrA5IHRjiqBhhcYCMZCidjdb93fS+Lem+jz9+qeQbhXNPEZpzFlH2QyztZA8/uQrb0KKNV8gBXGQ6Z9ZYdXheAjdT2XgfoQ5jndGFbVWCVt7IG0dopyStofGL0mMWbgXsUtQ+uNXGebubI10AcsDKfaFOHNA/KxEb+FvKEdQcthqKkKtU2xD0RxSAZTOWF9KRzMB7gqI6RtEgMmw2DawoBKBtxNtXDHgPN/V/hOXkfKHMF+lD67W4MVPKMHNG9QMBTFZAgILegL5TGLWkXlLcfXX5Q+wLfL37y2l7G5BaX2Cz8Qa0/Cl72fazHmkVAUR6etf469DnhhvczAWyHhLLJWB7zapkg5LenMyw4Waq1bX4kFzqMihOawXKpeEPCKlGrgW6Idenihshx5tlV7U67EcZ7vdaH8VUGfrJY/kdLHF5m69VCopZYnBLDRGCAYyPjRWtlDT7IBEgqftCtyqRBU8QiNdZVes1mrknpDIoUBbSVIAPVCleLS0rcAMUP4TGBGLJbSaG0oFvwt1mnhJ/XVdKs4RXUTiL08T0pCaDatlzbJzjCKeFFVnu/xIQ5FL+TWlOxFiBtE7yPSaeMNGaZD6XFDTClpCQkK8nKZ54U4fCXBsSZlqdoBhcjiMA7J2IQer0cGRkJffkZcPkLS1uQVVY919GGZLBQggQQ7i/uVuMjzhYwtswhBMqx9aji+yyCyog/JGvJ805iOauqh0ntcPcoaVcYhNM+lGelrOtTzmBqPOyH1naX2PONZXiSGo1SIXE4h+hAwctbO2AvJ2sVeaNthKgnOMoGsbUT8t6zNNGyfVIQENZqfiPuWul8pGOEC1NTzPOmpMy2EMjnRirdN08pRMFYE9lbGkPS8tdkQFV34ddP6os6k1D75M1rEY9oTzVejYuU5z3OduAafCeyM9pwfHv2t+aPrPfZBuxMOnsCnw/8bXVxcjP/4132+/v9aY78zAz8LnvZHK2898jqzkkv8bvOnkil9JtWwxT9LeVryo39s5UcT4t6KqqQCanGhn6z6twZAVFtEv23lrMWkt+MLbrP4Le2BN0I+r8Hft9Z9eSl5xeWlow2JrdBlJqngJjLB6tU/SXVTB4/S8eA34nKv2fyNuMwb/kJcBrgXii/Qcrz4y/+Irkv7MGlDM6BPzOaKbUNDRlTuTvwmmEThsCET8xp5fydu5jWbsm9olI1BZtl+i3wYbZHSOYIYFUJ6iaIUbYrOhaCNkejRN0XErXoIHqolQbDxsD7aJXlY3ll+o+6xF/KhPndSJ4EhDoVUcuCtXT21ANfSnn6zAsAWItqwLtNhtCHTsYpMp0x1JJmgij0tle56jAdOCuUyCAjck1MGIMjbiHNW2wD5qjZAeGULsbIJUpMEpbi4GUVx6GSRE8rZP2BIEKkrf9QhmZEWfSHc/KPYu/VTX2YqEMOHXGZhIVu73DZUB1yfSFpruSd3Z6rZliXoq+EWvvKTkhKUXCBEhNCRO56x6/hfVEBuz5GryQrE1brlFY2y9eHvpAqiJ0Gv5Akrb3kegSmkgvfKkRgqaitlDL1WYDNQXltdHXW14boXZmAuo+fTVRK/ouwGMRlbbCAr3UiWUQe2ZC8RI7egLH69kVXnEH3//7n71+7GbaRRFP6+fwWFeGRCgijJ7rbdtGlNT+4zSTqTzmWeEWmbliCJaQpUSMqXiMza/+F9P5yz1jlfzw/bv+QsFC4EKcl2JvPs/ZydlZZJEJcCUChUFQpV+76V7o5yYgNekjmQn0859ZqSZESr8YBhlzHkMHn05oaaGbQxioLd7j6mrO1+0Is7UByr0Qu9ZmPAjkrFFcRXg8B0sySe1ljEjEy8HT0ia28HP0lWnhJTyXRbRb9lXyBXgiYdQBtcWmKSGLGM2e5jLaXkjHjnxEERJ7U/JMAD2qEXcq6ShDgd54GX8B+k3V0g8CNmM0gnkRfyP6zdjkZMqLNcVhQRdnk6F9HHKUmC0v4psnOyk+ByAfcvCclJhMnMm44HAVl40/EwIMvGQFRECZQYkfezYTCXj/afQvwl4Uww5+z25WCQobRDkpAZJnMvJY/ewjkIs6LIxZ+FI17474rcep9H9iMmd94C3KAZRHyB3Zw8AFGVO9k9H947jA74hn0/HgTtNgozeGm3bTQT2EGnbzM+uvejByfMvLvxfeDak9HEviffJOQRu63bovgmse9BynkY3weQp+JspXVdu70QDxwwlWQ/iCeFMuINwBWPGJMHR8+yt4emxGRNli1OFJewg8BBsixDFtXzFsmpFPTkwUnpzJsLbKhtW9h+JA+4tJdw8vBYBZ+8NQmktyL20gPc5sP2HZ3ZtxiL5erNyLKxXL05WTaKL7eXpbcgyx1r2Ev2U9cdK37HysburwlvsJnuTclSrniPEzSlLiNL5z7KFzqn11y5rLHLNm+4RTMpWylTyY0wnQEq621KEnlm3FNphJ56g/O0Ys6An/OicRqQyuc3w5feoCjshO/L1Nxwk9LOyRgZYKGAL1DWbovN2hYbJuVb+y/SpkSV5QyHwMqEbGAW3Rkxd7+oxGDHvTu+6pIgkxgjCLbqbnNtoGG5FpP2iVGgJJmZP5cnvTtyegnnnyGkaY3859jNyxLz+dyra4KDrR233EjUbh8kNgacl71vDUhje2sNiIHB/HUb+XjqFlpD4pbyojUgEt1aA1LDNogIS5bCM1+4S6Kq6xikFkdvUMJtPZcV5eXEKAPnOHKBf/+4org6kQcFnNa/STOjZJcBFPAIv0RSCSHPB6u7nhWlSOTqYbPImAWDNwGoBbqlnPwlGJckUdTj2QJihvbQhFTyDMkW+SuhldJOQjBsGKMQERTe3qb8z3Sa0izjTymF9DSPJuD7NMyiKfxdT6MEEXTL/4UZT7qdRvALydGc/8bJ5MMv6ySHz8n0kf/hDdxCfFFE0CRkd2EGD6Dh5k8RZJ8kU/EnFr9wkQYRMFuXf+Ioy/njlP/QGH7zMIp5fdMZr2sahXEyh4c7/gt5eBm6hJ9bOgUXsDSeZjSHx3kFySyar1MOxCxJcprCQ8oLLob854j/HPOfV/znNf854T80nMo/UGihQF/AW77kUPChikB3yx+WHEbwNQV/eQc+3PJKPtDHOXjwBtdS/C+dU8a/xBH8gDf0ZRgx+LOC31Skpb+sKa8d4nOLP1EOHV9SGEOIL4kIYiEfHJZk4McGESUZEgSDn6xy1YNEDU2yzgWwPHUVpiGvdiVcewnn6vCbzCUe/YIISnnelBdK17ccFfiHLFzyZN10Jo5K4CkWQGTLMOZwCEc1/GEVQoY8TdgcHh4BN7P1LfyCgyd44lXn0mtvLhEw56PHmT2J2zmfXf53AT9i8vIIJgacQvG/KfyEEz6yfDDXHKC7kCdzkZaj/D1g9iRKxUJRbocAK2e8qzSOo1Um8Cml0Zy9U8MMs78M51RMqfoTpp9LdzNyWmG2lmH2AQYd6pa+R8Ctfvw4T9STrIaXD2OjmlSOaZ7AsN/N5WDIPxLiHIY42M2sR+GYBl4UirNscVMkfOokZttOaYeNkTZSEqZIDXuiRqHuED9lKS5YuJ3WRRXHntp1Sxzp91lb4iC43bXVMj1ntUOfiERcVCTK1H5Hq3hjWkpud4bK4mxK071A08ujdvuZUVEmXCYkoGGVo24Mi65YHOtU2pYsfEbvlu7WuyXe8Dy5yEGJlo6Tut4tCWQkneaGaSiSQcCDU615nNyGsVCoNCK6RxgTYYYehnZEQgPwuFKjgTCWgjBGkt1KtUgnf0dn2N5lMG2HGDtwsZrljbPSr8LHZJ3vOjGVODixI5AYEpJisv25MUURyTFn18a6UIAJqMN07ya2NnYG/qZaMDiroY5NyecJYSSpGZ01xHKQfVMS17hGXOLzrboiqEqb+DBnSZeJHRvOtOPnEOZfVNSKVfoEwjBsrNbI+zsY7gAGQPm/KjjpvfVVBEdrQCgm+wiUQBlqnBNf02WUw32wj9+/N0spgqMOwoxDGcLMq3LoAnYkC3XHrN0+hFtyHjrssu4hOiQ/Jt1DD+XpmqJDcvjEddbDYL/I2kWX4Er8og9lL1GpDb+F77lwnu3gWqmT0TCm09E/EvsIu7TeWRs3apE88tYgnIsLdlCVwTgfKSWQLe6XjH9MAjBCHe+8bBhovxe5s8dLrLe5vuYMk7tz1OEqRFK7pJhwbt8RI55gMm5qoRWvoLnnD/TR5TRn0BugEuNAjgDvm9lt1VuvNZA5FDyesLaxjWs7A3W1RpUZPrlZJXG8yxa2LibW5q3Zq28ishGWMDXQSiJ2FnBIFtPwjv4U5Ytvkil9n6c0XO5q7B+JfawsFtfhlqif17UcFeUz9PN76G1DRA09IEIJiapF2zwyIA2yFZKUztyUiy6VtA6yqrgLWVOqIN7Z73k5UwNO8pKswu2lsQvokkxDbwMTA0vEXUZkGfLNV7x+H5VkFnpRKAKeb5Tp4CIkkyxzlyER/fkc9jMhN89Doo023MeQAIDqYMS9DUuPkrvQk3pW79J2HCfF3uUyvPlvFvz3Z/ALax1s8hFapRHLiYVchEorA//DVsimlr0MH3rgCsvlGb3LXJzVOGAaKTzPjWlQYutgw4qCl97I6i3rYLMMRbPluUws4e8NLO+H0FuEhiF8aKKqdwmWorI1qt3MfZEkH6rYbLu+AqNUliJ0/IfQewidaXTHO70SLpFd62iweuAQgRdO10rp9Py/3ZyDhs/6NLSgvmlmMUcrDzbGWSUHM1uvaKot3bM8zKm3AR8qUl/PAZBlP4mmH9fv0qqVmINlmy0L0hITMOTn+2ZDuQMtOJBv60DsQwhb/JbxE0iX8AW9T5Y0X0Rsbt1Tllv3XN5xHAdt21UpIUmUsxBpNu8saZaFc0pA4blVfIX2AKMl6t2ftbAlAc7DyQeLC0p0ZytcLBRK2iZ4GS+J8bM9+45+kkysH8UW4lqIoCNn4Ax66cQ5ecW5dgttV8ElM3Gf9pnaP06WyyiHao9vX5+eTM4Q5uT2Y3lI6SRMuvXilHyVVaeXCnPfhd4jLNXBn+SS0t73XEv4UrQHUzrH57CohoMn8h2fiJz/jS/AG/KeLwrbpt7ldi+4HLfRum6XGjpwud26aOgMERFEAb0eHiEiXGLLF+lWz0UDa2C9Hh7xf2jbNE/KnZupi74+On3tnJwdWcNXp86bN28mA2s4cM5OXvXOnLPjU2v4xjk5Gfb4H54J3u4Gkx7PdPraGogvw96Zc/rmRL3IbL03J87J8evJAHKfvbbOnLPBifxq1fMOJjzPq1fWwJJtnTmnpydWvWFR4a+o3IWX2316dTJwToavVZ9eG306OzL7dHa0u09nw1OzT2dHok+DV7v6dFbr09mePr2p9ens6E5U+GyfYH5Oz6yj4xPn+PjNRDYvqx7yql+/tgw4XnEARM/PXvd0y6eDIwPa08HRArp09Er0/+SV7P+J2X+BAacDPkxGz9WUvxqaePJquBA1PtsnOT+1Pp28rg2X6tPRzj6dDU9rfToy+/T6TPbpTM7p6dFR1Sf+sqtPZ8enRp9kLtmn12fP92n45th5/erEGp68dk4Hx5NT5+SNdeqcnPCfM+to4AxfHVkD6+jUOTsCtDt1TgdDC357/PPJkXo5dc5eH1sDZ3A0iHsnZ87xcAh/jo54qZMzUVQ8qoqh1Mnx3WAic8hGj4byGdq1BjGv6NWRJf48261Xw1fO6zen1vHZiXN6+npy6pyKDvEHgFoAOrR0+z2Z5/UbBZx8OXXOXh33Bs7g5Mjs1tFJ1Svdp6PBqx19Uk2KR16f7NHRm6ElRujZHvEJOnnzyjoenjmvTl7BROmqX1dV8xmQLYsOWDClqs+yv6Ijcjzl/Ozt/dGR6L0YJDlL1TQeqWkcDOParD/bJzk71ptT5/jkaKIGUmJdHQGgT41JPKtPYizbtQQUAlhLw3lyLJ/1hB4N9nTpRHXp6CgWdULVx9AljDHfbHXMG9c6yqyDzbuwtIQG1YrYLGJRTvkuKjni15KPlPufflfXZq3DQ/4qhQnXkpEH4TSDfxCBG3oxneWu1Tt6zUsDn5ov5F4+i+KYc97Uu6QOsKul2sWvTdZ2lrC8NwOf6K61oPEdzaNJSKwsZJkBMOcS+CuXTHrgpt+1JpRLdeeqkiz6lbqWgEVB6FrHg9UDxzP4Y7DODcgUE/3WZKK/Xae0YqSb7O02oxjdIbIB8drdgJ9igBMJOFG5zUpch2Qj4DEZKgCJoK9E6AxrN7v7fn9RjEuQtj8OvdR+ffLmFAvpzPpu2yiPi+7XXMTEmHwfet8ZJmrfwqu21uM1fslrPD45fY3Jz/B4enqKyTf88ezN0Wuh/PiKvw7PXg8xOeCPJ6dHbzD5BPK/Pj3G5OsQ/Nt+Eiq4Pgu9T0IHXHDJafg13IirmNZtmFF1td8bYiHOWMz7VRYAozQ5IfqKWC8PSll+GqUvLP5JCJrkKKY2czLwc8IlYlUjxqrKlMYQlUkotp+oUSflWFaoqtN1qSKbmOZW7imlCPoIaT/CKuZb7uVm0FiMyWehneuaQDG2DyKlMMx39lbXMZce6DZVJpWksqhC1MxUJapsNJuEq0YunVaWaro1jKTm0dj+NSQcPTg6/QVw6NXpAJMfJA6dYfJL6O20PCA/7f4Q0Yz8qD/NaW5Y2X9Cxdlbkmbkiz153j8ub5M4I/+hv+9zjUz+viOLCoryZfYp46spvI0p+dxQcoCxFx39Igw9N1TnEoYHDA5i1ft9KgIY8WdhR8pK7NJxHniM/EPUir3LygsA3C4oCqGTxP8RCn/FvOV2+3PeJCMi4Fo0s78Iq+hsVjKzvuBIhv++v4xSrJbkb7rpn3iGH6GkYQkdPm3f3fenDw99fe/FMISGUfFaQ9D7K8sSZHoey0cIpGjkomwNgazQOV9SlT1r1dJIO/ujZDjALoRZBODabZt1vOFggAm7GA4GRcEuX795g7f8zkbsLoyjqfXF999/a8E5PYbmUq9qXlGlS+94MGi32cWrwWCUeiilIr4JctmlJ9Mk7OziiGe1Uw9FbJYgTFIpVNPM20jbkFWSib9r+LOgIRiPrMJ8sgCjFPDixJ/UlbnWgBykdOa2BoZNcZ6Z1vyAfplsjGXeRoVWejfT1zzIMnyIlutllUAfJvE6i+7o180vy4jty9r8ooM+uWqqiI7wVCXJU94qQQXzYiIA19YHCFf2/eOKVl8gBrGLILIBtPtlPSFi9YQ1i35Z0y+bpSqS4mo7gWXEdiWr0BJViog1lLAw3pV/tZ1mTFkKZ5YeBe/iho1Py/OokzD6bqYcIEFKyB7fzbSfDbkcWgO56aYNBwJ6azDiNXp5UaR8UYDtWj4Slbu5E7FJvJ7STOfFYP/IPKP5qi+jgefV7duMjyrEt1sZ1Dq7Bgkb4R4dmMl225az8iJIRVYFKB9LUQ2Rf8WoYsIqwpMYawQupMMhSDpZ2P2fs4T1I4NIRVnjrk7zvsGIOstwBdor8whHHeEx7G5fVxnVrQJFBbl3eXOwycuDDSsPNpzslzdGLXkXeeKaoT4l0kCGWW1/3wLR5riRxNS5DzkiTCldCQgscZ43CRlLcuuWWuuMTq37KF9YMK6W2Ifq7YIFwUt7xWSvxrxbgcc7xoyOoTbC7r8CHktYT/r43wujEYxYz6JaJej6OqXTZHINNj7XLFzS62tEEi8foQ5ykSb0Pyh262YzOtik5cEmKcsb7NCHVcim9macBnyfrvFw+tJUf1cr/Tkxt8G4PnlJZud41LAOoM1BuoEofTSnqZXRNArj6NdQooLFh9uKMouPWbZerZI0p9ObxohM6q1SJ2IjiHpIf/juSy0dNfwAiNMg3guXCVtHNyX0YRUnU+omXmtIasB8HS2pG5Ui4HGkAjzzpoTPCiGlg9cKZVSmo8xndk4iDL4u0CRJPkRUZgTHeirfDccq72Ajs5c3TS8Xdcz6gdGHFYTfs1Z6/MA6QujcuwAbQaiMZnYrxbsqufk6yjIuwAnc1HHgrCRVcjZ4o68a4DDC8J/vGwHZzrZtjMDWxGMKKTm1jzyEzqXdHNwQiDzkIBctIaoWkne+Iw+dIyWKhXvwfQeSH2yi8mATbuN5GLhp+SLUlm5Scjl9tRnb0cl6sGJhiqhyw8LluURV2Sqc0E8oRCGiU52rTvBSPGIjXdC9OdhQjiOppDh/OhogXN40qc73CyqntN4IX0kJix+tcLWKowln0K08EeQxE9ZUArZVtPqjoBVPA1Zr4cVwVeRUAdViRdGEa8e1ubS5b1SQGCR6Bxgc/UVlmSDWkkR4YBsito8ws1NC8YvXq2iX1wzoxBdrDiu1iW0NQlJHN41sVCJbFi1XMSctcltQ1J8k+3aIyKstlqTkm0J5owWmHUQ0qhZRApvFv9Jt0S8gUrLfZq8VifyDi+z3gyUa3jkdL63sGVJcwt6D3VyKMevM61995Pf1eXbm9+1ssqDLEELYLYCzx37fHl/1gy4+6Fes9sqUjtaZlEmLorY1TjNtFCLIJ9yNlJfoc0/e+FC8KJU+i9YZxhV/KiPF2hgXxVjfOTd40JnmSEDAVDk0M5wbzuHZKPVyj/8FVsriVOPGvRmLnd5xYIexApleK3Zz4YmvjW85iKMQ7GqEOC9Fl6v8Ebk3l55VtcEFVQ3xAoZFzEHujQPCvFlmo8kiTMNJTtMMEepoEY8/KwkQVw4gWbudCy8FDGuJhVcDvLqs4UvJvytRziif6vKpKl93W2/ekFBqhHMFtMEhDgdqxfavBr4z6AwP+ioO2OhmSifRMowt2OoyCwYxV06xHITHw0DKN3wilFBtJTMYvJvSpk4laRvgJxr8RIG/w4E/YXpolDhthG9qitwjcDy5jJi9/Y2Ia/E277qU3fEod4f9AXZ1Cqd1TzUjlACymfDB3v6mmmEeTJpohrk91Y7MFb2kO0WxoxvhSyCslxRpW+sqNdZVwtdTNEK2hVw0thCQcrGeOFkPR8jCyEVWgMylA6XCEbrgpS48KJaYGVJZ7SXPcOnJelWG0tAk6yKRxosIE+oYGgr9AYlEhInhS2ApVAfjoFIPjwMVSqOiO7Syd6fe5YY6SoExMiRp4QQWj1Llz81N9BMzfbylTpakuW2DAbZ3WV1akzX0jGts0tEPJmPHcVLiOE7Cf1hQ9WFek0R4PhrUW+CysAOhW+HcJkypzcZ5gLFBtB+zupa8IgK1O+V5+qhJ2CoxpiKXKgAw6zSFbOEN0JCUytK2bSzswVo/KSEBIblmqYrloTYzZ5HSWTUTlE2zn6J8YSMHbszgkT0gfwmdaZTCWIFblBLbGLtbH1QtIhph5Q7eG2/WaeyiPioDTHKtkFAw/y20/xHawv055ASCsE5jsk5sxndXMpXacr77Usd4AyM6rAIaYrkJ32YeUtG4e6CSB81Ohshd5qH38ssnxgcQXR5EMZ7Sf7vOF5TlkRilvhq/+8yj3qW9kfpOcf9JqTxRssozVIIrb2rooD/UpdmGIkIaG/MRacHQjagDMVnlRDz0EG63WzuMRqkVsQ166E2iFKK89lI6Q25rQHhaMqW9LOT8Y2amva8nGZabKok+1LNEc5akdPoFcHhasNef42SeqGdOaOHaj3yHgLpV1jycg9fmKiENo/z7cK7ed6ng6qBxLj7Kvw5Xq4jN37H4kX8qpbee7VEzVj++7A0x1i4EbWnnmasrrIBnm1LYrX+awSnmCd+G7dOz01eYpParo9M3/O/rV8fH/O/J0RD+Hp0eD/nfN4PhCf97OngFf1+fwtfXA5H77NVQ/H0tajs+fs3/Dl8dQe6zI1HqzZtXkH58Aq9Hb46h0TfHZ5B8dHYmKj8S3yVsx8evzwyMeycoL5rE0QeK8Cb38roHMKmY/TRzYhkAFwJyKk6wKOzGx2302/ycJcxFP8M1wm4XuWiyWvHnj/hjtgjh4pmQtKI72psgt3qbIJItaBy76DbMFojcRcvYRXfRUi4fCXlp5zjA5NPMWUTzBcTPtusXAEiOSxPQekgP9HN4F1aX3KRKfoPU0Zglk9yNUvX37fGGBH7Wwcgeub7vFOMr30d+6rMAd5A98vys4+J+ROIk+XBLFxGbAgoS5XnipdCs+IiugbwgslEQ7YJkHPZ+Dfz7zvONAyF8n+05prze/SGiGXmbPX9M+fGePOqY8rvs2WPK73dk2XlM+W22dUz5PvvDx5RfZs8dU36XmUeO32b1Y8qPs/ox5ceZnWP8/f4yelcmP+umr3mGt1BSbirfZDXHO19p4Sua2Tt8TDEHOob36BD4xi+zFIV80O7rt08V/7ykyyT6lYJqAOK8W5OQCa3JLRWKEzq18sRaQrzwjHf8V5omlr42hCph6eZaVje9BlkD4rYBCHosxmngfZORnzP7y4zv+gxLx0R1I26ezfO+yWRAGf6ayHGGYCFEppYlLmXXz/eN17yKSNUcrScBn9P8SbDnNP/jQL90RvZMRmrNKScYGbHmSW6hrvZiKbCki8CFIA2nphbhIKvsP4bK/qMHp9vglcTOvd6QUI/KkwMw/QCPg95lb8iZlHRMt9leGmCXbX/gecXG+sk+2vT1swRI2e1kHlqE2WKyCNmcImW7k9XuHKhoTMso94Abrq6Y0RSS7c9kdCp50/DLqbqFJXPBBaOD0Pn0jrL802XEx1j634/Y1MblnOaWLlyhwU/prpOKLa47zBZ1wxoXoTKO2Afh6tRg8kboI3ArhUqef5JGt9RUddR6Fk6nX0VZThlNeQc1T26DJCQuP9YzlKI3m5/SdlsCGU6n0Gmd0RxvogeWtIa45PxjwhkKswLRzkvqwKVS2CtbC16NkNdpuw2Oa2qTxDFTRR1cRFmepI9K5y9uh4gbBYjsEnOUiuQjhMeDoAs1m0OOXbtRNZcr/w31Vh22McQ70ppPYydKSOR9ncEuAr6mpA3Y8Dy89AbnYa+H7cSj0idn5CXgjiLCRRHh86jd/iSTCSW2x1+FgKXkq9CZ0ttkzSY0IL9m1a5LkBw1Tbv/Iu73/poBD/EDZ4DPhsdYrq9fdq6vZbjSIU+lRSC9+56mSw+hMpwCGquMKsIOvbd+gIg9pZChanl0Ei/N2fvaV60mkMz7pidcXlZuaTh6OGu2DNMPthx1o1omLrDxAZerh+9lFOt8IghRUdRgzhXMOZcvYxpCwCwJ1nZbKkwPpFO8samsT42NDt9b61LOiZRRnSPKN8uWCpn0SG9nUZXsGDgwA1Dft6pCqCz5lvBT5m1uw4z+kMbCtxNcX8vc1pBUl8fEl/lsqeyBaCp9z4gX4fIa3Kwr1l0U4cyx+qgY5R4iy5DNBdu2otOQS968PWH/SlNRNAu5vP4r5V/Us/oUxeC1ZkiyZZgC3cn02+MqZOI1Tz5QVpW6D+MP3/Mk2Z0HuPXaGpZyUfyYef1x++ISHQZ98oXxMif/wd/gpWjbo9ZHI/++e4775O+70+fk88zboDZyUTtcrs4RQRf8Oc754yV/nPPHQ3ToovYv6wTSD3n6R8dvzlFJ/gGqh88hlqHex/8mVQsQJ4L//qiODapIDpWT1Iz8I8OlCvHxH09k/TtkrfhXMRz/zLx+2/6IC0bTLi7skfvRw3jQe/O291nYmwUiyb/vYnw+6s+jCsy/1uy+dCv/zIgtuWI0SWJg2iCYWV1YxSPkInfLPHWEHmopQzzaFSpJG96ZlqxHmAxPMHZ3FejmWzuz1izR2OvbV1wmHAfYvzI91eaxmApgmsBnSlHwXS0vCq1+Y95G9t2Fq7vepZ16duqlukRanWHTmKCDIcLAhqlEXorvEHOaf0fn9MHlW7sR+AHMZqsTHdls7PXHV/69yxE3jb3+1UFxBVIl/xn03nSdXtBxi6vx6KOgb8xbEhtShWQY6TnEI/F2cDl/zcA7gIKV8R0TN1yPNwKlgqPwUgYVqUi5ISq7CAsPz8bXu9v936ZhHrpI4zTUn7fbrTQW6M6ELVbddiSKx8hCXRoUhR3G2gu6TvZoF/WRW71P+cigPiKtgZbjmAcbkk09nQ9XcLlIOyro9wXiVmg2IEd4xEa5W810Jqe/m7uo30T9eta4ykq7eQnbI4ZpYh5lcppsI5ZX/09Hr/tzgv6E9kxIA4Gi2NuUJOSYM75yg67r9zvjq37QOeiTjKfaIhmP/cx/D8mxkaxyG58nsbehD3Ri+mcrDSF4HWsBhTNK3lBESE8vmn4uwJEF/yYk+ZozC5LjZzQSpuRuC1/IdcG9OpyN6yr8avT7ftGfE1vrK8SZqdcaksQToY/Pe73k0hu028j3+UyycRKc49Rr6ZPVdIQK5CKrQCXGkp/sW37RVya+Ay7csvFAhRjnon22iGa5jYlxB2Fofl8lK/5VCf85ZiqWqoyLaAFwKsNFfo7lUQpCWI03q3kC5BIt/5GtGGPgwyigAuEd58nTuClvaz/+cukbJxW8w4k3EAAkF+m5KhVBsG9YAmkv6Q1B4I9aYIcpSFQkjDJbDItgREm3K7Y7/qC3HynSDkjaSwyZeAYoB67MFXPRbreoI1iLdntSMxEAx1BTG7uWygwuADRbUhkOZFaYcmF+ldJJCPYJEZtQS14QtgbOqTMglvDYZ5mmhLy++yiOeYKQqaaA4wtqzdb5OqWO9R0Np9YySam1oCl1rUWerzK33xfQOT9nTpLO+x/1f3j/5TefX7/95Me333z86SfOcvqRPLQwlQKLuGImLob1CdGhBM/zy+E5HrZzTkW7HsUkv7z0hoR29UUSi3WNhbOMty3GcpCbSMR3+iiP6ehvmS0fhUNqLgGNh4GJX/bYH/sBRLwAYgfanhZ4PufLQtNGvEnlFfeIfRWxD5X1MfU2OdhmC/9taXjvMsIBcRMCbbsRyelD7oaCT8zc1BGX0ASPaIdkHFS7a7OZIaESx2Qz0rfY/nb+lkFkfiFizeOm2wTgzlWcYFoUP2UlWH9tif8iOhxclHMYvecQO5y42hRGKW+3cwjYpJSANSihSgElz1WWEwgw+UQTPEOtfpWXQoihatKurM2QvCr78yUYfNWaFY4GVauEv/6F1y78dSC+bbKcTpEYKXMoHCUgjKgrtmGfIVyW5YyyCc2eBF1keQJ40uQMKnovLGn6V7afdbE9cm9ubnAf6hBGNx7TF0O0PpSNh4FxiCv0BBzc6hRUwVo14GfdWr1VOP3K4kcrJjV591IVKIvKi18qAY5slUkzjBXv2vg4ANOifdNCQVJz8/FRMOI/KpgGfxaTwsqy5MIeZ2CeGnSZpzHqwEt6Rs08vf+RMnShuKpRzPJHSAaa38YDTkckdO12q29V1jJFYVdfFRfPFCGQkBl4OKWrfOHmlQmN6CpVFGEc6PUv9Dz0gSoqYTMIyk6YIzJjwspykT49Nml9WGqTsUjNdVm59XyyxirbC9do59Ia7Vyiph9RPUByHIzOQzZJISmnkHLIyrKMI5hJqWjeApV/3oEVO+IYkimZkQWELlPYIrqz9BZqAQzJvCLwWS5gRogk6ZSmdOouCRwQu8tRd6HvWvaGEAouTpIM1Ariug6f5YW3HN34/nQzJG9K3z/YqEK9IS5v3BtIKm/ITpQET/nL0cJF4063F2gt26MZpO/myrY2A3Jc8oqwbY9ca3zl+yzo4BEcPrLiAOMbyYrRdtue8V0m9x7VoOF2u7ULpeQKOhdOoAVhq5T54nhA0gYyEWuwok1kiHl+cE/fTNy9/uzIOyJTbwJT8xXlTCl27UhWLC+vjK+soI9J5EWXr0ZDN4ICYkQjTKKuZyw6TDLe09ak3eYIqpbzGgumY90FkOo9Wsuy3SEmM4jm3ppVy6Q27HzUDzbaMu2YRHxOS3vkwmwVatbHDg5q47/aNSYTb7UXCSbeZGs7tEeebW1elbjDhwT4GctCGJNWLro5wXLmJo3Bu/SiomhNFDWbdj0ORrcaRuF7MJrZmWSAdZYyK4qJlg3sTIS773qrXUO5qoayLOcOLI6isOORfPZaA7fvM6vD/6nJAREq5vXi+nDMZ0uw5+xf+eOx9fCPwA+svsDgKSZpu20nHhpbgcV5uRSIsDc1Rq0q1e1zIoUxmcvbUyCsGGv+WnjaFRxXHmYf3FYrJZMFnXygUzepljlQqGnJa0rD+67HSlnlWFVdCVRpeO8xGLrvwABBN78jL6/XmzYy8wrg10yXBOHWq1cCuBZ6g/Pw4vY87HYlFygoreA382TFF4cCIgzkduPtoclmRr49jQOsGeKtSkxzJMkagnpF3lPjbAq9o+ljk3fhvZMrAynrkoGhagfz0xxznt0HNR8VS3mICbtUskZrIDcgCOp43pLoxiUyZU7GxY4KC81BUGk6KNC8LBf5Mn56+82X8Z5tUu3B4Dhab3+rlLqtGnpria/dFq62OMc2HnLmStp6GAngBlG+y30SNvcaT9Gsud22xQR44PN5noarBSJUINtuWEa7k23eGOZyBzzwOgTqjCVpr7EzogWdCWNCy3JKZ0+O6JTOdnE0Fuc3222b//H4j6ljBWZUryKMiRz7KZ0hkodzwY/V9IiGZJh1gYQiXM0SCFuCUQV5i9dflmAY8iTwkONpfJB+reWFh1Vsw1Rqdt7eSOaHkynhMwR2QZPfKvyCk805aEeVrqfDE/uYpMl9BvCOYFCqbrKx5eegO6uKATcP3Aq4BhVAyYEUl1o5BGpT3cAyBW7gvMZnNTLCsuXLl12E56zbxRzoXtetaL3MP2YBHlXPHko5bUMuz+++qIB0U6JKPF8gprMcuUYKl5Ek0aQOHzzFt5sdEF949lVs6xfSGLHds6grr+UlIk5GCGox9Q0UY/sXlOKRzdxigTWL4509Mpvk3yP5fZwGJPEGzZhq0Th5CTgiG4fDKGBoQMsyfomQF++W8prUdI/AhTxBFY8MRc5o6B4pEjkMXiSANSkWJ1iaZD4Jvs71NPwG/a0kIg6i3NWAUMkeGPxsb4hH8GqKHX+oV+BI50lSRh+aslWTkoH/+Xo3TBHvd8NU+V/ZAZUoJ/2xPCHzigxNuGDHGgaYE/F9eChbyMP5rupbW3yU0NtxCeMitJQLENgXR3vycr73qWr8fnhZq0gd9e+qasgZ/u2P34X3oAeDCu1VSotJMqXFh9tpIdgJbPtZcYmfBVhVtAfoWjt+/6Ut7e5R1dZQbd47GZCRQLotrkqMyb6xJVUDT/Vkh6ZQt/tHuCSpfokj9uFpzOM59upcamquOgdZyYv9qwtD/cUz9i8NhZjA5HNTLWZSFIJ8X+jFbW0+pC5i4D8deZ7S/MKZiIatcRI6sxtmNbDwZMneUJ916hMceUBFjDMbJjYgzuz7wqgwCXDS7Z4r2wOeAORyEOB0V/qQM4tpr0fSi4E+y03OFRSlDdwdsrHoML3sGY624EQJ1Fz69LWF8Oi1+wp3Darcpee8FqmmMM5iKSa8tKjC/MBUSGHgWLXBDIMqSOohBPO+a3IrXIBj0UMUdMZXfhZgP+va40MUYNvpYP9ISsYMg8KBwTEIST06Pg6k6UbqVeyhmP2hVGNpnbCUV21MKoyS5957MK+GaCPli2yIXWa2gckytnOyAf6ajVhllrC1GK4FIc/EYQ0Xx4ETT0fpywulJcm11gkWPYREmImlSJS6EDCe7ViQMqvWlsG1hu1sLKnlUqppm42PgqJgwN/vEDcA77x83AiuHpAWLYoWhSOuatZZ7ZCqrmitdmKqdadyKpexzQglbGsY6PI9BOIRh2seQvKu7q49V2Z1Yrifb5Io7UaCv6QgojF1DjH2V5uvSn+1+aYM+usG9Um8FETaFMZI4H0rKYqES8Fwxi3t0mqQGHceFJrjatmm1SFVT7gOEtIJI5mnzvBiD3V49TzveBCMnuhtCr19m8k94alMP7ApkK7YicMs/5ITDW9AwPmdVPl2FLnrMnwuL5SmntQd5EphVx+VFI5Y0vEr+H0NvycBaSV4krA8YmvhesRLNIOvC+BN2PWic5Wv5BheVYHbbfan43a7ZdusG+E/HWO8yZr5w54XkfBy0GhMaz0jEnXDboaJTmEkwn86woZWRy191k0FKe1GDdRV6rZqIzLydodKx7Hj2KAmhIBWSjnzrlo+MmvrDRttq0hU/772xeFntgrZ0zv9jhNQ4zjLkNkVqVAoLhS5is6S1OtfWfq13a5OrgwPk+12CtFeaU1lQk19CfXAELA10KoT1Y8mI83ludt9R1Kyd7dPnUnd1s6kpnSffk3WNaXxE5XB9cmmBHK065CpPls8D0xYuM6TajdQo7wNhspnwiK9G1CirHDQn4VxzlEwsmFEa3ulMFAd5TZsCC788i1/GUZxnrioS7EriqlPVM+GYXBQzYTQUqVa3Nq/GQRlWa7TuLHl7ernOtXDXfWO82G6a/jJng2gZ4Nmz8S5ApzinU+TTQ67GWxKO2C4vg0nHzhnIUGB+ji23C+imNp5y4Pi+FwOlmzt/v7eEUAOgxFa5PnK7fdRl7oNq4p/w1hKZAIR+mm8aUrRCme0esR7QiDZLV78TlmEKVmkmhy3OYGGkXNjFrfGgdUogSS4j7G3kXYjbv/KHrlWxx654vix2wfbDJ5ubV6V4yufBV34Ws/XwSOeVxhYuP0rcbJp32yOSWmPvPHVjc+Cjs9w8RtPwjbU1MFQT2FLy8AR9hnmFUNpfzj+7SboWHDzkbdSHOA+WaRV9fbI7VkdzGss7JF7bTz7HfmCAcauKCv0T1UFH22G5IRn8fysOAAe3MhenYCL/vMil9bI1mqgQvbCHK44yvIq++06jrFtiXEbiYNdJmDJl7GLFCAj98IWYnfBRXE4KShyGS8Rj30/uwz4rw/DxLP3fX94KQ+MfQFxMUmWS8pymWqr5AvfH9UK+/7o0vdZBz62xm97/6xXbnz0/fHHn7z9/q3vjxtVBL4fVBn7IzsP5zB53cL3WdEfXeJaCXGmbXVwVxxtFxf2qLW/z7awUPb9+54YYe3NDHdGVqc/uuR4Zfl+HnSq4/JnWuw/2aTZou9nnd/fAkZkSmcav/yxDa7QsB+oxWJ18OhixNE/uwy6+FLWYnX110IcrGJbGMThkSwpcFJcb53EJK6QWSymLvaZxCavW/S6uFbuWiNtVUCu49YiLWRlhaq1qHC/EIu64IhdcKwtAIbC6voMy5Y7HDJOVvpXIqVPrqHnLh9xP+v4Aa4uVI8Bd/hiuRZiYd8eueLCNRoV4yvEv3ZQcTi+OgRE5nCK5y7u+Gx0WPj2+MrGQcfHuF+eP0JMPS+PbfFUCWwqhOtj7AiAjE8yzij/JIbaUWb1NuapfO3S3OtXhgGGXUCf5+BD8mXOpYkwzXnzfN13sA2r3ur0jcZ4EqpqbbbFa5Lw80dD4uT5+3OzpK4TQtvyRc7plz+UqLSXItZJokAMjIz64MBNVYi6Yizl3YQu4lnrQF/n4dxTcYsLGa64gGDFxW2YiZ9ZwnITm26T6WMhw/0W4gComCRxoaINF9NpIeMfFSKScDGN0mIa3RXTuJjmhQocXFRhgwsRNLgQIYOLWZIuC4j2JX555sV42DsJAM8Lcd5ScLTn6CwiAhciyG8RRwXnMYplGLFiSdm6UDF8iyXNw4KFdwVLRL1FEhcqUG8htuNiVYDpbyFdiRTyaoeM2STXDoTFLfJpAXFwi3xRQAzcAvCwyNMCwt4Wa4m5kq57/YtWr2ePWj2grZmiQr3eJazxxxhOtCUe8UeCInOCZT21Ss0FEc6RmlcjWRNeRPpWlxPJt71/utfB2L933B4sT6vjWR3EVy4LOqiAV7V6D8Urp3jo0Lu4vAm6eNRv4pImTxL6il41EJ73LDXT1JkSEsRPbOmW2W1N1RAcnlbpKkqxmVgLny33fPO7oIb6mz1yTSZH7saKzan2Z7MKGUJbVyCoyxDoSg1wGbaab64jd3t75Tuou3c7K1q9Xm1516e3Qet0r+X4VwlGDcb5lzllzcpYki7D2FvH9qYkjzGkzWdLnSAzkI3YzNCV1bFhpKzA6fh+4XSwr/cyTqoKvi/a7qjXdeVuyJPUOxYMmMwFpM0GUtiy+MgXxvZm0CE47WhubdgxdnqAgnM3qFRdECYCcoj0+x/H0OeQTsZllyy4z4L//TGSj+7/CqIgacKe+X1uov73nAt1ULC9gkGKyWMb1vDIlXuKpVYR56KB0+eVKs65OxLCi8q1OSKlzpmHc56Kxlc+Cjq+YAL5JuL7Gd9QUP/S97Oggzuj/mhXFfjlG14/D+f9OUH2qMXli4IuC6FULCBAYZEVkyinxS/FdMaK8PY2LaZhHhZ5tJTk4y5MiyxcrsSp6fq2yNarIipui3WxDNMPRbq+fSzSvEhXxe00Km6nSZGtQlbcpsX9bVpELCumNC6i5Rz7/i32/fuuPWq54HTo3vezPwedP/Mvdc5LShgdf8ypZsAZfy5eNKUKq2uPkR0IfnyMcNAUJQwBQsnBdflXSvOTmFTCg1iIYvr/pfXYkWuxA4DVEF/n4lywfPkda6/Qi6++zsV6qqXJpVMb11IbZcbeRpxEuf0r37fHLfTRwZ/ahzbudInfc/ru+YV3OfqzkGOurm82RfkblwiUmtHtX10Ir6/U5VPiPwwGPf9hOLu4DDoFXYZRjC/7ZJ3GfGzzcO6iK4mcxdVFX3JYIIm6ShQtri7MdMF2mSIxz9Uf8Xw1aZ+L+sXVRUsV7vJ1pL/Cp50ivpTvEZEdao0MYda3/axjwwkXR5esq2VVLurhPpFHb1vlxjYv4wd9whIzg0jldY39AI90Be/BANpF8rUQpbhI6dsYEXWO427E2ZZQX/kdLtnaYzhuug4wX05ZJ8C4uLo2vnQCXMCKuQ4wB1mfF3EZ9rrDx+Dav1aPHfnARa1r/xoXqnrb73Qxp+9+FhQHvDFR+7WfVd9EXpVDv+nvRhlcjLdLBjvaM7q3o0WzRtW5H9jU6FxH90n3kneu43dUY53A9q+f6Ny1AUin1rmO+X1H52olgx3tqS/9Uusfb7rYHl/dBAX/UdIPf8b+0B61bnCf3KZC8yZ2A1AutmBT6JMpFYtNKCnsmy5Ug4FP9KAE35cNoQp67V+0/PFN5zoo/NtrMQBWYBTgiGOcaoJqxc+MFN6D6lrzXbzTEUK/1+vxfeh//Pf/v0Gl+irx/2cm2lfFuOevjwbDV33bH28QH9VDcSvyf/z3/8PMeiiK/59PFYfHM14HUnX8X2Z+JOr4v80039kclyL9/zEvkD40Lm1rvwdJZS0yS1I79wbn+UVynne7mMlLvR8nU/o2t3N5HpmGbJosbXzpvAazBfSAusxwkHyCMUm7Hmp/hLqsi8617UNa3vJtqZoAD7V8Rb67vt9ziCbf/tj3g5srTr0RuY3N42nOb9ZTjP4bqf05abRX26lvpRz1/kO08vr+GLbrzogT0PGVj/kjLm44InZGN8XF+OqS02RRqdiBpp8u3+de3/f9TuH717I9pQ+QXPG2JA9KAf/hmHLphSDxjJqwNSwDZKcbqc2OP9/l7SP4Zs36A0Fz9Icb+IFNdzfwA5v+aw0oQxSv/zu2f1Gr2Pa9ahMXf6WXjc2QHA/LvmiD8wE646D3xmlBO51u3xvJantB1/4zrrLwLbJ66wWbATkZlsZ3IQA7v6sE5kznuHcdwJGHPiyVY6peDewSfURGf42P0C1U9XBrbDXT4vX9bLc6yc86np+BQinooEK+aklAvDYUSrzuPJxLqOsaLC0G3O5cLYaCqwbgFujAx4BC2B9vqbM7flDwFLGeb/SXm4DLKlCec0xe/6Iqyi4uQRN+WdT4xKAj8gNX5fV3qcYh6ZAnHULSYeHbkOZjnogFRGJGjdlszKTUjt/u0I5zWJGG2hQUhdr8dqfa/DZWZleyQfn2sjahSUNVX6+YmWjJmkj5dNkaP1kHTaTVCYViOBHZ2QXROCIGHE1QDQ3YbQxpDSH6thKiM8nEiguq/avr64KzYX2yjKbTmEIKZ83eY31Q6r/HPK11jYsrnnf7s0ht+R3cJ5RNgbE10uY8ERhCWU9/XhK6NIAoahDYeHcjorriaheAol6j9e22ddMgDcAJSkPSsJ3OCPu4/yQGGaOvRI8ddWVaZO5wGeSFNZYwe5X+0pg4KSXKzQdejEoDvvX+VgSNg5NrEe2XTgV9dPvjt71/CkdMznW3SfF71+KczqkldUwCbpBvLlL2rzghmOWrAtyBjLDr9/1+cX9/7zu4thv4vaDrOyPc5cTnIugUVwBRn1Q2HHA0N74atRzinneuf7NxO+jC6RscvoGTMwOW7jnnkXVuzGFviXNxzoD3r+zffhsJocDPfgsqdJHvnJP3xle/BeKsUzLr45vfAuDXf9ti2Hn27Q3U73uj65uNL3bQP+/l63+TjL0YKDFOs3xlDNgOnr8YXz3T4suAwrivUctZp7GkSvKtcXJT7ar8ewOFtnhOcNhXoet8tiSb21Ti6a2pmOF9QgR16igqTLE0OPzVKOP7t9dwTnh7XYhBqSkw+/7miPggIHS2FCzg6+R+t6+TxmUleSOVL2btHVZEkgbPGPVrxsJBSv3msfb25+1OLgpG7615bDT3RO5GLt2wmbuZBwyDIIf4IsyK/r6ma6q7CWZD3kbegWgNzesO4LJwBUFUlY3dBgQKt1LBijpdTZXKPV4y7FzIIp6hzyW5BMkz9idcv0Qh7m8bhTk21XIIdBuZdUmXkWbSfLbEzfEBYysvN2JBW5Ck/enq3lbdLFXumD7UAivwybyP7Rw78AUb+b6Ut5Z25q7ZFlJcitLS3I3Lq7Tm7Sv1WeGnHLsbWJ+Lq/yWhWQ/654xDJzG59JW0sAH5c7rHBtflMGjk6UTiPxRu5xn1Fg22oKoK8YlTyF378ILaVuqu3FldQ+kOxB8Ts9xNLNb9ZKVE9B2e88H0fVnPjtZsqS2nXqXrZbNvFQ4Y9vAmgEULAkE19qyfmVw3Vy5itAhm8AXH8a4so2sEE05TsJP1TT0PM9MabfV9ZnLwSgf53WnAMK1gltFjFKXWLYalx6Vnmw79WoNkFZaFMZxa8vzUrgD3m4Laz6dMNIAuHZawdWF6kkKtFsnwaW9JuaNt1Cx6meWTjxRxxP9046XnuzhCwaqumj6h2tK/w2VVOcN/4bKpC+cP1qNdGnwR6sR1/j/szBy0di9x4zL40FR2Ps+efJOkXAMJ4zCmPAIV74EsXnSvx2vlcOAPzrY8b+E1+JCCSW/m/aCAAf8g3bx3x8Y9/bU3S5xc+/8+WoqB9K1MDAe3UGxGSZb0dDSdjsF/5d2Xt0/yUmKhT/ri2F/0G7nIkdSG58BybtDjEt1q057QKnuslXDXN30TjDGTfSN2m0Dez2NrM/j1k6iKb1r/os4V+0apLr/A7G+5VWgJ9DkCXwVl8J/16pO1fL9LzMi1WXQ6mIJ+pJBsC5qxUmyshJm3T7mVETiNE4PBnjr/qXw3ilqSmLqUAiykeNz4FDLZvSNHOurd3WE81oDksubA4KP3O4/eCPK0knlLi4vcVlnL7dZM+HnTMSh3iKP1QVCM2zYdjbhAEQxK1g4dhXX1KImmuy6Iyl0YOKqQ4zxOaZV7L0IrsEKF1NwRU/dkXs3s9EY4a64Gwrun2J9DysSt7BwF41RdxHbKEQkMm74HeEuClBXFXg5jLp5jMuX91Mfwxh9/E8Ct2qqAvX85ZAa5z7Pwtrtvgwks84mUILHD8ErGEKYhOB67fez/KKp577/z2T6tUOK37Hr7mEEnt27n6KrrMYnbRPaOo1lewniDp4SfBL80e4ZV6q3CMt/vU4bN59j8gyAL6jOuPH5R6u6/XcIHeJK5R+txbgY+RD/3tqMnU9opYqitd2EuJHIa8d/jFUVypk/zquKev5LMKtbg2VcOUzI3TMzgq65MCXStM/RdtvOmmlArAe/h6d76ar7X8V7Qfsvw1bFpikH2h9e4kBbqGLqvuhtCNGBld8D/32nj8eDYKs7OpBN48Lz1nebklR5Ccjb7bwl3R3yuaJerj0U1vWKTLh2Ew4509HhxSqllxccYAs66KHDbq29KpJO92+ZnfKdsHuILg+7NhtRV90Ix1100ee1XF70eY0+Qy6q6r5Ez2ZveB6Wl6UvqlSeqUt5wXqa9r+o+lu5i1Ye4U1eW4+jiiY0QhcL1M27h1Y03er9wggz1E2dLF7PbSYHAGCBokj2V76g5qdykdq7oYBYQByCtK/qSKGEUOTUUSgfoSRGLlrHyhAJXaBu2rXzdnsI0e4PLaBRvBusC1F++FRXI8dzI11/lNOlOdZxpECPI8gEPk1vkwczU8RW69xCXZuODqXPUw8hSzR1OI2y8DYWScKZpKoDHXbtXV23+khCaaG6GzXV4kpBtQKgpL7EULLnQEbRBVx3uoRRv+jLF0zQBZS49NkF3H6qRqN6FSVkNtlEmtybUOSpUTCtsk1o3AjakUusGaF8gVyUT9Vs2bnwKDji08a6hxa8Ac6JD4BXrviKLhFWk8bkpGWSJamgEilqgNRbWZ9XulQZ+FPN+4TKIhcp1esSlbfP4ext2r/kGHubXiLlo0HVN6Wxqg4eS8X6yTA/0um8Tb0kbpBzeSm9cfgjIoURiquYO9In1OFFaIHFCzrkFIry1Xl4bqBG2vUOLWHjwoeafxZmfZcwshf98BKRtIRACv9ZIEbLuZWlEw4A7R4iK4yrRfoSWHdNAIw+gC5VMkZ8drFZfRpvmihj0RpyQNStJjpYtD6dnKQ2aexWk+YESyxAXVYfVSPdwC6EFLzv6pur3FszSpm3KcuMplEYR7/SmnVr3WFrM2LMxbjl98Per4EDFo9RzUC/P/bXR4PBACxVTz7z10efipdPTz/z/UNhkAf2eNoab+wHV8IST3pWrXbWjKf0EMTs/IY+5O/DGX3P94vKoYZHiQyyozvWCBVkM8zZSP15TIPzabJJu13CPNpFPdRNlYuLJ6rQ2iWlDJd1efJ8GV5Z4A0wYWUmgfQ2ZcNLhTnitePAZhcZyZ1p+piumY408v4FjFJ9AakwfN7OVHGM/kEeoz+dt55Ht2nmlUIofci/U1UBjyjr52Myl2nvYnXGC1Hets5338P5rvyGa3n3nAgbJVQOXOrKvdbgmRAFZEnm5JHckjvyQO4rC+gPdQto4Zz2AzinjWb2SoagX/xO8UmN40uyjFcgCQTttv3gvTi3FJpgBJTUtMKkxZmah6JojVX8GHEXvbrmIy8sqgu2tas78kKOvINj3CkVUktQqR5X0vE4vu/y5hASAkp2H3FWXX7dTMKMSjhc7e0KEhcpcu8ljdZIx1m+80Y+CfeOzJJjhVQTL1ZST4LJygEntuSv2f5c20it3ORLfG5CBOO3DQ7ILyuhgF+BBEBWSrvXrEKMvQtO2D2ESMx/Im+105NxBG6F42Z7FSO1o2uLpttishFJbmsgnV+vpKfmNChl5NWdLXCOLsZkrSDcdnss4INouZnMME4D0afQ05mFH+QQ/E/+ns5khu/jqhfDRi8S3ov1Ez0otyZM8MQTsm7OjrEi3LVXAWQg1lZlhiC2VR8sKpjsqbdyZNATMvNWQjlCFt5K+MiHATZjDohhN4d5rnLwIX705o4UJ8itN3fyMPtAlryIeG637bsmlirp5BGTxWiuNYryeKJ5EqcyQHg70FbUUuhD7t11kYW6zWRSS4Cndns7zWxY6UW2c6nWIcLAzo97AKllwNjV/V0zYdNT88LEf927ErvLrneHybJrzr0qShaYbOGZFgyX5JY84vMt9ADJdM03oi36xkntDuLGeceVPAavl6gmaLtYJQvup4pbxAgc/3L0XHsq02h/cVdAdc66w4sPxrTRMesOxTydY75tdrss4EMFJ5P2y2sWwzfa17E1dtdVD6Z0Fq7j3NWHcYdwnGfdR/nCQoddsRFx6YH/te7DDAL5zZI1mzqH+/Riku24S6KpVVeRUXzeVI7R6mDyvtziYCDMbK0vpof/ig0Jd7EhoWJD0v8ZbEiq2ZDkBWxIup8NSSUbkgAbovyGK65C2OerGHzaVyQ4rDS8I4I/Q+GHcIv5SBXzEXV5Iw3mIzWZD9m6G3W9XBzDK+MSEYfHWISQBRbejiwAtcgCUlsq7GFSYQlDtrA61ewFrtUjui0qEnJeo6YdbcshEoWkcPriBulSFqTLlxfS0yCKanF3B3C3qczEpVPzA5868YULxi9uWpCjfdP13HpP/6eu96isrlhex1t6EIqbZY3gpEInqGORWlFmrdmUziJGp1aSQrRfGUtTqNtRSx2E/N56k5kYDdTdCrqr7m2KZUxxFxFLNGfRhxWd5HQqgVAdrc5jcmHqQ3JPGH3PYjuXlu3X4J+Kz1RG8qLYlBjXlLKVRl54E4aQyIl3HzvKdHg7+jEfeFFB5JkHSLyCCLwcU8yryZ0qeHy7fR0br3ZCzK+YRN77WG7wSdUoxArPtT6gAtZLCR3xRl0GU0wiXApnzUWhuPaLY4VOkXApP6UxzalZDWkpwyIzK+9H6KlAS1YT8NqhmRBCdPyndtsOu12S0fz7aEmTdW7bNvYuN2kVDQIEkqoOhah5BUGuDkZYu83A4okXFSGOOH/FiLZWgBhlYa9HBp7nhe12ZOMS4xKTgTiL4wvJrr7hks+L0pIYk1wF4Nw/ZawxZXrCWA1LwMpmSbMsnFPgOb6NaZhRK6WrJM1BA2PliQ7DO4/yxfrWmSRLGZH350yF5kUkr9MFdLG6fMssIAhWMpms05RO3Yv+6hIOaxBoUHXbCCKPg+qdf5Tkg5bldayVKtexk9H8nXwzJ/YuTC0dQXQd2+ZCopjknpnwU+bl5DqG5Tan+Scy3TMid4uaNlLPKiL4yhsArSGpNnbxZT5bcgFRH/NUL+I0x0WIaCwWRaqjLhfx53U4pz1EhOdaXl5Zs/P2FPcgiiqVMP+i3arKTzD+8GEZpvlXUZZn+k34UxU3MOQprihVoYl4B52v2xqWNYLk/ZTx13VmBFhwHMc4VxU0DNIIM0fc4ISKYqN5IXdTkskiiqey8U1ZylNx48ybepcCSU2+zU7h5NHksJoFWtRh4XIHyddlLP7dSukv6yhV5JpqTq3qFqu4t5HxPBYNBDBm5zs+ePnIHCim/NlXbTjhahU/wtZK9Plva+h5Xgp9zOsZMElLtypdArx6LrHsdUzvaFwUQhxH0gTzjsbtNhJn9kbaU6MDGazlOoP43YdQ3SHfYQ9FNYcIn7OxrCgYVY9aSjSBc6vv3tj4EBAqxPl2W7rDEeQZso6YYbNbexFn5rIoxHTQn3j18Ba4qsOeMQg2M20rRrW33bWKb1W1GJfUMfAW6jTe9fzXcmEIoLaNX/WFor4qDbQRcDC3IuFho14+9dg4D875j8fRLFEB+yMD0cZ5IFGJkaSGaFG7bUdeanzFJCrLXBf12Bae7QJcf1ZX0LYh36rhSdB17n8Bdl1WAW9shDuhr76fm7tmReg4a2N8EGwfLMscE77x11LKMoULZhV58hgmtd3LzmHrJ7VNuxG5phpBZgH7KgW1XDR2HROGCTOlNlNBKhh9XpBJvSaucwi0kiSacS0ZqCPxFgANFsOooCbyZTlym1lB+0a2BJLduwQwMzvS68vu+TxjMTrB6OVZd1tbNXozpgGBCXSZ1tLtHRuxjRoy3HaAomfknpoA+J8kA72gjT8sDz0t6Zxvc7uGRuiP8Lyymv+vcb58kL4FBZH3PtY4lGrZiyfpE8UPkON785DxU0j6Cm7s3sNzLJ/5A2TXhHIO39/Lo8h3VXPeNTyro8waEZP8YJ2INZBdTwIRzZ5zVv1trKz/Bdaq82Ty8e4PEc3Id/rTnObGGfQnVHiETNKMfL8nz/vH5W0SZ+Rb/b1C3fqJNvlyR5aV/Phl9ilbL2nKqSz5Ofak5sK7FDvc6K3QZWyozsU5+UnCwJmzer9Po1w934XxmrqsxC7luyAj34ha+QALQPS/TsipLx8sxiuH03WPL5NvY7nXEIbb7Z95k4zkYxbAgv8+xlW5ZGZ9H9s5xl/uL6ONKshXuumPeYbvoKRUsx7EcDxtINx5fTvTXL17EBuyjqzwXSaUE6q6T2IP2SNX+ZR/OJ60ej3rO/pJMul9yfjou76fdUcX9maSLFcJoywvsQMOMuGDcP8E7jGLqqJ6drty/YcvzZeLvu8fXRbPFrJHbv+ykL44McZIXvb/+hlzA6HVlOes1e1/mfDdOqaethf0Lm3Oyki9PVAKln+frL4QmaVtRHhHv6gMDbF7xItI3XTjI9ldkcy8la725d9ZaKp8FaTRPGJh/EXVN901bGh3U4U+gp7VBuRTtgjZhNZsIwxE29uQ90QlKtm5jdjUfiIjfgoUlew1508ZXkwSlocRyz5WCLRlfiFD9H8SV9Y7Brr155x/RPNlhLAKk2S4DuDU/C90lqT0i2ry9RZJVTB9o52bq48+GvEVcrDJyxuClghXcZcue8MRbYT/c2nZRCBW625GUryp2fW2P7L9aRef9+fElutbbv6zNFl+LA2obbkH5HZOhnCjxaghXK54cdTWkaQSbxNN3XR0c7BJy/7BZpLwobhxb6TT+SqJcOHKpQTkOTcngMBmbFcmxLgEk6ScxWGeUya7l8l9HxTWAy4Vyg17HGhvFOPgfIvtre7myCfHcWCMmtVLNhcbttxhnoeThcqhNiugmYbqhHqX5izqSRSipGFF1vP7vn910OmOHBsXYz/YlGAe5vsHbYTLrOOzG6ymsAlebV5F+B+lfVUR66UVIUTVSbzcTjGJKkxLhKQgVK7D8/BCR9iGyP6iN5nHxmFAYi+3M0wm2vTdjrpDrGqKcTfqDs9TZ1qNSM1IPiKTCmMSsH+TESBTLyOJF5PIm5RPlN9duhT71NdTYf1kxNjMR9Ue9gRNKF2BPZW+2a7YXxsThkv6kKfhJDeRDio0mm4NJOF5Ej00UtYmrmYdV9tldOd+ivKFpkk1RDN3qsbhZhjHyT2dfj2tSoKSPi8KvlZq1zVxXRE/bvQPB/rGS6PYz0nEbFQgPo0voo8ME7SM5giThPcx4gtU4J8O6gbRFOHmX3iON4nW4mhcyEgoLxjyvGl1YVBDmY9DiHMYQpzDcPw64AgcQvjCcHwSkIkXjl8F56zdjuS1WA2lyxz9TDirmL2nMeWsgcuc2rv46n4V29/A/5uSfBbbMeZSPHzCZAMiaUqZOylxiYnRzXJXzzSHFivKJeL2Dc7phTotOafV4sy9ZEyD87zdjkVt9ZnLMSbRmAb6M3/RJp6xcW73WSyJaUsR0U3l0qdvj/37XtDF0rGhPXI39viqDLojXBbIHl8h/ohwfx4tCfM2SvFrXCr1QAGqYr/Blc50fBxgNk7HwyDw+Iu+3ZOOjwIVyYyLkdT76/t338gTD/hYCX6lqkHFYbOYtCP9dTdjJzkYSiQuh1kWzZlQ9lAnW9GJE7FZIld0gyCpr2Z6USAkbeVEDJVaRhVXpdBGDnLZGjUoMtqH/T7r9pf4PL/sDVU0axOI7bLmBS/Fpk2TexYn4RRieUPKnOafGIl2I+NnUUy/CZd0K7P6YIN5cr2KjTpJFmMKvf4hjbFJ0uqfOAn6KW237yM2Te6dv8TJrX754buvzGfpS0vM0g/ffWXEqqX3Fi9pjwEtRO+j2eMWLAQOQI5woALNhatVHE2EZ9yfs4ShUu/t+xuGs+6dI7LRsbJ3DgDK7kMugDuiqZKLcX/ZJyv/sF9W/uUFsvJPz8jKPz4vK3/xUln5P7Zl5b/8YVlZSmN/byza+vUYWFaaPPMtr5nkZHSyTqP88T34fc2KYiMdjglHsFltC6Ogq3KW4QqufG8U98onIaUzm43TAFimcRoUxRju3CVydhW3/APv+i8gXmPbfkbc/7Emuv9HQ9z/qSHu/wS1frG/jBb3Md99EkyA7SaSy/5y6j5k3ZRkk2RFMzeSAnsSU+c+TJl9803CLPoQZXnE5pYaOEsMlJXSGU0pm9Cpa3E23rHef4hWq4jNb3CJsTOL4pymcEIneKgW58CxQPPP96H5P/aj+d+eRXPyz2ezZOSvz6wEOnl2JeQ7suxcCWyytRI+/8MrgaST57RGHOUrlGCTOhr9tYFGfwU0yveXqbRGiW76H7wf/4wFDzExVRwaqIREXno5HInpd9PR30Ttbk4qQ77e8Dy89AbnYa+H7cSj4zDAcNJjp6OEZycRdhM7wrgodPRmK223o3b781hmIFEp6UM4adIHAlaEcnOnD6uQTenUaw2VnSBNQ6HJ4Ty12Ofl3sdgv5O7MpeL5KLH59ShD1H+nXhpCJAm/Yh0ePDQi8YsIHXyEupVkmdmPRGvJ6skrHAccQaV72vLtU1JMrHTCV/RnIVchfmCbzcuI6skYjlN3V9DoHhRTO1xCiMQBZgs8nz1I01v3YjwMt8qZX/mho7W/GecjMH39zS9Ex8z8VQKkxVrQBIu0Zw3xk9wkDEuyzJP5vOY2ltjXnsty2hijz+mAQkn1ToiSH1H5Ihjlj1+mzeziPoRGWLQL2eTPcQk3v2BE5PJ5DlKQdbPZsnIak8eRUymzxOT2UuJyWKbmGSTP0xMls8Sk2mNMCwaxGQ1qROTFcSTn+0vUxGTuW465hnWUJI8vpCYTCb/XmKSTUxiAivvduIBVdlNUkCfYMrU6g4cn0Jh7eMpzj/KPo7SyToOU015wkke3dF3jL6beYMG5ZEL2cudg5TOisKQIdLwHliXUNOjnLSGlYohUx+XNJ3Tt3H8TvLgumCtCZJol1dRzkkLJhVxy9XLt2EKqgWjBUxSJ1sk95+ahjpygetz8A+1IlslMC5hFDg3zcdBy2Dm2NByEWbfP67My5l6mD3Po0XxNk3DRyfK4K+tP2Kp8oAlpc2iKS5lX5uhswWU2vzVmDM2Rg+9iXzrpXSGlI9fuFArPf0VxUpdoRKDi9vtX0O4vgvyQO1TNaOm9MZ2C47QVXFkXRTmSbVWb7YqK8dWfTioNANX605cPlCiprkdsWxrMzN8RbBszIDBrRrk61mrPqVME7JHVILylAM+S9JlmHtMPohETq08Bn9gt5FYEy5XMJbySQ3OKqWTMOfbR4sZr+q4Ic9pysdNPhGNgikL40+SSQY1Vq/y8AMWdBixPPMWmQZ3GmWrOHz8TEBt9ECt4m/TaBlx3PRSOIDWqKaghUNumEZ4kmuWhtN3LH6ELqgX8YnTZqq/6TcDSo+JvxU2TBKWU5Z/yiYJnFewZkot29d0GoXfCwRqJomMy4h9mdMlHyn1KD+ED/qDfCQ2c7jUzPeTooB1oV4R0Nr9a7FVLUbhRIt6l/IqPC0KBGYMoKXHowrpx0r5LnZ+yBS4+xopClmhTmq3dcU6TfvxhAa2asd1ZICh29dgBakQEo0ujUR1LsVKD2olqYWkd2posCWxStEZzElPUegDi4cJ3Nrmqe12HQTmJJw6ck5dPDmziE0BAAqbhuqwoje43ZY21rIA0etY1WUSV04iBU1W2RWOwxsMCnrHqJXMkLBkNqoL2eO7WbtdFyahnBWyqQWfrTClcOsgW69WSZrTqZXwtqmVhUsq7BErkVKVya2Djdmt8gbjGk2Sje/tC3zlfQGYmx16yx55hypXQGrrQQnQSYSFd2sRwrlm2SP8wVQKgpXmNYtiU5LIy51wOo149jA2GNEQlAlALEArWpcQEk4gpQIikvZymZeMo+A8Kwq7PsKfcagsdLCJSmRFmRWxuzCOpsTK5Cg6PrNEJmXoGTJL9My6XefWPIHxFbZDWcmHGx1sWIluMMk4L6i1z3q8c0eZ1Lbb1bPQv7+b2RG+7A3PjRPSt5zT28ChXkRUdjcmYu915xN7qSUbZTWm14MmsO12OOJCkatTSlwS1kX9atj7qBuRFJfV8VzqZEma87HP3sarRXhL84hzqY/gm2qe2RlBHDKEOXOjgIP8n0VplkO2Jc+2tybFnlZDgTFRyKPNsqJ2u8UHLyoKKTY1hkbjm2cUiTix3YVDnLlAQVEgJTZYohec3E/C3EYdhKuxbg3VYLf4mEajTelG5EPEpi7aVTsSA7vzE5z7Z6Xg7o1lKSmFYIsbjtn0kgo5IUNAweAcVfGPkdhy6L11C3KDabQg6++iPiSiekPbdLuq0Ex2slUc5Yoga8ptepG3hda4EPNQCC9rBW98TtMCQC9ukySmIcPZyLZGTgf3CToYZgdHCDdI/l7mQkBmshiG7GDkqFK7i0SO3LuZqlgwodWjvEopi1Y370z2xchhJBO91OC75MTa7Wq5V8X0R9vMK/fTWpZAiRjN5nRZzhCa5dh6icm+PRdXmn6daGobJWIJdeO5Eg31WUmFBl3vhs/PwYbWZqu8waUGS5c2EQ1WP5fMf+TS9BYxqQrzfDYWXuFE/1iUfxJxDn8ZsZCLk4xIgURKQNJGVDQnBCCBoHwpYK2DTrUOmirxj+86htCXNlcM1NZHXXDavMpswSdwxiwRWDIyhRX51b052CQKrRAq+RtA0G43DldkOgg25Q0J1QrOiSbqCSYb4Rs9IiEH0h3rbwCsEi03AKsk/AT2bPlS4qDEe3vWoDvaiFQJtJyHqQm0CSZhieuhWJws4lj7TrEFX0FAJY1zpvilZSN6b72n+kqSPjalNvt/2XvX5baRZkHwfz8FhfbHBlpFGNTFF9AQjyzZ3eqWZLckt9vN4dgQUCQhgwAaKEiiSUTMzv7Zx9hHmNjYjdiYiZmN2Cfo7402KuuCwoWS/H19Nk6cmNPns4i6ZmVVZWVmZWapht0ps7YGcOFgT9nvIdZTwxbh6IFREP65BYWZ7YRJGs91YoIGJ9MNo2Aag0GD6NWWc7n6GpSRcY6C/vEIllglN1R8hLXxiW4TFtC+o9PfSmOF8cmuJCioF5wAh4bfWjqf9EdLUhifDESKGrUsmpukIqvfeszhlA2oLEXPJSeSujO6igflZqHs8SFOg2vs61SowGYCa+AMT7JSCuVraszdgxhfrPo2xJOOSK7YFjFNjVEGDeCrpSL/szKDdMR+jR1cCIaRSljAo8GFFHOLAOkK3yZh4AXkhGVT4ZCe9Rv9Qd1MIzZKUhc4G31DOs0vi4rJfxB14pqFQJXWuiMyNob0X26DYNj0wxnhcSF00nNPB9aB7d7UQC5zzgyrNlW4rhLPjLLrjHYdTOoyo1F3RSAGt09YUrTZmBmFRQXnLNoyKUPIWvBqSBrQc8wrUQWRqSmdlndzYqF5cvFy7zKUKmmEpUnm9oXV7aYvrCE34gpjzw3xQTyny0wUtqMX1rBv02K9vh31UnATUmh9yGl9faAK3ZdklZiXC07UqgHjQDsveV6uokK0L+5yd+05l175qi9sqDLuWWVTrVaYrsJKmjYuFlx1f13RyytqO9DeL7j2vqWUUPmBEp8N7cajC5UHQ229xuHawXkwx04kTQmlHpQTBSCQTsz+8nOFG15Icwuhrik1bxWTDRRLnREc8apqUya+S0NHt9APVFTI4vAaGzoWN/ygrKk1YtRUqxVrg9vezc1Nj3KCvTwNceTFPvYhDjXnJ64ZHA3BQM3UlfGrsinEX2vsM2w0vUPeuoswdrl8OHOvcYeJuixcbmn4JtdX5bacs9KRslohIscyI4sQ27Gj0QFqiNK02Md24GxYhUNG0RioHnd4irl7E5S1eT9ZpkeIynODMloWvJEbEOzLUkGmpyhC2t+2LI2XTILkjoIrUczHOGFjkWVcKGNI5yWeXJG5taPIi9OUCtBx2smjUpmBuS6uw8be0TZjA2laUZ52XY0f4XylpgaY0LxS10xd511fgEP9xhu15oxXq/V5zgSDa1lbpmGSGY50nTh7PLiESIm4ry0x489CwfI2jedBRiUniju9XEoRU8xsxPCwkiCSYK7FPxSbraglkgHFFKWOawdh2GXnsP/4acxNDF6tuxV8c++9Hjp/4B3Um7/4DupV8w7qo+fAFa/NN5HGuNNyE230C/RHjtOFLFHdZBtWwd3T72zCi+PPAV7fhqDM+2soM8cPCyk44DPGL345Hy/uuAbiYK5T7s9B5DsE/qxWGlAeLuGzq3j4s1p58JfLlOyYFnp2puNwNjY8+QEnXu544hIqcTRtsJF3u7Qe/ZcrxbtdPamwCjLHGFljRFvg36NkrNQbJWMptyhCDJzT13CvCQpAiqTmqSP5R09NHirt1C+E7EpJxBHNZG9P/OIaAN6CuFCRUrwsl9Wk98yJY73MRbrOrpvBPdnjk+2ZgrbB/kw4tDyiJxxnJ/SETmzPhNXEC9CfDk+y+eSJ/lmmfF+E6dD12Pnoifd3xobYdjErbQwDvkwNpKCRL1l+agYclzxVNJyJH25rD64ob6xWmV1pgK4s/lvMprygqkymSB1ubFRnU2TYaqkqZ/Cwm1Wv5T5V3vxkxOF+pnqo3m7KMYZSXOflPJHjqYL8w0w5vDgM3SRrKdcv2O9mjqWYFx9UONAXfWuoWdomtnFZ5MyreNuQPUFvh6C2wy7R4bkDkuaRp5PHItsAN4SKDaza7IVXC2uBnb02NgtLuwUzxX7uYamQ0StXqEbpUawaDOJROkZUokvHA6LHRrdL9MAY0mTnwtNjeibAR1BQNtGoa7/wSHl3yhiOxvayMMpRvFXwt2QmHuUIHEzlNK4Vg8/RWGhTyiaOOH5Jt8ufwirOOZO/v94+55xz+Ptr7HPWFBDr5Y4irBtFPLjynOU8D0mQhPjNxBYPX6C5exvM83mZgG+9MM+Ca3xSz5kH0bqi9Zy5e3sM+LaFUzWtXU/il85lAnNP4rhG4tK0TODXqzIhj4I/clxNKzXtR/XWStW7nF/aZluy1PfLlDYNfpmbtKWx4bUV93GCIx9HnppalDLlqdduniA4wVYbhaElgzWJzU1pk82SRtbYvsN64cpj1gtgiQSBAcWbIhAfkIdjocIGip0rj+7EqjFDKo0ZYukqkIdhQSseU9kUPfJAuSHGeOjp8p1dXkEZLcA4JOKXrWSVp2/5WwyYKPl0xGq1KJ9DlVIvzYpH+bxWVN6T6aT8MhAp9/uJpyowYSgVfAjvdk5OCBJ2CxCThpswSHsFG6u2C4sEQ5wc1YHEK1nFYKKzfx95qlmOFCk8/ZR5gTzyhP6poHW63ZSFKt4j5ty9PQckHdIEUfXI0x95lNEq2wA9HujdQHaJmjLvhzhPmVGzK108O7SG2fkQ50wUTtL4OvBxZ5KHYYfK+MGES+5gKzcDBWvqlxEUTI2pw2LHx1SWf3d2pLiNckVgzGLMZO8DMtO1bzUDokrGynHVlx4/gXPi6vAaOYuMAl5RIj4KnbBjbxSPhzr8cTYs5DqvPT3gOEc8uW/YrsOQExgGkvhyi+pW5SuwgVe+GmSBr10VbP8W1Z1nwl1Aoy9Yoaq5U2nLy/Sjr5lZYVoqOlWnKNV8ibl3KGs4U4AMuVGkV9AWWdGAGWhQ1qDgnQ4CoZ9nT+KIz+olvMbuNfh6yljIRT+YgK08gYgaWcdzo+/g+h2ua3zNQKwxh8hfAbdUISgozYfKn6tVhgLFeEj5vVqFiDHSXrfrsg3kwQZSWIKgQowDrjO68HT+E0QW0zTdysVagymi/H8wWJa8hURKZP6RB5isVhXsfPcmwdH+26MO27upzWJOdgBpPDwlawswZXbOcJaHpDN3FxRdgVC2fCe3BXbckVuyRoPaiBgi8JDOKNOyBEWhL+m88hsozgghvgr5flHU/5TisnsSzlAusTBw0UnrKLW/wNRFU3an1HTy4457pC0fvPfo6ACmkVUa4PLt9Zpyn2zQLHoSHxv/UQvBWN+cdAuyglRGVnEXQBtkhqM76l54UBLxgqIBRjjhTEJMGByody2xsYwhFZyVYaNW2YnAgL5LNmLPAg2M5CMMFKxWeuDwM4J5mL73RsF44AINduVpJd0h6zQw/lrap8ZB/VKyDuzZDo0bEyiby6xzp6vV3aUYuyti3bAvigjO9kqbKKfZ9BBkp0kYx6leVtjs2/ID6c2u4CE52dVqtdFeRJYwgB8pgdssu3q8ZSDCVk4N3H8E2IGKgraGWM5QltmzhpZdbZZX7kGzSin5VYhXrltAFnC0AC/e5RMd1QsYm31EHMdpwyXFHtlcU10CTJFp2C3DXdtzy1g56yjQIOO8lmv4pacv50FkYyqZ2ATF8wAiq9oR/Dx0CbbTgq3yuMVWDjSGTjTUNBtTvubdxcHrPAw/YDfVDXiQ5oCSB5ZzEkdkplNhvp5D+1EuJMhqpcebjnZRKfRjnKeZbhibml1tNohygttyzrEXRz7L+V0zUFyAcht607as/vOe9ay3tXPR37H7u/bWltnf2qblgIAJOULEW8B1Y8h3GaX0UqLsOJ1HS1wwoz1xoQDHIbMN6mi+S3CPBHOsfTIQ6XZF03tkTdNCfoWmyYObjsv5fcc1AhCJ3TnzZHgxpNzvd7uRAokeOU2H44hfxP7hOUs8d4PQboRe1fIMp//CeUrTi+dagbTAj3pQXmup8Of/8+f/+Pv/9vf//Od/+Ze//69//te//yfzz//+5//19/+sFShxs+wmTn27GniNDUNL3EePaK4mFTp7UXkZHG062kcNRZsw3j9ucEoWG//y7aO//cf+1vbO7hMN4Z4oXlUrKel0yEhBaw0Q3u/a7bPRL/fPRr8wCkSb+tpGrHojFJSvbUSFxCoM+ZxpgYLkeqdlWvrPt8z+k2emZfY1KPSkpdCWZfVty798Zj/bdbdty7Is9s8zdwvb1vZTy366vb2jFWgWZwSuwJuNtCwWUbp9vfz9P/35f//5X//8b3/+lz//T5OtGQpiGrSUnhGS2I8f1/tIg570em3rxDQf//1/+fO//fk//vw//vzvtDetQPlXdJA/oAM/gDQ3XYgaBM+T0CWtFZr9PF7iyAczl4JClwfVfVI+ptZJmzGXGa9ilQ/9S56ipnrBquqFHlovXuwaPVJ9cpUyfF2HlNFz9Gi10gIfon80zwteTBkkO0F0vHIso6frhP598WLr6Yrs7e3tGisZtgU75D/qesTy+09X0d7eXn/XQMSJNvWUJq8sFDnpZryykK6nDqa/jL29Pct4vLP1fOf5k6dbz58UhZ4i+M9A2i3/vx78s0P/WYhP8X+aEsvndjF+PEVgZ8Vw2X/yfawbf+s/kXDq2q3mOHhI7O0uWT0zygv3/hMwZKYVUxQXSNxJv/OQdpXFUY8bLrWtAYhk8FgUKJCW4tAlwTXu3Vez/1gUrbeR4im+besLMh5rRQGwvmcmHUD+f/WcZfY5SM4E17zRR1Utjt3fVTSIP3piPTLNXU34KdCvnhIoUlHQIdALpCgymMhXnmgf+In23hvhsUOKD56wQlYDx4O9RNWcv1Q9rVZ9bp0lH1fmMqZ0kRmWP+3+Ywth6VWzWilGWZgZu65WoCAErVPdDIvdG7OO3Fs9QK48YrivAAs5sOGKfZhJ/Ufl2SkGsR46af1egYewGrqjEIwwbBdCHgghh+lEmBZpCQiw481+YQwyqVig8xyKacgKw0AUrUJQqUbkZ6XoUcJKcXtqDX3xWIJQv4tvoW5unx7GWcoVFtTmibLmbVc5im+GWFx105jSfH9Y/rZHY0O9/SGGs6eDG+2GBXc2y8IYVAxi1J7KiyGX2VEQk26H0zg6kx4UG2n9yUVXqEX5GDPQeintjlwmdy9Vu0fbRWyyApgs1pPYeN1upuiRWN57IarSTEWVpMcjd+xwCxWIYbwWqW3XC2Xs5/b8B3s0aIN49OnRklPD1Cj6n8YME61ONcpyBQxw3U+tja1/oA0hB8ViCQueWG8eWGx5Ym7fv1ppnGprKHD+8EbxeLV65yGXrdqK2SrvJNCtFVAPxsojICz8twsHAg+KcnfQA2Y8IXwA6GrDGWEegRWLhZT/6Hal7YJIQpomPYXjKFyIJXsUnQvDgfZ0VmWKI5y6BPvcvoxnnri3QPid+L4Spe1CKm9Hhg3LhVSxXIgUq4UIEZSqVgt2s7laa9L5SDYiVd/ZDGKnHYLpiqxPOWy1k8KOM50IF2QxvFesMLywXjQTFSvn6lnZnDtU2bb2xpoSCnlpaUS4NbTOXO1wfshEFtJxTqwk1faBm03XEK3aJoOBfEsVcQ7/6Omp4sge8YBcxqBiYlE3Cm8hV3G3G3e7ejy6s+LY4eazRsXOBp71osljp7464qK0V0JEWQ2KFb5Ajf7AFfejR4+K2ojX9SPi66wzfvvtfuO3nx9o/PbbX2z89oPXiOby+11mwK2kjJkgnwRzfOTfqnEVUjOPMgiD8TGYRnEKZcoYKKDuUlkVcTO6LNaYusrjvGHuGjuR8DAbaAa8rAjRKAdkFI+H9B/nN1f/zQW3l1E8NlBq2JCcgi9Kocs4bXPhqV11CyXc0jaWXQcObUA1Uskw+TXIAoJ93UB0Tf1C11SMmBltocReqIVdEMjDxRSTDkurPdhegjVqVhxDvZmbMeKwtqp6tbSxUd56G4bU2hfFz9wG5fcWQ3PeHxii/MyNSFrKUdEY9VmRozVNMTsTWHM/VdeceLQPoyCaxG/SMzyxCeKW9naEguzVNY4IaDoFmdpIUdAwblTN/oL2MA+K/WIgPyqmYVJ6UJeqcNvhBokyzCVm/iMMq9oYpZUUDUSHyFgShy/FxsMQVcsm9SEPPB4QKkP9XK5jPDbQUvRG0cFpHrvtf1gnqVEegOl9ndhRUT4yRwo9MAbyWJfkleMECPXvdAO4dAuIMGQ4X0MmSXsG5Quj/F4Kmt5bJEPxmjIiclCQ3xs5yG0p0ho5KMsbkYNwrv+zkYPC/GHnRJT/tecEzhvnhJev2bNe7GObCHXJfgYmH3TXyr2cyr0cy70cFOvChTFD6pZYYbKk5rJoEzFPOsNZEkcZzlarRtKIjBV1ACMXqRpdLJUGnT7l4MvlrRgtr1nmIgkF8FJOWZWSAO4Fo42HnFvj/jHVzKa5csMa2bBrDbQTNrUNTbot02P7JxcWh5RuXYHici9L81eB/Ko7GTsJieK3BXjlS0Y61guBndCFn+YPC8cY5GoYqyyvhr6K82roqxhaddfXEaczC8cYGdzbnxQGk6/AGyx+kPGv2yhnGA801i3CnJ2pXr7WrpMWocdptUgt7lq+jnom99I/5D+QeCR/MfHIVeIhFYOTvNROaQkTbfg7Ym407XaZDghn5GXsLw7YxgK7wFnubPQ5EZrn7VI4xAmjgwsYIyADDMNXLALonSfYE1J6S0AxR5MlRUwxiJMgPFdT7PoLZ8NS2WBJtip0bE2ksUrohkpE4abDAXOdddqiLZGWaEuVIE6kEcRJBCaEh4XZzwfVkwg58h2ifgkgyYyOi8dHFPqPAzcML13vsxOLlPf4chbHnx1S/hZZcB44tZoivkK1MGhZ9MAhRhnTOVChop8KJrvdYG2c5l2LLl0J+mqlvYjiDm92T0STDnx86abgnu6k8HnqXp+DJ4XjvIrNty6ZvYnCxVCiw5aQ1rEhDgIe5NWhIif/rYSgIUyp8gulbli6rvL4kM4i0zV4HYl9r1YM+eficzQ2xHkR+GoIGQVJw3KZP9Y2K1ml0iYaRmbgb6oL2FY/0B1j4bG3/5HBSe/OO8Yom1fG/EB/DnJXfDy9IqI5G1bh43V5/QceBFXPDLanucaGfZiihOrgAdKdQg5r8l2Fnqlkk2kVf/Iqz6BzYqjKVnc2Ipk1Xgw+JN+mbtoCnCk7lHPiSiqdh4x3ml1AeL+ypDbmW7y1UC8rS43Gg4cU7HY3Znm3q9PjArhsxSSyXrgTZJ2S0pmddxnu1MDrBFFGsOuXZpCcRlXQXU+R8iGLJ0ZMKaKXQpe81BJnbeU8MhNV63fk3xoDFqENc8sAC5gaemba8hhFISVQtnAt1lAW56mHbY35KFQPVZuwJ2V5e5ExLiTTRKezjFOrt0XkQISeh5EzGpfC6lJ5KkbqbCi7SEXmii6XGCgdMSfDTe0jpT5BNHbYbZVOIIYEU1gQZ09vq73RrA5P4fA4TJHw902UZ5GqS70amLe9hMgtAxdxJldtG6MmQRRxURRjqVktqE1bSKtppmMRGKuy71pCZA3nmY4NG3MiweUcufM2+m3KtNYtL6UmSp8VxAsuTdylOI5D+XUtyz0PZxn9pjIFZQgxvMCtltQjhxirlRvrkbFa/e6ClzLw74VRPQW8vJVOtcuT+D76Vcp7X0PADE7C+BGdlZT2HuzJGsrpxpeJ27pM1lSHhy/vWEZF4XNRYl6RE4AXBTmiPV/o3NYWqMgiPpdFWtoQqr32IuUJeUchxVeNFjjOmoORROqOUip5Xl+q3Lx3dsiXy13diSlSHOSmuXPrmn5w/embTucm8MnMpmvH0/uW9bdOr/NoCTHOyAzPsZkG0xl560Y4NKFoYQy+6XQS1/eDaGp3rGrpLHG9IJqa/OGAH+M0+BJHxA2L5HbwzTedzqMleyLH9YhN1xRmYq2zd+3q2hz7QT6Hdy8paBI4CtcAEmS/j5afHi3x0LJJvc9fcQoEqUhuO4+WjewKSJ8K2iz99xNaCKyYLiFpBhtBX47IbGxjM/DpLvv0TQWC9eNWYbBg3F07dDPSg2d8OksYyzyIejMM7yFK9F/POpudfnILSC6gYmfvvspBFJDADWWVR8tWZJZzxgYNJWEMeeTjNAwi7A+1/xBB2TiDi267Iwx7Bv8hYlldO4qJziCKJz26zAzbnRCcdpashFrdvcziMCe0Osu6jAmJ5xQIkaJOskjjIaLsDrz9LZM5Y2J3vvtOaTD1cdoT7faT204Wh4HfSaeXrm6hDv9/c8vgdQr6R7M1rfjmE7qk06439sPde4Ai0IvDOLVhQbNljOkyrhQm+JYc0GJQgW7DaRrnkd+Tdds7KUuWtf+JHffVWws7eyyK131re22hdbsMOv9nEPEJXavUS66TSYhvB980hqWu+fW4oJV7fpAy2G06tfk8KknDbe4s+7bWN5/tPu3v4LmGtugX/dimX9v0a+spnmsFuskd7OzNXdryJI5Ib+LOg3DRslDIIomnqZvMFvK5NpPWeA0VAGfQwA3f5g9u4D1UKBvIgi+YVr/NR3gMyXSvS/LxoHZpjR9Fu5/QZ5iEWf8TIPUm1/vGnZsC0jMzSYO5my7MuRtEBZ+RG1fXfuxrBrT7irW7JdvdqrR7GbreZ7XeFq/3Jnf0asXtuytu84q00vanr9/OsqUzmf8jaJ1ZuwY6ZyPZhQV/J4nafoY6uxbq7D6hVGobSP/cTadBZHf6eN6x2L/KaFqq7RqN9RLF6ZydChTwHkndKJvE6dzu5EmCU8/NcG2JWObzred43lghW5akJXTI7+RxoQ4ZfcwdKtfxV69ATrslhoi1g5ZvmWtsau/n6CCOsnyOU/sgL5yPealgPcvlnfoyS7BnE8R1KXYsWeIAxdFx7PrYt10kX8bLCgejUYi8sROZeYbPiUswGF0aA0h4NZlgj+i6bjh7y42GTSoX+NlbX5EUFr8Xz3N1uxuxtLHj7QrJcgHBkpsWjFzerjUnRHHKZ1+55iHWl4WBImfJrtVsgi7dDNvv0yF/TCyMmQ+xOUvxxE7SmEowpnfj60YxeJ+CgyGPbQSaUdPLMxLPX2PizZzUnJoQxqkMMFxa43W7/Fk9PIxMP/acJZe6l+LkprKKBt4SaYZ9Gxd2ZKZ44nDn+uVlHvkhtpc8Py4Khg3dQkeuyXINPTIanu+xyZ81G+qBE1eVHdoIXn3uQFg8ElwGYUAWnXns47HdOYija3oIRdOOcBPdMq0OieXntmlpzJaBR34qzTAtdApXXrSFN5dXhh7AyzjeDK4x3TRiVlIWoqvX1paFhtzIm8VpBgGSdJ1fRMCVuJhkeOqH+Z3HCY7cJDBYUCo7BqkxKBrAQCPMLh07e0uSLpauHpkRviU6NtQwV/BsHAoqxcA3vbWc60A8Lj+O8BCLKKDNCFgig0XsilFgDFwdvHLcJAkXOoFtYBgMIEMalRMUFTpZrWJjAI9P1sZF/hXHBSwCjIvoeN248D3jwmvGhem4jMJAI4LisdjYOaMkJ3gec7JBKYF8lxAcTpVAZRQXNws9RLTfcgQskIDb7boQgrGgvUCZ8qavSZ/ybhdqAEw5cscGyvRlGMN5bG/kKCNxiu1chq+8UBgP8BFjgoKXpxk9M7hkzng9drz0QjwhdqfHyHtTRKidAv2ByjiWlSQPFsDL/j3GskNWnBOaxNvjEkdhX8Lj1QJAhaevcKa7ogMJgExROEh2cnHD+EZuMHen2O7kaah/57vEtSHhcXY93bydhwNKZp/soLc/nm79vni5c/n+Nve+WIH745nlHcbXx9v+tr/Y3T5Z7F57c+/65Gr/5uTg+Rd/7gVHP/4eetFpcrm18/zo6lV+cn40xYdWcHJwNMUX7K+/FX72f5g+P7p6d3sSHE3dH35Nft+aWW/Pj/onF0e0jeT33/yDy21aZn96crBP06enF68WR8HL8HL+Orj84R35MH995W75i8vtX/PfD63gcv7r9tFho/zO5fubJ972y9mHrXfPj6KXi99/Ow296Pfw6GrnmffDa8s9eDl3399mb8+Prk4OX92cXOzfHgUvP789/+n09PDd7vGVNz25OvlyfHWWHV98vjm+ejd9c7Gfn74/IacX+9PTi31ycnFye3T47ub44tXOyfn+zdGBtX189ZmcLnZ2ji9eWccXr7aOrzxycvE5Pz2wFqfnOzuXh78sjq9ekdPDo/zk/cnimMJ8sNM/vjjJT4L9reOrKaHfR4dH+Zvz/d3jq8/TNwf7t2/Od74cHb7qH19NpydXHi27OD2H/22dnu9sHR0eWVCWwni+f3N5CDATDvPi9Nzi5S1efp/wsuTk6pf8DeRDXv/44qgvxnzyww05+XJE+/tyEuwsPiysxWmwc3t88erm+OqInF78kp8E1u1JsLN7fDG9Pb76QN4c7OxeHn7Yob9Pr6b56fykf3Jg9U8O9m9PvrwC/J1cTG+PDl8enl7QMX6YnlzsL46vTqbl9/TL8dUv09pcPLm4OFqcHFBcnOxQeC4PLIDr6PBkcXz10xWFneOCnF69y08png4obHw8B3S87+T/eJkblv9rxnBi7Z4c7PQ/fDnqs/Y+9I9ZeYnfo0Mvf3Owvw3zcQFzdXu6oHAoc3ROx/QLOTnfsY4Of8nfHFgLCsNpQNfHL/np+xvrBHD5C8Vrn5Z9c76zOL54BXg8uZhW1s4R4BD+J/BIOB7XrlGGa7pOBc7f3bD/vfpycr4Pc/Lm8BWd5603Bztbxxd03n4/PLnyLJiHL5/7x1evpidXv2zR+Tj58hnm6eTq6Ab+fplSvD85Cp5tvmX0YPNg6jjfGZzsUWGYLChDvctSroOMMzF2Zxb4Po7upZ3XXM7uuWEwjezOPPD9EA+EkmfWt2fxNU47e4ymcqKKOrOtNRnwBVl2lQKrwMFv0c2nki9/m1fCmNPjinP4+sccXu2GJK5tZLaupNutewzKJ0zepvgaRwT7qxW72r3MCYmj1YoZeerYnGPi/ozhItYNCf/lkTTkP7NZMKHJhqFDcDpiJqzNQ9aDbqDynYYIoqCbcxzl5iygR+cCTKRJzM98+rM8jslQiDGvQjzHEdE1V0NLMN8Atxlsyt8IePJq21Rc/vw6To98eAXeQHF0EAbeZztFmpsGbg+uujSbZhYIm0KGMVg0JIbmI9BMvc0NdqJf5CwS7ECdlqtcjYRag/koR0sSs04El3CaO0s49rXnlo+nGgL51tZ6/DNPbK3Xf8Y+/PgmsjVLE9Zzx3kHbqL9rBOZb/MUy0hF/I18fS0sWnY9rWCQXRekcZIpqFRCPrIsSEDXOM2COLK1vtnX0HWAb17Gt7ZmdazO1k5na0dD9EtDt/Mwymzhy3pzc2PebJtxOn28ZVnWY4BgAQXZJLCNqNkaSXOsFagBcxKHi2kcaWgJ3FNma/2n5nbnmbnd6W91+tvmk84T8yl875rbnefmU0h/Yu50+s/Mp5CgQTRthvxHMKPHbEZL9QswtpSPWa20/rPkVisGDUVkI3s9eZiEsVu2C18QoRE0AakbCdWsVAh0LHMr62A3w704J7IY0xWkMRWjf9ehudN8hE2pKFutNLpCtHFhgHaAo4tTlUkQhjbX94dw96Vo++H1Aq4UKm+98HhNMktbrXDBCRM6BPVKlrhRRQ1YJ6OSod1KbjvPGPsodCvAk96ji2SwjFg8mLHQWynaovVlKUuauhm5wLctujilnqJu82IfgwrvPPiC75nmKm9uPhmUiqbU9YM8szs7bMAP1iKWysOXcejXge5vseY2OxTtIxiluI1Q5QneK52lk9xhAglooHzsxez20GbQU8Eon84UhH771KL/Db75hF7DDHsu6HxkGxwNQLUGDe0V012t0YKtnzPQ7JkZBPJw0wVos75A98RX9HdseKX2rqqHZ65BdFyZovOPbyl0sASlFhDQ03LDoq7XvpXcKv+o6uts7oahxlXXtYsSxn5c43QSxjcqq/EJmAaS2pMgLS9uOnudLoJ0M3QzQj/5jCpD7nFKxGVCZceUYyBx0qFlG0VYxFU6DfxnowRfXDBSprRfC6qArSHfUay7aW9KFz6l3FCs0yExv25CIoHSNWay1LH+1pa6tZXcivR75verytKxQVFDGWED6f/wwO7rvhzsfSXVQa1DjJp+x8A2OyRds6T4XlQaqtfms8/uPNtQRNdUhAcPbvoTegnH75e8eo8LxOadmlWnuSROGgRXqD9uZgHBPXhlgAJ0k7pJnWxuK1S4vAy65wCQl0DfdDpdxaCVo+HR8iQvBuWFr76Ed9mApPN46KDT1Rgg7GWBgLhh4MHFp6LNf6v4Ex9gSlmA/v3RpH/N+4tvn08udy5bKBfQirarVBndGnj0Q0zcIMzey0vVdfSSrQth7VFfUgIwsSCKNcRSuUMt1Vdr2vjHqf43bIvUN3etwbKfQpLn6oRw5Chz8r7C9LSdZ+2n0D+49OS5nnImQ1wDde17VHj/kFirXN42NH9Nxd+DBl5waLl5wr8KsP8gaOXgnpb80q/q3bZyIV9j2XiLEc5IEE3P2dU7rJAf2a51L0OsbFxhlGt3Mpy4qUvwoMksqmTqbi5VYVDLZrgBgF3Z+uxE/6bT2aNHwfIenK7btm08Dm0Q0X8vY3+hNt9eXN1jZftoo480CL+p9+ZZbxZMZz3Bttt0gxoCBOLL5rl4VXI7LbYUZXddTq5/zQt2eioJbb8eVKjtV4UT/4o1U1YS27zB593dGvZfypLKpvsLBveVxe/AijqWbyfwf2LLfVC3nBQNOxbdDwwVa+jDJ/RLhRy3SSJt9PNOQaRmIPFA0t1uPkJH9wOAyHRrdwrK7ZDyVHE27jZIhGU+YyNtuWZihGHt0bluxBWRXQBSE3Z3Wafyekkcpl17Ent5JrmD2142c30qCVnwX5/ZLN0PBCcVUJIZoQ4/lUZoMH3A+ZVWaG16hLs6ERUlyCKhCjeMTMlq6eZtqpv9XXRHb0bZXSF+fLI/lc1+HchtYFSx8Ymuvd/UnbVWTr9vbbexJWtP9M7oO7Gvf/7/v/ex6BxulH/P0U85wgkiidOwNdFJUo1TpoYvN6SXI0GR00ep46bTfI4jksloeS9SiJgn3SHBHbUsN4rGxj1e4cL5NAYL+FE8hsAQqu+pMAWYBRmSLRvFQMeJ83u+Wum/5+D8au6naXzjaPBHQzgxD9M48eOb6ByH2CNx6mj1lEqx96mbJFgpxROgkKhxjt3Umzla9Vspgn148UuU4J9Q4G3oengWhz7tRPmAzB/SOE8O2AUyza9+l0UOAzBf4gX4V5n9IyPCPJt/QfYbUGEpPdQSlEJHBM9FPv2tIXVZ4BE2D9+8P/24f3b25r2zY40drfzWEM1/dXrx6szpb48dDX7y1POD/bevnK2nNBl+s/S3+z+8+kibcLZ3xo4mP5Xcd2+d7W2R9+4ty7nYf+k8Hzvaxf5LlvDuLQdq+9nY0cQXyzt/u3/wytneGjsa/NQK/Se6fH5iy4f5VSTO6Kecw4l+ymWD9Hc5RvrFAZE/ae4YpYmjffvMov9pKKYfTw/ofxoK6McT/MR/4mvIpR8Hr+h/Gsrox2SX/qehkH5Y1jPr0tPKCxYvUS5YlJcIKPVL2DxlECEiTyruRbKOl+jEGGLh2kMqNQ27zDAKlKxpgyQ6SfRlgbCBlmp9uwqIdH9pMUTjhjEmiY/jG5weuBnWjfJVDQKBXgzF1dlP9JIQYXAfdqwBedGgRWRz04BIDyX1IUqAGQ7TS/4GOnMyaQIo4qOVpmlDbONhPZZOfYAlkigIygvBmmFrWuUbpmmSOBM4FqowsECbmJl3o8jBJmM2UOrAO6dUoPJR7GCw72JBWzitek2Pb+zzAS9rJst2OnQTO0sQ54a0LckNaZt6vFoFwzCx48TgBc6YNKY91RBnqdKhFsWkBw5k2NdsTQTXRIKZ0yYhvtUQ/fdQGjFrzIhZQ0Jas7U+pSeciYqQVN7KMJ8aYoIMQVqXXRRr9vJOuIPEKGhhgSFavjZ+7VvsY/DQ4ePR8ijDRCuKwjDQ7O7pyIDG06YFekFo5M8deZjh4TK+PWc6I63UGcn+2JR1u2SoEXxLNFsLohlOA9JAIEeNtr2V3GpI8KGa1en3IWEtwjQq+WkoiJKctGBA9idwSZk6dWJkAQmBRTsU7C0vr/bFsDcH7FEBREGf2BBLzrVbiN331gch7DvlFfDWLi1A4sS2oPVp4rS3UdqCS0jFjYPG71Qf0A++JW9kNRyGQZIFGe8fATt5DlpVjWlVtQIt2oaLVSq5pK3ug14Bm2x5XOBbMhRLxdboODTEbyTFc7gbbI0MNTAT1+w0KdA0oRQRXa7pU6zQspOBAgZrP01QCU8DCNnFdcsekJPYvt75pMhuagv5DuT3reok394zPoqXdwlQxLl7y51v2eSvo3gal7C1Fponz+EqtduhQPFhkaHWt3b/polH/enuZsKQZiW3lPqQodajNVg9Y1Pr7CS3TXefXWM9aWCAsumW2CtXQUxXAd92bOVbdNlnBIImXCwSuSm5xoDmz91bviui1UrrP91Vd8Zv5dYQSR9szc1JrFAaiierffrojBER7YTTmwrx+XIU+fjWfv78+XOkycOpl3FuucfFlF4PzxOy0OzWlbVuQa05Wq7yjAQT6ZItm5ED2oEBwRFh927w5eeA9DIvjcPw0qWHCx8BxdSaQj2SwpZUVpmtfev7/voKs3x+Wa/w5MkTTjNv7tptEnDmd2FR4Gmlz3dV4otpmuLFfWcyyEcl3QdZtHrS0CW+ndx2ACW061d3dc3W9Eu2cTTlXkbwvmJ5VhbaRZzYfUssn2e7f2M9vbnvLGZSFdCCCWN6UOpkCYodeYJJe2Z63uqpE9PcLDHsaJg62rfYov9pNul29dRxEwM1+aXaKcmwG0vuQXI/FTTuUjy2nEICs7tcl7T+3Gk5caobrDazbdtHZZtqwyLDOLHdhA+HDLNEPiilcUfpXuDFkWaLRXjGCDZbCHR+zhPmXzPH89hYQ60jLlqGgfcZpgfzxjnvyjLdLAMWNiB4fgaGWziFsEkBpSEoU2c7VGbbYwAohn41OLCZkTh5m8aJO3XZUkVET9GGxc3s0rGBKm5C3NbK0CPzdepO6W/mgJOaFB0Aa7fbVkELKvZkSvlNrSPpn4rawkApdw+QgZO7XT13Ah0j1zBQWzdvErSs2OylJv2CYDrcjkzgSrMzVALkJ7pWA0NDMVqK0naGOF7tsCgtBD0EEWNtHjkWtRZHOXAOH5OWlxdKa0KY/tK4LgZRZo6C8v3heLi1Y8fiUYE2JDOzvQcY1rG9EggWNmg10wObML6xM5LGn7GteXma4og51onU92zjbYnv4yDCnptQAppHvppKpTuZXCJfm2CXzHDa0TbTAlHZer9NC9cy4o+JuqpEO70gooxD0bpEwE6QMsWKoeDWFjMFhH93Ov3dTt+i/z6jCTSPrsb2xlwy09DSt7WTXXNnt7Nr9vvHtMb1E5dWZZrsrc7WrF9J6G1d956EvW1zZ7f3xHz2fL/M6z8xnz7p7Pz41NzaKav0+ubT552+2e9/ASNFdPDPocib4es0jnpgE4j8YG73nzwcYU86zwFXu53+s85zBtDZPwdQxjWEd4LiBakXUkC8WyrfaMhbsL+prT1bO0kc+Nu+rW31NbTgf2+3bK3/xHyyq6GF/EmHUqpVLpK2Q5WRbYVeZyguCS+wdkCx6wTelRWOFFrOXjUDRs+4Y2/7wXWFhGr3co3tONxPmFMV0k7jju8SV2M6vcxxh636LHg0zygEhx86FvKctKkZCiY66N8YvtKa2o0F+gM63Fpb1GEPPDoOQa4TUqIniH+46fRbB3SeoOVnvBACIlLOzYrld2027ICXtDFSj1Y7Q3Cw2mGvX9LzVNJztwA3NKEwFC/2tkF2IyGDgbfPx2c2H+0rl4p6Gst3TRK/SxKhDERaZ9X5f/93bc2SVyqm5QNWXmvhV3xFcHt20I+KmUBJ5VTyK3Ny12zklXlIvhr7Op1vQ52CHFaFmAZfnYaHsCj8TZO3ibPkp55gqq0mL1qgo6p2t3zZDtfXLorvonZ836ZxiG1NMBaBb6eb2kcqo37UNmNEEVZJqLMqMYy95o3AXq64Bw2V/mn7IFIrAGjcjv9tUqDYKNDVuoELbhI8tQ1d0wwUOPHIGiPXiUf9McpkkZMa0ytpSdrtBjxseo3YlA9NjcYodUhV9Y1ix6IkdRC/CIQmO97cZKC5TjCKIey1l+gupz+ZkyS6i1JjkFW17jwIuWN1uxF77SYzWEhr926le2rIGq58ODEqdIICA4K9jggKxgYK7+S7wbFGsnQRPK63YRnI1YmBom4X64z7xsiV13tLdjZe4HRuByjD5Lz8DhHTsotTKbOzokCniWOh4xaGEw4tN03jGylKxGWM8QO50YPKtndVvToVOGaBj+ECESSOgAobbUcbonQkcaf4Z7y4SN1rnGaYSoFAVZLyZg/5FfUxmkjyM1OOXbghLEGc37/cCHgonSboNKGnh5Zi1yMfxcH5kW6nj9om5k7FMIVOODbQtHazIw4n9bRXwGVn/cHMjaYtuKK9sBC5l9h/uQCMlUKJp36FUKBKfLnx5ZsER8ivb0LLQBPHp3tw5vh0D87rJRI6mjktsXDmtMSlLHGGJwaLjICu2xJv2xJv6h1s9A302bmhPbxybmgPb5yrRJ/BSzXo3HljlqsXfYRPZf2ifeeNWVvB6OD+md0XLzblCRqNYcfsjw10dn/Ng3V3Wh1JUQ0mWr+Z6Dm0fIDysYEu7pOn5a7GLEpd30AfdU1D9McC8IS73WuTi1DKT8Y5MudxmYg+osXYQG/v7NVYzvSzPWt4ZlvQB6MdCzRDZ2MDHd0NMaxsATPEHHc4kHqg4xJ4eJn0QjQeoAv0cWwMNtq2iEwD70E50g35Wz6KpkcmcdMpJgaleUYxEKAyv/rWqfNjD64sTdf3IZjecZARHOFU1+ZxnuE80VAK6L6jJIlzb4apAMqKKt3IWimex9d4bRdK+60llS4MiB8wNgr9Al0qnQHO7hoyvCQmEYj3HIvhOHJKXE4x4ed89nIhCWNTkQEen+WTrsNohMe2eH8b4mBMMXlJpfIgmh6EAY7IGQWIH/xrsnVDXLsGVZjuKuoqRZkW+CJOUOakZjyZZJhcxMkLxx0on3uOC5E6xPdm/MJxN4PVSs+Gzbb0JYkTWyleGPYDSvWCzXjzGTj/weFLJ2yCbtnBcHUvUVlWXRRdzqnJeIf2VDgxulkSJ3miKbwYy2F2az7OPBz5bkQ0m5QM4YQXAnPXOMzKTK3KFIbqZ4j9y4VmezzNF2cQTcxgnC6aIoImKEQeykp2QxVk7QllOF6rKTMUJziypzSDHkv2AikMynmNQfmIanfv9mda4rCW+IomwglvHzVYmn3oUVSx3yIvAABA/7+MMyy/L9AkdAndfLLGAfKEwY59ye56z/DEvoZ7IW6wZN8iihgIc2pfwW+6h+2jRD9AZ1TmLXSM5gZaOFNmSXDpTOuWBOjamVYl/1tnatZQhm5YWm3Q6DNLhmGjV7wXUQi9caZmZaDoHMorp+m0cZpOW07TqVnHDzqjbQsMoQtnagocobfO1FSwhI6cqSnxhK74F8UUOr3ncLooKdhF22EnE8cGOr6nrVPdQO5qteh2/dVKXwzf0APJfgVRYeiR5yIfvUGvxgZ6dN9Bnd0EPNiL52a4o9gv2betnAEc6sMD+VCBjXt9KnZdptj9PBCNlIZP7c3oeLNv/E200qzPTaXWwIB7+Qur2wWDpqFlw2cVpHxNkxSudY06jlO2QZvdzPeUBKV9HW/md0HPjMFsmBYgLrfoAOXozdhAh/dNiFCwfcaLg9jHg15/w3GiRLJhxBjC65iNiAHNC4xHOjEMm2w4DoXp9OLVGWVs2CfYs61WvrFaLYY87WL/5WrlD3XilJ/8N9Q2ut0D+XBVt3sNguOCMngtnbfA+Fk/GF2P0YZlGPYb3bDbxiEW8QH6jK7RAj1Cr+hiHhvo5D7MfdQx56PkY55o9HFsoNf3bCe+AG4EW3czNtCXB9fpyzov7zgcg4meVaIvwaNR63UV10m7ghPkVa1Aqb4QAaAcSgfuUHvc1xRuv6Y6E8rRjTUFDoSujBGdFPnKwdlWYZKgZYon9hmKGdm3T+Xt0TFiahlm8S9uZYRdG9dSSeM2IVTaLjt/F42D9XLNhZaGAqNd+Thbg6ZMGv7G6gEPj0apom97q/N7WhW6/jVKfjiJNEQSfRn49hxR9F3wh6rOkRC07RMURz/jxSHlAA4ldl+jOHoZ5qn9BaXySerFarXhqwh0cxIfxPMkxATbWjyZaHwqvHh+GbPLoyPDMNDGpNvdOG9fC5f3DTNRbZdL26OKtVOBEgPd0cmi0knlmlL2c81Mp2fGuk448iZ8Ngs0MdBLA1214v82Qcu69ZDdNChCzNjIllZHfKXcByxXNcHDs3Rm37avgoukvHxlTAuAL/jBCot63dAuf0ZNZZTtIbgXsS3l0INw7IPjpIx0EyeZs6zpbGymgRdqmtpnqBZRNGvixkSZlI2+gh+RXdO9sZYUtQ+tJdfuRl8ahdJiUhFHMwKfJTZmr79riena6LehhoPSoqqz+xZS1rHN7fU7pmlqKlXYKDX1VT0dA4npmJcFX4m8P0bw4NaBx/B7lEDQlQQ8+bpd1TeoNTADi61duvQJ/86Gs9GdnqM158qtqrfxPTFgd3kcqbqrJLOQY3kVNykruYW/T2Qgv9boEtJTkRKrppcf8+H5RnEI+nbryfbW9jOW9iCHmXWRjNfFmV3n2rUmcKEav4ahEiz9WPQaxMCupJS+VEoya4sb63AvQ+aG1bsJyCyIai7bX+3D1ul8nZdfp+6txucU4n881GeNuZ12Ok3jv6ZrLF+wImp2pyX2Y+mgXK4WWUo4CpZu9OvX3Do3wvXwsuOn9Lj95xbeXZCtW5QtPr3t0TDv9hFv30idDgsBIBGtrurmEoa4N2vWcB2DcFpIxLWE4ec5fPq2y9kjcWJ3dsvBKiGg4GfoEvxB7+1afzMGlc1xR9yk6hqthA2phedQmuPBKmC31bJEIBpzexfP5Z/ajMnv7HoqMaEs/ZJ8C/QV36xbh/wgfQBC+RIHLG6VWBURVsuU0smaJ3zpsevpTl9C3jyABB7aqfUDj5UtYx2toWfHDqc3rOIO6mw/QR3agGX2twwky/Wt9QWtZ4aEde7eltFSVDpRhicqCUtjChhHUSUBNQfOztrt1Xp0qBTO3CmbaPqySg9xXqI7qtydO9+RNMffjZXF1Wyjbo1u7RrlohPt8kCN97ZTncb+llFfv/RfkHFkW2tQ0Aio0dZnY28WIugasFKPaqxUJfhXGbujHnS+3HfVyXwC01nP6IsJEiu7rK5EcembW8xQm5dVtkdlEN90vvK8V4lEwx2bp997bn09D9BRiX2VDXhwG0Vlyk4SNUZB61Stm6j2s5EPiT+ooISifK16SpbGCSJpY4NAYLxul/01iXuZncXwBCVmj2x/SZzXia5duJeagV7Kj+MgI5qB3skEeG1BM8qu/0hK88A/HuZY7fTXuTLyO7GKM6OolnaCqBM9zLM6QinzrE7HTjRKx0b5QN06z2o5oPdJxV4uMg+4SS/cNGPUpnilMg8olekPu6XAFzpBq9VL9ucd/VPo2BgSeIiNBdzsdrEIysl77HabjwbUinBLtTCOSmEboz+Yxyori5bymQY6tloDCLxPbVwYCg5+XYsD8ThfDQ/iIYNuV/+ijPGfH1+3qwPSul3aFPq1dQAQSr6E/sfSzBNFKHU0bRBM9KaT62qlRfn8EqdKmpFuOngg3sRvgmcEE30/Td2FGWTwV8cGRAJgDrq47pgLFkEUoBEZG3RNpvR/m47W0QyUbjqRwTqDJuDVd1GtVpCUbySXI/1Q8RNGBEWOxQYcNTeYoWM1SMHmJjzITAC6NtDUHmn7vyToh8Sxyq3/W7n1mS1Oj9KVnrb5Q7K5WQL5s2J1a4kmf21spS98mjc3C8NApKz/u0Jhfv/3QGF+quwu/Sc5pgyTt6LXNxN1bMpmxObHjwDbx48OQbgwmEGvbB376o1Qt6tNMdknJA0uc4I1usLKsqRS1ocJ0Ih7yZ7VVivqWhqHWFP6iVrrpjluq8yurIWnMrPdTP02g7ZyecV6NRhHfT5RCo+4sF0YgVHhIH4RgSVhOopVn/hY+MTDi6B0AuWTFCM6TWMRCSA1DPaqrEHPyNPYx+zxbnPmRn6IuYK6AXfkEE5rUycqg/SiGL5g1O8SWvNnvMjgaVczyC7cy9dpPJehKOTdD7d5DESj0mSO3T67zkYfZc5Gf7C9BfEQ+D1bt9vfVr9XK911NiwoKkcAKlW639H2U6dSeCPudrefqWlDPXC0lIR0QtMhGIOc4lty4V7qgWHD99sUX7NvJPqyDHv7ebPpHeuepsum7FpXlaZ3681A4WM3g8LVsk+cCnpEYXgEtV4auex8ql3mZZRnglt5NgV6gOBJlAo+W9aDmMuBHy/XzXdkwKVa5NNfbH0OmOHVaMze1uW0hr/0TJdjGa5cxGMgfmngVnvppwp5CpDfzIKQvcy04cDbLGXbhlEgUqQORjpxYqOkgII+MaW+npY5BlIJpfKyvkPQTwk8ScMe4XHispx0AFPBq9loBhN9Q8cvrNUK77Fnk6eYzll2EOcR0Q1DbjwZsJzZnMU8zA0li1Ft5xB49EZZXE776dHSH4ocvNkfRC8IxP6h4EW+rhSkcyhvR8sjhZ54L/Agba+TlnXSMvgPA5HvhzUg4gHp9QZtbZKyTTJgnEnLeGj1zh6+v4UaVGLvqM5BZaCSNsRxxghO3wd2BlcIrD++sR/c3QCvQQsu+8Et/cgmml5PlIFRI+aLDSjmiUpEa+tip6UqxQlqckDvqhwQfxuJlBA6LZIFNC/OqpHGOTA85rUE466CViIPAEkVEFHspCWYgZNK4+cL9/JAsSBPmeEP2PpN4tTD7PJJSIgodNLa5vOUlEpjeTUD6pe5iZOaOLoO0jiiZ/lAjPfIzxzl92o1Es8g0/oyV3zBK/Bi5fhqTWET07aY/M3NF9bAUEuDxwDlfI1qd0qGWF7vEz1WZli6XoCP2MuE7v4lA8dCE3qeMzHyl0R9u0Oa06xWupZHPp4EEfa1DSGRsFfq+GN1/CbOgIexfkmcDb20CF6tNogpLF0rHzzKnpAfy8ezaAv9otATA1Gg9ImjSIIkZpxXWt8X4mD6khhmFs9xw10C6GLyVeMRRLLbTdeALZhORooLw6AMYYtwnFbF4Tr0ynxJM2ixqXwUg8OUjzJnSdzLMzyx1dK43Ifp2KH71rcxXzcjf4z4UqHyMF80NFV6RMXsGtyOu13dXa0mhnwT3+t29ZILlHvD8QwUQJbYpGVWYCB/cxO1IICgjMebElLuu3IpzpxlUAGQjBEMoBwIUUCm2CDFIOt29ZlKBpzMQDkkNoHODUQ2N9dNzkwKUjG4oQYtjFOFDMLzkFT64NR9oz/gG4ZzNrxxwYhRiOm+jSjDw6tYjCWviiy+S1wQaDXDYLZxhDLkapucmZKC8kafAsyeY1lLcBVimzo6UQ6F0kUH1i5pp710387P8MRAAS3DyDBpJcJEckOI1FmhdlpM7qDERKXDiDQFG9Rg4RhBE3heFizcHEpR7CwLFDjVCGNAnxnHJN3CKOMUOcEopUJYyebuOdZqpcejaOzgUVRGTowLnaCRJnCqIU3iVENaGz5pMuBTQxrgEv42cKkhTeBSQ1oFl8p3reG1uNSQpuCyhKzEpTY2lAcKK9Y03Anwd9DxBao90Qe6kaU9Giw0RUpRDKyULJ4ExjtVYkZ3iENQ3O3GECFP2RH2hlXw80/hMXS6YeNCj0z5NpGiKI79itYj9v8KrUfq10x9FAuuUiWlccpK92fqw+a7WCQ4c/iKDO7VRPCzIBJqhIirEZiSh0ilAcNpq0xTul5G/MyRmzNwIjMjLsHmPPYxKCtFzfJgjFerjf6G48S8MeEtyez7be0zXoB1IJWoQctfDPqO49ADwq1ufgcbIBoR9kqvS6UiDoATm16cLACZFzF/xVeokanUy7EN1nkGigSx/suExtgHoRHFdGEd4jS4xj6AQU8ANset66MFblggrKGT2G9toKHAryJq2Lct2kK96eq8tniA9g0uyPPJiRCdWLsJi46Ngs53H2aNFuK6H+Q6Jy6ZmXP3VrfQz4muSP69vjEIHCbC1+j6kFUKIr1O8F3Dlt6HkLJaWajGozuBnE867HKO7jrS+OqoBT/Rq50hXFk5/zZOClw9KVR4y0+Al1JjFLPhwj5BgRPzo9d14ioWJbPKCjgBSuVWdxTKK6gEYjPpdrt6fT5co25Kqac+StnCXkdoXb/Ul7v+vwN9eVY9ObK/5OQI6ieHOt/2Rh+1MAGqWSSzVVWNO5UU5XDnRernO5xFQfUsot/yZlajcqgG2yC893hSBtuKS3Y8/eXEOpPE+p8hFdU4Sf8WKUPJQ47XM2V5qCHXpzxZ3OTJmDk6cS/By4/yTnftYE/Zwd6/hx2cV3dw/pfs4PBBvN/Hj8S97DG0o7C24cLahgNzB1hgie/UG9GQ/5dtxL9qB+b+vTp2Tyyww8A/qWspYVd6M+x9fs39+FC1xrvErzA866rI73t3fiaPPRFkaUC63ajblWK59ClcL0xzOfoe3aVXUVgqYRzSpsYEhY4ulJqpGfgGKCy5HqSiowSVZEOvgXzKdruXjN2ZsI8zPEGzfxskLb1fLFZ+qpKqkIoDWoAjRBFulZ9qLYEK9pPK13fQzjDQkAe0c1ajnQHSMUUKHiVjJ0d4lI0dF2HDqAqs2FgSJrBiNOl2J5SvLokuRMhpRgzMh+y+2tYmbphh4XxdBtR22wuUftseEsO0/dVKz4eapcGBbxQGhN9ZS+InComf/Hsg8bMqiZ/9JSTeX0/ik9ID7EBJ3NR65QRKsV/60ggVLPNiEWpMha2rtyVXS4H82uHh1w4PdnDM/7Iz4i9m1mYPZ9bqWkpFSRk7ipoSQkUofDLEgwgogSVqEFPSQi09hzCFMsr/bdDHO9SGyggFGXwA8fPvInigwZsAxctrFC+WFC8cOxkjdYKQJUwVGfgyKEUlNERhoGC1yoYpp0EN8jP/CpaJ96UMvn2ftFes7Jx5befMazuHaVi5z9jUd25dPfDB0Hmvk4fcppeycMJBoc0geaAYRDc/O71dacu/1wmD0q1ANLCrPHnVWe9gttZyu/FOmxf7+CWtZNYCEhdVz4GWtz3rFuylAfsa23L1fWbmoCgt/puuc4ptdAXkt6levsocR274BgKqIGyC4wTMEjzXDKMw5DAkkqUlda3hT4+W2OSPFJp5FJCCGVU/JO1TDVtVf7A6/Ka1i+7AvFFHvfAR3C3nXXEAeaIsh3VeEBP1wevLOPRL1wWzvjPknniYmTq8jM3tzBUz9cu7HgdsmymlbvWRNvZ/coWovmbClr3iMhFH4YK/Clw2MAnxbXV1rfPiVNuiBKCX5Z6Hs+xh2JBv0pu8Gm3iojHGWhcpZtZ4X9uHqPegToJoEn9tB7TOgxrHaRqnX9s6VFrXfEf6KFBa2FilQL9bHm/8agLX7ex1/OAayY8kxU26CwPZ+V6+2Frd/g0aM/hGwRHvYV3TsjDzx1j4jn7r6tPG0dL+yGnbIbHFngdooRXq5ilPnT49VazSL27SfJu6Uyci5av5nfYzwnezGfb/dWh5jS5KwC8bb3+LRWqHrnwrvFylrc+aVtb2VxHHr6NyTWBF752HL/2vWL1b61ZvfQWWryI+/v77bzqd7zsv3Qz7nTjqJGmQzXu+m342vSyjeY+/AZcfH4+AS/ve+S50o2nuTnHvuzEFK0lbsziQj7+vvpb5TStmaDedhu9Tp2eZ8AwH+Hhxf6NOjc8oX+GtPMSepMLfPU798mlidVVDDthUtKTfpG5STa57qfO115vHX3pwjMB+2mGFe3EzrZLASvGnS2aLZIajTF0m0GxretaW3EiCJf4vc+wHLp1U6cF610zeN5e1+am+Xw4dPv6+cxD7mFGwjM3q3W2Wj8YLZkaSLVPx7W16jEJ/Jok/48j04jlYg5QpSRqH8VRJ8GOPyppKiue7xJVYgSU6y0J920KdLetvqCP8nNWOEioj5hCZideM6coiCwru07J05M4xLMQ7S0lQQfmhgEZcFXTmHaRCTiUUtzLebDG/jMPqaL7dcZ9dXm7X+7tkz/DVyuInOzs7/XpZRgxjtXOXkLRHx6f2Dj5NKoQzV61zmQchCSIlJYgynJZUVkDhWpNL1x1wYrfZcVH5074OskAlzHKY2N+6dAfqEvWxF6cwTXYnp0Ij3by1tVpDPx9EFSBJs9QatLxbRQqOSFCZwTwNla9rKiRfhri52nYs1HlOV9uTltXmkjQPcR33LIpvmfgZLyjFalnJuxbq7NDGn7Y0nuIpvlVnZJ7EKV1V9YXx3KpXlUXVKY7lwdsiizC0i+rEDQNPLczlaZZR743hVkDFBc8ZDpN6QR+HuLGkUuwPytecb1xde0uPOI3yGp8MdOkrbwTXd6kalIHndSxzu4y+oJ5DwAwMvlnjVyyb7g/kuc8idDVY3LU+2ELy5CSRF+PvLg2q1HSrokaohc+osTG1d/3XhWy5r9558AXzWpWj8q565TuCvGarYkGKhiJkgurGXRMlVdYC9Bdbu7uoU/5jmX1DJQSf0LW6BIRD/qPlpV+smbtP6BaUQwvfpHMsFVu6lqRYM4xP/8zT0hWE31NNYlycjr3b8nxURJVvarzRXTMCjVPmZ0hHA2yQZsPAioqv943qdzfFhGIhJ9iH5/F0rKjkP3OVvAzGDw9VC6tmMorGg4YDrPABTW41FpFxEeJRNHbS8ipAtv/KL83TpVF2i6JTqkEV1bGDEQEvwDe+02YGzhvodnX+S9Faz13izXC2WjWzGFt3wgqI16rbCs7jLw8pldUKKTc4537pqfTGN8gsjW86Eb7pvKKyt66dxh3MGuwAwPSIm2Myi/1OlieUjmO/RM0bn13BVH05PwKGMY9LPRQ/dPCpln5b4LhWeoixMmCUWVkO+5UbGuY3qYyVWe1zKNrs4ctVx4deGMyR88BvManTEipTzfL5ZU/bxAU6W1sodYOQlbnwHUiBzns9ym3lc6yht5De6/GbyCP+6YWB9xke+r5a03iPB2JmzZ+uLcUiSQfRlBU89p0lt+RZ8HhmEouPOBavuZsfn2O2siGMbuqc+joxBlEZHT01hl6I3fQimOM4J/qxPyJjw45M1/f1VJmjQ946FHAyTESNlsCd2Ayy/TC4hvlvgCGWCsBiFLCZMSEQpkkO92KW4mwWhz6byJMqguAOiDdM92tpupZmzrIo0GvfWQbZKwjDt/TiaBJM85TFj7OKYnDiK8vrMojqPn6lb4ra8giPu129nuSMxgaqJzKfG8IzBAoaQeIxImijbxSoAlAetYEkfQoHDQgavTcexE7F3GzoG2S1SunQjNVKjyRsbQHmMQ9dD2FY26HcD8NWDzgg6CpYzFWJVYI78Ne+yWfInGLSbpwhaZByrVZt1cTXOF3oFd8YXom59Uq0kHEZirFAvEVG3fldc4AzXR0ieu0z+5UvfsPMBJxxOVnOnNFY2Ycvfe79UZpKO1UfIvMgz0g8B2RLz0x801GSdf5YSPP8glxNKaqeYkEUkEoraKNP/597K6nBC975zEYY3s9gpr2DYFK6ZcF5C/7H5cOA3a4ew9sNGokTDRZR4Iw0Tw0CqSFNBvyWKTIEv4a0hYa0PAHvhptIG0OUCUAXPIC8QRttHFn7HSaTddzbIOtkszgP/c4lpqnXgQ/HlQIIPBSowiESGBjH8Nqzdqsh/vCzBoy6Ni4qb01UUONE7AGiiD1AFI22xih0otH2GHlONNoZo9yJRrvjwYPwxwy5Sho9wKDwm43CscOsAUbZ+EUfoj/LDC0jbko0AzL38CgY9/DIHffqxXDka/CUhp6YfpAl9Ihnq+Glr9NDhWGhp22GhoHIC2t4XznPMGyyZ3W79xXMDQOlqo8gpVz8XEL8BCl0jGjHJciUqK5WsbG2fW0z3NR6UJweg7KiAY1FKICJKpf2Hyojmrhpho9gL/QtY7Wyii8qGVM3ctM+wmlu9iZxLUkOkYeS4+DCMEbWWO7N1UonEBbihEKHWhrmZwbdpejLnScUilrIkI4NKAm+jLUWWo6U0uGxraVBKmg1LYhSQau5MVwV8CwJAw/rLTnCwCE1UL8dptoB0oZvHtin/Skd2YoOj5+2E+dqx3HktThKrEVFxfTXWCqIiQ0UgZ9EasoUZhLyHviP9/jy54DYbVKEoOrdrvYeJIP9JMFu6kYeREKRRF/8EBIAiD2Is+nZRZx7s9b22UHT7epaHMEzMYx4BBHPWa20uXsL9d/CW5tllhm518HUJXHa7dZTzGqlPWu14kUOOaCQ2+0KuDsB6CU95fCrlDTkWI7wWybgt45HgUkBJjupgIOC7GCWxnN8XxOPWbHHgUlwRvTWxvMMp/tTcDsuz/ZfFcFSUm8UMY+YSRjHqa68N2OAhdKal2oG2KyeT6wRDwehnrLQ7AZSyrCztFKIqVNEKXHwOQIC+CozeQMil0fXVl5KwqZ8L/23MzcIKYO4T1f1ma9rt5ph3LkVQSKELWi6SYIjn8t59UaNNV1+aHS5+Oe7/MC73FBljDxJUpxl51DoNyqjVCdisyGQ/HYCmhN2U/miiu5hZYj7INU5GxY939wg/I1NSb2LHs9l7YqJgqQzlwRxo8JjtTmk9sg6+JEervTcU4p939KICjkcwmVDlC1y/vB1HZsRnkJAXIaiff8qzwhd6Zti8dCyxveV3noNoIzHerXDXh0gwzDsNuz175iwD5UJY6u4OWMf2meMFa9M2Yf6lH3gG6XRC5803jTfPzytMWss+3GlSRXdopfqxPHU79saqgyhOncfLuKETl30fbWdXrNDdVJkoVpntWn5UE5Lfb3sOXcvAfZ+SXWJ3bNo6uMSXawfUrUTwMV9VeovpDHpesksJogCYIFSlbhjhbgPiBlkZyQcRiYVIxyyfttgZdtskjotIJVNYvPm1DqIdnUuEfUuC6LpS7C7GEYmM8CQdJ0WYHm91I5MEieVrIs42UzRZ18nNcKMIiaWxA57tEyE/ycqKotBBZIPAMkZ7CmBjZjZQDjVUfX0B6LH6BGVfMP8qSlvciLw9twu+6pXUZu0S9C+aqK2vr9nqiqA0SprILVlx9Xile5qcwInF+Uwa1OFliEbUnVXIbF0a9upx6bvJdwT8SVdb/MDghkn1T1Uzn9981Ta/MDbLHSCcPVAYWRjqKr+XN/Xrzg3YestSkGR2XLEWc3TykLqgeRsMJUPm+zq0WNbVcJyB2yLu2Bb1GATZNxqkOMSNvhSo4D6NQ8DeXbNg0jurWNQVkEcTOlvTdCdhY2KLnXu3q5vLIhqjTUKV0Ndfqgol8nIgseTR/0xih0y2hqjwCGj7TFyHTLaGaPMIaPdMQodMnoyRp5DRk/HKHfI6NkYKXoP5DN1x4T9mcGfktueU9GamOyZS4h3x3+OLFAajOKxo6bBE8AfDJSMwrHjb86+hyK9iYFAB+EZ6Fcme7c8qUUaEfbKwU91Y3nIW8CjfNxcGkc+RT3UlzpOM76JcCqkHcTe9aSlNTRXGl/oBLnG0nco1MhVRnnXECcOzUIzB3xieuAz8FjnSqFsbCB3KOBphwaaFNDY+t2FK6DLgVI5ek3ZPNHQtA2pDQTSXUex1zInRRWokTvmrbO3pioSwYJLAi1VFPG3UQfBq2TsjuEX31lqcHPTo+RNq/hwlUu2himFiq4FrtzojSE2QK6fAO2NljuRLYgel63hgzG9vXpT6wRRyiLs1ajXsG/3+oPy8kYSsk0najKn67fVXeP77a9G2G8PR9hvKsJ+ayLstzsRRk/gvfph1I4yOOarOGMi3F0oK5Dmp+60B5eU1XUIdHjU1Gx7Vc03DEtDWsnISu03hbfyUc1WlONVbGhjA9V7r2j81RsAWIe8/w+1WwC6xCofa28JqutXGxsF+owXl7Gb+nZTVatq0+8iZiIcjbI6Ih7WMzKD7FC4IUEb2O9221J1Y7WKSpclnmp0u/q5rxOkMZsRzVitzuuLnlmnNLM+lFk8hE6KYqc9ptywPdmuDbaaOwgmesxupo5en+2fvNIcx4lN4k4hslcMIXZgHtfUl/HAB7HJLD7P4pgMoGb53ez03NdTJ0bswT004p1gPyDuZYjHHBWp8Fi7qwTBt8RNsXtXGWZE1VaCX7YV7ErHQq5jDfgjrZF5Mwu8GX+qdfupHTiROcfE/Rkvhj1cF9HckCgZ5Va0e9uW+mDp9jPbVRqqid5lQw2aatfaeV4BaB08DXCqrexYFWh6a8Fp6gQaA9uCprJZMFkzgGYblfrbttvUl1RK7Niuc08jT2QjchCV/N2yiXoBvndtviTuUhBaG44TrFZ3qaRoEXe1UrW/PcdF1WMg4FS/pDtl6K01GmS6fSB8E6NQTRGmDC7IS8bdbrpnrVbxXh0zTVx2u+kLS7SgDO9mhnGonEp8w6ijEd2lDcB+WwNY0O1GL6zVKlAAa1cLdrvR3oPA4kWsQg+Qa1BK3eA3CzhPoeadZ4bkx+E0YLdBbeV9HBL3NxQ5vf73/OtDJbQ1XQmk25W/I7j4g9IAxSE08PgJRJkoUz48fmIg3uAJi5kOwqySoJPvnb6FIvqvgcgG7SbagMheVACttgeioNico16EemRsjwiKxgULSZ9SGS5w0lF/TGdIvfqGZUnT3vumuMWicskfOU4XwuBM59RanlliMqA1VcevBMAU9iGxgwdxtxtTXA2gr1iRCWTVC19plq3BG1+PYVek3W5gCivHD8z0Tn+ss2W4cnMSG49lKLqYL0++EWhnQUkQgonu7lndrh6XO49+p3S5KmkvXNhbJUxFMNEjFY7f7oQjk3CwdS/AgC8KRVaBAhSsFt81auKLjO2QEg56ApeGdmJf9As94tHeUYwCiY0NyqfKXZVn+GVMZu/p0tm/xdmwSWS63ZYNPtSDYYXcBd/X9+p5grFvV8SHuL0QxLtvuwyodi3h0eNhlbauaddWS60FkfeuP2Q46EH9ClWD7tJj4SsIPgocMDwrk5DrxJvEjEFI4eomp36Nl1VqgUYwrHzKFpgyzaneEoowsTpA5V5memrsyd+RMQxWK9fOVqvQWK3uJMk6LLRudyMyPZKGP+NFt6tHLQqXVlotqSYXz+IIOqjqMgjSIFVDkWE3a4D8BwXA/LBSr8zTwEgCdAOVcyGY6O99s3LBvlopKfKauu0aeFmg1LFEMAhQZtUbG+p1mFT9hFeTbquKmnxNLo58DSWGYbfB2e3qHDU8AUxrmmBw83omGrXAwfPXQsLz84SBwvs8OVd7hZuaajVZ4HBdx7LEybquZYl3rHNFu+ayLVfZ2CmqEoWI7VUlrF9FB8EI6AVTwQ1r3yNrbCuG52FZc0PHJsfJBbxwpiU4Yi/QVJKZzprJLNlqRVmpSg+rVR/eTqkkclNGKm9uVNpbrdgab3RE2VflE7JPzt++OTq9eHX28eLD21cfT968O3+lIs/jG4KOSix3iGsSMb2JUKYg9v1BaKNQ6ugRvukcugQbEPo8mGO65dlbXEG3CzbHRxSYazfUA6NQIrLpAe9UHFiek+mBgXJnCb3ZHu8V+uJfHwqUODnX7XDwkM9TPvCUD/SMbeNz/ie38m+DWwkEt5IgicuBq9MvFDk5IHXSvrb+P/b+dbttW3kYh7/3KmjWP4XYhhgpbbpbOrTfnNqkbQ6Nc2iq+hfTIiShoQgVhGKrEtd6rua5sOdK3oXBgeBBltLu/e2/19qNBeI4GMwMBnOYxZM+P57pKV3Hi9szzMJVnN6eYR5PPuvShetXHRPxVrFCXMQOk1RwSAAp+L1Br8fgZO24d202XE4UrmvGAFj+0ERTDf0etq/XAyFcGSzZwPjJSSHZqhyQugN236c2m9wMRx0UrW5PEsASMVpPINWxXARo7V6Ar+iCPE4Kmk97vaB5nDGNCyJsgesiQEJaPM2poElG/yLpabNpxMJriT+rUwtlFl6je+Fg2Os5RSsoajcPkuCrwb9YeI3hnxXCLLz+Vxx+K7FB/ouiFvFBeDiQ0keJf7jB7N41jhZw51qXCLeT90kmV6nt6ncmArZIIELlLCWgd2sZO+eVfw4tvGJBxnRCSeoJ5lELOe8l4RMyFvbVzkf1yGoNHwnSeHPxF4WvzSXNpsZrYywfjdyHkJo2GvSnoIL1rRimpBD/HLdfEZWvSvupUsc5g0LX3SMakq90cc3oKhro0vfN0rqyBiJB1ZUzUFSha3QwwM0rj6zSlGRlPeceMSyxQDVwQSqNET9X/hj1E6feM+sftOhe/2KN9lrFTnVll4EpTlxTWSug1Df2ZYpKXOyoqJ8tZV01fXgzt4nPwJPPyRZ3YH1hoB5YYDWx6cMH2VijFC2e10ws4oDWDVrcH3F/iFnt871BvQLFTHe8zXIj7hzWXmUtXaw4WDRwjIXBMPuvVJXUVOhxQ6W+2ZijrQ+PwWt4JIkfp8GryoTBtUrsqI2aXcjmD03zjgY3ddhqIBHVyRoikkuqwl4OXDNpLUTXm9rQmskeVS+zJfdx0RpfW41ViF19aqJ89QW22+J8JjGxC3DHjUJl8BRbW/9MW0VJwo5p8Tx53uxGtUCngUacTusqyE9Yb6ct7bJQMHnNubm1RrGmBY7qQPluywVDITpySsGISRWDsU4bBHhtYgP5EFnDN2kvmnalajDl+gsGVkdOAYyzxxD13pvb59itduzpe/dgrHYdjPddB+O9ORir9sF4v+NgvG81+PsH4/3+B+P91oPxfvvBeN/iEdUniXj2YIzbB+N918FQ1nDVuRgrg7mtx0LV7zgVjqVf+1CAMZvEszE8jXcci1rzQbN5ZSnnMJnTtvYd2JJRtv+ZBkKbyR/B3zrQgcVxW6LWpIq6Dp1oH7qyhURRHd1d4ze1ctXHa7aoOjaFihxsO87vdx7nmsWxGk0dX3lZOXJ+a6K2e4x69y2sc0yanUKSjGfx+jqqcep4cKod02rlOjVm7VpiSyo56RS81YxDs+lAXl47+gVjYLdbY444a4tZTscl1kgFLskV+pmrjBF6b3Q1+CUdkXOVvk01z5JCy97yYG4xEW5W/blt2NtFRIxCURtAdBvHQEJR+K5Nn96q1qg8/qHmZtUdJ916aKshP1Oucqepl+PsceXy7UpbO5mMRfyd6Lub422RG5p88OZqmjtuP4dbiHDjdN5ca+uZbYInZznZCzqmokEI/Eb9obx28QB8ggdOsfKCteU7Z7LXLHx4eP2h7ninbwMuOjewccukOxDuNVv020extayOlqD27Tiau4529yS6T/mWYZsgSUkhOFvtOp6KQji+jvhDxwWgVfa+q54SsNp1HcFLXQ9fFhBLmRRBPY5Bp+DeKbN01gRxcKucWH2wBHvYBFpjem3/UUt/TEyX7mJwXBWB7/mo7dVbKfKJUZP+76IIRv0P5+HRBh3elkQ3/IPRHDpQfp+/pvEPKf7JhpivxRdY4d/shykRTpD7MwjVVuAf7fdt4fAxmbSrmHhlT4vH+XJOINAFFpNY+7bGJ8KjuUdOf1Iu/2tia0UHA9wIj4GvuLKXkn9DYLEoL1FERuI8znUk7HwS/5puNuI4I8Ljk9j3j9+Bv/sk5sFXX3/1FcKy1MDSCeIzCQU7A41Zr+f8CNBm4/vQaMRgeTrmwzlkjZuc+n7EJ0gPzybxNLk4XPNJeYGTiROracFMcC5OMmBYx19cHMOGe8XEI9eC5GnhOaHH104s+gCti+WC8CAMwyrqvcJGJSW8IpOYxCcKzT5YmSMmZdnKZhIg1bdJNFJVr+fq1C7V2z5XhGazGWhlTV4ojUU+CRpt1WR1Fr+FBEWx2awNp3TGML22RzdfggEmqGynXLEkKi+Eli4Cp947mmVv8rmGQFVTU7oAlSq2vwFPlfSW4Crou8Cq5+/ziJdOzH83365ae3uClSSF2lnK8vB7nkzVe60kNXzS6zXrsAl8azdOJm5I/AtLuvoWet7hWpQXkAKkjjYlJsjVp2eTmixXH+dVEj5UIYa4mmUg4hMR5o4Idpnw4rQ7ev9axc5b2wCZfrIUzMfyt5ryAzJLPlHGI2PK6+N58UJXh3Bdkd+fF33ZbkblHapv1+qXJXZS/kXNORQTHIDuPD5pxPcCQ6h1idCPOqSUJE69npjAU5yAtAd0EvyWoqodm3i/QZwgMtnaxug3SxSsS+WEZKenbfvHky0Uedn9gZICLybdxPoRKcacLgTjBU631DEEfdJBrRsEfbYvQZ+3Cfp48k8JOp6qXm/YrUkN8vPGbqWT+m6lE7lbs+1t7G7hlR16KSssoKUm1peTGmF2Y16oWJuSssWjc80ROFjKcTIJciB3xyQk11S8kgVGJZ1T8Y5czhj7WEBkI4HKRhmMIVejO5XrqYUeQoakM9D8NxJ+MCtFiEI9xqjKkmF51DTlMRsJMLlj4SEnk6rcLIGpJXTNej0S5xEvcY5KOgkOOJLnl+ZLouFAgS3MlwHBq0kwncgDwRFez4RYvCX8MhKliUeDc3ww1KNUIFVBSCgqy7JUO/GpcydaYDfzTWOjGFdvB0/T+Lo40mUSuXUOWFWQ6rNEWR5z9xeIA36yoD+RVZU41ojDqjxe55IMcwiti2ke8ZDmJcK+XG27kSyN18UYohxKNif/wJck4YR/z/g8EREP3Z+yK7Yg+dP0IctzMhbtPtXnWIJDVnjDs4iHtTZveAb9JEsxu+N2wOWl4qowPcGPWBciA/zrBvAN4EGLsCDjivsVvV6rSO7BklOxOoO1giRgFIRQENexO5wniyDI4xOJRJ+cQwumWQn3rraR0Y/byejjPcjoix1k9Gw3Gf2wLxm93yajV/+cjD7cSUbPaiTxfoOMvmiQ0RdADD9sb2PJqCaYryYNSdaIdctcEB6vy5KTgoiuDxBE2V7FzRcbWM4pOG0WHA2jYSkp7V7NK1nTlPSHpQ7h7Ny3Dpq1zGl43UGKgOB9YIEEseEPijnkWublZPJQL1bWfTVR5UmWsatnhE+ldFZYpfblysj48m4D1jbqxCzIGK39L30wxhrPEn5fBANIShb7X/pHUuyIUzJmKXnz6mkVAJagY8FXaxH/lUjkrjoD4RrulQStTQxTIY9oqTWWn5KMgnRtwkUtOFlwNiZFYYtkTyYCYmNFBAhRsqAh6FGLd1TMAv+rcOgjyzXf8VNtc5KxMXCAcCZlV98/bhk2CEOq5JhveBYHA/wDDzkpWPaJoEByVClt2UmvXYsJO5u2vYN5WvXmy0J4l8SDPrwXC5Lff/nU+yochAMP6Arc7XxU1gChLLicnQ9zdn8p5P9nkijSfMJUzBCXVG6nki6NhVwoDbYE9u3PMmv3Ve21wJcF6vW2ffxUWPkhj/3fr78aH/T73ivyiI37T3NJuyLvnplMv1pwceL1+79ff0X84/aMWoGszNYCrpPp4+tFcBH87+b333P05e+/F6fygvL778W/fv89v8A+9RFm9brB77/nm/+Fyv8ylaHsEAWnUQg9/esUyaIvN4dIdQI2biqakrWg80jIySJLxiRg+OJw+Hv+e364zsvf88OvL9CxnakPxoqbDQnl5VyhqazrI3ntr5fKst9zP1IVNBW8OFyT8nDNyy/h+mXGuSjLQGBf4gHJBVX4DXa/ZUkLKRs6NIc4LhsEBLNeT9srqp+Kfr7V1MpQuxZxKY3cWak21S9D/KoWoSKcSgoslRxFMLyvQab2taE9potqc9PCtNPGhTX8p9OccTAuSgGnE3kPLQJuNmYtT3TkK0WLjwUVGYl4eWxlW0sIzSiYxq3ZW8JdTaS7TtVJr3dgA17WEkvq5MT+dX9M+XiZJbzPycSPDgYlAiVTEjMbSa8CCZP0N1FT07IzltAz+kq9Fcw82tQppOJmc/MzIJjhHEVJFVC6mEGLR2prtm+IaGyI2G9DxI0bIsyG5B0bUgPGrmWBpB/l1brcj3VxHq9l9xErY45pbC/yygxuXdZNzIgVagjk5xROvL97g14vyEf8PCYjrmQcdZxIr+cIO1wLOwShZusPtb7dvozWpESQPFbO2D9HOKmJs9TWk+wn0RbTp87+CaR+1XZZoEhEea+XhAWbkyAg8YnvkFtg/72eD1tkfpBrQXieZI/YuIAyhE7XSZa9mEQjisV5GT2cBA/hMiYQpkjB/76soIWYgyFWBOSMqMDdQl4QkjQNhBM/NNCaxBmjhXiRkxcTsFcOYShLdOG8MLt3H+UYj0GcRHoSBGE9PX0VVApHiRDR6FyjHwnh380mlYhaomNLHpkRrCkpej2DtVZOqH8O3J+xGt8tQmZ90DEVZN7dp/4S6L9sT/ALIXv/JQoa6iojxTg6CSAOtSLpHA6ePkTGwtgcYoeOwKEZSLqn6m42GlSa2jg7KDAFS3KbsjOswKmu02EYJk7hZjM6R/qgUQxXsSRKyhJVrxAkPqm4EXKUCaoVMa3yUqkWQJsgYXUQx7m+YDpgbRSYGrJHlpHwKuF5cPE0lzJRIuhlRjxZoZBnHKDpJcLzJWv1I/mv6rD0vSRP5e9c/75w9tKMoeelf9cqOEiwrmGJ+wPurJUuBQJL15rC0qvfI3JekbPmVplD2WiA8/rv8xKLI/92VXZbyvfHjVYxr7jMS9hcyWKViXazamOA0oFCE7H1v3LdBr1vWAd8x7oXPW/420c1WHPy55JyksJA5kfs/A1IKcXWcSKCqj6S4qGlXjnCDGG1q00kJ26gY0U7er0FECjDeFg5oXn6iHD6SV34zMGTXcf2blGT1LtKlfoiaeKGTii9rokxWj0FfMM5EQDAXk//Ecp5BYFwTp3QBINYrqRK0El/iBCE5vG/vF3N6bae023/iJ/HIzbyr/splXxjTvNEMJ2kxz/fbJz01aJ0sYe42kfQGpIm2ajJNYoYiBKVdY7QuHg12EN1u4EPAEDJMkg8OCb3hElUTI6OqtuKGBFQWarUDLSAf4M8ZHJIRy4VYQGhgAcY4uaan+RoaMjjGppEumlFpms0uAPVwzDkmOAwDNl5WRd/XBAKhEUJtvxW2AHN1cttmqunO1RPf+xWPT3fV/X0c1v19PKfq54Od6qe/qipkX5uqJ6eNlRPT0FWeL69TVP19KhTQ/xJBTDB9NgVhY1WBiwSlcjzWgtBVk8/URfSv7LAqWpF+krUip3PikS4X1V9bSn2FMjoTxNIO5aewVSXnLgDYHeayOqwXc0ATOt6UpuWPk5JfDgJDhWRhBzhgTKdi+OAu/NEp+pgRmrG9ifQiyut6JfCrG5MOxtTtVxTX+vezU+Y5mVtmjjHidbhPtt2Er7fqajFfxkExtxFN4ZpzE+Gdmmn308AbyKBk5hogtIfHicn8eA46fdRwGIySs4lGaVxwE+ZrI4pilhAEdpsKtmd93q013s20RUwNUj3YPsDkeKZUpCFy5ENXqoRaJHkKUmhINe2RqpZCjniNxty5N/2j8YsEPCygJy3C61py8GmRJP4RZasILv6+WajWqhKGflEsliofzcbYzRLU3KZ8J+TS/nRdNZ+DREttVNFY2GBx1xKs5kN7Nfs4BnEr3pNrsUDMmGcPElSmk9b9TAfDc7VOpE9mmDk03Xg6ifMn3K2VHkgDISswZIF8wCVsAWO5YDZkkGpqplyNbLm+epHaGo0d29QjlmWJYtC9qoncnDjRIaoTMm2qQzL8q9JMHpIzvGDSUXHsa8q+PgOwt0VzAC2yn3R2UciiI+H26qoXm6oYFZ7Q5VqdbIS2CO92XbY/9z+YPNuJx0o8NsdXPPJbq75fl+u+Uuba77551zzh51c80mNA/7S4JpvG1zzLXDN99vbVO/ev9qh/5QV3rnv3j9N1oVIBB17DU4F3ohGHFMvfZhLIsckW5MnPZmClvSFfcuVg1eE1F5Ff5qESZo+S/jHlF3lwBmDvFPTbV6Kh1gghHNJ70Qy/UGetcI/7/WaJZoanQxOa6OpyalKajhi36AbPWAmh4o6mtuWzLTV/8ip8VIDrbUww63spQAycGQBR5KU8WQsnhAgjEVA5JLlLc/QVIh544BEkpS9SGyNvrKKvlolhdb6DCVGKxFYWBFYCUUPJoGvX9B9LLDOBsSq3UzJQswkkbYXSK4ZHw24KcX50RAh3Pke0X5uh8eLgMU8pKlkgfi6iJkELrJYRAMBSlID766ttYlzzGpH584lLZGHJa9Q2SxWUXCcYMhPplY3MBfbuI0GINLI2yhVuJLbOxWtT649L3nZocc0tlckflp/B494KJJpYUU7aq8p8h50Gsj/hssC2BCWP1AU1HUpz1neJ9e0EDSfeiKZev7hmpS+RwuJosqXV8yIB6uWH5URA6hQwPQMIVzUAQf3wUS/djXtPiqkEcnUB2KpXmQUIIfYB+ao8NAgymgLMWiJHphj3dPRUII8DENgnpL2W2pTbYyo1T7HWkHAkUr1ZHb+vzO8oQr1ORxXmrgc2bshCwvGAUfuZ4tZckkEldR71esV8CU4LAJfgsyX2+GgVXtYi1wmXptrU6ODdahRrc1S58FwmtXPCNj0JFhgVp0P3kZ+taRqfs2F0fbCmuelxUQcxgMBbkT9riKlXvOrpqljE0/AQQLNRT4igH7n8a+T4Aerh67WG43kxd4aSDKAKndVInS7QVYSixE9x3WLluQmgywL3yJOtEFWUjPIEta4KUHHDIyv6HkkSqwufXD8SklLMn3TK8wFqFDkI+v1Mr33m02QxSPfP0dNCGWKHrE4HxEne5hKFaYMnAiuAwnLqpIyw6VR8ITKfZMbwVqWXBbWBcLrRSJmYLlKsQ4FE/2VgF6NZiQY+fJ74WOKxTnClckYluUvE57MiSC8iECXrX/IrYXvZ4R/Uh8L9ReGyHESK6KDA650MmV1q2Mqu+AAgkTLcVWR/oFwrm6rv20TYH/cKaViMtvvtvrjf/i2+lvttqpwaRb7aSKSvubpfZr6WuLLZ1svssrm1hjUzWghGF+Zi5m6mEj68zS9jvvO9fJBwl8sSK7vuLJU2VK/MO43rr6NqLjFEge1CrbWMaDrcdAfqkiGBPV6B0Gu3fAmWaI0KxZovR5BKkIOaVi/T4kxaL8vXvDvKS+E8taVIkplZQMTDGmh6z4gWcauAoIQBO0sHQbS0W+Qb+/p/iX7RKqO8qNYlNVy5Y2wvqRRfo4PBhAfvA7DJ3ob7GOc+h2Ol1xeWJ+mSD06HZgImMfKkEg0YWZ1ziKkaQzvPFic1uZ0P0+1ix/kCY0C4tryXIO8tqVfEp9cF25tEtIU2Ydwu+i6P7X+52ku2FtKrh5UkUsuRodrMStjJcicXyADlymBcR+snqYSsfZZZF3tArIIqWnqcL2XRkwWK0CcYw643FSao7zKv2rEYx7oP1FpT2tAJJ0Jqmmol7nmEoxbqL60kTC5LFi2FEQevAqAy0tJeS5JYKXjBsoEJH5QVHgil0LkFWN/mJfOINoAZZnbsri2kbZmBwUw7iCzpJi9aXZgEHpLD3oxqBRsOs3ImdJnmfk06E+7rBxnrNjRaljWTrXzUNQ4o6RKr9jrva0BTOIbwGyzASfgrfSHKAZ8c9+Opstql4wibjQ4h3SbO8f3KspaRWVpjFqdTkOBz83Tc6VGAyOhQWUkFDRaaQ1aVSCP/kEcq4dwmqqwcZtNpTYj6nW2snBxNGWNvhC2lM1rz1YyIphuDZWMGZjvy4sJUeLrvXiw2TR7l13UDhg2+sBmX3IhOIdgElanh4nVF6LS1fa5b2LwpD4BT21XH1i9DpJjJMmR0S5iEptnuLJNmJsGNHq2DlVUlHezIcd10sudRw/jc6VCQwSQRVVf06wECRXrp6dstlvXSECNrgRmXtXBasMeoTKlxYIVnQQm2EI3AlSWZKaUo/msrT3VnYOGtLtejQDYevdFs16N5oAqtLueC6YbqtUUs6pKeMmWebqtot13q2Hlsy0CKpvtElDNPXAWG0d/LRImDZGwYdisXws+LDj5pOJgvY91UIMPqiP1GlpZ9xo7H1WHzKmxVzxMVBl4zKFS/bNud++g1XuLBe5YxrrRLWvnO7cBDdSJBt84zZFaeLez966M5TcMUFu8bnw/y0zTIqAzc57eW/LclUf0yetnPzdcN915uRlPnaqnHSuwnp1VFNt2ra6GTpqXaFC2peW1tbaLSWWMe1P+FxfBzEarAQJUtoRo039c9e+YFdwwjmapgTgZnLqO9Siq8poKhO7FN86nIjxN0cBsb5KmFifoDNuoMQFoXNXm1yuUDWpJ0NpA0MkvaD/vfQbUjwerGz8GAzzs37Rk1JzfAzemoIXBWw7+BtVhrYg/Kt3T0PRNtnjfb539E+10vJseaNjLfzRMy2DbBZzNVGLpPW7c5roNF23a6/GZLihRMPo5AdqFg+FggO0z0ToP4cGncXGASy4GowQVZyCJB8dGCSRRY510BxfV1VkMkauyFcQQxXSzCfKYw7fqVuEEI1BdZ919jmPRD7J+UpmzAlQxj63rOR6DjDQ+EacBNWE2ZXO2FCrKpnJTTuKb54Yi+RNicprWBR4jhFlZBhpUeDgYoBKd46TG+Fyk8c0jVVHnT0bqIAkfz94x/pFwNyQD2BbJe/k7jgRfrUnMg2+++3Zg3F/kNSjmwdf//u5bZDLqKCu6VrEFFbnySCkpU56Sa62DdfR28cmaVPc2+bMp6hoROZXiGbzAk5baGeQ2LKT8pi6OCJXHonK9cdYbpiyXYhD052pw3DrVxyazq1UThIPJmBW36gOZlqUqdrzI25VtlVKwH8+cUJAK1VSsDbtX/wpu6Ep1UGIJ+peczWlBgiDQJ/uTCpIcn6zlBieQ6/MaPEEqFydJmsoS01o18AXqrJfIegTgepoHRCEpivTQxuvIfgjFjOQQe/44CeBupg4D0c8pakJI7iGIbQSLMmNJaoWr2mL1l3LC2fyxtnj48UwREaIeBlttOuoqFWa2TUIcd3+gpMDLncJjgRdb6pg3+HS28w1+0lGl8w1+Nmu9wWezf/oG7yR6nNnjuwbLmEjEzxb4EWeLlF3lEY8fLcqYmOM/1P5k7utKKxaCju9g640G5waJmlU5Dip7+W3mAOnMfdqfzermAItZ3RxgIekammxvY80BTNCC8SxgeDkL1gqrFNCGJUIaYxkg03QW8+Df3979xjwmr2bxPLn4wvMSb/2F53meINein5IxU+8AkZeznBzDpzHLGI+8wzUcLTEjcyCGbMqTxWwVZjT/WIRQqTz+ABhA578CWvQi7eWjO9+zD92oVMOWpi/IifZ5PUET24/8/wW+nMXXSbBKkVz2hOWiP0nmNFtt70tW+h7qQFfQ5kplqbqxzTuo84pMl1miZpHRnPRnO5rKSipImILjQq+5F2VJIfoQnMKCQUUB66t4pZE3cNf6hecdroM12OWPRURKFJ+QXs//PZd1FtGE8qo/VWg7FGwhe1OlpWnhTqDRoJqB08a3k6C5XFY1B7kqVdGE/PJUlT5EZ4NOStV8NtSrPVxfLYMhKrejI5QV4YLTecJX4Tyhua5dX5YBz+yO2/WdPbqW58P0X9p+xiwluifbNlhDQ71kd4NlbXtQZJvLZPxRShh52t+3edXkoXvi9sJn6KCB1J6ngk32eZLSZRF5dxbXbnnkDRfXXsEymnp8epkEX32LvbsD7N39BnuDcIhUZR0zM/IG7SUUi2RM82m4zKkoTe8w4YL+RfaY7hn9i5ROs+oM7gBWdRgNnK4YT/vwlhN58E9fltj9XHCznf8AoFczKkhfrprsMccrnixO/QUnffmXH8k//f3xQ/bxQJ6cDsxw0BLm1NgqWNXX/zLr6twmEwyofx15yVIwVVojZznj8yTrxKXBZ+OSnrM9VV0wEDzJC6VZPa4zBWeVLkrqbiUlvQSLK2x/JxPh8BbZETwnuexPUVWHtgKh+nPJhJmkojGWCDcI45DMW2dkeNdARs/8y3//+981EEK6du9rC68v07RCUzqf2qGv+yqHuzccDP7HdHEtjxaMpRfUv2TXtvkykwBgme5Dz0sPecdMd49VwQfVm9PfNubUQYwdqIK8p3uwrEHxBChrrdLGqXIQ0z3eLl665R8JWfSTrI6xRm8vAab+qn3WZ6MJDFjIMLxbB1kFI/PFWaAw2NbG6y8nk0ltVNV9hQLj8dgKWLmYKYYc3MnRDYelTY3B4SjMSSFI+sDWLzu3Q8xw9Xdax5fI+2Zx7Q2/2n7GazhrOnTlzSSj0zzyJOKpPmrk/ZJlVfPD9etl4IfFLOGkL4U8HymafrhezXSNqyTwjVEYfL4AEfjTtpvU9Y6r0NXuq9DHfa9Cj9tXoU///CqkhPkXs/hyFl5RMavsNP1ikeS+Yxh1NqvHAVJS1+mLWXQ5swqSxg3nZaLjyPH4ZFvQObEzbttV7TrzuHEFum5cga7hCvRxexv3ClRF1fM5Sdm4P9fb7/lHAalCdoKNLk6TfEo4WxbZ6oyIp3lO+JPXz36O1h8+zMQ8i8CIdZkLvpRn42xBxuDIK79hdjqdhUWSU0H/IgFFEYV824lI+pxlxI/IyPl1DnH7TAKOEiEdiubDrDOYZCO0YcGWfEwigrXwLLAR5bkT65DVhqduuEOcaIPlbRt7NsNrWHISqrGfQdrBzxoPlaXCpvuzXaE08cPuKubBVp7yOc0NJ/tWyw0Oc7s70GUVhasIpqW3mjcoRnZX/WjSZN0PCBETxudansgSQX4N+ncH/6OkkIYk87VqVbHw8Csy9wbhN4rAu9RsTHJBuJrXdV8luAZRCP5/V/8L8s+dwdfYq/4jBaAL/MqFVddyDbsYDIAbNe5Rx1/UhOtB+K1mQjWxNGdS2pTDvd69NXoPYDQj9Q1cwPe1ONMFeFVmatSkG8UlHHHOq9fiaqhd1YBNao4zmUzU1wv8cu+FGbwxa7tjcM0sTxWYiLBP9zrEbAGxSXVQDmzDlXbGJW2ez/szHWYUk3ac0Yf6Yyv8py4X7Qikr2dbQpO+nBnDcXOa/5jFXc+XJn1Nr1fPUfWQzedJnp6p/JEk3fU98MdssbJvAs9nxnGFFlUdq1D+Y2aMolTWYDNtY32D82M73CVLV3p1r8m1eCWJ/Wkg4hsrBAiLcM4+kddM9/1aqaCxCNWQAUKR7UK1hpa9ng6BNSVCPaopX4887iiXw8RdvQTVQM9ZSh4qaR0CdeXVazNULSD7aZKmqqFA1mAsJWaqazoJ7DCFGR21i0IyX4hVoGzrPToJOiZdPfZ1rugYzIJacyzNrOQ+q+qwo+o9R73k2PmQazLWGGIQw33eORg6QXWqXh0seD4Lm5hhn5Sfz8L6HBzLrOezsIIaFm7vD5eFYHNXWGpsnA2bK6l+wknio2MRQvTc0NCZ2J/Qa5L62HwQbBH7g+q3pIC1AqBFsX+HzKsyRZAahZoH1RorShirGP62lC2F5AjN4kt2fQZcqfXBMpvYd8itrKDeRQmuH6Za+hz3yNgQRFv3oN6RwiLbUW5C9/3sktqXS066A3ATE4HbPLLJMdXTrEHhdlw6S4RDKdacNn5HP569eB6qRnSyChqfFaW9g471Ai3S6Le3Gbt6zVgm6CIwFq+KPzxki9UDyNoK82uFYlYZXX28ZvnDjI4/RnY9ZYt4P53hteIvz2dhjX6e+g/ZgpLUj/znTHiF+SIF8xVbcu+Ss6uCcB8Dm1JzFomQeAqzPpuxq7zEshsneZKsEa/dKtHBsKwic7vPgApWhu0F6+byo06glKiswc68sokzOXbQGHtQIuy8Tgew4ze2GJaQt/HuYIBK8MI4nMXD6pL0aKZe66BUGbf7vmXSR/Gteyn95AFuxvrG8UfBcv/kFs6PYv/emKXkxJd/v1E9qeLbVbl/73ZKP8m/q6Dez9zn2Mqe8JQ4ge6tAePt3u0p9nvJfHHsO6U+lP65ZKJWfA+Ks3rhCRROZWHk+9U8vnfn0cB/gnRQjiHuD51kv39piKlWt+7Ja6cB0K0jcXTLP7l1BAs88u/dll9PnBEfOCPW2wr2keTeQlZcqgh8J7eOSFcfGtLWvlufbxXQirv7B6ZH5JQfxX/NAl/+hCSUcqCPZHXFeOqjiKgwj5a4xHEMYUtOg8PZ0RHmR1vMyg9nJ+LU+lvLk+frGVzcU4faLM3U4b6XcJr0M3Dq9w/Xsouj4anx6o4q7+3SP7l3W/Vycrh+MAv8kY/KGsBIltFFQQtZE0B0b5mZb4lcgNFs0cuM+CcXmMUHQyf+lY7fYsK6JPHgOLlHj5OjI8Tig4Fc+K17GT1xTwA8s4Fe59ZRDlstq8kNGSXnEvuTe7Q/7PUCfhT72Efyqz4A925n9MRuDT+KL+7dXmZ6cec+Ki8w22wCHsNivXMf/HXVmTqc9fudG/UoEWZ7b/m3juT5eXr2whyho1v+LbPfmhugqIoZFud/Y4sxr7mOQfgaE14Btp/+d7Z//Tnbzy7/aG5+EutE1XKORTw4Lu6x46KK3ZPFfFScHydy5+l+Ow/V3CkZPZhXA/mJD/Qgk9uhpxp50BrwJgO8Ke4xwBt6BPuPweGwgTvWcbeOOyXgTgKWSwApr1Tuii7u+Plyfkm42nWFMMSghv6EokpkiPPT2/8bzIRYbOR/ChT9fvv326P//b04Pzq8beKXVpjXxLKjW/cSb8bJRNJEkutov5ImGvIIpBdIZHLiH3X3ElWYDdW78fmSsYwkkDI+VyfPXZz5CqdJbfWfxhQgrBiaeoI58aw9O29q5qv3Ee0T2IdkQ0X1BZSyf/sZ7W+8DzZ1HP/g6U37vdvnE1nWfgqTMBsnWSbl5r7lR7Xn4ClPVhYYFTRr7072zelW/5YC6XjJC9lag7bdQVrbmy29He3qzdCMLe29//d//q93qzU4rd5paiqeO85bR1jRh/obk3nSOK6VWuVc84PuuVmsFUONp+rmE7YzE2uJ0n4gUYq4r+5i785X32LvztffKUVca8+29tB6jzQvIfqxqPW887cPxd86Fh2A+6Ybzq1i96GuuVe62BKESUZ0a9CD9sH40dWGet4fy0LQyapvUcz9aHRx9mXUaOOqkm4lnufBNL82tbTC0XmWMwfAmINC4bIgvK/uqy4161+Ry49U9Ld8tgpgi3u9CHK72ic4feluP+pVn1SiHS9lQpC0+dHAwfRfVq+2eoyMFkL10Zeybuf07Mu7fcXVemf5/zvfOAcko+aIdmjuvc7H2O4j3m3PY6sXWgWgazdgAerb4y9uAsRW6G0njbRjdjX2ZEngzbVqfW9rQvMZ4VQca3Ozd6762RixnXiH68u0NDBYJGMqVpE31I20UvTtflqPG9KOqWs1vHDFHVdv4IdNbcK7LWrly1SbRAZt9fEWdYWSYO9nWYl97zH88JIs8/y9ezAQ13081D91L+1u2qmvSHuFq9TNw+VqKUwhZOAy7sg5S0HltePV8NGspRwioRSizpL5IiNq+T+TTyRDJdhl4jqM6noqO7Ljc1c8WD00Mwx8V5JvhadQkTart2i4s+uA2Mjx3tCeic9ZSo47Mvw7lxyEidLkW88Rv+KJPmpkxa5uNL4TfAyZ3BTOtv6jZWMR37RSPGwFzBDu27ezeOEsPknT+srF3125vsK11q1X5iQKca6DYJ5sURF8hUkjqd9ewBkNzrFoNKwWaUI61VZ6Gmxv0I0Se207im7otwXtGzs1ELUBBMaSWBhnrCq7YgPSAQlFwqdEmGbArGvN/MdSCFHQ/0iMx9X2flrqziaZ+XmG16BCbpCFskWbUWf6x+ostD0hYdV+BwQ0VdnSTKefb0Pg5gyM0Funw+Re8+hsecNU9IX0CRhqv52Bofbh+s9ZWb29vt/OGrcZUWRJPo3EPq+u16ncuJup/YtC+2jYZFu/7HgO/gwsUXMucbAvz/6U7uTZbV75fobXCijVyPI31iBrTwihWhLKH2bBWpkiETync/JaSqGitEtlRSBQy7PiiVkwKVEUtGL1g79k3NQ6m3eW9ip+MasIeCwwRJqxnku3r+fZbYpO/et55kcSWT9KpmFQwnjz8GpJv86CNbkGhr1lUU5kbFh7r0dsWNO3suANz1pr/mmGt3Tb8ib5YYYNULVrnVu9mulP22eqjg/v0l6OMD+PgwHOw2VB4GUEBQcDhJktfEUmSIc6QJh2FttwfiYaiXZzZeZ3bNvbEoJNT48nEzIWSL/SqP/WfRhp3adMThAejKv+V5RkqfJJfuzCPhCOK1hVnZQ8gDzQdfczJzsJd/zKaIf7mVBuZaxWrcP9TBj3M4hZA+5nJBDb3M9Ezf2MYwbuZzSm1hez2/0sx7REASoRHhGItmWXqrSbx01c5e1cr2AXqI6V/zOD0JNhGPoo4q4LOuTYajW+1mTFh89eppp75hh4Bi89v0PO5/4WGxQ/8V25vK7RxJBYrH3UsGLHkf/hMkvyjz7mJIv8nLGF5CVezjiZEM4J90vcbo1uOn+8fvLUqfqtZk1UmYF9p5QMOw1vH/Ag/AaTEDQwL5OcZE2DfeWEYu/r3gBs1by6jZe9VDd0SNs1nTMdqPQGBesg/O6OXkfNsl+rUC7wj7B4iTkdvlP/aOih1qN0q3b+6oOnrr4gg5qnPxy6tmam/d5+IZVLyAOWpVrZu23DvqpvmCDXwm7VBSbznXaPQlYJDhcgyvR6XWrToVXVgBGhY5dYqXW692obsnTbz//HMLS+f2YqRufZpYuSh8Qbht+AxeR35r+mXWUjWbXV+hLsatj6V1TMaF7ZurdG3NZbeWM3+8Dlq73goj0Ww1Q7oPYTztlVY8J9wRZbjfO7kK10F1H1XehLqUoQYgcBJKpcI4yyygCo0whUfaoazWiaktyU/625bpusVv02PEW2uIhYHavblfLLtR3sXPGNa96+atfn5wLn7lH/2+r7DrpntMSEfDv496S65/B556ViT/WfNtTRYZTS62ig757FFRXj2TOS0iQO1jS9VpvZtJmpGpLSvfCqm5X7Na7Gw8K5YoVzOYbkoaEWClRqIt5dB0IpsLjJk/O5ljeeM6+AXnzUyJ4twIlAyjq0HjDXY/KDKTwZGvGYmbjMEOc8PjFXGYjOXCzn84SvNhuCJXByefPBECR2RM7PcREnbriHbfdINu++lZEt5T/OjFh1bRbpQElB3zi1m+kyOV11T9Ce6hHDLH84k/fXqLnZOOE0US7ydpCy41Llp/STFg6LtuHxhxk21+qibDf+1bnsJJUMxSUQy0rTN6Kjwfn5LtiRegj1G6ZSq7ljWqQ+rdKoHJh7vmvOXcqYHJK3OnenVjLaObu87nOSjEU/o4J4OhFW4b2SZZ7kOd4Txj4WxhZP5T49EPnOvv5/X1W9yU9eIryMJIXwPhFeSFr4jSeYd0m85FNCs0Trhc19kYIpKwkQBAJI5hA+2nws5o7F16EI/lR3RnXbECoOxdy1B7fX9e9pnmT0LzDNekWmtBB8ZWLjdn2rxhw7Y65hmVJsIhg0TySNDoZ4DFicqvD4oBaD0owk+X0RPUoECXN2FaCj5VwFy1jO4yH5Gi/mcTY/ra6/Kp2QUM4wyQLnsUmYSIKgWS2PQb8aEHQMdtyhmVsVPAWLMCUZgciAqIpvv07S9JWu/Jq95sn4Y+TcwRmmaoQkzo+Oqlj8HEBDeEBxggnCxN5bx/OAOb/DSQdAH0poLBev5WUpTsD2VgRJ1chpX2JOxozbOd4vHrL5nAoJbRcKPFzmdlLuhMDSas+5qOwHCkh7N0IlnjA+JqaMzgl/zV4t8+fs6nvGX5NCFJETHEiuqCBCVz8bz0i6zEhnzbIMsjlyi3QgF5M4s8JM+GjVPKCPcqxLOR6Sr5GjiZEckWiVh9InxRVqHosqklAb0yxkJKrxE8n4FHJvQ7wKN5SLRx0P5e7Tv8jJoNfLAxPUfQdWQth5ORtqPepc/OOQxBIrNT1FOA/+BkI50/zMDSbNuFUEYR4gtP/GK30Jh8jOGjoINDg2nljcJhS+KaoInXIG7fXUvyEVhCeCcZzH8liMxDnm8QDy1KKKpan3tmOVRLQyNjOqzrqkss7JtXCnbvYDUINUyZqI1a8ZTaGcAT86Oscpy0l0QMqyPK74ieRziqeIU18JTR4tvJwJD5ZxmZHQj/zGykwVTfJDH5WBkNjAtDrq+ICChuu4KjL0jWqRRApKBsOLXi8ounA6qeE0KittWh6viZx3RMoSSEe2gq2jvZ4eu9cLeMxCBSnU63EFc4ZsfdgRDYsQeitLAceMB6jswi8LXkkzEE7n8WIetg8RnsCHrScAz+ZxABW2IypezMOd5wEfDB0+Pnei/87mFRWaOuzUZ5cqjL5/RIAvruZuSLWy6u1yrpTDbspHyNQfmz5SH2E5pg0EGWilOWYNBbMiaTccHTJqoNi5kqeq5JKfTNa/2B4enEhJxRzYY2eam43o972TAQSV5zE1OKiQEiU6b4jWsTp64S1YxXu9A26wKo9phVV6MrSGVUxjFTNYpVeRlEElIULsvtUc4SE8x9I4aKrl/z+oGag1niUGCN9Bo+G5fTh4qE0skcNJ0ZrX+aoBytFQyvUIJ3O4uZk3DIg7qkRuS3aQhJ9KezgXwXQuqZw7QhZqkfSUBijKwrZUGh8MJPfN4nQeJLjATB2RMV7iRUUBLe0DLiEn9IhcLqfq4WKBizlyH0jqi1SrmsyDxKGXp0HVt55ifDCovnfMtNcLbvocHwwxDRBCUVUtroTzrSCiAYgfVnQf7BDdh7cHJQyEnU7agNrKJMoS4dE5wotQSFJcg5VEynEsLzoWd5cxKeX8lhr5lkbUGQN1/FSjjupT8Glu9AtJUdBpvtm4aGaEB6HvElbzYmz+83v8OD86sjENGMRCqOqN8nO0I6iEiXzAkOT5I3YeixGrBT7Qz0TwaFbpfkpAvut5vD48VLREbohSH6jIEvNFwiGQBNgNHgwchnA1r6QgYt22sBRVVQ+YSxpidB4V3bIewvxU7lB0KWXH8moeOjkuY/+FYUzYhSbZbAIS0znCP4vAopthlhy0TwENl3kBITA+XMqNJekbyClQqMP2cR4P8ON57HK3F+619vF8RM43mwD+rcl8dBJspb+Gyqpfgc6kJmL/w4fD6oLu+UfkyPcC/+jj/MhH1p/l4/zoCItSiucYxq349VnFeT+oP/VQByBFmndxC1aiMgHIG8lm0/oq7Fdhuhmqp8KmXwrvUJvlGmvh7bwmk2rvECUnD47ZPVP1mB0dIUlGdW/dqJtLhN1sDuQKR/LHORbqX1QNYJZdwUYDpIo3GsfiFHzhNpvhbRLHw9siIgcQLv8gFlXD+3MTP/WGacmuT1XglKgzIEw7HMtwv3AsQE0ezuMX88BfSBx9Rq9pXvgIv3IKSfpIDgfPRK6G5rVetQ2D0oroq2GPVR5ClUWbn9w55f07EbzW3zmm9/gxPTpCbET7d84dekPPj0WYsfHH4ugIBAOQ1F2fOIBnkNhIwDA6k+yzYviqh34fgyyhfsmb/pyIGUuL7rtuFVqYQRTcar9e1jfaocIVEFqr587qc4Q1XgJCckklqzWz8+PXc9h0PYPXcww5MjDB4tykq+e1KT21KKSu8l3SGhk9nJ+r/2ptdg7oNBLwu1LtAHxi/e9mM8DcQCq2f0EOLG4e7i0kTd74HN0byHuNKdcZ21RMmV1hXlWn8piyzeaAjV7Nz/VlP4YraxL/oZbLTlnoILwO+M8xRcfbj0jiwk13lDsKBZzEL+cBw9zGT6fxukRyFuBPJqfd5rxeUmIaFu4nZjOLQMj4qltI6KTW88dcIayZwpZ56zoUggmH7qlWU6qAEOeYwoF+Po/fbjY+kHsf/6xOMi2esctf4dpneRrCh+ajNqCD29MjVVh8pItXwEJ9hJ+Zit8zPqb5VLEylxp8X2PEVkYAXcLoZ7OPPP5LCmPgv2nzR/qvZ8RbcPaJpiT1rGGf8seTTIof+cgz8Tur/82SwksyTpJ05V0SknspGWcJJ6knP+SeuVVWXYY+0rG25ZRixbpEWLMlBBi1tdtyju16XkYnpD9ejTPigSOZ0kJ4GcunhFcO7EptTsIPHwAyHz4cxHHDEBApjc+MLbPUFio4K3Tq/nYQx2/m7ek+tSqTJMvYlcrBuSyI19mJFPYstC6Twt2GwgJtywziN/PjP+eBwOA5KbmH+gWva745+ULLYzaYhf7dcaAezDU/VgS9xE+hvy6LT78m1suRAOMOJPOdzwMpiSo5w+QvU4OOns8lnyeuinxGi9GhOukHzaoGsf9Sh7YLf5UU+En+IZtB+lIXBQGXK9wO/CPRjdVXSQGvu5ymJPeUi5s8u14iRCK5cei9ntHCmycrj5NimUFYtsSbkznjKy8jyUePTiDfarvzquPmfOWwEl2U92u28jRoQJEmLyPEcZ535VTiSswSprn+13n0hZwSzu9mE/cTJG3dbPx7Flg1z3uHzMitULsdq92ukn9Y/EHH9zWhfTTHB0OEzc9n8PO4IkqQo43FRGWHUT+pvGAm5qrNj/zQvCnXEU9OgkL6BkiidxDHQuKSxhtJqkGEkWPDwAOExeiR5MbOK7lzsQIdmzpdeikIQ1gZI9jYnoYIk14vcQLly81yXsrk7GItXBtNITYWjyoNaPedVHSKEn8RyLnBVzZoRlDpSx6QIEdlGRwM5bF1AuIIhUGaTNnI5sJqU9QV2oJCSZKFPHtx4pqfxwUunM11oinUJTN19uundFTdf869p8IrCJkXnpglwks8TvpqBJpP4ezqF9DqxNLCE5xOp+CVeTWjGVBNHYAnUMe8X9CUIG/OUhJ6LzOSFMSbJx+JVyy5wz4KL+Hm4JHUY3m28lg+Jp7TS+i7RhEHoAk7OJs7PjuYOOv/c+7ukuTVsFApR3wAUvMBpP4nLFMMnXfWSQSbmypubtpaiJQRP99szDHi+BfdjaQl/pFJEDji5+UNl5Xm9aQeS3JKROvhK7Y3Ly8XvR4X8LCQi+BggMCg1CJFyIlkulrMSQOETQNu01mM8vMSF+4wOjPC6Jk8lRrOo/wcE3Rq1ppjgqLA/YVd4jLonIaybJCzqBMiMMWXK3s33+P5ZsI4fjuP381PqwINd/nnVcLTD5xMfBR19JWbKq/IpNcD9WRVgDr1kaC0Qig0Ghn8ZMvgkutsG1V+0+PJP/cbqUK793Ot7DhQ5usgwl4/zf8giqXUT7f8Ztlt5L1nSzhkgq8gKbkSfm6ZCrc8JnlmdboVGdDCpBQsb1EY6JY9x3Ajc3tQMZlVuRzDtPARfjLv9YhdUhzHTzpEtL81YwudaupXPFksVIwkQsWMcC/JGfxrpQ/GvVuv7H7dkhIEqb6aZcuVUFLUqnoTxr0VW4ZKgn3bXNjbeSX0awGvpp6qND5tAGjJw8bbYBPve4uXViCp1uzbe9l2FDbUwl6q3SY1AxsUXGmbnQ7NtUmoovklAT0AMk/UHcsDMcYycAmkipurdcoKtADQggfcZtPSp9Lipfn7xUSREkc+kKQIbllRnTHTSVATfqr3FZzEn+bBuoJUdDAsIU5J3Cm14azi+aBS0F1ezru0+wTqlAg7SWazmvoUlEHORp26tKC5hxlCkfM9A2EM05hjVwHIULfO5lppS7tZDsUE79I8MKxtEnhzCWVAUKkMqarL2g3WT00jqraRk+zs4Y3WWA3TqXYXyv7rF7DTfrMEO20drufvhnvQfur2t2v1aYNl/20b0s5wHvVg995nZrJoxzD4J9b0xmjW8w7Xh0vj6j7b1pkORw6W0mCmYZIoKO//vesvWLaaOnbBE5plu5qPG+bV5RcX+Ie56+rwiXBBx0lmYvvOaZpmzRC7O+PM1IJx1DwsdGBZ/Cvg3w9zwD937x7wIBxim6JBzV7SNXmoHF+En7Z1cFNTaPnbZ7R8TUVGKkPvbck0LvCP8/inOSZT1XUzNHlKP/lo13j64ILRajXktvgnuhF4CxevyXUF7xouVzkB6qFrtA9G3fsFHDimXdBp5eCAgyXlJ5pPq+wzrZN/gfOO/r4ckH+Pv/3mGOJEOBkqelEtMM+kOzb+BeZun92hcBpTvlAKjS7XB4lw393FndQClTrHT6328IbKOn+QmxymnWhET6aVPkBPZsdcmpT0RgL6e15ewNb0vCOv0x1H5wgy6QS0sTS81auUApgBuPkUXVxg+t8EvclmlMkt3wl7N/eRA/vKRWg76P9T+9OawmcC+yForxKq0vlrcCcSxKHiyRednnYNhlxjxzuOLGBUQcYsTw03rE1wn1xG3dvewaUbkYE+Y04tx5GL7leOXcKZyVo6dazdIX/GcWfKsFPfj3yDQEMy9wZ++cUFhDXMprHSxO4RCd04Xz5i48K6jNQc8UHOX3b4TxdTbOdUNQt1UTsiLriSao/RJc/KZnpOKEUoUrYkx9k03ppqVuyXZFYnmNULoSUKRu/n5zibmgjn4+k/DeajvXlsqIzoYFCWKqV5O0CuU6tqXAUwKlHTmwfUWUVEMC3gaVX7vbrZJJxOec3jB97Kzz7SxS9LJkgRMTxPrh8pqZ+kj/Pl/K3q3WSnAPevawGCe8MKFhQYGkGTuGvuvR491XFeggGmKCK4iA8OqEQe7eVDcRbTU3568f/+z/8FWqb3j5benHFyEflPaEogNqsZdbsHTMtDWF9zxemMBb5cOgAMguhi3/OxSjCpE0uaOmc0n1oGEplSH2E/kv/xfJxYfyRRhcThMTvVgUsJagajJmjb9PPwe55M5Z94/ZGsoo4zwqc6twCMDle1onXwltMqIFMVVdkgXVniTB0iVJbjqdlWiTrxq0Rv4nLqStI3XEhaWfv2krrNXapDnq5xtLtb6PEFXgDzvlRxRgyZu6O8aI0fXrr99NbPkYlhpAgUtCkoy7fGGmkHrBLt8B7Obmqz/2LGrh7bznu9upGPQqSOjhbTrehgsFpiogiL5aVCs+COxFBPo2jLS0vjUCuqOhmJc7CxaaHsSJwj/T/HemAyDdYTSrJUspzqJcz4DLbwsgmRm1YDZ0135JvVNBvM9Eo0IBU1DKoZaJgGAjhEi1pk1FeQ5dsP2hhCxmjDWgnPvm+hrd0NhcumAEaKRSnUmsFJWmYt5zTlRF0P4jhQh8KGCKwc02le0JRUuD3fA7f1joDVj8t/jaBW5dFdZlkrpkIt2ITn4y1dAIQ74rVRjbWkhNYE6JWTqmQ6jZWWy1Fh2cA0mUoIjHlyFfGybulOOngOi/nfIbh78AtYOcy98ywZNGHKpcwejZWciBO0TF9xF4mQ4hRez2hKzqDspSqSzFkZTCtyHLxKEB4xTM9jxzD9YGjtoo1htQrJQoMDhmQDa2p6IDYb3r2zu85hbhYlcVuhyL2v756K6OJwbahMMMBf30VlGIYXCJtaJ1/fbXt7Jg43SkrMToGNexoUfuSfzdiV/en6aF1Og7UCnENgDshm4wR3NqndD8jeiP3J0L+RB3FOfWz1wN8zPk9Eew0/amy48HqZOJaySa1B2ZuKY++iTaDmIALbaUW1SXa4u66m2Fkx1lno2/O5dOqpOqXEz3PfRDz5BOzx13mNPVp+2uTRKngFW5ike9fTLUn3rqY3J937ON2ZdO9xR5XOpHsvpq2ke9fTtpXn5yXdw2eq1xsy3n2cutnrXkzrGe+upvWMd1fTQCD0eHsbwxZLTao+dNA9mwi9IZILXNEJUN8VnWRirQQLxfMihhVPptp6/BGVzGlO80QwfgZu5VFSxsRiUIEd/hVlOCULTsaJIGk0xpUwFC0xzaMFhplGaRlTPNHZCeRBLOAg4lksNht/RpJUheVb4Lma8DNYsqRVB2yzsdScGmbd67XLCnWAbVYNul22mEyxlkVoR3yu6RSvFU9x5AofHfmRr1FkXAQU2/4RcJ4HKt56QEOag6g9otix5f8MbnLDp181aVHwe8nJhF63CcNPtpYmPFJcR9XPXYRL8i7/nt9sgP0TXzE3fb3LxeN8zKREsk9fjSYdvT0zUSI+ozvbxu0PUuX0ege83dFvtqPANzWxj7oExiY9Lvanx/JzEdLiIeXjZZZ0zENM6+IrJ/LeQj8RJTsgPOn1ij0oemEoOsLjdsUbUOnREq/BOcTX2my/tJOpDrWeTXux8pBItJ/h6qjoqNu1o1KEurRE+CBpz3A8xWtXHzHBWk1RgKFuqSSpeWv8dIrXDrk5mwZn02Bd4qUEfPUBdezTDUD5MKu0UAcDE0Ywg5tz6Gq32gvJ9ISs/qveAFfdlggnvV4SEKRcOnDa7q1OgwDvamBNS93YRoy7v40NP+z+QEmBX23h0JUescCvd3Dxl7u5+NN9ufgfbS5+/x9zcc1Kn0/bYd26db93/tWh/TVXqZ/3uEp1qAnUacWQjleeV8xjJ8zknOZP1Ul3C5NrKDz1/egiOFzP5L2/RBdGZCcudd9spARvJdn9Mf7XpaFDcAY9H/P2iXk+7W68XNmUwA/lPr0C+QYFu/IEv6xJQH80pKbXDanpNfT6dHsbKzUhSQEqqCNLJQWE92nxSbX2jhCBNwDspypsjcNckYpOcrjtED6axsGOo9at0tfHDOFnu8/Z9/ues7/a5+zwn5+zjAjvwU2vBXtqwZXuUUUNr7yaq7MEkpuOqk5SHcXZaONk4YPVI8VzTlutjIo5QFHrm9V5qmnMkjzNyE9k9ZKTougOIB1IAIMXgx4xqK0hQO2YWlX4S6Jlb4Fp8XNSiIjjxvwjVtfO57IZdWXuBOvX8zQq8Eeap1FWxgKP4wNh1Ai0eCklekE/SZHIKTbCCV5WtEhYuJ6yqPqBF/G4RVV+mbvBPJNTV2yIfF9PR+fFpW2t2Tt9/NoMujtTgIIpZrnZk6hjn7AbTDzSwcSNwRwlhd/xlOTormh7NodLvE4pV8lQo+WpD0nnIx+i4kFsrQ5pgFjxzuyPlKJadObN8gYQaku6vw/G+rr2nuUeLw7d9xbBa+Fd+amfJQV4zkakxItWgz+XW6Sw6c5M889q3OCvBgd51OAgj4CDfL+9zVYOItnGstfrEq1htaBqB0vAI5/mOQShbdZ8sIR3tbNFkkd32p/fboHCclWxLyM/KA+zJH2RZ6ta9G6nHCq941SQrlr2A4bsmypntVPFFOKMfCJZLXC4LCi1Wv/4wX/tQfXBdItn3843b8mA3vwHGJCKbHAfDPQhU22VdECBQpkghGDCn0hwkheTgIQ0vUZlWTAuXqhAfdbaVPvSuq+gNnHuunQjSBm8z0fkPBbgAxLKHu2XfKSjhp+f5CP91nB+Ooz6Q9R68VXzjAg4C+gH2np8/JquPGRyIR0ac26+1d4vrQZe36Jpeq0FLRbzEVHgUcDRAQytFwu8+Tpw4l2pzA8XJvoRs5EPeSPyYWuruuMfluXxm/8awr6ZGuPSP6fx+3kQWEW0UjIVEYlH5yY/fOkcPI5TV98WsfoBp42jnOhDWZT29XitGJx6ela6v+9BqMhgGHViVLnV+Y1xoQsWCdySIWVNtOxQFi6a6ji62SSnJJzQTBAOTzkHATzLW1s+NffNJnFKr8wSEEIRAdVYgsk5wmmc9XrDOI4XGvqbzfIk3vqU+kSTyg59yvf6Uwce+eKSpSvNCDkLFpa7tCi1eYZStt1aLBNaTiMt8Sy9QWuqvSiZCZXIlJQpOSOCwyaHOO3KDP1mis3JZZrUqB10j7GFrdKSGGHBkS4rSc43f1mZoqYDHu/COhdhLQYCH9C6h3fbrj1vt+senuzUPeD3O6sU+Jcd6okfdl+bft332vRT+9r07h9fm/Bvptc2XeInQ4M+/PTJFCSXaC9iFfBTJqtjiiJJuGqUi/d6tNd7N9UVMC2Bdf74H2CdNZYYV/YkrhakwTed74qBNpgYxC7GRhLCxfJSnQZrobS4KdPLD0uswxhHEGTE5Uq4dr2ozarEXHG1zYY7uvYjXrv1l+Xxj9P4t6niAz9OEcCRrPa3mDOMArirlJKtwqJjbRWn3vIIv11r8cuyUjcLxcuV0rxL8f1+aVQcht13WUT8aImltrTp2iMlFXCVDa1DwjWU+K08R+/3VB/9UBPkf2oI/780hP9foNdft7fZrT4ioxrenJdKBiYru/dkpcMGrbZQwrz7g6SEfPU3dUMOHUSYrW4mhHS1kxAmHVU6CWGxahHCrpg6n0kIs9Wu11a6cjexWNU3nq3qG89WcuOT7W3sxuOxHTqXFTi0hMO83OswqzAKxoLDVdkUFa3CLK5lpAHR38yYAxjtCuWR6/WEjRHDIUZMkI/4eUxGXC04NyF9nJVzvXKCULN1Uuvb7cvQzhIFAo98NWf/HLIDMXXx22wG6GgI5pwcbXvTJHNrAqTOv4mPoOKUGCcs9e6UYEX0iroQLLExynClnorGZQwukuOt4+7W1tbptiHuNz0P+qZSN43c9X6HqqvVQRzbIGNFr1ds09L/OcXjVZCtJBViCK+VqEUNWS1GvEaEGneHtRUvowy7UmPEyxKhCFIkWuffi58hRHlGPxJvpd1olwXNp16tV++Ks3waQZWU5beEN0s+ES/JVypoLNibmXyoJPUmnM0hjsbhWkOvvEBKPVWDR7FtK8kKSwDYU4MZMperpU4EqV8LgwSdJtEogViZy5Dm42yZksKGVUNw8c5NKBOuxO8CGYGqZZR8w27UeILelhLpGC+N4ZWNA9rW7c+7u9XrXcQWDBgUv75fKXsPhjU7DO5aFeLaMySvP0M6uuODIVYqVbD7VRxfXxSig2H5NywXPli7igVEATterv5bl+6lZriLbQw33cEPJ7v54Wxffjhv88PFP+aH+sFxuvqnXgX1tBJxh/nlfLZT4TqpsdF5g/WmDdabAgOdbW/jylxKW/Nsgc0UIzEvwbdYhwqZksrMw6rUDoxp57qsVGlGnD4Ex5DS4rCKtm7sgWKbJUJVFGWJcF5OifAgUckzlpLMVaIVhNsryCvZAOsO5I+8Uk51Ce1Q8qHqV0K0UQTRcn4ZBwT7fxQs9/HBEE9XYW3ZEoaYm5TCTuPmdUle1u1dHkKeyRJHHxwfDPe5OK22qKU/bSmf3qTGrikUDkRd4XBQ3e7krKql6ftiV/qSyy2jrVbd5XyO1/VzEHWcDWzz1DSnYvTeCtNWK8eWoHJT6/T0SsmDjI0/NjNJaXe5Ey+ln7D+c8FNdifr1QBeFF//yzq/tp3SGpmVICGT7re7y4HxJr1cxWuWLMXsTuS/uC//9XGyoD+RVeTff/nU+4msfDwTYhH5T16/fuljtiD50/Qhy3MyFpH/Qv585OnffqkJ1qftBKuBqiAGEgxJmfZK2wpvLlvenmaO9bmU2WBF3vcZu+pMRi5SU5/OFxkdU+HrwKsSIozrFBYPWUp8dePenw36hZBik53QfbdH782rn8E/QYS1kd5w7WiD/UVSFFeMp2ZG44ySXDzkJCW5oElW/PemCjk6nClChsZqaiLkZMJJMXvDs8+yNmuO80p144xUdfxZFlvNjs/GbEGKqNNmzV9mup5m6ypAblhAm81mXaKtHgqV/wfpeEGWx1x3TcDvo8P6/8MMr2kOASMq0zIzOITi8P3S+s2os3S9x1ly+YxWs8m7CBUrkP+JVruRyvtivZ3kr2kaEdmBxKinKVYKHpq21/y5fODxlvI/lngtmDuosmVP2/u3LRWUglybR8y20QqICFLLRGpA1k+JSGjWaSbgPiP8Pcp0pkdRt2MCaTt2UCfPx5erkXJcON9s1B/aJpOEily3D/xes/Ex5J1XfYQUwIjC8Szh90UwQKFgbxYLwh8mBQnQkdD+mEOJ34uEJ3MiCPfUzWTXEuwo8K4Cs49IKHnL6ahz8nDSlCKCdO5FtQzJmxokVoN3j2nJKejzoYHqX5KEGyMf53Ovp3+q79tsqJ3Z645unv0DqORNoLubZ3zL82/hjkngW753C6HziISKQ/9NfNCMXNLkmyfS+pL4eL13ll6T51fNNRyrUd8oH+5WIbwYhlJEKE5dqq3LtjtCflpp6wwVAl8oMUM3GwnQ4SrHVvifzoNWkd6rVe1+Bde7GCJBHwyUwg/CReHiWImKCf9IVNzqPwslpOsAk1wncgJxM7nST95xrkqY+UmuvA8syPHHlXEGH3OWqbtBMgvcygjns3AJsS5f5E9oIRhfBQ8Kkz/haep2YHpbkDH09WgCa6n3p6XdfAlVcj2cbON2hR+YqrqhXKKkpWeQjN3cbFRqduipmGGuDfRUqVJJgl1rYAdVJrGoAbWAxbYGprGvk1EKMn+aXvv4OkgqswwFjGcJ//gif0byZUDCnFy9VQlO0Kkb/QtUEYYDvlMBwUId2O1DID+Wgd7ZetgwJ7qXbOY0gqBeqhGqbq0TzuY/nrmefRIiV6uAAGDDNBEJ1n8veQbID1CFKKuGqysA1dYek47CzWaA3cqJIIH+PckSCLNRjLp6O5fC15b9FGbXMpakct7w66ncQoRFyfJHNIXMHyY6AXTfxEy9sa09qlrUJoRKG5l17SBfI/CwatgoU/OrI1xVJQd1eQ3JdFXzM0ClYD+eOQHbVFhVnYstr2etV9oHOY9oXVtBtGVlJZabHa2XXBtWwd4r/QL8/YZnWKJF99cSO/CPnDWeqmT57qrVMsxzv1FQNGhQ2UyXzzEzjxPU5sEvgrwjXT4zafDdah3p8nU9sJ8lKl0+D8i2dPmkli5fnqfjIgjyONfBBSGJRjNXPpzNsk0CqoP3LBGzcJ5cBwMpnuf6N80dFLSHxOQgEEd3EeaQQ5PxAN51Y3FM7uXH5Oio6rrqYUqE5j33IbWk6PW4iuUvIBhef6hyDb7jlYdAysagqgv/XBK+OtO5k4NbI4kFfc4yEvucpGzcd8Rd//wWwuIz2mrnc9numNhZEYRrU1QrATYWJimoZgJuDpsqlv8EVgvycRWvdaj0Z1WE8yJajy6L82htw21G1ysMFxMzx4jEJ8G6cUuJNClsFJeoxKNP/9n+1LtIlaLD7Xva2bfRAbpn0p4qS7hLVJYlfryKr5Pg4xI1nfgHTtChSyYEm0feQCXet4GR7i/oE+UOqWIivQBNU3LxRXdYpj1CbHxOOI59IqjpGTsKpa8X1963i2v5ryy3KenVZbdvM9OD43BKxoyDlF7lbW9F7LDgeMSucsl7HiiDcAWTs5UbbsQGUtN6Lu0XGHm3NreUfmzrhDyPLZIxFStY1XE9GuHwbllL16+9n8fEBHlSmrYoSwrRhyxK9SBudlSzyvKLC/zBVRy2E5Jf4PtuBdvFJCMwFflv/4oni8gzuc1v35atiVcQeScTjHsshwCZcqlF5NGUJOpZTt4biuj27UIk449m7HDM5reT218N//3Vne8Gd24P//31d99++21z0/sWHn83HpUkoA9vekvf8zFDWfsbvADzHWBBJFQXkFDeLjaboPa75oklGNfnmOYTFqa6q59p/rFtfAS166Gs8Fq2gzcA95mtjFWvEBDfyFNya+o4jGks7Jjf0wxiNOLEKZQTwUUsQnndzouOR+ozreT2f1Y1IhNlRLcIKSgKJ5Tw067CtuGQDaZVVYegWtVPyDFgHBazWID/bTIWvZ79Uza5YbJK1dd9edRjOx3JsZ2fduhx99BkntAbBq8qqlQL/uO+bOBjX8Nu+6x8WVGwyD9qjObOEArsHJexCAXh8+LF5IzwT3R8wx7eBI56HyX2X8sCj008XeTbIRexCHWS8A6dhBucJZCIoqtiH/m6h//gM5CrV0sWtC+PS4cW5LHdG2tmgRcIH7COBSz07MHLWJ+TswUZ0wkdAzNRUbZaY7xY4bWpH9HN5mCAm3oKgHVSNwXsIDJlbWy/y5zN6BsDe2rkDUqjiPyzvp+oI9f9FqS4r8vHACSluyrgv0uDATu0pRW908Ig9q2Y6EcNObFDl7qlM9fqoKNDV2gtUZfZdstrWpkKluXxw/+a6cDDlTGxeAXcls6nSlS77lfBix1pKWNTJm8PT+CjDh153beSQkfVd/JbWZOS2vWmSyGIjq+r+hoOBv9TE6G0qHKBX7tyQZc8coFfVqLiFonnn/Dup3vZwWmLXckf6zxTxGTkX/flun2V3VZsNgeKtBvK4/qbGD5OKmJPXH6AWSzCJBOvybU4tX9FPgyg0uTW8OzVCq8LPo5U4wRcK7c6ur2WlcUqI9G68WobidY7bon5aZDEHHc8Gr1caVqegD1DQFFE1Z01Kcvjp/81DH+qjWP+2GYc83yHcczPu41jDvc1jnnUNo754x8bx+BnO41Ff65ZnzxqWKw8b1isPAeLlcPtbazFin7m/n5181HYglsvE80kOtDl4dIwkPhEqWqgs3dUzLTG5n6enkmJVClCkPX42lbFSLGKcnM8E/Psnbw/sFhOgKCmM9hBR5z+dzOSa+NAJx8PzeUV4SOYTXggJoOXrTdfFsK7rLLT2cj7FPSfz7KAIL2wZ+k7N1x4EfAKlY2RJK3ZoLejEJ7m4ThjuYUhC1qS1gyv5bojgs3z67CKxjEsETJx/dr+uaRKdIefrQIT/+/ZKngGFnzEmO/pP6wWRu2OCT8rseyvVcyDr4fffo3wg1XMwzz4y/KhN/ZGGyZC8AJeaQNHjrqQ5woEnb5cuIl+TcoLyS4vKg7yHbn5Dt7J4PaPYr9/s3bw5i+/+uqr43YUZR3c06nPyYIkoIDQfza+V3EOv6m0Dk680H87JSZc+FvC0yRPsFckedEvCKeTY3l3viKX/SKZkEpRcjWjglh1BUScnjA+j7zlYkH4OCmqjy2VQGfg9u0xTvUVm6v636hpuxojiAD9hef1JJnemqaiS7UDj4RToqQVpakIF6z4G53IVrVeln+nk2WtD309/vx+jKLNnU8ixrPP7wmauf2kJCOCfH5Hqp3b02VS0PHndwTN3H4ymn/8/G5kK7eXGUnSz+9Ftqr1wtjnzaWlWyy/uKgiXv4pOau2lBNOONiT4elLCHYvwoKm5DLhTXkLRaBGh2qDuzfV832tp363agZV1bpY1yQOrOZ6bgIGRUwG4Xd3vlMKz1LpJWGtlW+lH/l1VZ8PSsq3MGhGL2oxWlUVHZ/VagbbikBNYKoPJMvooqBFc9p6Qsp9OyULMTv1a4Fj7y6ufQkKOacnq3g9iOZwRajpPv99XOk5HYrXjomvYS3hvFCvJRAN2jTRGVZq4PtWAa+KuWRV36rYKH91mDBd2IFYZnA5YmVCeYGHdkXd2/YZ6wIb/OH2hfWimdwSm3rmpmmql7/XtcmqFAgX+I6d8mcstMTvFU4llySryQnyzh35c5IvqSBz33ECfrAKUOD3ATH8I40hlUOknmSJjBTRkcugPkPV4HTHYqObl9J9CId3wruL6z0sXuX2wUIiYmw71G7mJYiIxKTVi+Wt8WTY6/n1eF/+0bf/yms9H/mL62Mf7Mi69O5/LAtBJ6u+fVuQbUn/kogroo7rXlmeJFGl+bRoZnqC+k9WI70/51sEqPoWSBKq95MgdcIr8lR5efR6z5awLkXiagi8ZYhaz6VD+fZJ8mQQYu8sT9sa7JvmqdZ+zNp5nn6pPRdtlYy3i2l1RQ/8OtX/Rn6yFMwvP5uKX+AfVrXUHO3UMS0qKgtd2n647opUJ2vV0rx8vaWSK8LKc6ETydTYgipKMPw3+kQLKkiqf2lMauSq6Trz3gGdLxgXSS5qKWY0i3LeM1/qTDfbmHrZzGPTkcXGG+hKDS2aLCx/zy/KKpjfr3uY16obdK4CdoE1WxoJh8RyqzpmYCz/lvDLRoyufUzbf1rVQidVnZrwt20F+o8rHcGTlviqCGiHSvpwideAQv4wvCtZQxXISjQCWeFJxhIR+RIVujTAv63wurYoTBBOWqaGnxVW1CaWADntp1Uj/4+b3qehIW0hr/Z6+JemF9tPc4uW7UVoXvKgStvD8iR7MZkURFQZkaY8WY2Gg8E5apCf32rkp/UG3iLYpz7QJTHjbDmd+ZEvpUTf4ZvmvvityjP2I5gbvFm1g3d7A8hvgcklhPdWNSp2O7gpqVHDTOHrrqxpxhCgi410JzyyQFKWCZ+bOOnzNuECi8t2yE+1cO/O3ZbaYZ+539VTb4DnbvvqftcNGppf/lMfvgIUS/qQqbgaz2f1UmXMBJYIHVEHZTEneXdWptZ7G/hbrMFOV6sixyoOVv2drDY+Zvn3bLwsuj6J5FJZrQ2wElZ1hD9JRMzx5+5udeBGpfbhJEukDLRtJy4wu3QP3V7CWVcKzpoNhDkwUiiEnIEVy+9f78n06WWdxNUziGoM1O7Ue1K9LkjVUP0r+R/4Sy+d5pI6SkojS/3IvyP/KTuIQavBwI/8r5XSTVIX/2ZJtWrnJG7zo0pTcJNvXEsIB8VcHyRveY02BjAAjj5YELuqOMM8OpdQiRzuxFwIGHxqg8w2/XI8HvvR/5+6L19y02j7/T9XwRC/MiQtDNqXV5ljj+3Yie1xZrxm4rJBao2IESiAGGQNVeciTtW5oO9Oviv5qlcaaCR5xq56vywaCbqbppenn/X3qHQQcEN0fdI28GAoptHqRgrEesOq/gDnomCtNxqfxKqEuyloVchtY2aHn7PxJyKv/KAoxp1t4GTcAUo6B6WWxAyLI/XHOf5Hpdx+OU+sE6TNaGHP0HJ2/QjGionTJ6H/w0vH1kyg0P+MTlcH9LZJblqtAVDyDzQg+piejrazT/ONeKpmAkNHqSq9qzlCqV7/WMUsM5oeogggbybTZfMa1qC8GQ5SdKH+5fE56o9D/A9pgVajozuWmIP501vEiU4dqW26Xem62qWFPoiw1UmdghT+CUSFo5JTWtuJAm8dQwkt+tLErvz4wrgUBvvj3Eb/ikPQ6rVb7QHZYSmaMzwKfLel/A5dZoheof97kiXWbuvjGoGrsH0x4ebErFPgd2gJzEuVi4h72fa8whZWFCQFOa6HZaT8wRW9oFgMf/fgWB2pwlTir54dw/das2v+S1eiqe3B95qpj1W0N7xa9gXN2FR6tyu+pChbIWpVnSayKKvZfW3PG3+l7+gvCtrFUhpUS3i4YpiwSWtnr2cgZDwSlIBFU8aDJUjMwSzIDZxjkF3MGMwzzbkoIl+UmSdufMMmREJPabqVJ0EUY9kwLLoI8uYCMY1iHb9VTRHnVq3DoSN3DnIdOU5y3gWh01Up0naowEYiy5D4CnYl4syLVWXEgHYRGis7XsjFUSpmUqGTLJT4WHU8e/pZHan4lFcBEVoxLRZk1uBYXa/UERFcAXXRIHTsDBN1tYkYezWTQQZEjjgtFCeabGB1dBSgN8PxPGHEY8qon36Ac8mgmhT48RyXhJBVVBtc26aDB0vx4la8uBVLkAItLsU1WJEigeJQ3EpxCO4OoUhxL+7uVtyd4jrrnVlr5p31/9/MfbBP9r6u/Ty3V6AeTIyUeOMHkz5PqyFQOxMcvAg+dq+Zqf3RXp7aG5rlcuyesH8DHOa5/tFwJs5PvhdfMNTQFtKUad1tzChIcM2e0Vip2B0k4dhgMmaARj59fpvnIofCs9GioFuIVpvJlfnedl3SJQNIDXUUvq1LXs41mKrQbZhKPcxtNnX/dky+ISuqdVoSP9AN0ZqJBWM5183ChMJIRVpLkxoHWRqtQmTxzrJneT/ag+gJTkcrVV/T+IwCrvxKW7ZUYrt1ICXnpezvk3vfhXBz0Prm7hM8EdmfUAt+tT9dpDJZ08Dx4J0AHplpIcfkY90i74i3Joa2Sn6/VSC+qdw4Ra6oiM7ucBTPnRy7H64VciZHbGQ1K9w6JwbA1ItZQ+WZqulpGb/k2pZ/sk5rWYBTcHELKVs0dhR4ZzzKGqrOEF50YuUelYKyIaVg7+uOJoxppXen2vj8wa367vifknf1aj6bhMik70hZ8oU4vrdMAkX1ylKIho6mn26LvPsadri8XOKYoS/UbLibOGo016ggh19yuNxb0jA6krHUNDpxdSgUj00cq0xcLBSgiHbAD4Q0q6KxMy5hoO+rqyjw5H231mOQXbYTviQYrhqhQ4Gg0gF7O1CRR7K679EWhcpf1u9ToQRG3uNI91L0U8jpihycp1bSrxT4vZzOc6iXDD7+JBwCK6vJnNuZUommTJrDd6o2IzghADfklLdsizyCd6zpoaH21dkkNuYyr0yADMyf3JEc90RgiNFpbdBawijHWteCLt1rh4PsxtL9vbvUjdfjMjFIVzjP1SFqZWLAzxTBpgJyAUwgP3x9kdzA7V5WEQvO9NxPO50TpobtZRVdKeQ4K1guPHR78PgiefM8gtdqf2Gm79/lVoQ6ZuG1G70L5jPxNlMNiJfPwLEyxZp8kssUpszt5jGC1kthqvSo1gqFaalKHUOwJEA5Jgja09fkDOS/v+OizHQ3oZZkUsytOxE7yNIlo/Mh90TbQcuhKENdzLllrobbuobmxNGdsm9M6zgH03crtzmzY/er1ZKRdI3awwt+yJMEXK75FPQcpl8U+VMi1SS8LUc+DgxJZS0dBD0ZOyzfg1wpdOe3QR3goAm2szekPHZJUDtxRU0tO0mscC1VsBNuY2tUIIr+yAMcM5WsJjz69Hk7iSrq+SIYb7Ldmy5A4+n05eFlmqe+5zWl6ISmoJ27xBCTS2m4bNI2BGNPmbHevpL8ZduyWMEZr1IOUk+wluaW8n4uL4M891NL69hccvQWc12hsh1B7PvEQtsqOfXoKfmR/gzJyTEaiP/X3NYeoEGWeUmAXCK0U9pbTIf2DYYKQ73m9of7KwFHryV4W6NytkiBl77m6N6F2sdlF4bQNtZwY1jRbY8FpyRoidUHH+P8wYVyd4A66q+teN/dgWrUXwv4ZssLrpByCyDzzyJWE82AxmDLOCakHXfTSQsqZZRImhRPsOkUQJakfeXCEKFgTRgWgUXE97bP7/iVMwOhumY/YR/rRk5ZMYOYZsRNPGVkwRGiit10HMn7zZAQaWwK1uBwgnndjZM2Qbba19evpFOy26lSq0MjyWdEYnSLydyGydD80BUTU+w6WWUa0Wc3CQVk2Heb0jVDp2r2z3tCJzSm6YEprkLN/U7ttDxrpveScYW7H39Q4GrUAJyL/zKIJu+zP+r9NRa0EUCn00F5kL1DiGNjWeM2q1bahtkuAz80mgofF2PhR5Ntc7YqYhjlOdaUco58ELDpKgKxDNPttP3G9pbmWGT8mmNRo8BCUjgRoICfZ5ZfM4HWwzuP37AkmW86H5NrfSb2CyMrJL2dTHJNlrlul65crjw3yHx2HZegow3mHubiXaa8b0Z6HgFT5HqIqsI47J5rT7kNx33MFmJUnPp4/YdKTLg4eTlV/zS/YzMCxOs/6C1qDmO7+M5BuoKtrMXvWtIQ0tvcovgjXehqgNjkvdMtAcxtOPIcuT+spjKM52KctTOvX1/7pN29WNWPyHpenfiP+Vg8D6JVF9p76VHySgDIsZhJfbTXVp6eSaXqZXxzynZvuG6Hsro0vpE/lO19dyYJdcwNtb9U77TC0tf44Jv19RPFe7cCfWqtNaMhTZoLXLYul2+6PWYFsLIY0xknuE6ef/Xe30OXVy2bsCHghnM+7n54qQJBPsTc+/7H71AbHxtffEaag9gCHZ2P0oen/u76JMUqfGpqZGd0SN9G8q5PbQn1P+UVHHuUKtMLYPHiwzvEc56uU8N175VvLgLqe8TjTjRNX1JWCRHWsZtyf0QjcBIQIuO6tUb3ZdHOrG2tM+rOJj7D04XcJcJp7dMGviOF9X6reiirj35cHhM16pxX8yYNWbbYE/G717Ll75ojDK4gKDJjgNhPCVCgP9Qpn6onsldNZ8irR5FH0yIqU4hxJhc1V6tmyweN7YMmxvdbsefUzoD111/7UNh5Tirxk1CxrLbEGQpWRaBpFfJSiDMNhUEm0Ghh/+XueL8vwFSaWyr35RvesDmuGOHtIDCpcFXGHof87lXc/daIG59aq6PO8i1hbFSChi+jfSHHd+RGYtr+Bwfo+U+hU9U0Gqr+T3VRF9NHFqwpvRYwubejZtxSPOh5LLTa1LDifIO2V1+8HQbX6V0yOvEitmVXp48R8vUD8l4vK1qLXjWTZwwvjnsTVRYZZWqrK1JSd/DDo3nlrsEmAwJ/4W2TnRud1KYzMPgNZGWB4Mng+nxUcBjiPwgk5Puma393Ja5c3HIH8XHbg5Q3/MH/8jxFynm4LFCpLRi6aeHjIVNmoHPd/faPIOJOogrhlsHcB/KNpMok+RPZwj6Iuzw6Rg8ZH8uFjW/U+sS+MsZcatyKVvvJ5jIuUYv2EnHxxcgYYYsy6/Vl+gZzqsxtNfJzax6Isn2uZOrF2T7ZPv5gyeVsySdYVBGk0dAnJ7P+/HBMfGJl9jDgT/GghXWDorHbTjy95qiukfGiq57x8l1zl7vk55vS0QHkp69qSlR1Ctk5Tl4zuQz1dN9Tbdz9Cslh7Rzdh/KxmZ2MQzBJRcnSGI+DmA/jqDU+F62usVmV8eKKIDw3+U2FEpTZ5oz4d/w75eJdRZfePyUNx3arpFwDpZVpn6STMWKti57NdPcTQHFsbsOSPOM53x1H48l5TZjrGQljg9AT+oPcWFKStQaC0rwJeaueVegI1UyGVBTMO5XDzTuV8VLODg6XgxSneSsS2vGORwQ4c65aWJrChOTeBFVfETmhobsypS3yeNLAJP9cswjmQjGtFTYETdn4DCs6lBIaM0whSQO0PS0Qsu+8XYpnRcs8V+ifs6ZcUsDaWte92EcpUiXpwzVtpQtHp5QSwq3hRfCILc/p+IRzRillWWEkZRakz3zPcc5wnOpBNP/AEh45t9SYasaeNvN4PoqydopgI2YxtbKPu+lplm/EhPbX7LojFzidvmaDcI/5TFT8VGFTqB3dnR7PA2hs3uO6HbGou+W++5IHfz+kuluI2nozLlYGzooNIXPUkKslBMr/HCKbVx/hiwwvL11vJZuPW0tQi/Fv0KqHpPFYtFk+JIkjaGayBPrvnDXH/KCCTKagJwVEdkFz3tP2n+tzj2cBp0fJXfeSURrsShmq7CeAMAnPs1SwM3JwusWmrsWb0bYl2XTGe47rrkeKY4xyOBEYHUrN3dFOTxJUpmLYz5ugb9pmSo9AZF2uL7H70uOeGtwij7vbiipdWaZSc70Tt/R7BLvD4+WNeYA9M2LbCg0NtLurdncjDi2P/ftVMbABAZGtTIPQiMTzCwp2s9xhjkar15cFMl+/Yy/vcTiTSJ55mFsSAnMHYl2JBMk/2HO8qEfWXDKUbLa52Ci4Je7T9j5Im1bHvt8R2zqNvI5pRZDPvNqwcZaoRBrpynFUedolfdwpOH5fMSEUx69ZsyUxYRu/T1uqpcPAyDfl88pVrkWqZ3hrcFjxhULpfdwvXyEJIq6GGMpjeYdvzlOsCSnzcd8Yd7wUyuLvk2jZzy6a8ZsspIi8klwIHphiHwawkJs/fQpqnGR6kLm+VI19KmX7ZfxHzxwjK/5bw66cJFMb28CEslyUayVlxuzcuhO/e7dRsUj1OtcsTw5a3pl7/JqrLIZSPQk1RrEQ7Ao/9b5zOTQyZMnKgKkGAOPznk+n9pknIv6kk20eqZ3Rd/htcTR+2QI9W6s40EQQosQUTfBLQoWQyu30UXCli6N7y5ZpCzzMBFMk+qtX7FDkiqqJ87s06qNRJ0+vLekmRdW3kqizd+iB37Hgf3Z8kCHMi4KE/DdNnHWd3/3KruWkGL7yo9YQbO+Avmm4ZgdLm1Jss5aukOnkxV4a0IzKSkWfl5kmk+JtSk92o2va7/Gb3KPpBc2rj/3dF9tFvu6TLpzsTLF3ykIHDBytintfp1x5JikAfyfXMD4IHHDDmH8OmBNQiutFQyocbJwXU3qZ+/orlt3cnMQKygmeMQaddsT+bLWxzOMmW7LcJvd/+9SWKIwY4/4qnnX44HyYScnvIWDWqmhzdG2Fw5s+xeS7gQkeGT1Qrta+oOCM+D30hLEy1SpDf3aT2XXW89x1tpATup5xYOLu+tB1tu7PPDnk4E2fAVfJ312V/g7Z3fqLM6qrrI/+JYZZtBDd4AUy9lffwGa+gxekZZV4pNBCLjepvJjjNGkUZ3xTQoPhYOB+5Ry1FJxqVHxOXqS9ol9wIrvw1m8xqMSTM+hrYkvThDuBzfYPYjBY2Lcyh0Onj3m4jOvqO5fD1Lu0uDEQhYmEZAHrNc+AZXDmtLMl21UinIqfeGVuM4hC1ChH5pnor05T3RjyRe7v4BVWR3vfJKH6dkfE2MFhGElMJ1J61qqmzJIX8l+2iPeY7JSqlbRlVh0eB3vmmq++iwv69RDwSRvbfh+QOK8fDgRwmD4+Gg/LBlJPiNZoaJrnLJNpSW+zoQIsxdwW1YZpnPqn/jAgJ6j+EWPhJqJdzXmz38ZI2ffX/CImE3Nsn/Xy1ks1nqr5jsJh6L3g+rMF0943afflybhA9Dkkzbr1LyHRZblLbANrbjJYiLiCsaHdOl6cMnZaI7nue9x5dZazkmMlgSH+lwJ++DUUfnAgiU3FEdB3R++uSBbI5RLREahPUWh8Kj7/InwJ9dUHz7cv30OZ/8xinJuiZXHjoUsaSO9yWpGisHMpSWulHq8cfhnoaZp5cK2eS31qkkhaTbS6CyTg8PWzvhO/cpHW42yh6pEgbIriAs47kIVFWwcAV5UNOkHFC1Zp+16U+1nMw7GZmXUY43wbd48rGhIO9mWHstgHA+9oEWj2wxlfSJ8KJPhTShwxn67eHuEO41x1Cgc9iYK9iCWVdjHCCqODHXuEtxc2Tx6qvw7rWuNRpoiEQR8HDTuhVPHuKlJ94nGUt/kMx8rrqYV5fKGe+ouYrfKgwPR2do2U379QPqtZ+jfp1iu1CM/H1VF/8ih+VDUpCs+PNdzSejyeQZZSgVrxKJoFk7azYl/BBYY8wIqs+TnA9pPBYf1Ragoph/x7JNdLELE4cJ0yhA7H2kgXzrjS5rzZs9ixUDe2xp7smeYlJFOainRFp7QVbazoQWbQgTdKZJmX3hHaocGYdiDXk3u31WxXzWzw9xySYvWx8Kon24ox8/dmR/FCSdqN8RdvkeePLLI/ZizWIoUpD5hBoaW1WqyqJ7abtvADeVJohckX6OhawTMmcK1MOLnUlJwjYLz0M+/Kwxx43nbjA80lOxjFN1uyc6Tru0W4gmcub8KgKklVueyABRKI+XNBRUU92UcD9yvajx9KS5IHK2f49I7/wIqdH+zyVslAomzZ1ukfSi102CQYtUuwBC+5TBRos9cLeauZPL0hBDYQgvfVZjj6HAiU1MDn8UqRwETOgXVFpO666lh5J/sY30T56jkHilafijkkLYQFWWv5gnrqzzqLGpEVzuxV9M/6+66RmTOHyFU+hIa2V/CSScHIE6iVP9M97xFOk3y9pQ5KNYZOiv0Y6aXSjxfByD/QeVZ+S7anHJ692odscW7Pnew59TKfOVJXvW/QK1FZh3GqGmIVutVQDh+edvU9qnawZgi46+iVJOHLcT37MgyxVBcCHh9eKow+xPW6SFzMXzKEslllYpBYueBWr/xqenzq9rzUBEPcL5Ep1kYrMS7wM9mUEDPvyiRfx7S3KucQFpvXz9D8YtsazF4d5UqWbZ6q9Svh5yC8clf1xK02SwYjkubMCcu8B7BLAUWzqiWXflTRGhEW1wirQKMP3LZxl0ge5hy4cbYTvxVIJEd8CPFugZ5f8VHaCOR1aRg9hCbP7dKz/jBu1pvk5bQqMOXM1pZFjQKPTwe2DCetWhT4qR5TjrCNChYcy91bDqgfC1KdRWqtf4Cohe73GsHBSsKc161ZsOSa4/s3jOHv3cij4dpFr1RYJ53z3a+ZdPrkt+4/Faezd0Ix4f53U600QdZ1iny6Edj9W2pHyuIO4XOp2uN3R70jj9SuNz9xU0e+jK4QjX7kFu4TcJhAdSm4XQZzujaH6JHqiID3rMBaE3skBK3e9AtNz69csbS1cg6r09N6NAL5N17eOXbAKlm0pJqySrF3+jywnx5c0iQnczJSRG+FQnue9JHiuQLSXAbGX5+tExPOlQd0mdm6D9hqkwhQWUTBZ3MWtPaDbuRrQp5I4r7EntBAPiUDf19emwJx4Viw5zTtjvD02xRSzbtO5cz3voaY5d1OaKxOyrM2GU63N/kTt2CeowXFvFcyS+HUT2JcuD8OBh8CHAw6k7nvT+XiqJWIoi4VVT+0uoBPa9vZIfxBQ7T+v3Y/wxNz2hhlP+2MCA7kZaF16JR9feTh/niW/oAmf89akmsm9xMmN4U0Sll8Ao/h1nWHhhYJ0RJ1IzO1dGCcFAq2iH9fGaA5Ji4iPf3B9L0qOCt5kU2XRWnY5TCLV+LTiy2C0A9VqrGzbrlilcAaxm6YrPn5Auz7ykY/1Fp3x3//Js4DOhi1IQRm4MkCCL+hHwmj5Stg8ImLQ+0pROZmYb0jWRUJTPoyBpKDO/ESVmE13aCu0lsEe/NO/p5ElqcrjN4LZ9hUJ9tW/UjZr2x8MThEG/ZaTCZrXMDnA2X2e4WkE3TEvGEuVUuA0BDeAelCeMPPTjs6TDq5MAVPqiXETmergbsQPpCqaDIld7cisvCX9diz0QceC8yPfOJV0mECC0r9SoLSV6/sXJolBsT38nQXpdZ+fOET5++r3a8yX6YCr0q7XIGufzmlB7yJzyxmHA3LLEpfeZNOdeCaTE2e43eHfLTD9Eot5nOhiYGRT2IacjQdfVliZqiA+wafIw9KxqDDintOyYv6FeWUp0UovvdBXxzbb14yObpLDdL5C3c2cTo2rzFeJWnrRvvKZXMmwATtiWkrkWxbp0HMNn6+gLAJ8Cjih0Pzsw1Vta1CqpFifb7sOKjoBxNnPu/tYhMxX/EP/Ik+UcKnLaDeg5SSfIX/j/qD8Dx6d/frej2/VY7tx40waM3PzrgJoyC9bz6TxhEn50MwZ+bpm22en1JJcFepkRz1EAAUpk2PgxTMuMSISULIq12ARMe12MCm4Y0sqCevrt0Yro6NhfNRzURTFaZbKAdxktFqunwM21P9cHNiaGhIpm33Bsh1Wqs41RKaVW2Sfgoamf5r4gCt+Z3Nxy8y5tnaNoG+MgoTsaLoKpw5ITMcPyR7+rx0QJHxeY73fkS5+culsshTm4mAvuH4QV0E572prp1ZmLjoVOEMNamhH2Tp0qt5jtfzN6rhlIi17vs8tHu7qUqJPpu8U6rL5bYJlFajsT1PuyneEMA318KMugmU27zV9yp72a+qzWpStYb20nEwSEjr0GUpdAotyFC4Sev8z7SME3ZXtPr2AuwRAnYg9F48HHTZ9gWb+oEkV+wZ3oFWprag9trFhr5bH69BhwCtZqW28XBm8OVotgApOZVEm9uiHX/MUZUxd9U4q2GsWoL1GoJsQJKtYINhaOP5Z9qmztT0RYJICrrybZScbAs05dGad65VHzAwEZvgTfJW2wmXJk760qKY7LPba3B/m30Xp6H4B/yjVJwH0e3X+iv0ikJKpIb7M8r0cLmwzcjFGJMiOPeAKCO9rOUnNdjEYtC2VLkiVtuNTxfhw2T+6W0V+GL6kc0rh5p43cPJWcJHFUGtgu09znBacFeTJmSo5zRAUZG+6/EMjaZcvHooJHFS1qCazUzZpMmv3BZ+qPF9T/I5Dhk6u2vMycRTWHlFUICvi60D3RZ65/1j+alq7nDFgudxqqZX0zTj5G9APi0G4pLW6gALVTnK1gl9lzBrs14RbBU6me9MFzFrRBnJCQGIC+WJR7HjdcGE1TVVpdut9XSRjC2sQ7NMrMq+XcqYFS4HH4+J3Youi+VP3IRV2F1VBS5aNghjfl4Wirwv2M82I3GwKTAi8TpfjnrdO3klIPlFjeW8mrG4AOc+3IBorgrRwRaEeWmWKqk05TJO7f2N+UiDT9Lw3QGNRW3PB/g0f7DR3OZsRGxljAJKZ5lBJymxZ6WHyFR2VVDVz+gfwqXSlkpgMywiJ94NzCEk1LDgFMBNhC50p32p7+5xQjOv576Y39Qdv4fst23rGZCEhEuZlg1xyHhUUGGUoZvzQfWldBvkxnUC7G0xwZsTxA1O7EkGWW827JPWGpK+1jkLevNunwb3IOzyjoGO9hAlCwVQpSIzQFOC48jIXpN7EX1MTOKei0/TtPIDW3qKtlsZvlcBnMOjUMPrXS5gZmJMrcnv/sbxEekKRO+ACD9EqsCXmzfSmzxcF4hBump/bmdYnFNGOq9iX4V9oqXX21ZB9VexXiiW//NROV9mje5cCczMZ0HKpkQWiDKl6fqecbRUhyc/Macchlnz0VXI0/Nr5ZM8TQILmv6GSESvpgWKaC7fzwvoM7lt0y57S0imwVY5SXz2q6Zfsuy75HqnuoWnVyOlDfKfbB+T0az87iGEo0YVnDjryKsBxFzDT5tVQH74nG8EKROc/m5PVwtxYlg0r3LCXcB1PtsXblw/kVx4KVX45fWYbZfjE9m44tmw4OdxzNlnogO9Pv6rV1D4DihGgkMdFy7JMDJJrq8c2QX+O40tZYXq41M/yqReEqTTBsirT9gDtYEXZd8KUUlWBj17EmEv3O6NY/ipdsWmES+/OZa7k3NhwuxDT7jCxTTWWcG4mbP1WppJq7B15Sv7EzElZS5+HW9jFHwtT7/TRWS7/wVLcxzOhNuTpOHZhKQ/l7XZb+tLbS4ihIWbCg3Hi2Jj1CmA6pNBaPF21djjDjpDyprOecb+ys9lMhx9Mzfp8HE0P4I3b3KoCPqVY+hvEMD72nvEnn+qs+TXpAm5jp4Z6ay3EBEuXn63a/AhWnomyhytRUTaxzjb2AMtyQSKh6ekyvWa1CcIIpHu/4pcytIZF3SYp/n/9iWZ5xOiaFxARfZyIrdCQneQTDJ8IaDUFQljgrSoQ9BFLxYgv7aZqqsF5idQzs8lpuqoPfaAyBeTPLPjVEtODQ0PgvMEPIyLJqIVTVlj6oLGqBD6rl8jucp1urP9guyeh7wrh1utsUSxIh6i1j0DXrF/ZgcoGPbbVHeGNJzDXCdzCa94OUTUuD5xzF4pfaM6kQb7kHxZcglC53Mx4VdfacyYLw9tKv08jJdcSFhrkRyygFMkW5EXgHDOrcuwb39HVWyWaXn2lS0cDQ6PijdB9kWushl2meWJ6C1enX8NNY1ab//m6Re5PiZerbfe3e5H03suE1bVCFGUoifgDpRMp6ObzrLlWyYltjo721YC3hWlpXYQKBOOVvohh/BN9O75C6EUhc9xRMFEno8fL4P9lWj0sqORqZvTmPW8g5KQPYdgF0zTwA4tF7y9jyBG6pt41ejXJrCCbI4HFpxA1WaE1K8LzeDGdyz2+beSZWWdtI6WsML5Z8W7d/anrxnruBaehE0JEn5rb6BpaF0ztiggW9riRc6wgAxf1DMUxz1BO1hidcywfHT3AuwkClyOVAkqqkdOtMvJ2ovC9KIEVWlhNaDQSKXwyEd1DjnHZDgIUqQXhorAhqu/7c7yGZdkYSgSYzRjAmn373AkG9hFeJCy+4rOZUPKbz03QVyC1eNRJrV9wmQdZ5N7JSLcV0dhFcMGj8TUKrQnxYgmP0s3zM0H2xUbNs/zHZFLDfY1iJQ3kbIx3HpPHM98vsv7savVS5yNoeymsVWv8Xn7sNqS8JGhm+uebwnb2+oxcjvzBRMAeHlRVcAAYgecXWxRoQLmhXABqgooqEQAIAAAECU00QD8KwQATACXpcNnJxM7C66vbiaWlhZOLtaaGmgAJN4gKtN/RP9+/p9FwH+J/j844L/Bkf7B/8UhIROh/PMRELDtZKDx712YAJj/m8r3/+f8r/NzOVmYO5hxfnU2sTc3sXWwt+C0+fo/5WOLlP+S//d1/K/gAV4kJalR/9/l/GcR8P8Shf9L9F/w/1TH/8EH/sH/xaGh/3ODCkAFUCEBAOfUqAAA4H8EAAD//0uSe6okIAQA\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/internal/swaggerui/swaggerui.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package swaggerui provides packed swagger ui static files using resource manager.\n//\n// Files from:\n// https://github.com/Redocly/redoc\n// https://www.jsdelivr.com/package/npm/redoc\n//\n// Pack command:\n// gf pack redoc.standalone.js swaggerui-redoc.go -n=swaggerui -p=/goframe/swaggerui\npackage swaggerui\n"
  },
  {
    "path": "net/ghttp/testdata/https/files/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDzzCCAregAwIBAgIJAJYpWLkC2lEXMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV\nBAYTAkNIMRAwDgYDVQQIDAdTaUNodWFuMRAwDgYDVQQHDAdDaGVuZ2R1MRAwDgYD\nVQQKDAdKb2huLmNuMQwwCgYDVQQLDANEZXYxDTALBgNVBAMMBEpvaG4xHDAaBgkq\nhkiG9w0BCQEWDWpvaG5Aam9obmcuY24wHhcNMTgwNDIzMTMyNjA4WhcNMTkwNDIz\nMTMyNjA4WjB+MQswCQYDVQQGEwJDSDEQMA4GA1UECAwHU2lDaHVhbjEQMA4GA1UE\nBwwHQ2hlbmdkdTEQMA4GA1UECgwHSm9obi5jbjEMMAoGA1UECwwDRGV2MQ0wCwYD\nVQQDDARKb2huMRwwGgYJKoZIhvcNAQkBFg1qb2huQGpvaG5nLmNuMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6cngPUrDgBhiNfn+7MMHPzOoO+oVavlS\nF/tCPyKINhsePGqHkR4ILkHu9IuoBiPYR1JgrMz5goQ6mkrvq/LMfo4dCuA29ZRg\n+Vps/RimBpiz+RU3FDGyqc7d+fk74dElGk6NhJJ6XO3qHqgIg1yc6d5DiZfEnlMz\nCRKoZ2dQ+98o5LwES+XJBVWfZiC1pEfyppIh+ci7fXajxkRPJ+5qYWaS5cIHmJIN\nDIp5Ypszg1cPs0gIr5EgPeGwZzOeqMMzsbLLE8kjSw59Pt1/+Jkdm1e0GhO18qIO\nNcqaHeGaTUVjzX9XwRj8cw+q3kRoqD5aWMjUzAg9+IDrMqvo6VZQ5QIDAQABo1Aw\nTjAdBgNVHQ4EFgQU1/tUQpOK0xEwLLlYDiNrckqPlDowHwYDVR0jBBgwFoAU1/tU\nQpOK0xEwLLlYDiNrckqPlDowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\nAQEA5MbG2xU3s/GDU1MV4f0wKhWCNhXfrLaYSwNYGT/eb8ZG2iHSTO0dvl0+pjO2\nEK63PDMvMhUtL1Zlyvl+OqssYcDhVfDzdFoYX6TZNbYxFwSzcx78mO6boAADk9ro\nGEQWN+VHsl984SzBRZRJbtNbiw5iVuPruofeKHrrk4dLMiCsStyUaz9lUZxjo2Fi\nvVJOY+mRNOBqz1HgU2+RilFTl04zWadCWPJMugQSgJcUPgxRXQ96PkC8uYevEnmR\n2DUReSRULIOYEjHw0DZ6yGlqUkJcUGge3XAQEx3LlCpJasOC8Xpsh5i6WBnDPbMh\nkPBjRRTooSrJOQJC5v3QW+0Kgw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "net/ghttp/testdata/https/files/server.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA6cngPUrDgBhiNfn+7MMHPzOoO+oVavlSF/tCPyKINhsePGqH\nkR4ILkHu9IuoBiPYR1JgrMz5goQ6mkrvq/LMfo4dCuA29ZRg+Vps/RimBpiz+RU3\nFDGyqc7d+fk74dElGk6NhJJ6XO3qHqgIg1yc6d5DiZfEnlMzCRKoZ2dQ+98o5LwE\nS+XJBVWfZiC1pEfyppIh+ci7fXajxkRPJ+5qYWaS5cIHmJINDIp5Ypszg1cPs0gI\nr5EgPeGwZzOeqMMzsbLLE8kjSw59Pt1/+Jkdm1e0GhO18qIONcqaHeGaTUVjzX9X\nwRj8cw+q3kRoqD5aWMjUzAg9+IDrMqvo6VZQ5QIDAQABAoIBAHF7cMHPvL49F88j\nnr7GnIntRUhwBB19EIBbknibBotc9nxVKaEjds0dbCSAdfslAyL7tbmrdaIJFXk3\nzsckgGceDLLuyz7B26CuaCEjCdRB43qQ9b9zsEoFBHMGrC6dGul+H+uuPn9FbVOc\nNSWumuxa22W6qdJAiJFq4RvwZrsbVnYs5V29Y4Y20IlVUj3siJpAny//UUHequW9\nA/U7RvVssDsEEbbKvCpfcS7STNJKU7GlgV5l5hMKN2xLs1bVG5OKiZN82Zh9r7e1\nm2irxu/ehu6rENxZN0gsfPE4vqoQpbRMNAJlCfq9a3k0PH0TOy5oOVJXPGTIDQab\nE3PeAwECgYEA9wh4+bPgMuO04hsAqsoO0DJ9Cwa+BzoDPYOvENobDzmcMErSDLKb\nekl1ej+fBTHRHVaBkuOf/9neLjhjMLad1B+I5gLksqwoMh87odDRCCpkO/B20ln8\nIN6RFiMiNjOaZqjPCCUobgzjbaIz3I69lCQQnMNPwjllSgZs9Lh/PjUCgYEA8kZU\nhhUN6ctHIo8ocnmqa4AUPbt2l4qOoBGHCMmhjthyft6g8y6cQlACVJzbco37MhjY\nuCOhhOClyUS1tyfds3NXdzAxXPl8SwQJGvl3zqkDQG7/GhCh6AzvHhZR8u7UaweC\nkVnAG87Ck6Qqo5ZNbjhMIUm0ujm2cdVd3vyV3fECgYEAmJSMHDck8GnCzLE+/T5m\nXeQBZfEZKF+FptYSKId+lS3RMebUzHD5JVQAEqz/LHczoTpQOAkORzorSEMdyPXS\nkDWWGfOJjG5XOXYfH/hZVADS/k6tJYnc9/RgitrSg8XlxSjZDz/cM/UT+CBqhf1I\nTRrlg94DAoTu8gT8AT9/oE0CgYB5CSPO/JO/2jtGi6iUUC4QmKMEGDRuDt2kID2K\n6ViaCY5hzY0xEHcmNdyEMvz7JO16oKkcjUhzHtwUSgxSXUtIDHaE6AGxRj6PJ4v4\n+uqcxxkFxq4Rcn/Acz2+lT4JlMFwWwci4Gi2O7w/kENxCHTUfLGj67OrWYvJIORN\ns3iXsQKBgD1I+v+simBvKZKmozzv99EgGfxkRxmrUQsclg1V8a1VTNfE5X9oNaE5\nkjp+dTnwbtmFl3SHVdFUzX/L6FvQIQ9FIwWI2bsszPm4rw8FBeOvH+8lXwVhCwPs\ny9him/PhdjBPX0zydDI+h+fmrxH/XbmryZcq1rNmEtFRHBsUs5jg\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "net/ghttp/testdata/https/packed/packed.go",
    "content": "package packed\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/5TWV1TTydsH8B+EpoAginEBDVIEQYp0kUTpSjAJhCwsxSwlgEtRwVCkKwJSo9IWCCChSAkoTZoivfeF0JEEQpMgvQrvcc/x1X/Zi/9zMTfzzPfMc/OZQcFBLKcBDoAD6DTsRQE/FS9wDLC/64xzl3PHuXng3GRt3R5iTFgBJt6X83cexsJLqjT4mrd9w0fQ6OPh+uAVEbGTj1k4TK1bdBu6nrT2Sab5GyC7ao5yc613l3Ly29Yfbl6fSovmph6AbK6L+TBrhl03yQhO9w7hHUcIcWSAEJd/z6I0MtJHaaKscBAb6STB5unZoVdhgDIFqQaCzyEuLwhza87xLoKCvMJtmjmYMYn63Sjx/X3IuE66VuXJKcVB08OurMS3IObBV6ilar8HjNhjTAGCzixCKecGJI4HfU3NBhngff1mmvfuihCWagSzqpwiiWaLhGkW8ZUMtrUOV0nZWSiGUl8ADw2xVAvrVMqUy2Fdmmmo4nl5CLKwynbmI/hlC5qZSd5INHqjEshnzRH8Sy60vatCdrS2MpPTWqGMEQEfxExDuC0T6/aRAmQZc8NLZ/0reVtVbeKKswKpFFBw4NFq4J7WWY2yE9p6i/oLwNCCT2HkioAirGf/cEcnDGH+6SCBPXAaCsiyOHNOMrfy8MpzqcyqbmcIUh9NqM3d240wHkieqIsLVQvYCCrFHtxYwQsjoEQNW6VrAbc/d9estPr1Cspt8kdMzResBrnITixfkXV+dH6IvwaET9i1fEFbKv2SHOHvYj8S86uPXU3zWv6LnglKVf37PpeU0WIVfU/lJFEJS++4ZAPt2x7NU1Ci+DwkxJCcWDN2IknmvjBEBoro/g0UJw2rLTQ17sCt42H05ZJ1KHyoWakNRBajN4lEB7di4EUDnXH9yfEp40qd719eKB6BRsV2o63HvMbKgno9JmOKCeTCKsmcLKPqdg+xwplYW9fUSI1IqgeMEV1/710WoQUzxyPavxZc3se1g7g4r9fS8uaZYvb7d0QmP1Qgof6MyYqy8ojAytWI2CZkYyHDerexvnz/tHI3+bNekf4Ted1wm4CRRXXwPpNvaf/RKdEvJ0PVw1h4zbCdtZVH5/Y3nlk9ciD31aPS+v4wPytp7FgDk2t6hUhHQ3pUryFB05l6FWr8Y50oQUWOCdzmfMJaGR5zDKIizdPHTiZBLNr2KKSEiQdJ/XyDq790DfrfjEmWdw/fqATXWcJqy8GeaC4g3dVTUAxU0vjc1n3Rcwwvv+RPt2iKQStpOVGrPat55gbqaiaq8LgBNkRdj3T7nBUE1+OB2o7aCJNRjZP7QFukFSRqGONqF7atay17bt2payyZJ5YEWuBmVnMC7KqjKHXLUCj0y3ZTgsnp3ZyPMc7U7ArlJj5cckJfjJFD3PM6ZL7o7zuVxT5eZWttT8do+Lwy+5fzU63SjjL41Mk9fzWuui63P1nLWsLF19Y+NmEDbqWVPDu3UZuzgWUCgKMjFJydY3YuFzkBAgAHVgD4H4xwwnn/vxHOg6p8+cPMLL0pmJqUvac3hnndgyJUmS8oRH7R8yrZw65fJCKuLSzOHKykcdwIGoL0zB2pnefaBe+QnvRMsV25wEJjYk2l6E6yahC5s051Gl8yKcNwSdom5bmPkaKirYs9P0SSM9wXevPii0iGUv2PxJTM8bRPKsfL1lfvk1O6kqX0Exhj3mnyDZf1FMCqqZ9sinQaph574+UOFgU3H0uIwNuVcYbRZ2S06elo89E8pajoz3OZCPHLq9Ikd4M8GjMX0TsiFdasw8gQumbczMQLiVK64At+IEO9jrKshRT0FtiHS97tHnJXik2CrTTmKLzeEigV2yHBamdlVzt/Oy+uY388ttv0KnXsEJHtLZdrDZS7HDyhpvC3oMhdPgf7KClBBwlHi5HY11hxb1Zrd33LYKE7Dfbs6lCLeyliUt7Jt++vi4dq3VXJ8ctsGM6ylFyVlfsietoLY6+Axns8mbGLdyFY28cyncgHm4QKfxIK1Bo9gZeKdGrmdngtkd6WoJ8aDksDw1uwbCXZX1MkUC9JW8/G4UPxBltxXLbVrnrCjg/gOr1hlRKEnrZZY8adj5KcebmdIkRpi9C8+fKrIImcV8QL8UeTe8uGHNTbyMpmSpLG80n/xvUXIQ0Or7Qe7xMgVKZqecdUOPnrznT9G2FU7cAWnfc859l7PAm65sBNtB84QJeueNjRvxFoVKWQqZ6ngI9Qi2JFaj8t3lQvNxMprPhzl3oT+dd6pfXUHySH34lvNyUT6plmYFEMuU3DCIr628SKmRGY0OZqsdwfpdoybrHg2HEx3Y8Du2vsvB08nypJIn1/Xerq8icM1iM7HK+LRZ2KYeFnGLnBtk4UXIljwBTrPsNDUkWmyhtquc055AbRDTqOqtUfK6adlDC2AreiOSUzDUhW2bZK0vG/uLedasI62TKvzrOdCTqz3Fb2m0UUsRFNC7ORz56dyDxWk0agq/fh2QfcorOXDhTuqJHqUy7uVCe60IDcvI8ZJZinotfsta+Li0HUFgweztjFPM4It8cqO+H5pa2KwcTKc3Iho0R72ssr+fQnzhlWmPJhq6CYItPnckjp9nuHkSnRmzym6C2GN5I8I8WVbWKju75d+OvbFldDghD25N2GIFMzPee7ngK5wwbJ7cGaR8NJqa1r8gEM053Lh9BKii86rjgew7aqAoS/f33+2YdCXrDwEM7kkAzBhl4d3UX2HGTXkQ1iz1RpJLp2okp8fL9aJt9zWTnvAEncndWB9RusvDMeNiehnp/zO86fTyUk+BZkmS4r2gnR4zbV98UF8TlTjf1RuItnalBGiXnMoa0dydUvRMX9fV2cd212waFRny7EQ4L4/FqalQRFkzC5C+ocOv3L+FOSL97dku7TetZ7Ur3g1Ko2ZnvuAbPyEvmAme6vmBQ1QJq0v42aWHzE4u+9Z/RG69ZtoEs6h9IbrccQe+yK9kgl+yIyE7jPpk2wjL6/SVacpfnZKef+FdwlZMZZgDbBalpLcncNr++XOPVuXbbzHuqjLmpdmuad6MtiPLWK2fSvWSHSbuSedlgifhWqgA/FebVe9NopPn5Dd9xRPFBrlB5KL5q+SbnDSP0gQHe7r5+o2VHNaYUIaRHkWygeRyC72aU5sT6mRuUR0W/4eBw0ZQvzfDpz1/TuZ7T4zfLpSJfOz6GbMkrTitSSv4ws1kn55L1h4RyMbcUaB4p/VVU+4vmOKYfAsggbKwBEsP3AFACgAWFGP2PK+h3TvwUNyejBfjv7cwcKzsR8GvSD4p+R/kbx98oM+rb+4+ft32N+vt6/xoixAP/s+4+Y/z7L9yfiSPPBMeA/JmNl+7YLAkBAOwAA5L/b/y8AAP//A6tAlY0KAAA=\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "net/ghttp/testdata/issue1611/header.html",
    "content": "{{define \"header\"}}\n<h1>{{.header}}</h1>\n{{end}}"
  },
  {
    "path": "net/ghttp/testdata/issue1611/index/layout.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>GoFrame Layout</title>\n</head>\n<body>\n{{template \"header\" .}}\n</body>\n</html>"
  },
  {
    "path": "net/ghttp/testdata/issue2963/1.txt",
    "content": "1"
  },
  {
    "path": "net/ghttp/testdata/issue2963/中文G146(1)-icon.txt",
    "content": "中文G146(1)-icon"
  },
  {
    "path": "net/ghttp/testdata/main.html",
    "content": "main"
  },
  {
    "path": "net/ghttp/testdata/static1/index.html",
    "content": "index"
  },
  {
    "path": "net/ghttp/testdata/static1/test.html",
    "content": "test"
  },
  {
    "path": "net/ghttp/testdata/template/basic/index.html",
    "content": "Name:{{.name}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout1/container.html",
    "content": "{{define \"container\"}}2{{end}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout1/footer.html",
    "content": "{{define \"footer\"}}3{{end}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout1/header.html",
    "content": "{{define \"header\"}}1{{end}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout1/layout.html",
    "content": "{{template \"header\"}}{{template \"container\"}}{{template \"footer\"}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout2/footer.html",
    "content": "b"
  },
  {
    "path": "net/ghttp/testdata/template/layout2/header.html",
    "content": "a"
  },
  {
    "path": "net/ghttp/testdata/template/layout2/layout.html",
    "content": "{{include \"header.html\" .}}{{include .mainTpl .}}{{include \"footer.html\" .}}"
  },
  {
    "path": "net/ghttp/testdata/template/layout2/main/main1.html",
    "content": "1"
  },
  {
    "path": "net/ghttp/testdata/template/layout2/main/main2.html",
    "content": "2"
  },
  {
    "path": "net/ghttp/testdata/upload/file1.txt",
    "content": "file1.txt: This file is for uploading unit test case."
  },
  {
    "path": "net/ghttp/testdata/upload/file2.txt",
    "content": "file2.txt: This file is for uploading unit test case."
  },
  {
    "path": "net/ghttp/testdata/upload/中文.txt",
    "content": "中文.txt: This file is for uploading unit test case."
  },
  {
    "path": "net/gipv4/gipv4.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\n// Package gipv4 provides useful API for IPv4 address handling.\n\npackage gipv4\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Validate checks whether given `ip` a valid IPv4 address.\nfunc Validate(ip string) bool {\n\tparsed := net.ParseIP(ip)\n\treturn parsed != nil && parsed.To4() != nil\n}\n\n// ParseAddress parses `address` to its ip and port.\n// Eg: 192.168.1.1:80 -> 192.168.1.1, 80\nfunc ParseAddress(address string) (string, int) {\n\thost, port, err := net.SplitHostPort(address)\n\tif err != nil {\n\t\treturn \"\", 0\n\t}\n\tportInt, err := strconv.Atoi(port)\n\tif err != nil {\n\t\treturn \"\", 0\n\t}\n\treturn host, portInt\n}\n\n// GetSegment returns the segment of given ip address.\n// Eg: 192.168.2.102 -> 192.168.2\nfunc GetSegment(ip string) string {\n\tif !Validate(ip) {\n\t\treturn \"\"\n\t}\n\tsegments := strings.Split(ip, \".\")\n\tif len(segments) != 4 {\n\t\treturn \"\"\n\t}\n\treturn strings.Join(segments[:3], \".\")\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\n// Package gipv4 provides useful API for IPv4 address handling.\n\npackage gipv4\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n)\n\n// IpToLongBigEndian converts ip address to an uint32 integer with big endian.\nfunc IpToLongBigEndian(ip string) uint32 {\n\tnetIP := net.ParseIP(ip)\n\tif netIP == nil {\n\t\treturn 0\n\t}\n\treturn binary.BigEndian.Uint32(netIP.To4())\n}\n\n// LongToIpBigEndian converts an uint32 integer ip address to its string type address with big endian.\nfunc LongToIpBigEndian(long uint32) string {\n\tipByte := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(ipByte, long)\n\treturn net.IP(ipByte).String()\n}\n\n// IpToLongLittleEndian converts ip address to an uint32 integer with little endian.\nfunc IpToLongLittleEndian(ip string) uint32 {\n\tnetIp := net.ParseIP(ip)\n\tif netIp == nil {\n\t\treturn 0\n\t}\n\treturn binary.LittleEndian.Uint32(netIp.To4())\n}\n\n// LongToIpLittleEndian converts an uint32 integer ip address to its string type address with little endian.\nfunc LongToIpLittleEndian(long uint32) string {\n\tipByte := make([]byte, 4)\n\tbinary.LittleEndian.PutUint32(ipByte, long)\n\treturn net.IP(ipByte).String()\n}\n\n// Ip2long converts ip address to an uint32 integer.\n//\n// Deprecated: Use IpToLongBigEndian instead.\nfunc Ip2long(ip string) uint32 {\n\treturn IpToLongBigEndian(ip)\n}\n\n// Long2ip converts an uint32 integer ip address to its string type address.\n//\n// Deprecated: Use LongToIpBigEndian instead.\nfunc Long2ip(long uint32) string {\n\treturn LongToIpBigEndian(long)\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_ip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gipv4\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// GetIpArray retrieves and returns all the ip of current host.\nfunc GetIpArray() (ips []string, err error) {\n\tinterfaceAddr, err := net.InterfaceAddrs()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `net.InterfaceAddrs failed`)\n\t\treturn nil, err\n\t}\n\tfor _, address := range interfaceAddr {\n\t\tipNet, isValidIpNet := address.(*net.IPNet)\n\t\tif !isValidIpNet || ipNet.IP.IsLoopback() {\n\t\t\tcontinue\n\t\t}\n\t\tif ipNet.IP.To4() != nil {\n\t\t\tips = append(ips, ipNet.IP.String())\n\t\t}\n\t}\n\treturn ips, nil\n}\n\n// MustGetIntranetIp performs as GetIntranetIp, but it panics if any error occurs.\nfunc MustGetIntranetIp() string {\n\tip, err := GetIntranetIp()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn ip\n}\n\n// GetIntranetIp retrieves and returns the first intranet ip of current machine.\nfunc GetIntranetIp() (ip string, err error) {\n\tips, err := GetIntranetIpArray()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(ips) == 0 {\n\t\treturn \"\", gerror.New(\"no intranet ip found\")\n\t}\n\treturn ips[0], nil\n}\n\n// GetIntranetIpArray retrieves and returns the intranet ip list of current machine.\nfunc GetIntranetIpArray() (ips []string, err error) {\n\tvar (\n\t\taddresses  []net.Addr\n\t\tinterFaces []net.Interface\n\t)\n\tinterFaces, err = net.Interfaces()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `net.Interfaces failed`)\n\t\treturn ips, err\n\t}\n\tfor _, interFace := range interFaces {\n\t\tif interFace.Flags&net.FlagUp == 0 {\n\t\t\t// interface down\n\t\t\tcontinue\n\t\t}\n\t\tif interFace.Flags&net.FlagLoopback != 0 {\n\t\t\t// loop back interface\n\t\t\tcontinue\n\t\t}\n\t\t// ignore warden bridge\n\t\tif strings.HasPrefix(interFace.Name, \"w-\") {\n\t\t\tcontinue\n\t\t}\n\t\taddresses, err = interFace.Addrs()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrap(err, `interFace.Addrs failed`)\n\t\t\treturn ips, err\n\t\t}\n\t\tfor _, addr := range addresses {\n\t\t\tvar ip net.IP\n\t\t\tswitch v := addr.(type) {\n\t\t\tcase *net.IPNet:\n\t\t\t\tip = v.IP\n\t\t\tcase *net.IPAddr:\n\t\t\t\tip = v.IP\n\t\t\t}\n\n\t\t\tif ip == nil || ip.IsLoopback() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tip = ip.To4()\n\t\t\tif ip == nil {\n\t\t\t\t// not an ipv4 address\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tipStr := ip.String()\n\t\t\tif IsIntranet(ipStr) {\n\t\t\t\tips = append(ips, ipStr)\n\t\t\t}\n\t\t}\n\t}\n\treturn ips, nil\n}\n\n// IsIntranet checks and returns whether given ip an intranet ip.\n//\n// Local: 127.0.0.1\n// A: 10.0.0.0--10.255.255.255\n// B: 172.16.0.0--172.31.255.255\n// C: 192.168.0.0--192.168.255.255\nfunc IsIntranet(ip string) bool {\n\tif ip == \"127.0.0.1\" {\n\t\treturn true\n\t}\n\tarray := strings.Split(ip, \".\")\n\tif len(array) != 4 {\n\t\treturn false\n\t}\n\t// A\n\tif array[0] == \"10\" || (array[0] == \"192\" && array[1] == \"168\") {\n\t\treturn true\n\t}\n\t// C\n\tif array[0] == \"192\" && array[1] == \"168\" {\n\t\treturn true\n\t}\n\t// B\n\tif array[0] == \"172\" {\n\t\tsecond, err := strconv.ParseInt(array[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tif second >= 16 && second <= 31 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_lookup.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gipv4\n\nimport (\n\t\"net\"\n\t\"strings\"\n)\n\n// GetHostByName returns the IPv4 address corresponding to a given Internet host name.\nfunc GetHostByName(hostname string) (string, error) {\n\tips, err := net.LookupIP(hostname)\n\tif ips != nil {\n\t\tfor _, v := range ips {\n\t\t\tif v.To4() != nil {\n\t\t\t\treturn v.String(), nil\n\t\t\t}\n\t\t}\n\t\treturn \"\", nil\n\t}\n\treturn \"\", err\n}\n\n// GetHostsByName returns a list of IPv4 addresses corresponding to a given Internet\n// host name.\nfunc GetHostsByName(hostname string) ([]string, error) {\n\tips, err := net.LookupIP(hostname)\n\tif ips != nil {\n\t\tvar ipStrings []string\n\t\tfor _, v := range ips {\n\t\t\tif v.To4() != nil {\n\t\t\t\tipStrings = append(ipStrings, v.String())\n\t\t\t}\n\t\t}\n\t\treturn ipStrings, nil\n\t}\n\treturn nil, err\n}\n\n// GetNameByAddr returns the Internet host name corresponding to a given IP address.\nfunc GetNameByAddr(ipAddress string) (string, error) {\n\tnames, err := net.LookupAddr(ipAddress)\n\tif names != nil {\n\t\treturn strings.TrimRight(names[0], \".\"), nil\n\t}\n\treturn \"\", err\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_mac.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gipv4\n\nimport (\n\t\"net\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// GetMac retrieves and returns the first mac address of current host.\nfunc GetMac() (mac string, err error) {\n\tmacs, err := GetMacArray()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(macs) > 0 {\n\t\treturn macs[0], nil\n\t}\n\treturn \"\", nil\n}\n\n// GetMacArray retrieves and returns all the mac address of current host.\nfunc GetMacArray() (macs []string, err error) {\n\tnetInterfaces, err := net.Interfaces()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, `net.Interfaces failed`)\n\t\treturn nil, err\n\t}\n\tfor _, netInterface := range netInterfaces {\n\t\tmacAddr := netInterface.HardwareAddr.String()\n\t\tif len(macAddr) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tmacs = append(macs, macAddr)\n\t}\n\treturn macs, nil\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_z_unit_convert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gipv4_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\tipv4             string = \"192.168.1.1\"\n\tlongBigEndian    uint32 = 3232235777\n\tlongLittleEndian uint32 = 16885952\n)\n\nfunc TestIpToLongBigEndian(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar u = gipv4.IpToLongBigEndian(ipv4)\n\t\tt.Assert(u, longBigEndian)\n\n\t\tvar u2 = gipv4.Ip2long(ipv4)\n\t\tt.Assert(u2, longBigEndian)\n\t})\n}\n\nfunc TestLongToIpBigEndian(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = gipv4.LongToIpBigEndian(longBigEndian)\n\t\tt.Assert(s, ipv4)\n\n\t\tvar s2 = gipv4.Long2ip(longBigEndian)\n\t\tt.Assert(s2, ipv4)\n\t})\n}\n\nfunc TestIpToLongLittleEndian(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar u = gipv4.IpToLongLittleEndian(ipv4)\n\t\tt.Assert(u, longLittleEndian)\n\t})\n}\n\nfunc TestLongToIpLittleEndian(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = gipv4.LongToIpLittleEndian(longLittleEndian)\n\t\tt.Assert(s, ipv4)\n\t})\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_z_unit_ip_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gipv4_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestGetIpArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tips, err := gipv4.GetIpArray()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(ips), 0)\n\t\tfor _, ip := range ips {\n\t\t\tt.Assert(gipv4.Validate(ip), true)\n\t\t}\n\t})\n}\n\nfunc TestMustGetIntranetIp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tt.Errorf(\"MustGetIntranetIp() panicked: %v\", r)\n\t\t\t}\n\t\t}()\n\t\tip := gipv4.MustGetIntranetIp()\n\t\tt.Assert(gipv4.IsIntranet(ip), true)\n\t})\n}\n\nfunc TestGetIntranetIp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tip, err := gipv4.GetIntranetIp()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(ip, \"\")\n\t\tt.Assert(gipv4.IsIntranet(ip), true)\n\t})\n}\n\nfunc TestGetIntranetIpArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tips, err := gipv4.GetIntranetIpArray()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(ips), 0)\n\t\tfor _, ip := range ips {\n\t\t\tt.Assert(gipv4.IsIntranet(ip), true)\n\t\t}\n\t})\n}\n\nfunc TestIsIntranet(t *testing.T) {\n\ttests := []struct {\n\t\tip       string\n\t\texpected bool\n\t}{\n\t\t{\"127.0.0.1\", true},\n\t\t{\"10.0.0.1\", true},\n\t\t{\"172.16.0.1\", true},\n\t\t{\"172.31.255.255\", true},\n\t\t{\"192.168.0.1\", true},\n\t\t{\"192.168.255.255\", true},\n\t\t{\"8.8.8.8\", false},\n\t\t{\"172.32.0.1\", false},\n\t\t{\"256.256.256.256\", false},\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range tests {\n\t\t\tresult := gipv4.IsIntranet(test.ip)\n\t\t\tt.Assert(result, test.expected)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_z_unit_lookup_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gipv4_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestGetHostByName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tip, err := gipv4.GetHostByName(\"localhost\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(ip, \"127.0.0.1\")\n\t})\n}\n\nfunc TestGetHostsByName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tips, err := gipv4.GetHostsByName(\"localhost\")\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(\"127.0.0.1\", ips)\n\t})\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_z_unit_mac_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gipv4_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestGetMac(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmac, err := gipv4.GetMac()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(mac, \"\")\n\t\t// MAC addresses are typically 17 characters in length\n\t\tt.Assert(len(mac), 17)\n\t})\n}\n\nfunc TestGetMacArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmacs, err := gipv4.GetMacArray()\n\t\tt.AssertNil(err)\n\t\tt.AssertGT(len(macs), 0)\n\t\tfor _, mac := range macs {\n\t\t\t// MAC addresses are typically 17 characters in length\n\t\t\tt.Assert(len(mac), 17)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/gipv4/gipv4_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gipv4_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestValidate(t *testing.T) {\n\ttests := []struct {\n\t\tip       string\n\t\texpected bool\n\t}{\n\t\t{\"192.168.1.1\", true},\n\t\t{\"255.255.255.255\", true},\n\t\t{\"0.0.0.0\", true},\n\t\t{\"256.256.256.256\", false},\n\t\t{\"192.168.1\", false},\n\t\t{\"abc.def.ghi.jkl\", false},\n\t\t{\"19216811\", false},\n\t\t{\"abcdefghijkl\", false},\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range tests {\n\t\t\tresult := gipv4.Validate(test.ip)\n\t\t\tt.Assert(result, test.expected)\n\t\t}\n\t})\n}\n\nfunc TestParseAddress(t *testing.T) {\n\ttests := []struct {\n\t\taddress      string\n\t\texpectedIP   string\n\t\texpectedPort int\n\t}{\n\t\t{\"192.168.1.1:80\", \"192.168.1.1\", 80},\n\t\t{\"10.0.0.1:8080\", \"10.0.0.1\", 8080},\n\t\t{\"127.0.0.1:65535\", \"127.0.0.1\", 65535},\n\t\t{\"invalid:address\", \"\", 0},\n\t\t{\"192.168.1.1\", \"\", 0},\n\t\t{\"19216811\", \"\", 0},\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range tests {\n\t\t\tip, port := gipv4.ParseAddress(test.address)\n\t\t\tt.Assert(ip, test.expectedIP)\n\t\t\tt.Assert(port, test.expectedPort)\n\t\t}\n\t})\n}\n\nfunc TestGetSegment(t *testing.T) {\n\ttests := []struct {\n\t\tip       string\n\t\texpected string\n\t}{\n\t\t{\"192.168.2.102\", \"192.168.2\"},\n\t\t{\"10.0.0.1\", \"10.0.0\"},\n\t\t{\"255.255.255.255\", \"255.255.255\"},\n\t\t{\"invalid.ip.address\", \"\"},\n\t\t{\"123\", \"\"},\n\t\t{\"192.168.2.102.123\", \"\"},\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range tests {\n\t\t\tresult := gipv4.GetSegment(test.ip)\n\t\t\tt.Assert(result, test.expected)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/gipv6/gipv6.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gipv6 provides useful API for IPv6 address handling.\npackage gipv6\n\nimport \"github.com/gogf/gf/v2/text/gregex\"\n\n// Validate checks whether given `ip` a valid IPv6 address.\nfunc Validate(ip string) bool {\n\treturn gregex.IsMatchString(`^([\\da-fA-F]{1,4}:){7}[\\da-fA-F]{1,4}$|^:((:[\\da-fA-F]{1,4}){1,6}|:)$|^[\\da-fA-F]{1,4}:((:[\\da-fA-F]{1,4}){1,5}|:)$|^([\\da-fA-F]{1,4}:){2}((:[\\da-fA-F]{1,4}){1,4}|:)$|^([\\da-fA-F]{1,4}:){3}((:[\\da-fA-F]{1,4}){1,3}|:)$|^([\\da-fA-F]{1,4}:){4}((:[\\da-fA-F]{1,4}){1,2}|:)$|^([\\da-fA-F]{1,4}:){5}:([\\da-fA-F]{1,4})?$|^([\\da-fA-F]{1,4}:){6}:$`, ip)\n}\n"
  },
  {
    "path": "net/goai/goai.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package goai implements and provides document generating for OpenApi specification.\n//\n// https://editor.swagger.io/\npackage goai\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// OpenApiV3 is the structure defined from:\n// https://swagger.io/specification/\n// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md\ntype OpenApiV3 struct {\n\tConfig       Config                `json:\"-\"`\n\tOpenAPI      string                `json:\"openapi\"`\n\tComponents   Components            `json:\"components,omitempty\"`\n\tInfo         Info                  `json:\"info\"`\n\tPaths        Paths                 `json:\"paths\"`\n\tSecurity     *SecurityRequirements `json:\"security,omitempty\"`\n\tServers      *Servers              `json:\"servers,omitempty\"`\n\tTags         *Tags                 `json:\"tags,omitempty\"`\n\tExternalDocs *ExternalDocs         `json:\"externalDocs,omitempty\"`\n}\n\nconst (\n\tTypeInteger    = `integer`\n\tTypeNumber     = `number`\n\tTypeBoolean    = `boolean`\n\tTypeArray      = `array`\n\tTypeString     = `string`\n\tTypeFile       = `file`\n\tTypeObject     = `object`\n\tFormatInt32    = `int32`\n\tFormatInt64    = `int64`\n\tFormatDouble   = `double`\n\tFormatByte     = `byte`\n\tFormatBinary   = `binary`\n\tFormatDate     = `date`\n\tFormatDateTime = `date-time`\n\tFormatPassword = `password`\n)\n\nconst (\n\tParameterInHeader = `header`\n\tParameterInPath   = `path`\n\tParameterInQuery  = `query`\n\tParameterInCookie = `cookie`\n)\n\nconst (\n\tvalidationRuleKeyForRequired  = `required`\n\tvalidationRuleKeyForIn        = `in:`\n\tvalidationRuleKeyForMax       = `max:`\n\tvalidationRuleKeyForMin       = `min:`\n\tvalidationRuleKeyForLength    = `length:`\n\tvalidationRuleKeyForMaxLength = `max-length:`\n\tvalidationRuleKeyForMinLength = `min-length:`\n\tvalidationRuleKeyForBetween   = `between:`\n)\n\nvar (\n\tdefaultReadContentTypes  = []string{`application/json`}\n\tdefaultWriteContentTypes = []string{`application/json`}\n\tshortTypeMapForTag       = map[string]string{\n\t\tgtag.DefaultShort:      gtag.Default,\n\t\tgtag.SummaryShort:      gtag.Summary,\n\t\tgtag.SummaryShort2:     gtag.Summary,\n\t\tgtag.DescriptionShort:  gtag.Description,\n\t\tgtag.DescriptionShort2: gtag.Description,\n\t\tgtag.ExampleShort:      gtag.Example,\n\t\tgtag.ExamplesShort:     gtag.Examples,\n\t\tgtag.ExternalDocsShort: gtag.ExternalDocs,\n\t}\n)\n\n// New creates and returns an OpenApiV3 implements object.\nfunc New() *OpenApiV3 {\n\toai := &OpenApiV3{}\n\toai.fillWithDefaultValue()\n\treturn oai\n}\n\n// AddInput is the structured parameter for function OpenApiV3.Add.\ntype AddInput struct {\n\tPath   string // Path specifies the custom path if this is not configured in Meta of struct tag.\n\tPrefix string // Prefix specifies the custom route path prefix, which will be added with the path tag in Meta of struct tag.\n\tMethod string // Method specifies the custom HTTP method if this is not configured in Meta of struct tag.\n\tObject any    // Object can be an instance of struct or a route function.\n}\n\n// Add adds an instance of struct or a route function to OpenApiV3 definition implements.\nfunc (oai *OpenApiV3) Add(in AddInput) error {\n\tvar (\n\t\treflectValue = reflect.ValueOf(in.Object)\n\t)\n\tfor reflectValue.Kind() == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t}\n\tswitch reflectValue.Kind() {\n\tcase reflect.Struct:\n\t\treturn oai.addSchema(in.Object)\n\n\tcase reflect.Func:\n\t\treturn oai.addPath(addPathInput{\n\t\t\tPath:     in.Path,\n\t\t\tPrefix:   in.Prefix,\n\t\t\tMethod:   in.Method,\n\t\t\tFunction: in.Object,\n\t\t})\n\n\tdefault:\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`unsupported parameter type \"%s\", only struct/function type is supported`,\n\t\t\treflect.TypeOf(in.Object).String(),\n\t\t)\n\t}\n}\n\nfunc (oai OpenApiV3) String() string {\n\tb, err := json.Marshal(oai)\n\tif err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t}\n\treturn string(b)\n}\n\nfunc (oai *OpenApiV3) golangTypeToOAIType(t reflect.Type) string {\n\tfor t.Kind() == reflect.Pointer {\n\t\tt = t.Elem()\n\t}\n\n\tswitch t.String() {\n\tcase `time.Time`, `gtime.Time`:\n\t\treturn TypeString\n\tcase `ghttp.UploadFile`:\n\t\treturn TypeFile\n\tcase `[]uint8`:\n\t\treturn TypeString\n\tcase `uuid.UUID`:\n\t\treturn TypeString\n\t}\n\n\tswitch t.Kind() {\n\tcase reflect.String:\n\t\treturn TypeString\n\n\tcase reflect.Struct:\n\t\treturn TypeObject\n\n\tcase reflect.Slice, reflect.Array:\n\t\treturn TypeArray\n\n\tcase reflect.Bool:\n\t\treturn TypeBoolean\n\n\tcase\n\t\treflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,\n\t\treflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn TypeInteger\n\n\tcase\n\t\treflect.Float32, reflect.Float64,\n\t\treflect.Complex64, reflect.Complex128:\n\t\treturn TypeNumber\n\n\tdefault:\n\t\treturn TypeObject\n\t}\n}\n\n// golangTypeToOAIFormat converts and returns OpenAPI parameter format for given golang type `t`.\n// Note that it does not return standard OpenAPI parameter format but custom format in golang type.\nfunc (oai *OpenApiV3) golangTypeToOAIFormat(t reflect.Type) string {\n\tformat := t.String()\n\tswitch gstr.TrimLeft(format, \"*\") {\n\tcase `[]uint8`:\n\t\treturn FormatBinary\n\n\tdefault:\n\t\tif oai.isEmbeddedStructDefinition(t) {\n\t\t\treturn `EmbeddedStructDefinition`\n\t\t}\n\t\treturn format\n\t}\n}\n\nfunc (oai *OpenApiV3) golangTypeToSchemaName(t reflect.Type) string {\n\tvar (\n\t\tpkgPath    string\n\t\tschemaName = gstr.TrimLeft(t.String(), \"*\")\n\t)\n\t// Pointer type has no PkgPath.\n\tfor t.Kind() == reflect.Pointer {\n\t\tt = t.Elem()\n\t}\n\tschemaName = gstr.Replace(schemaName, `/`, `.`)\n\tif pkgPath = t.PkgPath(); pkgPath != \"\" && pkgPath != \".\" {\n\t\tif !oai.Config.IgnorePkgPath {\n\t\t\tschemaName = gstr.Replace(pkgPath, `/`, `.`) + gstr.SubStrFrom(schemaName, \".\")\n\t\t}\n\t}\n\tschemaName = gstr.ReplaceByMap(schemaName, map[string]string{\n\t\t` `: ``,\n\t\t`{`: ``,\n\t\t`}`: ``,\n\t\t`[`: `.`,\n\t\t`]`: `.`,\n\t})\n\treturn schemaName\n}\n\nfunc (oai *OpenApiV3) fillMapWithShortTags(m map[string]string) map[string]string {\n\tfor k, v := range shortTypeMapForTag {\n\t\tif m[v] == \"\" && m[k] != \"\" {\n\t\t\tm[v] = m[k]\n\t\t}\n\t}\n\treturn m\n}\n\nfunc formatRefToBytes(ref string) []byte {\n\treturn []byte(fmt.Sprintf(`{\"$ref\":\"#/components/schemas/%s\"}`, ref))\n}\n\nfunc formatRefAndDescToBytes(ref, desc string) []byte {\n\treturn []byte(fmt.Sprintf(`{\"$ref\":\"#/components/schemas/%s\",\"description\":\"%s\"}`, ref, desc))\n}\n\nfunc isValidParameterName(key string) bool {\n\treturn key != \"-\"\n}\n"
  },
  {
    "path": "net/goai/goai_callback.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Callback is specified by OpenAPI/Swagger standard version 3.0.\ntype Callback map[string]*Path\n\ntype Callbacks map[string]*CallbackRef\n\ntype CallbackRef struct {\n\tRef   string\n\tValue *Callback\n}\n\nfunc (r CallbackRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_components.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// Components is specified by OpenAPI/Swagger standard version 3.0.\ntype Components struct {\n\tSchemas         Schemas         `json:\"schemas,omitempty\"`\n\tParameters      ParametersMap   `json:\"parameters,omitempty\"`\n\tHeaders         Headers         `json:\"headers,omitempty\"`\n\tRequestBodies   RequestBodies   `json:\"requestBodies,omitempty\"`\n\tResponses       Responses       `json:\"responses,omitempty\"`\n\tSecuritySchemes SecuritySchemes `json:\"securitySchemes,omitempty\"`\n\tExamples        Examples        `json:\"examples,omitempty\"`\n\tLinks           Links           `json:\"links,omitempty\"`\n\tCallbacks       Callbacks       `json:\"callbacks,omitempty\"`\n}\n\ntype ParametersMap map[string]*ParameterRef\n\ntype RequestBodies map[string]*RequestBodyRef\n"
  },
  {
    "path": "net/goai/goai_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// Config provides extra configuration feature for OpenApiV3 implements.\ntype Config struct {\n\tReadContentTypes        []string // ReadContentTypes specifies the default MIME types for consuming if MIME types are not configured.\n\tWriteContentTypes       []string // WriteContentTypes specifies the default MIME types for producing if MIME types are not configured.\n\tCommonRequest           any      // Common request structure for all paths.\n\tCommonRequestDataField  string   // Common request field name to be replaced with certain business request structure. Eg: `Data`, `Request.`.\n\tCommonResponse          any      // Common response structure for all paths.\n\tCommonResponseDataField string   // Common response field name to be replaced with certain business response structure. Eg: `Data`, `Response.`.\n\tIgnorePkgPath           bool     // Ignores package name for schema name.\n}\n\n// fillWithDefaultValue fills configuration object of `oai` with default values if these are not configured.\nfunc (oai *OpenApiV3) fillWithDefaultValue() {\n\tif oai.OpenAPI == \"\" {\n\t\toai.OpenAPI = `3.0.0`\n\t}\n\tif len(oai.Config.ReadContentTypes) == 0 {\n\t\toai.Config.ReadContentTypes = defaultReadContentTypes\n\t}\n\tif len(oai.Config.WriteContentTypes) == 0 {\n\t\toai.Config.WriteContentTypes = defaultWriteContentTypes\n\t}\n}\n"
  },
  {
    "path": "net/goai/goai_example.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n)\n\n// Example is specified by OpenAPI/Swagger 3.0 standard.\ntype Example struct {\n\tSummary       string `json:\"summary,omitempty\"`\n\tDescription   string `json:\"description,omitempty\"`\n\tValue         any    `json:\"value,omitempty\"`\n\tExternalValue string `json:\"externalValue,omitempty\"`\n}\n\ntype Examples map[string]*ExampleRef\n\ntype ExampleRef struct {\n\tRef   string\n\tValue *Example\n}\n\nfunc (e *Examples) applyExamplesFile(path string) error {\n\tif empty.IsNil(e) {\n\t\treturn nil\n\t}\n\tvar json string\n\tif resource := gres.Get(path); resource != nil {\n\t\tjson = string(resource.Content())\n\t} else {\n\t\tabsolutePath := gfile.RealPath(path)\n\t\tif absolutePath != \"\" {\n\t\t\tjson = gfile.GetContents(absolutePath)\n\t\t}\n\t}\n\tif json == \"\" {\n\t\treturn nil\n\t}\n\tvar data any\n\terr := gjson.Unmarshal([]byte(json), &data)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = e.applyExamplesData(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (e *Examples) applyExamplesData(data any) error {\n\tif empty.IsNil(e) || empty.IsNil(data) {\n\t\treturn nil\n\t}\n\n\tswitch v := data.(type) {\n\tcase map[string]any:\n\t\tfor key, value := range v {\n\t\t\t(*e)[key] = &ExampleRef{\n\t\t\t\tValue: &Example{\n\t\t\t\t\tValue: value,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase []any:\n\t\tfor i, value := range v {\n\t\t\t(*e)[fmt.Sprintf(\"example %d\", i+1)] = &ExampleRef{\n\t\t\t\tValue: &Example{\n\t\t\t\t\tValue: value,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tdefault:\n\t}\n\treturn nil\n}\n\nfunc (r ExampleRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_external_docs.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ExternalDocs is specified by OpenAPI/Swagger standard version 3.0.\ntype ExternalDocs struct {\n\tURL         string `json:\"url,omitempty\"`\n\tDescription string `json:\"description,omitempty\"`\n}\n\nfunc (ed *ExternalDocs) UnmarshalValue(value any) error {\n\tvar valueBytes = gconv.Bytes(value)\n\tif json.Valid(valueBytes) {\n\t\treturn json.UnmarshalUseNumber(valueBytes, ed)\n\t}\n\tvar (\n\t\tvalueString = string(valueBytes)\n\t\tvalueArray  = gstr.Split(valueString, \"|\")\n\t)\n\ted.URL = valueArray[0]\n\tif len(valueArray) > 1 {\n\t\ted.Description = valueArray[1]\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/goai/goai_header.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Header is specified by OpenAPI/Swagger 3.0 standard.\n// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#headerObject\ntype Header struct {\n\tParameter\n}\n\ntype Headers map[string]HeaderRef\n\ntype HeaderRef struct {\n\tRef   string\n\tValue *Header\n}\n\nfunc (r HeaderRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_info.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// Info is specified by OpenAPI/Swagger standard version 3.0.\ntype Info struct {\n\tTitle          string   `json:\"title\"`\n\tDescription    string   `json:\"description,omitempty\"`\n\tTermsOfService string   `json:\"termsOfService,omitempty\"`\n\tContact        *Contact `json:\"contact,omitempty\"`\n\tLicense        *License `json:\"license,omitempty\"`\n\tVersion        string   `json:\"version\"`\n}\n\n// Contact is specified by OpenAPI/Swagger standard version 3.0.\ntype Contact struct {\n\tName  string `json:\"name,omitempty\"`\n\tURL   string `json:\"url,omitempty\"`\n\tEmail string `json:\"email,omitempty\"`\n}\n\n// License is specified by OpenAPI/Swagger standard version 3.0.\ntype License struct {\n\tName string `json:\"name\"`\n\tURL  string `json:\"url,omitempty\"`\n}\n"
  },
  {
    "path": "net/goai/goai_link.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Link is specified by OpenAPI/Swagger standard version 3.0.\ntype Link struct {\n\tOperationID  string         `json:\"operationId,omitempty\"`\n\tOperationRef string         `json:\"operationRef,omitempty\"`\n\tDescription  string         `json:\"description,omitempty\"`\n\tParameters   map[string]any `json:\"parameters,omitempty\"`\n\tServer       *Server        `json:\"server,omitempty\"`\n\tRequestBody  any            `json:\"requestBody,omitempty\"`\n}\n\ntype Links map[string]LinkRef\n\ntype LinkRef struct {\n\tRef   string\n\tValue *Link\n}\n\nfunc (r LinkRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_mediatype.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// MediaType is specified by OpenAPI/Swagger 3.0 standard.\ntype MediaType struct {\n\tSchema   *SchemaRef           `json:\"schema,omitempty\"`\n\tExample  any                  `json:\"example,omitempty\"`\n\tExamples Examples             `json:\"examples,omitempty\"`\n\tEncoding map[string]*Encoding `json:\"encoding,omitempty\"`\n}\n\n// Content is specified by OpenAPI/Swagger 3.0 standard.\ntype Content map[string]MediaType\n\n// Encoding is specified by OpenAPI/Swagger 3.0 standard.\ntype Encoding struct {\n\tContentType   string  `json:\"contentType,omitempty\"`\n\tHeaders       Headers `json:\"headers,omitempty\"`\n\tStyle         string  `json:\"style,omitempty\"`\n\tExplode       *bool   `json:\"explode,omitempty\"`\n\tAllowReserved bool    `json:\"allowReserved,omitempty\"`\n}\n"
  },
  {
    "path": "net/goai/goai_operation.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Operation represents \"operation\" specified by OpenAPI/Swagger 3.0 standard.\ntype Operation struct {\n\tTags         []string              `json:\"tags,omitempty\"`\n\tSummary      string                `json:\"summary,omitempty\"`\n\tDescription  string                `json:\"description,omitempty\"`\n\tOperationID  string                `json:\"operationId,omitempty\"`\n\tParameters   Parameters            `json:\"parameters,omitempty\"`\n\tRequestBody  *RequestBodyRef       `json:\"requestBody,omitempty\"`\n\tResponses    Responses             `json:\"responses\"`\n\tDeprecated   bool                  `json:\"deprecated,omitempty\"`\n\tCallbacks    *Callbacks            `json:\"callbacks,omitempty\"`\n\tSecurity     *SecurityRequirements `json:\"security,omitempty\"`\n\tServers      *Servers              `json:\"servers,omitempty\"`\n\tExternalDocs *ExternalDocs         `json:\"externalDocs,omitempty\"`\n\tXExtensions  XExtensions           `json:\"-\"`\n}\n\nfunc (oai *OpenApiV3) tagMapToOperation(tagMap map[string]string, operation *Operation) error {\n\tvar mergedTagMap = oai.fillMapWithShortTags(tagMap)\n\tif err := gconv.Struct(mergedTagMap, operation); err != nil {\n\t\treturn gerror.Wrap(err, `mapping struct tags to Operation failed`)\n\t}\n\toai.tagMapToXExtensions(mergedTagMap, operation.XExtensions)\n\treturn nil\n}\n\nfunc (o Operation) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tb   []byte\n\t\tm   map[string]json.RawMessage\n\t\terr error\n\t)\n\ttype tempOperation Operation // To prevent JSON marshal recursion error.\n\tif b, err = json.Marshal(tempOperation(o)); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = json.Unmarshal(b, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range o.XExtensions {\n\t\tif b, err = json.Marshal(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[k] = b\n\t}\n\treturn json.Marshal(m)\n}\n"
  },
  {
    "path": "net/goai/goai_parameter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Parameter is specified by OpenAPI/Swagger 3.0 standard.\n// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#parameterObject\ntype Parameter struct {\n\tName            string      `json:\"name,omitempty\"`\n\tIn              string      `json:\"in,omitempty\"`\n\tDescription     string      `json:\"description,omitempty\"`\n\tStyle           string      `json:\"style,omitempty\"`\n\tExplode         *bool       `json:\"explode,omitempty\"`\n\tAllowEmptyValue bool        `json:\"allowEmptyValue,omitempty\"`\n\tAllowReserved   bool        `json:\"allowReserved,omitempty\"`\n\tDeprecated      bool        `json:\"deprecated,omitempty\"`\n\tRequired        bool        `json:\"required,omitempty\"`\n\tSchema          *SchemaRef  `json:\"schema,omitempty\"`\n\tExample         any         `json:\"example,omitempty\"`\n\tExamples        *Examples   `json:\"examples,omitempty\"`\n\tContent         *Content    `json:\"content,omitempty\"`\n\tXExtensions     XExtensions `json:\"-\"`\n}\n\nfunc (oai *OpenApiV3) tagMapToParameter(tagMap map[string]string, parameter *Parameter) error {\n\tvar mergedTagMap = oai.fillMapWithShortTags(tagMap)\n\tif err := gconv.Struct(mergedTagMap, parameter); err != nil {\n\t\treturn gerror.Wrap(err, `mapping struct tags to Parameter failed`)\n\t}\n\toai.tagMapToXExtensions(mergedTagMap, parameter.XExtensions)\n\treturn nil\n}\n\nfunc (p Parameter) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tb   []byte\n\t\tm   map[string]json.RawMessage\n\t\terr error\n\t)\n\ttype tempParameter Parameter // To prevent JSON marshal recursion error.\n\tif b, err = json.Marshal(tempParameter(p)); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = json.Unmarshal(b, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range p.XExtensions {\n\t\tif b, err = json.Marshal(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[k] = b\n\t}\n\treturn json.Marshal(m)\n}\n"
  },
  {
    "path": "net/goai/goai_parameter_ref.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Parameters is specified by OpenAPI/Swagger 3.0 standard.\ntype Parameters []ParameterRef\n\ntype ParameterRef struct {\n\tRef   string\n\tValue *Parameter\n}\n\nfunc (oai *OpenApiV3) newParameterRefWithStructMethod(field gstructs.Field, path, method string) (*ParameterRef, error) {\n\tvar (\n\t\ttagMap    = field.TagMap()\n\t\tfieldName = field.TagPriorityName()\n\t)\n\tfieldName = gstr.Split(gstr.Trim(fieldName), \",\")[0]\n\tif fieldName == \"\" {\n\t\tfieldName = field.Name()\n\t}\n\tvar parameter = &Parameter{\n\t\tName:        fieldName,\n\t\tXExtensions: make(XExtensions),\n\t}\n\tif len(tagMap) > 0 {\n\t\tif err := oai.tagMapToParameter(tagMap, parameter); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif parameter.In == \"\" {\n\t\t// Automatically detect its \"in\" attribute.\n\t\tif gstr.ContainsI(path, fmt.Sprintf(`{%s}`, parameter.Name)) {\n\t\t\tparameter.In = ParameterInPath\n\t\t} else {\n\t\t\t// Default the parameter input to \"query\" if method is \"GET/DELETE\".\n\t\t\tswitch gstr.ToUpper(method) {\n\t\t\tcase http.MethodGet, http.MethodDelete:\n\t\t\t\tparameter.In = ParameterInQuery\n\n\t\t\tdefault:\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch parameter.In {\n\tcase ParameterInPath:\n\t\t// Required for path parameter.\n\t\tparameter.Required = true\n\n\tcase ParameterInCookie, ParameterInHeader, ParameterInQuery:\n\n\tdefault:\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid tag value \"%s\" for In`, parameter.In)\n\t}\n\t// Necessary schema or content.\n\tschemaRef, err := oai.newSchemaRefWithGolangType(field.Type().Type, tagMap)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tparameter.Schema = schemaRef\n\n\t// Ignore parameter.\n\tif !isValidParameterName(parameter.Name) {\n\t\treturn nil, nil\n\t}\n\n\t// Required check.\n\tif parameter.Schema.Value != nil && parameter.Schema.Value.ValidationRules != \"\" {\n\t\tvalidationRuleArray := gstr.Split(parameter.Schema.Value.ValidationRules, \"|\")\n\t\tif gset.NewStrSetFrom(validationRuleArray).Contains(validationRuleKeyForRequired) {\n\t\t\tparameter.Required = true\n\t\t}\n\t}\n\n\treturn &ParameterRef{\n\t\tRef:   \"\",\n\t\tValue: parameter,\n\t}, nil\n}\n\nfunc (r ParameterRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_path.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"net/http\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// Path is specified by OpenAPI/Swagger standard version 3.0.\ntype Path struct {\n\tRef         string      `json:\"$ref,omitempty\"`\n\tSummary     string      `json:\"summary,omitempty\"`\n\tDescription string      `json:\"description,omitempty\"`\n\tConnect     *Operation  `json:\"connect,omitempty\"`\n\tDelete      *Operation  `json:\"delete,omitempty\"`\n\tGet         *Operation  `json:\"get,omitempty\"`\n\tHead        *Operation  `json:\"head,omitempty\"`\n\tOptions     *Operation  `json:\"options,omitempty\"`\n\tPatch       *Operation  `json:\"patch,omitempty\"`\n\tPost        *Operation  `json:\"post,omitempty\"`\n\tPut         *Operation  `json:\"put,omitempty\"`\n\tTrace       *Operation  `json:\"trace,omitempty\"`\n\tServers     Servers     `json:\"servers,omitempty\"`\n\tParameters  Parameters  `json:\"parameters,omitempty\"`\n\tXExtensions XExtensions `json:\"-\"`\n}\n\n// Paths are specified by OpenAPI/Swagger standard version 3.0.\ntype Paths map[string]Path\n\nconst (\n\tresponseOkKey = `200`\n)\n\ntype addPathInput struct {\n\tPath     string // Precise route path.\n\tPrefix   string // Route path prefix.\n\tMethod   string // Route method.\n\tFunction any    // Uniformed function.\n}\n\nfunc (oai *OpenApiV3) addPath(in addPathInput) error {\n\tif oai.Paths == nil {\n\t\toai.Paths = map[string]Path{}\n\t}\n\n\tvar reflectType = reflect.TypeOf(in.Function)\n\tif reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`unsupported function \"%s\" for OpenAPI Path register, there should be input & output structures`,\n\t\t\treflectType.String(),\n\t\t)\n\t}\n\tvar (\n\t\tinputObject  reflect.Value\n\t\toutputObject reflect.Value\n\t)\n\t// Create instance according input/output types.\n\tif reflectType.In(1).Kind() == reflect.Pointer {\n\t\tinputObject = reflect.New(reflectType.In(1).Elem()).Elem()\n\t} else {\n\t\tinputObject = reflect.New(reflectType.In(1)).Elem()\n\t}\n\tif reflectType.Out(0).Kind() == reflect.Pointer {\n\t\toutputObject = reflect.New(reflectType.Out(0).Elem()).Elem()\n\t} else {\n\t\toutputObject = reflect.New(reflectType.Out(0)).Elem()\n\t}\n\n\tvar (\n\t\t// mime                string\n\t\tpath                = Path{XExtensions: make(XExtensions)}\n\t\tinputMetaMap        = gmeta.Data(inputObject.Interface())\n\t\toutputMetaMap       = gmeta.Data(outputObject.Interface())\n\t\tisInputStructEmpty  = oai.doesStructHasNoFields(inputObject.Interface())\n\t\tinputStructTypeName = oai.golangTypeToSchemaName(inputObject.Type())\n\t\toperation           = Operation{\n\t\t\tResponses:   map[string]ResponseRef{},\n\t\t\tXExtensions: make(XExtensions),\n\t\t}\n\t\tseRequirement = SecurityRequirement{}\n\t)\n\t// Path check.\n\tif in.Path == \"\" {\n\t\tin.Path = gmeta.Get(inputObject.Interface(), gtag.Path).String()\n\t\tif in.Prefix != \"\" {\n\t\t\tin.Path = gstr.TrimRight(in.Prefix, \"/\") + \"/\" + gstr.TrimLeft(in.Path, \"/\")\n\t\t}\n\t}\n\tif in.Path == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t`missing necessary path parameter \"%s\" for input struct \"%s\", missing tag in attribute Meta?`,\n\t\t\tgtag.Path, inputStructTypeName,\n\t\t)\n\t}\n\n\tif v, ok := oai.Paths[in.Path]; ok {\n\t\tpath = v\n\t}\n\n\t// Method check.\n\tif in.Method == \"\" {\n\t\tin.Method = gmeta.Get(inputObject.Interface(), gtag.Method).String()\n\t}\n\tif in.Method == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeMissingParameter,\n\t\t\t`missing necessary method parameter \"%s\" for input struct \"%s\", missing tag in attribute Meta?`,\n\t\t\tgtag.Method, inputStructTypeName,\n\t\t)\n\t}\n\n\tif err := oai.addSchema(inputObject.Interface()); err != nil {\n\t\treturn err\n\t}\n\n\tif len(inputMetaMap) > 0 {\n\t\t// Path and Operation are not the same thing, so it is necessary to copy a Meta for Path from Operation and edit it.\n\t\t// And you know, we set the Summary and Description for Operation, not for Path, so we need to remove them.\n\t\tinputMetaMapForPath := gmap.NewStrStrMapFrom(inputMetaMap).Clone()\n\t\tinputMetaMapForPath.Removes([]string{\n\t\t\tgtag.SummaryShort,\n\t\t\tgtag.SummaryShort2,\n\t\t\tgtag.Summary,\n\t\t\tgtag.DescriptionShort,\n\t\t\tgtag.DescriptionShort2,\n\t\t\tgtag.Description,\n\t\t})\n\t\tif err := oai.tagMapToPath(inputMetaMapForPath.Map(), &path); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := oai.tagMapToOperation(inputMetaMap, &operation); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Allowed request mime.\n\t\t// if mime = inputMetaMap[gtag.Mime]; mime == \"\" {\n\t\t// \tmime = inputMetaMap[gtag.Consumes]\n\t\t// }\n\t}\n\n\t// path security\n\t// note: the security schema type only support http and apiKey;not support oauth2 and openIdConnect.\n\t// multi schema separate with comma, e.g. `security: apiKey1,apiKey2`\n\tTagNameSecurity := gmeta.Get(inputObject.Interface(), gtag.Security).String()\n\tsecurities := gstr.SplitAndTrim(TagNameSecurity, \",\")\n\tfor _, sec := range securities {\n\t\tseRequirement[sec] = []string{}\n\t}\n\tif len(securities) > 0 {\n\t\toperation.Security = &SecurityRequirements{seRequirement}\n\t}\n\n\t// =================================================================================================================\n\t// Request Parameter.\n\t// =================================================================================================================\n\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         inputObject.Interface(),\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t})\n\tfor _, structField := range structFields {\n\t\tif operation.Parameters == nil {\n\t\t\toperation.Parameters = []ParameterRef{}\n\t\t}\n\t\tparameterRef, err := oai.newParameterRefWithStructMethod(structField, in.Path, in.Method)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif parameterRef != nil {\n\t\t\toperation.Parameters = append(operation.Parameters, *parameterRef)\n\t\t}\n\t}\n\n\t// =================================================================================================================\n\t// Request Body.\n\t// =================================================================================================================\n\tif operation.RequestBody == nil {\n\t\toperation.RequestBody = &RequestBodyRef{}\n\t}\n\tif operation.RequestBody.Value == nil {\n\t\tvar (\n\t\t\trequestBody = RequestBody{\n\t\t\t\tContent: map[string]MediaType{},\n\t\t\t}\n\t\t)\n\t\t// Supported mime types of request.\n\t\tvar (\n\t\t\tcontentTypes     = oai.Config.ReadContentTypes\n\t\t\ttagMimeValue     = gmeta.Get(inputObject.Interface(), gtag.Mime).String()\n\t\t\ttagRequiredValue = gmeta.Get(inputObject.Interface(), gtag.Required).Bool()\n\t\t)\n\t\trequestBody.Required = tagRequiredValue\n\t\tif tagMimeValue != \"\" {\n\t\t\tcontentTypes = gstr.SplitAndTrim(tagMimeValue, \",\")\n\t\t}\n\t\tfor _, v := range contentTypes {\n\t\t\tif isInputStructEmpty {\n\t\t\t\trequestBody.Content[v] = MediaType{}\n\t\t\t} else {\n\t\t\t\tschemaRef, err := oai.getRequestSchemaRef(getRequestSchemaRefInput{\n\t\t\t\t\tBusinessStructName: inputStructTypeName,\n\t\t\t\t\tRequestObject:      oai.Config.CommonRequest,\n\t\t\t\t\tRequestDataField:   oai.Config.CommonRequestDataField,\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\trequestBody.Content[v] = MediaType{\n\t\t\t\t\tSchema: schemaRef,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toperation.RequestBody = &RequestBodyRef{\n\t\t\tValue: &requestBody,\n\t\t}\n\t}\n\n\t// =================================================================================================================\n\t// Default Response.\n\t// =================================================================================================================\n\tstatus := responseOkKey\n\tif statusValue, ok := outputMetaMap[gtag.Status]; ok {\n\t\tstatusCode := gconv.Int(statusValue)\n\t\tif statusCode < 100 || statusCode >= 600 {\n\t\t\treturn gerror.Newf(\"Invalid HTTP status code: %s\", statusValue)\n\t\t}\n\t\tstatus = statusValue\n\t}\n\tif _, ok := operation.Responses[status]; !ok {\n\t\tresponse, err := oai.getResponseFromObject(outputObject.Interface(), true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\toperation.Responses[status] = ResponseRef{Value: response}\n\t}\n\n\t// =================================================================================================================\n\t// Other Responses.\n\t// =================================================================================================================\n\tif enhancedResponse, ok := outputObject.Interface().(IEnhanceResponseStatus); ok {\n\t\tfor statusCode, data := range enhancedResponse.EnhanceResponseStatus() {\n\t\t\tif statusCode < 100 || statusCode >= 600 {\n\t\t\t\treturn gerror.Newf(\"Invalid HTTP status code: %d\", statusCode)\n\t\t\t}\n\t\t\tif data.Response == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tstatus := gconv.String(statusCode)\n\t\t\tif _, ok := operation.Responses[status]; !ok {\n\t\t\t\tresponse, err := oai.getResponseFromObject(data, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\toperation.Responses[status] = ResponseRef{Value: response}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove operation body duplicated properties.\n\toai.removeOperationDuplicatedProperties(&operation)\n\n\t// Assign to certain operation attribute.\n\tswitch gstr.ToUpper(in.Method) {\n\tcase http.MethodGet:\n\t\t// GET operations cannot have a requestBody.\n\t\toperation.RequestBody = nil\n\t\tpath.Get = &operation\n\n\tcase http.MethodPut:\n\t\tpath.Put = &operation\n\n\tcase http.MethodPost:\n\t\tpath.Post = &operation\n\n\tcase http.MethodDelete:\n\t\t// DELETE operations cannot have a requestBody.\n\t\toperation.RequestBody = nil\n\t\tpath.Delete = &operation\n\n\tcase http.MethodConnect:\n\t\t// Nothing to do for Connect.\n\n\tcase http.MethodHead:\n\t\tpath.Head = &operation\n\n\tcase http.MethodOptions:\n\t\tpath.Options = &operation\n\n\tcase http.MethodPatch:\n\t\tpath.Patch = &operation\n\n\tcase http.MethodTrace:\n\t\tpath.Trace = &operation\n\n\tdefault:\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid method \"%s\"`, in.Method)\n\t}\n\toai.Paths[in.Path] = path\n\treturn nil\n}\n\nfunc (oai *OpenApiV3) removeOperationDuplicatedProperties(operation *Operation) {\n\tif len(operation.Parameters) == 0 {\n\t\t// Nothing to do.\n\t\treturn\n\t}\n\n\tvar (\n\t\tduplicatedParameterNames []any\n\t\tdataField                string\n\t)\n\n\tfor _, parameter := range operation.Parameters {\n\t\tduplicatedParameterNames = append(duplicatedParameterNames, parameter.Value.Name)\n\t}\n\n\t// Check operation request body have common request data field.\n\tdataFields := gstr.Split(oai.Config.CommonRequestDataField, \".\")\n\tif len(dataFields) > 0 && dataFields[0] != \"\" {\n\t\tdataField = dataFields[0]\n\t}\n\n\tfor _, requestBodyContent := range operation.RequestBody.Value.Content {\n\t\t// Check request body schema\n\t\tif requestBodyContent.Schema == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check request body schema ref.\n\t\tif requestBodyContent.Schema.Ref != \"\" {\n\t\t\tif schema := oai.Components.Schemas.Get(requestBodyContent.Schema.Ref); schema != nil {\n\t\t\t\tnewSchema := schema.Value.Clone()\n\t\t\t\trequestBodyContent.Schema.Ref = \"\"\n\t\t\t\trequestBodyContent.Schema.Value = newSchema\n\t\t\t\tnewSchema.Required = oai.removeItemsFromArray(newSchema.Required, duplicatedParameterNames)\n\t\t\t\tnewSchema.Properties.Removes(duplicatedParameterNames)\n\t\t\t\t// remove request body if there are no properties left\n\t\t\t\tif newSchema.Properties.refs.IsEmpty() {\n\t\t\t\t\toperation.RequestBody = nil\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Check the Value public field for the request body.\n\t\tif commonRequest := requestBodyContent.Schema.Value.Properties.Get(dataField); commonRequest != nil {\n\t\t\tcommonRequest.Value.Required = oai.removeItemsFromArray(commonRequest.Value.Required, duplicatedParameterNames)\n\t\t\tcommonRequest.Value.Properties.Removes(duplicatedParameterNames)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check request body schema value.\n\t\tif requestBodyContent.Schema.Value != nil {\n\t\t\trequestBodyContent.Schema.Value.Required = oai.removeItemsFromArray(requestBodyContent.Schema.Value.Required, duplicatedParameterNames)\n\t\t\trequestBodyContent.Schema.Value.Properties.Removes(duplicatedParameterNames)\n\t\t\tcontinue\n\t\t}\n\t}\n}\n\nfunc (oai *OpenApiV3) removeItemsFromArray(array []string, items []any) []string {\n\tarr := garray.NewStrArrayFrom(array)\n\tfor _, item := range items {\n\t\tif value, ok := item.(string); ok {\n\t\t\tarr.RemoveValue(value)\n\t\t}\n\t}\n\treturn arr.Slice()\n}\n\nfunc (oai *OpenApiV3) doesStructHasNoFields(s any) bool {\n\treturn reflect.TypeOf(s).NumField() == 0\n}\n\nfunc (oai *OpenApiV3) tagMapToPath(tagMap map[string]string, path *Path) error {\n\tvar mergedTagMap = oai.fillMapWithShortTags(tagMap)\n\tif err := gconv.Struct(mergedTagMap, path); err != nil {\n\t\treturn gerror.Wrap(err, `mapping struct tags to Path failed`)\n\t}\n\toai.tagMapToXExtensions(mergedTagMap, path.XExtensions)\n\treturn nil\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (p Path) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tb   []byte\n\t\tm   map[string]json.RawMessage\n\t\terr error\n\t)\n\ttype tempPath Path // To prevent JSON marshal recursion error.\n\tif b, err = json.Marshal(tempPath(p)); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = json.Unmarshal(b, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range p.XExtensions {\n\t\tif b, err = json.Marshal(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[k] = b\n\t}\n\treturn json.Marshal(m)\n}\n"
  },
  {
    "path": "net/goai/goai_requestbody.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RequestBody is specified by OpenAPI/Swagger 3.0 standard.\ntype RequestBody struct {\n\tDescription string  `json:\"description,omitempty\"`\n\tRequired    bool    `json:\"required,omitempty\"`\n\tContent     Content `json:\"content,omitempty\"`\n}\n\ntype RequestBodyRef struct {\n\tRef   string\n\tValue *RequestBody\n}\n\nfunc (r RequestBodyRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n\ntype getRequestSchemaRefInput struct {\n\tBusinessStructName string\n\tRequestObject      any\n\tRequestDataField   string\n}\n\nfunc (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaRef, error) {\n\tif oai.Config.CommonRequest == nil {\n\t\treturn &SchemaRef{\n\t\t\tRef: in.BusinessStructName,\n\t\t}, nil\n\t}\n\n\tvar (\n\t\tdataFieldsPartsArray      = gstr.Split(in.RequestDataField, \".\")\n\t\tbizRequestStructSchemaRef = oai.Components.Schemas.Get(in.BusinessStructName)\n\t\tschema, err               = oai.structToSchema(in.RequestObject)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif bizRequestStructSchemaRef == nil {\n\t\treturn &SchemaRef{\n\t\t\tValue: schema,\n\t\t}, nil\n\t}\n\n\tif in.RequestDataField == \"\" && bizRequestStructSchemaRef.Value != nil {\n\t\t// Append bizRequest.\n\t\tschema.Required = append(schema.Required, bizRequestStructSchemaRef.Value.Required...)\n\n\t\t// Normal request.\n\t\tbizRequestStructSchemaRef.Value.Properties.Iterator(func(key string, ref SchemaRef) bool {\n\t\t\tschema.Properties.Set(key, ref)\n\t\t\treturn true\n\t\t})\n\t} else {\n\t\t// Common request.\n\t\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         in.RequestObject,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tfor _, structField := range structFields {\n\t\t\tvar fieldName = structField.Name()\n\t\t\tif jsonName := structField.TagJsonName(); jsonName != \"\" {\n\t\t\t\tfieldName = jsonName\n\t\t\t}\n\t\t\tswitch len(dataFieldsPartsArray) {\n\t\t\tcase 1:\n\t\t\t\tif structField.Name() == dataFieldsPartsArray[0] {\n\t\t\t\t\tif err = oai.tagMapToSchema(structField.TagMap(), bizRequestStructSchemaRef.Value); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tschema.Properties.Set(fieldName, *bizRequestStructSchemaRef)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif structField.Name() == dataFieldsPartsArray[0] {\n\t\t\t\t\tvar structFieldInstance = reflect.New(structField.Type().Type).Elem()\n\t\t\t\t\tschemaRef, err := oai.getRequestSchemaRef(getRequestSchemaRefInput{\n\t\t\t\t\t\tBusinessStructName: in.BusinessStructName,\n\t\t\t\t\t\tRequestObject:      structFieldInstance,\n\t\t\t\t\t\tRequestDataField:   gstr.Join(dataFieldsPartsArray[1:], \".\"),\n\t\t\t\t\t})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tschema.Properties.Set(fieldName, *schemaRef)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn &SchemaRef{\n\t\tValue: schema,\n\t}, nil\n}\n"
  },
  {
    "path": "net/goai/goai_response.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// EnhancedStatusCode is http status for response.\ntype EnhancedStatusCode = int\n\n// EnhancedStatusType is the structure for certain response status.\n// Currently, it only supports `Response` and `Examples`.\n// `Response` is the response structure\n// `Examples` is the examples for the response, map[string]any, []any are supported.\ntype EnhancedStatusType struct {\n\tResponse any\n\tExamples any\n}\n\n// IEnhanceResponseStatus is used to enhance the documentation of the response.\n// Normal response structure could implement this interface to provide more information.\ntype IEnhanceResponseStatus interface {\n\tEnhanceResponseStatus() map[EnhancedStatusCode]EnhancedStatusType\n}\n\n// Response is specified by OpenAPI/Swagger 3.0 standard.\ntype Response struct {\n\tDescription string      `json:\"description\"`\n\tHeaders     Headers     `json:\"headers,omitempty\"`\n\tContent     Content     `json:\"content,omitempty\"`\n\tLinks       Links       `json:\"links,omitempty\"`\n\tXExtensions XExtensions `json:\"-\"`\n}\n\nfunc (oai *OpenApiV3) tagMapToResponse(tagMap map[string]string, response *Response) error {\n\tvar mergedTagMap = oai.fillMapWithShortTags(tagMap)\n\tif err := gconv.Struct(mergedTagMap, response); err != nil {\n\t\treturn gerror.Wrap(err, `mapping struct tags to Response failed`)\n\t}\n\toai.tagMapToXExtensions(mergedTagMap, response.XExtensions)\n\treturn nil\n}\n\nfunc (r Response) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tb   []byte\n\t\tm   map[string]json.RawMessage\n\t\terr error\n\t)\n\ttype tempResponse Response // To prevent JSON marshal recursion error.\n\tif b, err = json.Marshal(tempResponse(r)); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = json.Unmarshal(b, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range r.XExtensions {\n\t\tif b, err = json.Marshal(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[k] = b\n\t}\n\treturn json.Marshal(m)\n}\n"
  },
  {
    "path": "net/goai/goai_response_ref.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\ntype ResponseRef struct {\n\tRef   string\n\tValue *Response\n}\n\n// Responses is specified by OpenAPI/Swagger 3.0 standard.\ntype Responses map[string]ResponseRef\n\n// object could be someObject.Interface()\n// There may be some difference between someObject.Type() and reflect.TypeOf(object).\nfunc (oai *OpenApiV3) getResponseFromObject(data any, isDefault bool) (*Response, error) {\n\tvar object any\n\tenhancedResponse, isEnhanced := data.(EnhancedStatusType)\n\tif isEnhanced {\n\t\tobject = enhancedResponse.Response\n\t} else {\n\t\tobject = data\n\t}\n\t// Add object schema to oai\n\tif err := oai.addSchema(object); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tmetaMap  = gmeta.Data(object)\n\t\tresponse = &Response{\n\t\t\tContent:     map[string]MediaType{},\n\t\t\tXExtensions: make(XExtensions),\n\t\t}\n\t)\n\tif len(metaMap) > 0 {\n\t\tif err := oai.tagMapToResponse(metaMap, response); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\t// Supported mime types of response.\n\tvar (\n\t\tcontentTypes = oai.Config.ReadContentTypes\n\t\ttagMimeValue = gmeta.Get(object, gtag.Mime).String()\n\t\trefInput     = getResponseSchemaRefInput{\n\t\t\tBusinessStructName:      oai.golangTypeToSchemaName(reflect.TypeOf(object)),\n\t\t\tCommonResponseObject:    oai.Config.CommonResponse,\n\t\t\tCommonResponseDataField: oai.Config.CommonResponseDataField,\n\t\t}\n\t)\n\n\t// If customized response mime type, it then ignores common response feature.\n\tif tagMimeValue != \"\" {\n\t\tcontentTypes = gstr.SplitAndTrim(tagMimeValue, \",\")\n\t\trefInput.CommonResponseObject = nil\n\t\trefInput.CommonResponseDataField = \"\"\n\t}\n\n\t// If it is not default status, check if it has any fields.\n\t// If so, it would override the common response.\n\tif !isDefault {\n\t\tfields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         object,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tif len(fields) > 0 {\n\t\t\trefInput.CommonResponseObject = nil\n\t\t\trefInput.CommonResponseDataField = \"\"\n\t\t}\n\t}\n\n\t// Generate response example from meta data.\n\tresponseExamplePath := metaMap[gtag.ResponseExampleShort]\n\tif responseExamplePath == \"\" {\n\t\tresponseExamplePath = metaMap[gtag.ResponseExample]\n\t}\n\texamples := make(Examples)\n\tif responseExamplePath != \"\" {\n\t\tif err := examples.applyExamplesFile(responseExamplePath); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Override examples from enhanced response.\n\tif isEnhanced {\n\t\terr := examples.applyExamplesData(enhancedResponse.Examples)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Generate response schema from input.\n\tschemaRef, err := oai.getResponseSchemaRef(refInput)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, contentType := range contentTypes {\n\t\tresponse.Content[contentType] = MediaType{\n\t\t\tSchema:   schemaRef,\n\t\t\tExamples: examples,\n\t\t}\n\t}\n\treturn response, nil\n}\n\nfunc (r ResponseRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n\ntype getResponseSchemaRefInput struct {\n\tBusinessStructName      string // The business struct name.\n\tCommonResponseObject    any    // Common response object.\n\tCommonResponseDataField string // Common response data field.\n}\n\nfunc (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*SchemaRef, error) {\n\tif in.CommonResponseObject == nil {\n\t\treturn &SchemaRef{\n\t\t\tRef: in.BusinessStructName,\n\t\t}, nil\n\t}\n\n\tvar (\n\t\tdataFieldsPartsArray       = gstr.Split(in.CommonResponseDataField, \".\")\n\t\tbizResponseStructSchemaRef = oai.Components.Schemas.Get(in.BusinessStructName)\n\t\tschema, err                = oai.structToSchema(in.CommonResponseObject)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif in.CommonResponseDataField == \"\" && bizResponseStructSchemaRef != nil {\n\t\t// Normal response.\n\t\tbizResponseStructSchemaRef.Value.Properties.Iterator(func(key string, ref SchemaRef) bool {\n\t\t\tschema.Properties.Set(key, ref)\n\t\t\treturn true\n\t\t})\n\t} else {\n\t\t// Common response.\n\t\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         in.CommonResponseObject,\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tfor _, structField := range structFields {\n\t\t\tvar fieldName = structField.Name()\n\t\t\tif jsonName := structField.TagJsonName(); jsonName != \"\" {\n\t\t\t\tfieldName = jsonName\n\t\t\t}\n\t\t\tswitch len(dataFieldsPartsArray) {\n\t\t\tcase 1:\n\t\t\t\tif structField.Name() == dataFieldsPartsArray[0] {\n\t\t\t\t\tif err = oai.tagMapToSchema(structField.TagMap(), bizResponseStructSchemaRef.Value); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tschema.Properties.Set(fieldName, *bizResponseStructSchemaRef)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\t// Recursively creating common response object schema.\n\t\t\t\tif structField.Name() == dataFieldsPartsArray[0] {\n\t\t\t\t\tvar structFieldInstance = reflect.New(structField.Type().Type).Elem()\n\t\t\t\t\tschemaRef, err := oai.getResponseSchemaRef(getResponseSchemaRefInput{\n\t\t\t\t\t\tBusinessStructName:      in.BusinessStructName,\n\t\t\t\t\t\tCommonResponseObject:    structFieldInstance,\n\t\t\t\t\t\tCommonResponseDataField: gstr.Join(dataFieldsPartsArray[1:], \".\"),\n\t\t\t\t\t})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tschema.Properties.Set(fieldName, *schemaRef)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &SchemaRef{\n\t\tValue: schema,\n\t}, nil\n}\n"
  },
  {
    "path": "net/goai/goai_security.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\ntype SecurityScheme struct {\n\tType             string      `json:\"type,omitempty\"`\n\tDescription      string      `json:\"description,omitempty\"`\n\tName             string      `json:\"name,omitempty\"`\n\tIn               string      `json:\"in,omitempty\"`\n\tScheme           string      `json:\"scheme,omitempty\"`\n\tBearerFormat     string      `json:\"bearerFormat,omitempty\"`\n\tFlows            *OAuthFlows `json:\"flows,omitempty\"`\n\tOpenIdConnectUrl string      `json:\"openIdConnectUrl,omitempty\"`\n}\n\ntype SecuritySchemes map[string]SecuritySchemeRef\n\ntype SecuritySchemeRef struct {\n\tRef   string\n\tValue *SecurityScheme\n}\n\ntype SecurityRequirements []SecurityRequirement\n\ntype SecurityRequirement map[string][]string\n\ntype OAuthFlows struct {\n\tImplicit          *OAuthFlow `json:\"implicit,omitempty\"`\n\tPassword          *OAuthFlow `json:\"password,omitempty\"`\n\tClientCredentials *OAuthFlow `json:\"clientCredentials,omitempty\"`\n\tAuthorizationCode *OAuthFlow `json:\"authorizationCode,omitempty\"`\n}\n\ntype OAuthFlow struct {\n\tAuthorizationURL string            `json:\"authorizationUrl,omitempty\"`\n\tTokenURL         string            `json:\"tokenUrl,omitempty\"`\n\tRefreshURL       string            `json:\"refreshUrl,omitempty\"`\n\tScopes           map[string]string `json:\"scopes\"`\n}\n\nfunc (r SecuritySchemeRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefToBytes(r.Ref), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// Server is specified by OpenAPI/Swagger standard version 3.0.\ntype Server struct {\n\tURL         string                     `json:\"url\"`\n\tDescription string                     `json:\"description,omitempty\"`\n\tVariables   map[string]*ServerVariable `json:\"variables,omitempty\"`\n}\n\n// ServerVariable is specified by OpenAPI/Swagger standard version 3.0.\ntype ServerVariable struct {\n\tEnum        []string `json:\"enum,omitempty\"`\n\tDefault     string   `json:\"default,omitempty\"`\n\tDescription string   `json:\"description,omitempty\"`\n}\n\n// Servers is specified by OpenAPI/Swagger standard version 3.0.\ntype Servers []Server\n"
  },
  {
    "path": "net/goai/goai_shema.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\n// Schema is specified by OpenAPI/Swagger 3.0 standard.\ntype Schema struct {\n\tOneOf                SchemaRefs     `json:\"oneOf,omitempty\"`\n\tAnyOf                SchemaRefs     `json:\"anyOf,omitempty\"`\n\tAllOf                SchemaRefs     `json:\"allOf,omitempty\"`\n\tNot                  *SchemaRef     `json:\"not,omitempty\"`\n\tType                 string         `json:\"type,omitempty\"`\n\tTitle                string         `json:\"title,omitempty\"`\n\tFormat               string         `json:\"format,omitempty\"`\n\tDescription          string         `json:\"description,omitempty\"`\n\tEnum                 []any          `json:\"enum,omitempty\"`\n\tDefault              any            `json:\"default,omitempty\"`\n\tExample              any            `json:\"example,omitempty\"`\n\tExternalDocs         *ExternalDocs  `json:\"externalDocs,omitempty\"`\n\tUniqueItems          bool           `json:\"uniqueItems,omitempty\"`\n\tExclusiveMin         bool           `json:\"exclusiveMinimum,omitempty\"`\n\tExclusiveMax         bool           `json:\"exclusiveMaximum,omitempty\"`\n\tNullable             bool           `json:\"nullable,omitempty\"`\n\tReadOnly             bool           `json:\"readOnly,omitempty\"`\n\tWriteOnly            bool           `json:\"writeOnly,omitempty\"`\n\tAllowEmptyValue      bool           `json:\"allowEmptyValue,omitempty\"`\n\tXML                  any            `json:\"xml,omitempty\"`\n\tDeprecated           bool           `json:\"deprecated,omitempty\"`\n\tMin                  *float64       `json:\"minimum,omitempty\"`\n\tMax                  *float64       `json:\"maximum,omitempty\"`\n\tMultipleOf           *float64       `json:\"multipleOf,omitempty\"`\n\tMinLength            uint64         `json:\"minLength,omitempty\"`\n\tMaxLength            *uint64        `json:\"maxLength,omitempty\"`\n\tPattern              string         `json:\"pattern,omitempty\"`\n\tMinItems             uint64         `json:\"minItems,omitempty\"`\n\tMaxItems             *uint64        `json:\"maxItems,omitempty\"`\n\tItems                *SchemaRef     `json:\"items,omitempty\"`\n\tRequired             []string       `json:\"required,omitempty\"`\n\tProperties           *Schemas       `json:\"properties,omitempty\"`\n\tMinProps             uint64         `json:\"minProperties,omitempty\"`\n\tMaxProps             *uint64        `json:\"maxProperties,omitempty\"`\n\tAdditionalProperties *SchemaRef     `json:\"additionalProperties,omitempty\"`\n\tDiscriminator        *Discriminator `json:\"discriminator,omitempty\"`\n\tXExtensions          XExtensions    `json:\"-\"`\n\tValidationRules      string         `json:\"-\"`\n}\n\n// Clone only clones necessary attributes.\n// TODO clone all attributes, or improve package deepcopy.\nfunc (s *Schema) Clone() *Schema {\n\tnewSchema := *s\n\tnewSchema.Required = make([]string, len(s.Required))\n\tcopy(newSchema.Required, s.Required)\n\tnewSchema.Properties = s.Properties.Clone()\n\treturn &newSchema\n}\n\nfunc (s Schema) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tb   []byte\n\t\tm   map[string]json.RawMessage\n\t\terr error\n\t)\n\ttype tempSchema Schema // To prevent JSON marshal recursion error.\n\tif b, err = json.Marshal(tempSchema(s)); err != nil {\n\t\treturn nil, err\n\t}\n\tif err = json.Unmarshal(b, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range s.XExtensions {\n\t\tif b, err = json.Marshal(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[k] = b\n\t}\n\treturn json.Marshal(m)\n}\n\n// Discriminator is specified by OpenAPI/Swagger standard version 3.0.\ntype Discriminator struct {\n\tPropertyName string            `json:\"propertyName\"`\n\tMapping      map[string]string `json:\"mapping,omitempty\"`\n}\n\n// addSchema creates schemas with objects.\n// Note that the `object` can be array alias like: `type Res []Item`.\nfunc (oai *OpenApiV3) addSchema(object ...any) error {\n\tfor _, v := range object {\n\t\tif err := oai.doAddSchemaSingle(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (oai *OpenApiV3) doAddSchemaSingle(object any) error {\n\tif oai.Components.Schemas.refs == nil {\n\t\toai.Components.Schemas.refs = gmap.NewListMap()\n\t}\n\n\tvar (\n\t\treflectType    = reflect.TypeOf(object)\n\t\tstructTypeName = oai.golangTypeToSchemaName(reflectType)\n\t)\n\n\t// Already added.\n\tif oai.Components.Schemas.Get(structTypeName) != nil {\n\t\treturn nil\n\t}\n\t// Take the holder first.\n\toai.Components.Schemas.Set(structTypeName, SchemaRef{})\n\n\tschema, err := oai.structToSchema(object)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toai.Components.Schemas.Set(structTypeName, SchemaRef{\n\t\tRef:   \"\",\n\t\tValue: schema,\n\t})\n\treturn nil\n}\n\n// structToSchema converts and returns given struct object as Schema.\nfunc (oai *OpenApiV3) structToSchema(object any) (*Schema, error) {\n\tvar (\n\t\ttagMap = gmeta.Data(object)\n\t\tschema = &Schema{\n\t\t\tProperties:  createSchemas(),\n\t\t\tXExtensions: make(XExtensions),\n\t\t}\n\t\tignoreProperties []any\n\t)\n\tif len(tagMap) > 0 {\n\t\tif err := oai.tagMapToSchema(tagMap, schema); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif schema.Type != \"\" && schema.Type != TypeObject {\n\t\treturn schema, nil\n\t}\n\t// []struct.\n\tif utils.IsArray(object) {\n\t\tschema.Type = TypeArray\n\t\tsubSchemaRef, err := oai.newSchemaRefWithGolangType(reflect.TypeOf(object).Elem(), nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschema.Items = subSchemaRef\n\t\tif len(schema.Enum) > 0 {\n\t\t\tschema.Items.Value.Enum = schema.Enum\n\t\t\tschema.Enum = nil\n\t\t}\n\t\treturn schema, nil\n\t}\n\t// struct.\n\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         object,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbedded,\n\t})\n\tschema.Type = TypeObject\n\tfor _, structField := range structFields {\n\t\tif !gstr.IsLetterUpper(structField.Name()[0]) {\n\t\t\tcontinue\n\t\t}\n\t\tvar fieldName = structField.TagPriorityName()\n\t\tfieldName = gstr.Split(gstr.Trim(fieldName), \",\")[0]\n\t\tif fieldName == \"\" {\n\t\t\tfieldName = structField.Name()\n\t\t}\n\t\tschemaRef, err := oai.newSchemaRefWithGolangType(\n\t\t\tstructField.Type().Type,\n\t\t\tstructField.TagMap(),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschema.Properties.Set(fieldName, *schemaRef)\n\t}\n\n\tschema.Properties.Iterator(func(key string, ref SchemaRef) bool {\n\t\tif ref.Value != nil && ref.Value.ValidationRules != \"\" {\n\t\t\tvalidationRuleSet := gset.NewStrSetFrom(gstr.Split(ref.Value.ValidationRules, \"|\"))\n\t\t\tif validationRuleSet.Contains(validationRuleKeyForRequired) {\n\t\t\t\tschema.Required = append(schema.Required, key)\n\t\t\t}\n\n\t\t\t// Extract validation rules to schema. like min, max, length\n\t\t\tlstRules := gstr.Split(ref.Value.ValidationRules, \"|\")\n\t\t\tfor _, rule := range lstRules {\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForMax) {\n\t\t\t\t\tif ref.Value.Type == \"integer\" || ref.Value.Type == \"number\" {\n\t\t\t\t\t\tf := gconv.Float64(rule[4:])\n\t\t\t\t\t\tref.Value.Max = &f\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForMaxLength) {\n\t\t\t\t\tmaxlength := gconv.Uint64(rule[11:])\n\t\t\t\t\tref.Value.MaxLength = &maxlength\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForMin) {\n\t\t\t\t\tif ref.Value.Type == \"integer\" || ref.Value.Type == \"number\" {\n\t\t\t\t\t\tf := gconv.Float64(rule[4:])\n\t\t\t\t\t\tref.Value.Min = &f\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForMinLength) {\n\t\t\t\t\tminlength := gconv.Uint64(rule[11:])\n\t\t\t\t\tref.Value.MinLength = minlength\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForLength) {\n\t\t\t\t\tlengthRule := gstr.Split(rule[7:], \",\")\n\t\t\t\t\tif len(lengthRule) == 2 {\n\t\t\t\t\t\tminlength := gconv.Uint64(lengthRule[0])\n\t\t\t\t\t\tref.Value.MinLength = minlength\n\t\t\t\t\t\tmaxlength := gconv.Uint64(lengthRule[1])\n\t\t\t\t\t\tref.Value.MaxLength = &maxlength\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(rule, validationRuleKeyForBetween) {\n\t\t\t\t\tif ref.Value.Type == \"integer\" || ref.Value.Type == \"number\" {\n\t\t\t\t\t\tlengthRule := gstr.Split(rule[8:], \",\")\n\t\t\t\t\t\tif len(lengthRule) == 2 {\n\t\t\t\t\t\t\tminimum := gconv.Float64(lengthRule[0])\n\t\t\t\t\t\t\tref.Value.Min = &minimum\n\t\t\t\t\t\t\tmaximum := gconv.Float64(lengthRule[1])\n\t\t\t\t\t\t\tref.Value.Max = &maximum\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !isValidParameterName(key) {\n\t\t\tignoreProperties = append(ignoreProperties, key)\n\t\t}\n\t\treturn true\n\t})\n\n\tif len(ignoreProperties) > 0 {\n\t\tschema.Properties.Removes(ignoreProperties)\n\t}\n\n\treturn schema, nil\n}\n\nfunc (oai *OpenApiV3) tagMapToSchema(tagMap map[string]string, schema *Schema) error {\n\tvar mergedTagMap = oai.fillMapWithShortTags(tagMap)\n\tif err := gconv.Struct(mergedTagMap, schema); err != nil {\n\t\treturn gerror.Wrap(err, `mapping struct tags to Schema failed`)\n\t}\n\toai.tagMapToXExtensions(mergedTagMap, schema.XExtensions)\n\t// Validation info to OpenAPI schema pattern.\n\tfor _, tag := range gvalid.GetTags() {\n\t\tif validationTagValue, ok := tagMap[tag]; ok {\n\t\t\t_, validationRules, _ := gvalid.ParseTagValue(validationTagValue)\n\t\t\tschema.ValidationRules = validationRules\n\t\t\t// Enum checks.\n\t\t\tif len(schema.Enum) == 0 {\n\t\t\t\tfor _, rule := range gstr.SplitAndTrim(validationRules, \"|\") {\n\t\t\t\t\tif gstr.HasPrefix(rule, validationRuleKeyForIn) {\n\t\t\t\t\t\tvar (\n\t\t\t\t\t\t\tisAllEnumNumber = true\n\t\t\t\t\t\t\tenumArray       = gstr.SplitAndTrim(rule[len(validationRuleKeyForIn):], \",\")\n\t\t\t\t\t\t)\n\t\t\t\t\t\tfor _, enum := range enumArray {\n\t\t\t\t\t\t\tif !gstr.IsNumeric(enum) {\n\t\t\t\t\t\t\t\tisAllEnumNumber = false\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif isAllEnumNumber {\n\t\t\t\t\t\t\tschema.Enum = gconv.Interfaces(gconv.Int64s(enumArray))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tschema.Enum = gconv.Interfaces(enumArray)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "net/goai/goai_shema_ref.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\ntype SchemaRefs []SchemaRef\n\ntype SchemaRef struct {\n\tRef         string\n\tDescription string\n\tValue       *Schema\n}\n\n// isEmbeddedStructDefinition checks and returns whether given golang type is embedded struct definition, like:\n//\n//\tstruct A struct{\n//\t    B struct{\n//\t        // ...\n//\t    }\n//\t}\n//\n// The `B` in `A` is called `embedded struct definition`.\nfunc (oai *OpenApiV3) isEmbeddedStructDefinition(golangType reflect.Type) bool {\n\ts := golangType.String()\n\treturn gstr.Contains(s, `struct {`)\n}\n\n// newSchemaRefWithGolangType creates a new Schema and returns its SchemaRef.\nfunc (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap map[string]string) (*SchemaRef, error) {\n\tvar (\n\t\terr       error\n\t\toaiType   = oai.golangTypeToOAIType(golangType)\n\t\toaiFormat = oai.golangTypeToOAIFormat(golangType)\n\t\ttypeName  = golangType.Name()\n\t\tpkgPath   = golangType.PkgPath()\n\t\tschemaRef = &SchemaRef{}\n\t\tschema    = &Schema{\n\t\t\tType:        oaiType,\n\t\t\tFormat:      oaiFormat,\n\t\t\tXExtensions: make(XExtensions),\n\t\t}\n\t)\n\tif pkgPath == \"\" {\n\t\tswitch golangType.Kind() {\n\t\tcase reflect.Pointer, reflect.Array, reflect.Slice:\n\t\t\tpkgPath = golangType.Elem().PkgPath()\n\t\t\ttypeName = golangType.Elem().Name()\n\t\tdefault:\n\t\t}\n\t}\n\n\t// Type enums.\n\tvar typeId = fmt.Sprintf(`%s.%s`, pkgPath, typeName)\n\tif enums := gtag.GetEnumsByType(typeId); enums != \"\" {\n\t\tschema.Enum = make([]any, 0)\n\t\tif err = json.Unmarshal([]byte(enums), &schema.Enum); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif len(tagMap) > 0 {\n\t\tif err = oai.tagMapToSchema(tagMap, schema); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif oaiType == TypeArray && schema.Type == TypeFile {\n\t\t\tschema.Type = TypeArray\n\t\t}\n\t}\n\tschemaRef.Value = schema\n\tswitch schema.Type {\n\tcase TypeString, TypeFile:\n\t// Nothing to do.\n\tcase TypeInteger:\n\t\tif schemaRef.Value.Default != nil {\n\t\t\tschemaRef.Value.Default = gconv.Int64(schemaRef.Value.Default)\n\t\t}\n\t\t// keep the default value as nil.\n\n\t\t// example value needs to be converted just like default value\n\t\tif schemaRef.Value.Example != nil {\n\t\t\tschemaRef.Value.Example = gconv.Int64(schemaRef.Value.Example)\n\t\t}\n\t\t// keep the example value as nil.\n\tcase TypeNumber:\n\t\tif schemaRef.Value.Default != nil {\n\t\t\tschemaRef.Value.Default = gconv.Float64(schemaRef.Value.Default)\n\t\t}\n\t\t// keep the default value as nil.\n\n\t\t// example value needs to be converted just like default value\n\t\tif schemaRef.Value.Example != nil {\n\t\t\tschemaRef.Value.Example = gconv.Float64(schemaRef.Value.Example)\n\t\t}\n\t\t// keep the example value as nil.\n\tcase TypeBoolean:\n\t\tif schemaRef.Value.Default != nil {\n\t\t\tschemaRef.Value.Default = gconv.Bool(schemaRef.Value.Default)\n\t\t}\n\t\t// keep the default value as nil.\n\n\t\t// example value needs to be converted just like default value\n\t\tif schemaRef.Value.Example != nil {\n\t\t\tschemaRef.Value.Example = gconv.Bool(schemaRef.Value.Example)\n\t\t}\n\t\t// keep the example value as nil.\n\tcase TypeArray:\n\t\tsubSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschema.Items = subSchemaRef\n\t\tif len(schema.Enum) > 0 {\n\t\t\tschema.Items.Value.Enum = schema.Enum\n\t\t\tschema.Enum = nil\n\t\t}\n\n\tcase TypeObject:\n\t\tfor golangType.Kind() == reflect.Pointer {\n\t\t\tgolangType = golangType.Elem()\n\t\t}\n\t\tswitch golangType.Kind() {\n\t\tcase reflect.Map:\n\t\t\t// Specially for map type.\n\t\t\tsubSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tschema.AdditionalProperties = subSchemaRef\n\t\t\treturn schemaRef, nil\n\n\t\tcase reflect.Interface:\n\t\t\t// Specially for interface type.\n\t\t\tvar structTypeName = oai.golangTypeToSchemaName(golangType)\n\t\t\tif oai.Components.Schemas.Get(structTypeName) == nil {\n\t\t\t\tif err = oai.addSchema(reflect.New(golangType).Interface()); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tschemaRef.Ref = structTypeName\n\t\t\tschemaRef.Value = nil\n\n\t\tdefault:\n\t\t\tgolangTypeInstance := reflect.New(golangType).Elem().Interface()\n\t\t\tif oai.isEmbeddedStructDefinition(golangType) {\n\t\t\t\tschema, err = oai.structToSchema(golangTypeInstance)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tschemaRef.Ref = \"\"\n\t\t\t\tschemaRef.Value = schema\n\t\t\t} else {\n\t\t\t\tvar structTypeName = oai.golangTypeToSchemaName(golangType)\n\t\t\t\tif oai.Components.Schemas.Get(structTypeName) == nil {\n\t\t\t\t\tif err = oai.addSchema(golangTypeInstance); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tschemaRef.Ref = structTypeName\n\t\t\t\tschemaRef.Value = schema\n\t\t\t\tschemaRef.Description = schema.Description\n\t\t\t}\n\t\t}\n\t}\n\treturn schemaRef, nil\n}\n\nfunc (r SchemaRef) MarshalJSON() ([]byte, error) {\n\tif r.Ref != \"\" {\n\t\treturn formatRefAndDescToBytes(r.Ref, r.Description), nil\n\t}\n\treturn json.Marshal(r.Value)\n}\n"
  },
  {
    "path": "net/goai/goai_shemas.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\ntype Schemas struct {\n\trefs *gmap.ListMap // map[string]SchemaRef\n}\n\nfunc createSchemas() *Schemas {\n\treturn &Schemas{\n\t\trefs: gmap.NewListMap(),\n\t}\n}\n\nfunc (s *Schemas) init() {\n\tif s.refs == nil {\n\t\ts.refs = gmap.NewListMap()\n\t}\n}\n\nfunc (s *Schemas) Clone() *Schemas {\n\tnewSchemas := createSchemas()\n\tnewSchemas.refs = s.refs.Clone()\n\treturn newSchemas\n}\n\nfunc (s *Schemas) Get(name string) *SchemaRef {\n\ts.init()\n\tvalue := s.refs.Get(name)\n\tif value != nil {\n\t\tref := value.(SchemaRef)\n\t\treturn &ref\n\t}\n\treturn nil\n}\n\nfunc (s *Schemas) Set(name string, ref SchemaRef) {\n\ts.init()\n\ts.refs.Set(name, ref)\n}\n\nfunc (s *Schemas) Removes(names []any) {\n\ts.init()\n\ts.refs.Removes(names)\n}\n\nfunc (s *Schemas) Map() map[string]SchemaRef {\n\ts.init()\n\tm := make(map[string]SchemaRef)\n\ts.refs.Iterator(func(key, value any) bool {\n\t\tm[key.(string)] = value.(SchemaRef)\n\t\treturn true\n\t})\n\treturn m\n}\n\nfunc (s *Schemas) Iterator(f func(key string, ref SchemaRef) bool) {\n\ts.init()\n\ts.refs.Iterator(func(key, value any) bool {\n\t\treturn f(key.(string), value.(SchemaRef))\n\t})\n}\n\nfunc (s Schemas) MarshalJSON() ([]byte, error) {\n\ts.init()\n\treturn s.refs.MarshalJSON()\n}\n"
  },
  {
    "path": "net/goai/goai_tags.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\n// Tags is specified by OpenAPI/Swagger 3.0 standard.\ntype Tags []Tag\n\n// Tag is specified by OpenAPI/Swagger 3.0 standard.\ntype Tag struct {\n\tName         string        `json:\"name,omitempty\"`\n\tDescription  string        `json:\"description,omitempty\"`\n\tExternalDocs *ExternalDocs `json:\"externalDocs,omitempty\"`\n}\n"
  },
  {
    "path": "net/goai/goai_xextensions.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai\n\nimport (\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// XExtensions stores the `x-` custom extensions.\ntype XExtensions map[string]string\n\nfunc (oai *OpenApiV3) tagMapToXExtensions(tagMap map[string]string, extensions XExtensions) {\n\tfor k, v := range tagMap {\n\t\tif gstr.HasPrefix(k, \"x-\") || gstr.HasPrefix(k, \"X-\") {\n\t\t\textensions[k] = v\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "net/goai/goai_z_unit_generic_type_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai_test\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\n// TestOpenApiV3_GenericType tests the schema name generation for generic types\n// This test validates the PR fix for swagger $ref replace that handles Go generics\n// Specifically testing that [ and ] characters in type names are replaced with dots\nfunc TestOpenApiV3_GenericType(t *testing.T) {\n\t// Define a generic type wrapper\n\ttype GenericItem[T any] struct {\n\t\tValue T `dc:\"Generic value\"`\n\t}\n\n\ttype StringItem = GenericItem[string]\n\n\ttype IntItem = GenericItem[int]\n\n\ttype Req struct {\n\t\tgmeta.Meta `path:\"/generic\" method:\"POST\" tags:\"default\"`\n\t\tStringData StringItem `dc:\"String generic type\"`\n\t\tIntData    IntItem    `dc:\"Int generic type\"`\n\t}\n\n\ttype Res struct {\n\t\tgmeta.Meta `description:\"Generic Response\"`\n\t\tData       string `dc:\"Response data\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/generic\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify that schema names are properly generated without special characters\n\t\tschemas := oai.Components.Schemas.Map()\n\t\tt.AssertGT(len(schemas), 0)\n\n\t\t// Check that bracket characters [ and ] have been replaced with dots\n\t\t// According to PR fix: `[`: `.`, `]`: `.`\n\t\tfor schemaName := range schemas {\n\t\t\t// Should not contain [ or ] characters after replacement\n\t\t\tt.Assert(!strings.Contains(schemaName, \"[\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"]\"), true)\n\t\t}\n\t})\n}\n\n// TestOpenApiV3_SchemaNameReplacement tests the special character replacement in schema names\n// This verifies the core PR change which replaces:\n// - [ with .\n// - ] with .\n// - { with empty string\n// - } with empty string\n// - spaces with empty string\nfunc TestOpenApiV3_SchemaNameReplacement(t *testing.T) {\n\ttype SimpleReq struct {\n\t\tgmeta.Meta `path:\"/test\" method:\"POST\"`\n\t\tName       string `dc:\"Name field\"`\n\t}\n\n\ttype SimpleRes struct {\n\t\tgmeta.Meta `description:\"Simple Response\"`\n\t\tStatus     string `dc:\"Status field\"`\n\t}\n\n\tf := func(ctx context.Context, req *SimpleReq) (res *SimpleRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Get schema names and verify they are properly formatted\n\t\tschemas := oai.Components.Schemas.Map()\n\t\tfor schemaName := range schemas {\n\t\t\t// Verify special characters have been replaced:\n\t\t\t// - [ should be replaced with .\n\t\t\t// - ] should be replaced with .\n\t\t\t// - { should be replaced with empty\n\t\t\t// - } should be replaced with empty\n\t\t\t// - spaces should be replaced with empty\n\t\t\tt.Assert(!strings.Contains(schemaName, \"[\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"]\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"{\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"}\"), true)\n\t\t}\n\t})\n}\n\n// TestOpenApiV3_ComplexGenericType tests more complex generic types\n// This specifically tests handling of map types and nested generic structures\nfunc TestOpenApiV3_ComplexGenericType(t *testing.T) {\n\ttype MapWrapper struct {\n\t\tgmeta.Meta `path:\"/mapwrapper\" method:\"POST\"`\n\t\tData       map[string]string `dc:\"Map data\"`\n\t}\n\n\ttype Res struct {\n\t\tgmeta.Meta `description:\"Map Response\"`\n\t\tResult     string `dc:\"Result\"`\n\t}\n\n\tf := func(ctx context.Context, req *MapWrapper) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/mapwrapper\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify schema generation completes without errors\n\t\tschemas := oai.Components.Schemas.Map()\n\t\tt.AssertGT(len(schemas), 0)\n\n\t\t// All schema names should be valid (no bracket characters)\n\t\tfor schemaName := range schemas {\n\t\t\tt.Assert(!strings.Contains(schemaName, \"[\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"]\"), true)\n\t\t}\n\t})\n}\n\n// TestOpenApiV3_PathWithSpecialChars tests path parameters with special handling\n// This ensures the PR changes don't affect regular parameter handling\nfunc TestOpenApiV3_PathWithSpecialChars(t *testing.T) {\n\ttype GetDetailReq struct {\n\t\tgmeta.Meta `path:\"/detail\" method:\"GET\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" dc:\"Resource identifier\"`\n\t\tType       string `json:\"type\" in:\"query\" dc:\"Resource type\"`\n\t}\n\n\ttype DetailRes struct {\n\t\tgmeta.Meta `description:\"Detail Response\"`\n\t\tContent    string `dc:\"Detail content\"`\n\t}\n\n\tf := func(ctx context.Context, req *GetDetailReq) (res *DetailRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/detail\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Verify all schemas are properly named\n\t\tschemas := oai.Components.Schemas.Map()\n\t\tfor schemaName := range schemas {\n\t\t\t// Should not contain special characters that were supposed to be replaced\n\t\t\tt.Assert(!strings.Contains(schemaName, \"[\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"]\"), true)\n\t\t}\n\t})\n}\n\n// TestOpenApiV3_SliceOfGenericTypes tests slice of generic types\n// This validates that slices containing generics are properly handled\nfunc TestOpenApiV3_SliceOfGenericTypes(t *testing.T) {\n\ttype Item[T any] struct {\n\t\tValue T `dc:\"Item value\"`\n\t}\n\n\ttype StringItem = Item[string]\n\n\ttype SliceReq struct {\n\t\tgmeta.Meta `path:\"/slice\" method:\"POST\"`\n\t\tItems      []StringItem `dc:\"Slice of generic items\"`\n\t}\n\n\ttype SliceRes struct {\n\t\tgmeta.Meta `description:\"Slice Response\"`\n\t\tCount      int `dc:\"Item count\"`\n\t}\n\n\tf := func(ctx context.Context, req *SliceReq) (res *SliceRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/slice\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tschemas := oai.Components.Schemas.Map()\n\t\tt.AssertGT(len(schemas), 0)\n\n\t\t// Verify no bracket characters in schema names\n\t\tfor schemaName := range schemas {\n\t\t\tt.Assert(!strings.Contains(schemaName, \"[\"), true)\n\t\t\tt.Assert(!strings.Contains(schemaName, \"]\"), true)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "net/goai/goai_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar ctx = context.Background()\n\ntype Issue3664DefaultReq struct {\n\tg.Meta `path:\"/default\" method:\"post\"`\n\tName   string\n}\ntype Issue3664DefaultRes struct{}\n\ntype Issue3664RequiredTagReq struct {\n\tg.Meta `path:\"/required-tag\" required:\"true\" method:\"post\"`\n\tName   string\n}\ntype Issue3664RequiredTagRes struct{}\n\ntype Issue3664 struct{}\n\nfunc (Issue3664) Default(ctx context.Context, req *Issue3664DefaultReq) (res *Issue3664DefaultRes, err error) {\n\tres = &Issue3664DefaultRes{}\n\treturn\n}\n\nfunc (Issue3664) RequiredTag(\n\tctx context.Context, req *Issue3664RequiredTagReq,\n) (res *Issue3664RequiredTagRes, err error) {\n\tres = &Issue3664RequiredTagRes{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3664\nfunc Test_Issue3664(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3664),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tapiContent := c.GetBytes(ctx, \"/api.json\")\n\t\tj, err := gjson.LoadJson(apiContent)\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(`paths./default.post.requestBody.required`).String(), \"\")\n\t\tt.Assert(j.Get(`paths./required-tag.post.requestBody.required`).String(), \"true\")\n\t})\n}\n\ntype Issue3135DefaultReq struct {\n\tg.Meta `path:\"/demo/colors\" method:\"POST\" summary:\"颜色 - 保存\" tags:\"颜色管理\" description:\"颜色 - 保存\"`\n\tID     uint64      `json:\"id,string\" dc:\"ID\" v:\"id-zero\"`\n\tColor  string      `json:\"color\" dc:\"颜色值16进制表示法\" v:\"required|max-length:10\"`\n\tRgba   *gjson.Json `json:\"rgba\" dc:\"颜色值RGBA表示法\" v:\"required|json\" type:\"string\"`\n}\ntype Issue3135DefaultRes struct{}\n\ntype Issue3135 struct{}\n\nfunc (Issue3135) Default(ctx context.Context, req *Issue3135DefaultReq) (res *Issue3135DefaultRes, err error) {\n\tres = &Issue3135DefaultRes{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3135\nfunc Test_Issue3135(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3135),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tvar (\n\t\t\tapi           = s.GetOpenApi()\n\t\t\treqPath       = \"github.com.gogf.gf.v2.net.goai_test.Issue3135DefaultReq\"\n\t\t\trgbType       = api.Components.Schemas.Get(reqPath).Value.Properties.Get(\"rgba\").Value.Type\n\t\t\trequiredArray = api.Components.Schemas.Get(reqPath).Value.Required\n\t\t)\n\t\tt.Assert(rgbType, \"string\")\n\t\tt.AssertIN(\"rgba\", requiredArray)\n\t})\n}\n\ntype Issue3889CommonRes struct {\n\tg.Meta  `mime:\"application/json\"`\n\tCode    int    `json:\"code\"`\n\tMessage string `json:\"message\"`\n\tData    any    `json:\"data\"`\n}\n\ntype Issue3889Req struct {\n\tg.Meta `path:\"/default\" method:\"post\"`\n\tName   string\n}\ntype Issue3889Res struct {\n\tg.Meta `status:\"201\" resEg:\"testdata/Issue3889JsonFile/201.json\"`\n\tInfo   string `json:\"info\" eg:\"Created!\"`\n}\n\n// Example case\ntype Issue3889Res401 struct{}\n\n// Override case 1\ntype Issue3889Res402 struct {\n\tg.Meta `mime:\"application/json\"`\n}\n\n// Override case 2\ntype Issue3889Res403 struct {\n\tCode    int    `json:\"code\"`\n\tMessage string `json:\"message\"`\n}\n\n// Common response case\ntype Issue3889Res404 struct{}\n\nvar Issue3889ErrorRes = map[int][]gcode.Code{\n\t401: {\n\t\tgcode.New(1, \"Aha, 401 - 1\", nil),\n\t\tgcode.New(2, \"Aha, 401 - 2\", nil),\n\t},\n}\n\nfunc (r Issue3889Res) EnhanceResponseStatus() map[goai.EnhancedStatusCode]goai.EnhancedStatusType {\n\tCodes401 := Issue3889ErrorRes[401]\n\t// iterate Codes401 to generate Examples\n\tvar Examples401 []any\n\tfor _, code := range Codes401 {\n\t\texample := Issue3889CommonRes{\n\t\t\tCode:    code.Code(),\n\t\t\tMessage: code.Message(),\n\t\t\tData:    nil,\n\t\t}\n\t\tExamples401 = append(Examples401, example)\n\t}\n\treturn map[goai.EnhancedStatusCode]goai.EnhancedStatusType{\n\t\t401: {\n\t\t\tResponse: Issue3889Res401{},\n\t\t\tExamples: Examples401,\n\t\t},\n\t\t402: {\n\t\t\tResponse: Issue3889Res402{},\n\t\t},\n\t\t403: {\n\t\t\tResponse: Issue3889Res403{},\n\t\t},\n\t\t404: {\n\t\t\tResponse: Issue3889Res404{},\n\t\t},\n\t\t500: {\n\t\t\tResponse: struct{}{},\n\t\t},\n\t\t501: {},\n\t}\n}\n\ntype Issue3889 struct{}\n\nfunc (Issue3889) Default(ctx context.Context, req *Issue3889Req) (res *Issue3889Res, err error) {\n\tres = &Issue3889Res{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3889\nfunc Test_Issue3889(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\topenapi := s.GetOpenApi()\n\t\topenapi.Config.CommonResponse = Issue3889CommonRes{}\n\t\topenapi.Config.CommonResponseDataField = `Data`\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3889),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tapiContent := c.GetBytes(ctx, \"/api.json\")\n\t\tj, err := gjson.LoadJson(apiContent)\n\n\t\tt.AssertNil(err)\n\t\tt.Assert(j.Get(`paths./default.post.responses.200`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.201`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.401`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.402`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.403`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.404`).String(), \"\")\n\t\tt.AssertNE(j.Get(`paths./default.post.responses.500`).String(), \"\")\n\t\tt.Assert(j.Get(`paths./default.post.responses.501`).String(), \"\")\n\t\t// Check content\n\t\tcommonResponseSchema := `{\"properties\":{\"code\":{\"format\":\"int\",\"type\":\"integer\"},\"data\":{\"properties\":{},\"type\":\"object\"},\"message\":{\"format\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}`\n\t\tStatus201ExamplesContent := `{\"code 1\":{\"value\":{\"code\":1,\"data\":\"Good\",\"message\":\"Aha, 201 - 1\"}},\"code 2\":{\"value\":{\"code\":2,\"data\":\"Not Bad\",\"message\":\"Aha, 201 - 2\"}}}`\n\t\tStatus401ExamplesContent := `{\"example 1\":{\"value\":{\"code\":1,\"data\":null,\"message\":\"Aha, 401 - 1\"}},\"example 2\":{\"value\":{\"code\":2,\"data\":null,\"message\":\"Aha, 401 - 2\"}}}`\n\t\tStatus402SchemaContent := `{\"$ref\":\"#/components/schemas/github.com.gogf.gf.v2.net.goai_test.Issue3889Res402\",\"description\":\"\"}`\n\t\tIssue3889Res403Ref := `{\"$ref\":\"#/components/schemas/github.com.gogf.gf.v2.net.goai_test.Issue3889Res403\",\"description\":\"\"}`\n\n\t\tt.Assert(j.Get(`paths./default.post.responses.201.content.application/json.examples`).String(), Status201ExamplesContent)\n\t\tt.Assert(j.Get(`paths./default.post.responses.401.content.application/json.examples`).String(), Status401ExamplesContent)\n\t\tt.Assert(j.Get(`paths./default.post.responses.402.content.application/json.schema`).String(), Status402SchemaContent)\n\t\tt.Assert(j.Get(`paths./default.post.responses.403.content.application/json.schema`).String(), Issue3889Res403Ref)\n\t\tt.Assert(j.Get(`paths./default.post.responses.404.content.application/json.schema`).String(), commonResponseSchema)\n\t\tt.Assert(j.Get(`paths./default.post.responses.500.content.application/json.schema`).String(), commonResponseSchema)\n\n\t\tapi := s.GetOpenApi()\n\t\treqPath := \"github.com.gogf.gf.v2.net.goai_test.Issue3889Res403\"\n\t\tschema := api.Components.Schemas.Get(reqPath).Value\n\n\t\tIssue3889Res403Schema := `{\"properties\":{\"code\":{\"format\":\"int\",\"type\":\"integer\"},\"message\":{\"format\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}`\n\t\tt.Assert(schema, Issue3889Res403Schema)\n\t})\n}\n\ntype Issue3930DefaultReq struct {\n\tg.Meta `path:\"/user/{id}\" method:\"get\" tags:\"User\" summary:\"Get one user\"`\n\tId     int64 `v:\"required\" dc:\"user id\"`\n}\ntype Issue3930DefaultRes struct {\n\t*Issue3930User `dc:\"user\"`\n}\ntype Issue3930User struct {\n\tId uint `json:\"id\"     orm:\"id\"     description:\"user id\"` // user id\n}\n\ntype Issue3930 struct{}\n\nfunc (Issue3930) Default(ctx context.Context, req *Issue3930DefaultReq) (res *Issue3930DefaultRes, err error) {\n\tres = &Issue3930DefaultRes{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3930\nfunc Test_Issue3930(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3930),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tvar (\n\t\t\tapi     = s.GetOpenApi()\n\t\t\treqPath = \"github.com.gogf.gf.v2.net.goai_test.Issue3930DefaultRes\"\n\t\t)\n\t\tt.AssertNE(api.Components.Schemas.Get(reqPath).Value.Properties.Get(\"id\"), nil)\n\t})\n}\n\ntype Issue3235DefaultReq struct {\n\tg.Meta `path:\"/user/{id}\" method:\"get\" tags:\"User\" summary:\"Get one user\"`\n\tId     int64 `v:\"required\" dc:\"user id\"`\n}\ntype Issue3235DefaultRes struct {\n\tName string         `dc:\"test name desc\"`\n\tUser *Issue3235User `dc:\"test user desc\"`\n}\ntype Issue3235User struct {\n\tId uint `json:\"id\"     orm:\"id\"     description:\"user id\"` // user id\n}\n\ntype Issue3235 struct{}\n\nfunc (Issue3235) Default(ctx context.Context, req *Issue3235DefaultReq) (res *Issue3235DefaultRes, err error) {\n\tres = &Issue3235DefaultRes{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3235\nfunc Test_Issue3235(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue3235),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tvar (\n\t\t\tapi     = s.GetOpenApi()\n\t\t\treqPath = \"github.com.gogf.gf.v2.net.goai_test.Issue3235DefaultRes\"\n\t\t)\n\n\t\tt.Assert(api.Components.Schemas.Get(reqPath).Value.Properties.Get(\"Name\").Value.Description,\n\t\t\t\"test name desc\")\n\t\tt.Assert(api.Components.Schemas.Get(reqPath).Value.Properties.Get(\"User\").Description,\n\t\t\t\"test user desc\")\n\t})\n}\n\ntype Issue4247NoBodyReq struct {\n\tg.Meta    `path:\"/cluster/{cluster_id}/node/{name}/drain\" method:\"post\" tags:\"节点管理\" summary:\"驱逐节点\" dc:\"该接口会先设置节点不可调度，再进行驱逐\"`\n\tClusterId string `json:\"cluster_id\" v:\"required\" dc:\"集群ID\" `\n\tName      string `json:\"name\"       v:\"required\" dc:\"节点名称\"`\n}\ntype Issue4247NoBodyRes struct{}\n\ntype Issue4247HasBodyReq struct {\n\tg.Meta    `path:\"/cluster/{cluster_id}/node/{name}/join\" method:\"post\" tags:\"节点管理\" summary:\"增加节点\" dc:\"增加节点\"`\n\tClusterId string `json:\"cluster_id\" v:\"required\" dc:\"集群ID\" `\n\tName      string `json:\"name\"       v:\"required\" dc:\"节点名称\"`\n\tType      string `json:\"type\"       v:\"required\" dc:\"节点类型\"`\n}\ntype Issue4247HasBodyRes struct{}\n\ntype Issue4247 struct{}\n\nfunc (Issue4247) Issue4247NoBody(ctx context.Context, req *Issue4247NoBodyReq) (res *Issue4247NoBodyRes, err error) {\n\tres = &Issue4247NoBodyRes{}\n\treturn\n}\n\nfunc (Issue4247) Issue4247HasBody(ctx context.Context, req *Issue4247HasBodyReq) (res *Issue4247HasBodyRes, err error) {\n\tres = &Issue4247HasBodyRes{}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/4247\nfunc Test_Issue4247(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Server(guid.S())\n\t\ts.Use(ghttp.MiddlewareHandlerResponse)\n\t\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\t\tgroup.Bind(\n\t\t\t\tnew(Issue4247),\n\t\t\t)\n\t\t})\n\t\ts.SetLogger(nil)\n\t\ts.SetOpenApiPath(\"/api.json\")\n\t\ts.SetDumpRouterMap(false)\n\t\ts.Start()\n\n\t\tdefer s.Shutdown()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tapiContent := c.GetBytes(ctx, \"/api.json\")\n\t\tj, err := gjson.LoadJson(apiContent)\n\t\tt.AssertNil(err)\n\t\trequestBody := `{\"content\":{\"application/json\":{\"schema\":{\"description\":\"增加节点\",\"properties\":{\"type\":{\"description\":\"节点类型\",\"format\":\"string\",\"type\":\"string\"}},\"required\":[\"type\"],\"type\":\"object\"}}}}`\n\t\tt.Assert(j.Get(`paths./cluster/{cluster_id}/node/{name}/drain.post.requestBody`).IsEmpty(), true)\n\t\tt.Assert(j.Get(`paths./cluster/{cluster_id}/node/{name}/join.post.requestBody`).String(), requestBody)\n\t})\n}\n"
  },
  {
    "path": "net/goai/goai_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage goai_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/goai\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nfunc Test_Basic(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"cookie\" description:\"应用Id\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" description:\"资源Id\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" description:\"StorageType\"`\n\t\tShards      int32    `description:\"shards 分片数\"`\n\t\tParams      []string `description:\"默认参数(json 串-ClickHouseParams)\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\"`\n\t\tName       string                  `description:\"实例名称\"`\n\t\tProduct    string                  `description:\"业务类型\"`\n\t\tRegion     string                  `v:\"required\" description:\"区域\"`\n\t\tSetMap     map[string]*SetSpecInfo `v:\"required\" description:\"配置Map\"`\n\t\tSetSlice   []SetSpecInfo           `v:\"required\" description:\"配置Slice\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 2)\n\t\tvar (\n\t\t\tschemaCreate      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\t\tschemaSetSpecInfo = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.SetSpecInfo`)\n\t\t)\n\n\t\tt.Assert(schemaCreate.Value.Type, goai.TypeObject)\n\t\tt.Assert(len(schemaCreate.Value.Properties.Map()), 7)\n\t\tt.Assert(schemaCreate.Value.Properties.Get(`appId`).Value.Type, goai.TypeInteger)\n\t\tt.Assert(schemaCreate.Value.Properties.Get(`resourceId`).Value.Type, goai.TypeString)\n\n\t\tt.Assert(len(schemaSetSpecInfo.Value.Properties.Map()), 3)\n\t\tt.Assert(schemaSetSpecInfo.Value.Properties.Get(`Params`).Value.Type, goai.TypeArray)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaCreate.Value.Required, []string{\"appId\", \"Region\", \"SetMap\", \"SetSlice\"})\n\t})\n}\n\nfunc TestOpenApiV3_Add(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"path\" description:\"应用Id\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" description:\"资源Id\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" description:\"StorageType\"`\n\t\tShards      int32    `description:\"shards 分片数\"`\n\t\tParams      []string `description:\"默认参数(json 串-ClickHouseParams)\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\"`\n\t\tName       string                  `description:\"实例名称\"`\n\t\tProduct    string                  `description:\"业务类型\"`\n\t\tRegion     string                  `v:\"required\" description:\"区域\"`\n\t\tSetMap     map[string]*SetSpecInfo `v:\"required\" description:\"配置Map\"`\n\t\tSetSlice   []SetSpecInfo           `v:\"required\" description:\"配置Slice\"`\n\t}\n\n\ttype CreateResourceRes struct {\n\t\tgmeta.Meta `description:\"Demo Response Struct\"`\n\t\tFlowId     int64 `description:\"创建实例流程id\"`\n\t}\n\n\tf := func(ctx context.Context, req *CreateResourceReq) (res *CreateResourceRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test1/{appId}\",\n\t\t\tMethod: http.MethodPut,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test1/{appId}\",\n\t\t\tMethod: http.MethodPost,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// fmt.Println(oai.String())\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\n\t\tvar (\n\t\t\tschemaCreate      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\t\tschemaSetSpecInfo = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.SetSpecInfo`)\n\t\t\tschemaTest1       = oai.Paths[\"/test1/{appId}\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t)\n\t\tt.Assert(schemaCreate.Value.Type, goai.TypeObject)\n\n\t\tt.Assert(len(schemaCreate.Value.Properties.Map()), 7)\n\t\tt.Assert(len(schemaTest1.Value.Properties.Map()), 5)\n\t\tt.Assert(len(schemaTest1.Value.Properties.Map()), 5)\n\n\t\tt.Assert(oai.Paths[\"/test1/{appId}\"].Post.Parameters[0].Value.Schema.Value.Type, goai.TypeInteger)\n\t\tt.Assert(oai.Paths[\"/test1/{appId}\"].Post.Parameters[1].Value.Schema.Value.Type, goai.TypeString)\n\n\t\tt.Assert(len(schemaSetSpecInfo.Value.Properties.Map()), 3)\n\t\tt.Assert(schemaSetSpecInfo.Value.Properties.Get(`Params`).Value.Type, goai.TypeArray)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaCreate.Value.Required, []string{\"appId\", \"Region\", \"SetMap\", \"SetSlice\"})\n\n\t\t// Paths.\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tt.AssertNE(oai.Paths[`/test1/{appId}`].Put, nil)\n\t\tt.Assert(len(oai.Paths[`/test1/{appId}`].Put.Tags), 1)\n\t\tt.Assert(len(oai.Paths[`/test1/{appId}`].Put.Parameters), 2)\n\t\tt.AssertNE(oai.Paths[`/test1/{appId}`].Post, nil)\n\t\tt.Assert(len(oai.Paths[`/test1/{appId}`].Post.Tags), 1)\n\t\tt.Assert(len(oai.Paths[`/test1/{appId}`].Post.Parameters), 2)\n\t})\n}\n\nfunc TestOpenApiV3_Add_Recursive(t *testing.T) {\n\ttype CategoryTreeItem struct {\n\t\tId       uint                `json:\"id\"`\n\t\tParentId uint                `json:\"parent_id\"`\n\t\tItems    []*CategoryTreeItem `json:\"items,omitempty\"`\n\t}\n\n\ttype CategoryGetTreeReq struct {\n\t\tgmeta.Meta  `path:\"/category-get-tree\" method:\"GET\" tags:\"default\"`\n\t\tContentType string `in:\"query\"`\n\t}\n\ttype CategoryGetTreeRes struct {\n\t\tList []*CategoryTreeItem\n\t}\n\n\tf := func(ctx context.Context, req *CategoryGetTreeReq) (res *CategoryGetTreeRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/tree\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tvar (\n\t\t\tschemaCategoryTreeItem = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CategoryTreeItem`)\n\t\t)\n\t\tt.Assert(schemaCategoryTreeItem.Value.Type, goai.TypeObject)\n\t\tt.Assert(len(schemaCategoryTreeItem.Value.Properties.Map()), 3)\n\t})\n}\n\nfunc TestOpenApiV3_Add_EmptyReqAndRes(t *testing.T) {\n\ttype CaptchaIndexReq struct {\n\t\tgmeta.Meta `method:\"PUT\" summary:\"获取默认的验证码\" description:\"注意直接返回的是图片二进制内容\" tags:\"前台-验证码\"`\n\t}\n\ttype CaptchaIndexRes struct {\n\t\tgmeta.Meta `mime:\"png\" description:\"验证码二进制内容\" `\n\t}\n\n\tf := func(ctx context.Context, req *CaptchaIndexReq) (res *CaptchaIndexRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/tree\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tfmt.Println(oai.String())\n\t})\n}\n\nfunc TestOpenApiV3_Add_AutoDetectIn(t *testing.T) {\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"get\" tags:\"default\"`\n\t\tName       string\n\t\tProduct    string\n\t\tRegion     string\n\t}\n\n\ttype Res struct {\n\t\tgmeta.Meta `description:\"Demo Response Struct\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr  error\n\t\t\toai  = goai.New()\n\t\t\tpath = `/test/{product}/{name}`\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   path,\n\t\t\tMethod: http.MethodGet,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tfmt.Println(oai.String())\n\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 2)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tt.AssertNE(oai.Paths[path].Get, nil)\n\t\tt.Assert(len(oai.Paths[path].Get.Parameters), 3)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[0].Value.Name, `Name`)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[0].Value.In, goai.ParameterInPath)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[1].Value.Name, `Product`)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[1].Value.In, goai.ParameterInPath)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[2].Value.Name, `Region`)\n\t\tt.Assert(oai.Paths[path].Get.Parameters[2].Value.In, goai.ParameterInQuery)\n\t})\n}\n\nfunc TestOpenApiV3_CommonRequest(t *testing.T) {\n\ttype CommonRequest struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"PUT\"`\n\t\tProduct    string `json:\"product\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonRequest = CommonRequest{}\n\t\toai.Config.CommonRequestDataField = `Data`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaPut = oai.Paths[\"/index\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t\tschemaRes = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\t\tt.Assert(len(schemaPut.Value.Properties.Map()), 3)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonRequest_WithoutDataField_Setting(t *testing.T) {\n\ttype CommonRequest struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype PutReq struct {\n\t\tgmeta.Meta `method:\"PUT\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\n\ttype PostReq struct {\n\t\tgmeta.Meta `method:\"POST\"`\n\t\tProduct    string `json:\"product\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    v:\"required\" description:\"Instance name\"`\n\t}\n\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *PutReq) (res *Res, err error) {\n\t\treturn\n\t}\n\tf2 := func(ctx context.Context, req *PostReq) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonRequest = CommonRequest{}\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f2,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 4)\n\t\tt.Assert(len(oai.Paths), 1)\n\n\t\tvar (\n\t\t\tschemaIndexPut  = oai.Paths[\"/index\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaIndexPost = oai.Paths[\"/index\"].Post.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaPutReq    = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.PutReq`)\n\t\t\tschemaRes       = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\n\t\tt.Assert(len(oai.Paths[\"/index\"].Put.Parameters), 2)\n\t\tt.Assert(len(schemaIndexPut.Value.Properties.Map()), 3)\n\t\tt.Assert(len(oai.Paths[\"/index\"].Post.Parameters), 0)\n\t\tt.Assert(len(schemaIndexPost.Value.Properties.Map()), 5)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaPutReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaPutReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonRequest_EmptyRequest(t *testing.T) {\n\ttype CommonRequest struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"Put\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct{}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonRequest = CommonRequest{}\n\t\toai.Config.CommonRequestDataField = `Data`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndex = oai.Paths[\"/index\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq   = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t)\n\t\tt.Assert(len(schemaIndex.Value.Properties.Map()), 3)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonRequest_SubDataField(t *testing.T) {\n\ttype CommonReqError struct {\n\t\tCode    string `description:\"错误码\"`\n\t\tMessage string `description:\"错误描述\"`\n\t}\n\n\ttype CommonReqRequest struct {\n\t\tRequestId string          `description:\"RequestId\"`\n\t\tError     *CommonReqError `json:\",omitempty\" description:\"执行错误信息\"`\n\t}\n\n\ttype CommonReq struct {\n\t\tRequest CommonReqRequest\n\t}\n\n\ttype PutReq struct {\n\t\tgmeta.Meta `method:\"Put\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\n\ttype PostReq struct {\n\t\tgmeta.Meta `method:\"Post\"`\n\t\tProduct    string `json:\"product\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    v:\"required\" description:\"Instance name\"`\n\t}\n\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *PutReq) (res *Res, err error) {\n\t\treturn\n\t}\n\tf2 := func(ctx context.Context, req *PostReq) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonRequest = CommonReq{}\n\t\toai.Config.CommonRequestDataField = `Request.`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f2,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 5)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndexPut  = oai.Paths[\"/index\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaIndexPost = oai.Paths[\"/index\"].Post.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemaPutReq    = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.PutReq`)\n\t\t\tschemaRes       = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\t\tt.Assert(len(schemaIndexPut.Value.Properties.Map()), 1)\n\t\tt.Assert(len(schemaIndexPut.Value.Properties.Get(`Request`).Value.Properties.Map()), 2)\n\t\tt.Assert(len(schemaIndexPost.Value.Properties.Map()), 1)\n\t\tt.Assert(len(schemaIndexPost.Value.Properties.Get(`Request`).Value.Properties.Map()), 4)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaPutReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaPutReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonRequest_Files(t *testing.T) {\n\ttype Req struct {\n\t\tg.Meta `path:\"/upload\" method:\"POST\" tags:\"Upload\" mime:\"multipart/form-data\" summary:\"上传文件\"`\n\t\tFiles  []*ghttp.UploadFile `json:\"files\" type:\"file\" dc:\"选择上传文件\"`\n\t\tFile   *ghttp.UploadFile   `json:\"file\" type:\"file\" dc:\"选择上传文件\"`\n\t}\n\ttype Res struct {\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/upload\",\n\t\t\tMethod: http.MethodGet,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvar schemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\tt.Assert(schemaReq.Value.Properties.Get(\"files\").Value.Type, goai.TypeArray)\n\t\tt.Assert(schemaReq.Value.Properties.Get(\"file\").Value.Type, goai.TypeFile)\n\t})\n}\n\nfunc TestOpenApiV3_CommonResponse(t *testing.T) {\n\ttype CommonResponse struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"GET\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonResponse{}\n\t\toai.Config.CommonResponseDataField = `Data`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndexGet = oai.Paths[\"/index\"].Get.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t\tschemaRes      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\t\tt.Assert(len(schemaIndexGet.Value.Properties.Map()), 3)\n\t\tt.Assert(\n\t\t\tschemaIndexGet.Value.Properties.Get(\"data\").Value.Description,\n\t\t\t`Result data for certain request according API definition`,\n\t\t)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonResponse_WithoutDataField_Setting(t *testing.T) {\n\ttype CommonResponse struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"GET\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonResponse{}\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tfmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndexGet = oai.Paths[\"/index\"].Get.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t\tschemaRes      = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\t\tt.Assert(len(schemaIndexGet.Value.Properties.Map()), 8)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonResponse_EmptyResponse(t *testing.T) {\n\ttype CommonResponse struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"PUT\"`\n\t\tProduct    string `json:\"product\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct{}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonResponse{}\n\t\toai.Config.CommonResponseDataField = `Data`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndexPut    = oai.Paths[\"/index\"].Put.RequestBody.Value.Content[\"application/json\"].Schema\n\t\t\tschemeIndexPut200 = oai.Paths[\"/index\"].Put.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq         = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t)\n\t\tt.Assert(schemaIndexPut.Ref, `github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\tt.Assert(len(schemeIndexPut200.Value.Properties.Map()), 3)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t})\n}\n\nfunc TestOpenApiV3_CommonResponse_SubDataField(t *testing.T) {\n\ttype CommonResError struct {\n\t\tCode    string `description:\"错误码\"`\n\t\tMessage string `description:\"错误描述\"`\n\t}\n\n\ttype CommonResResponse struct {\n\t\tRequestId string          `description:\"RequestId\"`\n\t\tError     *CommonResError `json:\",omitempty\" description:\"执行错误信息\"`\n\t}\n\n\ttype CommonRes struct {\n\t\tResponse CommonResResponse\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"GET\"`\n\t\tProduct    string `json:\"product\" in:\"query\" v:\"required\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\n\ttype Res struct {\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonRes{}\n\t\toai.Config.CommonResponseDataField = `Response.`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 4)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaGet = oai.Paths[\"/index\"].Get.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t\tschemaRes = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`)\n\t\t)\n\t\tt.Assert(len(schemaGet.Value.Properties.Map()), 1)\n\t\tt.Assert(len(schemaGet.Value.Properties.Get(`Response`).Value.Properties.Map()), 7)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t\tt.AssertEQ(schemaRes.Value.Required, []string{\"product\", \"templateName\", \"version\", \"txID\"})\n\t})\n}\n\nfunc TestOpenApiV3_ShortTags(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"path\" dc:\"应用Id\" sm:\"应用Id Summary\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" dc:\"资源Id\" sm:\"资源Id Summary\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" dc:\"StorageType\"`\n\t\tShards      int32    `dc:\"shards 分片数\" sm:\"Shards Summary\"`\n\t\tParams      []string `dc:\"默认参数(json 串-ClickHouseParams)\" sm:\"Params Summary\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\" sm:\"sm\" dc:\"CreateResourceReq des\"`\n\t\tName       string                  `dc:\"实例名称\"`\n\t\tProduct    string                  `dc:\"业务类型\"`\n\t\tRegion     string                  `v:\"required\" dc:\"区域\"`\n\t\tSetMap     map[string]*SetSpecInfo `v:\"required\" dc:\"配置Map\"`\n\t\tSetSlice   []SetSpecInfo           `v:\"required\" dc:\"配置Slice\"`\n\t}\n\n\ttype CreateResourceRes struct {\n\t\tgmeta.Meta `dc:\"Demo Response Struct\"`\n\t\tFlowId     int64 `dc:\"创建实例流程id\"`\n\t}\n\n\tf := func(ctx context.Context, req *CreateResourceReq) (res *CreateResourceRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test1/{appId}\",\n\t\t\tMethod: http.MethodPut,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test1/{appId}\",\n\t\t\tMethod: http.MethodPost,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Schema asserts.\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(oai.Paths[`/test1/{appId}`].Summary, ``)\n\t\tt.Assert(oai.Paths[`/test1/{appId}`].Description, ``)\n\t\tt.Assert(oai.Paths[`/test1/{appId}`].Put.Summary, `sm`)\n\t\tt.Assert(oai.Paths[`/test1/{appId}`].Put.Description, `CreateResourceReq des`)\n\t\tt.Assert(oai.Paths[`/test1/{appId}`].Put.Parameters[1].Value.Schema.Value.Description, `资源Id`)\n\t\tvar (\n\t\t\tschemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\t)\n\t\tt.Assert(schemaReq.Value.Properties.Get(`Name`).Value.Description, `实例名称`)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"appId\", \"Region\", \"SetMap\", \"SetSlice\"})\n\t})\n}\n\nfunc TestOpenApiV3_HtmlResponse(t *testing.T) {\n\ttype Req struct {\n\t\tg.Meta `path:\"/test\" method:\"get\" summary:\"展示内容详情页面\" tags:\"内容\"`\n\t\tId     uint `json:\"id\" v:\"min:1#请选择查看的内容\" dc:\"内容id\"`\n\t}\n\ttype Res struct {\n\t\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test\",\n\t\t\tMethod: http.MethodGet,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`).Value.Type, goai.TypeString)\n\t})\n}\n\nfunc TestOpenApiV3_HtmlResponseWithCommonResponse(t *testing.T) {\n\ttype CommonResError struct {\n\t\tCode    string `description:\"错误码\"`\n\t\tMessage string `description:\"错误描述\"`\n\t}\n\n\ttype CommonResResponse struct {\n\t\tRequestId string          `description:\"RequestId\"`\n\t\tError     *CommonResError `json:\",omitempty\" description:\"执行错误信息\"`\n\t}\n\n\ttype CommonRes struct {\n\t\tResponse CommonResResponse\n\t}\n\n\ttype Req struct {\n\t\tg.Meta `path:\"/test\" method:\"get\" summary:\"展示内容详情页面\" tags:\"内容\"`\n\t\tId     uint `json:\"id\" v:\"min:1#请选择查看的内容\" dc:\"内容id\"`\n\t}\n\ttype Res struct {\n\t\tg.Meta `mime:\"text/html\" type:\"string\" example:\"<html/>\"`\n\t}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\t\toai.Config.CommonResponse = CommonRes{}\n\t\toai.Config.CommonResponseDataField = `Response.`\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/test\",\n\t\t\tMethod: http.MethodGet,\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Res`).Value.Type, goai.TypeString)\n\t})\n}\n\nfunc Test_Required_In_Schema(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"cookie\" description:\"应用Id\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" description:\"资源Id\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" description:\"StorageType\"`\n\t\tShards      int32    `description:\"shards 分片数\"`\n\t\tParams      []string `description:\"默认参数(json 串-ClickHouseParams)\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\"`\n\t\tName       string                  `description:\"实例名称\"`\n\t\tProduct    string                  `description:\"业务类型\"`\n\t\tRegion     string                  `v:\"required|min:1\" description:\"区域\"`\n\t\tSetMap     map[string]*SetSpecInfo `v:\"required|min:1\" description:\"配置Map\"`\n\t\tSetSlice   []SetSpecInfo           `v:\"required|min:1\" description:\"配置Slice\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tvar (\n\t\t\tschemaKey1 = `github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`\n\t\t\tschemaKey2 = `github.com.gogf.gf.v2.net.goai_test.SetSpecInfo`\n\t\t)\n\t\tt.Assert(oai.Components.Schemas.Map()[schemaKey1].Value.Required, g.Slice{\n\t\t\t\"appId\",\n\t\t\t\"Region\",\n\t\t\t\"SetMap\",\n\t\t\t\"SetSlice\",\n\t\t})\n\t\tt.Assert(oai.Components.Schemas.Map()[schemaKey2].Value.Required, g.Slice{\n\t\t\t\"StorageType\",\n\t\t})\n\t\tt.Assert(oai.Components.Schemas.Map()[schemaKey2].Value.Properties.Map()[\"StorageType\"].Value.Enum, g.Slice{\n\t\t\t\"CLOUD_PREMIUM\",\n\t\t\t\"CLOUD_SSD\",\n\t\t\t\"CLOUD_HSSD\",\n\t\t})\n\n\t\t// Schema Required.\n\t\tvar schemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"appId\", \"Region\", \"SetMap\", \"SetSlice\"})\n\t})\n}\n\nfunc Test_Properties_In_Sequence(t *testing.T) {\n\ttype ResourceCreateReq struct {\n\t\tg.Meta           `path:\"/resource\" tags:\"OSS Resource\" method:\"put\" x-sort:\"1\" summary:\"创建实例(发货)\"`\n\t\tAppId            uint64 `v:\"required\" dc:\"应用Id\"`\n\t\tUin              string `v:\"required\" dc:\"主用户账号，该资源隶属于的账号\"`\n\t\tCreateUin        string `v:\"required\" dc:\"创建实例的用户账号\"`\n\t\tProduct          string `v:\"required\" dc:\"业务类型\" eg:\"tdach\"`\n\t\tRegion           string `v:\"required\" dc:\"地域\" eg:\"ap-guangzhou\"`\n\t\tZone             string `v:\"required\" dc:\"区域\" eg:\"ap-guangzhou-1\"`\n\t\tTenant           string `v:\"required\" dc:\"业务自定义数据，透传到底层\"`\n\t\tVpcId            string `dc:\"业务Vpc Id, TCS场景下非必须\"`\n\t\tSubnetId         string `dc:\"业务Vpc子网Id\"`\n\t\tName             string `dc:\"自定义实例名称，默认和ResourceId一致\"`\n\t\tClusterPreset    string `dc:\"业务自定义Cluster定义，透传到底层\"`\n\t\tEngine           string `dc:\"引擎名称，例如：TxLightning\"`\n\t\tVersion          string `dc:\"引擎版本，例如：10.3.213 (兼容ClickHouse 21.3.12)\"`\n\t\tSkipUpdateStatus bool   `dc:\"是否跳过状态更新，继续保持creating\" ed:\"http://goframe.org\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(ResourceCreateReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\t// Schema Required.\n\t\tvar schemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.ResourceCreateReq`)\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\n\t\t\t\"AppId\", \"Uin\", \"CreateUin\", \"Product\", \"Region\", \"Zone\", \"Tenant\",\n\t\t})\n\t})\n}\n\nfunc TestOpenApiV3_Ignore_Parameter(t *testing.T) {\n\ttype CommonResponse struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\ttype ProductSearchReq struct {\n\t\tgmeta.Meta `path:\"/test\" method:\"get\"`\n\t\tProduct    string `json:\"-\" in:\"query\" v:\"required|max:5\" description:\"Unique product key\"`\n\t\tName       string `json:\"name\"    in:\"query\"  v:\"required\" description:\"Instance name\"`\n\t}\n\ttype ProductSearchRes struct {\n\t\tID           int64  `json:\"-\"                         description:\"Product ID\"`\n\t\tProduct      string `json:\"product\"      v:\"required\" description:\"Unique product key\"`\n\t\tTemplateName string `json:\"templateName\" v:\"required\" description:\"Workflow template name\"`\n\t\tVersion      string `json:\"version\"      v:\"required\" description:\"Workflow template version\"`\n\t\tTxID         string `json:\"txID\"         v:\"required\" description:\"Transaction ID for creating instance\"`\n\t\tGlobals      string `json:\"globals\"                   description:\"Globals\"`\n\t}\n\n\tf := func(ctx context.Context, req *ProductSearchReq) (res *ProductSearchRes, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonResponse{}\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\t// fmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar schemaTest = oai.Paths[\"/test\"].Get.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\tt.Assert(len(schemaTest.Value.Properties.Map()), 8)\n\t})\n}\n\nfunc Test_EnumOfSchemaItems(t *testing.T) {\n\ttype CreateResourceReq struct {\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\"`\n\t\tMembers    []string `v:\"required|in:a,b,c\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvar schemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\tt.Assert(\n\t\t\tschemaReq.Value.\n\t\t\t\tProperties.Get(`Members`).Value.\n\t\t\t\tItems.Value.Enum,\n\t\t\tg.Slice{\"a\", \"b\", \"c\"},\n\t\t)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"Members\"})\n\t})\n}\n\nfunc Test_AliasNameOfAttribute(t *testing.T) {\n\ttype CreateResourceReq struct {\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\"`\n\t\tName       string `p:\"n\"`\n\t\tAge        string `json:\"a\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tvar schemaReq = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.CreateResourceReq`)\n\t\tt.Assert(schemaReq.Value.Properties.Get(`Name`), nil)\n\t\tt.Assert(schemaReq.Value.Properties.Get(`Age`), nil)\n\t\tt.AssertNE(schemaReq.Value.Properties.Get(`n`), nil)\n\t\tt.AssertNE(schemaReq.Value.Properties.Get(`a`), nil)\n\t})\n}\n\nfunc Test_EmbeddedStructAttribute(t *testing.T) {\n\ttype CreateResourceReq struct {\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\"`\n\t\tName       string `dc:\"This is name.\"`\n\t\tEmbedded   struct {\n\t\t\tAge uint `dc:\"This is embedded age.\"`\n\t\t}\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tb, err := json.Marshal(oai)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, gtest.DataContent(\"EmbeddedStructAttribute\", \"expect.json\"))\n\t})\n}\n\nfunc Test_NameFromJsonTag(t *testing.T) {\n\t// POST\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype CreateReq struct {\n\t\t\tgmeta.Meta `path:\"/CreateReq\" method:\"POST\"`\n\t\t\tName       string `json:\"nick_name, omitempty\"`\n\t\t}\n\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tb, err := json.Marshal(oai)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, gtest.DataContent(\"NameFromJsonTag\", \"expect1.json\"))\n\t})\n\t// GET\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype CreateReq struct {\n\t\t\tgmeta.Meta `path:\"/CreateReq\" method:\"GET\"`\n\t\t\tName       string `json:\"nick_name, omitempty\" in:\"header\"`\n\t\t}\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tb, err := json.Marshal(oai)\n\t\tt.AssertNil(err)\n\t\tfmt.Println(string(b))\n\t\tt.Assert(b, gtest.DataContent(\"NameFromJsonTag\", \"expect2.json\"))\n\t})\n}\n\nfunc TestOpenApiV3_PathSecurity(t *testing.T) {\n\ttype CommonResponse struct {\n\t\tCode    int    `json:\"code\"    description:\"Error code\"`\n\t\tMessage string `json:\"message\" description:\"Error message\"`\n\t\tData    any    `json:\"data\"    description:\"Result data for certain request according API definition\"`\n\t}\n\n\ttype Req struct {\n\t\tgmeta.Meta `method:\"PUT\" security:\"apiKey\"` // 这里的apiKey要和openApi定义的key一致\n\t\tProduct    string                           `json:\"product\"           v:\"required\" description:\"Unique product key\"`\n\t\tName       string                           `json:\"name\"              v:\"required\" description:\"Instance name\"`\n\t}\n\ttype Res struct{}\n\n\tf := func(ctx context.Context, req *Req) (res *Res, err error) {\n\t\treturn\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t)\n\n\t\toai.Config.CommonResponse = CommonResponse{}\n\t\toai.Components = goai.Components{\n\t\t\tSecuritySchemes: goai.SecuritySchemes{\n\t\t\t\t\"apiKey\": goai.SecuritySchemeRef{\n\t\t\t\t\tRef: \"\",\n\t\t\t\t\tValue: &goai.SecurityScheme{\n\t\t\t\t\t\t// 此处type是openApi的规定，详见 https://swagger.io/docs/specification/authentication/api-keys/\n\t\t\t\t\t\tType: \"apiKey\",\n\t\t\t\t\t\tIn:   \"header\",\n\t\t\t\t\t\tName: \"X-API-KEY\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tPath:   \"/index\",\n\t\t\tObject: f,\n\t\t})\n\t\tt.AssertNil(err)\n\t\t// Schema asserts.\n\t\tfmt.Println(oai.String())\n\t\tt.Assert(len(oai.Components.Schemas.Map()), 3)\n\t\tt.Assert(len(oai.Components.SecuritySchemes), 1)\n\t\tt.Assert(oai.Components.SecuritySchemes[\"apiKey\"].Value.Type, \"apiKey\")\n\t\tt.Assert(len(oai.Paths), 1)\n\t\tvar (\n\t\t\tschemaIndex = oai.Paths[\"/index\"].Put.Responses[\"200\"].Value.Content[\"application/json\"].Schema\n\t\t\tschemaReq   = oai.Components.Schemas.Get(`github.com.gogf.gf.v2.net.goai_test.Req`)\n\t\t)\n\t\tt.Assert(len(schemaIndex.Value.Properties.Map()), 3)\n\n\t\t// Schema Required.\n\t\tt.AssertEQ(schemaReq.Value.Required, []string{\"product\", \"name\"})\n\t})\n}\n\nfunc Test_EmptyJsonNameWithOmitEmpty(t *testing.T) {\n\ttype CreateResourceReq struct {\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\"`\n\t\tName       string `description:\"实例名称\" json:\",omitempty\"`\n\t\tProduct    string `description:\"业务类型\" json:\",omitempty\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(CreateResourceReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tvar reqKey = \"github.com.gogf.gf.v2.net.goai_test.CreateResourceReq\"\n\t\tt.AssertNE(oai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Name\"), nil)\n\t\tt.AssertNE(oai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Product\"), nil)\n\t\tt.Assert(oai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"None\"), nil)\n\t})\n}\n\nfunc Test_Enums(t *testing.T) {\n\ttype Status string\n\tconst (\n\t\tStatusA Status = \"a\"\n\t\tStatusB Status = \"b\"\n\t)\n\ttype Req struct {\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\"`\n\t\tName       string    `dc:\"实例名称\" json:\",omitempty\"`\n\t\tStatus1    Status    `dc:\"状态1\" json:\",omitempty\"`\n\t\tStatus2    *Status   `dc:\"状态2\" json:\",omitempty\"`\n\t\tStatus3    []Status  `dc:\"状态2\" json:\",omitempty\"`\n\t\tStatus4    []*Status `dc:\"状态2\" json:\",omitempty\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(Req)\n\t\t)\n\t\terr = gtag.SetGlobalEnums(gjson.MustEncodeString(g.Map{\n\t\t\t\"github.com/gogf/gf/v2/net/goai_test.Status\": []any{StatusA, StatusB},\n\t\t}))\n\t\tt.AssertNil(err)\n\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tvar reqKey = \"github.com.gogf.gf.v2.net.goai_test.Req\"\n\t\tt.AssertNE(oai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Name\"), nil)\n\t\tt.Assert(\n\t\t\toai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Status1\").Value.Enum,\n\t\t\tg.Slice{\"a\", \"b\"},\n\t\t)\n\t\tt.Assert(\n\t\t\toai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Status2\").Value.Enum,\n\t\t\tg.Slice{\"a\", \"b\"},\n\t\t)\n\t\tt.Assert(\n\t\t\toai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Status3\").Value.Items.Value.Enum,\n\t\t\tg.Slice{\"a\", \"b\"},\n\t\t)\n\t\tt.Assert(\n\t\t\toai.Components.Schemas.Get(reqKey).Value.Properties.Get(\"Status4\").Value.Items.Value.Enum,\n\t\t\tg.Slice{\"a\", \"b\"},\n\t\t)\n\t})\n}\n\nfunc Test_XExtension(t *testing.T) {\n\ttype GetListReq struct {\n\t\tg.Meta `path:\"/user\" tags:\"User\" method:\"get\" x-group:\"User/Info\" summary:\"Get user list with basic info.\"`\n\t\tPage   int `dc:\"Page number\" d:\"1\" x-sort:\"1\"`\n\t\tSize   int `dc:\"Size for per page.\" d:\"10\" x-sort:\"2\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(GetListReq)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(oai.String(), gtest.DataContent(\"XExtension\", \"expect.json\"))\n\t})\n}\n\nfunc Test_ValidationRules(t *testing.T) {\n\ttype Req struct {\n\t\tg.Meta  `path:\"/rules\" method:\"POST\" tags:\"Rules\" summary:\"Validation rules.\"`\n\t\tName    string `v:\"required|min-length:3|max-length:32#required|min|max\" dc:\"Name\"`\n\t\tAge     int    `v:\"required|min:1|max:100\" dc:\"Age\"`\n\t\tGrade   int    `v:\"between:1,12#please enter the correct grade.\" dc:\"Grade\"`\n\t\tAddress string `v:\"length:3,64\" dc:\"Address\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\toai = goai.New()\n\t\t\treq = new(Req)\n\t\t)\n\t\terr = oai.Add(goai.AddInput{\n\t\t\tObject: req,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tschema := oai.Components.Schemas.Get(\"github.com.gogf.gf.v2.net.goai_test.Req\").Value\n\t\tt.Assert(schema.Properties.Get(\"Name\").Value.MinLength, 3)\n\t\tt.Assert(schema.Properties.Get(\"Name\").Value.MaxLength, 32)\n\t\tt.Assert(schema.Properties.Get(\"Age\").Value.Min, 1.0)\n\t\tt.Assert(schema.Properties.Get(\"Age\").Value.Max, 100.0)\n\t\tt.Assert(schema.Properties.Get(\"Grade\").Value.Min, 1.0)\n\t\tt.Assert(schema.Properties.Get(\"Grade\").Value.Max, 12.0)\n\t\tt.Assert(schema.Properties.Get(\"Address\").Value.MinLength, 3)\n\t\tt.Assert(schema.Properties.Get(\"Address\").Value.MaxLength, 64)\n\t})\n}\n"
  },
  {
    "path": "net/goai/testdata/EmbeddedStructAttribute/expect.json",
    "content": "{\"openapi\":\"3.0.0\",\"components\":{\"schemas\":{\"github.com.gogf.gf.v2.net.goai_test.CreateResourceReq\":{\"properties\":{\"Name\":{\"description\":\"This is name.\",\"format\":\"string\",\"type\":\"string\"},\"Embedded\":{\"properties\":{\"Age\":{\"description\":\"This is embedded age.\",\"format\":\"uint\",\"type\":\"integer\"}},\"type\":\"object\"}},\"type\":\"object\"}}},\"info\":{\"title\":\"\",\"version\":\"\"},\"paths\":null}"
  },
  {
    "path": "net/goai/testdata/Issue3889JsonFile/201.json",
    "content": "{\n    \"code 1\": {\n        \"code\": 1,\n        \"message\": \"Aha, 201 - 1\",\n        \"data\": \"Good\"\n    },\n    \"code 2\": {\n        \"code\": 2,\n        \"message\": \"Aha, 201 - 2\",\n        \"data\": \"Not Bad\"\n    }\n}"
  },
  {
    "path": "net/goai/testdata/NameFromJsonTag/expect1.json",
    "content": "{\"openapi\":\"3.0.0\",\"components\":{\"schemas\":{\"github.com.gogf.gf.v2.net.goai_test.CreateReq\":{\"properties\":{\"nick_name\":{\"format\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}}},\"info\":{\"title\":\"\",\"version\":\"\"},\"paths\":null}"
  },
  {
    "path": "net/goai/testdata/NameFromJsonTag/expect2.json",
    "content": "{\"openapi\":\"3.0.0\",\"components\":{\"schemas\":{\"github.com.gogf.gf.v2.net.goai_test.CreateReq\":{\"properties\":{\"nick_name\":{\"format\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}}},\"info\":{\"title\":\"\",\"version\":\"\"},\"paths\":null}"
  },
  {
    "path": "net/goai/testdata/XExtension/expect.json",
    "content": "{\"openapi\":\"3.0.0\",\"components\":{\"schemas\":{\"github.com.gogf.gf.v2.net.goai_test.GetListReq\":{\"properties\":{\"Page\":{\"default\":1,\"description\":\"Page number\",\"format\":\"int\",\"type\":\"integer\",\"x-sort\":\"1\"},\"Size\":{\"default\":10,\"description\":\"Size for per page.\",\"format\":\"int\",\"type\":\"integer\",\"x-sort\":\"2\"}},\"type\":\"object\",\"x-group\":\"User/Info\"}}},\"info\":{\"title\":\"\",\"version\":\"\"},\"paths\":null}"
  },
  {
    "path": "net/goai/testdata/example.yaml",
    "content": "openapi: 3.0.1\ninfo:\n  title: Swagger Petstore\n  description: 'This is a sample server Petstore server.  You can find out more about     Swagger\n    at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).      For\n    this sample, you can use the api key `special-key` to test the authorization     filters.'\n  termsOfService: http://swagger.io/terms/\n  contact:\n    email: apiteam@swagger.io\n  license:\n    name: Apache 2.0\n    url: http://www.apache.org/licenses/LICENSE-2.0.html\n  version: 1.0.0\nexternalDocs:\n  description: Find out more about Swagger\n  url: http://swagger.io\nservers:\n  - url: https://petstore.swagger.io/v2\n  - url: http://petstore.swagger.io/v2\ntags:\n  - name: pet\n    description: Everything about your Pets\n    externalDocs:\n      description: Find out more\n      url: http://swagger.io\n  - name: store\n    description: Access to Petstore orders\n  - name: user\n    description: Operations about user\n    externalDocs:\n      description: Find out more about our store\n      url: http://swagger.io\npaths:\n  /pet:\n    put:\n      tags:\n        - pet\n      summary: Update an existing pet\n      operationId: updatePet\n      requestBody:\n        description: Pet object that needs to be added to the store\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Pet'\n          application/xml:\n            schema:\n              $ref: '#/components/schemas/Pet'\n        required: true\n      responses:\n        400:\n          description: Invalid ID supplied\n          content: {}\n        404:\n          description: Pet not found\n          content: {}\n        405:\n          description: Validation exception\n          content: {}\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n      x-codegen-request-body-name: body\n    post:\n      tags:\n        - pet\n      summary: Add a new pet to the store\n      operationId: addPet\n      requestBody:\n        description: Pet object that needs to be added to the store\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/Pet'\n          application/xml:\n            schema:\n              $ref: '#/components/schemas/Pet'\n        required: true\n      responses:\n        405:\n          description: Invalid input\n          content: {}\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n      x-codegen-request-body-name: body\n  /pet/findByStatus:\n    get:\n      tags:\n        - pet\n      summary: Finds Pets by status\n      description: Multiple status values can be provided with comma separated strings\n      operationId: findPetsByStatus\n      parameters:\n        - name: status\n          in: query\n          description: Status values that need to be considered for filter\n          required: true\n          style: form\n          explode: true\n          schema:\n            type: array\n            items:\n              type: string\n              default: available\n              enum:\n                - available\n                - pending\n                - sold\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Pet'\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Pet'\n        400:\n          description: Invalid status value\n          content: {}\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n  /pet/findByTags:\n    get:\n      tags:\n        - pet\n      summary: Finds Pets by tags\n      description: Multiple tags can be provided with comma separated strings. Use         tag1,\n        tag2, tag3 for testing.\n      operationId: findPetsByTags\n      parameters:\n        - name: tags\n          in: query\n          description: Tags to filter by\n          required: true\n          style: form\n          explode: true\n          schema:\n            type: array\n            items:\n              type: string\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Pet'\n            application/json:\n              schema:\n                type: array\n                items:\n                  $ref: '#/components/schemas/Pet'\n        400:\n          description: Invalid tag value\n          content: {}\n      deprecated: true\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n  /pet/{petId}:\n    get:\n      tags:\n        - pet\n      summary: Find pet by ID\n      description: Returns a single pet\n      operationId: getPetById\n      parameters:\n        - name: petId\n          in: path\n          description: ID of pet to return\n          required: true\n          schema:\n            type: integer\n            format: int64\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                $ref: '#/components/schemas/Pet'\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Pet'\n        400:\n          description: Invalid ID supplied\n          content: {}\n        404:\n          description: Pet not found\n          content: {}\n      security:\n        - api_key: []\n    post:\n      tags:\n        - pet\n      summary: Updates a pet in the store with form data\n      operationId: updatePetWithForm\n      parameters:\n        - name: petId\n          in: path\n          description: ID of pet that needs to be updated\n          required: true\n          schema:\n            type: integer\n            format: int64\n      requestBody:\n        content:\n          application/x-www-form-urlencoded:\n            schema:\n              properties:\n                name:\n                  type: string\n                  description: Updated name of the pet\n                status:\n                  type: string\n                  description: Updated status of the pet\n      responses:\n        405:\n          description: Invalid input\n          content: {}\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n    delete:\n      tags:\n        - pet\n      summary: Deletes a pet\n      operationId: deletePet\n      parameters:\n        - name: api_key\n          in: header\n          schema:\n            type: string\n        - name: petId\n          in: path\n          description: Pet id to delete\n          required: true\n          schema:\n            type: integer\n            format: int64\n      responses:\n        400:\n          description: Invalid ID supplied\n          content: {}\n        404:\n          description: Pet not found\n          content: {}\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n  /pet/{petId}/uploadImage:\n    post:\n      tags:\n        - pet\n      summary: uploads an image\n      operationId: uploadFile\n      parameters:\n        - name: petId\n          in: path\n          description: ID of pet to update\n          required: true\n          schema:\n            type: integer\n            format: int64\n      requestBody:\n        content:\n          multipart/form-data:\n            schema:\n              properties:\n                additionalMetadata:\n                  type: string\n                  description: Additional data to pass to server\n                file:\n                  type: string\n                  description: file to upload\n                  format: binary\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ApiResponse'\n      security:\n        - petstore_auth:\n            - write:pets\n            - read:pets\n  /store/inventory:\n    get:\n      tags:\n        - store\n      summary: Returns pet inventories by status\n      description: Returns a map of status codes to quantities\n      operationId: getInventory\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/json:\n              schema:\n                type: object\n                additionalProperties:\n                  type: integer\n                  format: int32\n      security:\n        - api_key: []\n  /store/order:\n    post:\n      tags:\n        - store\n      summary: Place an order for a pet\n      operationId: placeOrder\n      requestBody:\n        description: order placed for purchasing the pet\n        content:\n          '*/*':\n            schema:\n              $ref: '#/components/schemas/Order'\n        required: true\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                $ref: '#/components/schemas/Order'\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Order'\n        400:\n          description: Invalid Order\n          content: {}\n      x-codegen-request-body-name: body\n  /store/order/{orderId}:\n    get:\n      tags:\n        - store\n      summary: Find purchase order by ID\n      description: For valid response try integer IDs with value >= 1 and <= 10.         Other\n        values will generated exceptions\n      operationId: getOrderById\n      parameters:\n        - name: orderId\n          in: path\n          description: ID of pet that needs to be fetched\n          required: true\n          schema:\n            maximum: 10.0\n            minimum: 1.0\n            type: integer\n            format: int64\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                $ref: '#/components/schemas/Order'\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Order'\n        400:\n          description: Invalid ID supplied\n          content: {}\n        404:\n          description: Order not found\n          content: {}\n    delete:\n      tags:\n        - store\n      summary: Delete purchase order by ID\n      description: For valid response try integer IDs with positive integer value.         Negative\n        or non-integer values will generate API errors\n      operationId: deleteOrder\n      parameters:\n        - name: orderId\n          in: path\n          description: ID of the order that needs to be deleted\n          required: true\n          schema:\n            minimum: 1.0\n            type: integer\n            format: int64\n      responses:\n        400:\n          description: Invalid ID supplied\n          content: {}\n        404:\n          description: Order not found\n          content: {}\n  /user:\n    post:\n      tags:\n        - user\n      summary: Create user\n      description: This can only be done by the logged in user.\n      operationId: createUser\n      requestBody:\n        description: Created user object\n        content:\n          '*/*':\n            schema:\n              $ref: '#/components/schemas/User'\n        required: true\n      responses:\n        default:\n          description: successful operation\n          content: {}\n      x-codegen-request-body-name: body\n  /user/createWithArray:\n    post:\n      tags:\n        - user\n      summary: Creates list of users with given input array\n      operationId: createUsersWithArrayInput\n      requestBody:\n        description: List of user object\n        content:\n          '*/*':\n            schema:\n              type: array\n              items:\n                $ref: '#/components/schemas/User'\n        required: true\n      responses:\n        default:\n          description: successful operation\n          content: {}\n      x-codegen-request-body-name: body\n  /user/createWithList:\n    post:\n      tags:\n        - user\n      summary: Creates list of users with given input array\n      operationId: createUsersWithListInput\n      requestBody:\n        description: List of user object\n        content:\n          '*/*':\n            schema:\n              type: array\n              items:\n                $ref: '#/components/schemas/User'\n        required: true\n      responses:\n        default:\n          description: successful operation\n          content: {}\n      x-codegen-request-body-name: body\n  /user/login:\n    get:\n      tags:\n        - user\n      summary: Logs user into the system\n      operationId: loginUser\n      parameters:\n        - name: username\n          in: query\n          description: The user name for login\n          required: true\n          schema:\n            type: string\n        - name: password\n          in: query\n          description: The password for login in clear text\n          required: true\n          schema:\n            type: string\n      responses:\n        200:\n          description: successful operation\n          headers:\n            X-Rate-Limit:\n              description: calls per hour allowed by the user\n              schema:\n                type: integer\n                format: int32\n            X-Expires-After:\n              description: date in UTC when token expires\n              schema:\n                type: string\n                format: date-time\n          content:\n            application/xml:\n              schema:\n                type: string\n            application/json:\n              schema:\n                type: string\n        400:\n          description: Invalid username/password supplied\n          content: {}\n  /user/logout:\n    get:\n      tags:\n        - user\n      summary: Logs out current logged in user session\n      operationId: logoutUser\n      responses:\n        default:\n          description: successful operation\n          content: {}\n  /user/{username}:\n    get:\n      tags:\n        - user\n      summary: Get user by user name\n      operationId: getUserByName\n      parameters:\n        - name: username\n          in: path\n          description: 'The name that needs to be fetched. Use user1 for testing. '\n          required: true\n          schema:\n            type: string\n      responses:\n        200:\n          description: successful operation\n          content:\n            application/xml:\n              schema:\n                $ref: '#/components/schemas/User'\n            application/json:\n              schema:\n                $ref: '#/components/schemas/User'\n        400:\n          description: Invalid username supplied\n          content: {}\n        404:\n          description: User not found\n          content: {}\n    put:\n      tags:\n        - user\n      summary: Updated user\n      description: This can only be done by the logged in user.\n      operationId: updateUser\n      parameters:\n        - name: username\n          in: path\n          description: name that need to be updated\n          required: true\n          schema:\n            type: string\n      requestBody:\n        description: Updated user object\n        content:\n          '*/*':\n            schema:\n              $ref: '#/components/schemas/User'\n        required: true\n      responses:\n        400:\n          description: Invalid user supplied\n          content: {}\n        404:\n          description: User not found\n          content: {}\n      x-codegen-request-body-name: body\n    delete:\n      tags:\n        - user\n      summary: Delete user\n      description: This can only be done by the logged in user.\n      operationId: deleteUser\n      parameters:\n        - name: username\n          in: path\n          description: The name that needs to be deleted\n          required: true\n          schema:\n            type: string\n      responses:\n        400:\n          description: Invalid username supplied\n          content: {}\n        404:\n          description: User not found\n          content: {}\ncomponents:\n  schemas:\n    Order:\n      type: object\n      properties:\n        id:\n          type: integer\n          format: int64\n        petId:\n          type: integer\n          format: int64\n        quantity:\n          type: integer\n          format: int32\n        shipDate:\n          type: string\n          format: date-time\n        status:\n          type: string\n          description: Order Status\n          enum:\n            - placed\n            - approved\n            - delivered\n        complete:\n          type: boolean\n          default: false\n      xml:\n        name: Order\n    Category:\n      type: object\n      properties:\n        id:\n          type: integer\n          format: int64\n        name:\n          type: string\n      xml:\n        name: Category\n    User:\n      type: object\n      properties:\n        id:\n          type: integer\n          format: int64\n        username:\n          type: string\n        firstName:\n          type: string\n        lastName:\n          type: string\n        email:\n          type: string\n        password:\n          type: string\n        phone:\n          type: string\n        userStatus:\n          type: integer\n          description: User Status\n          format: int32\n      xml:\n        name: User\n    Tag:\n      type: object\n      properties:\n        id:\n          type: integer\n          format: int64\n        name:\n          type: string\n      xml:\n        name: Tag\n    Pet:\n      required:\n        - name\n        - photoUrls\n      type: object\n      properties:\n        id:\n          type: integer\n          format: int64\n        category:\n          $ref: '#/components/schemas/Category'\n        name:\n          type: string\n          example: doggie\n        photoUrls:\n          type: array\n          xml:\n            name: photoUrl\n            wrapped: true\n          items:\n            type: string\n        tags:\n          type: array\n          xml:\n            name: tag\n            wrapped: true\n          items:\n            $ref: '#/components/schemas/Tag'\n        status:\n          type: string\n          description: pet status in the store\n          enum:\n            - available\n            - pending\n            - sold\n      xml:\n        name: Pet\n    ApiResponse:\n      type: object\n      properties:\n        code:\n          type: integer\n          format: int32\n        type:\n          type: string\n        message:\n          type: string\n  securitySchemes:\n    petstore_auth:\n      type: oauth2\n      flows:\n        implicit:\n          authorizationUrl: http://petstore.swagger.io/oauth/dialog\n          scopes:\n            write:pets: modify pets in your account\n            read:pets: read your pets\n    api_key:\n      type: apiKey\n      name: api_key\n      in: header\n"
  },
  {
    "path": "net/gsel/gsel.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsel provides selector definition and implements.\npackage gsel\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n)\n\n// Builder creates and returns selector in runtime.\ntype Builder interface {\n\tName() string\n\tBuild() Selector\n}\n\n// Selector for service balancer.\ntype Selector interface {\n\t// Pick selects and returns service.\n\tPick(ctx context.Context) (node Node, done DoneFunc, err error)\n\n\t// Update updates services into Selector.\n\tUpdate(ctx context.Context, nodes Nodes) error\n}\n\n// Node is node interface.\ntype Node interface {\n\tService() gsvc.Service\n\tAddress() string\n}\n\n// Nodes contains multiple Node.\ntype Nodes []Node\n\n// DoneFunc is callback function when RPC invoke done.\ntype DoneFunc func(ctx context.Context, di DoneInfo)\n\n// DoneInfo contains additional information for done.\ntype DoneInfo struct {\n\t// Err is the rpc error the RPC finished with. It could be nil.\n\tErr error\n\n\t// Trailer contains the metadata from the RPC's trailer, if present.\n\tTrailer DoneInfoMD\n\n\t// BytesSent indicates if any bytes have been sent to the server.\n\tBytesSent bool\n\n\t// BytesReceived indicates if any byte has been received from the server.\n\tBytesReceived bool\n\n\t// ServerLoad is the load received from server. It's usually sent as part of\n\t// trailing metadata.\n\t//\n\t// The only supported type now is *orca_v1.LoadReport.\n\tServerLoad any\n}\n\n// DoneInfoMD is a mapping from metadata keys to value array.\n// Users should use the following two convenience functions New and Pairs to generate MD.\ntype DoneInfoMD interface {\n\t// Len returns the number of items in md.\n\tLen() int\n\n\t// Get obtains the values for a given key.\n\t//\n\t// k is converted to lowercase before searching in md.\n\tGet(k string) []string\n\n\t// Set sets the value of a given key with a slice of values.\n\t//\n\t// k is converted to lowercase before storing in md.\n\tSet(key string, values ...string)\n\n\t// Append adds the values to key k, not overwriting what was already stored at\n\t// that key.\n\t//\n\t// k is converted to lowercase before storing in md.\n\tAppend(k string, values ...string)\n\n\t// Delete removes the values for a given key k which is converted to lowercase\n\t// before removing it from md.\n\tDelete(k string)\n}\n\n// String formats and returns Nodes as string.\nfunc (ns Nodes) String() string {\n\tvar s string\n\tfor _, node := range ns {\n\t\tif s != \"\" {\n\t\t\ts += \",\"\n\t\t}\n\t\ts += node.Address()\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "net/gsel/gsel_builder.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\n// defaultBuilder is the default Builder for globally used purpose.\nvar defaultBuilder = NewBuilderRoundRobin()\n\n// SetBuilder sets the default builder for globally used purpose.\nfunc SetBuilder(builder Builder) {\n\tdefaultBuilder = builder\n}\n\n// GetBuilder returns the default builder for globally used purpose.\nfunc GetBuilder() Builder {\n\treturn defaultBuilder\n}\n"
  },
  {
    "path": "net/gsel/gsel_builder_least_connection.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\ntype builderLeastConnection struct{}\n\nfunc NewBuilderLeastConnection() Builder {\n\treturn &builderLeastConnection{}\n}\n\nfunc (*builderLeastConnection) Name() string {\n\treturn \"BalancerLeastConnection\"\n}\n\nfunc (*builderLeastConnection) Build() Selector {\n\treturn NewSelectorLeastConnection()\n}\n"
  },
  {
    "path": "net/gsel/gsel_builder_random.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\ntype builderRandom struct{}\n\nfunc NewBuilderRandom() Builder {\n\treturn &builderRandom{}\n}\n\nfunc (*builderRandom) Name() string {\n\treturn \"BalancerRandom\"\n}\n\nfunc (*builderRandom) Build() Selector {\n\treturn NewSelectorRandom()\n}\n"
  },
  {
    "path": "net/gsel/gsel_builder_round_robin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\ntype builderRoundRobin struct{}\n\nfunc NewBuilderRoundRobin() Builder {\n\treturn &builderRoundRobin{}\n}\n\nfunc (*builderRoundRobin) Name() string {\n\treturn \"BalancerRoundRobin\"\n}\n\nfunc (*builderRoundRobin) Build() Selector {\n\treturn NewSelectorRoundRobin()\n}\n"
  },
  {
    "path": "net/gsel/gsel_builder_weight.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\ntype builderWeight struct{}\n\nfunc NewBuilderWeight() Builder {\n\treturn &builderWeight{}\n}\n\nfunc (*builderWeight) Name() string {\n\treturn \"BalancerWeight\"\n}\n\nfunc (*builderWeight) Build() Selector {\n\treturn NewSelectorWeight()\n}\n"
  },
  {
    "path": "net/gsel/gsel_selector_least_connection.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\ntype selectorLeastConnection struct {\n\tmu    sync.RWMutex\n\tnodes []*leastConnectionNode\n}\n\ntype leastConnectionNode struct {\n\tNode\n\tinflight *gtype.Int\n}\n\nfunc NewSelectorLeastConnection() Selector {\n\treturn &selectorLeastConnection{\n\t\tnodes: make([]*leastConnectionNode, 0),\n\t}\n}\n\nfunc (s *selectorLeastConnection) Update(ctx context.Context, nodes Nodes) error {\n\tintlog.Printf(ctx, `Update nodes: %s`, nodes.String())\n\tvar newNodes []*leastConnectionNode\n\tfor _, v := range nodes {\n\t\tnode := v\n\t\tnewNodes = append(newNodes, &leastConnectionNode{\n\t\t\tNode:     node,\n\t\t\tinflight: gtype.NewInt(),\n\t\t})\n\t}\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\ts.nodes = newNodes\n\treturn nil\n}\n\nfunc (s *selectorLeastConnection) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\tvar pickedNode *leastConnectionNode\n\tif len(s.nodes) == 1 {\n\t\tpickedNode = s.nodes[0]\n\t} else {\n\t\tfor _, v := range s.nodes {\n\t\t\tif pickedNode == nil {\n\t\t\t\tpickedNode = v\n\t\t\t} else if v.inflight.Val() < pickedNode.inflight.Val() {\n\t\t\t\tpickedNode = v\n\t\t\t}\n\t\t}\n\t}\n\tpickedNode.inflight.Add(1)\n\tdone = func(ctx context.Context, di DoneInfo) {\n\t\tpickedNode.inflight.Add(-1)\n\t}\n\tnode = pickedNode.Node\n\tintlog.Printf(ctx, `Picked node: %s`, node.Address())\n\treturn node, done, nil\n}\n"
  },
  {
    "path": "net/gsel/gsel_selector_random.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\ntype selectorRandom struct {\n\tmu    sync.RWMutex\n\tnodes Nodes\n}\n\nfunc NewSelectorRandom() Selector {\n\treturn &selectorRandom{\n\t\tnodes: make([]Node, 0),\n\t}\n}\n\nfunc (s *selectorRandom) Update(ctx context.Context, nodes Nodes) error {\n\tintlog.Printf(ctx, `Update nodes: %s`, nodes.String())\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\ts.nodes = nodes\n\treturn nil\n}\n\nfunc (s *selectorRandom) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\tif len(s.nodes) == 0 {\n\t\treturn nil, nil, nil\n\t}\n\tnode = s.nodes[grand.Intn(len(s.nodes))]\n\tintlog.Printf(ctx, `Picked node: %s`, node.Address())\n\treturn node, nil, nil\n}\n"
  },
  {
    "path": "net/gsel/gsel_selector_round_robin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\ntype selectorRoundRobin struct {\n\tmu    sync.Mutex\n\tnodes Nodes\n\tnext  int\n}\n\nfunc NewSelectorRoundRobin() Selector {\n\treturn &selectorRoundRobin{\n\t\tnodes: make(Nodes, 0),\n\t}\n}\n\nfunc (s *selectorRoundRobin) Update(ctx context.Context, nodes Nodes) error {\n\tintlog.Printf(ctx, `Update nodes: %s`, nodes.String())\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\ts.nodes = nodes\n\ts.next = 0\n\treturn nil\n}\n\nfunc (s *selectorRoundRobin) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\tif len(s.nodes) == 0 {\n\t\treturn\n\t}\n\tnode = s.nodes[s.next]\n\ts.next = (s.next + 1) % len(s.nodes)\n\tintlog.Printf(ctx, `Picked node: %s`, node.Address())\n\treturn\n}\n"
  },
  {
    "path": "net/gsel/gsel_selector_weight.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsel\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gsvc\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\ntype selectorWeight struct {\n\tmu    sync.RWMutex\n\tnodes Nodes\n}\n\nfunc NewSelectorWeight() Selector {\n\treturn &selectorWeight{\n\t\tnodes: make(Nodes, 0),\n\t}\n}\n\nfunc (s *selectorWeight) Update(ctx context.Context, nodes Nodes) error {\n\tintlog.Printf(ctx, `Update nodes: %s`, nodes.String())\n\tvar newNodes []Node\n\tfor _, v := range nodes {\n\t\tnode := v\n\t\tfor i := 0; i < s.getWeight(node); i++ {\n\t\t\tnewNodes = append(newNodes, node)\n\t\t}\n\t}\n\ts.mu.Lock()\n\ts.nodes = newNodes\n\ts.mu.Unlock()\n\treturn nil\n}\n\nfunc (s *selectorWeight) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\tif len(s.nodes) == 0 {\n\t\treturn nil, nil, nil\n\t}\n\tnode = s.nodes[grand.Intn(len(s.nodes))]\n\tintlog.Printf(ctx, `Picked node: %s`, node.Address())\n\treturn node, nil, nil\n}\n\nfunc (s *selectorWeight) getWeight(node Node) int {\n\treturn node.Service().GetMetadata().Get(gsvc.MDWeight).Int()\n}\n"
  },
  {
    "path": "net/gsvc/gsvc.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsvc provides service registry and discovery definition.\npackage gsvc\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Registry interface for service.\ntype Registry interface {\n\tRegistrar\n\tDiscovery\n}\n\n// Registrar interface for service registrar.\ntype Registrar interface {\n\t// Register registers `service` to Registry.\n\t// Note that it returns a new Service if it changes the input Service with custom one.\n\tRegister(ctx context.Context, service Service) (registered Service, err error)\n\n\t// Deregister off-lines and removes `service` from the Registry.\n\tDeregister(ctx context.Context, service Service) error\n}\n\n// Discovery interface for service discovery.\ntype Discovery interface {\n\t// Search searches and returns services with specified condition.\n\tSearch(ctx context.Context, in SearchInput) (result []Service, err error)\n\n\t// Watch watches specified condition changes.\n\t// The `key` is the prefix of service key.\n\tWatch(ctx context.Context, key string) (watcher Watcher, err error)\n}\n\n// Watcher interface for service.\ntype Watcher interface {\n\t// Proceed proceeds watch in blocking way.\n\t// It returns all complete services that watched by `key` if any change.\n\tProceed() (services []Service, err error)\n\n\t// Close closes the watcher.\n\tClose() error\n}\n\n// Service interface for service definition.\ntype Service interface {\n\t// GetName returns the name of the service.\n\t// The name is necessary for a service, and should be unique among services.\n\tGetName() string\n\n\t// GetVersion returns the version of the service.\n\t// It is suggested using GNU version naming like: v1.0.0, v2.0.1, v2.1.0-rc.\n\t// A service can have multiple versions deployed at once.\n\t// If no version set in service, the default version of service is \"latest\".\n\tGetVersion() string\n\n\t// GetKey formats and returns a unique key string for service.\n\t// The result key is commonly used for key-value registrar server.\n\tGetKey() string\n\n\t// GetValue formats and returns the value of the service.\n\t// The result value is commonly used for key-value registrar server.\n\tGetValue() string\n\n\t// GetPrefix formats and returns the key prefix string.\n\t// The result prefix string is commonly used in key-value registrar server\n\t// for service searching.\n\t//\n\t// Take etcd server for example, the prefix string is used like:\n\t// `etcdctl get /services/prod/hello.svc --prefix`\n\tGetPrefix() string\n\n\t// GetMetadata returns the Metadata map of service.\n\t// The Metadata is key-value pair map specifying extra attributes of a service.\n\tGetMetadata() Metadata\n\n\t// GetEndpoints returns the Endpoints of service.\n\t// The Endpoints contain multiple host/port information of service.\n\tGetEndpoints() Endpoints\n}\n\n// Endpoint interface for service.\ntype Endpoint interface {\n\t// Host returns the IPv4/IPv6 address of a service.\n\tHost() string\n\n\t// Port returns the port of a service.\n\tPort() int\n\n\t// String formats and returns the Endpoint as a string.\n\tString() string\n}\n\n// Endpoints are composed by multiple Endpoint.\ntype Endpoints []Endpoint\n\n// Metadata stores custom key-value pairs.\ntype Metadata map[string]any\n\n// SearchInput is the input for service searching.\ntype SearchInput struct {\n\tPrefix   string   // Search by key prefix.\n\tName     string   // Search by service name.\n\tVersion  string   // Search by service version.\n\tMetadata Metadata // Filter by metadata if there are multiple result.\n}\n\nconst (\n\tSchema                    = `service`            // Schema is the schema of service.\n\tDefaultHead               = `service`            // DefaultHead is the default head of service.\n\tDefaultDeployment         = `default`            // DefaultDeployment is the default deployment of service.\n\tDefaultNamespace          = `default`            // DefaultNamespace is the default namespace of service.\n\tDefaultVersion            = `latest`             // DefaultVersion is the default version of service.\n\tEnvPrefix                 = `GF_GSVC_PREFIX`     // EnvPrefix is the environment variable prefix.\n\tEnvDeployment             = `GF_GSVC_DEPLOYMENT` // EnvDeployment is the environment variable deployment.\n\tEnvNamespace              = `GF_GSVC_NAMESPACE`  // EnvNamespace is the environment variable namespace.\n\tEnvName                   = `GF_GSVC_Name`       // EnvName is the environment variable name.\n\tEnvVersion                = `GF_GSVC_VERSION`    // EnvVersion is the environment variable version.\n\tMDProtocol                = `protocol`           // MDProtocol is the metadata key for protocol.\n\tMDInsecure                = `insecure`           // MDInsecure is the metadata key for insecure.\n\tMDWeight                  = `weight`             // MDWeight is the metadata key for weight.\n\tDefaultProtocol           = `http`               // DefaultProtocol is the default protocol of service.\n\tDefaultSeparator          = \"/\"                  // DefaultSeparator is the default separator of service.\n\tEndpointHostPortDelimiter = \":\"                  // EndpointHostPortDelimiter is the delimiter of host and port.\n\tdefaultTimeout            = 5 * time.Second      // defaultTimeout is the default timeout for service registry.\n\tEndpointsDelimiter        = \",\"                  // EndpointsDelimiter is the delimiter of endpoints.\n)\n\nvar defaultRegistry Registry\n\n// SetRegistry sets the default Registry implements as your own implemented interface.\nfunc SetRegistry(registry Registry) {\n\tif registry == nil {\n\t\tpanic(gerror.New(`invalid Registry value \"nil\" given`))\n\t}\n\tdefaultRegistry = registry\n}\n\n// GetRegistry returns the default Registry that is previously set.\n// It returns nil if no Registry is set.\nfunc GetRegistry() Registry {\n\treturn defaultRegistry\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_discovery.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsvc\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// watchedMap stores discovery object and its watched service mapping.\nvar watchedMap = gmap.New(true)\n\n// ServiceWatch is used to watch the service status.\ntype ServiceWatch func(service Service)\n\n// Get retrieves and returns the service by service name.\nfunc Get(ctx context.Context, name string) (service Service, err error) {\n\treturn GetAndWatchWithDiscovery(ctx, defaultRegistry, name, nil)\n}\n\n// GetWithDiscovery retrieves and returns the service by service name in `discovery`.\nfunc GetWithDiscovery(ctx context.Context, discovery Discovery, name string) (service Service, err error) {\n\treturn GetAndWatchWithDiscovery(ctx, discovery, name, nil)\n}\n\n// GetAndWatch is used to getting the service with custom watch callback function.\nfunc GetAndWatch(ctx context.Context, name string, watch ServiceWatch) (service Service, err error) {\n\treturn GetAndWatchWithDiscovery(ctx, defaultRegistry, name, watch)\n}\n\n// GetAndWatchWithDiscovery is used to getting the service with custom watch callback function in `discovery`.\nfunc GetAndWatchWithDiscovery(ctx context.Context, discovery Discovery, name string, watch ServiceWatch) (service Service, err error) {\n\tif discovery == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `discovery cannot be nil`)\n\t}\n\t// Retrieve service map by discovery object.\n\twatchedServiceMap := watchedMap.GetOrSetFunc(discovery, func() any {\n\t\treturn gmap.NewStrAnyMap(true)\n\t}).(*gmap.StrAnyMap)\n\t// Retrieve service by name.\n\tstoredService := watchedServiceMap.GetOrSetFuncLock(name, func() any {\n\t\tvar (\n\t\t\tservices []Service\n\t\t\twatcher  Watcher\n\t\t)\n\t\tservices, err = discovery.Search(ctx, SearchInput{\n\t\t\tName: name,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tif len(services) == 0 {\n\t\t\terr = gerror.NewCodef(gcode.CodeNotFound, `service not found with name \"%s\"`, name)\n\t\t\treturn nil\n\t\t}\n\n\t\t// Just pick one if multiple.\n\t\tservice = services[0]\n\n\t\t// Watch the service changes in goroutine.\n\t\tif watch != nil {\n\t\t\tif watcher, err = discovery.Watch(ctx, service.GetPrefix()); err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tgo watchAndUpdateService(watchedServiceMap, watcher, service, watch)\n\t\t}\n\t\treturn service\n\t})\n\tif storedService != nil {\n\t\tservice = storedService.(Service)\n\t}\n\treturn\n}\n\n// watchAndUpdateService watches and updates the service in memory if it is changed.\nfunc watchAndUpdateService(watchedServiceMap *gmap.StrAnyMap, watcher Watcher, service Service, watchFunc ServiceWatch) {\n\tvar (\n\t\tctx      = context.Background()\n\t\terr      error\n\t\tservices []Service\n\t)\n\tfor {\n\t\ttime.Sleep(time.Second)\n\t\tif services, err = watcher.Proceed(); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\tcontinue\n\t\t}\n\t\tif len(services) > 0 {\n\t\t\twatchedServiceMap.Set(service.GetName(), services[0])\n\t\t\tif watchFunc != nil {\n\t\t\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\t\t\twatchFunc(services[0])\n\t\t\t\t}, func(ctx context.Context, exception error) {\n\t\t\t\t\tintlog.Errorf(ctx, `%+v`, exception)\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Search searches and returns services with specified condition.\nfunc Search(ctx context.Context, in SearchInput) ([]Service, error) {\n\tif defaultRegistry == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)\n\t}\n\tctx, _ = context.WithTimeout(ctx, defaultTimeout)\n\treturn defaultRegistry.Search(ctx, in)\n}\n\n// Watch watches specified condition changes.\nfunc Watch(ctx context.Context, key string) (Watcher, error) {\n\tif defaultRegistry == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)\n\t}\n\treturn defaultRegistry.Watch(ctx, key)\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_endpoint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsvc provides service registry and discovery definition.\npackage gsvc\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// LocalEndpoint implements interface Endpoint.\ntype LocalEndpoint struct {\n\thost string // host can be either IPv4 or IPv6 address.\n\tport int    // port is port as commonly known.\n}\n\n// NewEndpoint creates and returns an Endpoint from address string of pattern \"host:port\",\n// eg: \"192.168.1.100:80\".\nfunc NewEndpoint(address string) Endpoint {\n\tarray := gstr.SplitAndTrim(address, EndpointHostPortDelimiter)\n\tif len(array) != 2 {\n\t\tpanic(gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid address \"%s\" for creating endpoint, endpoint address is like \"ip:port\"`,\n\t\t\taddress,\n\t\t))\n\t}\n\treturn &LocalEndpoint{\n\t\thost: array[0],\n\t\tport: gconv.Int(array[1]),\n\t}\n}\n\n// Host returns the IPv4/IPv6 address of a service.\nfunc (e *LocalEndpoint) Host() string {\n\treturn e.host\n}\n\n// Port returns the port of a service.\nfunc (e *LocalEndpoint) Port() int {\n\treturn e.port\n}\n\n// String formats and returns the Endpoint as a string, like: 192.168.1.100:80.\nfunc (e *LocalEndpoint) String() string {\n\treturn fmt.Sprintf(`%s:%d`, e.host, e.port)\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_endpoints.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsvc provides service registry and discovery definition.\npackage gsvc\n\nimport (\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// NewEndpoints creates and returns Endpoints from multiple addresses like:\n// \"192.168.1.100:80,192.168.1.101:80\".\nfunc NewEndpoints(addresses string) Endpoints {\n\tendpoints := make([]Endpoint, 0)\n\tfor _, address := range gstr.SplitAndTrim(addresses, EndpointsDelimiter) {\n\t\tendpoints = append(endpoints, NewEndpoint(address))\n\t}\n\treturn endpoints\n}\n\n// String formats and returns the Endpoints as a string like:\n// \"192.168.1.100:80,192.168.1.101:80\"\nfunc (es Endpoints) String() string {\n\tvar s string\n\tfor _, endpoint := range es {\n\t\tif s != \"\" {\n\t\t\ts += EndpointsDelimiter\n\t\t}\n\t\ts += endpoint.String()\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_metadata.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsvc\n\nimport (\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// Set sets key-value pair into metadata.\nfunc (m Metadata) Set(key string, value any) {\n\tm[key] = value\n}\n\n// Sets sets key-value pairs into metadata.\nfunc (m Metadata) Sets(kvs map[string]any) {\n\tfor k, v := range kvs {\n\t\tm[k] = v\n\t}\n}\n\n// Get retrieves and returns value of specified key as gvar.\nfunc (m Metadata) Get(key string) *gvar.Var {\n\tif v, ok := m[key]; ok {\n\t\treturn gvar.New(v)\n\t}\n\treturn nil\n}\n\n// IsEmpty checks and returns whether current Metadata is empty.\nfunc (m Metadata) IsEmpty() bool {\n\treturn len(m) == 0\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_registry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsvc\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Register registers `service` to default registry..\nfunc Register(ctx context.Context, service Service) (Service, error) {\n\tif defaultRegistry == nil {\n\t\treturn nil, gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)\n\t}\n\tctx, cancel := context.WithTimeout(ctx, defaultTimeout)\n\tdefer cancel()\n\n\treturn defaultRegistry.Register(ctx, service)\n}\n\n// Deregister removes `service` from default registry.\nfunc Deregister(ctx context.Context, service Service) error {\n\tif defaultRegistry == nil {\n\t\treturn gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)\n\t}\n\tctx, cancel := context.WithTimeout(ctx, defaultTimeout)\n\tdefer cancel()\n\n\treturn defaultRegistry.Deregister(ctx, service)\n}\n"
  },
  {
    "path": "net/gsvc/gsvc_service.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsvc\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// LocalService provides a default implements for interface Service.\ntype LocalService struct {\n\tHead       string    // Service custom head string in service key.\n\tDeployment string    // Service deployment name, eg: dev, qa, staging, prod, etc.\n\tNamespace  string    // Service Namespace, to indicate different services in the same environment with the same Name.\n\tName       string    // Name for the service.\n\tVersion    string    // Service version, eg: v1.0.0, v2.1.1, etc.\n\tEndpoints  Endpoints // Service Endpoints, pattern: IP:port, eg: 192.168.1.2:8000.\n\tMetadata   Metadata  // Custom data for this service, which can be set using JSON by environment or command-line.\n}\n\n// NewServiceWithName creates and returns a default implements for interface Service by service name.\nfunc NewServiceWithName(name string) Service {\n\ts := &LocalService{\n\t\tName:     name,\n\t\tMetadata: make(Metadata),\n\t}\n\ts.autoFillDefaultAttributes()\n\treturn s\n}\n\n// NewServiceWithKV creates and returns a default implements for interface Service by key-value pair string.\nfunc NewServiceWithKV(key, value string) (Service, error) {\n\tvar (\n\t\terr   error\n\t\tarray = gstr.Split(gstr.Trim(key, DefaultSeparator), DefaultSeparator)\n\t)\n\tif len(array) < 6 {\n\t\terr = gerror.NewCodef(gcode.CodeInvalidParameter, `invalid service key \"%s\"`, key)\n\t\treturn nil, err\n\t}\n\ts := &LocalService{\n\t\tHead:       array[0],\n\t\tDeployment: array[1],\n\t\tNamespace:  array[2],\n\t\tName:       array[3],\n\t\tVersion:    array[4],\n\t\tEndpoints:  NewEndpoints(array[5]),\n\t\tMetadata:   make(Metadata),\n\t}\n\ts.autoFillDefaultAttributes()\n\tif len(value) > 0 {\n\t\tif err = gjson.Unmarshal([]byte(value), &s.Metadata); err != nil {\n\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `invalid service value \"%s\"`, value)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn s, nil\n}\n\n// GetName returns the name of the service.\n// The name is necessary for a service, and should be unique among services.\nfunc (s *LocalService) GetName() string {\n\treturn s.Name\n}\n\n// GetVersion returns the version of the service.\n// It is suggested using GNU version naming like: v1.0.0, v2.0.1, v2.1.0-rc.\n// A service can have multiple versions deployed at once.\n// If no version set in service, the default version of service is \"latest\".\nfunc (s *LocalService) GetVersion() string {\n\treturn s.Version\n}\n\n// GetKey formats and returns a unique key string for service.\n// The result key is commonly used for key-value registrar server.\nfunc (s *LocalService) GetKey() string {\n\tserviceNameUnique := s.GetPrefix()\n\tserviceNameUnique += DefaultSeparator + s.Endpoints.String()\n\treturn serviceNameUnique\n}\n\n// GetValue formats and returns the value of the service.\n// The result value is commonly used for key-value registrar server.\nfunc (s *LocalService) GetValue() string {\n\tb, err := gjson.Marshal(s.Metadata)\n\tif err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t}\n\treturn string(b)\n}\n\n// GetPrefix formats and returns the key prefix string.\n// The result prefix string is commonly used in key-value registrar server\n// for service searching.\n//\n// Take etcd server for example, the prefix string is used like:\n// `etcdctl get /services/prod/hello.svc --prefix`\nfunc (s *LocalService) GetPrefix() string {\n\ts.autoFillDefaultAttributes()\n\treturn DefaultSeparator + gstr.Join(\n\t\t[]string{\n\t\t\ts.Head,\n\t\t\ts.Deployment,\n\t\t\ts.Namespace,\n\t\t\ts.Name,\n\t\t\ts.Version,\n\t\t},\n\t\tDefaultSeparator,\n\t)\n}\n\n// GetMetadata returns the Metadata map of service.\n// The Metadata is key-value pair map specifying extra attributes of a service.\nfunc (s *LocalService) GetMetadata() Metadata {\n\treturn s.Metadata\n}\n\n// GetEndpoints returns the Endpoints of service.\n// The Endpoints contain multiple host/port information of service.\nfunc (s *LocalService) GetEndpoints() Endpoints {\n\treturn s.Endpoints\n}\n\nfunc (s *LocalService) autoFillDefaultAttributes() {\n\tif s.Head == \"\" {\n\t\ts.Head = gcmd.GetOptWithEnv(EnvPrefix, DefaultHead).String()\n\t}\n\tif s.Deployment == \"\" {\n\t\ts.Deployment = gcmd.GetOptWithEnv(EnvDeployment, DefaultDeployment).String()\n\t}\n\tif s.Namespace == \"\" {\n\t\ts.Namespace = gcmd.GetOptWithEnv(EnvNamespace, DefaultNamespace).String()\n\t}\n\tif s.Name == \"\" {\n\t\ts.Name = gcmd.GetOptWithEnv(EnvName).String()\n\t}\n\tif s.Version == \"\" {\n\t\ts.Version = gcmd.GetOptWithEnv(EnvVersion, DefaultVersion).String()\n\t}\n}\n"
  },
  {
    "path": "net/gtcp/gtcp.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtcp provides TCP server and client implementations.\npackage gtcp\n"
  },
  {
    "path": "net/gtcp/gtcp_conn.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Conn is the TCP connection object.\ntype Conn struct {\n\tnet.Conn                     // Underlying TCP connection object.\n\treader         *bufio.Reader // Buffer reader for connection.\n\tdeadlineRecv   time.Time     // Timeout point for reading.\n\tdeadlineSend   time.Time     // Timeout point for writing.\n\tbufferWaitRecv time.Duration // Interval duration for reading buffer.\n}\n\nconst (\n\t// Default interval for reading buffer.\n\treceiveAllWaitTimeout = time.Millisecond\n)\n\n// NewConn creates and returns a new connection with given address.\nfunc NewConn(addr string, timeout ...time.Duration) (*Conn, error) {\n\tif conn, err := NewNetConn(addr, timeout...); err == nil {\n\t\treturn NewConnByNetConn(conn), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// NewConnTLS creates and returns a new TLS connection\n// with given address and TLS configuration.\nfunc NewConnTLS(addr string, tlsConfig *tls.Config) (*Conn, error) {\n\tif conn, err := NewNetConnTLS(addr, tlsConfig); err == nil {\n\t\treturn NewConnByNetConn(conn), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// NewConnKeyCrt creates and returns a new TLS connection\n// with given address and TLS certificate and key files.\nfunc NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error) {\n\tif conn, err := NewNetConnKeyCrt(addr, crtFile, keyFile); err == nil {\n\t\treturn NewConnByNetConn(conn), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// NewConnByNetConn creates and returns a TCP connection object with given net.Conn object.\nfunc NewConnByNetConn(conn net.Conn) *Conn {\n\treturn &Conn{\n\t\tConn:           conn,\n\t\treader:         bufio.NewReader(conn),\n\t\tdeadlineRecv:   time.Time{},\n\t\tdeadlineSend:   time.Time{},\n\t\tbufferWaitRecv: receiveAllWaitTimeout,\n\t}\n}\n\n// Send writes data to remote address.\nfunc (c *Conn) Send(data []byte, retry ...Retry) error {\n\tfor {\n\t\tif _, err := c.Write(data); err != nil {\n\t\t\t// Connection closed.\n\t\t\tif err == io.EOF {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// Still failed even after retrying.\n\t\t\tif len(retry) == 0 || retry[0].Count == 0 {\n\t\t\t\terr = gerror.Wrap(err, `Write data failed`)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif len(retry) > 0 {\n\t\t\t\tretry[0].Count--\n\t\t\t\tif retry[0].Interval == 0 {\n\t\t\t\t\tretry[0].Interval = defaultRetryInternal\n\t\t\t\t}\n\t\t\t\ttime.Sleep(retry[0].Interval)\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// Recv receives and returns data from the connection.\n//\n// Note that,\n//  1. If length = 0, which means it receives the data from current buffer and returns immediately.\n//  2. If length < 0, which means it receives all data from connection and returns it until no data\n//     from connection. Developers should notice the package parsing yourself if you decide receiving\n//     all data from buffer.\n//  3. If length > 0, which means it blocks reading data from connection until length size was received.\n//     It is the most commonly used length value for data receiving.\nfunc (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {\n\tvar (\n\t\terr        error  // Reading error.\n\t\tsize       int    // Reading size.\n\t\tindex      int    // Received size.\n\t\tbuffer     []byte // Buffer object.\n\t\tbufferWait bool   // Whether buffer reading timeout set.\n\t)\n\tif length > 0 {\n\t\tbuffer = make([]byte, length)\n\t} else {\n\t\tbuffer = make([]byte, defaultReadBufferSize)\n\t}\n\n\tfor {\n\t\tif length < 0 && index > 0 {\n\t\t\tbufferWait = true\n\t\t\tif err = c.SetReadDeadline(time.Now().Add(c.bufferWaitRecv)); err != nil {\n\t\t\t\terr = gerror.Wrap(err, `SetReadDeadline for connection failed`)\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tsize, err = c.reader.Read(buffer[index:])\n\t\tif size > 0 {\n\t\t\tindex += size\n\t\t\tif length > 0 {\n\t\t\t\t// It reads til `length` size if `length` is specified.\n\t\t\t\tif index == length {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif index >= defaultReadBufferSize {\n\t\t\t\t\t// If it exceeds the buffer size, it then automatically increases its buffer size.\n\t\t\t\t\tbuffer = append(buffer, make([]byte, defaultReadBufferSize)...)\n\t\t\t\t} else {\n\t\t\t\t\t// It returns immediately if received size is lesser than buffer size.\n\t\t\t\t\tif !bufferWait {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\t// Connection closed.\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Re-set the timeout when reading data.\n\t\t\tif bufferWait && isTimeout(err) {\n\t\t\t\tif err = c.SetReadDeadline(c.deadlineRecv); err != nil {\n\t\t\t\t\terr = gerror.Wrap(err, `SetReadDeadline for connection failed`)\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\terr = nil\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif len(retry) > 0 {\n\t\t\t\t// It fails even it retried.\n\t\t\t\tif retry[0].Count == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tretry[0].Count--\n\t\t\t\tif retry[0].Interval == 0 {\n\t\t\t\t\tretry[0].Interval = defaultRetryInternal\n\t\t\t\t}\n\t\t\t\ttime.Sleep(retry[0].Interval)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\t// Just read once from buffer.\n\t\tif length == 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn buffer[:index], err\n}\n\n// RecvLine reads data from the connection until reads char '\\n'.\n// Note that the returned result does not contain the last char '\\n'.\nfunc (c *Conn) RecvLine(retry ...Retry) ([]byte, error) {\n\tvar (\n\t\terr    error\n\t\tbuffer []byte\n\t\tdata   = make([]byte, 0)\n\t)\n\tfor {\n\t\tbuffer, err = c.Recv(1, retry...)\n\t\tif len(buffer) > 0 {\n\t\t\tif buffer[0] == '\\n' {\n\t\t\t\tdata = append(data, buffer[:len(buffer)-1]...)\n\t\t\t\tbreak\n\t\t\t} else {\n\t\t\t\tdata = append(data, buffer...)\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn data, err\n}\n\n// RecvTill reads data from the connection until reads bytes `til`.\n// Note that the returned result contains the last bytes `til`.\nfunc (c *Conn) RecvTill(til []byte, retry ...Retry) ([]byte, error) {\n\tvar (\n\t\terr    error\n\t\tbuffer []byte\n\t\tdata   = make([]byte, 0)\n\t\tlength = len(til)\n\t)\n\tfor {\n\t\tbuffer, err = c.Recv(1, retry...)\n\t\tif len(buffer) > 0 {\n\t\t\tif length > 0 &&\n\t\t\t\tlen(data) >= length-1 &&\n\t\t\t\tbuffer[0] == til[length-1] &&\n\t\t\t\tbytes.EqualFold(data[len(data)-length+1:], til[:length-1]) {\n\t\t\t\tdata = append(data, buffer...)\n\t\t\t\tbreak\n\t\t\t} else {\n\t\t\t\tdata = append(data, buffer...)\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn data, err\n}\n\n// RecvWithTimeout reads data from the connection with timeout.\nfunc (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {\n\tif err = c.SetDeadlineRecv(time.Now().Add(timeout)); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineRecv(time.Time{})\n\t}()\n\tdata, err = c.Recv(length, retry...)\n\treturn\n}\n\n// SendWithTimeout writes data to the connection with timeout.\nfunc (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {\n\tif err = c.SetDeadlineSend(time.Now().Add(timeout)); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineSend(time.Time{})\n\t}()\n\terr = c.Send(data, retry...)\n\treturn\n}\n\n// SendRecv writes data to the connection and blocks reading response.\nfunc (c *Conn) SendRecv(data []byte, length int, retry ...Retry) ([]byte, error) {\n\tif err := c.Send(data, retry...); err == nil {\n\t\treturn c.Recv(length, retry...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// SendRecvWithTimeout writes data to the connection and reads response with timeout.\nfunc (c *Conn) SendRecvWithTimeout(data []byte, length int, timeout time.Duration, retry ...Retry) ([]byte, error) {\n\tif err := c.Send(data, retry...); err == nil {\n\t\treturn c.RecvWithTimeout(length, timeout, retry...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// SetDeadline sets the deadline for current connection.\nfunc (c *Conn) SetDeadline(t time.Time) (err error) {\n\tif err = c.Conn.SetDeadline(t); err == nil {\n\t\tc.deadlineRecv = t\n\t\tc.deadlineSend = t\n\t}\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `SetDeadline for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n\n// SetDeadlineRecv sets the deadline of receiving for current connection.\nfunc (c *Conn) SetDeadlineRecv(t time.Time) (err error) {\n\tif err = c.SetReadDeadline(t); err == nil {\n\t\tc.deadlineRecv = t\n\t}\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `SetDeadlineRecv for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n\n// SetDeadlineSend sets the deadline of sending for current connection.\nfunc (c *Conn) SetDeadlineSend(t time.Time) (err error) {\n\tif err = c.SetWriteDeadline(t); err == nil {\n\t\tc.deadlineSend = t\n\t}\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `SetDeadlineSend for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n\n// SetBufferWaitRecv sets the buffer waiting timeout when reading all data from connection.\n// The waiting duration cannot be too long which might delay receiving data from remote address.\nfunc (c *Conn) SetBufferWaitRecv(bufferWaitDuration time.Duration) {\n\tc.bufferWaitRecv = bufferWaitDuration\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_conn_pkg.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"encoding/binary\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\t_                    = iota << 1\n\tpkgHeaderSizeDefault // Header size for simple package protocol.\n\tpkgHeaderSizeMax     // Max header size for simple package protocol.\n)\n\n// PkgOption is package option for simple protocol.\ntype PkgOption struct {\n\t// HeaderSize is used to mark the data length for next data receiving.\n\t// It's 2 bytes in default, 4 bytes max, which stands for the max data length\n\t// from 65535 to 4294967295 bytes.\n\tHeaderSize int\n\n\t// MaxDataSize is the data field size in bytes for data length validation.\n\t// If it's not manually set, it'll automatically be set correspondingly with the HeaderSize.\n\tMaxDataSize int\n\n\t// Retry policy when operation fails.\n\tRetry Retry\n}\n\n// SendPkg send data using simple package protocol.\n//\n// Simple package protocol: DataLength(24bit)|DataField(variant)。\n//\n// Note that,\n// 1. The DataLength is the length of DataField, which does not contain the header size.\n// 2. The integer bytes of the package are encoded using BigEndian order.\nfunc (c *Conn) SendPkg(data []byte, option ...PkgOption) error {\n\tpkgOption, err := getPkgOption(option...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlength := len(data)\n\tif length > pkgOption.MaxDataSize {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`data too long, data size %d exceeds allowed max data size %d`,\n\t\t\tlength, pkgOption.MaxDataSize,\n\t\t)\n\t}\n\toffset := pkgHeaderSizeMax - pkgOption.HeaderSize\n\tbuffer := make([]byte, pkgHeaderSizeMax+len(data))\n\tbinary.BigEndian.PutUint32(buffer[0:], uint32(length))\n\tcopy(buffer[pkgHeaderSizeMax:], data)\n\tif pkgOption.Retry.Count > 0 {\n\t\treturn c.Send(buffer[offset:], pkgOption.Retry)\n\t}\n\treturn c.Send(buffer[offset:])\n}\n\n// SendPkgWithTimeout writes data to connection with timeout using simple package protocol.\nfunc (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {\n\tif err := c.SetDeadlineSend(time.Now().Add(timeout)); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineSend(time.Time{})\n\t}()\n\terr = c.SendPkg(data, option...)\n\treturn\n}\n\n// SendRecvPkg writes data to connection and blocks reading response using simple package protocol.\nfunc (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {\n\tif err := c.SendPkg(data, option...); err == nil {\n\t\treturn c.RecvPkg(option...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// SendRecvPkgWithTimeout writes data to connection and reads response with timeout using simple package protocol.\nfunc (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {\n\tif err := c.SendPkg(data, option...); err == nil {\n\t\treturn c.RecvPkgWithTimeout(timeout, option...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// RecvPkg receives data from connection using simple package protocol.\nfunc (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) {\n\tvar (\n\t\tbuffer []byte\n\t\tlength int\n\t)\n\tpkgOption, err := getPkgOption(option...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Header field.\n\tbuffer, err = c.Recv(pkgOption.HeaderSize, pkgOption.Retry)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch pkgOption.HeaderSize {\n\tcase 1:\n\t\t// It fills with zero if the header size is lesser than 4 bytes (uint32).\n\t\tlength = int(binary.BigEndian.Uint32([]byte{0, 0, 0, buffer[0]}))\n\tcase 2:\n\t\tlength = int(binary.BigEndian.Uint32([]byte{0, 0, buffer[0], buffer[1]}))\n\tcase 3:\n\t\tlength = int(binary.BigEndian.Uint32([]byte{0, buffer[0], buffer[1], buffer[2]}))\n\tdefault:\n\t\tlength = int(binary.BigEndian.Uint32([]byte{buffer[0], buffer[1], buffer[2], buffer[3]}))\n\t}\n\t// It here validates the size of the package.\n\t// It clears the buffer and returns error immediately if it validates failed.\n\tif length < 0 || length > pkgOption.MaxDataSize {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid package size %d`, length)\n\t}\n\t// Empty package.\n\tif length == 0 {\n\t\treturn nil, nil\n\t}\n\t// Data field.\n\treturn c.Recv(length, pkgOption.Retry)\n}\n\n// RecvPkgWithTimeout reads data from connection with timeout using simple package protocol.\nfunc (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {\n\tif err = c.SetDeadlineRecv(time.Now().Add(timeout)); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineRecv(time.Time{})\n\t}()\n\tdata, err = c.RecvPkg(option...)\n\treturn\n}\n\n// getPkgOption wraps and returns the PkgOption.\n// If no option given, it returns a new option with default value.\nfunc getPkgOption(option ...PkgOption) (*PkgOption, error) {\n\tpkgOption := PkgOption{}\n\tif len(option) > 0 {\n\t\tpkgOption = option[0]\n\t}\n\tif pkgOption.HeaderSize == 0 {\n\t\tpkgOption.HeaderSize = pkgHeaderSizeDefault\n\t}\n\tif pkgOption.HeaderSize > pkgHeaderSizeMax {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`package header size %d definition exceeds max header size %d`,\n\t\t\tpkgOption.HeaderSize, pkgHeaderSizeMax,\n\t\t)\n\t}\n\tif pkgOption.MaxDataSize == 0 {\n\t\tswitch pkgOption.HeaderSize {\n\t\tcase 1:\n\t\t\tpkgOption.MaxDataSize = 0xFF\n\t\tcase 2:\n\t\t\tpkgOption.MaxDataSize = 0xFFFF\n\t\tcase 3:\n\t\t\tpkgOption.MaxDataSize = 0xFFFFFF\n\t\tcase 4:\n\t\t\t// math.MaxInt32 not math.MaxUint32\n\t\t\tpkgOption.MaxDataSize = 0x7FFFFFFF\n\t\t}\n\t}\n\tif pkgOption.MaxDataSize > 0x7FFFFFFF {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`package data size %d definition exceeds allowed max data size %d`,\n\t\t\tpkgOption.MaxDataSize, 0x7FFFFFFF,\n\t\t)\n\t}\n\treturn &pkgOption, nil\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nconst (\n\tdefaultConnTimeout    = 30 * time.Second       // Default connection timeout.\n\tdefaultRetryInternal  = 100 * time.Millisecond // Default retry interval.\n\tdefaultReadBufferSize = 128                    // (Byte) Buffer size for reading.\n)\n\ntype Retry struct {\n\tCount    int           // Retry count.\n\tInterval time.Duration // Retry interval.\n}\n\n// NewNetConn creates and returns a net.Conn with given address like \"127.0.0.1:80\".\n// The optional parameter `timeout` specifies the timeout for dialing connection.\nfunc NewNetConn(address string, timeout ...time.Duration) (net.Conn, error) {\n\tvar (\n\t\tnetwork  = `tcp`\n\t\tduration = defaultConnTimeout\n\t)\n\tif len(timeout) > 0 {\n\t\tduration = timeout[0]\n\t}\n\tconn, err := net.DialTimeout(network, address, duration)\n\tif err != nil {\n\t\terr = gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.DialTimeout failed with network \"%s\", address \"%s\", timeout \"%s\"`,\n\t\t\tnetwork, address, duration,\n\t\t)\n\t}\n\treturn conn, err\n}\n\n// NewNetConnTLS creates and returns a TLS net.Conn with given address like \"127.0.0.1:80\".\n// The optional parameter `timeout` specifies the timeout for dialing connection.\nfunc NewNetConnTLS(address string, tlsConfig *tls.Config, timeout ...time.Duration) (net.Conn, error) {\n\tvar (\n\t\tnetwork = `tcp`\n\t\tdialer  = &net.Dialer{\n\t\t\tTimeout: defaultConnTimeout,\n\t\t}\n\t)\n\tif len(timeout) > 0 {\n\t\tdialer.Timeout = timeout[0]\n\t}\n\tconn, err := tls.DialWithDialer(dialer, network, address, tlsConfig)\n\tif err != nil {\n\t\terr = gerror.Wrapf(\n\t\t\terr,\n\t\t\t`tls.DialWithDialer failed with network \"%s\", address \"%s\", timeout \"%s\", tlsConfig \"%v\"`,\n\t\t\tnetwork, address, dialer.Timeout, tlsConfig,\n\t\t)\n\t}\n\treturn conn, err\n}\n\n// NewNetConnKeyCrt creates and returns a TLS net.Conn with given TLS certificate and key files\n// and address like \"127.0.0.1:80\". The optional parameter `timeout` specifies the timeout for\n// dialing connection.\nfunc NewNetConnKeyCrt(addr, crtFile, keyFile string, timeout ...time.Duration) (net.Conn, error) {\n\ttlsConfig, err := LoadKeyCrt(crtFile, keyFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewNetConnTLS(addr, tlsConfig, timeout...)\n}\n\n// Send creates connection to `address`, writes `data` to the connection and then closes the connection.\n// The optional parameter `retry` specifies the retry policy when fails in writing data.\nfunc Send(address string, data []byte, retry ...Retry) error {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\treturn conn.Send(data, retry...)\n}\n\n// SendRecv creates connection to `address`, writes `data` to the connection, receives response\n// and then closes the connection.\n//\n// The parameter `length` specifies the bytes count waiting to receive. It receives all buffer content\n// and returns if `length` is -1.\n//\n// The optional parameter `retry` specifies the retry policy when fails in writing data.\nfunc SendRecv(address string, data []byte, length int, retry ...Retry) ([]byte, error) {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendRecv(data, length, retry...)\n}\n\n// SendWithTimeout does Send logic with writing timeout limitation.\nfunc SendWithTimeout(address string, data []byte, timeout time.Duration, retry ...Retry) error {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendWithTimeout(data, timeout, retry...)\n}\n\n// SendRecvWithTimeout does SendRecv logic with reading timeout limitation.\nfunc SendRecvWithTimeout(address string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendRecvWithTimeout(data, receive, timeout, retry...)\n}\n\n// isTimeout checks whether given `err` is a timeout error.\nfunc isTimeout(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tif netErr, ok := err.(net.Error); ok && netErr.Timeout() {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.\nfunc LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {\n\tcrtPath, err := gfile.Search(crtFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkeyPath, err := gfile.Search(keyFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcrt, err := tls.LoadX509KeyPair(crtPath, keyPath)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err,\n\t\t\t`tls.LoadX509KeyPair failed for certFile \"%s\" and keyFile \"%s\"`,\n\t\t\tcrtPath, keyPath,\n\t\t)\n\t}\n\ttlsConfig := &tls.Config{}\n\ttlsConfig.Certificates = []tls.Certificate{crt}\n\ttlsConfig.Time = time.Now\n\ttlsConfig.Rand = rand.Reader\n\treturn tlsConfig, nil\n}\n\n// MustGetFreePort performs as GetFreePort, but it panics is any error occurs.\nfunc MustGetFreePort() int {\n\tport, err := GetFreePort()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn port\n}\n\n// GetFreePort retrieves and returns a port that is free.\nfunc GetFreePort() (port int, err error) {\n\tvar (\n\t\tnetwork = `tcp`\n\t\taddress = `:0`\n\t)\n\tresolvedAddr, err := net.ResolveTCPAddr(network, address)\n\tif err != nil {\n\t\treturn 0, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.ResolveTCPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\tnetwork, address,\n\t\t)\n\t}\n\tl, err := net.ListenTCP(network, resolvedAddr)\n\tif err != nil {\n\t\treturn 0, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.ListenTCP failed for network \"%s\", address \"%s\"`,\n\t\t\tnetwork, resolvedAddr.String(),\n\t\t)\n\t}\n\tport = l.Addr().(*net.TCPAddr).Port\n\tif err = l.Close(); err != nil {\n\t\terr = gerror.Wrapf(\n\t\t\terr,\n\t\t\t`close listening failed for network \"%s\", address \"%s\", port \"%d\"`,\n\t\t\tnetwork, resolvedAddr.String(), port,\n\t\t)\n\t}\n\treturn\n}\n\n// GetFreePorts retrieves and returns specified number of ports that are free.\nfunc GetFreePorts(count int) (ports []int, err error) {\n\tvar (\n\t\tnetwork = `tcp`\n\t\taddress = `:0`\n\t)\n\tfor i := 0; i < count; i++ {\n\t\tresolvedAddr, err := net.ResolveTCPAddr(network, address)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`net.ResolveTCPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\t\tnetwork, address,\n\t\t\t)\n\t\t}\n\t\tl, err := net.ListenTCP(network, resolvedAddr)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`net.ListenTCP failed for network \"%s\", address \"%s\"`,\n\t\t\t\tnetwork, resolvedAddr.String(),\n\t\t\t)\n\t\t}\n\t\tports = append(ports, l.Addr().(*net.TCPAddr).Port)\n\t\t_ = l.Close()\n\t}\n\treturn ports, nil\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_func_pkg.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport \"time\"\n\n// SendPkg sends a package containing `data` to `address` and closes the connection.\n// The optional parameter `option` specifies the package options for sending.\nfunc SendPkg(address string, data []byte, option ...PkgOption) error {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendPkg(data, option...)\n}\n\n// SendRecvPkg sends a package containing `data` to `address`, receives the response\n// and closes the connection. The optional parameter `option` specifies the package options for sending.\nfunc SendRecvPkg(address string, data []byte, option ...PkgOption) ([]byte, error) {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendRecvPkg(data, option...)\n}\n\n// SendPkgWithTimeout sends a package containing `data` to `address` with timeout limitation\n// and closes the connection. The optional parameter `option` specifies the package options for sending.\nfunc SendPkgWithTimeout(address string, data []byte, timeout time.Duration, option ...PkgOption) error {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendPkgWithTimeout(data, timeout, option...)\n}\n\n// SendRecvPkgWithTimeout sends a package containing `data` to `address`, receives the response with timeout limitation\n// and closes the connection. The optional parameter `option` specifies the package options for sending.\nfunc SendRecvPkgWithTimeout(address string, data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {\n\tconn, err := NewConn(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendRecvPkgWithTimeout(data, timeout, option...)\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_pool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gpool\"\n)\n\n// PoolConn is a connection with pool feature for TCP.\n// Note that it is NOT a pool or connection manager, it is just a TCP connection object.\ntype PoolConn struct {\n\t*Conn              // Underlying connection object.\n\tpool   *gpool.Pool // Connection pool, which is not a real connection pool, but a connection reusable pool.\n\tstatus int         // Status of current connection, which is used to mark this connection usable or not.\n}\n\nconst defaultPoolExpire = 10 * time.Second // Default TTL for connection in the pool.\n\nconst (\n\tconnStatusUnknown = iota // Means it is unknown it's connective or not.\n\tconnStatusActive         // Means it is now connective.\n\tconnStatusError          // Means it should be closed and removed from pool.\n)\n\nvar (\n\tpoolChecker = func(v *gpool.Pool) bool { return v == nil }\n\t// addressPoolMap is a mapping for address to its pool object.\n\taddressPoolMap = gmap.NewKVMapWithChecker[string, *gpool.Pool](poolChecker, true)\n)\n\n// NewPoolConn creates and returns a connection with pool feature.\nfunc NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {\n\tv := addressPoolMap.GetOrSetFuncLock(addr, func() *gpool.Pool {\n\t\tvar pool *gpool.Pool\n\t\tpool = gpool.New(defaultPoolExpire, func() (any, error) {\n\t\t\tif conn, err := NewConn(addr, timeout...); err == nil {\n\t\t\t\treturn &PoolConn{conn, pool, connStatusActive}, nil\n\t\t\t} else {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t})\n\t\treturn pool\n\t})\n\tvalue, err := v.Get()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn value.(*PoolConn), nil\n}\n\n// Close puts back the connection to the pool if it's active,\n// or closes the connection if it's not active.\n//\n// Note that, if `c` calls Close function closing itself, `c` can not\n// be used again.\nfunc (c *PoolConn) Close() error {\n\tif c.pool != nil && c.status == connStatusActive {\n\t\tc.status = connStatusUnknown\n\t\treturn c.pool.Put(c)\n\t}\n\treturn c.Conn.Close()\n}\n\n// Send writes data to the connection. It retrieves a new connection from its pool if it fails\n// writing data.\nfunc (c *PoolConn) Send(data []byte, retry ...Retry) error {\n\terr := c.Conn.Send(data, retry...)\n\tif err != nil && c.status == connStatusUnknown {\n\t\tif v, e := c.pool.Get(); e == nil {\n\t\t\tc.Conn = v.(*PoolConn).Conn\n\t\t\terr = c.Send(data, retry...)\n\t\t} else {\n\t\t\terr = e\n\t\t}\n\t}\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn err\n}\n\n// Recv receives data from the connection.\nfunc (c *PoolConn) Recv(length int, retry ...Retry) ([]byte, error) {\n\tdata, err := c.Conn.Recv(length, retry...)\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn data, err\n}\n\n// RecvLine reads data from the connection until reads char '\\n'.\n// Note that the returned result does not contain the last char '\\n'.\nfunc (c *PoolConn) RecvLine(retry ...Retry) ([]byte, error) {\n\tdata, err := c.Conn.RecvLine(retry...)\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn data, err\n}\n\n// RecvTill reads data from the connection until reads bytes `til`.\n// Note that the returned result contains the last bytes `til`.\nfunc (c *PoolConn) RecvTill(til []byte, retry ...Retry) ([]byte, error) {\n\tdata, err := c.Conn.RecvTill(til, retry...)\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn data, err\n}\n\n// RecvWithTimeout reads data from the connection with timeout.\nfunc (c *PoolConn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {\n\tif err := c.SetDeadlineRecv(time.Now().Add(timeout)); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineRecv(time.Time{})\n\t}()\n\tdata, err = c.Recv(length, retry...)\n\treturn\n}\n\n// SendWithTimeout writes data to the connection with timeout.\nfunc (c *PoolConn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {\n\tif err := c.SetDeadlineSend(time.Now().Add(timeout)); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineSend(time.Time{})\n\t}()\n\terr = c.Send(data, retry...)\n\treturn\n}\n\n// SendRecv writes data to the connection and blocks reading response.\nfunc (c *PoolConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {\n\tif err := c.Send(data, retry...); err == nil {\n\t\treturn c.Recv(receive, retry...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// SendRecvWithTimeout writes data to the connection and reads response with timeout.\nfunc (c *PoolConn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {\n\tif err := c.Send(data, retry...); err == nil {\n\t\treturn c.RecvWithTimeout(receive, timeout, retry...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_pool_pkg.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"time\"\n)\n\n// SendPkg sends a package containing `data` to the connection.\n// The optional parameter `option` specifies the package options for sending.\nfunc (c *PoolConn) SendPkg(data []byte, option ...PkgOption) (err error) {\n\tif err = c.Conn.SendPkg(data, option...); err != nil && c.status == connStatusUnknown {\n\t\tif v, e := c.pool.NewFunc(); e == nil {\n\t\t\tc.Conn = v.(*PoolConn).Conn\n\t\t\terr = c.Conn.SendPkg(data, option...)\n\t\t} else {\n\t\t\terr = e\n\t\t}\n\t}\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn err\n}\n\n// RecvPkg receives package from connection using simple package protocol.\n// The optional parameter `option` specifies the package options for receiving.\nfunc (c *PoolConn) RecvPkg(option ...PkgOption) ([]byte, error) {\n\tdata, err := c.Conn.RecvPkg(option...)\n\tif err != nil {\n\t\tc.status = connStatusError\n\t} else {\n\t\tc.status = connStatusActive\n\t}\n\treturn data, err\n}\n\n// RecvPkgWithTimeout reads data from connection with timeout using simple package protocol.\nfunc (c *PoolConn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {\n\tif err := c.SetDeadlineRecv(time.Now().Add(timeout)); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineRecv(time.Time{})\n\t}()\n\tdata, err = c.RecvPkg(option...)\n\treturn\n}\n\n// SendPkgWithTimeout writes data to connection with timeout using simple package protocol.\nfunc (c *PoolConn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {\n\tif err := c.SetDeadlineSend(time.Now().Add(timeout)); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = c.SetDeadlineSend(time.Time{})\n\t}()\n\terr = c.SendPkg(data, option...)\n\treturn\n}\n\n// SendRecvPkg writes data to connection and blocks reading response using simple package protocol.\nfunc (c *PoolConn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {\n\tif err := c.SendPkg(data, option...); err == nil {\n\t\treturn c.RecvPkg(option...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// SendRecvPkgWithTimeout reads data from connection with timeout using simple package protocol.\nfunc (c *PoolConn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {\n\tif err := c.SendPkg(data, option...); err == nil {\n\t\treturn c.RecvPkgWithTimeout(timeout, option...)\n\t} else {\n\t\treturn nil, err\n\t}\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\t// FreePortAddress marks the server listens using random free port.\n\tFreePortAddress = \":0\"\n)\n\nconst (\n\tdefaultServer = \"default\"\n)\n\n// Server is a TCP server.\ntype Server struct {\n\tmu        sync.Mutex   // Used for Server.listen concurrent safety. -- The golang test with data race checks this.\n\tlisten    net.Listener // TCP address listener.\n\taddress   string       // Server listening address.\n\thandler   func(*Conn)  // Connection handler.\n\ttlsConfig *tls.Config  // TLS configuration.\n}\n\n// Map for name to server, for singleton purpose.\nvar (\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *Server) bool { return v == nil }\n\t// serverMapping is the map for name to server.\n\tserverMapping = gmap.NewKVMapWithChecker[any, *Server](checker, true)\n)\n\n// GetServer returns the TCP server with specified `name`,\n// or it returns a new normal TCP server named `name` if it does not exist.\n// The parameter `name` is used to specify the TCP server\nfunc GetServer(name ...any) *Server {\n\tserverName := defaultServer\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tserverName = gconv.String(name[0])\n\t}\n\treturn serverMapping.GetOrSetFuncLock(serverName, func() *Server {\n\t\treturn NewServer(\"\", nil)\n\t})\n}\n\n// NewServer creates and returns a new normal TCP server.\n// The parameter `name` is optional, which is used to specify the instance name of the server.\nfunc NewServer(address string, handler func(*Conn), name ...string) *Server {\n\ts := &Server{\n\t\taddress: address,\n\t\thandler: handler,\n\t}\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tserverMapping.Set(name[0], s)\n\t}\n\treturn s\n}\n\n// NewServerTLS creates and returns a new TCP server with TLS support.\n// The parameter `name` is optional, which is used to specify the instance name of the server.\nfunc NewServerTLS(address string, tlsConfig *tls.Config, handler func(*Conn), name ...string) *Server {\n\ts := NewServer(address, handler, name...)\n\ts.SetTLSConfig(tlsConfig)\n\treturn s\n}\n\n// NewServerKeyCrt creates and returns a new TCP server with TLS support.\n// The parameter `name` is optional, which is used to specify the instance name of the server.\nfunc NewServerKeyCrt(address, crtFile, keyFile string, handler func(*Conn), name ...string) (*Server, error) {\n\ts := NewServer(address, handler, name...)\n\tif err := s.SetTLSKeyCrt(crtFile, keyFile); err != nil {\n\t\treturn nil, err\n\t}\n\treturn s, nil\n}\n\n// SetAddress sets the listening address for server.\nfunc (s *Server) SetAddress(address string) {\n\ts.address = address\n}\n\n// GetAddress get the listening address for server.\nfunc (s *Server) GetAddress() string {\n\treturn s.address\n}\n\n// SetHandler sets the connection handler for server.\nfunc (s *Server) SetHandler(handler func(*Conn)) {\n\ts.handler = handler\n}\n\n// SetTLSKeyCrt sets the certificate and key file for TLS configuration of server.\nfunc (s *Server) SetTLSKeyCrt(crtFile, keyFile string) error {\n\ttlsConfig, err := LoadKeyCrt(crtFile, keyFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.tlsConfig = tlsConfig\n\treturn nil\n}\n\n// SetTLSConfig sets the TLS configuration of server.\nfunc (s *Server) SetTLSConfig(tlsConfig *tls.Config) {\n\ts.tlsConfig = tlsConfig\n}\n\n// Close closes the listener and shutdowns the server.\nfunc (s *Server) Close() error {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\tif s.listen == nil {\n\t\treturn nil\n\t}\n\treturn s.listen.Close()\n}\n\n// Run starts running the TCP Server.\nfunc (s *Server) Run() (err error) {\n\tif s.handler == nil {\n\t\terr = gerror.NewCode(gcode.CodeMissingConfiguration, \"start running failed: socket handler not defined\")\n\t\treturn\n\t}\n\tif s.tlsConfig != nil {\n\t\t// TLS Server\n\t\ts.mu.Lock()\n\t\ts.listen, err = tls.Listen(\"tcp\", s.address, s.tlsConfig)\n\t\ts.mu.Unlock()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `tls.Listen failed for address \"%s\"`, s.address)\n\t\t\treturn\n\t\t}\n\t} else {\n\t\t// Normal Server\n\t\tvar tcpAddr *net.TCPAddr\n\t\tif tcpAddr, err = net.ResolveTCPAddr(\"tcp\", s.address); err != nil {\n\t\t\terr = gerror.Wrapf(err, `net.ResolveTCPAddr failed for address \"%s\"`, s.address)\n\t\t\treturn err\n\t\t}\n\t\ts.mu.Lock()\n\t\ts.listen, err = net.ListenTCP(\"tcp\", tcpAddr)\n\t\ts.mu.Unlock()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `net.ListenTCP failed for address \"%s\"`, s.address)\n\t\t\treturn err\n\t\t}\n\t}\n\t// Listening loop.\n\tfor {\n\t\tvar conn net.Conn\n\t\tif conn, err = s.listen.Accept(); err != nil {\n\t\t\terr = gerror.Wrapf(err, `Listener.Accept failed`)\n\t\t\treturn err\n\t\t} else if conn != nil {\n\t\t\tgo s.handler(NewConnByNetConn(conn))\n\t\t}\n\t}\n}\n\n// GetListenedAddress retrieves and returns the address string which are listened by current server.\nfunc (s *Server) GetListenedAddress() string {\n\tif !gstr.Contains(s.address, FreePortAddress) {\n\t\treturn s.address\n\t}\n\tvar (\n\t\taddress      = s.address\n\t\tlistenedPort = s.GetListenedPort()\n\t)\n\taddress = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort))\n\treturn address\n}\n\n// GetListenedPort retrieves and returns one port which is listened to by current server.\nfunc (s *Server) GetListenedPort() int {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\tif ln := s.listen; ln != nil {\n\t\treturn ln.Addr().(*net.TCPAddr).Port\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n)\n\nfunc ExampleGetFreePort() {\n\tfmt.Println(gtcp.GetFreePort())\n\n\t// May Output:\n\t// 57429 <nil>\n}\n\nfunc ExampleGetFreePorts() {\n\tfmt.Println(gtcp.GetFreePorts(2))\n\n\t// May Output:\n\t// [57743 57744] <nil>\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_z_unit_conn_pkg_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Package_Basic(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.SendPkg(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\t// SendPkg\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\terr := conn.SendPkg([]byte(gconv.String(i)))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\terr := conn.SendPkgWithTimeout([]byte(gconv.String(i)), time.Second)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\t// SendPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65536)\n\t\terr = conn.SendPkg(data)\n\t\tt.AssertNE(err, nil)\n\t})\n\t// SendRecvPkg\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tfor i := 100; i < 200; i++ {\n\t\t\tdata := []byte(gconv.String(i))\n\t\t\tresult, err := conn.SendRecvPkg(data)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result, data)\n\t\t}\n\t\tfor i := 100; i < 200; i++ {\n\t\t\tdata := []byte(gconv.String(i))\n\t\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result, data)\n\t\t}\n\t})\n\t// SendRecvPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65536)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\t// SendRecvPkg with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65500)\n\t\tdata[100] = byte(65)\n\t\tdata[65400] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Package_Basic_HeaderSize1(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg(gtcp.PkgOption{HeaderSize: 1})\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.SendPkg(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// SendRecvPkg with empty data.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(result)\n\t})\n}\n\nfunc Test_Package_Timeout(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(time.Second)\n\t\t\tgtest.Assert(conn.SendPkg(data), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"10000\")\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Millisecond*500)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"10000\")\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second*2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"10000\")\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second*2, gtcp.PkgOption{HeaderSize: 5})\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertNil(result)\n\t})\n}\n\nfunc Test_Package_Option(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\toption := gtcp.PkgOption{HeaderSize: 1}\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg(option)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tgtest.Assert(conn.SendPkg(data, option), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\t// SendRecvPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF+1)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\t// SendRecvPkg with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Package_Option_HeadSize3(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\toption := gtcp.PkgOption{HeaderSize: 3}\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg(option)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tgtest.Assert(conn.SendPkg(data, option), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 3})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Package_Option_HeadSize4(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\toption := gtcp.PkgOption{HeaderSize: 4}\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg(option)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tgtest.Assert(conn.SendPkg(data, option), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\t// SendRecvPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFFFF+1)\n\t\t_, err = conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 4})\n\t\tt.AssertNil(err)\n\t})\n\t// SendRecvPkg with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 4})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n\t// pkgOption.HeaderSize oversize\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\t_, err = conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 5})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Server_NewServerKeyCrt(t *testing.T) {\n\tvar (\n\t\tnoCrtFile = \"noCrtFile\"\n\t\tnoKeyFile = \"noKeyFile\"\n\t\tcrtFile   = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/crtFile\"\n\t\tkeyFile   = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/keyFile\"\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\taddr := \"127.0.0.1:%d\"\n\t\tfreePort, _ := gtcp.GetFreePort()\n\t\taddr = fmt.Sprintf(addr, freePort)\n\t\ts, err := gtcp.NewServerKeyCrt(addr, noCrtFile, noKeyFile, func(conn *gtcp.Conn) {\n\t\t})\n\t\tif err != nil {\n\t\t\tt.AssertNil(s)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\taddr := \"127.0.0.1:%d\"\n\t\tfreePort, _ := gtcp.GetFreePort()\n\t\taddr = fmt.Sprintf(addr, freePort)\n\t\ts, err := gtcp.NewServerKeyCrt(addr, crtFile, noKeyFile, func(conn *gtcp.Conn) {\n\t\t})\n\t\tif err != nil {\n\t\t\tt.AssertNil(s)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\taddr := \"127.0.0.1:%d\"\n\t\tfreePort, _ := gtcp.GetFreePort()\n\t\taddr = fmt.Sprintf(addr, freePort)\n\t\ts, err := gtcp.NewServerKeyCrt(addr, crtFile, keyFile, func(conn *gtcp.Conn) {\n\t\t})\n\t\tif err != nil {\n\t\t\tt.AssertNil(s)\n\t\t}\n\t})\n}\n\nfunc Test_Conn_RecvPkgError(t *testing.T) {\n\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\toption := gtcp.PkgOption{HeaderSize: 5}\n\t\tfor {\n\t\t\t_, err := conn.RecvPkg(option)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65536)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_z_unit_pool_pkg_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Pool_Package_Basic(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.SendPkg(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\t// SendPkg\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\terr := conn.SendPkg([]byte(gconv.String(i)))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\terr := conn.SendPkgWithTimeout([]byte(gconv.String(i)), time.Second)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\t// SendPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65536)\n\t\terr = conn.SendPkg(data)\n\t\tt.AssertNE(err, nil)\n\t})\n\t// SendRecvPkg\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tfor i := 100; i < 200; i++ {\n\t\t\tdata := []byte(gconv.String(i))\n\t\t\tresult, err := conn.SendRecvPkg(data)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result, data)\n\t\t}\n\t\tfor i := 100; i < 200; i++ {\n\t\t\tdata := []byte(gconv.String(i))\n\t\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(result, data)\n\t\t}\n\t})\n\t// SendRecvPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65536)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\t// SendRecvPkg with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 65500)\n\t\tdata[100] = byte(65)\n\t\tdata[65400] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Pool_Package_Timeout(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(time.Second)\n\t\t\tgtest.Assert(conn.SendPkg(data), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"10000\")\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Millisecond*500)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"10000\")\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second*2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Pool_Package_Option(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\toption := gtcp.PkgOption{HeaderSize: 1}\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg(option)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tgtest.Assert(conn.SendPkg(data, option), nil)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\t// SendRecvPkg with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF+1)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\t// SendRecvPkg with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\tresult, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n\t// SendRecvPkgWithTimeout with big data - failure.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF+1)\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\t// SendRecvPkgWithTimeout with big data - success.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := make([]byte, 0xFF)\n\t\tdata[100] = byte(65)\n\t\tdata[200] = byte(85)\n\t\tresult, err := conn.SendRecvPkgWithTimeout(data, time.Second, gtcp.PkgOption{HeaderSize: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_z_unit_pool_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Pool_Basic1(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.SendPkg(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.SendPkg(data)\n\t\tt.AssertNil(err)\n\t\terr = conn.SendPkgWithTimeout(data, time.Second)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gtcp.NewPoolConn(\"127.0.0.1:80\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Pool_Basic2(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tconn.Close()\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.SendPkg(data)\n\t\tt.AssertNil(err)\n\t\t//err = conn.SendPkgWithTimeout(data, time.Second)\n\t\t//t.AssertNil(err)\n\n\t\t_, err = conn.SendRecv(data, -1)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Pool_Send(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.Send(data)\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Pool_Recv(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.Send(data)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Pool_RecvLine(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\\n\")\n\t\terr = conn.Send(data)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err := conn.RecvLine()\n\t\tt.AssertNil(err)\n\t\tsplitData := gstr.Split(string(data), \"\\n\")\n\t\tt.Assert(result, splitData[0])\n\t})\n}\n\nfunc Test_Pool_RecvTill(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\\n\")\n\t\terr = conn.Send(data)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err := conn.RecvTill([]byte(\"\\n\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, data)\n\t})\n}\n\nfunc Test_Pool_RecvWithTimeout(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.Send(data)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err := conn.RecvWithTimeout(-1, time.Millisecond*500)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, result)\n\t})\n}\n\nfunc Test_Pool_SendWithTimeout(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\terr = conn.SendWithTimeout(data, time.Millisecond*500)\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, result)\n\t})\n}\n\nfunc Test_Pool_SendRecvWithTimeout(t *testing.T) {\n\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tdata := []byte(\"9999\")\n\t\tresult, err := conn.SendRecvWithTimeout(data, -1, time.Millisecond*500)\n\t\tt.AssertNil(err)\n\t\tt.Assert(data, result)\n\t})\n}\n"
  },
  {
    "path": "net/gtcp/gtcp_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtcp_test\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\tsimpleTimeout = time.Millisecond * 100\n\tsendData      = []byte(\"hello\")\n\tinvalidAddr   = \"127.0.0.1:99999\"\n\tcrtFile       = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.crt\"\n\tkeyFile       = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/server.key\"\n)\n\nfunc startTCPServer(addr string) *gtcp.Server {\n\ts := gtcp.NewServer(addr, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\ttime.Sleep(simpleTimeout)\n\treturn s\n}\n\nfunc startTCPPkgServer(addr string) *gtcp.Server {\n\ts := gtcp.NewServer(addr, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.RecvPkg()\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.SendPkg(data)\n\t\t}\n\t})\n\tgo s.Run()\n\ttime.Sleep(simpleTimeout)\n\treturn s\n}\n\nfunc startTCPTLSServer(addr string) *gtcp.Server {\n\ttlsConfig := &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t\tCertificates: []tls.Certificate{\n\t\t\t{},\n\t\t},\n\t}\n\ts := gtcp.NewServerTLS(addr, tlsConfig, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\ttime.Sleep(simpleTimeout)\n\treturn s\n}\n\nfunc startTCPKeyCrtServer(addr string) *gtcp.Server {\n\ts, _ := gtcp.NewServerKeyCrt(addr, crtFile, keyFile, func(conn *gtcp.Conn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconn.Send(data)\n\t\t}\n\t})\n\tgo s.Run()\n\ttime.Sleep(simpleTimeout)\n\treturn s\n}\n\nfunc TestGetFreePorts(t *testing.T) {\n\tports, _ := gtcp.GetFreePorts(2)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(ports[0], 0)\n\t\tt.AssertGT(ports[1], 0)\n\t})\n\n\tstartTCPServer(fmt.Sprintf(\"%s:%d\", \"127.0.0.1\", ports[0]))\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(fmt.Sprintf(\"127.0.0.1:%d\", ports[0]))\n\t\tt.AssertNil(err)\n\t\tdefer conn.Close()\n\t\tresult, err := conn.SendRecv(sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewPoolConn(fmt.Sprintf(\"127.0.0.1:%d\", 80))\n\t\tt.AssertNE(err, nil)\n\t\tt.AssertNil(conn)\n\t})\n}\n\nfunc TestMustGetFreePort(t *testing.T) {\n\tport := gtcp.MustGetFreePort()\n\taddr := fmt.Sprintf(\"%s:%d\", \"127.0.0.1\", port)\n\tstartTCPServer(addr)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gtcp.SendRecv(addr, sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(sendData, result)\n\t})\n}\n\nfunc TestNewConn(t *testing.T) {\n\taddr := gtcp.FreePortAddress\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(addr, simpleTimeout)\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := startTCPServer(gtcp.FreePortAddress)\n\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress(), simpleTimeout)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tdefer conn.Close()\n\t\tresult, err := conn.SendRecv(sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\n// TODO\nfunc TestNewConnTLS(t *testing.T) {\n\taddr := gtcp.FreePortAddress\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConnTLS(addr, &tls.Config{})\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := startTCPTLSServer(addr)\n\n\t\tconn, err := gtcp.NewConnTLS(s.GetListenedAddress(), &tls.Config{\n\t\t\tInsecureSkipVerify: true,\n\t\t\tCertificates: []tls.Certificate{\n\t\t\t\t{},\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestNewConnKeyCrt(t *testing.T) {\n\taddr := gtcp.FreePortAddress\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConnKeyCrt(addr, crtFile, keyFile)\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := startTCPKeyCrtServer(addr)\n\n\t\tconn, err := gtcp.NewConnKeyCrt(s.GetListenedAddress(), crtFile, keyFile)\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestConn_Send(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\terr = conn.Send(sendData, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_SendWithTimeout(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\terr = conn.SendWithTimeout(sendData, time.Second, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_SendRecv(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tresult, err := conn.SendRecv(sendData, -1, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_SendRecvWithTimeout(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tresult, err := conn.SendRecvWithTimeout(sendData, -1, time.Second, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_RecvWithTimeout(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tconn.Send(sendData)\n\t\tresult, err := conn.RecvWithTimeout(-1, time.Second, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_RecvLine(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tdata := []byte(\"hello\\n\")\n\t\tconn.Send(data)\n\t\tresult, err := conn.RecvLine(gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tsplitData := gstr.Split(string(data), \"\\n\")\n\t\tt.Assert(result, splitData[0])\n\t})\n}\n\nfunc TestConn_RecvTill(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tconn.Send(sendData)\n\t\tresult, err := conn.RecvTill([]byte(\"hello\"), gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_SetDeadline(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tconn.SetDeadline(time.Time{})\n\t\terr = conn.Send(sendData, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestConn_SetReceiveBufferWait(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewConn(s.GetListenedAddress())\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(conn, nil)\n\t\tconn.SetBufferWaitRecv(time.Millisecond * 100)\n\t\terr = conn.Send(sendData, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t\tresult, err := conn.Recv(-1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestNewNetConnKeyCrt(t *testing.T) {\n\taddr := gtcp.FreePortAddress\n\n\tstartTCPKeyCrtServer(addr)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewNetConnKeyCrt(addr, \"crtFile\", keyFile, time.Second)\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gtcp.NewNetConnKeyCrt(addr, crtFile, keyFile, time.Second)\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestSend(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.Send(invalidAddr, sendData, gtcp.Retry{Count: 1})\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.Send(s.GetListenedAddress(), sendData, gtcp.Retry{Count: 1})\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestSendRecv(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gtcp.SendRecv(invalidAddr, sendData, -1)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestSendWithTimeout(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendWithTimeout(invalidAddr, sendData, time.Millisecond*500)\n\t\tt.AssertNE(err, nil)\n\t\terr = gtcp.SendWithTimeout(s.GetListenedAddress(), sendData, time.Millisecond*500)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestSendRecvWithTimeout(t *testing.T) {\n\ts := startTCPServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gtcp.SendRecvWithTimeout(invalidAddr, sendData, -1, time.Millisecond*500)\n\t\tt.AssertNil(result)\n\t\tt.AssertNE(err, nil)\n\t\tresult, err = gtcp.SendRecvWithTimeout(s.GetListenedAddress(), sendData, -1, time.Millisecond*500)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestSendPkg(t *testing.T) {\n\ts := startTCPPkgServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\terr = gtcp.SendPkg(invalidAddr, sendData)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData, gtcp.PkgOption{Retry: gtcp.Retry{Count: 3}})\n\t\tt.AssertNil(err)\n\t\terr = gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestSendRecvPkg(t *testing.T) {\n\ts := startTCPPkgServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\t_, err = gtcp.SendRecvPkg(invalidAddr, sendData)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\tresult, err := gtcp.SendRecvPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestSendPkgWithTimeout(t *testing.T) {\n\ts := startTCPPkgServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\terr = gtcp.SendPkgWithTimeout(invalidAddr, sendData, time.Second)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\terr = gtcp.SendPkgWithTimeout(s.GetListenedAddress(), sendData, time.Second)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestSendRecvPkgWithTimeout(t *testing.T) {\n\ts := startTCPPkgServer(gtcp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\t_, err = gtcp.SendRecvPkgWithTimeout(invalidAddr, sendData, time.Second)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gtcp.SendPkg(s.GetListenedAddress(), sendData)\n\t\tt.AssertNil(err)\n\t\tresult, err := gtcp.SendRecvPkgWithTimeout(s.GetListenedAddress(), sendData, time.Second)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestNewServer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tdata, err := conn.Recv(-1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconn.Send(data)\n\t\t\t}\n\t\t}, \"NewServer\")\n\t\tdefer s.Close()\n\t\tgo s.Run()\n\n\t\ttime.Sleep(simpleTimeout)\n\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestGetServer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.GetServer(\"GetServer\")\n\t\tdefer s.Close()\n\t\tgo s.Run()\n\n\t\tt.Assert(s.GetAddress(), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tdata, err := conn.Recv(-1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconn.Send(data)\n\t\t\t}\n\t\t}, \"NewServer\")\n\n\t\ts := gtcp.GetServer(\"NewServer\")\n\t\tdefer s.Close()\n\t\tgo s.Run()\n\n\t\ttime.Sleep(simpleTimeout)\n\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestServer_SetAddress(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.NewServer(\"\", func(conn *gtcp.Conn) {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tdata, err := conn.Recv(-1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconn.Send(data)\n\t\t\t}\n\t\t})\n\t\tdefer s.Close()\n\t\tt.Assert(s.GetAddress(), \"\")\n\t\ts.SetAddress(gtcp.FreePortAddress)\n\t\tgo s.Run()\n\n\t\ttime.Sleep(simpleTimeout)\n\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestServer_SetHandler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.NewServer(gtcp.FreePortAddress, nil)\n\t\tdefer s.Close()\n\t\ts.SetHandler(func(conn *gtcp.Conn) {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tdata, err := conn.Recv(-1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconn.Send(data)\n\t\t\t}\n\t\t})\n\t\tgo s.Run()\n\n\t\ttime.Sleep(simpleTimeout)\n\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n}\n\nfunc TestServer_Run(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.NewServer(gtcp.FreePortAddress, func(conn *gtcp.Conn) {\n\t\t\tdefer conn.Close()\n\t\t\tfor {\n\t\t\t\tdata, err := conn.Recv(-1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconn.Send(data)\n\t\t\t}\n\t\t})\n\t\tdefer s.Close()\n\t\tgo s.Run()\n\n\t\ttime.Sleep(simpleTimeout)\n\n\t\tresult, err := gtcp.SendRecv(s.GetListenedAddress(), sendData, -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, sendData)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtcp.NewServer(gtcp.FreePortAddress, nil)\n\t\tdefer s.Close()\n\t\tgo func() {\n\t\t\terr := s.Run()\n\t\t\tt.AssertNE(err, nil)\n\t\t}()\n\t})\n}\n"
  },
  {
    "path": "net/gtcp/testdata/crtFile",
    "content": ""
  },
  {
    "path": "net/gtcp/testdata/keyFile",
    "content": ""
  },
  {
    "path": "net/gtcp/testdata/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDVzCCAj+gAwIBAgIJAPRQQvW4UaTJMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV\nBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg\nQ29tcGFueSBMdGQwHhcNMTcxMTA2MDMwNjUzWhcNMjcxMTA0MDMwNjUzWjBCMQsw\nCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh\ndWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\nrvm9LVnIIPlimBCiNzhLmKqe8soWN7ZND+cN8myD8mcGVZblp01JZbR4n1btEekU\nrl3oNr/6aXhLml4ijre150Z73q31XMarlgBtbkbs4Lu22rlLZg/u2hzs9f1aF1VT\nqXzru+2ifcYR15Ptoyr8t12dYSQ9YXP7LwzghE9oWw52w0LxlNL0cNq2muSMTelQ\nxBU3OuAOdy7dPhiHvkpCCZ5SmwZuK8IpSX0/pJUgDkmd3zfKaaOE4JdLKJ5lWsGF\nRgM8leygKfvW4hwguEh7S1UG9CT/6jqPpyiPii3Qc4dxrogmiTPlFpYWY8bFNa9s\niuwr8KFPPZIIwxZgDLAvywIDAQABo1AwTjAdBgNVHQ4EFgQUMsBb4Dhl4OZl+xw8\nPl2wkRhUVi0wHwYDVR0jBBgwFoAUMsBb4Dhl4OZl+xw8Pl2wkRhUVi0wDAYDVR0T\nBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAQEaUz59HZHbPt4Etv4zASn3mFJeR\nQZHmUnKhVjB163xvHoN46GJmc4VnWahOd1a7i7b+qK6AnFzKI5zmZ4z5ZrjwqZiG\nepvAQ4FVbZy1nzMjBXQIyAkiDgbdjASvOUoE4OlKA3jLH7H204K3jhpaFTKVQNeY\nBGEALlKdveQUjlp5YTk38NrrZg0yzGDBUQ6X6PCYB+kdEOOpyx6061jxgIVKuBaY\n37I88vGcC9C3PVhYvDcilMkEcUPnp7DRMiZpXU7DraCWlWbr/b+47NkTPBWiNiLC\nnlfGdCGuL0ylZ16nEpkvZVUWiAijh3sUYbz1dbBACw+8dTG/+vlKUuz/hA==\n-----END CERTIFICATE-----"
  },
  {
    "path": "net/gtcp/testdata/server.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEArvm9LVnIIPlimBCiNzhLmKqe8soWN7ZND+cN8myD8mcGVZbl\np01JZbR4n1btEekUrl3oNr/6aXhLml4ijre150Z73q31XMarlgBtbkbs4Lu22rlL\nZg/u2hzs9f1aF1VTqXzru+2ifcYR15Ptoyr8t12dYSQ9YXP7LwzghE9oWw52w0Lx\nlNL0cNq2muSMTelQxBU3OuAOdy7dPhiHvkpCCZ5SmwZuK8IpSX0/pJUgDkmd3zfK\naaOE4JdLKJ5lWsGFRgM8leygKfvW4hwguEh7S1UG9CT/6jqPpyiPii3Qc4dxrogm\niTPlFpYWY8bFNa9siuwr8KFPPZIIwxZgDLAvywIDAQABAoIBAQCRYfXaWY/cPfm6\nqY9u3DqLpbCdwGWHctRC01MWSy2y2gE8Wj2ErcW/WJ0kn4Ao8oX5fxMzcn2o5ofC\nwlZqSKA+gqTnV5jXtkbZQo+qIgotjCqZP34zVie6WHBWz2PsoTv7Rk1D/2WUpV8r\nxMCdY1lJLeJW1Vqev1REOqnNpYDqrhBsCCNn0vvCOS+/UbTbJ2d4sw3BuqGfd2Uk\neIXSlwkODKf2Tk3b4tktC7I0XZfBeO1DEpBJAYP+zPTt/we/Kne6FI/squdephJL\nJMj30bSZ0jpgP/K6otEiE3pfdzijTFPjw8ayU1yuZZMSRLJtFKbSfSNGUfXVHwZP\n6ygv91DJAoGBAOIawxKzSVJxz6yvaxh2Zxnib33TmpyWcDVKje/bk88hxEXm7C3Q\nOPMGbfy37mc6jDoH2erv2GFDFRCezHKS+OEN5heZnL3m/c6E0A4K/V9VUDSnABLi\njmDRw45mDZq9edGxkvydHYMdJhH+hbbWrxr8LQtsBLuaDzLEkHa8cscdAoGBAMYc\nWd4x3fBCA2/Xd98+ZTpYhtbYDvIYl2gfVLSiLuvf3ZgnWozibCOJg5DVh/0vCS+G\nct4Ga3e17qRXZOXuSoZdBIh7nV2mQ0+zc+4ZE7UE0cAU4KYkGBabt1J4HdIxCOUB\n60smideKfFKurh5OCxSP76tIwOhcSXpduhmb/VYHAoGAfe7V89Zz4j2No+rYRXm9\nFwetfXGcTdbkjGoIAC5WdymhfiWOKj4tWf6cyANR/6D2dWPmFhqcdB++3dD0omQF\nxqPNIhvm10aO2rXSg9/PG4gS8iCJw/r3vilXODrTHPqnnQnAin6f72UOzTrsEtgk\nE22dUR1KzYqTKH2e0ONJMmkCgYBlcFzftd7zR4nk+YoKiDNi9bNNTOISOl9EVE6W\nEzk9U6puXzAxVTqT07THM17nV+83I3urjdP3PvPLuGgUh7gnJnfMvqbsLdbnd3aT\n4slBdg9EcCw7Rd4DrYXnt1Nlre/k+t+U4k3QTLutxn2nTMTFqZHJvX3xPFfvTRCe\nTk4gfwKBgDDo8/NvOZQJi+A5qJFooWkm5mFjsq2RTuOE5dZlgfNp3FzbJ1wcC0X5\nifOWAMGIyw0m68Q07fL2rsfvfB69iB6oRv6WCuUXH2f5THgUeVxxYHHUfGJQQkcu\nXJXnZDH/OB1Pg674BzC6dGsHDM19kgWmr0aVQK4jueqxsm5pchEr\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "net/gtrace/gtrace.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtrace provides convenience wrapping functionality for tracing feature using OpenTelemetry.\npackage gtrace\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.24.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/net/gtrace/internal/provider\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\ttracingCommonKeyIpIntranet        = `ip.intranet`\n\ttracingCommonKeyIpHostname        = `hostname`\n\tcommandEnvKeyForMaxContentLogSize = \"gf.gtrace.max.content.log.size\" // To avoid too big tracing content.\n\tcommandEnvKeyForTracingInternal   = \"gf.gtrace.tracing.internal\"     // For detailed controlling for tracing content.\n)\n\nvar (\n\tintranetIps, _           = gipv4.GetIntranetIpArray()\n\tintranetIpStr            = strings.Join(intranetIps, \",\")\n\thostname, _              = os.Hostname()\n\ttracingInternal          = true       // tracingInternal enables tracing for internal type spans.\n\ttracingMaxContentLogSize = 512 * 1024 // Max log size for request and response body, especially for HTTP/RPC request.\n\t// defaultTextMapPropagator is the default propagator for context propagation between peers.\n\tdefaultTextMapPropagator = propagation.NewCompositeTextMapPropagator(\n\t\tpropagation.TraceContext{},\n\t\tpropagation.Baggage{},\n\t)\n)\n\nfunc init() {\n\ttracingInternal = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForTracingInternal, \"true\"))\n\tif maxContentLogSize := gconv.Int(command.GetOptWithEnv(commandEnvKeyForMaxContentLogSize)); maxContentLogSize > 0 {\n\t\ttracingMaxContentLogSize = maxContentLogSize\n\t}\n\t// Default trace provider.\n\totel.SetTracerProvider(provider.New())\n\tCheckSetDefaultTextMapPropagator()\n}\n\n// IsUsingDefaultProvider checks and return if currently using default trace provider.\nfunc IsUsingDefaultProvider() bool {\n\t_, ok := otel.GetTracerProvider().(*provider.TracerProvider)\n\treturn ok\n}\n\n// IsTracingInternal returns whether tracing spans of internal components.\nfunc IsTracingInternal() bool {\n\treturn tracingInternal\n}\n\n// MaxContentLogSize returns the max log size for request and response body, especially for HTTP/RPC request.\nfunc MaxContentLogSize() int {\n\treturn tracingMaxContentLogSize\n}\n\n// CommonLabels returns common used attribute labels:\n// ip.intranet, hostname.\nfunc CommonLabels() []attribute.KeyValue {\n\treturn []attribute.KeyValue{\n\t\tattribute.String(tracingCommonKeyIpHostname, hostname),\n\t\tattribute.String(tracingCommonKeyIpIntranet, intranetIpStr),\n\t\tsemconv.HostName(hostname),\n\t}\n}\n\n// CheckSetDefaultTextMapPropagator sets the default TextMapPropagator if it is not set previously.\nfunc CheckSetDefaultTextMapPropagator() {\n\tp := otel.GetTextMapPropagator()\n\tif len(p.Fields()) == 0 {\n\t\totel.SetTextMapPropagator(GetDefaultTextMapPropagator())\n\t}\n}\n\n// GetDefaultTextMapPropagator returns the default propagator for context propagation between peers.\nfunc GetDefaultTextMapPropagator() propagation.TextMapPropagator {\n\treturn defaultTextMapPropagator\n}\n\n// GetTraceID retrieves and returns TraceId from context.\n// It returns an empty string is tracing feature is not activated.\nfunc GetTraceID(ctx context.Context) string {\n\tif ctx == nil {\n\t\treturn \"\"\n\t}\n\ttraceID := trace.SpanContextFromContext(ctx).TraceID()\n\tif traceID.IsValid() {\n\t\treturn traceID.String()\n\t}\n\treturn \"\"\n}\n\n// GetSpanID retrieves and returns SpanId from context.\n// It returns an empty string is tracing feature is not activated.\nfunc GetSpanID(ctx context.Context) string {\n\tif ctx == nil {\n\t\treturn \"\"\n\t}\n\tspanID := trace.SpanContextFromContext(ctx).SpanID()\n\tif spanID.IsValid() {\n\t\treturn spanID.String()\n\t}\n\treturn \"\"\n}\n\n// SetBaggageValue is a convenient function for adding one key-value pair to baggage.\n// Note that it uses attribute.Any to set the key-value pair.\nfunc SetBaggageValue(ctx context.Context, key string, value any) context.Context {\n\treturn NewBaggage(ctx).SetValue(key, value)\n}\n\n// SetBaggageMap is a convenient function for adding map key-value pairs to baggage.\n// Note that it uses attribute.Any to set the key-value pair.\nfunc SetBaggageMap(ctx context.Context, data map[string]any) context.Context {\n\treturn NewBaggage(ctx).SetMap(data)\n}\n\n// GetBaggageMap retrieves and returns the baggage values as map.\nfunc GetBaggageMap(ctx context.Context) *gmap.StrAnyMap {\n\treturn NewBaggage(ctx).GetMap()\n}\n\n// GetBaggageVar retrieves value and returns a *gvar.Var for specified key from baggage.\nfunc GetBaggageVar(ctx context.Context, key string) *gvar.Var {\n\treturn NewBaggage(ctx).GetVar(key)\n}\n\n// WithUUID injects custom trace id with UUID into context to propagate.\nfunc WithUUID(ctx context.Context, uuid string) (context.Context, error) {\n\treturn WithTraceID(ctx, gstr.Replace(uuid, \"-\", \"\"))\n}\n\n// WithTraceID injects custom trace id into context to propagate.\nfunc WithTraceID(ctx context.Context, traceID string) (context.Context, error) {\n\tgeneratedTraceID, err := trace.TraceIDFromHex(traceID)\n\tif err != nil {\n\t\treturn ctx, gerror.WrapCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\terr,\n\t\t\t`invalid custom traceID \"%s\", a traceID string should be composed with [0-f] and fixed length 32`,\n\t\t\ttraceID,\n\t\t)\n\t}\n\tsc := trace.SpanContextFromContext(ctx)\n\tif !sc.HasTraceID() {\n\t\tvar span trace.Span\n\t\tctx, span = NewSpan(ctx, \"gtrace.WithTraceID\")\n\t\tdefer span.End()\n\t\tsc = trace.SpanContextFromContext(ctx)\n\t}\n\tctx = trace.ContextWithRemoteSpanContext(ctx, trace.NewSpanContext(trace.SpanContextConfig{\n\t\tTraceID:    generatedTraceID,\n\t\tSpanID:     sc.SpanID(),\n\t\tTraceFlags: sc.TraceFlags(),\n\t\tTraceState: sc.TraceState(),\n\t\tRemote:     sc.IsRemote(),\n\t}))\n\treturn ctx, nil\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_baggage.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/baggage\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Baggage holds the data through all tracing spans.\ntype Baggage struct {\n\tctx context.Context\n}\n\n// NewBaggage creates and returns a new Baggage object from given tracing context.\nfunc NewBaggage(ctx context.Context) *Baggage {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &Baggage{\n\t\tctx: ctx,\n\t}\n}\n\n// Ctx returns the context that Baggage holds.\nfunc (b *Baggage) Ctx() context.Context {\n\treturn b.ctx\n}\n\n// SetValue is a convenient function for adding one key-value pair to baggage.\n// Note that it uses attribute.Any to set the key-value pair.\nfunc (b *Baggage) SetValue(key string, value any) context.Context {\n\tmember, _ := baggage.NewMember(key, gconv.String(value))\n\tbag, _ := baggage.New(member)\n\tb.ctx = baggage.ContextWithBaggage(b.ctx, bag)\n\treturn b.ctx\n}\n\n// SetMap is a convenient function for adding map key-value pairs to baggage.\n// Note that it uses attribute.Any to set the key-value pair.\nfunc (b *Baggage) SetMap(data map[string]any) context.Context {\n\tmembers := make([]baggage.Member, 0)\n\tfor k, v := range data {\n\t\tmember, _ := baggage.NewMember(k, gconv.String(v))\n\t\tmembers = append(members, member)\n\t}\n\tbag, _ := baggage.New(members...)\n\tb.ctx = baggage.ContextWithBaggage(b.ctx, bag)\n\treturn b.ctx\n}\n\n// GetMap retrieves and returns the baggage values as map.\nfunc (b *Baggage) GetMap() *gmap.StrAnyMap {\n\tm := gmap.NewStrAnyMap()\n\tmembers := baggage.FromContext(b.ctx).Members()\n\tfor i := range members {\n\t\tm.Set(members[i].Key(), members[i].Value())\n\t}\n\treturn m\n}\n\n// GetVar retrieves value and returns a *gvar.Var for specified key from baggage.\nfunc (b *Baggage) GetVar(key string) *gvar.Var {\n\tvalue := baggage.FromContext(b.ctx).Member(key).Value()\n\treturn gvar.New(value)\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_carrier.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Carrier is the storage medium used by a TextMapPropagator.\ntype Carrier map[string]any\n\n// NewCarrier creates and returns a Carrier.\nfunc NewCarrier(data ...map[string]any) Carrier {\n\tif len(data) > 0 && data[0] != nil {\n\t\treturn data[0]\n\t}\n\treturn make(map[string]any)\n}\n\n// Get returns the value associated with the passed key.\nfunc (c Carrier) Get(k string) string {\n\treturn gconv.String(c[k])\n}\n\n// Set stores the key-value pair.\nfunc (c Carrier) Set(k, v string) {\n\tc[k] = v\n}\n\n// Keys lists the keys stored in this carrier.\nfunc (c Carrier) Keys() []string {\n\tkeys := make([]string, 0, len(c))\n\tfor k := range c {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n\n// MustMarshal .returns the JSON encoding of c\nfunc (c Carrier) MustMarshal() []byte {\n\tb, err := json.Marshal(c)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn b\n}\n\n// String converts and returns current Carrier as string.\nfunc (c Carrier) String() string {\n\treturn string(c.MustMarshal())\n}\n\n// UnmarshalJSON implements interface UnmarshalJSON for package json.\nfunc (c Carrier) UnmarshalJSON(b []byte) error {\n\tcarrier := NewCarrier(nil)\n\treturn json.UnmarshalUseNumber(b, carrier)\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_content.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SafeContentForHttp cuts and returns given content by `MaxContentLogSize`.\n// It appends string `...` to the tail of the result if the content size is greater than `MaxContentLogSize`.\nfunc SafeContentForHttp(data []byte, header http.Header) (string, error) {\n\tvar err error\n\tif gzipAccepted(header) {\n\t\tif data, err = gcompress.UnGzip(data); err != nil {\n\t\t\treturn string(data), err\n\t\t}\n\t}\n\n\treturn SafeContent(data), nil\n}\n\n// SafeContent cuts and returns given content by `MaxContentLogSize`.\n// It appends string `...` to the tail of the result if the content size is greater than `MaxContentLogSize`.\nfunc SafeContent(data []byte) string {\n\tcontent := string(data)\n\tif gstr.LenRune(content) > MaxContentLogSize() {\n\t\tcontent = gstr.StrLimitRune(content, MaxContentLogSize(), \"...\")\n\t}\n\n\treturn content\n}\n\n// gzipAccepted returns whether the client will accept gzip-encoded content.\nfunc gzipAccepted(header http.Header) bool {\n\ta := header.Get(\"Content-Encoding\")\n\tparts := strings.Split(a, \",\")\n\tfor _, part := range parts {\n\t\tpart = strings.TrimSpace(part)\n\t\tif part == \"gzip\" || strings.HasPrefix(part, \"gzip;\") {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_span.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\n// Span warps trace.Span for compatibility and extension.\ntype Span struct {\n\ttrace.Span\n}\n\n// NewSpan creates a span using default tracer.\nfunc NewSpan(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, *Span) {\n\tctx, span := NewTracer().Start(ctx, spanName, opts...)\n\treturn ctx, &Span{\n\t\tSpan: span,\n\t}\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_tracer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace\n\nimport (\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\n// Tracer warps trace.Tracer for compatibility and extension.\ntype Tracer struct {\n\ttrace.Tracer\n}\n\n// NewTracer Tracer is a short function for retrieving Tracer.\nfunc NewTracer(name ...string) *Tracer {\n\ttracerName := \"\"\n\tif len(name) > 0 {\n\t\ttracerName = name[0]\n\t}\n\treturn &Tracer{\n\t\tTracer: otel.Tracer(tracerName),\n\t}\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_z_unit_carrier_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nconst (\n\ttraceIDStr = \"4bf92f3577b34da6a3ce929d0e0e4736\"\n\tspanIDStr  = \"00f067aa0ba902b7\"\n)\n\nvar (\n\ttraceID = mustTraceIDFromHex(traceIDStr)\n\tspanID  = mustSpanIDFromHex(spanIDStr)\n)\n\nfunc mustTraceIDFromHex(s string) (t trace.TraceID) {\n\tvar err error\n\tt, err = trace.TraceIDFromHex(s)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn\n}\n\nfunc mustSpanIDFromHex(s string) (t trace.SpanID) {\n\tvar err error\n\tt, err = trace.SpanIDFromHex(s)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn\n}\n\nfunc TestNewCarrier(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := trace.ContextWithRemoteSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{\n\t\t\tTraceID:    traceID,\n\t\t\tSpanID:     spanID,\n\t\t\tTraceFlags: trace.FlagsSampled,\n\t\t}))\n\t\tsc := trace.SpanContextFromContext(ctx)\n\t\tt.Assert(sc.TraceID().String(), traceID.String())\n\t\tt.Assert(sc.SpanID().String(), \"00f067aa0ba902b7\")\n\n\t\tctx, _ = otel.Tracer(\"\").Start(ctx, \"inject\")\n\t\tcarrier1 := gtrace.NewCarrier()\n\t\totel.GetTextMapPropagator().Inject(ctx, carrier1)\n\n\t\tctx = otel.GetTextMapPropagator().Extract(ctx, carrier1)\n\t\tgotSc := trace.SpanContextFromContext(ctx)\n\t\tt.Assert(gotSc.TraceID().String(), traceID.String())\n\t\t// New span is created internally, so the SpanID is different.\n\t})\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_z_unit_feature_http_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Client_Server_Tracing(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := 8888\n\t\ts := g.Server(p)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\tctx := r.Context()\n\t\t\tg.Log().Print(ctx, \"GetTraceID:\", gtrace.GetTraceID(ctx))\n\t\t\tr.Response.Write(gtrace.GetTraceID(ctx))\n\t\t})\n\t\ts.SetPort(p)\n\t\ts.SetDumpRouterMap(false)\n\t\tt.AssertNil(s.Start())\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tctx := gctx.New()\n\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", p)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tt.Assert(gtrace.IsUsingDefaultProvider(), true)\n\t\tt.Assert(client.GetContent(ctx, \"/\"), gtrace.GetTraceID(ctx))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), gctx.CtxId(ctx))\n\t})\n}\n\nfunc Test_WithTraceID(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp := 8889\n\t\ts := g.Server(p)\n\t\ts.BindHandler(\"/\", func(r *ghttp.Request) {\n\t\t\tctx := r.Context()\n\t\t\tr.Response.Write(gtrace.GetTraceID(ctx))\n\t\t})\n\t\ts.SetPort(p)\n\t\ts.SetDumpRouterMap(false)\n\t\tt.AssertNil(s.Start())\n\t\tdefer s.Shutdown()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tctx, err := gtrace.WithTraceID(context.TODO(), traceID.String())\n\t\tt.AssertNil(err)\n\n\t\tprefix := fmt.Sprintf(\"http://127.0.0.1:%d\", p)\n\t\tclient := g.Client()\n\t\tclient.SetPrefix(prefix)\n\t\tt.Assert(gtrace.IsUsingDefaultProvider(), true)\n\t\tt.Assert(client.GetContent(ctx, \"/\"), gtrace.GetTraceID(ctx))\n\t\tt.Assert(client.GetContent(ctx, \"/\"), traceIDStr)\n\t})\n}\n"
  },
  {
    "path": "net/gtrace/gtrace_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtrace_test\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc TestWithTraceID(t *testing.T) {\n\tvar (\n\t\tctx  = context.Background()\n\t\tuuid = `a323f910-f690-11ec-963d-79c0b7fcf119`\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnewCtx, err := gtrace.WithTraceID(ctx, uuid)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(newCtx, ctx)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar traceId = gstr.Replace(uuid, \"-\", \"\")\n\t\tnewCtx, err := gtrace.WithTraceID(ctx, traceId)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(newCtx, ctx)\n\t\tt.Assert(gtrace.GetTraceID(ctx), \"\")\n\t\tt.Assert(gtrace.GetTraceID(newCtx), traceId)\n\t})\n}\n\nfunc TestWithUUID(t *testing.T) {\n\tvar (\n\t\tctx  = context.Background()\n\t\tuuid = `a323f910-f690-11ec-963d-79c0b7fcf119`\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnewCtx, err := gtrace.WithTraceID(ctx, uuid)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(newCtx, ctx)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnewCtx, err := gtrace.WithUUID(ctx, uuid)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(newCtx, ctx)\n\t\tt.Assert(gtrace.GetTraceID(ctx), \"\")\n\t\tt.Assert(gtrace.GetTraceID(newCtx), gstr.Replace(uuid, \"-\", \"\"))\n\t})\n}\n\nfunc TestSafeContent(t *testing.T) {\n\tvar (\n\t\tdefText    = \"中\"\n\t\tshortData  = strings.Repeat(defText, gtrace.MaxContentLogSize()-1)\n\t\tstandData  = strings.Repeat(defText, gtrace.MaxContentLogSize())\n\t\tlongData   = strings.Repeat(defText, gtrace.MaxContentLogSize()+1)\n\t\theader     = http.Header{}\n\t\tgzipHeader = http.Header{\n\t\t\t\"Content-Encoding\": []string{\"gzip\"},\n\t\t}\n\t)\n\n\t// safe content\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tt1, err := gtrace.SafeContentForHttp([]byte(shortData), header)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t1, shortData)\n\t\tt.Assert(gtrace.SafeContent([]byte(shortData)), shortData)\n\n\t\tt2, err := gtrace.SafeContentForHttp([]byte(standData), header)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t2, standData)\n\t\tt.Assert(gtrace.SafeContent([]byte(standData)), standData)\n\n\t\tt3, err := gtrace.SafeContentForHttp([]byte(longData), header)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t3, standData+\"...\")\n\t\tt.Assert(gtrace.SafeContent([]byte(longData)), standData+\"...\")\n\t})\n\n\t// compress content\n\tvar (\n\t\tcompressShortData, _ = gcompress.Gzip([]byte(shortData))\n\t\tcompressStandData, _ = gcompress.Gzip([]byte(standData))\n\t\tcompressLongData, _  = gcompress.Gzip([]byte(longData))\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tt1, err := gtrace.SafeContentForHttp(compressShortData, gzipHeader)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t1, shortData)\n\n\t\tt2, err := gtrace.SafeContentForHttp(compressStandData, gzipHeader)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t2, standData)\n\n\t\tt3, err := gtrace.SafeContentForHttp(compressLongData, gzipHeader)\n\t\tt.AssertNil(err)\n\t\tt.Assert(t3, standData+\"...\")\n\t})\n}\n"
  },
  {
    "path": "net/gtrace/internal/provider/provider.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage provider\n\nimport (\n\tsdkTrace \"go.opentelemetry.io/otel/sdk/trace\"\n)\n\n// TracerProvider is a wrapper around sdkTrace.TracerProvider.\ntype TracerProvider struct {\n\t*sdkTrace.TracerProvider\n}\n\n// New returns a new and configured TracerProvider, which has no SpanProcessor.\n//\n// In default the returned TracerProvider is configured with:\n// - a ParentBased(AlwaysSample) Sampler;\n// - a unix nano timestamp and random umber based IDGenerator;\n// - the resource.Default() Resource;\n// - the default SpanLimits.\n//\n// The passed opts are used to override these default values and configure the\n// returned TracerProvider appropriately.\nfunc New() *TracerProvider {\n\treturn &TracerProvider{\n\t\tTracerProvider: sdkTrace.NewTracerProvider(\n\t\t\tsdkTrace.WithIDGenerator(NewIDGenerator()),\n\t\t),\n\t}\n}\n"
  },
  {
    "path": "net/gtrace/internal/provider/provider_idgenerator.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage provider\n\nimport (\n\t\"context\"\n\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/internal/tracing\"\n)\n\n// IDGenerator is a trace ID generator.\ntype IDGenerator struct{}\n\n// NewIDGenerator returns a new IDGenerator.\nfunc NewIDGenerator() *IDGenerator {\n\treturn &IDGenerator{}\n}\n\n// NewIDs creates and returns a new trace and span ID.\nfunc (id *IDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) {\n\treturn tracing.NewIDs()\n}\n\n// NewSpanID returns an ID for a new span in the trace with traceID.\nfunc (id *IDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) {\n\treturn tracing.NewSpanID()\n}\n"
  },
  {
    "path": "net/gudp/gudp.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gudp provides UDP server and client implementations.\npackage gudp\n"
  },
  {
    "path": "net/gudp/gudp_conn.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// localConn provides common operations for udp connection.\ntype localConn struct {\n\t*net.UDPConn           // Underlying UDP connection.\n\tdeadlineRecv time.Time // Timeout point for reading data.\n\tdeadlineSend time.Time // Timeout point for writing data.\n}\n\nconst (\n\tdefaultRetryInterval  = 100 * time.Millisecond // Retry interval.\n\tdefaultReadBufferSize = 1024                   // (Byte)Buffer size.\n)\n\n// Retry holds the retry options.\n// TODO replace with standalone retry package.\ntype Retry struct {\n\tCount    int           // Max retry count.\n\tInterval time.Duration // Retry interval.\n}\n\n// Recv receives and returns data from remote address.\n// The parameter `buffer` is used for customizing the receiving buffer size.\n// If `buffer` <= 0, it uses the default buffer size, which is 1024 byte.\n//\n// There's package border in UDP protocol, we can receive a complete package if specified\n// buffer size is big enough. VERY NOTE that we should receive the complete package in once\n// or else the leftover package data would be dropped.\nfunc (c *localConn) Recv(buffer int, retry ...Retry) ([]byte, *net.UDPAddr, error) {\n\tvar (\n\t\terr        error        // Reading error\n\t\tsize       int          // Reading size\n\t\tdata       []byte       // Buffer object\n\t\tremoteAddr *net.UDPAddr // Current remote address for reading\n\t)\n\tif buffer > 0 {\n\t\tdata = make([]byte, buffer)\n\t} else {\n\t\tdata = make([]byte, defaultReadBufferSize)\n\t}\n\tfor {\n\t\tsize, remoteAddr, err = c.ReadFromUDP(data)\n\t\tif err != nil {\n\t\t\t// Connection closed.\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif len(retry) > 0 {\n\t\t\t\t// It fails even it retried.\n\t\t\t\tif retry[0].Count == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tretry[0].Count--\n\t\t\t\tif retry[0].Interval == 0 {\n\t\t\t\t\tretry[0].Interval = defaultRetryInterval\n\t\t\t\t}\n\t\t\t\ttime.Sleep(retry[0].Interval)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\terr = gerror.Wrap(err, `ReadFromUDP failed`)\n\t\t\tbreak\n\t\t}\n\t\tbreak\n\t}\n\treturn data[:size], remoteAddr, err\n}\n\n// SetDeadline sets the read and write deadlines associated with the connection.\nfunc (c *localConn) SetDeadline(t time.Time) (err error) {\n\tif err = c.UDPConn.SetDeadline(t); err == nil {\n\t\tc.deadlineRecv = t\n\t\tc.deadlineSend = t\n\t} else {\n\t\terr = gerror.Wrapf(err, `SetDeadline for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n\n// SetDeadlineRecv sets the read deadline associated with the connection.\nfunc (c *localConn) SetDeadlineRecv(t time.Time) (err error) {\n\tif err = c.SetReadDeadline(t); err == nil {\n\t\tc.deadlineRecv = t\n\t} else {\n\t\terr = gerror.Wrapf(err, `SetDeadlineRecv for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n\n// SetDeadlineSend sets the deadline of sending for current connection.\nfunc (c *localConn) SetDeadlineSend(t time.Time) (err error) {\n\tif err = c.SetWriteDeadline(t); err == nil {\n\t\tc.deadlineSend = t\n\t} else {\n\t\terr = gerror.Wrapf(err, `SetDeadlineSend for connection failed with \"%s\"`, t)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "net/gudp/gudp_conn_client_conn.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp\n\nimport (\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// ClientConn holds the client side connection.\ntype ClientConn struct {\n\t*localConn\n}\n\n// NewClientConn creates UDP connection to `remoteAddress`.\n// The optional parameter `localAddress` specifies the local address for connection.\nfunc NewClientConn(remoteAddress string, localAddress ...string) (*ClientConn, error) {\n\tudpConn, err := NewNetConn(remoteAddress, localAddress...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ClientConn{\n\t\tlocalConn: &localConn{\n\t\t\tUDPConn: udpConn,\n\t\t},\n\t}, nil\n}\n\n// Send writes data to remote address.\nfunc (c *ClientConn) Send(data []byte, retry ...Retry) (err error) {\n\tfor {\n\t\t_, err = c.Write(data)\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\t// Connection closed.\n\t\tif err == io.EOF {\n\t\t\treturn err\n\t\t}\n\t\t// Still failed even after retrying.\n\t\tif len(retry) == 0 || retry[0].Count == 0 {\n\t\t\treturn gerror.Wrap(err, `Write data failed`)\n\t\t}\n\t\tif len(retry) > 0 {\n\t\t\tretry[0].Count--\n\t\t\tif retry[0].Interval == 0 {\n\t\t\t\tretry[0].Interval = defaultRetryInterval\n\t\t\t}\n\t\t\ttime.Sleep(retry[0].Interval)\n\t\t\tcontinue\n\t\t}\n\t\treturn err\n\t}\n}\n\n// SendRecv writes data to connection and blocks reading response.\nfunc (c *ClientConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {\n\tif err := c.Send(data, retry...); err != nil {\n\t\treturn nil, err\n\t}\n\tresult, _, err := c.Recv(receive, retry...)\n\treturn result, err\n}\n"
  },
  {
    "path": "net/gudp/gudp_conn_server_conn.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// ServerConn holds the server side connection.\ntype ServerConn struct {\n\t*localConn\n}\n\n// NewServerConn creates an udp connection that listens to `localAddress`.\nfunc NewServerConn(listenedConn *net.UDPConn) *ServerConn {\n\treturn &ServerConn{\n\t\tlocalConn: &localConn{\n\t\t\tUDPConn: listenedConn,\n\t\t},\n\t}\n}\n\n// Send writes data to remote address.\nfunc (c *ServerConn) Send(data []byte, remoteAddr *net.UDPAddr, retry ...Retry) (err error) {\n\tfor {\n\t\t_, err = c.WriteToUDP(data, remoteAddr)\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\t// Connection closed.\n\t\tif err == io.EOF {\n\t\t\treturn err\n\t\t}\n\t\t// Still failed even after retrying.\n\t\tif len(retry) == 0 || retry[0].Count == 0 {\n\t\t\treturn gerror.Wrap(err, `Write data failed`)\n\t\t}\n\t\tif len(retry) > 0 {\n\t\t\tretry[0].Count--\n\t\t\tif retry[0].Interval == 0 {\n\t\t\t\tretry[0].Interval = defaultRetryInterval\n\t\t\t}\n\t\t\ttime.Sleep(retry[0].Interval)\n\t\t\tcontinue\n\t\t}\n\t\treturn err\n\t}\n}\n"
  },
  {
    "path": "net/gudp/gudp_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp\n\nimport (\n\t\"net\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// NewNetConn creates and returns a *net.UDPConn with given addresses.\nfunc NewNetConn(remoteAddress string, localAddress ...string) (*net.UDPConn, error) {\n\tvar (\n\t\terr        error\n\t\tremoteAddr *net.UDPAddr\n\t\tlocalAddr  *net.UDPAddr\n\t\tnetwork    = `udp`\n\t)\n\tremoteAddr, err = net.ResolveUDPAddr(network, remoteAddress)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.ResolveUDPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\tnetwork, remoteAddress,\n\t\t)\n\t}\n\tif len(localAddress) > 0 {\n\t\tlocalAddr, err = net.ResolveUDPAddr(network, localAddress[0])\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`net.ResolveUDPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\t\tnetwork, localAddress[0],\n\t\t\t)\n\t\t}\n\t}\n\tconn, err := net.DialUDP(network, localAddr, remoteAddr)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.DialUDP failed for network \"%s\", local \"%s\", remote \"%s\"`,\n\t\t\tnetwork, localAddr.String(), remoteAddr.String(),\n\t\t)\n\t}\n\treturn conn, nil\n}\n\n// Send writes data to `address` using UDP connection and then closes the connection.\n// Note that it is used for short connection usage.\nfunc Send(address string, data []byte, retry ...Retry) error {\n\tconn, err := NewClientConn(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\treturn conn.Send(data, retry...)\n}\n\n// SendRecv writes data to `address` using UDP connection, reads response and then closes the connection.\n// Note that it is used for short connection usage.\nfunc SendRecv(address string, data []byte, receive int, retry ...Retry) ([]byte, error) {\n\tconn, err := NewClientConn(address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\treturn conn.SendRecv(data, receive, retry...)\n}\n\n// MustGetFreePort performs as GetFreePort, but it panics if any error occurs.\n//\n// Deprecated: the port might be used soon after they were returned, please use `:0` as the listening\n// address which asks system to assign a free port instead.\nfunc MustGetFreePort() (port int) {\n\tport, err := GetFreePort()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn port\n}\n\n// GetFreePort retrieves and returns a port that is free.\n//\n// Deprecated: the port might be used soon after they were returned, please use `:0` as the listening\n// address which asks system to assign a free port instead.\nfunc GetFreePort() (port int, err error) {\n\tvar (\n\t\tnetwork = `udp`\n\t\taddress = `:0`\n\t)\n\tresolvedAddr, err := net.ResolveUDPAddr(network, address)\n\tif err != nil {\n\t\treturn 0, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.ResolveUDPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\tnetwork, address,\n\t\t)\n\t}\n\tl, err := net.ListenUDP(network, resolvedAddr)\n\tif err != nil {\n\t\treturn 0, gerror.Wrapf(\n\t\t\terr,\n\t\t\t`net.ListenUDP failed for network \"%s\", address \"%s\"`,\n\t\t\tnetwork, resolvedAddr.String(),\n\t\t)\n\t}\n\tport = l.LocalAddr().(*net.UDPAddr).Port\n\t_ = l.Close()\n\treturn\n}\n\n// GetFreePorts retrieves and returns specified number of ports that are free.\n//\n// Deprecated: the ports might be used soon after they were returned, please use `:0` as the listening\n// address which asks system to assign a free port instead.\nfunc GetFreePorts(count int) (ports []int, err error) {\n\tvar (\n\t\tnetwork = `udp`\n\t\taddress = `:0`\n\t)\n\tfor i := 0; i < count; i++ {\n\t\tresolvedAddr, err := net.ResolveUDPAddr(network, address)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`net.ResolveUDPAddr failed for network \"%s\", address \"%s\"`,\n\t\t\t\tnetwork, address,\n\t\t\t)\n\t\t}\n\t\tl, err := net.ListenUDP(network, resolvedAddr)\n\t\tif err != nil {\n\t\t\treturn nil, gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`net.ListenUDP failed for network \"%s\", address \"%s\"`,\n\t\t\t\tnetwork, resolvedAddr.String(),\n\t\t\t)\n\t\t}\n\t\tports = append(ports, l.LocalAddr().(*net.UDPAddr).Port)\n\t\t_ = l.Close()\n\t}\n\treturn ports, nil\n}\n"
  },
  {
    "path": "net/gudp/gudp_server.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\t// FreePortAddress marks the server listens using random free port.\n\tFreePortAddress = \":0\"\n)\n\nconst (\n\tdefaultServer = \"default\"\n)\n\n// Server is the UDP server.\ntype Server struct {\n\t// Used for Server.listen concurrent safety.\n\t// The golang test with data race checks this.\n\tmu sync.Mutex\n\n\t// UDP server connection object.\n\tconn *ServerConn\n\n\t// UDP server listening address.\n\taddress string\n\n\t// Handler for UDP connection.\n\thandler ServerHandler\n}\n\n// ServerHandler handles all server connections.\ntype ServerHandler func(conn *ServerConn)\n\nvar (\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *Server) bool { return v == nil }\n\t// serverMapping is used for instance name to its UDP server mappings.\n\tserverMapping = gmap.NewKVMapWithChecker[string, *Server](checker, true)\n)\n\n// GetServer creates and returns an udp server instance with given name.\nfunc GetServer(name ...any) *Server {\n\tserverName := defaultServer\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tserverName = gconv.String(name[0])\n\t}\n\treturn serverMapping.GetOrSetFuncLock(serverName, func() *Server {\n\t\treturn NewServer(\"\", nil)\n\t})\n}\n\n// NewServer creates and returns an udp server.\n// The optional parameter `name` is used to specify its name, which can be used for\n// GetServer function to retrieve its instance.\nfunc NewServer(address string, handler ServerHandler, name ...string) *Server {\n\ts := &Server{\n\t\taddress: address,\n\t\thandler: handler,\n\t}\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tserverMapping.Set(name[0], s)\n\t}\n\treturn s\n}\n\n// SetAddress sets the server address for UDP server.\nfunc (s *Server) SetAddress(address string) {\n\ts.address = address\n}\n\n// SetHandler sets the connection handler for UDP server.\nfunc (s *Server) SetHandler(handler ServerHandler) {\n\ts.handler = handler\n}\n\n// Close closes the connection.\n// It will make server shutdowns immediately.\nfunc (s *Server) Close() (err error) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\terr = s.conn.Close()\n\tif err != nil {\n\t\terr = gerror.Wrap(err, \"connection failed\")\n\t}\n\treturn\n}\n\n// Run starts listening UDP connection.\nfunc (s *Server) Run() error {\n\tif s.handler == nil {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeMissingConfiguration,\n\t\t\t\"start running failed: socket handler not defined\",\n\t\t)\n\t}\n\taddr, err := net.ResolveUDPAddr(\"udp\", s.address)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `net.ResolveUDPAddr failed for address \"%s\"`, s.address)\n\t\treturn err\n\t}\n\tlistenedConn, err := net.ListenUDP(\"udp\", addr)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `net.ListenUDP failed for address \"%s\"`, s.address)\n\t\treturn err\n\t}\n\ts.mu.Lock()\n\ts.conn = NewServerConn(listenedConn)\n\ts.mu.Unlock()\n\ts.handler(s.conn)\n\treturn nil\n}\n\n// GetListenedAddress retrieves and returns the address string which are listened by current server.\nfunc (s *Server) GetListenedAddress() string {\n\tif !gstr.Contains(s.address, FreePortAddress) {\n\t\treturn s.address\n\t}\n\tvar (\n\t\taddress      = s.address\n\t\tlistenedPort = s.GetListenedPort()\n\t)\n\taddress = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort))\n\treturn address\n}\n\n// GetListenedPort retrieves and returns one port which is listened to by current server.\nfunc (s *Server) GetListenedPort() int {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\tif ln := s.conn; ln != nil {\n\t\treturn ln.LocalAddr().(*net.UDPAddr).Port\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "net/gudp/gudp_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/net/gudp\"\n)\n\nfunc ExampleGetFreePort() {\n\tfmt.Println(gudp.GetFreePort())\n\n\t// May Output:\n\t// 57429 <nil>\n}\n\nfunc ExampleGetFreePorts() {\n\tfmt.Println(gudp.GetFreePorts(2))\n\n\t// May Output:\n\t// [57743 57744] <nil>\n}\n"
  },
  {
    "path": "net/gudp/gudp_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gudp_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/net/gudp\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\tsimpleTimeout = time.Millisecond * 100\n\tsendData      = []byte(\"hello\")\n)\n\nfunc startUDPServer(addr string) *gudp.Server {\n\ts := gudp.NewServer(addr, func(conn *gudp.ServerConn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, remote, err := conn.Recv(-1)\n\t\t\tif err != nil {\n\t\t\t\tif err != io.EOF {\n\t\t\t\t\tglog.Error(context.TODO(), err)\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif err = conn.Send(data, remote); err != nil {\n\t\t\t\tglog.Error(context.TODO(), err)\n\t\t\t}\n\t\t}\n\t})\n\tgo s.Run()\n\ttime.Sleep(simpleTimeout)\n\treturn s\n}\n\nfunc Test_Basic(t *testing.T) {\n\tvar ctx = context.TODO()\n\ts := gudp.NewServer(gudp.FreePortAddress, func(conn *gudp.ServerConn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, remote, err := conn.Recv(-1)\n\t\t\tif len(data) > 0 {\n\t\t\t\tif err = conn.Send(append([]byte(\"> \"), data...), remote); err != nil {\n\t\t\t\t\tglog.Error(ctx, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// gudp.Conn.Send\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tconn, err := gudp.NewClientConn(s.GetListenedAddress())\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(conn.Send([]byte(gconv.String(i))), nil)\n\t\t\tt.AssertNE(conn.RemoteAddr(), nil)\n\t\t\tresult, _, err := conn.Recv(-1)\n\t\t\tt.AssertNil(err)\n\t\t\tt.AssertNE(conn.RemoteAddr(), nil)\n\t\t\tt.Assert(string(result), fmt.Sprintf(`> %d`, i))\n\t\t\tconn.Close()\n\t\t}\n\t})\n\t// gudp.Conn.SendRecv\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tconn, err := gudp.NewClientConn(s.GetListenedAddress())\n\t\t\tt.AssertNil(err)\n\t\t\tresult, err := conn.SendRecv([]byte(gconv.String(i)), -1)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(string(result), fmt.Sprintf(`> %d`, i))\n\t\t\tconn.Close()\n\t\t}\n\t})\n\n\t// gudp.Send\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\terr := gudp.Send(s.GetListenedAddress(), []byte(gconv.String(i)))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n}\n\n// If the read buffer size is less than the sent package size,\n// the rest data would be dropped.\nfunc Test_Buffer(t *testing.T) {\n\tvar ctx = context.TODO()\n\ts := gudp.NewServer(gudp.FreePortAddress, func(conn *gudp.ServerConn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, remote, err := conn.Recv(-1)\n\t\t\tif len(data) > 0 {\n\t\t\t\tif err = conn.Send(data, remote); err != nil {\n\t\t\t\t\tglog.Error(ctx, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t})\n\tgo s.Run()\n\tdefer s.Close()\n\ttime.Sleep(100 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gudp.SendRecv(s.GetListenedAddress(), []byte(\"123\"), -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(result), \"123\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult, err := gudp.SendRecv(s.GetListenedAddress(), []byte(\"456\"), -1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(result), \"456\")\n\t})\n}\n\nfunc Test_NewConn(t *testing.T) {\n\ts := startUDPServer(gudp.FreePortAddress)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gudp.NewClientConn(s.GetListenedAddress(), fmt.Sprintf(\"127.0.0.1:%d\", gudp.MustGetFreePort()))\n\t\tt.AssertNil(err)\n\t\tconn.SetDeadline(time.Now().Add(time.Second))\n\t\tt.Assert(conn.Send(sendData), nil)\n\t\tconn.Close()\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gudp.NewClientConn(s.GetListenedAddress(), fmt.Sprintf(\"127.0.0.1:%d\", 99999))\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconn, err := gudp.NewClientConn(fmt.Sprintf(\"127.0.0.1:%d\", 99999))\n\t\tt.AssertNil(conn)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_GetFreePorts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tports, err := gudp.GetFreePorts(2)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(len(ports), 2)\n\t})\n}\n\nfunc Test_Server(t *testing.T) {\n\tvar ctx = context.TODO()\n\tgudp.NewServer(gudp.FreePortAddress, func(conn *gudp.ServerConn) {\n\t\tdefer conn.Close()\n\t\tfor {\n\t\t\tdata, remote, err := conn.Recv(-1)\n\t\t\tif len(data) > 0 {\n\t\t\t\tif err = conn.Send(data, remote); err != nil {\n\t\t\t\t\tglog.Error(ctx, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}, \"GoFrameUDPServer\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tserver := gudp.GetServer(\"GoFrameUDPServer\")\n\t\tt.AssertNE(server, nil)\n\t\tserver = gudp.GetServer(\"TestUDPServer\")\n\t\tt.AssertNE(server, nil)\n\t\tserver.SetAddress(\"127.0.0.1:8888\")\n\t\tserver.SetHandler(func(conn *gudp.ServerConn) {\n\t\t\t_ = conn.Send([]byte(\"OtherHandle\"), nil)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "os/gbuild/gbuild.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gbuild manages the build-in variables from \"gf build\".\npackage gbuild\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// BuildInfo maintains the built info of the current binary.\ntype BuildInfo struct {\n\tGoFrame string         // Built used GoFrame version.\n\tGolang  string         // Built the used Golang version.\n\tGit     string         // Built used git repo. commit id and datetime.\n\tTime    string         // Built datetime.\n\tVersion string         // Built version.\n\tData    map[string]any // All custom built data key-value pairs.\n}\n\nconst (\n\tgfVersion    = `gfVersion`\n\tgoVersion    = `goVersion`\n\tBuiltGit     = `builtGit`\n\tBuiltTime    = `builtTime`\n\tBuiltVersion = `builtVersion`\n)\n\nvar (\n\tbuiltInVarStr = \"\"               // Raw variable base64 string, which is injected by go build flags.\n\tbuiltInVarMap = map[string]any{} // Binary custom variable map decoded.\n)\n\nfunc init() {\n\t// The `builtInVarStr` is injected by go build flags.\n\tif builtInVarStr != \"\" {\n\t\terr := json.UnmarshalUseNumber(gbase64.MustDecodeString(builtInVarStr), &builtInVarMap)\n\t\tif err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t\tbuiltInVarMap[gfVersion] = gf.VERSION\n\t\tbuiltInVarMap[goVersion] = runtime.Version()\n\t\tintlog.Printf(context.TODO(), \"build variables: %+v\", builtInVarMap)\n\t} else {\n\t\tintlog.Print(context.TODO(), \"no build variables\")\n\t}\n}\n\n// Info returns the basic built information of the binary as map.\n// Note that it should be used with gf-cli tool \"gf build\",\n// which automatically injects necessary information into the binary.\nfunc Info() BuildInfo {\n\treturn BuildInfo{\n\t\tGoFrame: Get(gfVersion).String(),\n\t\tGolang:  Get(goVersion).String(),\n\t\tGit:     Get(BuiltGit).String(),\n\t\tTime:    Get(BuiltTime).String(),\n\t\tVersion: Get(BuiltVersion).String(),\n\t\tData:    Data(),\n\t}\n}\n\n// Get retrieves and returns the build-in binary variable with given name.\nfunc Get(name string, def ...any) *gvar.Var {\n\tif v, ok := builtInVarMap[name]; ok {\n\t\treturn gvar.New(v)\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// Data returns the custom build-in variables as the map.\nfunc Data() map[string]any {\n\treturn builtInVarMap\n}\n"
  },
  {
    "path": "os/gbuild/gbuild_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gbuild_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gbuild\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Info(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gconv.Map(gbuild.Info()), g.Map{\n\t\t\t\"GoFrame\": \"\",\n\t\t\t\"Golang\":  \"\",\n\t\t\t\"Git\":     \"\",\n\t\t\t\"Time\":    \"\",\n\t\t\t\"Version\": \"\",\n\t\t\t\"Data\":    g.Map{},\n\t\t})\n\t})\n}\n\nfunc Test_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gbuild.Get(`none`), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gbuild.Get(`none`, 1), 1)\n\t})\n}\n\nfunc Test_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gbuild.Data(), map[string]any{})\n\t})\n}\n"
  },
  {
    "path": "os/gcache/gcache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcache provides kinds of cache management for process.\n//\n// It provides a concurrent-safe in-memory cache adapter for process in default.\npackage gcache\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// Func is the cache function that calculates and returns the value.\ntype Func = func(ctx context.Context) (value any, err error)\n\n// DurationNoExpire represents the cache key-value pair that never expires.\nconst DurationNoExpire = time.Duration(0)\n\n// defaultCache returns the lazily-initialized default cache instance using sync.OnceValue.\nvar defaultCache = sync.OnceValue(func() *Cache {\n\treturn New()\n})\n\n// Set sets cache with `key`-`value` pair, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc Set(ctx context.Context, key any, value any, duration time.Duration) error {\n\treturn defaultCache().Set(ctx, key, value, duration)\n}\n\n// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc SetMap(ctx context.Context, data map[any]any, duration time.Duration) error {\n\treturn defaultCache().SetMap(ctx, data, duration)\n}\n\n// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`\n// if `key` does not exist in the cache. It returns true the `key` does not exist in the\n// cache, and it sets `value` successfully to the cache, or else it returns false.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc SetIfNotExist(ctx context.Context, key any, value any, duration time.Duration) (bool, error) {\n\treturn defaultCache().SetIfNotExist(ctx, key, value, duration)\n}\n\n// SetIfNotExistFunc sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// The parameter `value` can be type of `func() any`, but it does nothing if its\n// result is nil.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc SetIfNotExistFunc(ctx context.Context, key any, f Func, duration time.Duration) (bool, error) {\n\treturn defaultCache().SetIfNotExistFunc(ctx, key, f, duration)\n}\n\n// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\n//\n// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc SetIfNotExistFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (bool, error) {\n\treturn defaultCache().SetIfNotExistFuncLock(ctx, key, f, duration)\n}\n\n// Get retrieves and returns the associated value of given `key`.\n// It returns nil if it does not exist, or its value is nil, or it's expired.\n// If you would like to check if the `key` exists in the cache, it's better using function Contains.\nfunc Get(ctx context.Context, key any) (*gvar.Var, error) {\n\treturn defaultCache().Get(ctx, key)\n}\n\n// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and\n// returns `value` if `key` does not exist in the cache. The key-value pair expires\n// after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc GetOrSet(ctx context.Context, key any, value any, duration time.Duration) (*gvar.Var, error) {\n\treturn defaultCache().GetOrSet(ctx, key, value, duration)\n}\n\n// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc GetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) (*gvar.Var, error) {\n\treturn defaultCache().GetOrSetFunc(ctx, key, f, duration)\n}\n\n// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\n//\n// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc GetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (*gvar.Var, error) {\n\treturn defaultCache().GetOrSetFuncLock(ctx, key, f, duration)\n}\n\n// Contains checks and returns true if `key` exists in the cache, or else returns false.\nfunc Contains(ctx context.Context, key any) (bool, error) {\n\treturn defaultCache().Contains(ctx, key)\n}\n\n// GetExpire retrieves and returns the expiration of `key` in the cache.\n//\n// Note that,\n// It returns 0 if the `key` does not expire.\n// It returns -1 if the `key` does not exist in the cache.\nfunc GetExpire(ctx context.Context, key any) (time.Duration, error) {\n\treturn defaultCache().GetExpire(ctx, key)\n}\n\n// Remove deletes one or more keys from cache, and returns its value.\n// If multiple keys are given, it returns the value of the last deleted item.\nfunc Remove(ctx context.Context, keys ...any) (value *gvar.Var, err error) {\n\treturn defaultCache().Remove(ctx, keys...)\n}\n\n// Removes deletes `keys` in the cache.\nfunc Removes(ctx context.Context, keys []any) error {\n\treturn defaultCache().Removes(ctx, keys)\n}\n\n// Update updates the value of `key` without changing its expiration and returns the old value.\n// The returned value `exist` is false if the `key` does not exist in the cache.\n//\n// It deletes the `key` if given `value` is nil.\n// It does nothing if `key` does not exist in the cache.\nfunc Update(ctx context.Context, key any, value any) (oldValue *gvar.Var, exist bool, err error) {\n\treturn defaultCache().Update(ctx, key, value)\n}\n\n// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n//\n// It returns -1 and does nothing if the `key` does not exist in the cache.\n// It deletes the `key` if `duration` < 0.\nfunc UpdateExpire(ctx context.Context, key any, duration time.Duration) (oldDuration time.Duration, err error) {\n\treturn defaultCache().UpdateExpire(ctx, key, duration)\n}\n\n// Size returns the number of items in the cache.\nfunc Size(ctx context.Context) (int, error) {\n\treturn defaultCache().Size(ctx)\n}\n\n// Data returns a copy of all key-value pairs in the cache as map type.\n// Note that this function may lead lots of memory usage, you can implement this function\n// if necessary.\nfunc Data(ctx context.Context) (map[any]any, error) {\n\treturn defaultCache().Data(ctx)\n}\n\n// Keys returns all keys in the cache as slice.\nfunc Keys(ctx context.Context) ([]any, error) {\n\treturn defaultCache().Keys(ctx)\n}\n\n// KeyStrings returns all keys in the cache as string slice.\nfunc KeyStrings(ctx context.Context) ([]string, error) {\n\treturn defaultCache().KeyStrings(ctx)\n}\n\n// Values returns all values in the cache as slice.\nfunc Values(ctx context.Context) ([]any, error) {\n\treturn defaultCache().Values(ctx)\n}\n\n// MustGet acts like Get, but it panics if any error occurs.\nfunc MustGet(ctx context.Context, key any) *gvar.Var {\n\treturn defaultCache().MustGet(ctx, key)\n}\n\n// MustGetOrSet acts like GetOrSet, but it panics if any error occurs.\nfunc MustGetOrSet(ctx context.Context, key any, value any, duration time.Duration) *gvar.Var {\n\treturn defaultCache().MustGetOrSet(ctx, key, value, duration)\n}\n\n// MustGetOrSetFunc acts like GetOrSetFunc, but it panics if any error occurs.\nfunc MustGetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) *gvar.Var {\n\treturn defaultCache().MustGetOrSetFunc(ctx, key, f, duration)\n}\n\n// MustGetOrSetFuncLock acts like GetOrSetFuncLock, but it panics if any error occurs.\nfunc MustGetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) *gvar.Var {\n\treturn defaultCache().MustGetOrSetFuncLock(ctx, key, f, duration)\n}\n\n// MustContains acts like Contains, but it panics if any error occurs.\nfunc MustContains(ctx context.Context, key any) bool {\n\treturn defaultCache().MustContains(ctx, key)\n}\n\n// MustGetExpire acts like GetExpire, but it panics if any error occurs.\nfunc MustGetExpire(ctx context.Context, key any) time.Duration {\n\treturn defaultCache().MustGetExpire(ctx, key)\n}\n\n// MustSize acts like Size, but it panics if any error occurs.\nfunc MustSize(ctx context.Context) int {\n\treturn defaultCache().MustSize(ctx)\n}\n\n// MustData acts like Data, but it panics if any error occurs.\nfunc MustData(ctx context.Context) map[any]any {\n\treturn defaultCache().MustData(ctx)\n}\n\n// MustKeys acts like Keys, but it panics if any error occurs.\nfunc MustKeys(ctx context.Context) []any {\n\treturn defaultCache().MustKeys(ctx)\n}\n\n// MustKeyStrings acts like KeyStrings, but it panics if any error occurs.\nfunc MustKeyStrings(ctx context.Context) []string {\n\treturn defaultCache().MustKeyStrings(ctx)\n}\n\n// MustValues acts like Values, but it panics if any error occurs.\nfunc MustValues(ctx context.Context) []any {\n\treturn defaultCache().MustValues(ctx)\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// Adapter is the core adapter for cache features implements.\n//\n// Note that the implementer itself should guarantee the concurrent safety of these functions.\ntype Adapter interface {\n\t// Set sets cache with `key`-`value` pair, which is expired after `duration`.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\n\tSet(ctx context.Context, key any, value any, duration time.Duration) error\n\n\t// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\n\tSetMap(ctx context.Context, data map[any]any, duration time.Duration) error\n\n\t// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`\n\t// if `key` does not exist in the cache. It returns true the `key` does not exist in the\n\t// cache, and it sets `value` successfully to the cache, or else it returns false.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil.\n\tSetIfNotExist(ctx context.Context, key any, value any, duration time.Duration) (ok bool, err error)\n\n\t// SetIfNotExistFunc sets `key` with result of function `f` and returns true\n\t// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n\t//\n\t// The parameter `value` can be type of `func() any`, but it does nothing if its\n\t// result is nil.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil.\n\tSetIfNotExistFunc(ctx context.Context, key any, f Func, duration time.Duration) (ok bool, err error)\n\n\t// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true\n\t// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil.\n\t//\n\t// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within\n\t// writing mutex lock for concurrent safety purpose.\n\tSetIfNotExistFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (ok bool, err error)\n\n\t// Get retrieves and returns the associated value of given `key`.\n\t// It returns nil if it does not exist, or its value is nil, or it's expired.\n\t// If you would like to check if the `key` exists in the cache, it's better using function Contains.\n\tGet(ctx context.Context, key any) (*gvar.Var, error)\n\n\t// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and\n\t// returns `value` if `key` does not exist in the cache. The key-value pair expires\n\t// after `duration`.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n\t// if `value` is a function and the function result is nil.\n\tGetOrSet(ctx context.Context, key any, value any, duration time.Duration) (result *gvar.Var, err error)\n\n\t// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of\n\t// function `f` and returns its result if `key` does not exist in the cache. The key-value\n\t// pair expires after `duration`.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n\t// if `value` is a function and the function result is nil.\n\tGetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) (result *gvar.Var, err error)\n\n\t// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of\n\t// function `f` and returns its result if `key` does not exist in the cache. The key-value\n\t// pair expires after `duration`.\n\t//\n\t// It does not expire if `duration` == 0.\n\t// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n\t// if `value` is a function and the function result is nil.\n\t//\n\t// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within\n\t// writing mutex lock for concurrent safety purpose.\n\tGetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (result *gvar.Var, err error)\n\n\t// Contains checks and returns true if `key` exists in the cache, or else returns false.\n\tContains(ctx context.Context, key any) (bool, error)\n\n\t// Size returns the number of items in the cache.\n\tSize(ctx context.Context) (size int, err error)\n\n\t// Data returns a copy of all key-value pairs in the cache as map type.\n\t// Note that this function may lead lots of memory usage, you can implement this function\n\t// if necessary.\n\tData(ctx context.Context) (data map[any]any, err error)\n\n\t// Keys returns all keys in the cache as slice.\n\tKeys(ctx context.Context) (keys []any, err error)\n\n\t// Values returns all values in the cache as slice.\n\tValues(ctx context.Context) (values []any, err error)\n\n\t// Update updates the value of `key` without changing its expiration and returns the old value.\n\t// The returned value `exist` is false if the `key` does not exist in the cache.\n\t//\n\t// It deletes the `key` if given `value` is nil.\n\t// It does nothing if `key` does not exist in the cache.\n\tUpdate(ctx context.Context, key any, value any) (oldValue *gvar.Var, exist bool, err error)\n\n\t// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n\t//\n\t// It returns -1 and does nothing if the `key` does not exist in the cache.\n\t// It deletes the `key` if `duration` < 0.\n\tUpdateExpire(ctx context.Context, key any, duration time.Duration) (oldDuration time.Duration, err error)\n\n\t// GetExpire retrieves and returns the expiration of `key` in the cache.\n\t//\n\t// Note that,\n\t// It returns 0 if the `key` does not expire.\n\t// It returns -1 if the `key` does not exist in the cache.\n\tGetExpire(ctx context.Context, key any) (time.Duration, error)\n\n\t// Remove deletes one or more keys from cache, and returns its value.\n\t// If multiple keys are given, it returns the value of the last deleted item.\n\tRemove(ctx context.Context, keys ...any) (lastValue *gvar.Var, err error)\n\n\t// Clear clears all data of the cache.\n\t// Note that this function is sensitive and should be carefully used.\n\tClear(ctx context.Context) error\n\n\t// Close closes the cache if necessary.\n\tClose(ctx context.Context) error\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// AdapterMemory is an adapter implements using memory.\ntype AdapterMemory struct {\n\tdata        *memoryData                       // data is the underlying cache data which is stored in a hash table.\n\texpireTimes *memoryExpireTimes                // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.\n\texpireSets  *memoryExpireSets                 // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting.\n\tlru         *memoryLru                        // lru is the LRU manager, which is enabled when attribute cap > 0.\n\teventList   *glist.TList[*adapterMemoryEvent] // eventList is the asynchronous event list for internal data synchronization.\n\tclosed      *gtype.Bool                       // closed controls the cache closed or not.\n}\n\nvar _ Adapter = (*AdapterMemory)(nil)\n\n// Internal event item.\ntype adapterMemoryEvent struct {\n\tk any   // Key.\n\te int64 // Expire time in milliseconds.\n}\n\nconst (\n\t// defaultMaxExpire is the default expire time for no expiring items.\n\t// It equals to math.MaxInt64/1000000.\n\tdefaultMaxExpire = 9223372036854\n)\n\n// NewAdapterMemory creates and returns a new adapter_memory cache object.\nfunc NewAdapterMemory() *AdapterMemory {\n\treturn doNewAdapterMemory()\n}\n\n// NewAdapterMemoryLru creates and returns a new adapter_memory cache object with LRU.\nfunc NewAdapterMemoryLru(cap int) *AdapterMemory {\n\tc := doNewAdapterMemory()\n\tc.lru = newMemoryLru(cap)\n\treturn c\n}\n\n// doNewAdapterMemory creates and returns a new adapter_memory cache object.\nfunc doNewAdapterMemory() *AdapterMemory {\n\tc := &AdapterMemory{\n\t\tdata:        newMemoryData(),\n\t\texpireTimes: newMemoryExpireTimes(),\n\t\texpireSets:  newMemoryExpireSets(),\n\t\teventList:   glist.NewT[*adapterMemoryEvent](true),\n\t\tclosed:      gtype.NewBool(),\n\t}\n\t// Here may be a \"timer leak\" if adapter is manually changed from adapter_memory adapter.\n\t// Do not worry about this, as adapter is less changed, and it does nothing if it's not used.\n\tgtimer.AddSingleton(context.Background(), time.Second, c.syncEventAndClearExpired)\n\treturn c\n}\n\n// Set sets cache with `key`-`value` pair, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterMemory) Set(ctx context.Context, key any, value any, duration time.Duration) error {\n\tdefer c.handleLruKey(ctx, key)\n\texpireTime := c.getInternalExpire(duration)\n\tc.data.Set(key, memoryDataItem{\n\t\tv: value,\n\t\te: expireTime,\n\t})\n\tc.eventList.PushBack(&adapterMemoryEvent{\n\t\tk: key,\n\t\te: expireTime,\n\t})\n\treturn nil\n}\n\n// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterMemory) SetMap(ctx context.Context, data map[any]any, duration time.Duration) error {\n\tvar (\n\t\texpireTime = c.getInternalExpire(duration)\n\t\terr        = c.data.SetMap(data, expireTime)\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor k := range data {\n\t\tc.eventList.PushBack(&adapterMemoryEvent{\n\t\t\tk: k,\n\t\t\te: expireTime,\n\t\t})\n\t}\n\tif c.lru != nil {\n\t\tfor key := range data {\n\t\t\tc.handleLruKey(ctx, key)\n\t\t}\n\t}\n\treturn nil\n}\n\n// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`\n// if `key` does not exist in the cache. It returns true the `key` does not exist in the\n// cache, and it sets `value` successfully to the cache, or else it returns false.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterMemory) SetIfNotExist(ctx context.Context, key any, value any, duration time.Duration) (bool, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tisContained, err := c.Contains(ctx, key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif !isContained {\n\t\tif _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n\n// SetIfNotExistFunc sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// The parameter `value` can be type of `func() any`, but it does nothing if its\n// result is nil.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterMemory) SetIfNotExistFunc(ctx context.Context, key any, f Func, duration time.Duration) (bool, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tisContained, err := c.Contains(ctx, key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif !isContained {\n\t\tvalue, err := f(ctx)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n\n// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\n//\n// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc (c *AdapterMemory) SetIfNotExistFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (bool, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tisContained, err := c.Contains(ctx, key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif !isContained {\n\t\tif _, err = c.doSetWithLockCheck(ctx, key, f, duration); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n\n// Get retrieves and returns the associated value of given `key`.\n// It returns nil if it does not exist, or its value is nil, or it's expired.\n// If you would like to check if the `key` exists in the cache, it's better using function Contains.\nfunc (c *AdapterMemory) Get(ctx context.Context, key any) (*gvar.Var, error) {\n\titem, ok := c.data.Get(key)\n\tif ok && !item.IsExpired() {\n\t\tc.handleLruKey(ctx, key)\n\t\treturn gvar.New(item.v), nil\n\t}\n\treturn nil, nil\n}\n\n// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and\n// returns `value` if `key` does not exist in the cache. The key-value pair expires\n// after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc (c *AdapterMemory) GetOrSet(ctx context.Context, key any, value any, duration time.Duration) (*gvar.Var, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v == nil {\n\t\treturn c.doSetWithLockCheck(ctx, key, value, duration)\n\t}\n\treturn v, nil\n}\n\n// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc (c *AdapterMemory) GetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) (*gvar.Var, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v == nil {\n\t\tvalue, err := f(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif value == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn c.doSetWithLockCheck(ctx, key, value, duration)\n\t}\n\treturn v, nil\n}\n\n// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\n//\n// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc (c *AdapterMemory) GetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (*gvar.Var, error) {\n\tdefer c.handleLruKey(ctx, key)\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v == nil {\n\t\treturn c.doSetWithLockCheck(ctx, key, f, duration)\n\t}\n\treturn v, nil\n}\n\n// Contains checks and returns true if `key` exists in the cache, or else returns false.\nfunc (c *AdapterMemory) Contains(ctx context.Context, key any) (bool, error) {\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn v != nil, nil\n}\n\n// GetExpire retrieves and returns the expiration of `key` in the cache.\n//\n// Note that,\n// It returns 0 if the `key` does not expire.\n// It returns -1 if the `key` does not exist in the cache.\nfunc (c *AdapterMemory) GetExpire(ctx context.Context, key any) (time.Duration, error) {\n\tif item, ok := c.data.Get(key); ok {\n\t\tc.handleLruKey(ctx, key)\n\t\treturn time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil\n\t}\n\treturn -1, nil\n}\n\n// Remove deletes one or more keys from cache, and returns its value.\n// If multiple keys are given, it returns the value of the last deleted item.\nfunc (c *AdapterMemory) Remove(ctx context.Context, keys ...any) (*gvar.Var, error) {\n\tdefer c.lru.Remove(keys...)\n\treturn c.doRemove(ctx, keys...)\n}\n\nfunc (c *AdapterMemory) doRemove(_ context.Context, keys ...any) (*gvar.Var, error) {\n\tvar removedKeys []any\n\tremovedKeys, value, err := c.data.Remove(keys...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, key := range removedKeys {\n\t\tc.eventList.PushBack(&adapterMemoryEvent{\n\t\t\tk: key,\n\t\t\te: gtime.TimestampMilli() - 1000,\n\t\t})\n\t}\n\treturn gvar.New(value), nil\n}\n\n// Update updates the value of `key` without changing its expiration and returns the old value.\n// The returned value `exist` is false if the `key` does not exist in the cache.\n//\n// It deletes the `key` if given `value` is nil.\n// It does nothing if `key` does not exist in the cache.\nfunc (c *AdapterMemory) Update(ctx context.Context, key any, value any) (oldValue *gvar.Var, exist bool, err error) {\n\tv, exist, err := c.data.Update(key, value)\n\tif exist {\n\t\tc.handleLruKey(ctx, key)\n\t}\n\treturn gvar.New(v), exist, err\n}\n\n// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n//\n// It returns -1 and does nothing if the `key` does not exist in the cache.\n// It deletes the `key` if `duration` < 0.\nfunc (c *AdapterMemory) UpdateExpire(ctx context.Context, key any, duration time.Duration) (oldDuration time.Duration, err error) {\n\tnewExpireTime := c.getInternalExpire(duration)\n\toldDuration, err = c.data.UpdateExpire(key, newExpireTime)\n\tif err != nil {\n\t\treturn\n\t}\n\tif oldDuration != -1 {\n\t\tc.eventList.PushBack(&adapterMemoryEvent{\n\t\t\tk: key,\n\t\t\te: newExpireTime,\n\t\t})\n\t\tc.handleLruKey(ctx, key)\n\t}\n\treturn\n}\n\n// Size returns the size of the cache.\nfunc (c *AdapterMemory) Size(ctx context.Context) (size int, err error) {\n\treturn c.data.Size()\n}\n\n// Data returns a copy of all key-value pairs in the cache as map type.\nfunc (c *AdapterMemory) Data(ctx context.Context) (map[any]any, error) {\n\treturn c.data.Data()\n}\n\n// Keys returns all keys in the cache as slice.\nfunc (c *AdapterMemory) Keys(ctx context.Context) ([]any, error) {\n\treturn c.data.Keys()\n}\n\n// Values returns all values in the cache as slice.\nfunc (c *AdapterMemory) Values(ctx context.Context) ([]any, error) {\n\treturn c.data.Values()\n}\n\n// Clear clears all data of the cache.\n// Note that this function is sensitive and should be carefully used.\nfunc (c *AdapterMemory) Clear(ctx context.Context) error {\n\tc.data.Clear()\n\tc.lru.Clear()\n\treturn nil\n}\n\n// Close closes the cache.\nfunc (c *AdapterMemory) Close(ctx context.Context) error {\n\tc.closed.Set(true)\n\treturn nil\n}\n\n// doSetWithLockCheck sets cache with `key`-`value` pair if `key` does not exist in the\n// cache, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// The parameter `value` can be type of <func() any>, but it does nothing if the\n// function result is nil.\n//\n// It doubly checks the `key` whether exists in the cache using mutex writing lock\n// before setting it to the cache.\nfunc (c *AdapterMemory) doSetWithLockCheck(ctx context.Context, key any, value any, duration time.Duration) (result *gvar.Var, err error) {\n\texpireTimestamp := c.getInternalExpire(duration)\n\tv, err := c.data.SetWithLock(ctx, key, value, expireTimestamp)\n\tc.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp})\n\treturn gvar.New(v), err\n}\n\n// getInternalExpire converts and returns the expiration time with given expired duration in milliseconds.\nfunc (c *AdapterMemory) getInternalExpire(duration time.Duration) int64 {\n\tif duration == 0 {\n\t\treturn defaultMaxExpire\n\t}\n\treturn gtime.TimestampMilli() + duration.Nanoseconds()/1000000\n}\n\n// makeExpireKey groups the `expire` in milliseconds to its according seconds.\nfunc (c *AdapterMemory) makeExpireKey(expire int64) int64 {\n\treturn int64(math.Ceil(float64(expire/1000)+1) * 1000)\n}\n\n// syncEventAndClearExpired does the asynchronous task loop:\n//  1. Asynchronously process the data in the event list,\n//     and synchronize the results to the `expireTimes` and `expireSets` properties.\n//  2. Clean up the expired key-value pair data.\nfunc (c *AdapterMemory) syncEventAndClearExpired(ctx context.Context) {\n\tif c.closed.Val() {\n\t\tgtimer.Exit()\n\t\treturn\n\t}\n\tvar (\n\t\toldExpireTime int64\n\t\tnewExpireTime int64\n\t)\n\t// ================================\n\t// Data expiration synchronization.\n\t// ================================\n\tfor {\n\t\tevent := c.eventList.PopFront()\n\t\tif event == nil {\n\t\t\tbreak\n\t\t}\n\t\t// Fetching the old expire set.\n\t\toldExpireTime = c.expireTimes.Get(event.k)\n\t\t// Calculating the new expiration time set.\n\t\tnewExpireTime = c.makeExpireKey(event.e)\n\t\t// Expiration changed for this key.\n\t\tif newExpireTime != oldExpireTime {\n\t\t\tc.expireSets.GetOrNew(newExpireTime).Add(event.k)\n\t\t\tif oldExpireTime != 0 {\n\t\t\t\tc.expireSets.GetOrNew(oldExpireTime).Remove(event.k)\n\t\t\t}\n\t\t\t// Updating the expired time for `event.k`.\n\t\t\tc.expireTimes.Set(event.k, newExpireTime)\n\t\t}\n\t}\n\t// =================================\n\t// Data expiration auto cleaning up.\n\t// =================================\n\tvar (\n\t\texpireSet  *gset.Set\n\t\texpireTime int64\n\t\tcurrentEk  = c.makeExpireKey(gtime.TimestampMilli())\n\t)\n\t// auto removing expiring key set for latest seconds.\n\tfor i := int64(1); i <= 5; i++ {\n\t\texpireTime = currentEk - i*1000\n\t\tif expireSet = c.expireSets.Get(expireTime); expireSet != nil {\n\t\t\t// Iterating the set to delete all keys in it.\n\t\t\texpireSet.Iterator(func(key any) bool {\n\t\t\t\tc.deleteExpiredKey(key)\n\t\t\t\t// remove auto expired key for lru.\n\t\t\t\tc.lru.Remove(key)\n\t\t\t\treturn true\n\t\t\t})\n\t\t\t// Deleting the set after all of its keys are deleted.\n\t\t\tc.expireSets.Delete(expireTime)\n\t\t}\n\t}\n}\n\nfunc (c *AdapterMemory) handleLruKey(ctx context.Context, keys ...any) {\n\tif c.lru == nil {\n\t\treturn\n\t}\n\tif evictedKeys := c.lru.SaveAndEvict(keys...); len(evictedKeys) > 0 {\n\t\t_, _ = c.doRemove(ctx, evictedKeys...)\n\t\treturn\n\t}\n}\n\n// clearByKey deletes the key-value pair with given `key`.\n// The parameter `force` specifies whether doing this deleting forcibly.\nfunc (c *AdapterMemory) deleteExpiredKey(key any) {\n\t// Doubly check before really deleting it from cache.\n\tc.data.Delete(key)\n\t// Deleting its expiration time from `expireTimes`.\n\tc.expireTimes.Delete(key)\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory_data.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\ntype memoryData struct {\n\tmu   sync.RWMutex           // dataMu ensures the concurrent safety of underlying data map.\n\tdata map[any]memoryDataItem // data is the underlying cache data which is stored in a hash table.\n}\n\n// memoryDataItem holds the internal cache item data.\ntype memoryDataItem struct {\n\tv any   // Value.\n\te int64 // Expire timestamp in milliseconds.\n}\n\nfunc newMemoryData() *memoryData {\n\treturn &memoryData{\n\t\tdata: make(map[any]memoryDataItem),\n\t}\n}\n\n// Update updates the value of `key` without changing its expiration and returns the old value.\n// The returned value `exist` is false if the `key` does not exist in the cache.\n//\n// It deletes the `key` if given `value` is nil.\n// It does nothing if `key` does not exist in the cache.\nfunc (d *memoryData) Update(key any, value any) (oldValue any, exist bool, err error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tif item, ok := d.data[key]; ok {\n\t\td.data[key] = memoryDataItem{\n\t\t\tv: value,\n\t\t\te: item.e,\n\t\t}\n\t\treturn item.v, true, nil\n\t}\n\treturn nil, false, nil\n}\n\n// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n//\n// It returns -1 and does nothing if the `key` does not exist in the cache.\n// It deletes the `key` if `duration` < 0.\nfunc (d *memoryData) UpdateExpire(key any, expireTime int64) (oldDuration time.Duration, err error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tif item, ok := d.data[key]; ok {\n\t\td.data[key] = memoryDataItem{\n\t\t\tv: item.v,\n\t\t\te: expireTime,\n\t\t}\n\t\treturn time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil\n\t}\n\treturn -1, nil\n}\n\n// Remove deletes the one or more keys from cache, and returns its value.\n// If multiple keys are given, it returns the value of the deleted last item.\nfunc (d *memoryData) Remove(keys ...any) (removedKeys []any, value any, err error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tremovedKeys = make([]any, 0)\n\tfor _, key := range keys {\n\t\titem, ok := d.data[key]\n\t\tif ok {\n\t\t\tvalue = item.v\n\t\t\tdelete(d.data, key)\n\t\t\tremovedKeys = append(removedKeys, key)\n\t\t}\n\t}\n\treturn removedKeys, value, nil\n}\n\n// Data returns a copy of all key-value pairs in the cache as map type.\nfunc (d *memoryData) Data() (map[any]any, error) {\n\td.mu.RLock()\n\tdefer d.mu.RUnlock()\n\tvar (\n\t\tdata     = make(map[any]any, len(d.data))\n\t\tnowMilli = gtime.TimestampMilli()\n\t)\n\tfor k, v := range d.data {\n\t\tif v.e > nowMilli {\n\t\t\tdata[k] = v.v\n\t\t}\n\t}\n\treturn data, nil\n}\n\n// Keys returns all keys in the cache as slice.\nfunc (d *memoryData) Keys() ([]any, error) {\n\td.mu.RLock()\n\tdefer d.mu.RUnlock()\n\tvar (\n\t\tkeys     = make([]any, 0, len(d.data))\n\t\tnowMilli = gtime.TimestampMilli()\n\t)\n\tfor k, v := range d.data {\n\t\tif v.e > nowMilli {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t}\n\treturn keys, nil\n}\n\n// Values returns all values in the cache as slice.\nfunc (d *memoryData) Values() ([]any, error) {\n\td.mu.RLock()\n\tdefer d.mu.RUnlock()\n\tvar (\n\t\tvalues   = make([]any, 0, len(d.data))\n\t\tnowMilli = gtime.TimestampMilli()\n\t)\n\tfor _, v := range d.data {\n\t\tif v.e > nowMilli {\n\t\t\tvalues = append(values, v.v)\n\t\t}\n\t}\n\treturn values, nil\n}\n\n// Size returns the size of the cache that not expired.\nfunc (d *memoryData) Size() (size int, err error) {\n\td.mu.RLock()\n\tdefer d.mu.RUnlock()\n\tvar nowMilli = gtime.TimestampMilli()\n\tfor _, v := range d.data {\n\t\tif v.e > nowMilli {\n\t\t\tsize++\n\t\t}\n\t}\n\treturn size, nil\n}\n\n// Clear clears all data of the cache.\n// Note that this function is sensitive and should be carefully used.\nfunc (d *memoryData) Clear() {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\td.data = make(map[any]memoryDataItem)\n}\n\nfunc (d *memoryData) Get(key any) (item memoryDataItem, ok bool) {\n\td.mu.RLock()\n\titem, ok = d.data[key]\n\td.mu.RUnlock()\n\treturn\n}\n\nfunc (d *memoryData) Set(key any, value memoryDataItem) {\n\td.mu.Lock()\n\td.data[key] = value\n\td.mu.Unlock()\n}\n\n// SetMap batch sets cache with key-value pairs by `data`, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc (d *memoryData) SetMap(data map[any]any, expireTime int64) error {\n\td.mu.Lock()\n\tfor k, v := range data {\n\t\td.data[k] = memoryDataItem{\n\t\t\tv: v,\n\t\t\te: expireTime,\n\t\t}\n\t}\n\td.mu.Unlock()\n\treturn nil\n}\n\nfunc (d *memoryData) SetWithLock(ctx context.Context, key any, value any, expireTimestamp int64) (any, error) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tvar (\n\t\terr error\n\t)\n\tif v, ok := d.data[key]; ok && !v.IsExpired() {\n\t\treturn v.v, nil\n\t}\n\tf, ok := value.(Func)\n\tif !ok {\n\t\t// Compatible with raw function value.\n\t\tf, ok = value.(func(ctx context.Context) (value any, err error))\n\t}\n\tif ok {\n\t\tif value, err = f(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif value == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\td.data[key] = memoryDataItem{v: value, e: expireTimestamp}\n\treturn value, nil\n}\n\nfunc (d *memoryData) Delete(key any) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\tdelete(d.data, key)\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory_expire_sets.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n)\n\ntype memoryExpireSets struct {\n\t// expireSetMu ensures the concurrent safety of expireSets map.\n\tmu sync.RWMutex\n\t// expireSets is the expiring timestamp in seconds to its key set mapping, which is used for quick indexing and deleting.\n\texpireSets map[int64]*gset.Set\n}\n\nfunc newMemoryExpireSets() *memoryExpireSets {\n\treturn &memoryExpireSets{\n\t\texpireSets: make(map[int64]*gset.Set),\n\t}\n}\n\nfunc (d *memoryExpireSets) Get(key int64) (result *gset.Set) {\n\td.mu.RLock()\n\tresult = d.expireSets[key]\n\td.mu.RUnlock()\n\treturn\n}\n\nfunc (d *memoryExpireSets) GetOrNew(key int64) (result *gset.Set) {\n\tif result = d.Get(key); result != nil {\n\t\treturn\n\t}\n\td.mu.Lock()\n\tif es, ok := d.expireSets[key]; ok {\n\t\tresult = es\n\t} else {\n\t\tresult = gset.New(true)\n\t\td.expireSets[key] = result\n\t}\n\td.mu.Unlock()\n\treturn\n}\n\nfunc (d *memoryExpireSets) Delete(key int64) {\n\td.mu.Lock()\n\tdelete(d.expireSets, key)\n\td.mu.Unlock()\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory_expire_times.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"sync\"\n)\n\ntype memoryExpireTimes struct {\n\tmu          sync.RWMutex  // expireTimeMu ensures the concurrent safety of expireTimes map.\n\texpireTimes map[any]int64 // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.\n}\n\nfunc newMemoryExpireTimes() *memoryExpireTimes {\n\treturn &memoryExpireTimes{\n\t\texpireTimes: make(map[any]int64),\n\t}\n}\n\nfunc (d *memoryExpireTimes) Get(key any) (value int64) {\n\td.mu.RLock()\n\tvalue = d.expireTimes[key]\n\td.mu.RUnlock()\n\treturn\n}\n\nfunc (d *memoryExpireTimes) Set(key any, value int64) {\n\td.mu.Lock()\n\td.expireTimes[key] = value\n\td.mu.Unlock()\n}\n\nfunc (d *memoryExpireTimes) Delete(key any) {\n\td.mu.Lock()\n\tdelete(d.expireTimes, key)\n\td.mu.Unlock()\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory_item.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// IsExpired checks whether `item` is expired.\nfunc (item *memoryDataItem) IsExpired() bool {\n\t// Note that it should use greater than or equal judgement here\n\t// imagining that the cache time is only 1 millisecond.\n\treturn item.e < gtime.TimestampMilli()\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_memory_lru.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\n// checker is used to check if the value is nil.\nvar checker = func(v *glist.Element) bool { return v == nil }\n\n// memoryLru holds LRU info.\n// It uses list.List from stdlib for its underlying doubly linked list.\ntype memoryLru struct {\n\tmu   sync.RWMutex                     // Mutex to guarantee concurrent safety.\n\tcap  int                              // LRU cap.\n\tdata *gmap.KVMap[any, *glist.Element] // Key mapping to the item of the list.\n\tlist *glist.List                      // Key list.\n}\n\n// newMemoryLru creates and returns a new LRU manager.\nfunc newMemoryLru(cap int) *memoryLru {\n\tlru := &memoryLru{\n\t\tcap:  cap,\n\t\tdata: gmap.NewKVMapWithChecker[any, *glist.Element](checker, false),\n\t\tlist: glist.New(false),\n\t}\n\treturn lru\n}\n\n// Remove deletes the `key` FROM `lru`.\nfunc (l *memoryLru) Remove(keys ...any) {\n\tif l == nil {\n\t\treturn\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tfor _, key := range keys {\n\t\tif v := l.data.Remove(key); v != nil {\n\t\t\tl.list.Remove(v)\n\t\t}\n\t}\n}\n\n// SaveAndEvict saves the keys into LRU, evicts and returns the spare keys.\nfunc (l *memoryLru) SaveAndEvict(keys ...any) (evictedKeys []any) {\n\tif l == nil {\n\t\treturn\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tevictedKeys = make([]any, 0)\n\tfor _, key := range keys {\n\t\tif evictedKey := l.doSaveAndEvict(key); evictedKey != nil {\n\t\t\tevictedKeys = append(evictedKeys, evictedKey)\n\t\t}\n\t}\n\treturn\n}\n\nfunc (l *memoryLru) doSaveAndEvict(key any) (evictedKey any) {\n\telement := l.data.Get(key)\n\tif element != nil {\n\t\tif element.Prev() == nil {\n\t\t\t// It this element is already on top of list,\n\t\t\t// it ignores the element moving.\n\t\t\treturn\n\t\t}\n\t\tl.list.Remove(element)\n\t}\n\n\t// pushes the active key to top of list.\n\telement = l.list.PushFront(key)\n\tl.data.Set(key, element)\n\t// evict the spare key from list.\n\tif l.data.Size() <= l.cap {\n\t\treturn\n\t}\n\n\tif evictedKey = l.list.PopBack(); evictedKey != nil {\n\t\tl.data.Remove(evictedKey)\n\t}\n\treturn\n}\n\n// Clear deletes all keys.\nfunc (l *memoryLru) Clear() {\n\tif l == nil {\n\t\treturn\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\tl.data.Clear()\n\tl.list.Clear()\n}\n"
  },
  {
    "path": "os/gcache/gcache_adapter_redis.go",
    "content": "// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// AdapterRedis is the gcache adapter implements using Redis server.\ntype AdapterRedis struct {\n\tredis *gredis.Redis\n}\n\nvar _ Adapter = (*AdapterRedis)(nil)\n\n// NewAdapterRedis creates and returns a new Redis cache adapter.\nfunc NewAdapterRedis(redis *gredis.Redis) *AdapterRedis {\n\treturn &AdapterRedis{\n\t\tredis: redis,\n\t}\n}\n\n// Set sets cache with `key`-`value` pair, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterRedis) Set(ctx context.Context, key any, value any, duration time.Duration) (err error) {\n\tredisKey := gconv.String(key)\n\tif value == nil || duration < 0 {\n\t\t_, err = c.redis.Del(ctx, redisKey)\n\t} else {\n\t\tif duration == 0 {\n\t\t\t_, err = c.redis.Set(ctx, redisKey, value)\n\t\t} else {\n\t\t\t_, err = c.redis.Set(ctx, redisKey, value, gredis.SetOption{TTLOption: gredis.TTLOption{PX: gconv.PtrInt64(duration.Milliseconds())}})\n\t\t}\n\t}\n\treturn err\n}\n\n// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterRedis) SetMap(ctx context.Context, data map[any]any, duration time.Duration) error {\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\t// DEL.\n\tif duration < 0 {\n\t\tvar (\n\t\t\tindex = 0\n\t\t\tkeys  = make([]string, len(data))\n\t\t)\n\t\tfor k := range data {\n\t\t\tkeys[index] = gconv.String(k)\n\t\t\tindex += 1\n\t\t}\n\t\t_, err := c.redis.Del(ctx, keys...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif duration == 0 {\n\t\terr := c.redis.MSet(ctx, gconv.Map(data))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif duration > 0 {\n\t\tvar err error\n\t\tfor k, v := range data {\n\t\t\tif err = c.Set(ctx, k, v, duration); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`\n// if `key` does not exist in the cache. It returns true the `key` does not exist in the\n// cache, and it sets `value` successfully to the cache, or else it returns false.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterRedis) SetIfNotExist(ctx context.Context, key any, value any, duration time.Duration) (bool, error) {\n\tvar (\n\t\terr      error\n\t\tredisKey = gconv.String(key)\n\t)\n\t// Execute the function and retrieve the result.\n\tf, ok := value.(Func)\n\tif !ok {\n\t\t// Compatible with raw function value.\n\t\tf, ok = value.(func(ctx context.Context) (value any, err error))\n\t}\n\tif ok {\n\t\tif value, err = f(ctx); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\t// DEL.\n\tif duration < 0 || value == nil {\n\t\tvar delResult int64\n\t\tdelResult, err = c.redis.Del(ctx, redisKey)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif delResult == 1 {\n\t\t\treturn true, err\n\t\t}\n\t\treturn false, err\n\t}\n\tok, err = c.redis.SetNX(ctx, redisKey, value)\n\tif err != nil {\n\t\treturn ok, err\n\t}\n\tif ok && duration > 0 {\n\t\t// Set the expiration.\n\t\t_, err = c.redis.PExpire(ctx, redisKey, duration.Milliseconds())\n\t\tif err != nil {\n\t\t\treturn ok, err\n\t\t}\n\t\treturn ok, err\n\t}\n\treturn ok, err\n}\n\n// SetIfNotExistFunc sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// The parameter `value` can be type of `func() any`, but it does nothing if its\n// result is nil.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\nfunc (c *AdapterRedis) SetIfNotExistFunc(ctx context.Context, key any, f Func, duration time.Duration) (ok bool, err error) {\n\tvalue, err := f(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn c.SetIfNotExist(ctx, key, value, duration)\n}\n\n// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true\n// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil.\n//\n// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc (c *AdapterRedis) SetIfNotExistFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (ok bool, err error) {\n\tvalue, err := f(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn c.SetIfNotExist(ctx, key, value, duration)\n}\n\n// Get retrieves and returns the associated value of given <key>.\n// It returns nil if it does not exist or its value is nil.\nfunc (c *AdapterRedis) Get(ctx context.Context, key any) (*gvar.Var, error) {\n\treturn c.redis.Get(ctx, gconv.String(key))\n}\n\n// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and\n// returns `value` if `key` does not exist in the cache. The key-value pair expires\n// after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc (c *AdapterRedis) GetOrSet(ctx context.Context, key any, value any, duration time.Duration) (result *gvar.Var, err error) {\n\tresult, err = c.Get(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif result.IsNil() {\n\t\treturn gvar.New(value), c.Set(ctx, key, value, duration)\n\t}\n\treturn\n}\n\n// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\nfunc (c *AdapterRedis) GetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) (result *gvar.Var, err error) {\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v.IsNil() {\n\t\tvalue, err := f(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif value == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn gvar.New(value), c.Set(ctx, key, value, duration)\n\t} else {\n\t\treturn v, nil\n\t}\n}\n\n// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of\n// function `f` and returns its result if `key` does not exist in the cache. The key-value\n// pair expires after `duration`.\n//\n// It does not expire if `duration` == 0.\n// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing\n// if `value` is a function and the function result is nil.\n//\n// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within\n// writing mutex lock for concurrent safety purpose.\nfunc (c *AdapterRedis) GetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) (result *gvar.Var, err error) {\n\treturn c.GetOrSetFunc(ctx, key, f, duration)\n}\n\n// Contains checks and returns true if `key` exists in the cache, or else returns false.\nfunc (c *AdapterRedis) Contains(ctx context.Context, key any) (bool, error) {\n\tn, err := c.redis.Exists(ctx, gconv.String(key))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn n > 0, nil\n}\n\n// Size returns the number of items in the cache.\nfunc (c *AdapterRedis) Size(ctx context.Context) (size int, err error) {\n\tn, err := c.redis.DBSize(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(n), nil\n}\n\n// Data returns a copy of all key-value pairs in the cache as map type.\n// Note that this function may lead lots of memory usage, you can implement this function\n// if necessary.\nfunc (c *AdapterRedis) Data(ctx context.Context) (map[any]any, error) {\n\t// Keys.\n\tkeys, err := c.redis.Keys(ctx, \"*\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Key-Value pairs.\n\tvar m map[string]*gvar.Var\n\tm, err = c.redis.MGet(ctx, keys...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Type converting.\n\tdata := make(map[any]any)\n\tfor k, v := range m {\n\t\tdata[k] = v.Val()\n\t}\n\treturn data, nil\n}\n\n// Keys returns all keys in the cache as slice.\nfunc (c *AdapterRedis) Keys(ctx context.Context) ([]any, error) {\n\tkeys, err := c.redis.Keys(ctx, \"*\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn gconv.Interfaces(keys), nil\n}\n\n// Values returns all values in the cache as slice.\nfunc (c *AdapterRedis) Values(ctx context.Context) ([]any, error) {\n\t// Keys.\n\tkeys, err := c.redis.Keys(ctx, \"*\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Key-Value pairs.\n\tvar m map[string]*gvar.Var\n\tm, err = c.redis.MGet(ctx, keys...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Values.\n\tvar values []any\n\tfor _, key := range keys {\n\t\tif v := m[key]; !v.IsNil() {\n\t\t\tvalues = append(values, v.Val())\n\t\t}\n\t}\n\treturn values, nil\n}\n\n// Update updates the value of `key` without changing its expiration and returns the old value.\n// The returned value `exist` is false if the `key` does not exist in the cache.\n//\n// It deletes the `key` if given `value` is nil.\n// It does nothing if `key` does not exist in the cache.\nfunc (c *AdapterRedis) Update(ctx context.Context, key any, value any) (oldValue *gvar.Var, exist bool, err error) {\n\tvar (\n\t\tv        *gvar.Var\n\t\toldPTTL  int64\n\t\tredisKey = gconv.String(key)\n\t)\n\t// TTL.\n\toldPTTL, err = c.redis.PTTL(ctx, redisKey) // update ttl -> pttl(millisecond)\n\tif err != nil {\n\t\treturn\n\t}\n\tif oldPTTL == -2 || oldPTTL == 0 {\n\t\t// It does not exist or expired.\n\t\treturn\n\t}\n\t// Check existence.\n\tv, err = c.redis.Get(ctx, redisKey)\n\tif err != nil {\n\t\treturn\n\t}\n\toldValue = v\n\t// DEL.\n\tif value == nil {\n\t\t_, err = c.redis.Del(ctx, redisKey)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\treturn\n\t}\n\t// Update the value.\n\tif oldPTTL == -1 {\n\t\t_, err = c.redis.Set(ctx, redisKey, value)\n\t} else {\n\t\t// update SetEX -> SET PX Option(millisecond)\n\t\t// Starting with Redis version 2.6.12: Added the EX, PX, NX and XX options.\n\t\t_, err = c.redis.Set(ctx, redisKey, value, gredis.SetOption{TTLOption: gredis.TTLOption{PX: gconv.PtrInt64(oldPTTL)}})\n\t}\n\treturn oldValue, true, err\n}\n\n// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n//\n// It returns -1 and does nothing if the `key` does not exist in the cache.\n// It deletes the `key` if `duration` < 0.\nfunc (c *AdapterRedis) UpdateExpire(ctx context.Context, key any, duration time.Duration) (oldDuration time.Duration, err error) {\n\tvar (\n\t\tv        *gvar.Var\n\t\toldPTTL  int64\n\t\tredisKey = gconv.String(key)\n\t)\n\t// TTL.\n\toldPTTL, err = c.redis.PTTL(ctx, redisKey)\n\tif err != nil {\n\t\treturn\n\t}\n\tif oldPTTL == -2 || oldPTTL == 0 {\n\t\t// It does not exist or expired.\n\t\toldPTTL = -1\n\t\treturn\n\t}\n\toldDuration = time.Duration(oldPTTL) * time.Millisecond\n\t// DEL.\n\tif duration < 0 {\n\t\t_, err = c.redis.Del(ctx, redisKey)\n\t\treturn\n\t}\n\t// Update the expiration.\n\tif duration > 0 {\n\t\t_, err = c.redis.PExpire(ctx, redisKey, duration.Milliseconds())\n\t}\n\t// No expire.\n\tif duration == 0 {\n\t\tv, err = c.redis.Get(ctx, redisKey)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\t_, err = c.redis.Set(ctx, redisKey, v.Val())\n\t}\n\treturn\n}\n\n// GetExpire retrieves and returns the expiration of `key` in the cache.\n//\n// Note that,\n// It returns 0 if the `key` does not expire.\n// It returns -1 if the `key` does not exist in the cache.\nfunc (c *AdapterRedis) GetExpire(ctx context.Context, key any) (time.Duration, error) {\n\tpttl, err := c.redis.PTTL(ctx, gconv.String(key))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tswitch pttl {\n\tcase -1:\n\t\treturn 0, nil\n\tcase -2, 0: // It does not exist or expired.\n\t\treturn -1, nil\n\tdefault:\n\t\treturn time.Duration(pttl) * time.Millisecond, nil\n\t}\n}\n\n// Remove deletes the one or more keys from cache, and returns its value.\n// If multiple keys are given, it returns the value of the deleted last item.\nfunc (c *AdapterRedis) Remove(ctx context.Context, keys ...any) (lastValue *gvar.Var, err error) {\n\tif len(keys) == 0 {\n\t\treturn nil, nil\n\t}\n\t// Retrieves the last key value.\n\tif lastValue, err = c.redis.Get(ctx, gconv.String(keys[len(keys)-1])); err != nil {\n\t\treturn nil, err\n\t}\n\t// Deletes all given keys.\n\t_, err = c.redis.Del(ctx, gconv.Strings(keys)...)\n\treturn\n}\n\n// Clear clears all data of the cache.\n// Note that this function is sensitive and should be carefully used.\n// It uses `FLUSHDB` command in redis server, which might be disabled in server.\nfunc (c *AdapterRedis) Clear(ctx context.Context) (err error) {\n\t// The \"FLUSHDB\" may not be available.\n\terr = c.redis.FlushDB(ctx)\n\treturn\n}\n\n// Close closes the cache.\nfunc (c *AdapterRedis) Close(ctx context.Context) error {\n\t// It does nothing.\n\treturn nil\n}\n"
  },
  {
    "path": "os/gcache/gcache_cache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Cache struct.\ntype Cache struct {\n\tlocalAdapter\n}\n\n// localAdapter is alias of Adapter, for embedded attribute purpose only.\ntype localAdapter = Adapter\n\n// New creates and returns a new cache object using default memory adapter.\n// Note that the LRU feature is only available using memory adapter.\nfunc New(lruCap ...int) *Cache {\n\tvar adapter Adapter\n\tif len(lruCap) == 0 {\n\t\tadapter = NewAdapterMemory()\n\t} else {\n\t\tadapter = NewAdapterMemoryLru(lruCap[0])\n\t}\n\tc := &Cache{\n\t\tlocalAdapter: adapter,\n\t}\n\treturn c\n}\n\n// NewWithAdapter creates and returns a Cache object with given Adapter implements.\nfunc NewWithAdapter(adapter Adapter) *Cache {\n\treturn &Cache{\n\t\tlocalAdapter: adapter,\n\t}\n}\n\n// SetAdapter changes the adapter for this cache.\n// Be very note that, this setting function is not concurrent-safe, which means you should not call\n// this setting function concurrently in multiple goroutines.\nfunc (c *Cache) SetAdapter(adapter Adapter) {\n\tc.localAdapter = adapter\n}\n\n// GetAdapter returns the adapter that is set in current Cache.\nfunc (c *Cache) GetAdapter() Adapter {\n\treturn c.localAdapter\n}\n\n// Removes deletes `keys` in the cache.\nfunc (c *Cache) Removes(ctx context.Context, keys []any) error {\n\t_, err := c.Remove(ctx, keys...)\n\treturn err\n}\n\n// KeyStrings returns all keys in the cache as string slice.\nfunc (c *Cache) KeyStrings(ctx context.Context) ([]string, error) {\n\tkeys, err := c.Keys(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn gconv.Strings(keys), nil\n}\n"
  },
  {
    "path": "os/gcache/gcache_cache_must.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// MustGet acts like Get, but it panics if any error occurs.\nfunc (c *Cache) MustGet(ctx context.Context, key any) *gvar.Var {\n\tv, err := c.Get(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetOrSet acts like GetOrSet, but it panics if any error occurs.\nfunc (c *Cache) MustGetOrSet(ctx context.Context, key any, value any, duration time.Duration) *gvar.Var {\n\tv, err := c.GetOrSet(ctx, key, value, duration)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetOrSetFunc acts like GetOrSetFunc, but it panics if any error occurs.\nfunc (c *Cache) MustGetOrSetFunc(ctx context.Context, key any, f Func, duration time.Duration) *gvar.Var {\n\tv, err := c.GetOrSetFunc(ctx, key, f, duration)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetOrSetFuncLock acts like GetOrSetFuncLock, but it panics if any error occurs.\nfunc (c *Cache) MustGetOrSetFuncLock(ctx context.Context, key any, f Func, duration time.Duration) *gvar.Var {\n\tv, err := c.GetOrSetFuncLock(ctx, key, f, duration)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustContains acts like Contains, but it panics if any error occurs.\nfunc (c *Cache) MustContains(ctx context.Context, key any) bool {\n\tv, err := c.Contains(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetExpire acts like GetExpire, but it panics if any error occurs.\nfunc (c *Cache) MustGetExpire(ctx context.Context, key any) time.Duration {\n\tv, err := c.GetExpire(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustSize acts like Size, but it panics if any error occurs.\nfunc (c *Cache) MustSize(ctx context.Context) int {\n\tv, err := c.Size(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustData acts like Data, but it panics if any error occurs.\nfunc (c *Cache) MustData(ctx context.Context) map[any]any {\n\tv, err := c.Data(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustKeys acts like Keys, but it panics if any error occurs.\nfunc (c *Cache) MustKeys(ctx context.Context) []any {\n\tv, err := c.Keys(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustKeyStrings acts like KeyStrings, but it panics if any error occurs.\nfunc (c *Cache) MustKeyStrings(ctx context.Context) []string {\n\tv, err := c.KeyStrings(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustValues acts like Values, but it panics if any error occurs.\nfunc (c *Cache) MustValues(ctx context.Context) []any {\n\tv, err := c.Values(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "os/gcache/gcache_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcache_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gcache\"\n)\n\nvar (\n\tlocalCache    = gcache.New()\n\tlocalCacheLru = gcache.NewWithAdapter(gcache.NewAdapterMemoryLru(10000))\n)\n\nfunc Benchmark_CacheSet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCache.Set(ctx, i, i, 0)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_CacheGet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCache.Get(ctx, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_CacheRemove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCache.Remove(ctx, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_CacheLruSet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCacheLru.Set(ctx, i, i, 0)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_CacheLruGet(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCacheLru.Get(ctx, i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nfunc Benchmark_CacheLruRemove(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ti := 0\n\t\tfor pb.Next() {\n\t\t\tlocalCacheLru.Remove(context.TODO(), i)\n\t\t\ti++\n\t\t}\n\t})\n}\n\nvar oldDefaultCache = gcache.New()\nvar newDefaultCache = sync.OnceValue(func() *gcache.Cache {\n\treturn gcache.New()\n})\n\nfunc BenchmarkOldImplementation(b *testing.B) {\n\tctx := context.Background()\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = oldDefaultCache.Set(ctx, \"key\", \"value\", time.Minute)\n\t}\n}\n\nfunc BenchmarkNewImplementation(b *testing.B) {\n\tctx := context.Background()\n\tnewDefaultCache()\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = newDefaultCache().Set(ctx, \"key\", \"value\", time.Minute)\n\t}\n}\n\nfunc BenchmarkOldGet(b *testing.B) {\n\tctx := context.Background()\n\toldDefaultCache.Set(ctx, \"test_key\", \"test_value\", time.Minute)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = oldDefaultCache.Get(ctx, \"test_key\")\n\t}\n}\n\nfunc BenchmarkNewGet(b *testing.B) {\n\tctx := context.Background()\n\tnewDefaultCache().Set(ctx, \"test_key\", \"test_value\", time.Minute)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = newDefaultCache().Get(ctx, \"test_key\")\n\t}\n}\n\nfunc BenchmarkOldConcurrent(b *testing.B) {\n\tctx := context.Background()\n\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\t_ = oldDefaultCache.Set(ctx, \"key\", \"value\", time.Minute)\n\t\t}\n\t})\n}\n\nfunc BenchmarkNewConcurrent(b *testing.B) {\n\tctx := context.Background()\n\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\t_ = newDefaultCache().Set(ctx, \"key\", \"value\", time.Minute)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "os/gcache/gcache_z_example_cache_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcache_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nfunc ExampleNew() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly.\n\tc := gcache.New()\n\n\t// Set cache without expiration\n\tc.Set(ctx, \"k1\", \"v1\", 0)\n\n\t// Get cache\n\tv, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(v)\n\n\t// Get cache size\n\tn, _ := c.Size(ctx)\n\tfmt.Println(n)\n\n\t// Does the specified key name exist in the cache\n\tb, _ := c.Contains(ctx, \"k1\")\n\tfmt.Println(b)\n\n\t// Delete and return the deleted key value\n\tfmt.Println(c.Remove(ctx, \"k1\"))\n\n\t// Close the cache object and let the GC reclaim resources\n\n\tc.Close(ctx)\n\n\t// Output:\n\t// v1\n\t// 1\n\t// true\n\t// v1 <nil>\n}\n\nfunc ExampleCache_Set() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set cache without expiration\n\tc.Set(ctx, \"k1\", g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9}, 0)\n\n\t// Get cache\n\tfmt.Println(c.Get(ctx, \"k1\"))\n\n\t// Output:\n\t// [1,2,3,4,5,6,7,8,9] <nil>\n}\n\nfunc ExampleCache_SetIfNotExist() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Write when the key name does not exist, and set the expiration time to 1000 milliseconds\n\tk1, err := c.SetIfNotExist(ctx, \"k1\", \"v1\", 1000*time.Millisecond)\n\tfmt.Println(k1, err)\n\n\t// Returns false when the key name already exists\n\tk2, err := c.SetIfNotExist(ctx, \"k1\", \"v2\", 1000*time.Millisecond)\n\tfmt.Println(k2, err)\n\n\t// Print the current list of key values\n\tkeys1, _ := c.Keys(ctx)\n\tfmt.Println(keys1)\n\n\t// It does not expire if `duration` == 0. It deletes the `key` if `duration` < 0 or given `value` is nil.\n\tc.SetIfNotExist(ctx, \"k1\", 0, -10000)\n\n\t// Wait 1.5 second for K1: V1 to expire automatically\n\ttime.Sleep(1500 * time.Millisecond)\n\n\t// Print the current key value pair again and find that K1: V1 has expired\n\tkeys2, _ := c.Keys(ctx)\n\tfmt.Println(keys2)\n\n\t// Output:\n\t// true <nil>\n\t// false <nil>\n\t// [k1]\n\t// []\n}\n\nfunc ExampleCache_SetMap() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// map[any]any\n\tdata := g.MapAnyAny{\n\t\t\"k1\": \"v1\",\n\t\t\"k2\": \"v2\",\n\t\t\"k3\": \"v3\",\n\t}\n\n\t// Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`.\n\t// It does not expire if `duration` == 0. It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\n\tc.SetMap(ctx, data, 1000*time.Millisecond)\n\n\t// Gets the specified key value\n\tv1, _ := c.Get(ctx, \"k1\")\n\tv2, _ := c.Get(ctx, \"k2\")\n\tv3, _ := c.Get(ctx, \"k3\")\n\n\tfmt.Println(v1, v2, v3)\n\n\t// Output:\n\t// v1 v2 v3\n}\n\nfunc ExampleCache_Size() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Add 10 elements without expiration\n\tfor i := 0; i < 10; i++ {\n\t\tc.Set(ctx, i, i, 0)\n\t}\n\n\t// Size returns the number of items in the cache.\n\tn, _ := c.Size(ctx)\n\tfmt.Println(n)\n\n\t// Output:\n\t// 10\n}\n\nfunc ExampleCache_Update() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`.\n\t// It does not expire if `duration` == 0. It deletes the keys of `data` if `duration` < 0 or given `value` is nil.\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\", \"k3\": \"v3\"}, 0)\n\n\t// Print the current key value pair\n\tk1, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(k1)\n\tk2, _ := c.Get(ctx, \"k2\")\n\tfmt.Println(k2)\n\tk3, _ := c.Get(ctx, \"k3\")\n\tfmt.Println(k3)\n\n\t// Update updates the value of `key` without changing its expiration and returns the old value.\n\tre, exist, _ := c.Update(ctx, \"k1\", \"v11\")\n\tfmt.Println(re, exist)\n\n\t// The returned value `exist` is false if the `key` does not exist in the cache.\n\t// It does nothing if `key` does not exist in the cache.\n\tre1, exist1, _ := c.Update(ctx, \"k4\", \"v44\")\n\tfmt.Println(re1, exist1)\n\n\tkup1, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(kup1)\n\tkup2, _ := c.Get(ctx, \"k2\")\n\tfmt.Println(kup2)\n\tkup3, _ := c.Get(ctx, \"k3\")\n\tfmt.Println(kup3)\n\n\t// Output:\n\t// v1\n\t// v2\n\t// v3\n\t// v1 true\n\t//  false\n\t// v11\n\t// v2\n\t// v3\n}\n\nfunc ExampleCache_UpdateExpire() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.Set(ctx, \"k1\", \"v1\", 1000*time.Millisecond)\n\texpire, _ := c.GetExpire(ctx, \"k1\")\n\tfmt.Println(expire)\n\n\t// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.\n\t// It returns -1 and does nothing if the `key` does not exist in the cache.\n\tc.UpdateExpire(ctx, \"k1\", 500*time.Millisecond)\n\n\texpire1, _ := c.GetExpire(ctx, \"k1\")\n\tfmt.Println(expire1)\n\n\t// May Output:\n\t// 1s\n\t// 500ms\n}\n\nfunc ExampleCache_Values() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Write value\n\tc.Set(ctx, \"k1\", g.Map{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\t// c.Set(ctx, \"k2\", \"Here is Value2\", 0)\n\t// c.Set(ctx, \"k3\", 111, 0)\n\n\t// Values returns all values in the cache as slice.\n\tdata, _ := c.Values(ctx)\n\tfmt.Println(data)\n\n\t// May Output:\n\t// [map[k1:v1 k2:v2]]\n}\n\nfunc ExampleCache_Close() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set Cache\n\tc.Set(ctx, \"k1\", \"v\", 0)\n\tdata, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(data)\n\n\t// Close closes the cache if necessary.\n\tc.Close(ctx)\n\n\tdata1, _ := c.Get(ctx, \"k1\")\n\n\tfmt.Println(data1)\n\n\t// Output:\n\t// v\n\t// v\n}\n\nfunc ExampleCache_Contains() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set Cache\n\tc.Set(ctx, \"k\", \"v\", 0)\n\n\t// Contains returns true if `key` exists in the cache, or else returns false.\n\t// return true\n\tdata, _ := c.Contains(ctx, \"k\")\n\tfmt.Println(data)\n\n\t// return false\n\tdata1, _ := c.Contains(ctx, \"k1\")\n\tfmt.Println(data1)\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleCache_Data() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\"}, 0)\n\n\tdata, _ := c.Data(ctx)\n\tfmt.Println(data)\n\n\t// Set Cache\n\tc.Set(ctx, \"k5\", \"v5\", 0)\n\tdata1, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(data1)\n\n\t// Output:\n\t// map[k1:v1]\n\t// v1\n}\n\nfunc ExampleCache_Get() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set Cache Object\n\tc.Set(ctx, \"k1\", \"v1\", 0)\n\n\t// Get retrieves and returns the associated value of given `key`.\n\t// It returns nil if it does not exist, its value is nil or it's expired.\n\tdata, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(data)\n\n\t// Output:\n\t// v1\n}\n\nfunc ExampleCache_GetExpire() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set cache without expiration\n\tc.Set(ctx, \"k\", \"v\", 10000*time.Millisecond)\n\n\t// GetExpire retrieves and returns the expiration of `key` in the cache.\n\t// It returns 0 if the `key` does not expire. It returns -1 if the `key` does not exist in the cache.\n\texpire, _ := c.GetExpire(ctx, \"k\")\n\tfmt.Println(expire)\n\n\t// May Output:\n\t// 10s\n}\n\nfunc ExampleCache_GetOrSet() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and returns `value`\n\t// if `key` does not exist in the cache.\n\tdata, _ := c.GetOrSet(ctx, \"k\", \"v\", 10000*time.Millisecond)\n\tfmt.Println(data)\n\n\tdata1, _ := c.Get(ctx, \"k\")\n\tfmt.Println(data1)\n\n\t// Output:\n\t// v\n\t// v\n\n}\n\nfunc ExampleCache_GetOrSetFunc() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of function `f`\n\t// and returns its result if `key` does not exist in the cache.\n\tc.GetOrSetFunc(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"v1\", nil\n\t}, 10000*time.Millisecond)\n\tv, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(v)\n\n\t// If func returns nil, no action is taken\n\tc.GetOrSetFunc(ctx, \"k2\", func(ctx context.Context) (value any, err error) {\n\t\treturn nil, nil\n\t}, 10000*time.Millisecond)\n\tv1, _ := c.Get(ctx, \"k2\")\n\tfmt.Println(v1)\n\n\t// Output:\n\t// v1\n}\n\nfunc ExampleCache_GetOrSetFuncLock() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Modify locking Note that the function `f` should be executed within writing mutex lock for concurrent safety purpose.\n\tc.GetOrSetFuncLock(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"v1\", nil\n\t}, 0)\n\tv, _ := c.Get(ctx, \"k1\")\n\tfmt.Println(v)\n\n\t// Modification failed\n\tc.GetOrSetFuncLock(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"update v1\", nil\n\t}, 0)\n\tv, _ = c.Get(ctx, \"k1\")\n\tfmt.Println(v)\n\n\tc.Remove(ctx, g.Slice{\"k1\"}...)\n\n\t// Output:\n\t// v1\n\t// v1\n}\n\nfunc ExampleCache_Keys() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\"}, 0)\n\n\t// Print the current list of key values\n\tkeys1, _ := c.Keys(ctx)\n\tfmt.Println(keys1)\n\n\t// Output:\n\t// [k1]\n}\n\nfunc ExampleCache_KeyStrings() {\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\n\t// KeyStrings returns all keys in the cache as string slice.\n\tkeys, _ := c.KeyStrings(ctx)\n\tfmt.Println(keys)\n\n\t// May Output:\n\t// [k1 k2]\n}\n\nfunc ExampleCache_Remove() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\n\t// Remove deletes one or more keys from cache, and returns its value.\n\t// If multiple keys are given, it returns the value of the last deleted item.\n\tremove, _ := c.Remove(ctx, \"k1\")\n\tfmt.Println(remove)\n\n\tdata, _ := c.Data(ctx)\n\tfmt.Println(data)\n\n\t// Output:\n\t// v1\n\t// map[k2:v2]\n}\n\nfunc ExampleCache_Removes() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\", \"k3\": \"v3\", \"k4\": \"v4\"}, 0)\n\n\t// Remove deletes one or more keys from cache, and returns its value.\n\t// If multiple keys are given, it returns the value of the last deleted item.\n\tc.Removes(ctx, g.Slice{\"k1\", \"k2\", \"k3\"})\n\n\tdata, _ := c.Data(ctx)\n\tfmt.Println(data)\n\n\t// Output:\n\t// map[k4:v4]\n}\n\nfunc ExampleCache_Clear() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\", \"k3\": \"v3\", \"k4\": \"v4\"}, 0)\n\n\t// clears all data of the cache.\n\tc.Clear(ctx)\n\n\tdata, _ := c.Data(ctx)\n\tfmt.Println(data)\n\n\t// Output:\n\t// map[]\n}\n\nfunc ExampleCache_MustGet() {\n\t// Intercepting panic exception information\n\t// err is empty, so panic is not performed\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tfmt.Println(\"recover...:\", r)\n\t\t}\n\t}()\n\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set Cache Object\n\tc.Set(ctx, \"k1\", \"v1\", 0)\n\n\t// MustGet acts like Get, but it panics if any error occurs.\n\tk2 := c.MustGet(ctx, \"k2\")\n\tfmt.Println(k2)\n\n\tk1 := c.MustGet(ctx, \"k1\")\n\tfmt.Println(k1)\n\n\t// Output:\n\t// v1\n}\n\nfunc ExampleCache_MustGetOrSet() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// MustGetOrSet acts like GetOrSet, but it panics if any error occurs.\n\tk1 := c.MustGetOrSet(ctx, \"k1\", \"v1\", 0)\n\tfmt.Println(k1)\n\n\tk2 := c.MustGetOrSet(ctx, \"k1\", \"v2\", 0)\n\tfmt.Println(k2)\n\n\t// Output:\n\t// v1\n\t// v1\n}\n\nfunc ExampleCache_MustGetOrSetFunc() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// MustGetOrSetFunc acts like GetOrSetFunc, but it panics if any error occurs.\n\tc.MustGetOrSetFunc(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"v1\", nil\n\t}, 10000*time.Millisecond)\n\tv := c.MustGet(ctx, \"k1\")\n\tfmt.Println(v)\n\n\tc.MustGetOrSetFunc(ctx, \"k2\", func(ctx context.Context) (value any, err error) {\n\t\treturn nil, nil\n\t}, 10000*time.Millisecond)\n\tv1 := c.MustGet(ctx, \"k2\")\n\tfmt.Println(v1)\n\n\t// Output:\n\t// v1\n\t//\n}\n\nfunc ExampleCache_MustGetOrSetFuncLock() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// MustGetOrSetFuncLock acts like GetOrSetFuncLock, but it panics if any error occurs.\n\tc.MustGetOrSetFuncLock(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"v1\", nil\n\t}, 0)\n\tv := c.MustGet(ctx, \"k1\")\n\tfmt.Println(v)\n\n\t// Modification failed\n\tc.MustGetOrSetFuncLock(ctx, \"k1\", func(ctx context.Context) (value any, err error) {\n\t\treturn \"update v1\", nil\n\t}, 0)\n\tv = c.MustGet(ctx, \"k1\")\n\tfmt.Println(v)\n\n\t// Output:\n\t// v1\n\t// v1\n}\n\nfunc ExampleCache_MustContains() {\n\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set Cache\n\tc.Set(ctx, \"k\", \"v\", 0)\n\n\t// MustContains returns true if `key` exists in the cache, or else returns false.\n\t// return true\n\tdata := c.MustContains(ctx, \"k\")\n\tfmt.Println(data)\n\n\t// return false\n\tdata1 := c.MustContains(ctx, \"k1\")\n\tfmt.Println(data1)\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleCache_MustGetExpire() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Set cache without expiration\n\tc.Set(ctx, \"k\", \"v\", 10000*time.Millisecond)\n\n\t// MustGetExpire acts like GetExpire, but it panics if any error occurs.\n\texpire := c.MustGetExpire(ctx, \"k\")\n\tfmt.Println(expire)\n\n\t// May Output:\n\t// 10s\n}\n\nfunc ExampleCache_MustSize() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Add 10 elements without expiration\n\tfor i := 0; i < 10; i++ {\n\t\tc.Set(ctx, i, i, 0)\n\t}\n\n\t// Size returns the number of items in the cache.\n\tn := c.MustSize(ctx)\n\tfmt.Println(n)\n\n\t// Output:\n\t// 10\n}\n\nfunc ExampleCache_MustData() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\n\tdata := c.MustData(ctx)\n\tfmt.Println(data)\n\n\t// May Output:\n\t// map[k1:v1 k2:v2]\n}\n\nfunc ExampleCache_MustKeys() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\n\t// MustKeys acts like Keys, but it panics if any error occurs.\n\tkeys1 := c.MustKeys(ctx)\n\tfmt.Println(keys1)\n\n\t// May Output:\n\t// [k1 k2]\n\n}\n\nfunc ExampleCache_MustKeyStrings() {\n\tc := gcache.New()\n\n\tc.SetMap(ctx, g.MapAnyAny{\"k1\": \"v1\", \"k2\": \"v2\"}, 0)\n\n\t// MustKeyStrings returns all keys in the cache as string slice.\n\t// MustKeyStrings acts like KeyStrings, but it panics if any error occurs.\n\tkeys := c.MustKeyStrings(ctx)\n\tfmt.Println(keys)\n\n\t// May Output:\n\t// [k1 k2]\n}\n\nfunc ExampleCache_MustValues() {\n\t// Create a cache object,\n\t// Of course, you can also easily use the gcache package method directly\n\tc := gcache.New()\n\n\t// Write value\n\tc.Set(ctx, \"k1\", \"v1\", 0)\n\n\t// MustValues returns all values in the cache as slice.\n\tdata := c.MustValues(ctx)\n\tfmt.Println(data)\n\n\t// Output:\n\t// [v1]\n}\n\nfunc ExampleCache_SetAdapter() {\n\tvar (\n\t\terr         error\n\t\tctx         = gctx.New()\n\t\tcache       = gcache.New()\n\t\tredisConfig = &gredis.Config{\n\t\t\tAddress: \"127.0.0.1:6379\",\n\t\t\tDb:      9,\n\t\t}\n\t\tcacheKey   = `key`\n\t\tcacheValue = `value`\n\t)\n\t// Create redis client object.\n\tredis, err := gredis.New(redisConfig)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\t// Create redis cache adapter and set it to cache object.\n\tcache.SetAdapter(gcache.NewAdapterRedis(redis))\n\n\t// Set and Get using cache object.\n\terr = cache.Set(ctx, cacheKey, cacheValue, time.Second)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(cache.MustGet(ctx, cacheKey).String())\n\n\t// Get using redis client.\n\tfmt.Println(redis.MustDo(ctx, \"GET\", cacheKey).String())\n\n\t// May Output:\n\t// value\n\t// value\n}\n\nfunc ExampleCache_GetAdapter() {\n\tvar (\n\t\terr         error\n\t\tctx         = gctx.New()\n\t\tcache       = gcache.New()\n\t\tredisConfig = &gredis.Config{\n\t\t\tAddress: \"127.0.0.1:6379\",\n\t\t\tDb:      10,\n\t\t}\n\t\tcacheKey   = `key`\n\t\tcacheValue = `value`\n\t)\n\tredis, err := gredis.New(redisConfig)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tcache.SetAdapter(gcache.NewAdapterRedis(redis))\n\n\t// Set and Get using cache object.\n\terr = cache.Set(ctx, cacheKey, cacheValue, time.Second)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(cache.MustGet(ctx, cacheKey).String())\n\n\t// Get using redis client.\n\tv, err := cache.GetAdapter().(*gcache.AdapterRedis).Get(ctx, cacheKey)\n\tfmt.Println(err)\n\tfmt.Println(v.String())\n\n\t// May Output:\n\t// value\n\t// <nil>\n\t// value\n}\n"
  },
  {
    "path": "os/gcache/gcache_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcache_test\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/grpool\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\tctx = context.Background()\n)\n\nfunc TestCache_GCache_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(gcache.Set(ctx, 1, 11, 0))\n\t\tdefer gcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\tv, _ := gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t\tb, _ := gcache.Contains(ctx, 1)\n\t\tt.Assert(b, true)\n\t})\n}\n\nfunc TestCache_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := gcache.New()\n\t\tdefer c.Close(ctx)\n\t\tt.Assert(c.Set(ctx, 1, 11, 0), nil)\n\t\tv, _ := c.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t\tb, _ := c.Contains(ctx, 1)\n\t\tt.Assert(b, true)\n\t})\n}\n\nfunc TestCache_Set_Expire(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.Assert(cache.Set(ctx, 2, 22, 100*time.Millisecond), nil)\n\t\tv, _ := cache.Get(ctx, 2)\n\t\tt.Assert(v, 22)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tv, _ = cache.Get(ctx, 2)\n\t\tt.Assert(v, nil)\n\t\ttime.Sleep(3 * time.Second)\n\t\tn, _ := cache.Size(ctx)\n\t\tt.Assert(n, 0)\n\t\tt.Assert(cache.Close(ctx), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.Assert(cache.Set(ctx, 1, 11, 100*time.Millisecond), nil)\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestCache_Update(t *testing.T) {\n\t// gcache\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := guid.S()\n\t\tt.AssertNil(gcache.Set(ctx, key, 11, 3*time.Second))\n\t\texpire1, _ := gcache.GetExpire(ctx, key)\n\t\toldValue, exist, err := gcache.Update(ctx, key, 12)\n\t\tt.AssertNil(err)\n\t\tt.Assert(oldValue, 11)\n\t\tt.Assert(exist, true)\n\n\t\texpire2, _ := gcache.GetExpire(ctx, key)\n\t\tv, _ := gcache.Get(ctx, key)\n\t\tt.Assert(v, 12)\n\t\tt.Assert(math.Ceil(expire1.Seconds()), math.Ceil(expire2.Seconds()))\n\t})\n\t// gcache.Cache\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.AssertNil(cache.Set(ctx, 1, 11, 3*time.Second))\n\n\t\toldValue, exist, err := cache.Update(ctx, 1, 12)\n\t\tt.AssertNil(err)\n\t\tt.Assert(oldValue, 11)\n\t\tt.Assert(exist, true)\n\n\t\texpire1, _ := cache.GetExpire(ctx, 1)\n\t\texpire2, _ := cache.GetExpire(ctx, 1)\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 12)\n\t\tt.Assert(math.Ceil(expire1.Seconds()), math.Ceil(expire2.Seconds()))\n\t})\n}\n\nfunc TestCache_UpdateExpire(t *testing.T) {\n\t// gcache\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := guid.S()\n\t\tt.AssertNil(gcache.Set(ctx, key, 11, 3*time.Second))\n\t\tdefer gcache.Remove(ctx, key)\n\t\toldExpire, _ := gcache.GetExpire(ctx, key)\n\t\tnewExpire := 10 * time.Second\n\t\toldExpire2, err := gcache.UpdateExpire(ctx, key, newExpire)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(oldExpire2, g.Slice{oldExpire, `2.999s`})\n\n\t\te, _ := gcache.GetExpire(ctx, key)\n\t\tt.AssertNE(e, oldExpire)\n\t\te, _ = gcache.GetExpire(ctx, key)\n\t\tt.Assert(math.Ceil(e.Seconds()), 10)\n\t})\n\t// gcache.Cache\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.AssertNil(cache.Set(ctx, 1, 11, 3*time.Second))\n\t\toldExpire, _ := cache.GetExpire(ctx, 1)\n\t\tnewExpire := 10 * time.Second\n\t\toldExpire2, err := cache.UpdateExpire(ctx, 1, newExpire)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(oldExpire2, g.Slice{oldExpire, `2.999s`})\n\n\t\te, _ := cache.GetExpire(ctx, 1)\n\t\tt.AssertNE(e, oldExpire)\n\n\t\te, _ = cache.GetExpire(ctx, 1)\n\t\tt.Assert(math.Ceil(e.Seconds()), 10)\n\t})\n}\n\nfunc TestCache_Keys_Values(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := gcache.New()\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.Assert(c.Set(ctx, i, i*10, 0), nil)\n\t\t}\n\t\tvar (\n\t\t\tkeys, _   = c.Keys(ctx)\n\t\t\tvalues, _ = c.Values(ctx)\n\t\t)\n\t\tt.Assert(len(keys), 10)\n\t\tt.Assert(len(values), 10)\n\t\tt.AssertIN(0, keys)\n\t\tt.AssertIN(90, values)\n\t})\n}\n\nfunc TestCache_LRU(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New(2)\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tt.AssertNil(cache.Set(ctx, i, i, 0))\n\t\t}\n\t\tn, _ := cache.Size(ctx)\n\t\tt.Assert(n, 2)\n\t\tv, _ := cache.Get(ctx, 6)\n\t\tt.AssertNil(v)\n\t\tv, _ = cache.Get(ctx, 9)\n\t\tt.Assert(v, 9)\n\t})\n}\n\nfunc TestCache_LRU_expire(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New(2)\n\t\tt.Assert(cache.Set(ctx, 1, nil, 50*time.Millisecond), nil)\n\n\t\tn, _ := cache.Size(ctx)\n\t\tt.Assert(n, 1)\n\n\t\ttime.Sleep(time.Millisecond * 100)\n\n\t\tn, _ = cache.Size(ctx)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc TestCache_SetIfNotExist(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tok, err := cache.SetIfNotExist(ctx, 1, 11, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tok, err = cache.SetIfNotExist(ctx, 1, 22, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tok, err = cache.SetIfNotExist(ctx, 2, 22, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tv, _ = cache.Get(ctx, 2)\n\t\tt.Assert(v, 22)\n\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\tok, err = gcache.SetIfNotExist(ctx, 1, 11, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tv, _ = gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tok, err = gcache.SetIfNotExist(ctx, 1, 22, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\n\t\tv, _ = gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_SetIfNotExistFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\texist, err := cache.SetIfNotExistFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, true)\n\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\texist, err = cache.SetIfNotExistFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 22, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\n\t\tok, err := gcache.SetIfNotExistFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tv, _ := gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tok, err = gcache.SetIfNotExistFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 22, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\n\t\tv, _ = gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_SetIfNotExistFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\texist, err := cache.SetIfNotExistFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, true)\n\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\texist, err = cache.SetIfNotExistFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 22, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\n\t\texist, err := gcache.SetIfNotExistFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, true)\n\n\t\tv, _ := gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\texist, err = gcache.SetIfNotExistFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 22, nil\n\t\t}, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(exist, false)\n\n\t\tv, _ = gcache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_SetMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.AssertNil(cache.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, 0))\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\tt.AssertNil(gcache.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, 0))\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_GetOrSet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tvalue, err := cache.GetOrSet(ctx, 1, 11, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 11)\n\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t\tvalue, err = cache.GetOrSet(ctx, 1, 111, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 11)\n\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\tvalue, err := gcache.GetOrSet(ctx, 1, 11, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 11)\n\n\t\tv, err := gcache.Get(ctx, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, 11)\n\n\t\tvalue, err = gcache.GetOrSet(ctx, 1, 111, 0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, 11)\n\n\t\tv, err = gcache.Get(ctx, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_GetOrSetFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tcache.GetOrSetFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tcache.GetOrSetFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 111, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\n\t\tgcache.GetOrSetFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tgcache.GetOrSetFunc(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 111, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_GetOrSetFuncLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tcache.GetOrSetFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tv, _ := cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tcache.GetOrSetFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 111, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\tgcache.GetOrSetFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 11, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\n\t\tgcache.GetOrSetFuncLock(ctx, 1, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 111, nil\n\t\t}, 0)\n\t\tv, _ = cache.Get(ctx, 1)\n\t\tt.Assert(v, 11)\n\t})\n}\n\nfunc TestCache_Clear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tcache.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, 0)\n\t\tcache.Clear(ctx)\n\t\tn, _ := cache.Size(ctx)\n\t\tt.Assert(n, 0)\n\t})\n}\n\nfunc TestCache_SetConcurrency(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tpool := grpool.New(4)\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tpool.Add(ctx, func(ctx context.Context) {\n\t\t\t\t\tcache.SetIfNotExist(ctx, 1, 11, 10)\n\t\t\t\t})\n\t\t\t}\n\t\t}()\n\t\ttime.Sleep(2 * time.Second)\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tpool.Add(ctx, func(ctx context.Context) {\n\t\t\t\t\tcache.SetIfNotExist(ctx, 1, nil, 10)\n\t\t\t\t})\n\t\t\t}\n\t\t}()\n\t\ttime.Sleep(2 * time.Second)\n\t})\n}\n\nfunc TestCache_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t{\n\t\t\tcache := gcache.New()\n\t\t\tcache.SetMap(ctx, g.MapAnyAny{\n\t\t\t\t1: 11,\n\t\t\t\t2: 22,\n\t\t\t}, 0)\n\t\t\tb, _ := cache.Contains(ctx, 1)\n\t\t\tt.Assert(b, true)\n\t\t\tv, _ := cache.Get(ctx, 1)\n\t\t\tt.Assert(v, 11)\n\t\t\tdata, _ := cache.Data(ctx)\n\t\t\tt.Assert(data[1], 11)\n\t\t\tt.Assert(data[2], 22)\n\t\t\tt.Assert(data[3], nil)\n\t\t\tn, _ := cache.Size(ctx)\n\t\t\tt.Assert(n, 2)\n\t\t\tkeys, _ := cache.Keys(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{1, 2}).Equal(gset.NewFrom(keys)), true)\n\t\t\tkeyStrs, _ := cache.KeyStrings(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{\"1\", \"2\"}).Equal(gset.NewFrom(keyStrs)), true)\n\t\t\tvalues, _ := cache.Values(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{11, 22}).Equal(gset.NewFrom(values)), true)\n\t\t\tremoveData1, _ := cache.Remove(ctx, 1)\n\t\t\tt.Assert(removeData1, 11)\n\t\t\tn, _ = cache.Size(ctx)\n\t\t\tt.Assert(n, 1)\n\n\t\t\tcache.Remove(ctx, 2)\n\t\t\tn, _ = cache.Size(ctx)\n\t\t\tt.Assert(n, 0)\n\t\t}\n\n\t\tgcache.Remove(ctx, g.Slice{1, 2, 3}...)\n\t\t{\n\t\t\tgcache.SetMap(ctx, g.MapAnyAny{1: 11, 2: 22}, 0)\n\t\t\tb, _ := gcache.Contains(ctx, 1)\n\t\t\tt.Assert(b, true)\n\t\t\tv, _ := gcache.Get(ctx, 1)\n\t\t\tt.Assert(v, 11)\n\t\t\tdata, _ := gcache.Data(ctx)\n\t\t\tt.Assert(data[1], 11)\n\t\t\tt.Assert(data[2], 22)\n\t\t\tt.Assert(data[3], nil)\n\t\t\tn, _ := gcache.Size(ctx)\n\t\t\tt.Assert(n, 2)\n\n\t\t\tkeys, _ := gcache.Keys(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{1, 2}).Equal(gset.NewFrom(keys)), true)\n\t\t\tkeyStrs, _ := gcache.KeyStrings(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{\"1\", \"2\"}).Equal(gset.NewFrom(keyStrs)), true)\n\t\t\tvalues, _ := gcache.Values(ctx)\n\t\t\tt.Assert(gset.NewFrom(g.Slice{11, 22}).Equal(gset.NewFrom(values)), true)\n\t\t\tremoveData1, _ := gcache.Remove(ctx, 1)\n\t\t\tt.Assert(removeData1, 11)\n\t\t\tn, _ = gcache.Size(ctx)\n\t\t\tt.Assert(n, 1)\n\t\t\tgcache.Remove(ctx, 2)\n\t\t\tn, _ = gcache.Size(ctx)\n\t\t\tt.Assert(n, 0)\n\t\t}\n\t})\n}\n\nfunc TestCache_Removes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.New()\n\t\tt.AssertNil(cache.Set(ctx, 1, 11, 0))\n\t\tt.AssertNil(cache.Set(ctx, 2, 22, 0))\n\t\tt.AssertNil(cache.Set(ctx, 3, 33, 0))\n\t\tt.AssertNil(cache.Removes(ctx, g.Slice{2, 3}))\n\n\t\tok, err := cache.Contains(ctx, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tok, err = cache.Contains(ctx, 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNil(gcache.Set(ctx, 1, 11, 0))\n\t\tt.AssertNil(gcache.Set(ctx, 2, 22, 0))\n\t\tt.AssertNil(gcache.Set(ctx, 3, 33, 0))\n\t\tt.AssertNil(gcache.Removes(ctx, g.Slice{2, 3}))\n\n\t\tok, err := gcache.Contains(ctx, 1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, true)\n\n\t\tok, err = gcache.Contains(ctx, 2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc TestCache_Basic_Must(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer gcache.Remove(ctx, g.Slice{1, 2, 3, 4}...)\n\n\t\tt.AssertNil(gcache.Set(ctx, 1, 11, 0))\n\t\tv := gcache.MustGet(ctx, 1)\n\t\tt.Assert(v, 11)\n\t\tgcache.MustGetOrSet(ctx, 2, 22, 0)\n\t\tv = gcache.MustGet(ctx, 2)\n\t\tt.Assert(v, 22)\n\n\t\tgcache.MustGetOrSetFunc(ctx, 3, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 33, nil\n\t\t}, 0)\n\t\tv = gcache.MustGet(ctx, 3)\n\t\tt.Assert(v, 33)\n\n\t\tgcache.GetOrSetFuncLock(ctx, 4, func(ctx context.Context) (value any, err error) {\n\t\t\treturn 44, nil\n\t\t}, 0)\n\t\tv = gcache.MustGet(ctx, 4)\n\t\tt.Assert(v, 44)\n\n\t\tt.Assert(gcache.MustContains(ctx, 1), true)\n\n\t\tt.AssertNil(gcache.Set(ctx, 1, 11, 3*time.Second))\n\t\texpire := gcache.MustGetExpire(ctx, 1)\n\t\tt.AssertGE(expire, 0)\n\n\t\tn := gcache.MustSize(ctx)\n\t\tt.Assert(n, 4)\n\n\t\tdata := gcache.MustData(ctx)\n\t\tt.Assert(len(data), 4)\n\n\t\tkeys := gcache.MustKeys(ctx)\n\t\tt.Assert(len(keys), 4)\n\n\t\tkeyStrings := gcache.MustKeyStrings(ctx)\n\t\tt.Assert(len(keyStrings), 4)\n\n\t\tvalues := gcache.MustValues(ctx)\n\t\tt.Assert(len(values), 4)\n\t})\n}\n\nfunc TestCache_NewWithAdapter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gcache.NewWithAdapter(gcache.NewAdapterMemory())\n\t\tt.AssertNE(cache, nil)\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcfg provides reading, caching and managing for configuration.\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n)\n\n// Config is the configuration management object.\ntype Config struct {\n\tadapter Adapter\n}\n\nconst (\n\t// DefaultInstanceName is the default instance name for instance usage.\n\tDefaultInstanceName = \"config\"\n\t// DefaultConfigFileName is the default configuration file name.\n\tDefaultConfigFileName = \"config\"\n)\n\n// New creates and returns a Config object with default adapter of AdapterFile.\nfunc New() (*Config, error) {\n\tadapterFile, err := NewAdapterFile()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Config{\n\t\tadapter: adapterFile,\n\t}, nil\n}\n\n// NewWithAdapter creates and returns a Config object with given adapter.\nfunc NewWithAdapter(adapter Adapter) *Config {\n\treturn &Config{\n\t\tadapter: adapter,\n\t}\n}\n\n// Instance returns an instance of Config with default settings.\n// The parameter `name` is the name for the instance. But very note that, if the file \"name.toml\"\n// exists in the configuration directory, it then sets it as the default configuration file. The\n// toml file type is the default configuration file type.\nfunc Instance(name ...string) *Config {\n\tvar instanceName = DefaultInstanceName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tinstanceName = name[0]\n\t}\n\treturn localInstances.GetOrSetFuncLock(instanceName, func() *Config {\n\t\tadapterFile, err := NewAdapterFile()\n\t\tif err != nil {\n\t\t\tintlog.Errorf(context.Background(), `%+v`, err)\n\t\t\treturn nil\n\t\t}\n\t\tif instanceName != DefaultInstanceName {\n\t\t\tadapterFile.SetFileName(instanceName)\n\t\t}\n\t\treturn NewWithAdapter(adapterFile)\n\t})\n}\n\n// SetAdapter sets the adapter of the current Config object.\nfunc (c *Config) SetAdapter(adapter Adapter) {\n\tc.adapter = adapter\n}\n\n// GetAdapter returns the adapter of the current Config object.\nfunc (c *Config) GetAdapter() Adapter {\n\treturn c.adapter\n}\n\n// Available checks and returns the configuration service is available.\n// The optional parameter `pattern` specifies certain configuration resource.\n//\n// It returns true if configuration file is present in default AdapterFile, or else false.\n// Note that this function does not return error as it just does simply check for backend configuration service.\nfunc (c *Config) Available(ctx context.Context, resource ...string) (ok bool) {\n\treturn c.adapter.Available(ctx, resource...)\n}\n\n// Get retrieves and returns value by specified `pattern`.\n// It returns all values of current Json object if `pattern` is given empty or string \".\".\n// It returns nil if no value found by `pattern`.\n//\n// It returns a default value specified by `def` if value for `pattern` is not found.\nfunc (c *Config) Get(ctx context.Context, pattern string, def ...any) (*gvar.Var, error) {\n\tvar (\n\t\terr   error\n\t\tvalue any\n\t)\n\tvalue, err = c.adapter.Get(ctx, pattern)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif value == nil {\n\t\tif len(def) > 0 {\n\t\t\treturn gvar.New(def[0]), nil\n\t\t}\n\t\treturn nil, nil\n\t}\n\treturn gvar.New(value), nil\n}\n\n// GetWithEnv returns the configuration value specified by pattern `pattern`.\n// If the configuration value does not exist, then it retrieves and returns the environment value specified by `key`.\n// It returns the default value `def` if none of them exists.\n//\n// Fetching Rules: Environment arguments are in uppercase format, eg: GF_PACKAGE_VARIABLE.\n//\n// Note: This method uses the configuration (adapter) as the primary source, with environment\n// variable as fallback only when the configuration value is not found. If you need standard\n// priority where environment variables can override configuration values, use GetEffective instead.\nfunc (c *Config) GetWithEnv(ctx context.Context, pattern string, def ...any) (*gvar.Var, error) {\n\tvalue, err := c.Get(ctx, pattern)\n\tif err != nil && gerror.Code(err) != gcode.CodeNotFound {\n\t\treturn nil, err\n\t}\n\tif value == nil {\n\t\tif v := genv.Get(utils.FormatEnvKey(pattern)); v != nil {\n\t\t\treturn v, nil\n\t\t}\n\t\tif len(def) > 0 {\n\t\t\treturn gvar.New(def[0]), nil\n\t\t}\n\t\treturn nil, nil\n\t}\n\treturn value, nil\n}\n\n// GetWithCmd returns the configuration value specified by pattern `pattern`.\n// If the configuration value does not exist, then it retrieves and returns the command line option specified by `key`.\n// It returns the default value `def` if none of them exists.\n//\n// Fetching Rules: Command line arguments are in lowercase format, eg: gf.package.variable.\n//\n// Note: This method uses configuration file as the primary source, with command line argument\n// as fallback only when config value is not found. If you need standard priority where\n// command line arguments can override config file values, use GetEffective instead.\nfunc (c *Config) GetWithCmd(ctx context.Context, pattern string, def ...any) (*gvar.Var, error) {\n\tvalue, err := c.Get(ctx, pattern)\n\tif err != nil && gerror.Code(err) != gcode.CodeNotFound {\n\t\treturn nil, err\n\t}\n\tif value == nil {\n\t\tif v := command.GetOpt(utils.FormatCmdKey(pattern)); v != \"\" {\n\t\t\treturn gvar.New(v), nil\n\t\t}\n\t\tif len(def) > 0 {\n\t\t\treturn gvar.New(def[0]), nil\n\t\t}\n\t\treturn nil, nil\n\t}\n\treturn value, nil\n}\n\n// GetEffective returns the configuration value with standard priority (highest to lowest):\n//\n//\tCommand line arguments > Environment variables > Configuration file > Default value\n//\n// This follows the 12-Factor App methodology where higher priority sources can override\n// lower priority ones, allowing runtime configuration without modifying config files.\n//\n// Key format conversion:\n//   - Command line: lowercase with dots, eg: gf.package.variable (--gf.package.variable=value)\n//   - Environment: uppercase with underscores, eg: GF_PACKAGE_VARIABLE\n//\n// Unlike GetWithEnv/GetWithCmd which use config file as primary source, this method\n// treats command line and environment variables as overrides, which is the standard\n// behavior in frameworks like Spring Boot and Viper.\nfunc (c *Config) GetEffective(ctx context.Context, pattern string, def ...any) (*gvar.Var, error) {\n\t// 1. Command line arguments (highest priority)\n\tcmdKey := utils.FormatCmdKey(pattern)\n\tif command.ContainsOpt(cmdKey) {\n\t\treturn gvar.New(command.GetOpt(cmdKey)), nil\n\t}\n\n\t// 2. Environment variables\n\tif v := genv.Get(utils.FormatEnvKey(pattern)); v != nil {\n\t\treturn v, nil\n\t}\n\n\t// 3. Configuration file\n\tvalue, err := c.Get(ctx, pattern)\n\tif err != nil && gerror.Code(err) != gcode.CodeNotFound {\n\t\treturn nil, err\n\t}\n\tif value != nil {\n\t\treturn value, nil\n\t}\n\n\t// 4. Default value\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0]), nil\n\t}\n\treturn nil, nil\n}\n\n// Data retrieves and returns all configuration data as map type.\nfunc (c *Config) Data(ctx context.Context) (data map[string]any, err error) {\n\treturn c.adapter.Data(ctx)\n}\n\n// MustGet acts as function Get, but it panics if error occurs.\nfunc (c *Config) MustGet(ctx context.Context, pattern string, def ...any) *gvar.Var {\n\tv, err := c.Get(ctx, pattern, def...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn v\n}\n\n// MustGetWithEnv acts as function GetWithEnv, but it panics if error occurs.\nfunc (c *Config) MustGetWithEnv(ctx context.Context, pattern string, def ...any) *gvar.Var {\n\tv, err := c.GetWithEnv(ctx, pattern, def...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetWithCmd acts as function GetWithCmd, but it panics if error occurs.\nfunc (c *Config) MustGetWithCmd(ctx context.Context, pattern string, def ...any) *gvar.Var {\n\tv, err := c.GetWithCmd(ctx, pattern, def...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustGetEffective acts as function GetEffective, but it panics if error occurs.\nfunc (c *Config) MustGetEffective(ctx context.Context, pattern string, def ...any) *gvar.Var {\n\tv, err := c.GetEffective(ctx, pattern, def...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustData acts as function Data, but it panics if error occurs.\nfunc (c *Config) MustData(ctx context.Context) map[string]any {\n\tv, err := c.Data(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adaper.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport \"context\"\n\n// Adapter is the interface for configuration retrieving.\ntype Adapter interface {\n\t// Available checks and returns the backend configuration service is available.\n\t// The optional parameter `resource` specifies certain configuration resource.\n\t//\n\t// Note that this function does not return error as it just does simply check for\n\t// backend configuration service.\n\tAvailable(ctx context.Context, resource ...string) (ok bool)\n\n\t// Get retrieves and returns value by specified `pattern` in current resource.\n\t// Pattern like:\n\t// \"x.y.z\" for map item.\n\t// \"x.0.y\" for slice item.\n\tGet(ctx context.Context, pattern string) (value any, err error)\n\n\t// Data retrieves and returns all configuration data in current resource as map.\n\t// Note that this function may lead lots of memory usage if configuration data is too large,\n\t// you can implement this function if necessary.\n\tData(ctx context.Context) (data map[string]any, err error)\n}\n\n// WatcherFunc is the callback function type for configuration watchers.\ntype WatcherFunc = func(context.Context)\n\n// WatcherAdapter is the interface for configuration watcher.\ntype WatcherAdapter interface {\n\t// AddWatcher adds a watcher function for specified `pattern` and `resource`.\n\tAddWatcher(name string, fn WatcherFunc)\n\t// RemoveWatcher removes the watcher function for specified `pattern` and `resource`.\n\tRemoveWatcher(name string)\n\t// GetWatcherNames returns all watcher names.\n\tGetWatcherNames() []string\n\t// IsWatching checks and returns whether the specified `pattern` is watching.\n\tIsWatching(name string) bool\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_content.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ Adapter        = (*AdapterContent)(nil)\n\t_ WatcherAdapter = (*AdapterContent)(nil)\n)\n\n// AdapterContent implements interface Adapter using content.\n// The configuration content supports the coding types as package `gjson`.\ntype AdapterContent struct {\n\tjsonVar  *gvar.Var        // The pared JSON object for configuration content, type: *gjson.Json.\n\twatchers *WatcherRegistry // Watchers for watching file changes.\n}\n\n// NewAdapterContent returns a new configuration management object using custom content.\n// The parameter `content` specifies the default configuration content for reading.\nfunc NewAdapterContent(content ...string) (*AdapterContent, error) {\n\ta := &AdapterContent{\n\t\tjsonVar:  gvar.New(nil, true),\n\t\twatchers: NewWatcherRegistry(),\n\t}\n\tif len(content) > 0 {\n\t\tif err := a.SetContent(content[0]); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn a, nil\n}\n\n// SetContent sets customized configuration content for specified `file`.\n// The `file` is unnecessary param, default is DefaultConfigFile.\nfunc (a *AdapterContent) SetContent(content string) error {\n\tj, err := gjson.LoadContent([]byte(content), true)\n\tif err != nil {\n\t\treturn gerror.Wrap(err, `load configuration content failed`)\n\t}\n\ta.jsonVar.Set(j)\n\tadapterCtx := NewAdapterContentCtx().WithOperation(OperationSet).WithContent(content)\n\ta.notifyWatchers(adapterCtx.Ctx)\n\treturn nil\n}\n\n// Available checks and returns the backend configuration service is available.\n// The optional parameter `resource` specifies certain configuration resource.\n//\n// Note that this function does not return error as it just does simply check for\n// backend configuration service.\nfunc (a *AdapterContent) Available(ctx context.Context, resource ...string) (ok bool) {\n\treturn !a.jsonVar.IsNil()\n}\n\n// Get retrieves and returns value by specified `pattern` in current resource.\n// Pattern like:\n// \"x.y.z\" for map item.\n// \"x.0.y\" for slice item.\nfunc (a *AdapterContent) Get(ctx context.Context, pattern string) (value any, err error) {\n\tif a.jsonVar.IsNil() {\n\t\treturn nil, nil\n\t}\n\treturn a.jsonVar.Val().(*gjson.Json).Get(pattern).Val(), nil\n}\n\n// Data retrieves and returns all configuration data in current resource as map.\n// Note that this function may lead lots of memory usage if configuration data is too large,\n// you can implement this function if necessary.\nfunc (a *AdapterContent) Data(ctx context.Context) (data map[string]any, err error) {\n\tif a.jsonVar.IsNil() {\n\t\treturn nil, nil\n\t}\n\treturn a.jsonVar.Val().(*gjson.Json).Var().Map(), nil\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (a *AdapterContent) AddWatcher(name string, fn WatcherFunc) {\n\ta.watchers.Add(name, fn)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (a *AdapterContent) RemoveWatcher(name string) {\n\ta.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (a *AdapterContent) GetWatcherNames() []string {\n\treturn a.watchers.GetNames()\n}\n\n// IsWatching checks and returns whether the specified `name` is watching.\nfunc (a *AdapterContent) IsWatching(name string) bool {\n\treturn a.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (a *AdapterContent) notifyWatchers(ctx context.Context) {\n\ta.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_content_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcfg provides reading, caching and managing for configuration.\npackage gcfg\n\nimport (\n\t\"context\"\n)\n\n// AdapterContentCtx is the context for AdapterContent.\ntype AdapterContentCtx struct {\n\t// Ctx is the context with configuration values\n\tCtx context.Context\n}\n\n// NewAdapterContentCtxWithCtx creates and returns a new AdapterContentCtx with the given context.\nfunc NewAdapterContentCtxWithCtx(ctx context.Context) *AdapterContentCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &AdapterContentCtx{Ctx: ctx}\n}\n\n// NewAdapterContentCtx creates and returns a new AdapterContentCtx.\n// If ctx is provided, it uses that context, otherwise it creates a background context.\nfunc NewAdapterContentCtx(ctx ...context.Context) *AdapterContentCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterContentCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterContentCtxWithCtx(context.Background())\n}\n\n// GetAdapterContentCtx creates and returns an AdapterContentCtx with the given context.\nfunc GetAdapterContentCtx(ctx context.Context) *AdapterContentCtx {\n\treturn NewAdapterContentCtxWithCtx(ctx)\n}\n\n// WithOperation sets the operation in the context and returns the updated AdapterContentCtx.\nfunc (a *AdapterContentCtx) WithOperation(operation OperationType) *AdapterContentCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyOperation, operation)\n\treturn a\n}\n\n// WithContent sets the content in the context and returns the updated AdapterContentCtx.\nfunc (a *AdapterContentCtx) WithContent(content string) *AdapterContentCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyContent, content)\n\treturn a\n}\n\n// GetOperation retrieves the operation from the context.\n// Returns empty string if not found.\nfunc (a *AdapterContentCtx) GetOperation() OperationType {\n\tif v := a.Ctx.Value(ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetContent retrieves the content from the context.\n// Returns empty string if not found.\nfunc (a *AdapterContentCtx) GetContent() string {\n\tif v := a.Ctx.Value(ContextKeyContent); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/util/gmode\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\t// Compile-time checking for interface implementation.\n\t_ Adapter        = (*AdapterFile)(nil)\n\t_ WatcherAdapter = (*AdapterFile)(nil)\n)\n\n// AdapterFile implements interface Adapter using file.\ntype AdapterFile struct {\n\tdefaultFileNameOrPath *gtype.String                    // Default configuration file name or file path.\n\tsearchPaths           *garray.StrArray                 // Searching the path array.\n\tjsonMap               *gmap.KVMap[string, *gjson.Json] // The parsed JSON objects for configuration files.\n\tviolenceCheck         bool                             // Whether it does violence check in value index searching. It affects the performance when set true(false in default).\n\twatchers              *WatcherRegistry                 // Watchers for watching file changes.\n}\n\nconst (\n\tcommandEnvKeyForFile = \"gf.gcfg.file\" // commandEnvKeyForFile is the configuration key for command argument or environment configuring file name.\n\tcommandEnvKeyForPath = \"gf.gcfg.path\" // commandEnvKeyForPath is the configuration key for command argument or environment configuring directory path.\n)\n\nvar (\n\tsupportedFileTypes     = []string{\"toml\", \"yaml\", \"yml\", \"json\", \"ini\", \"xml\", \"properties\"} // All supported file types suffixes.\n\tchecker                = func(v *Config) bool { return v == nil }\n\tlocalInstances         = gmap.NewKVMapWithChecker[string, *Config](checker, true) // Instances map containing configuration instances.\n\tcustomConfigContentMap = gmap.NewStrStrMap(true)                                  // Customized configuration content.\n\n\t// Prefix array for trying searching in resource manager.\n\tresourceTryFolders = []string{\n\t\t\"\", \"/\", \"config/\", \"config\", \"/config\", \"/config/\",\n\t\t\"manifest/config/\", \"manifest/config\", \"/manifest/config\", \"/manifest/config/\",\n\t}\n\n\t// Prefix array for trying searching in the local system.\n\tlocalSystemTryFolders = []string{\"\", \"config/\", \"manifest/config\"}\n\n\t// jsonMapChecker is the checker for JSON map.\n\tjsonMapChecker = func(v *gjson.Json) bool { return v == nil }\n)\n\n// NewAdapterFile returns a new configuration management object.\n// The parameter `file` specifies the default configuration file name for reading.\nfunc NewAdapterFile(fileNameOrPath ...string) (*AdapterFile, error) {\n\tvar (\n\t\terr                error\n\t\tusedFileNameOrPath = DefaultConfigFileName\n\t)\n\tif len(fileNameOrPath) > 0 {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t} else {\n\t\t// Custom default configuration file name from command line or environment.\n\t\tif customFile := command.GetOptWithEnv(commandEnvKeyForFile); customFile != \"\" {\n\t\t\tusedFileNameOrPath = customFile\n\t\t}\n\t}\n\tconfig := &AdapterFile{\n\t\tdefaultFileNameOrPath: gtype.NewString(usedFileNameOrPath),\n\t\tsearchPaths:           garray.NewStrArray(true),\n\t\tjsonMap:               gmap.NewKVMapWithChecker[string, *gjson.Json](jsonMapChecker, true),\n\t\twatchers:              NewWatcherRegistry(),\n\t}\n\t// Customized dir path from env/cmd.\n\tif customPath := command.GetOptWithEnv(commandEnvKeyForPath); customPath != \"\" {\n\t\tif gfile.Exists(customPath) {\n\t\t\tif err = config.SetPath(customPath); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, gerror.Newf(`configuration directory path \"%s\" does not exist`, customPath)\n\t\t}\n\t} else {\n\t\t// ================================================================================\n\t\t// Automatic searching directories.\n\t\t// It does not affect adapter object cresting if these directories do not exist.\n\t\t// ================================================================================\n\n\t\t// Dir path of working dir.\n\t\tif err = config.AddPath(gfile.Pwd()); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\n\t\t// Dir path of the main package.\n\t\tif mainPath := gfile.MainPkgPath(); mainPath != \"\" && gfile.Exists(mainPath) {\n\t\t\tif err = config.AddPath(mainPath); err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t}\n\t\t}\n\n\t\t// Dir path of binary.\n\t\tif selfPath := gfile.SelfDir(); selfPath != \"\" && gfile.Exists(selfPath) {\n\t\t\tif err = config.AddPath(selfPath); err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn config, nil\n}\n\n// SetViolenceCheck sets whether to perform hierarchical conflict checking.\n// This feature needs to be enabled when there is a level symbol in the key name.\n// It is off in default.\n//\n// Note that turning on this feature is quite expensive, and it is not recommended\n// allowing separators in the key names. It is best to avoid this on the application side.\nfunc (a *AdapterFile) SetViolenceCheck(check bool) {\n\ta.violenceCheck = check\n\ta.Clear()\n}\n\n// SetFileName sets the default configuration file name.\nfunc (a *AdapterFile) SetFileName(fileNameOrPath string) {\n\ta.defaultFileNameOrPath.Set(fileNameOrPath)\n}\n\n// GetFileName returns the default configuration file name.\nfunc (a *AdapterFile) GetFileName() string {\n\treturn a.defaultFileNameOrPath.String()\n}\n\n// Get retrieves and returns value by specified `pattern`.\n// It returns all values of the current JSON object if `pattern` is given empty or string \".\".\n// It returns nil if no value found by `pattern`.\n//\n// We can also access slice item by its index number in `pattern` like:\n// \"list.10\", \"array.0.name\", \"array.0.1.id\".\n//\n// It returns a default value specified by `def` if value for `pattern` is not found.\nfunc (a *AdapterFile) Get(ctx context.Context, pattern string) (value any, err error) {\n\tj, err := a.getJson()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif j != nil {\n\t\treturn j.Get(pattern).Val(), nil\n\t}\n\treturn nil, nil\n}\n\n// Set sets value with specified `pattern`.\n// It supports hierarchical data access by char separator, which is '.' in default.\n// It is commonly used to update certain configuration values in runtime.\n// Note that it is not recommended using `Set` configuration at runtime as the configuration would be\n// automatically refreshed if the underlying configuration file changed.\nfunc (a *AdapterFile) Set(pattern string, value any) error {\n\tj, err := a.getJson()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif j != nil {\n\t\terr = j.Set(pattern, value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfileName := a.GetFileName()\n\tfilePath, _ := a.GetFilePath(fileName)\n\tfileType := gfile.ExtName(fileName)\n\tadapterCtx := NewAdapterFileCtx().WithOperation(OperationSet).WithKey(pattern).WithValue(value).\n\t\tWithFileName(fileName).WithFilePath(filePath).WithFileType(fileType)\n\ta.notifyWatchers(adapterCtx.Ctx)\n\treturn nil\n}\n\n// Data retrieves and returns all configuration data as map type.\nfunc (a *AdapterFile) Data(ctx context.Context) (data map[string]any, err error) {\n\tj, err := a.getJson()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif j != nil {\n\t\treturn j.Var().Map(), nil\n\t}\n\treturn nil, nil\n}\n\n// MustGet acts as a function, but it panics if error occurs.\nfunc (a *AdapterFile) MustGet(ctx context.Context, pattern string) *gvar.Var {\n\tv, err := a.Get(ctx, pattern)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn gvar.New(v)\n}\n\n// Clear removes all parsed configuration files content cache,\n// which will force reload configuration content from the file.\nfunc (a *AdapterFile) Clear() {\n\ta.jsonMap.Clear()\n\tfileName := a.GetFileName()\n\tfilePath, _ := a.GetFilePath(fileName)\n\tfileType := gfile.ExtName(fileName)\n\tadapterFileCtx := NewAdapterFileCtx().WithOperation(OperationClear).WithFileName(fileName).WithFilePath(filePath).WithFileType(fileType)\n\ta.notifyWatchers(adapterFileCtx.Ctx)\n}\n\n// Dump prints current JSON object with more manually readable.\nfunc (a *AdapterFile) Dump() {\n\tif j, _ := a.getJson(); j != nil {\n\t\tj.Dump()\n\t}\n}\n\n// Available checks and returns whether configuration of given `file` is available.\nfunc (a *AdapterFile) Available(ctx context.Context, fileName ...string) bool {\n\tcheckFileName := gutil.GetOrDefaultStr(a.defaultFileNameOrPath.String(), fileName...)\n\t// Custom configuration content exists.\n\tif a.GetContent(checkFileName) != \"\" {\n\t\treturn true\n\t}\n\t// Configuration file exists in the system path.\n\tif path, _ := a.GetFilePath(checkFileName); path != \"\" {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// autoCheckAndAddMainPkgPathToSearchPaths automatically checks and adds the directory path of package main\n// to the searching path list if it's currently in the development environment.\nfunc (a *AdapterFile) autoCheckAndAddMainPkgPathToSearchPaths() {\n\tif gmode.IsDevelop() {\n\t\tmainPkgPath := gfile.MainPkgPath()\n\t\tif mainPkgPath != \"\" {\n\t\t\tif !a.searchPaths.Contains(mainPkgPath) {\n\t\t\t\ta.searchPaths.Append(mainPkgPath)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// getJson returns a *gjson.Json object for the specified `file` content.\n// It would print error if file reading fails. It returns nil if any error occurs.\nfunc (a *AdapterFile) getJson(fileNameOrPath ...string) (configJson *gjson.Json, err error) {\n\tusedFileNameOrPath := a.GetFileName()\n\tif len(fileNameOrPath) > 0 && fileNameOrPath[0] != \"\" {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t}\n\t// It uses JSON map to cache specified configuration file content.\n\tresult := a.jsonMap.GetOrSetFuncLock(usedFileNameOrPath, func() *gjson.Json {\n\t\tvar (\n\t\t\tcontent  string\n\t\t\tfilePath string\n\t\t)\n\t\t// The configured content can be any kind of data type different from its file type.\n\t\tisFromConfigContent := true\n\t\tif content = a.GetContent(usedFileNameOrPath); content == \"\" {\n\t\t\tisFromConfigContent = false\n\t\t\tfilePath, err = a.GetFilePath(usedFileNameOrPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif filePath == \"\" {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif file := gres.Get(filePath); file != nil {\n\t\t\t\tcontent = string(file.Content())\n\t\t\t} else {\n\t\t\t\tcontent = gfile.GetContents(filePath)\n\t\t\t}\n\t\t}\n\t\t// Note that the underlying configuration JSON object operations are concurrent safe.\n\t\tdataType := gjson.ContentType(gfile.ExtName(filePath))\n\t\tif gjson.IsValidDataType(dataType) && !isFromConfigContent {\n\t\t\tconfigJson, err = gjson.LoadContentType(dataType, []byte(content), true)\n\t\t} else {\n\t\t\tconfigJson, err = gjson.LoadContent([]byte(content), true)\n\t\t}\n\t\tif err != nil {\n\t\t\tif filePath != \"\" {\n\t\t\t\terr = gerror.Wrapf(err, `load config file \"%s\" failed`, filePath)\n\t\t\t} else {\n\t\t\t\terr = gerror.Wrap(err, `load configuration failed`)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tconfigJson.SetViolenceCheck(a.violenceCheck)\n\t\t// Add monitor for this configuration file,\n\t\t// any changes of this file will refresh its cache in the Config object.\n\t\tif filePath != \"\" && !gres.Contains(filePath) {\n\t\t\t_, err := gfsnotify.Add(filePath, func(event *gfsnotify.Event) {\n\t\t\t\ta.jsonMap.Remove(usedFileNameOrPath)\n\t\t\t\tif event.IsWrite() || event.IsRemove() || event.IsCreate() || event.IsRename() || event.IsChmod() {\n\t\t\t\t\tfileType := gfile.ExtName(usedFileNameOrPath)\n\t\t\t\t\tadapterCtx := NewAdapterFileCtx().WithFileName(usedFileNameOrPath).WithFilePath(filePath).WithFileType(fileType)\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase event.IsWrite():\n\t\t\t\t\t\tadapterCtx.WithOperation(OperationWrite)\n\t\t\t\t\tcase event.IsRemove():\n\t\t\t\t\t\tadapterCtx.WithOperation(OperationRemove)\n\t\t\t\t\tcase event.IsCreate():\n\t\t\t\t\t\tadapterCtx.WithOperation(OperationCreate)\n\t\t\t\t\tcase event.IsRename():\n\t\t\t\t\t\tadapterCtx.WithOperation(OperationRename)\n\t\t\t\t\tcase event.IsChmod():\n\t\t\t\t\t\tadapterCtx.WithOperation(OperationChmod)\n\t\t\t\t\t}\n\t\t\t\t\ta.notifyWatchers(adapterCtx.Ctx)\n\t\t\t\t}\n\t\t\t\t_ = event.Watcher.Remove(filePath)\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), \"failed listen config file event[%s]: %v\", filePath, err)\n\t\t\t}\n\t\t}\n\t\treturn configJson\n\t})\n\tif result != nil {\n\t\treturn result, err\n\t}\n\treturn\n}\n\n// AddWatcher adds a watcher for the specified configuration file.\nfunc (a *AdapterFile) AddWatcher(name string, fn WatcherFunc) {\n\ta.watchers.Add(name, fn)\n}\n\n// RemoveWatcher removes the watcher for the specified configuration file.\nfunc (a *AdapterFile) RemoveWatcher(name string) {\n\ta.watchers.Remove(name)\n}\n\n// GetWatcherNames returns all watcher names.\nfunc (a *AdapterFile) GetWatcherNames() []string {\n\treturn a.watchers.GetNames()\n}\n\n// IsWatching checks and returns whether the specified `name` is watching.\nfunc (a *AdapterFile) IsWatching(name string) bool {\n\treturn a.watchers.IsWatching(name)\n}\n\n// notifyWatchers notifies all watchers.\nfunc (a *AdapterFile) notifyWatchers(ctx context.Context) {\n\ta.watchers.Notify(ctx)\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_file_content.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// SetContent sets customized configuration content for specified `file`.\n// The `file` is unnecessary param, default is DefaultConfigFile.\nfunc (a *AdapterFile) SetContent(content string, fileNameOrPath ...string) {\n\tvar usedFileNameOrPath = DefaultConfigFileName\n\tif len(fileNameOrPath) > 0 {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t}\n\t// Clear file cache for instances which cached `name`.\n\tlocalInstances.LockFunc(func(m map[string]*Config) {\n\t\tif customConfigContentMap.Contains(usedFileNameOrPath) {\n\t\t\tfor _, v := range m {\n\t\t\t\tif fileConfig, ok := v.GetAdapter().(*AdapterFile); ok {\n\t\t\t\t\tfileConfig.jsonMap.Remove(usedFileNameOrPath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcustomConfigContentMap.Set(usedFileNameOrPath, content)\n\t})\n\tadapterCtx := NewAdapterFileCtx().WithFileName(usedFileNameOrPath).WithOperation(OperationSet).WithContent(content)\n\ta.notifyWatchers(adapterCtx.Ctx)\n}\n\n// GetContent returns customized configuration content for specified `file`.\n// The `file` is unnecessary param, default is DefaultConfigFile.\nfunc (a *AdapterFile) GetContent(fileNameOrPath ...string) string {\n\tvar usedFileNameOrPath = DefaultConfigFileName\n\tif len(fileNameOrPath) > 0 {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t}\n\treturn customConfigContentMap.Get(usedFileNameOrPath)\n}\n\n// RemoveContent removes the global configuration with specified `file`.\n// If `name` is not passed, it removes configuration of the default group name.\nfunc (a *AdapterFile) RemoveContent(fileNameOrPath ...string) {\n\tvar usedFileNameOrPath = DefaultConfigFileName\n\tif len(fileNameOrPath) > 0 {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t}\n\t// Clear file cache for instances which cached `name`.\n\tlocalInstances.LockFunc(func(m map[string]*Config) {\n\t\tif customConfigContentMap.Contains(usedFileNameOrPath) {\n\t\t\tfor _, v := range m {\n\t\t\t\tif fileConfig, ok := v.GetAdapter().(*AdapterFile); ok {\n\t\t\t\t\tfileConfig.jsonMap.Remove(usedFileNameOrPath)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcustomConfigContentMap.Remove(usedFileNameOrPath)\n\t\t}\n\t})\n\tadapterCtx := NewAdapterFileCtx().WithFileName(usedFileNameOrPath).WithOperation(OperationRemove)\n\ta.notifyWatchers(adapterCtx.Ctx)\n\tintlog.Printf(context.TODO(), `RemoveContent: %s`, usedFileNameOrPath)\n}\n\n// ClearContent removes all global configuration contents.\nfunc (a *AdapterFile) ClearContent() {\n\tcustomConfigContentMap.Clear()\n\t// Clear cache for all instances.\n\tlocalInstances.LockFunc(func(m map[string]*Config) {\n\t\tfor _, v := range m {\n\t\t\tif fileConfig, ok := v.GetAdapter().(*AdapterFile); ok {\n\t\t\t\tfileConfig.jsonMap.Clear()\n\t\t\t}\n\t\t}\n\t})\n\tadapterCtx := NewAdapterFileCtx().WithOperation(OperationClear)\n\ta.notifyWatchers(adapterCtx.Ctx)\n\tintlog.Print(context.TODO(), `RemoveConfig`)\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_file_ctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcfg provides reading, caching and managing for configuration.\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\n// AdapterFileCtx is the context for AdapterFile.\ntype AdapterFileCtx struct {\n\t// Ctx is the context with configuration values\n\tCtx context.Context\n}\n\n// NewAdapterFileCtxWithCtx creates and returns a new AdapterFileCtx with the given context.\nfunc NewAdapterFileCtxWithCtx(ctx context.Context) *AdapterFileCtx {\n\tif ctx == nil {\n\t\tctx = context.Background()\n\t}\n\treturn &AdapterFileCtx{Ctx: ctx}\n}\n\n// NewAdapterFileCtx creates and returns a new AdapterFileCtx.\n// If ctx is provided, it uses that context, otherwise it creates a background context.\nfunc NewAdapterFileCtx(ctx ...context.Context) *AdapterFileCtx {\n\tif len(ctx) > 0 {\n\t\treturn NewAdapterFileCtxWithCtx(ctx[0])\n\t}\n\treturn NewAdapterFileCtxWithCtx(context.Background())\n}\n\n// GetAdapterFileCtx creates and returns an AdapterFileCtx with the given context.\nfunc GetAdapterFileCtx(ctx context.Context) *AdapterFileCtx {\n\treturn NewAdapterFileCtxWithCtx(ctx)\n}\n\n// WithFileName sets the file name in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithFileName(fileName string) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyFileName, fileName)\n\treturn a\n}\n\n// WithFilePath sets the file path in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithFilePath(filePath string) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyFilePath, filePath)\n\treturn a\n}\n\n// WithFileType sets the file type in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithFileType(fileType string) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyFileType, fileType)\n\treturn a\n}\n\n// WithOperation sets the operation in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithOperation(operation OperationType) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyOperation, operation)\n\treturn a\n}\n\n// WithKey sets the key in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithKey(key string) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyKey, key)\n\treturn a\n}\n\n// WithValue sets the value in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithValue(value any) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyValue, value)\n\treturn a\n}\n\n// WithContent sets the content in the context and returns the updated AdapterFileCtx.\nfunc (a *AdapterFileCtx) WithContent(content any) *AdapterFileCtx {\n\ta.Ctx = context.WithValue(a.Ctx, ContextKeyContent, content)\n\treturn a\n}\n\n// GetFileName retrieves the file name from the context.\n// Returns empty string if not found.\nfunc (a *AdapterFileCtx) GetFileName() string {\n\tif v := a.Ctx.Value(ContextKeyFileName); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetFilePath retrieves the file path from the context.\n// Returns empty string if not found.\nfunc (a *AdapterFileCtx) GetFilePath() string {\n\tif v := a.Ctx.Value(ContextKeyFilePath); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetFileType retrieves the file type from the context.\n// Returns empty string if not found.\nfunc (a *AdapterFileCtx) GetFileType() string {\n\tif v := a.Ctx.Value(ContextKeyFileType); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetOperation retrieves the operation from the context.\n// Returns empty string if not found.\nfunc (a *AdapterFileCtx) GetOperation() OperationType {\n\tif v := a.Ctx.Value(ContextKeyOperation); v != nil {\n\t\tif s, ok := v.(OperationType); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetKey retrieves the key from the context.\n// Returns empty string if not found.\nfunc (a *AdapterFileCtx) GetKey() string {\n\tif v := a.Ctx.Value(ContextKeyKey); v != nil {\n\t\tif s, ok := v.(string); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// GetValue retrieves the value from the context.\n// Returns nil if not found.\nfunc (a *AdapterFileCtx) GetValue() *gvar.Var {\n\tif v := a.Ctx.Value(ContextKeyValue); v != nil {\n\t\treturn gvar.New(v)\n\t}\n\treturn nil\n}\n\n// GetContent retrieves the set content from the context.\n// Returns nil if not found.\nfunc (a *AdapterFileCtx) GetContent() *gvar.Var {\n\tif v := a.Ctx.Value(ContextKeyContent); v != nil {\n\t\treturn gvar.New(v)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_adapter_file_path.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gspath\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SetPath sets the configuration `directory` path for file search.\n// The parameter `path` can be absolute or relative `directory` path,\n// but absolute `directory` path is strongly recommended.\n//\n// Note that this parameter is a path to a directory not a file.\nfunc (a *AdapterFile) SetPath(directoryPath string) (err error) {\n\tvar (\n\t\tisDir    = false\n\t\trealPath = \"\"\n\t)\n\tif file := gres.Get(directoryPath); file != nil {\n\t\trealPath = directoryPath\n\t\tisDir = file.FileInfo().IsDir()\n\t} else {\n\t\t// Absolute path.\n\t\trealPath = gfile.RealPath(directoryPath)\n\t\tif realPath == \"\" {\n\t\t\t// Relative path.\n\t\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor _, v := range array {\n\t\t\t\t\tif searchedPath, _ := gspath.Search(v, directoryPath); searchedPath != \"\" {\n\t\t\t\t\t\trealPath = searchedPath\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tif realPath != \"\" {\n\t\t\tisDir = gfile.IsDir(realPath)\n\t\t}\n\t}\n\t// Path not exist.\n\tif realPath == \"\" {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tif a.searchPaths.Len() > 0 {\n\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t`SetPath failed: cannot find directory \"%s\" in following paths:`,\n\t\t\t\tdirectoryPath,\n\t\t\t)\n\t\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor k, v := range array {\n\t\t\t\t\tfmt.Fprintf(buffer, \"\\n%d. %s\", k+1, v)\n\t\t\t\t}\n\t\t\t})\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t`SetPath failed: path \"%s\" does not exist`,\n\t\t\t\tdirectoryPath,\n\t\t\t)\n\t\t}\n\t\treturn gerror.New(buffer.String())\n\t}\n\t// Should be a directory.\n\tif !isDir {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`SetPath failed: path \"%s\" should be directory type`,\n\t\t\tdirectoryPath,\n\t\t)\n\t}\n\t// Repeated path check.\n\tif a.searchPaths.Search(realPath) != -1 {\n\t\treturn nil\n\t}\n\ta.jsonMap.Clear()\n\ta.searchPaths.Clear()\n\ta.searchPaths.Append(realPath)\n\tintlog.Print(context.TODO(), \"SetPath:\", realPath)\n\treturn nil\n}\n\n// AddPath adds an absolute or relative `directory` path to the search paths.\n//\n// Note that this parameter is paths to a directories not files.\nfunc (a *AdapterFile) AddPath(directoryPaths ...string) (err error) {\n\tfor _, directoryPath := range directoryPaths {\n\t\tif err = a.doAddPath(directoryPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// doAddPath adds an absolute or relative `directory` path to the search paths.\nfunc (a *AdapterFile) doAddPath(directoryPath string) (err error) {\n\tvar (\n\t\tisDir    = false\n\t\trealPath = \"\"\n\t)\n\t// It firstly checks the resource manager,\n\t// and then checks the filesystem for the path.\n\tif file := gres.Get(directoryPath); file != nil {\n\t\trealPath = directoryPath\n\t\tisDir = file.FileInfo().IsDir()\n\t} else {\n\t\t// Absolute path.\n\t\trealPath = gfile.RealPath(directoryPath)\n\t\tif realPath == \"\" {\n\t\t\t// Relative path.\n\t\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor _, v := range array {\n\t\t\t\t\tif searchedPath, _ := gspath.Search(v, directoryPath); searchedPath != \"\" {\n\t\t\t\t\t\trealPath = searchedPath\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tif realPath != \"\" {\n\t\t\tisDir = gfile.IsDir(realPath)\n\t\t}\n\t}\n\tif realPath == \"\" {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tif a.searchPaths.Len() > 0 {\n\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t`AddPath failed: cannot find directory \"%s\" in following paths:`,\n\t\t\t\tdirectoryPath)\n\t\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor k, v := range array {\n\t\t\t\t\tfmt.Fprintf(buffer, \"\\n%d. %s\", k+1, v)\n\t\t\t\t}\n\t\t\t})\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t`AddPath failed: path \"%s\" does not exist`,\n\t\t\t\tdirectoryPath)\n\t\t}\n\t\treturn gerror.New(buffer.String())\n\t}\n\tif !isDir {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`AddPath failed: path \"%s\" should be directory type`,\n\t\t\tdirectoryPath,\n\t\t)\n\t}\n\t// Repeated path check.\n\tif a.searchPaths.Search(realPath) != -1 {\n\t\treturn nil\n\t}\n\ta.searchPaths.Append(realPath)\n\tintlog.Print(context.TODO(), \"AddPath:\", realPath)\n\treturn nil\n}\n\n// GetPaths returns the searching directory path array of current configuration manager.\nfunc (a *AdapterFile) GetPaths() []string {\n\treturn a.searchPaths.Slice()\n}\n\n// doGetFilePath returns the absolute configuration file path for the given filename by `fileNameOrPath`.\n// The `fileNameOrPath` can be either a file name or the file path.\nfunc (a *AdapterFile) doGetFilePath(fileNameOrPath string) (filePath string) {\n\tvar (\n\t\ttempPath string\n\t\tresFile  *gres.File\n\t\tfileInfo os.FileInfo\n\t)\n\t// Searching resource manager.\n\tif !gres.IsEmpty() {\n\t\tfor _, tryFolder := range resourceTryFolders {\n\t\t\ttempPath = tryFolder + fileNameOrPath\n\t\t\tif resFile = gres.Get(tempPath); resFile != nil {\n\t\t\t\tfileInfo, _ = resFile.Stat()\n\t\t\t\tif fileInfo != nil && !fileInfo.IsDir() {\n\t\t\t\t\tfilePath = resFile.Name()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\tfor _, searchPath := range array {\n\t\t\t\tfor _, tryFolder := range resourceTryFolders {\n\t\t\t\t\ttempPath = searchPath + tryFolder + fileNameOrPath\n\t\t\t\t\tif resFile = gres.Get(tempPath); resFile != nil {\n\t\t\t\t\t\tfileInfo, _ = resFile.Stat()\n\t\t\t\t\t\tif fileInfo != nil && !fileInfo.IsDir() {\n\t\t\t\t\t\t\tfilePath = resFile.Name()\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\ta.autoCheckAndAddMainPkgPathToSearchPaths()\n\n\t// Searching local file system.\n\tif filePath == \"\" {\n\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\tfor _, searchPath := range array {\n\t\t\t\tsearchPath = gstr.TrimRight(searchPath, `\\/`)\n\t\t\t\tfor _, tryFolder := range localSystemTryFolders {\n\t\t\t\t\trelativePath := gstr.TrimRight(\n\t\t\t\t\t\tgfile.Join(tryFolder, fileNameOrPath),\n\t\t\t\t\t\t`\\/`,\n\t\t\t\t\t)\n\t\t\t\t\tif filePath, _ = gspath.Search(searchPath, relativePath); filePath != \"\" &&\n\t\t\t\t\t\t!gfile.IsDir(filePath) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\t// The `fileNameOrPath` can be a file path.\n\tif filePath == \"\" {\n\t\tif filePath = gfile.RealPath(fileNameOrPath); filePath != \"\" && !gfile.IsDir(filePath) {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// GetFilePath returns the absolute configuration file path for the given filename by `file`.\n// If `file` is not passed, it returns the configuration file path of the default name.\n// It returns an empty `path` string and an error if the given `file` does not exist.\nfunc (a *AdapterFile) GetFilePath(fileNameOrPath ...string) (filePath string, err error) {\n\tvar (\n\t\tfileExtName        string\n\t\ttempFileNameOrPath string\n\t\tusedFileNameOrPath = a.defaultFileNameOrPath.String()\n\t)\n\tif len(fileNameOrPath) > 0 {\n\t\tusedFileNameOrPath = fileNameOrPath[0]\n\t}\n\tfileExtName = gfile.ExtName(usedFileNameOrPath)\n\tif filePath = a.doGetFilePath(usedFileNameOrPath); (filePath == \"\" || gfile.IsDir(filePath)) &&\n\t\t!gstr.InArray(supportedFileTypes, fileExtName) {\n\t\t// If it's not using default configuration or its configuration file is not available,\n\t\t// it searches the possible configuration file according to the name and all supported\n\t\t// file types.\n\t\tfor _, fileType := range supportedFileTypes {\n\t\t\ttempFileNameOrPath = fmt.Sprintf(`%s.%s`, usedFileNameOrPath, fileType)\n\t\t\tif filePath = a.doGetFilePath(tempFileNameOrPath); filePath != \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\t// If it cannot find the filePath of `file`, it formats and returns a detailed error.\n\tif filePath == \"\" {\n\t\tvar buffer = bytes.NewBuffer(nil)\n\t\tif a.searchPaths.Len() > 0 {\n\t\t\tif !gstr.InArray(supportedFileTypes, fileExtName) {\n\t\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t\t`possible config files \"%s\" or \"%s\" not found in resource manager or following system searching paths:`,\n\t\t\t\t\tusedFileNameOrPath, fmt.Sprintf(`%s.%s`, usedFileNameOrPath, gstr.Join(supportedFileTypes, \"/\")))\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t\t`specified config file \"%s\" not found in resource manager or following system searching paths:`,\n\t\t\t\t\tusedFileNameOrPath)\n\t\t\t}\n\t\t\ta.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tindex := 1\n\t\t\t\tfor _, searchPath := range array {\n\t\t\t\t\tsearchPath = gstr.TrimRight(searchPath, `\\/`)\n\t\t\t\t\tfor _, tryFolder := range localSystemTryFolders {\n\t\t\t\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t\t\t\t\"\\n%d. %s\",\n\t\t\t\t\t\t\tindex, gfile.Join(searchPath, tryFolder))\n\t\t\t\t\t\tindex++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t`cannot find config file \"%s\" with no filePath configured`,\n\t\t\t\tusedFileNameOrPath)\n\t\t}\n\t\terr = gerror.NewCode(gcode.CodeNotFound, buffer.String())\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_ctx_keys.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcfg provides reading, caching and managing for configuration.\npackage gcfg\n\nimport \"github.com/gogf/gf/v2/os/gctx\"\n\n// Context key constants for configuration operations.\nconst (\n\t// ContextKeyFileName is the context key for file name\n\tContextKeyFileName gctx.StrKey = \"fileName\"\n\t// ContextKeyFilePath is the context key for file path\n\tContextKeyFilePath gctx.StrKey = \"filePath\"\n\t// ContextKeyFileType is the context key for file type\n\tContextKeyFileType gctx.StrKey = \"fileType\"\n\t// ContextKeyOperation is the context key for operation type\n\tContextKeyOperation gctx.StrKey = \"operation\"\n\t// ContextKeyKey is the context key for key\n\tContextKeyKey gctx.StrKey = \"key\"\n\t// ContextKeyValue is the context key for value\n\tContextKeyValue gctx.StrKey = \"value\"\n\t// ContextKeyContent is the context key for set content\n\tContextKeyContent gctx.StrKey = \"content\"\n)\n\n// OperationType defines the type for configuration operation.\ntype OperationType string\n\n// Operation constants for configuration operations.\nconst (\n\t// OperationSet represents set operation\n\tOperationSet OperationType = \"set\"\n\t// OperationWrite represents write operation\n\tOperationWrite OperationType = \"write\"\n\t// OperationRename represents rename operation\n\tOperationRename OperationType = \"rename\"\n\t// OperationRemove represents remove operation\n\tOperationRemove OperationType = \"remove\"\n\t// OperationCreate represents create operation\n\tOperationCreate OperationType = \"create\"\n\t// OperationChmod represents chmod operation\n\tOperationChmod OperationType = \"chmod\"\n\t// OperationClear represents clear operation\n\tOperationClear OperationType = \"clear\"\n\t// OperationUpdate represents update operation\n\tOperationUpdate OperationType = \"update\"\n)\n"
  },
  {
    "path": "os/gcfg/gcfg_loader.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// Loader is a generic configuration manager that provides\n// configuration loading, watching and management similar to Spring Boot's @ConfigurationProperties\ntype Loader[T any] struct {\n\tconfig         *Config                              // The configuration instance to watch\n\tpropertyKey    string                               // The property key pattern to watch\n\ttargetStruct   *T                                   // The target struct pointer to bind configuration to\n\tmutex          sync.RWMutex                         // Mutex for thread-safe operations\n\tonChange       func(T) error                        // Callback function when configuration changes\n\tconverter      func(data any, target *T) error      // Optional custom converter function\n\twatchErrorFunc func(ctx context.Context, err error) // Optional error handling function for watch operations\n\treuse          bool                                 // reuse the same target struct, default is false to avoid data race\n\twatcherName    string                               // watcher name\n}\n\n// NewLoader creates a new Loader instance\n// config: the configuration instance to watch for changes\n// propertyKey: the property key pattern to watch (use \"\" or \".\" to watch all configuration)\n// targetStruct: pointer to the struct that will receive the configuration values\nfunc NewLoader[T any](config *Config, propertyKey string, targetStruct ...*T) *Loader[T] {\n\tif len(targetStruct) > 0 {\n\t\treturn &Loader[T]{\n\t\t\tconfig:       config,\n\t\t\tpropertyKey:  propertyKey,\n\t\t\ttargetStruct: targetStruct[0],\n\t\t\treuse:        false,\n\t\t}\n\t}\n\treturn &Loader[T]{\n\t\tconfig:       config,\n\t\tpropertyKey:  propertyKey,\n\t\ttargetStruct: new(T),\n\t\treuse:        false,\n\t}\n}\n\n// NewLoaderWithAdapter creates a new Loader instance\n// adapter: the adapter instance to use for loading and watching configuration\n// propertyKey: the property key pattern to watch (use \"\" or \".\" to watch all configuration)\n// targetStruct: pointer to the struct that will receive the configuration values\nfunc NewLoaderWithAdapter[T any](adapter Adapter, propertyKey string, targetStruct ...*T) *Loader[T] {\n\treturn NewLoader(NewWithAdapter(adapter), propertyKey, targetStruct...)\n}\n\n// OnChange sets the callback function that will be called when configuration changes\n// The callback function receives the updated configuration struct and can return an error\nfunc (l *Loader[T]) OnChange(fn func(updated T) error) *Loader[T] {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\tl.onChange = fn\n\treturn l\n}\n\n// Load loads configuration from the config instance and binds it to the target struct\n// The context is passed to the underlying configuration adapter\nfunc (l *Loader[T]) Load(ctx context.Context) error {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\n\t// Get configuration data\n\tvar data *gvar.Var\n\tif l.propertyKey == \"\" || l.propertyKey == \".\" {\n\t\t// Get all configuration data\n\t\tconfigData, err := l.config.Data(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdata = gvar.New(configData)\n\t} else {\n\t\t// Get specific property\n\t\tconfigValue, err := l.config.Get(ctx, l.propertyKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif configValue != nil {\n\t\t\tdata = configValue\n\t\t} else {\n\t\t\tdata = gvar.New(nil)\n\t\t}\n\t}\n\n\t// Use custom converter if provided, otherwise use default gconv.Scan\n\tif l.converter != nil && data != nil {\n\t\tif l.reuse {\n\t\t\tif err := l.converter(data.Val(), l.targetStruct); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tvar newConfig T\n\t\t\tif err := l.converter(data.Val(), &newConfig); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tl.targetStruct = &newConfig\n\t\t}\n\t} else {\n\t\tif data != nil {\n\t\t\tif l.reuse {\n\t\t\t\tif err := data.Scan(l.targetStruct); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar newConfig T\n\t\t\t\tif err := data.Scan(&newConfig); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tl.targetStruct = &newConfig\n\t\t\t}\n\t\t}\n\t}\n\n\t// Call change callback if exists\n\tif l.onChange != nil {\n\t\treturn l.onChange(*l.targetStruct)\n\t}\n\n\treturn nil\n}\n\n// MustLoad is like Load but panics if there is an error\nfunc (l *Loader[T]) MustLoad(ctx context.Context) {\n\tif err := l.Load(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Watch starts watching for configuration changes and automatically updates the target struct\n// name: the name of the watcher, which is used to identify this watcher\n// This method sets up a watcher that will call Load() when configuration changes are detected\nfunc (l *Loader[T]) Watch(ctx context.Context, name string) error {\n\tif name == \"\" {\n\t\treturn gerror.New(\"Watcher name cannot be empty\")\n\t}\n\tadapter := l.config.GetAdapter()\n\tif watcherAdapter, ok := adapter.(WatcherAdapter); ok {\n\t\twatcherAdapter.AddWatcher(name, func(ctx context.Context) {\n\t\t\t// Reload configuration when change is detected\n\t\t\tif err := l.Load(ctx); err != nil {\n\t\t\t\t// Use the configured error handler if available, otherwise execute default logging\n\t\t\t\tif l.watchErrorFunc != nil {\n\t\t\t\t\tl.watchErrorFunc(ctx, err)\n\t\t\t\t} else {\n\t\t\t\t\t// Default logging using intlog (internal logging for development)\n\t\t\t\t\tintlog.Errorf(ctx, \"Configuration load failed in watcher %s: %v\", name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tl.watcherName = name\n\t\treturn nil\n\t}\n\treturn gerror.New(\"Watcher adapter not found\")\n}\n\n// MustWatch is like Watch but panics if there is an error\nfunc (l *Loader[T]) MustWatch(ctx context.Context, name string) {\n\tif err := l.Watch(ctx, name); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustLoadAndWatch is a convenience method that calls MustLoad and MustWatch\nfunc (l *Loader[T]) MustLoadAndWatch(ctx context.Context, name string) {\n\tl.MustLoad(ctx)\n\tl.MustWatch(ctx, name)\n}\n\n// Get returns the current configuration struct\n// This method is thread-safe and returns a copy of the current configuration\nfunc (l *Loader[T]) Get() T {\n\tl.mutex.RLock()\n\tdefer l.mutex.RUnlock()\n\treturn *l.targetStruct\n}\n\n// GetPointer returns a pointer to the current configuration struct\n// This method is thread-safe and returns a pointer to the current configuration\n// The returned pointer is safe for read operations but should not be modified\nfunc (l *Loader[T]) GetPointer() *T {\n\tl.mutex.RLock()\n\tdefer l.mutex.RUnlock()\n\treturn l.targetStruct\n}\n\n// SetConverter sets a custom converter function that will be used during Load operations\n// The converter function receives the source data and the target struct pointer\nfunc (l *Loader[T]) SetConverter(converter func(data any, target *T) error) *Loader[T] {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\tl.converter = converter\n\treturn l\n}\n\n// SetWatchErrorHandler sets an error handling function that will be called when Load operations fail during Watch\nfunc (l *Loader[T]) SetWatchErrorHandler(errorFunc func(ctx context.Context, err error)) *Loader[T] {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\tl.watchErrorFunc = errorFunc\n\treturn l\n}\n\n// SetReuseTargetStruct sets whether to reuse the same target struct or create a new one on updates\nfunc (l *Loader[T]) SetReuseTargetStruct(reuse bool) *Loader[T] {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\tl.reuse = reuse\n\treturn l\n}\n\n// StopWatch stops watching for configuration changes and removes the associated watcher\nfunc (l *Loader[T]) StopWatch(ctx context.Context) (bool, error) {\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\n\tif l.watcherName == \"\" {\n\t\treturn false, gerror.New(\"No watcher name specified\")\n\t}\n\tadapter := l.config.GetAdapter()\n\tif watcherAdapter, ok := adapter.(WatcherAdapter); ok {\n\t\twatcherAdapter.RemoveWatcher(l.watcherName)\n\t\tl.watcherName = \"\"\n\t\treturn true, nil\n\t}\n\treturn false, gerror.New(\"Watcher adapter not found\")\n}\n\n// IsWatching returns true if the loader is currently watching for configuration changes\nfunc (l *Loader[T]) IsWatching() bool {\n\tl.mutex.RLock()\n\tdefer l.mutex.RUnlock()\n\tif l.watcherName == \"\" {\n\t\treturn false\n\t}\n\tadapter := l.config.GetAdapter()\n\tif watcherAdapter, ok := adapter.(WatcherAdapter); ok {\n\t\treturn watcherAdapter.IsWatching(l.watcherName)\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_watcher_registry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// WatcherRegistry is a helper type for managing configuration watchers.\n// It provides a unified implementation of watcher management to avoid code duplication\n// across different adapter implementations.\ntype WatcherRegistry struct {\n\twatchers *gmap.KVMap[string, WatcherFunc] // Watchers map storing watcher callbacks.\n}\n\n// NewWatcherRegistry creates and returns a new WatcherRegistry instance.\nfunc NewWatcherRegistry() *WatcherRegistry {\n\treturn &WatcherRegistry{\n\t\twatchers: gmap.NewKVMap[string, WatcherFunc](true),\n\t}\n}\n\n// IsWatching checks whether the watcher with the specified name is registered.\nfunc (r *WatcherRegistry) IsWatching(name string) bool {\n\treturn r.watchers.Contains(name)\n}\n\n// Add adds a watcher with the specified name and callback function.\nfunc (r *WatcherRegistry) Add(name string, fn WatcherFunc) {\n\tr.watchers.Set(name, fn)\n}\n\n// Remove removes the watcher with the specified name.\nfunc (r *WatcherRegistry) Remove(name string) {\n\tr.watchers.Remove(name)\n}\n\n// GetNames returns all watcher names.\nfunc (r *WatcherRegistry) GetNames() []string {\n\treturn r.watchers.Keys()\n}\n\n// Notify notifies all registered watchers by calling their callback functions.\n// Each callback is executed in a separate goroutine with panic recovery to prevent\n// one watcher's panic from affecting others.\nfunc (r *WatcherRegistry) Notify(ctx context.Context) {\n\tr.watchers.Iterator(func(k string, fn WatcherFunc) bool {\n\t\tgo func(k string, fn WatcherFunc, ctx context.Context) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tintlog.Errorf(ctx, \"watcher %s panic: %v\", k, r)\n\t\t\t\t}\n\t\t\t}()\n\t\t\tfn(ctx)\n\t\t}(k, fn, ctx)\n\t\treturn true\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_watcher_registry_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestWatcherRegistry_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistry := gcfg.NewWatcherRegistry()\n\n\t\t// Test Add and GetNames\n\t\tvar (\n\t\t\twg     sync.WaitGroup\n\t\t\tcalled bool\n\t\t)\n\t\twg.Add(1)\n\t\tregistry.Add(\"test-watcher\", func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tcalled = true\n\t\t})\n\n\t\tnames := registry.GetNames()\n\t\tt.AssertEQ(len(names), 1)\n\t\tt.AssertEQ(names[0], \"test-watcher\")\n\n\t\t// Test Notify\n\t\tregistry.Notify(context.Background())\n\t\twg.Wait()\n\t\tt.AssertEQ(called, true)\n\n\t\t// Test Remove\n\t\tregistry.Remove(\"test-watcher\")\n\t\tnames = registry.GetNames()\n\t\tt.AssertEQ(len(names), 0)\n\t})\n}\n\nfunc TestWatcherRegistry_MultipleWatchers(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tregistry := gcfg.NewWatcherRegistry()\n\n\t\tvar (\n\t\t\twg                     sync.WaitGroup\n\t\t\tcount1, count2, count3 int\n\t\t)\n\t\twg.Add(3)\n\t\tregistry.Add(\"watcher1\", func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tcount1++\n\t\t})\n\t\tregistry.Add(\"watcher2\", func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tcount2++\n\t\t})\n\t\tregistry.Add(\"watcher3\", func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tcount3++\n\t\t})\n\n\t\tnames := registry.GetNames()\n\t\tt.AssertEQ(len(names), 3)\n\n\t\tregistry.Notify(context.Background())\n\t\twg.Wait()\n\t\tt.AssertEQ(count1, 1)\n\t\tt.AssertEQ(count2, 1)\n\t\tt.AssertEQ(count3, 1)\n\n\t\t// Remove one watcher\n\t\tregistry.Remove(\"watcher2\")\n\t\tnames = registry.GetNames()\n\t\tt.AssertEQ(len(names), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n)\n\nfunc ExampleConfig_GetWithEnv() {\n\tvar (\n\t\tkey = `ENV_TEST`\n\t\tctx = gctx.New()\n\t)\n\tv, err := g.Cfg().GetWithEnv(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"env:%s\\n\", v)\n\tif err = genv.Set(key, \"gf\"); err != nil {\n\t\tpanic(err)\n\t}\n\tv, err = g.Cfg().GetWithEnv(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"env:%s\", v)\n\n\t// Output:\n\t// env:\n\t// env:gf\n}\n\nfunc ExampleConfig_GetWithCmd() {\n\tvar (\n\t\tkey = `cmd.test`\n\t\tctx = gctx.New()\n\t)\n\tv, err := g.Cfg().GetWithCmd(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"cmd:%s\\n\", v)\n\t// Re-Initialize custom command arguments.\n\tos.Args = append(os.Args, fmt.Sprintf(`--%s=yes`, key))\n\tgcmd.Init(os.Args...)\n\t// Retrieve the configuration and command option again.\n\tv, err = g.Cfg().GetWithCmd(ctx, key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"cmd:%s\", v)\n\n\t// Output:\n\t// cmd:\n\t// cmd:yes\n}\n\nfunc ExampleConfig_newWithAdapter() {\n\tvar (\n\t\tctx          = gctx.New()\n\t\tcontent      = `{\"a\":\"b\", \"c\":1}`\n\t\tadapter, err = gcfg.NewAdapterContent(content)\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tconfig := gcfg.NewWithAdapter(adapter)\n\tfmt.Println(config.MustGet(ctx, \"a\"))\n\tfmt.Println(config.MustGet(ctx, \"c\"))\n\n\t// Output:\n\t// b\n\t// 1\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_adapter_content_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcfg_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestAdapterContent_Available_Get_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, err := gcfg.NewAdapterContent()\n\t\tt.AssertNil(err)\n\t\tt.Assert(adapter.Available(ctx), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `{\"a\": 1, \"b\": 2, \"c\": {\"d\": 3}}`\n\t\tadapter, err := gcfg.NewAdapterContent(content)\n\t\tt.AssertNil(err)\n\n\t\tc := gcfg.NewWithAdapter(adapter)\n\t\tt.Assert(c.Available(ctx), true)\n\t\tt.Assert(c.MustGet(ctx, \"a\"), 1)\n\t\tt.Assert(c.MustGet(ctx, \"b\"), 2)\n\t\tt.Assert(c.MustGet(ctx, \"c.d\"), 3)\n\t\tt.Assert(c.MustGet(ctx, \"d\"), nil)\n\t\tt.Assert(c.MustData(ctx), g.Map{\n\t\t\t\"a\": 1,\n\t\t\t\"b\": 2,\n\t\t\t\"c\": g.Map{\n\t\t\t\t\"d\": 3,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc TestAdapterContent_SetContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tadapter, err := gcfg.NewAdapterContent()\n\t\tt.AssertNil(err)\n\t\tt.Assert(adapter.Available(ctx), false)\n\n\t\tcontent := `{\"a\": 1, \"b\": 2, \"c\": {\"d\": 3}}`\n\t\terr = adapter.SetContent(content)\n\t\tt.AssertNil(err)\n\t\tc := gcfg.NewWithAdapter(adapter)\n\t\tt.Assert(c.Available(ctx), true)\n\t\tt.Assert(c.MustGet(ctx, \"a\"), 1)\n\t\tt.Assert(c.MustGet(ctx, \"b\"), 2)\n\t\tt.Assert(c.MustGet(ctx, \"c.d\"), 3)\n\t\tt.Assert(c.MustGet(ctx, \"d\"), nil)\n\t\tt.Assert(c.MustData(ctx), g.Map{\n\t\t\t\"a\": 1,\n\t\t\t\"b\": 2,\n\t\t\t\"c\": g.Map{\n\t\t\t\t\"d\": 3,\n\t\t\t},\n\t\t})\n\t})\n\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_adapter_file_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcfg_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestAdapterFile_Dump(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(c.GetFileName(), \"config.yml\")\n\n\t\tc.Dump()\n\t\tc.Data(ctx)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"testdata/default/config.toml\")\n\t\tt.AssertNil(err)\n\n\t\tc.Dump()\n\t\tc.Data(ctx)\n\t\tc.GetPaths()\n\t})\n\n}\nfunc TestAdapterFile_Available(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"testdata/default/config.toml\")\n\t\tt.AssertNil(err)\n\t\tc.Available(ctx)\n\t})\n}\n\nfunc TestAdapterFile_SetPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.SetPath(\"/tmp\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.SetPath(\"notexist\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = c.SetPath(\"testdata/c1.toml\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = c.SetPath(\"\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.SetPath(\"gcfg.go\")\n\t\tt.AssertNE(err, nil)\n\n\t\tv, err := c.Get(ctx, \"name\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestAdapterFile_AddPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.AddPath(\"/tmp\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.AddPath(\"notexist\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = c.SetPath(\"testdata/c1.toml\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = c.SetPath(\"\")\n\t\tt.AssertNil(err)\n\n\t\terr = c.AddPath(\"gcfg.go\")\n\t\tt.AssertNE(err, nil)\n\n\t\tv, err := c.Get(ctx, \"name\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestAdapterFile_SetViolenceCheck(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\t\tc.SetViolenceCheck(true)\n\t\tv, err := c.Get(ctx, \"name\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc TestAdapterFile_FilePath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\n\t\tpath, _ := c.GetFilePath(\"tmp\")\n\t\tt.Assert(path, \"\")\n\n\t\tpath, _ = c.GetFilePath(\"tmp\")\n\t\tt.Assert(path, \"\")\n\t})\n}\n\nfunc TestAdapterFile_Content(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile()\n\t\tt.AssertNil(err)\n\n\t\tc.SetContent(\"gf\", \"config.yml\")\n\t\tt.Assert(c.GetContent(\"config.yml\"), \"gf\")\n\t\tc.SetContent(\"gf1\", \"config.yml\")\n\t\tt.Assert(c.GetContent(\"config.yml\"), \"gf1\")\n\t\tc.RemoveContent(\"config.yml\")\n\t\tc.ClearContent()\n\t\tt.Assert(c.GetContent(\"name\"), \"\")\n\t})\n}\n\nfunc TestAdapterFile_With_UTF8_BOM(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.NewAdapterFile(\"test-cfg-with-utf8-bom\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(c.SetPath(\"testdata\"), nil)\n\t\tc.SetFileName(\"cfg-with-utf8-bom.toml\")\n\t\tt.Assert(c.MustGet(ctx, \"test.testInt\"), 1)\n\t\tt.Assert(c.MustGet(ctx, \"test.testStr\"), \"test\")\n\t})\n}\n\nfunc TestAdapterFile_Set(t *testing.T) {\n\tconfig := `log-path = \"logs\"`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath = gcfg.DefaultConfigFileName\n\t\t\terr  = gfile.PutContents(path, config)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tc, err := gcfg.New()\n\t\tt.Assert(c.MustGet(ctx, \"log-path\").String(), \"logs\")\n\n\t\terr = c.GetAdapter().(*gcfg.AdapterFile).Set(\"log-path\", \"custom-logs\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(c.MustGet(ctx, \"log-path\").String(), \"custom-logs\")\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcfg_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Basic1(t *testing.T) {\n\tconfig := `\nv1    = 1\nv2    = \"true\"\nv3    = \"off\"\nv4    = \"1.23\"\narray = [1,2,3]\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath = gcfg.DefaultConfigFileName\n\t\t\terr  = gfile.PutContents(path, config)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t\tfilepath, _ := c.GetAdapter().(*gcfg.AdapterFile).GetFilePath()\n\t\tt.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)\n\t})\n}\n\nfunc Test_Basic2(t *testing.T) {\n\tconfig := `log-path = \"logs\"`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath = gcfg.DefaultConfigFileName\n\t\t\terr  = gfile.PutContents(path, config)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer func() {\n\t\t\t_ = gfile.Remove(path)\n\t\t}()\n\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tt.Assert(c.MustGet(ctx, \"log-path\"), \"logs\")\n\t})\n}\n\nfunc Test_Content(t *testing.T) {\n\tcontent := `\nv1    = 1\nv2    = \"true\"\nv3    = \"off\"\nv4    = \"1.23\"\narray = [1,2,3]\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tc.GetAdapter().(*gcfg.AdapterFile).SetContent(content)\n\t\tdefer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t})\n}\n\nfunc Test_SetFileName(t *testing.T) {\n\tconfig := `\n{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3\n\t],\n\t\"redis\": {\n\t\t\"cache\": \"127.0.0.1:6379,1\",\n\t\t\"disk\": \"127.0.0.1:6379,0\"\n\t},\n\t\"v1\": 1,\n\t\"v2\": \"true\",\n\t\"v3\": \"off\",\n\t\"v4\": \"1.234\"\n}\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"config.json\"\n\t\terr := gfile.PutContents(path, config)\n\t\tt.AssertNil(err)\n\t\tdefer func() {\n\t\t\t_ = gfile.Remove(path)\n\t\t}()\n\n\t\tconfig, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tc := config.GetAdapter().(*gcfg.AdapterFile)\n\t\tc.SetFileName(path)\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Int(), 1)\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Int8(), int8(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Int16(), int16(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Int32(), int32(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Int64(), int64(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Uint(), uint(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Uint8(), uint8(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Uint16(), uint16(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Uint32(), uint32(1))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Uint64(), uint64(1))\n\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").String(), \"1\")\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").Bool(), true)\n\t\tt.AssertEQ(c.MustGet(ctx, \"v2\").String(), \"true\")\n\t\tt.AssertEQ(c.MustGet(ctx, \"v2\").Bool(), true)\n\n\t\tt.AssertEQ(c.MustGet(ctx, \"v1\").String(), \"1\")\n\t\tt.AssertEQ(c.MustGet(ctx, \"v4\").Float32(), float32(1.234))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v4\").Float64(), float64(1.234))\n\t\tt.AssertEQ(c.MustGet(ctx, \"v2\").String(), \"true\")\n\t\tt.AssertEQ(c.MustGet(ctx, \"v2\").Bool(), true)\n\t\tt.AssertEQ(c.MustGet(ctx, \"v3\").Bool(), false)\n\n\t\tt.AssertEQ(c.MustGet(ctx, \"array\").Ints(), []int{1, 2, 3})\n\t\tt.AssertEQ(c.MustGet(ctx, \"array\").Strings(), []string{\"1\", \"2\", \"3\"})\n\t\tt.AssertEQ(c.MustGet(ctx, \"array\").Interfaces(), []any{1, 2, 3})\n\t\tt.AssertEQ(c.MustGet(ctx, \"redis\").Map(), map[string]any{\n\t\t\t\"disk\":  \"127.0.0.1:6379,0\",\n\t\t\t\"cache\": \"127.0.0.1:6379,1\",\n\t\t})\n\t\tfilepath, _ := c.GetFilePath()\n\t\tt.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)\n\t})\n}\n\nfunc TestCfg_Get_WrongConfigFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\tconfigPath := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(configPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(configPath)\n\n\t\tdefer gfile.Chdir(gfile.Pwd())\n\t\terr = gfile.Chdir(configPath)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.PutContents(\n\t\t\tgfile.Join(configPath, \"config.yml\"),\n\t\t\t\"wrong config\",\n\t\t)\n\t\tt.AssertNil(err)\n\t\tadapterFile, err := gcfg.NewAdapterFile(\"config.yml\")\n\t\tt.AssertNil(err)\n\n\t\tc := gcfg.NewWithAdapter(adapterFile)\n\t\tv, err := c.Get(ctx, \"name\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(v, nil)\n\t\tadapterFile.Clear()\n\t})\n}\n\nfunc Test_GetWithEnv(t *testing.T) {\n\tcontent := `\nv1    = 1\nv2    = \"true\"\nv3    = \"off\"\nv4    = \"1.23\"\narray = [1,2,3]\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tc.GetAdapter().(*gcfg.AdapterFile).SetContent(content)\n\t\tdefer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t\tt.Assert(c.MustGetWithEnv(ctx, `redis.user`), nil)\n\t\tt.Assert(genv.Set(\"REDIS_USER\", `1`), nil)\n\t\tdefer genv.Remove(`REDIS_USER`)\n\t\tt.Assert(c.MustGetWithEnv(ctx, `redis.user`), `1`)\n\t})\n}\n\nfunc Test_GetWithCmd(t *testing.T) {\n\tcontent := `\nv1    = 1\nv2    = \"true\"\nv3    = \"off\"\nv4    = \"1.23\"\narray = [1,2,3]\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tc.GetAdapter().(*gcfg.AdapterFile).SetContent(content)\n\t\tdefer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t\tt.Assert(c.MustGetWithCmd(ctx, `redis.user`), nil)\n\n\t\tgcmd.Init([]string{\"gf\", \"--redis.user=2\"}...)\n\t\tt.Assert(c.MustGetWithCmd(ctx, `redis.user`), `2`)\n\t})\n}\n\nfunc Test_GetEffective(t *testing.T) {\n\tcontent := `\nv1    = 1\nv2    = \"true\"\n[server]\n    port = 8080\n    host = \"localhost\"\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\"\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc, err := gcfg.New()\n\t\tt.AssertNil(err)\n\t\tc.GetAdapter().(*gcfg.AdapterFile).SetContent(content)\n\t\tdefer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()\n\n\t\t// Test 1: Get from config file when no cmd/env set\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.port\"), 8080)\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.host\"), \"localhost\")\n\n\t\t// Test 2: Environment variable overrides config file\n\t\tt.Assert(genv.Set(\"SERVER_PORT\", \"9090\"), nil)\n\t\tdefer genv.Remove(\"SERVER_PORT\")\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.port\"), \"9090\")\n\n\t\t// Test 3: Command line overrides environment variable\n\t\tgcmd.Init([]string{\"gf\", \"--server.port=7070\"}...)\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.port\"), \"7070\")\n\n\t\t// Test 4: Default value when nothing is set\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.timeout\", 30), 30)\n\n\t\t// Test 5: Empty string from command line should override\n\t\tgcmd.Init([]string{\"gf\", \"--server.name=\"}...)\n\t\tt.Assert(genv.Set(\"SERVER_NAME\", \"from-env\"), nil)\n\t\tdefer genv.Remove(\"SERVER_NAME\")\n\t\tt.Assert(c.MustGetEffective(ctx, \"server.name\"), \"\")\n\n\t\t// Test 6: Key not in config, only in env\n\t\tt.Assert(genv.Set(\"APP_DEBUG\", \"true\"), nil)\n\t\tdefer genv.Remove(\"APP_DEBUG\")\n\t\tt.Assert(c.MustGetEffective(ctx, \"app.debug\"), \"true\")\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_instance_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcfg\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_Instance_Basic(t *testing.T) {\n\tconfig := `\narray = [1.0, 2.0, 3.0]\nv1 = 1.0\nv2 = \"true\"\nv3 = \"off\"\nv4 = \"1.234\"\n\n[redis]\n  cache = \"127.0.0.1:6379,1\"\n  disk = \"127.0.0.1:6379,0\"\n\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpath = DefaultConfigFileName\n\t\t\terr  = gfile.PutContents(path, config)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer func() {\n\t\t\tt.AssertNil(gfile.Remove(path))\n\t\t}()\n\n\t\tc := Instance()\n\t\tt.Assert(c.MustGet(ctx, \"v1\"), 1)\n\t\tfilepath, _ := c.GetAdapter().(*AdapterFile).GetFilePath()\n\t\tt.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)\n\t})\n}\n\nfunc Test_Instance_AutoLocateConfigFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(Instance(\"gf\") != nil, true)\n\t})\n\t// Automatically locate the configuration file with supported file extensions.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpwd := gfile.Pwd()\n\t\tt.AssertNil(gfile.Chdir(gtest.DataPath()))\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.Assert(Instance(\"c1\") != nil, true)\n\t\tt.Assert(Instance(\"c1\").MustGet(ctx, \"my-config\"), \"1\")\n\t\tt.Assert(Instance(\"folder1/c1\").MustGet(ctx, \"my-config\"), \"2\")\n\t})\n\t// Automatically locate the configuration file with supported file extensions.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpwd := gfile.Pwd()\n\t\tt.AssertNil(gfile.Chdir(gtest.DataPath(\"folder1\")))\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.Assert(Instance(\"c2\").MustGet(ctx, \"my-config\"), 2)\n\t})\n\t// Default configuration file.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlocalInstances.Clear()\n\t\tpwd := gfile.Pwd()\n\t\tt.AssertNil(gfile.Chdir(gtest.DataPath(\"default\")))\n\t\tdefer gfile.Chdir(pwd)\n\t\tt.Assert(Instance().MustGet(ctx, \"my-config\"), 1)\n\n\t\tlocalInstances.Clear()\n\t\tt.AssertNil(genv.Set(\"GF_GCFG_FILE\", \"config.json\"))\n\t\tdefer genv.Set(\"GF_GCFG_FILE\", \"\")\n\t\tt.Assert(Instance().MustGet(ctx, \"my-config\"), 2)\n\t})\n}\n\nfunc Test_Instance_EnvPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgenv.Set(\"GF_GCFG_PATH\", gtest.DataPath(\"envpath\"))\n\t\tdefer genv.Set(\"GF_GCFG_PATH\", \"\")\n\t\tt.Assert(Instance(\"c3\") != nil, true)\n\t\tt.Assert(Instance(\"c3\").MustGet(ctx, \"my-config\"), \"3\")\n\t\tt.Assert(Instance(\"c4\").MustGet(ctx, \"my-config\"), \"4\")\n\t\tlocalInstances = gmap.NewKVMapWithChecker[string, *Config](checker, true)\n\t})\n}\n\nfunc Test_Instance_EnvFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgenv.Set(\"GF_GCFG_PATH\", gtest.DataPath(\"envfile\"))\n\t\tdefer genv.Set(\"GF_GCFG_PATH\", \"\")\n\t\tgenv.Set(\"GF_GCFG_FILE\", \"c6.json\")\n\t\tdefer genv.Set(\"GF_GCFG_FILE\", \"\")\n\t\tt.Assert(Instance().MustGet(ctx, \"my-config\"), \"6\")\n\t\tlocalInstances = gmap.NewKVMapWithChecker[string, *Config](checker, true)\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_loader_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\n// TestConfig is a test struct for configuration binding\ntype TestConfig struct {\n\tName     string       `json:\"name\" yaml:\"name\"`\n\tAge      int          `json:\"age\" yaml:\"age\"`\n\tEnabled  bool         `json:\"enabled\" yaml:\"enabled\"`\n\tFeatures []string     `json:\"features\" yaml:\"features\"`\n\tServer   ServerConfig `json:\"server\" yaml:\"server\"`\n}\n\n// TestConfig2 is a test struct for configuration binding\ntype TestConfig2 struct {\n\tName     string       `json:\"name\" yaml:\"name\"`\n\tAge      int          `json:\"age\" yaml:\"age\"`\n\tEnabled  bool         `json:\"enabled\" yaml:\"enabled\"`\n\tFeatures string       `json:\"features\" yaml:\"features\"`\n\tServer   ServerConfig `json:\"server\" yaml:\"server\"`\n}\n\n// TestConfig3 is a test struct for configuration binding\ntype TestConfig3 struct {\n\tName     string       `json:\"name\" yaml:\"name\"`\n\tAge      int          `json:\"age\" yaml:\"age\"`\n\tEnabled  bool         `json:\"enabled\" yaml:\"enabled\"`\n\tFeatures []string     `json:\"features\" yaml:\"features\"`\n\tServer   ServerConfig `json:\"server\" yaml:\"server\"`\n\tOther    string       `json:\"other\" yaml:\"other\"`\n}\n\ntype ServerConfig struct {\n\tHost string `json:\"host\" yaml:\"host\"`\n\tPort int    `json:\"port\" yaml:\"port\"`\n}\n\nvar configContent = `\nname: \"test-app\"\nage: 25\nenabled: true\nfeatures: [\"feature1\", \"feature2\", \"feature3\"]\nserver:\n  host: \"localhost\"\n  port: 8080\n`\n\nfunc TestLoader_Load(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tconfigFile = \"./\" + guid.S() + \".yaml\"\n\t\t\terr        = gfile.PutContents(configFile, configContent)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig](cfg, \"\")\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\t\tv := loader.Get()\n\n\t\t// Check loaded values\n\t\tt.Assert(v.Name, \"test-app\")\n\t\tt.Assert(v.Age, 25)\n\t\tt.Assert(v.Enabled, true)\n\t\tt.Assert(v.Server.Host, \"localhost\")\n\t\tt.Assert(v.Server.Port, 8080)\n\t\tt.Assert(len(v.Features), 3)\n\t})\n}\n\nfunc TestLoader_LoadWithDefaultValues(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tconfigFile = \"./\" + guid.S() + \".yaml\"\n\t\t\terr        = gfile.PutContents(configFile, configContent)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Create target struct\n\t\tvar targetConfig TestConfig3\n\t\ttargetConfig.Other = \"other\"\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter(cfg, \"\", &targetConfig)\n\t\tloader.SetReuseTargetStruct(true)\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\t\tv := loader.Get()\n\n\t\t// Check loaded values\n\t\tt.Assert(v.Name, \"test-app\")\n\t\tt.Assert(v.Age, 25)\n\t\tt.Assert(v.Enabled, true)\n\t\tt.Assert(v.Server.Host, \"localhost\")\n\t\tt.Assert(v.Server.Port, 8080)\n\t\tt.Assert(len(v.Features), 3)\n\t\tt.Assert(v.Other, \"other\")\n\t})\n}\n\nfunc TestLoader_LoadWithPropertyKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tconfigFile = \"./\" + guid.S() + \".yaml\"\n\t\t\terr        = gfile.PutContents(configFile, configContent)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader with specific property key\n\t\tloader := gcfg.NewLoaderWithAdapter[ServerConfig](cfg, \"server\")\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\t\tv := loader.Get()\n\n\t\t// Check loaded values - only the app section should be loaded\n\t\tt.Assert(v.Host, \"localhost\")\n\t\tt.Assert(v.Port, 8080)\n\t})\n}\n\nfunc TestLoader_WatchAndOnChange(t *testing.T) {\n\tvar configContent2 = `\nname: test-app-2\nage: 200\nenabled: true\nfeatures: [\"feature1\", \"feature2\", \"feature3\"]\nserver:\n  host: localhost\n  port: 8080\n`\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterContent(configContent)\n\t\tt.AssertNil(err)\n\n\t\t// Variable to track if callback was called\n\t\tcallbackCalled := gtype.NewBool(false)\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig](cfg, \"\")\n\n\t\t// Set change callback\n\t\tloader.OnChange(func(updated TestConfig) error {\n\t\t\tcallbackCalled.Set(true)\n\t\t\treturn nil\n\t\t})\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\t\terr = loader.Watch(context.Background(), \"test-watcher\")\n\t\tt.AssertNil(err)\n\t\tv := loader.Get()\n\t\tt.Assert(v.Name, \"test-app\")\n\t\tt.Assert(v.Age, 25)\n\t\terr = cfg.SetContent(configContent2)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(2 * time.Second)\n\t\tv2 := loader.Get()\n\t\tt.Assert(v2.Name, \"test-app-2\")\n\t\tt.Assert(v2.Age, 200)\n\t\tt.Assert(callbackCalled.Val(), true)\n\t})\n}\n\nfunc TestLoader_SetConverter(t *testing.T) {\n\tvar configContent2 = `\nname: test-app-2\nage: 200\nenabled: true\nfeatures: [\"feature\", \"feature\", \"feature\"]\nserver:\n  host: localhost\n  port: 8080\n`\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tconfigFile = \"./\" + guid.S() + \".yaml\"\n\t\t\terr        = gfile.PutContents(configFile, configContent2)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig2](cfg, \"features\")\n\n\t\t// Set custom converter\n\t\tloader.SetConverter(func(data any, target *TestConfig2) error {\n\t\t\ts := gconv.Strings(data)\n\t\t\ttarget.Features = strings.Join(s, \",\")\n\t\t\treturn nil\n\t\t})\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\t\tv := loader.Get()\n\n\t\t// Check converted values\n\t\tt.Assert(v.Features, \"feature,feature,feature\")\n\t})\n}\n\nfunc TestLoader_SetWatchErrorHandler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a new config instance with content that will cause converter error\n\t\tcfg, err := gcfg.NewAdapterContent(configContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig](cfg, \"\")\n\n\t\t// Set error handler for watch operations\n\t\terrorHandled := gtype.NewBool(false)\n\t\tloader.SetWatchErrorHandler(func(ctx context.Context, err error) {\n\t\t\terrorHandled.Set(true)\n\t\t})\n\n\t\t// Set a converter that will fail\n\t\tloader.SetConverter(func(data any, target *TestConfig) error {\n\t\t\treturn errors.New(\"converter error\")\n\t\t})\n\n\t\t// Load initially - this should return error without calling error handler\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"converter error\")\n\t\t// Error handler should NOT be called during direct Load\n\t\tt.Assert(errorHandled.Val(), false)\n\n\t\t// Start watching - now errors during Load should trigger the error handler\n\t\terr = loader.Watch(context.Background(), \"test-error-handler\")\n\t\tt.AssertNil(err)\n\t\t// Reset\n\t\terrorHandled.Set(false)\n\t\t// Trigger a config change - this will call Load internally and should trigger error handler\n\t\terr = cfg.SetContent(configContent)\n\t\tt.AssertNil(err)\n\n\t\t// Wait for watcher to process the change\n\t\ttime.Sleep(1 * time.Second)\n\n\t\t// Error handler should be called during Watch's Load\n\t\tt.Assert(errorHandled.Val(), true)\n\t})\n}\n\nfunc TestLoader_IsWatchingAndStopWatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterContent(configContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig](cfg, \"\")\n\n\t\t// Initially, should not be watching\n\t\tt.Assert(loader.IsWatching(), false)\n\n\t\t// Load configuration\n\t\terr = loader.Load(context.Background())\n\t\tt.AssertNil(err)\n\n\t\t// Start watching\n\t\terr = loader.Watch(context.Background(), \"test-stopwatch-watcher\")\n\t\tt.AssertNil(err)\n\n\t\t// Now should be watching\n\t\tt.Assert(loader.IsWatching(), true)\n\n\t\t// Stop watching\n\t\tstopped, err := loader.StopWatch(context.Background())\n\t\tt.AssertNil(err)\n\t\tt.Assert(stopped, true)\n\n\t\t// Should not be watching anymore\n\t\tt.Assert(loader.IsWatching(), false)\n\t})\n}\n\nfunc TestLoader_StopWatchWithoutWatcher(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Create a new config instance\n\t\tcfg, err := gcfg.NewAdapterContent(configContent)\n\t\tt.AssertNil(err)\n\n\t\t// Create loader without starting to watch\n\t\tloader := gcfg.NewLoaderWithAdapter[TestConfig](cfg, \"\")\n\n\t\t// Initially, should not be watching\n\t\tt.Assert(loader.IsWatching(), false)\n\n\t\t// Try to stop watching when not watching\n\t\tstopped, err := loader.StopWatch(context.Background())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(stopped, false)\n\t\tt.Assert(err.Error(), \"No watcher name specified\")\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcfg_test\n\nimport \"context\"\n\nvar (\n\tctx = context.TODO()\n)\n"
  },
  {
    "path": "os/gcfg/gcfg_z_unit_watcher_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcfg_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc TestWatcher_File_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tkey1       = \"test-ctx\"\n\t\t\tconfigFile = guid.S() + \".toml\"\n\t\t\tcontent1   = `key = \"value1\"`\n\t\t\tcontent2   = `key = \"value2\"`\n\t\t)\n\t\t// Create config file.\n\t\terr := gfile.PutContents(configFile, content1)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\t\tc.Data(context.Background())\n\t\tc.AddWatcher(key1, func(ctx context.Context) {\n\t\t\tfileCtx := gcfg.GetAdapterFileCtx(ctx)\n\t\t\tt.Assert(fileCtx.GetOperation(), gcfg.OperationWrite)\n\t\t\tt.Assert(fileCtx.GetFileName(), configFile)\n\t\t\tt.Assert(fileCtx.GetFilePath(), gfile.Abs(configFile))\n\t\t})\n\t\tgfile.PutContents(configFile, content2)\n\t\ttime.Sleep(1 * time.Second)\n\t\tc.AddWatcher(key1, func(ctx context.Context) {\n\t\t\tfileCtx := gcfg.GetAdapterFileCtx(ctx)\n\t\t\tt.Assert(fileCtx.GetOperation(), gcfg.OperationSet)\n\t\t\tt.Assert(fileCtx.GetKey(), \"key\")\n\t\t\tt.Assert(fileCtx.GetValue().String(), \"value2\")\n\t\t})\n\t\tc.Set(\"key\", \"value2\")\n\t\ttime.Sleep(1 * time.Second)\n\t\tc.RemoveWatcher(key1)\n\t})\n}\n\nfunc TestWatcher_AddWatcherAndNotify(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tm          = gmap.NewStrAnyMap(true)\n\t\t\tkey1       = \"test-watcher1\"\n\t\t\tkey2       = \"test-watcher2\"\n\t\t\tconfigFile = guid.S() + \".toml\"\n\t\t\tcontent1   = `key = \"value1\"`\n\t\t\tcontent2   = `key = \"value2\"`\n\t\t)\n\n\t\t// Create config file.\n\t\terr := gfile.PutContents(configFile, content1)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\t\tm.Set(key1, true)\n\t\tm.Set(key2, true)\n\n\t\t// Add watchers.\n\t\tc.AddWatcher(key1, func(ctx context.Context) {\n\t\t\tm.Set(key1, false)\n\t\t})\n\t\tc.AddWatcher(key2, func(ctx context.Context) {\n\t\t\tm.Set(key2, false)\n\t\t})\n\n\t\t// Check initial values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\")\n\t\tt.Assert(m.Get(key1), true)\n\t\tt.Assert(m.Get(key2), true)\n\n\t\t// Update config file content.\n\t\terr = gfile.PutContents(configFile, content2)\n\t\tt.AssertNil(err)\n\n\t\t// Wait for watching notification.\n\t\ttime.Sleep(1 * time.Second)\n\n\t\t// Check updated values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value2\")\n\t\tt.AssertEQ(m.Get(key1), false)\n\t\tt.AssertEQ(m.Get(key2), false)\n\t})\n}\n\nfunc TestWatcher_RemoveWatcher(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tm          = gmap.NewStrAnyMap(true)\n\t\t\tkey1       = \"test-watcher1\"\n\t\t\tkey2       = \"test-watcher2\"\n\t\t\tconfigFile = guid.S() + \".toml\"\n\t\t\tcontent1   = `key = \"value1\"`\n\t\t\tcontent2   = `key = \"value2\"`\n\t\t)\n\t\terr := gfile.PutContents(configFile, content1)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\t\tm.Set(key1, true)\n\t\tm.Set(key2, true)\n\n\t\t// Add watchers.\n\t\tc.AddWatcher(key1, func(ctx context.Context) {\n\t\t\tm.Set(key1, false)\n\t\t})\n\t\tc.AddWatcher(key2, func(ctx context.Context) {\n\t\t\tm.Set(key2, false)\n\t\t})\n\n\t\t// Check initial values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\")\n\t\tt.Assert(m.Get(key1), true)\n\t\tt.Assert(m.Get(key2), true)\n\n\t\t// Remove one watcher.\n\t\tc.RemoveWatcher(key2)\n\n\t\t// Update config file content.\n\t\terr = gfile.PutContents(configFile, content2)\n\t\tt.AssertNil(err)\n\n\t\t// Wait for watching notification.\n\t\ttime.Sleep(1 * time.Second)\n\n\t\t// Check updated values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value2\")\n\t\tt.AssertEQ(m.Get(key1), false)\n\t\t// watcherName2 should not be notified as it was removed\n\t\tt.AssertEQ(m.Get(key2), true)\n\t})\n}\n\nfunc TestWatcher_SetContentNotify(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcount    = gtype.NewInt(0)\n\t\t\tkey      = \"test-watcher\"\n\t\t\tcontent1 = `key = \"value1\"`\n\t\t\tcontent2 = `key = \"value2\"`\n\t\t)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterContent(content1)\n\t\tt.AssertNil(err)\n\n\t\t// Add watcher.\n\t\tc.AddWatcher(key, func(ctx context.Context) {\n\t\t\tcount.Add(1)\n\t\t})\n\n\t\t// Check initial values.\n\t\tvalue, err := c.Get(ctx, \"key\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, \"value1\")\n\t\tt.Assert(count.Val(), 0)\n\n\t\t// Set custom content.\n\t\tc.SetContent(content2)\n\n\t\t// Wait for watching notification.\n\t\ttime.Sleep(2 * time.Second)\n\n\t\t// Check that watcher was notified\n\t\tt.Assert(count.Val(), 1)\n\t\tvalue2, err := c.Get(ctx, \"key\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(value2, \"value2\")\n\t})\n}\n\nfunc TestWatcher_RemoveContentNotify(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcount      = gtype.NewInt(0)\n\t\t\tkey        = \"test-watcher\"\n\t\t\tconfigFile = guid.S() + \".toml\"\n\t\t\tcontent    = `key = \"value1\"`\n\t\t)\n\n\t\t// Create config file.\n\t\terr := gfile.PutContents(configFile, content)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Add watcher.\n\t\tc.AddWatcher(key, func(ctx context.Context) {\n\t\t\tcount.Add(1)\n\t\t})\n\n\t\t// Check initial values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\")\n\t\tt.Assert(count.Val(), 0)\n\n\t\t// Remove custom content.\n\t\tc.RemoveContent(configFile)\n\n\t\t// Wait for watching notification.\n\t\ttime.Sleep(1 * time.Second)\n\n\t\t// Check that watcher was notified again\n\t\tt.Assert(count.Val(), 1)\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\") // Back to file content\n\t})\n}\n\nfunc TestWatcher_ClearContentNotify(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcount      = gtype.NewInt(0)\n\t\t\tkey        = \"test-watcher\"\n\t\t\tconfigFile = guid.S() + \".toml\"\n\t\t\tcontent    = `key = \"value1\"`\n\t\t)\n\n\t\t// Create config file.\n\t\terr := gfile.PutContents(configFile, content)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.RemoveFile(configFile)\n\n\t\t// Create config instance.\n\t\tc, err := gcfg.NewAdapterFile(configFile)\n\t\tt.AssertNil(err)\n\n\t\t// Add watcher.\n\t\tc.AddWatcher(key, func(ctx context.Context) {\n\t\t\tcount.Add(1)\n\t\t})\n\n\t\t// Check initial values.\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\")\n\t\tt.Assert(count.Val(), 0)\n\n\t\t// Clear all custom content.\n\t\tc.ClearContent()\n\n\t\t// Wait for watching notification.\n\t\ttime.Sleep(1 * time.Second)\n\n\t\t// Check that watcher was notified again\n\t\tt.Assert(count.Val(), 1)\n\t\tt.Assert(c.MustGet(ctx, \"key\").String(), \"value1\") // Back to file content\n\t})\n}\n"
  },
  {
    "path": "os/gcfg/testdata/c1.toml",
    "content": "\nmy-config = \"1\""
  },
  {
    "path": "os/gcfg/testdata/cfg-with-utf8-bom.toml",
    "content": "﻿\r\n[test]\r\ntestInt=1\r\ntestStr=\"test\"\r\n"
  },
  {
    "path": "os/gcfg/testdata/default/config.json",
    "content": "{\"my-config\": 2}"
  },
  {
    "path": "os/gcfg/testdata/default/config.toml",
    "content": "my-config = \"1\""
  },
  {
    "path": "os/gcfg/testdata/envfile/c6.json",
    "content": "\n{\"my-config\": 6}"
  },
  {
    "path": "os/gcfg/testdata/envpath/c3.toml",
    "content": "\nmy-config = \"3\""
  },
  {
    "path": "os/gcfg/testdata/envpath/c4.json",
    "content": "\n{\"my-config\": 4}"
  },
  {
    "path": "os/gcfg/testdata/folder1/c1.toml",
    "content": "\nmy-config = \"2\""
  },
  {
    "path": "os/gcfg/testdata/folder1/c2.json",
    "content": "\n{\"my-config\": 2}"
  },
  {
    "path": "os/gcmd/gcmd.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\n// Package gcmd provides console operations, like options/arguments reading and command running.\npackage gcmd\n\nimport (\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n)\n\nconst (\n\tCtxKeyParser         gctx.StrKey = `CtxKeyParser`\n\tCtxKeyCommand        gctx.StrKey = `CtxKeyCommand`\n\tCtxKeyArgumentsIndex gctx.StrKey = `CtxKeyArgumentsIndex`\n)\n\nconst (\n\thelpOptionName        = \"help\"\n\thelpOptionNameShort   = \"h\"\n\tmaxLineChars          = 120\n\ttracingInstrumentName = \"github.com/gogf/gf/v2/os/gcmd.Command\"\n\ttagNameName           = \"name\"\n\ttagNameShort          = \"short\"\n)\n\n// Init does custom initialization.\nfunc Init(args ...string) {\n\tcommand.Init(args...)\n}\n\n// GetOpt returns the option value named `name` as gvar.Var.\nfunc GetOpt(name string, def ...string) *gvar.Var {\n\tif v := command.GetOpt(name, def...); v != \"\" {\n\t\treturn gvar.New(v)\n\t}\n\tif command.ContainsOpt(name) {\n\t\treturn gvar.New(\"\")\n\t}\n\treturn nil\n}\n\n// GetOptAll returns all parsed options.\nfunc GetOptAll() map[string]string {\n\treturn command.GetOptAll()\n}\n\n// GetArg returns the argument at `index` as gvar.Var.\nfunc GetArg(index int, def ...string) *gvar.Var {\n\tif v := command.GetArg(index, def...); v != \"\" {\n\t\treturn gvar.New(v)\n\t}\n\treturn nil\n}\n\n// GetArgAll returns all parsed arguments.\nfunc GetArgAll() []string {\n\treturn command.GetArgAll()\n}\n\n// GetOptWithEnv returns the command line argument of the specified `key`.\n// If the argument does not exist, then it returns the environment variable with specified `key`.\n// It returns the default value `def` if none of them exists.\n//\n// Fetching Rules:\n// 1. Command line arguments are in lowercase format, eg: gf.`package name`.<variable name>;\n// 2. Environment arguments are in uppercase format, eg: GF_`package name`_<variable name>；\nfunc GetOptWithEnv(key string, def ...any) *gvar.Var {\n\tcmdKey := utils.FormatCmdKey(key)\n\tif command.ContainsOpt(cmdKey) {\n\t\treturn gvar.New(GetOpt(cmdKey))\n\t} else {\n\t\tenvKey := utils.FormatEnvKey(key)\n\t\tif r, ok := os.LookupEnv(envKey); ok {\n\t\t\treturn gvar.New(r)\n\t\t} else {\n\t\t\tif len(def) > 0 {\n\t\t\t\treturn gvar.New(def[0])\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// BuildOptions builds the options as string.\nfunc BuildOptions(m map[string]string, prefix ...string) string {\n\toptions := \"\"\n\tleadStr := \"-\"\n\tif len(prefix) > 0 {\n\t\tleadStr = prefix[0]\n\t}\n\tfor k, v := range m {\n\t\tif len(options) > 0 {\n\t\t\toptions += \" \"\n\t\t}\n\t\toptions += leadStr + k\n\t\tif v != \"\" {\n\t\t\toptions += \"=\" + v\n\t\t}\n\t}\n\treturn options\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_command.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Command holds the info about an argument that can handle custom logic.\ntype Command struct {\n\tName          string        // Command name(case-sensitive).\n\tUsage         string        // A brief line description about its usage, eg: gf build main.go [OPTION]\n\tBrief         string        // A brief info that describes what this command will do.\n\tDescription   string        // A detailed description.\n\tArguments     []Argument    // Argument array, configuring how this command act.\n\tFunc          Function      // Custom function.\n\tFuncWithValue FuncWithValue // Custom function with output parameters that can interact with command caller.\n\tHelpFunc      Function      // Custom help function.\n\tExamples      string        // Usage examples.\n\tAdditional    string        // Additional info about this command, which will be appended to the end of help info.\n\tStrict        bool          // Strict parsing options, which means it returns error if invalid option given.\n\tCaseSensitive bool          // CaseSensitive parsing options, which means it parses input options in case-sensitive way.\n\tConfig        string        // Config node name, which also retrieves the values from config component along with command line.\n\tinternalCommandAttributes\n}\n\ntype internalCommandAttributes struct {\n\tparent   *Command   // Parent command for internal usage.\n\tcommands []*Command // Sub commands of this command.\n}\n\n// Function is a custom command callback function that is bound to a certain argument.\ntype Function func(ctx context.Context, parser *Parser) (err error)\n\n// FuncWithValue is similar like Func but with output parameters that can interact with command caller.\ntype FuncWithValue func(ctx context.Context, parser *Parser) (out any, err error)\n\n// Argument is the command value that are used by certain command.\ntype Argument struct {\n\tName    string // Option name.\n\tShort   string // Option short.\n\tDefault string // Option default value.\n\tBrief   string // Brief info about this Option, which is used in help info.\n\tIsArg   bool   // IsArg marks this argument taking value from command line argument instead of option.\n\tOrphan  bool   // Whether this Option having or having no value bound to it.\n}\n\nvar (\n\t// defaultHelpOption is the default help option that will be automatically added to each command.\n\tdefaultHelpOption = Argument{\n\t\tName:   `help`,\n\t\tShort:  `h`,\n\t\tBrief:  `more information about this command`,\n\t\tOrphan: true,\n\t}\n)\n\n// CommandFromCtx retrieves and returns Command from context.\nfunc CommandFromCtx(ctx context.Context) *Command {\n\tif v := ctx.Value(CtxKeyCommand); v != nil {\n\t\tif p, ok := v.(*Command); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// AddCommand adds one or more sub-commands to current command.\nfunc (c *Command) AddCommand(commands ...*Command) error {\n\tfor _, cmd := range commands {\n\t\tif err := c.doAddCommand(cmd); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// doAddCommand adds one sub-command to current command.\nfunc (c *Command) doAddCommand(command *Command) error {\n\tcommand.Name = gstr.Trim(command.Name)\n\tif command.Name == \"\" {\n\t\treturn gerror.New(\"command name should not be empty\")\n\t}\n\t// Repeated check.\n\tvar (\n\t\tcommandNameSet = gset.NewStrSet()\n\t)\n\tfor _, cmd := range c.commands {\n\t\tcommandNameSet.Add(cmd.Name)\n\t}\n\tif commandNameSet.Contains(command.Name) {\n\t\treturn gerror.Newf(`command \"%s\" is already added to command \"%s\"`, command.Name, c.Name)\n\t}\n\t// Add the given command to its sub-commands array.\n\tcommand.parent = c\n\tc.commands = append(c.commands, command)\n\treturn nil\n}\n\n// AddObject adds one or more sub-commands to current command using struct object.\nfunc (c *Command) AddObject(objects ...any) error {\n\tvar commands []*Command\n\tfor _, object := range objects {\n\t\trootCommand, err := NewFromObject(object)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcommands = append(commands, rootCommand)\n\t}\n\treturn c.AddCommand(commands...)\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_command_help.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Print prints help info to stdout for current command.\nfunc (c *Command) Print() {\n\tc.PrintTo(os.Stdout)\n}\n\n// PrintTo prints help info to custom io.Writer.\nfunc (c *Command) PrintTo(writer io.Writer) {\n\tvar (\n\t\tprefix    = gstr.Repeat(\" \", 4)\n\t\tbuffer    = bytes.NewBuffer(nil)\n\t\targuments = make([]Argument, len(c.Arguments))\n\t)\n\t// Copy options for printing.\n\tcopy(arguments, c.Arguments)\n\t// Add built-in help option, just for info only.\n\targuments = append(arguments, defaultHelpOption)\n\n\t// Usage.\n\tif c.Usage != \"\" || c.Name != \"\" {\n\t\tbuffer.WriteString(\"USAGE\\n\")\n\t\tbuffer.WriteString(prefix)\n\t\tif c.Usage != \"\" {\n\t\t\tbuffer.WriteString(c.Usage)\n\t\t} else {\n\t\t\tvar (\n\t\t\t\tp    = c\n\t\t\t\tname = c.Name\n\t\t\t)\n\t\t\tfor p.parent != nil {\n\t\t\t\tname = p.parent.Name + \" \" + name\n\t\t\t\tp = p.parent\n\t\t\t}\n\t\t\tbuffer.WriteString(name)\n\t\t\tif len(c.commands) > 0 {\n\t\t\t\tbuffer.WriteString(` COMMAND`)\n\t\t\t}\n\t\t\tif c.hasArgumentFromIndex() {\n\t\t\t\tbuffer.WriteString(` ARGUMENT`)\n\t\t\t}\n\t\t\tbuffer.WriteString(` [OPTION]`)\n\t\t}\n\t\tbuffer.WriteString(\"\\n\\n\")\n\t}\n\t// Command.\n\tif len(c.commands) > 0 {\n\t\tbuffer.WriteString(\"COMMAND\\n\")\n\t\tvar (\n\t\t\tmaxSpaceLength = 0\n\t\t)\n\t\tfor _, cmd := range c.commands {\n\t\t\tif len(cmd.Name) > maxSpaceLength {\n\t\t\t\tmaxSpaceLength = len(cmd.Name)\n\t\t\t}\n\t\t}\n\t\tfor _, cmd := range c.commands {\n\t\t\tvar (\n\t\t\t\tspaceLength    = maxSpaceLength - len(cmd.Name)\n\t\t\t\twordwrapPrefix = gstr.Repeat(\" \", len(prefix+cmd.Name)+spaceLength+4)\n\t\t\t)\n\t\t\tc.printLineBrief(printLineBriefInput{\n\t\t\t\tBuffer:         buffer,\n\t\t\t\tName:           cmd.Name,\n\t\t\t\tPrefix:         prefix,\n\t\t\t\tBrief:          gstr.Trim(cmd.Brief),\n\t\t\t\tWordwrapPrefix: wordwrapPrefix,\n\t\t\t\tSpaceLength:    spaceLength,\n\t\t\t})\n\t\t}\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\n\t// Argument.\n\tif c.hasArgumentFromIndex() {\n\t\tbuffer.WriteString(\"ARGUMENT\\n\")\n\t\tvar (\n\t\t\tmaxSpaceLength = 0\n\t\t)\n\t\tfor _, arg := range arguments {\n\t\t\tif !arg.IsArg {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(arg.Name) > maxSpaceLength {\n\t\t\t\tmaxSpaceLength = len(arg.Name)\n\t\t\t}\n\t\t}\n\t\tfor _, arg := range arguments {\n\t\t\tif !arg.IsArg {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tspaceLength    = maxSpaceLength - len(arg.Name)\n\t\t\t\twordwrapPrefix = gstr.Repeat(\" \", len(prefix+arg.Name)+spaceLength+4)\n\t\t\t)\n\t\t\tc.printLineBrief(printLineBriefInput{\n\t\t\t\tBuffer:         buffer,\n\t\t\t\tName:           arg.Name,\n\t\t\t\tPrefix:         prefix,\n\t\t\t\tBrief:          gstr.Trim(arg.Brief),\n\t\t\t\tWordwrapPrefix: wordwrapPrefix,\n\t\t\t\tSpaceLength:    spaceLength,\n\t\t\t})\n\t\t}\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\n\t// Option.\n\tif c.hasArgumentFromOption() {\n\t\tbuffer.WriteString(\"OPTION\\n\")\n\t\tvar (\n\t\t\tnameStr        string\n\t\t\tmaxSpaceLength = 0\n\t\t)\n\t\tfor _, arg := range arguments {\n\t\t\tif arg.IsArg {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif arg.Short != \"\" {\n\t\t\t\tnameStr = fmt.Sprintf(\"-%s,--%s\", arg.Short, arg.Name)\n\t\t\t} else {\n\t\t\t\tnameStr = fmt.Sprintf(\"-/--%s\", arg.Name)\n\t\t\t}\n\t\t\tif len(nameStr) > maxSpaceLength {\n\t\t\t\tmaxSpaceLength = len(nameStr)\n\t\t\t}\n\t\t}\n\t\tfor _, arg := range arguments {\n\t\t\tif arg.IsArg {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif arg.Short != \"\" {\n\t\t\t\tnameStr = fmt.Sprintf(\"-%s, --%s\", arg.Short, arg.Name)\n\t\t\t} else {\n\t\t\t\tnameStr = fmt.Sprintf(\"-/--%s\", arg.Name)\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tbrief          = gstr.Trim(arg.Brief)\n\t\t\t\tspaceLength    = maxSpaceLength - len(nameStr)\n\t\t\t\twordwrapPrefix = gstr.Repeat(\" \", len(prefix+nameStr)+spaceLength+4)\n\t\t\t)\n\t\t\tif arg.Default != \"\" {\n\t\t\t\tbrief = fmt.Sprintf(\"%s (default: \\\"%s\\\")\", brief, arg.Default)\n\t\t\t}\n\t\t\tc.printLineBrief(printLineBriefInput{\n\t\t\t\tBuffer:         buffer,\n\t\t\t\tName:           nameStr,\n\t\t\t\tPrefix:         prefix,\n\t\t\t\tBrief:          brief,\n\t\t\t\tWordwrapPrefix: wordwrapPrefix,\n\t\t\t\tSpaceLength:    spaceLength,\n\t\t\t})\n\t\t}\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\n\t// Example.\n\tif c.Examples != \"\" {\n\t\tbuffer.WriteString(\"EXAMPLE\\n\")\n\t\tfor _, line := range gstr.SplitAndTrim(gstr.Trim(c.Examples), \"\\n\") {\n\t\t\tbuffer.WriteString(prefix)\n\t\t\tbuffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, \"\\n\"+prefix))\n\t\t\tbuffer.WriteString(\"\\n\")\n\t\t}\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\n\t// Description.\n\tif c.Description != \"\" {\n\t\tbuffer.WriteString(\"DESCRIPTION\\n\")\n\t\tfor _, line := range gstr.SplitAndTrim(gstr.Trim(c.Description), \"\\n\") {\n\t\t\tbuffer.WriteString(prefix)\n\t\t\tbuffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, \"\\n\"+prefix))\n\t\t\tbuffer.WriteString(\"\\n\")\n\t\t}\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\n\t// Additional.\n\tif c.Additional != \"\" {\n\t\tlineStr := gstr.WordWrap(gstr.Trim(c.Additional), maxLineChars, \"\\n\")\n\t\tbuffer.WriteString(lineStr)\n\t\tbuffer.WriteString(\"\\n\")\n\t}\n\tcontent := buffer.String()\n\tcontent = gstr.Replace(content, \"\\t\", \"    \")\n\t_, _ = writer.Write([]byte(content))\n}\n\ntype printLineBriefInput struct {\n\tBuffer         *bytes.Buffer\n\tName           string\n\tPrefix         string\n\tBrief          string\n\tWordwrapPrefix string\n\tSpaceLength    int\n}\n\nfunc (c *Command) printLineBrief(in printLineBriefInput) {\n\tbriefArray := gstr.SplitAndTrim(in.Brief, \"\\n\")\n\tif len(briefArray) == 0 {\n\t\t// If command brief is empty, it just prints its command name.\n\t\tbriefArray = []string{\"\"}\n\t}\n\tfor i, line := range briefArray {\n\t\tvar lineStr string\n\t\tif i == 0 {\n\t\t\tlineStr = fmt.Sprintf(\n\t\t\t\t\"%s%s%s%s\\n\",\n\t\t\t\tin.Prefix, in.Name, gstr.Repeat(\" \", in.SpaceLength+4), line,\n\t\t\t)\n\t\t} else {\n\t\t\tlineStr = fmt.Sprintf(\n\t\t\t\t\"%s%s%s%s\\n\",\n\t\t\t\tin.Prefix, gstr.Repeat(\" \", len(in.Name)), gstr.Repeat(\" \", in.SpaceLength+4), line,\n\t\t\t)\n\t\t}\n\t\tlineStr = gstr.WordWrap(lineStr, maxLineChars, \"\\n\"+in.WordwrapPrefix)\n\t\tin.Buffer.WriteString(lineStr)\n\t}\n}\n\nfunc (c *Command) defaultHelpFunc(ctx context.Context, parser *Parser) error {\n\t// Print command help info to stdout.\n\tc.Print()\n\treturn nil\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_command_object.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nvar (\n\t// defaultValueTags is the struct tag names for default value storing.\n\tdefaultValueTags = []string{\"d\", \"default\"}\n)\n\n// NewFromObject creates and returns a root command object using given object.\nfunc NewFromObject(object any) (rootCmd *Command, err error) {\n\tswitch c := object.(type) {\n\tcase Command:\n\t\treturn &c, nil\n\tcase *Command:\n\t\treturn c, nil\n\t}\n\n\toriginValueAndKind := reflection.OriginValueAndKind(object)\n\tif originValueAndKind.OriginKind != reflect.Struct {\n\t\terr = gerror.Newf(\n\t\t\t`input object should be type of struct, but got \"%s\"`,\n\t\t\toriginValueAndKind.InputValue.Type().String(),\n\t\t)\n\t\treturn\n\t}\n\tvar reflectValue = originValueAndKind.InputValue\n\t// If given `object` is not pointer, it then creates a temporary one,\n\t// of which the value is `reflectValue`.\n\t// It then can retrieve all the methods both of struct/*struct.\n\tif reflectValue.Kind() == reflect.Struct {\n\t\tnewValue := reflect.New(reflectValue.Type())\n\t\tnewValue.Elem().Set(reflectValue)\n\t\treflectValue = newValue\n\t}\n\n\t// Root command creating.\n\trootCmd, err = newCommandFromObjectMeta(object, \"\")\n\tif err != nil {\n\t\treturn\n\t}\n\t// Sub command creating.\n\tvar (\n\t\tnameSet         = gset.NewStrSet()\n\t\trootCommandName = gmeta.Get(object, gtag.Root).String()\n\t\tsubCommands     []*Command\n\t)\n\tif rootCommandName == \"\" {\n\t\trootCommandName = rootCmd.Name\n\t}\n\tfor i := 0; i < reflectValue.NumMethod(); i++ {\n\t\tvar (\n\t\t\tmethod      = reflectValue.Type().Method(i)\n\t\t\tmethodValue = reflectValue.Method(i)\n\t\t\tmethodType  = methodValue.Type()\n\t\t\tmethodCmd   *Command\n\t\t)\n\t\tmethodCmd, err = newCommandFromMethod(object, method, methodValue, methodType)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif nameSet.Contains(methodCmd.Name) {\n\t\t\terr = gerror.Newf(\n\t\t\t\t`command name should be unique, found duplicated command name in method \"%s\"`,\n\t\t\t\tmethodType.String(),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t\tif rootCommandName == methodCmd.Name {\n\t\t\tmethodToRootCmdWhenNameEqual(rootCmd, methodCmd)\n\t\t} else {\n\t\t\tsubCommands = append(subCommands, methodCmd)\n\t\t}\n\t}\n\tif len(subCommands) > 0 {\n\t\terr = rootCmd.AddCommand(subCommands...)\n\t}\n\treturn\n}\n\nfunc methodToRootCmdWhenNameEqual(rootCmd *Command, methodCmd *Command) {\n\tif rootCmd.Usage == \"\" {\n\t\trootCmd.Usage = methodCmd.Usage\n\t}\n\tif rootCmd.Brief == \"\" {\n\t\trootCmd.Brief = methodCmd.Brief\n\t}\n\tif rootCmd.Description == \"\" {\n\t\trootCmd.Description = methodCmd.Description\n\t}\n\tif rootCmd.Examples == \"\" {\n\t\trootCmd.Examples = methodCmd.Examples\n\t}\n\tif rootCmd.Func == nil {\n\t\trootCmd.Func = methodCmd.Func\n\t}\n\tif rootCmd.FuncWithValue == nil {\n\t\trootCmd.FuncWithValue = methodCmd.FuncWithValue\n\t}\n\tif rootCmd.HelpFunc == nil {\n\t\trootCmd.HelpFunc = methodCmd.HelpFunc\n\t}\n\tif len(rootCmd.Arguments) == 0 {\n\t\trootCmd.Arguments = methodCmd.Arguments\n\t}\n\tif !rootCmd.Strict {\n\t\trootCmd.Strict = methodCmd.Strict\n\t}\n\tif rootCmd.Config == \"\" {\n\t\trootCmd.Config = methodCmd.Config\n\t}\n}\n\n// The `object` is the Meta attribute from business object, and the `name` is the command name,\n// commonly from method name, which is used when no name tag is defined in Meta.\nfunc newCommandFromObjectMeta(object any, name string) (command *Command, err error) {\n\tvar metaData = gmeta.Data(object)\n\tif err = gconv.Scan(metaData, &command); err != nil {\n\t\treturn\n\t}\n\t// Name field is necessary.\n\tif command.Name == \"\" {\n\t\tif name == \"\" {\n\t\t\terr = gerror.Newf(\n\t\t\t\t`command name cannot be empty, \"name\" tag not found in meta of struct \"%s\"`,\n\t\t\t\treflect.TypeOf(object).String(),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t\tcommand.Name = name\n\t}\n\tif command.Brief == \"\" {\n\t\tfor _, tag := range []string{gtag.Summary, gtag.SummaryShort, gtag.SummaryShort2} {\n\t\t\tcommand.Brief = metaData[tag]\n\t\t\tif command.Brief != \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif command.Description == \"\" {\n\t\tcommand.Description = metaData[gtag.DescriptionShort]\n\t}\n\tif command.Brief == \"\" && command.Description != \"\" {\n\t\tcommand.Brief = command.Description\n\t\tcommand.Description = \"\"\n\t}\n\tif command.Examples == \"\" {\n\t\tcommand.Examples = metaData[gtag.ExampleShort]\n\t}\n\tif command.Additional == \"\" {\n\t\tcommand.Additional = metaData[gtag.AdditionalShort]\n\t}\n\treturn\n}\n\nfunc newCommandFromMethod(\n\tobject any, method reflect.Method, methodValue reflect.Value, methodType reflect.Type,\n) (command *Command, err error) {\n\t// Necessary validation for input/output parameters and naming.\n\tif methodType.NumIn() != 2 || methodType.NumOut() != 2 {\n\t\tif methodType.PkgPath() != \"\" {\n\t\t\terr = gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid command: %s.%s.%s defined as \"%s\", but \"func(context.Context, Input)(Output, error)\" is required`,\n\t\t\t\tmethodType.PkgPath(), reflect.TypeOf(object).Name(), method.Name, methodType.String(),\n\t\t\t)\n\t\t} else {\n\t\t\terr = gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid command: %s.%s defined as \"%s\", but \"func(context.Context, Input)(Output, error)\" is required`,\n\t\t\t\treflect.TypeOf(object).Name(), method.Name, methodType.String(),\n\t\t\t)\n\t\t}\n\t\treturn\n\t}\n\tif !methodType.In(0).Implements(reflect.TypeOf((*context.Context)(nil)).Elem()) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid command: %s.%s defined as \"%s\", but the first input parameter should be type of \"context.Context\"`,\n\t\t\treflect.TypeOf(object).Name(), method.Name, methodType.String(),\n\t\t)\n\t\treturn\n\t}\n\tif !methodType.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid command: %s.%s defined as \"%s\", but the last output parameter should be type of \"error\"`,\n\t\t\treflect.TypeOf(object).Name(), method.Name, methodType.String(),\n\t\t)\n\t\treturn\n\t}\n\t// The input struct should be named as `xxxInput`.\n\tif !gstr.HasSuffix(methodType.In(1).String(), `Input`) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid struct naming for input: defined as \"%s\", but it should be named with \"Input\" suffix like \"xxxInput\"`,\n\t\t\tmethodType.In(1).String(),\n\t\t)\n\t\treturn\n\t}\n\t// The output struct should be named as `xxxOutput`.\n\tif !gstr.HasSuffix(methodType.Out(0).String(), `Output`) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid struct naming for output: defined as \"%s\", but it should be named with \"Output\" suffix like \"xxxOutput\"`,\n\t\t\tmethodType.Out(0).String(),\n\t\t)\n\t\treturn\n\t}\n\n\tvar inputObject reflect.Value\n\tif methodType.In(1).Kind() == reflect.Pointer {\n\t\tinputObject = reflect.New(methodType.In(1).Elem()).Elem()\n\t} else {\n\t\tinputObject = reflect.New(methodType.In(1)).Elem()\n\t}\n\n\t// Command creating.\n\tif command, err = newCommandFromObjectMeta(inputObject.Interface(), method.Name); err != nil {\n\t\treturn\n\t}\n\n\t// Options creating.\n\tif command.Arguments, err = newArgumentsFromInput(inputObject.Interface()); err != nil {\n\t\treturn\n\t}\n\n\t// For input struct converting using priority tag.\n\tvar priorityTag = gstr.Join([]string{tagNameName, tagNameShort}, \",\")\n\n\t// =============================================================================================\n\t// Create function that has value return.\n\t// =============================================================================================\n\tcommand.FuncWithValue = func(ctx context.Context, parser *Parser) (out any, err error) {\n\t\tctx = context.WithValue(ctx, CtxKeyParser, parser)\n\t\tvar (\n\t\t\tdata        = gconv.Map(parser.GetOptAll())\n\t\t\targIndex    = 0\n\t\t\targuments   = parser.GetArgAll()\n\t\t\tinputValues = []reflect.Value{reflect.ValueOf(ctx)}\n\t\t)\n\t\tif value := ctx.Value(CtxKeyArgumentsIndex); value != nil {\n\t\t\targIndex = value.(int)\n\t\t}\n\t\tif data == nil {\n\t\t\tdata = map[string]any{}\n\t\t}\n\t\t// Handle orphan options.\n\t\tfor _, arg := range command.Arguments {\n\t\t\tif arg.IsArg {\n\t\t\t\t// Read argument from command line index.\n\t\t\t\tif argIndex < len(arguments) {\n\t\t\t\t\tdata[arg.Name] = arguments[argIndex]\n\t\t\t\t\targIndex++\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Read argument from command line option name.\n\t\t\t\tif arg.Orphan {\n\t\t\t\t\tif orphanValue := parser.GetOpt(arg.Name); orphanValue != nil {\n\t\t\t\t\t\tif orphanValue.String() == \"\" {\n\t\t\t\t\t\t\t// Example: gf -f\n\t\t\t\t\t\t\tdata[arg.Name] = \"true\"\n\t\t\t\t\t\t\tif arg.Short != \"\" {\n\t\t\t\t\t\t\t\tdata[arg.Short] = \"true\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Adapter with common user habits.\n\t\t\t\t\t\t\t// Eg:\n\t\t\t\t\t\t\t// `gf -f=0`: which parameter `f` is parsed as false\n\t\t\t\t\t\t\t// `gf -f=1`: which parameter `f` is parsed as true\n\t\t\t\t\t\t\tdata[arg.Name] = orphanValue.Bool()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Default values from struct tag.\n\t\tif err = mergeDefaultStructValue(data, inputObject.Interface()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Construct input parameters.\n\t\tif len(data) > 0 {\n\t\t\tintlog.PrintFunc(ctx, func() string {\n\t\t\t\treturn fmt.Sprintf(`input command data map: %s`, gjson.MustEncode(data))\n\t\t\t})\n\t\t\tif inputObject.Kind() == reflect.Pointer {\n\t\t\t\terr = gconv.StructTag(data, inputObject.Interface(), priorityTag)\n\t\t\t} else {\n\t\t\t\terr = gconv.StructTag(data, inputObject.Addr().Interface(), priorityTag)\n\t\t\t}\n\t\t\tintlog.PrintFunc(ctx, func() string {\n\t\t\t\treturn fmt.Sprintf(`input object assigned data: %s`, gjson.MustEncode(inputObject.Interface()))\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// Parameters validation.\n\t\tif err = gvalid.New().Bail().Data(inputObject.Interface()).Assoc(data).Run(ctx); err != nil {\n\t\t\terr = gerror.Wrapf(gerror.Current(err), `arguments validation failed for command \"%s\"`, command.Name)\n\t\t\treturn\n\t\t}\n\t\tinputValues = append(inputValues, inputObject)\n\n\t\t// Call handler with dynamic created parameter values.\n\t\tresults := methodValue.Call(inputValues)\n\t\tout = results[0].Interface()\n\t\tif !results[1].IsNil() {\n\t\t\tif v, ok := results[1].Interface().(error); ok {\n\t\t\t\terr = v\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\treturn\n}\n\nfunc newArgumentsFromInput(object any) (args []Argument, err error) {\n\tvar (\n\t\tfields   []gstructs.Field\n\t\tnameSet  = gset.NewStrSet()\n\t\tshortSet = gset.NewStrSet()\n\t)\n\tfields, err = gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         object,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t})\n\tfor _, field := range fields {\n\t\tvar (\n\t\t\targ      = Argument{}\n\t\t\tmetaData = field.TagMap()\n\t\t)\n\t\tif err = gconv.Scan(metaData, &arg); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif arg.Name == \"\" {\n\t\t\targ.Name = field.Name()\n\t\t}\n\t\tif arg.Name == helpOptionName {\n\t\t\treturn nil, gerror.Newf(\n\t\t\t\t`argument name \"%s\" defined in \"%s.%s\" is already token by built-in arguments`,\n\t\t\t\targ.Name, reflect.TypeOf(object).String(), field.Name(),\n\t\t\t)\n\t\t}\n\t\tif arg.Short == helpOptionNameShort {\n\t\t\treturn nil, gerror.Newf(\n\t\t\t\t`short argument name \"%s\" defined in \"%s.%s\" is already token by built-in arguments`,\n\t\t\t\targ.Short, reflect.TypeOf(object).String(), field.Name(),\n\t\t\t)\n\t\t}\n\t\tif arg.Brief == \"\" {\n\t\t\targ.Brief = field.TagDescription()\n\t\t}\n\t\tif arg.Default == \"\" {\n\t\t\targ.Default = field.TagDefault()\n\t\t}\n\t\tif v, ok := metaData[gtag.Arg]; ok {\n\t\t\targ.IsArg = gconv.Bool(v)\n\t\t}\n\t\tif nameSet.Contains(arg.Name) {\n\t\t\treturn nil, gerror.Newf(\n\t\t\t\t`argument name \"%s\" defined in \"%s.%s\" is already token by other argument`,\n\t\t\t\targ.Name, reflect.TypeOf(object).String(), field.Name(),\n\t\t\t)\n\t\t}\n\t\tnameSet.Add(arg.Name)\n\n\t\tif arg.Short != \"\" {\n\t\t\tif shortSet.Contains(arg.Short) {\n\t\t\t\treturn nil, gerror.Newf(\n\t\t\t\t\t`short argument name \"%s\" defined in \"%s.%s\" is already token by other argument`,\n\t\t\t\t\targ.Short, reflect.TypeOf(object).String(), field.Name(),\n\t\t\t\t)\n\t\t\t}\n\t\t\tshortSet.Add(arg.Short)\n\t\t}\n\n\t\targs = append(args, arg)\n\t}\n\n\treturn\n}\n\n// mergeDefaultStructValue merges the request parameters with default values from struct tag definition.\nfunc mergeDefaultStructValue(data map[string]any, pointer any) error {\n\ttagFields, err := gstructs.TagFields(pointer, defaultValueTags)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(tagFields) > 0 {\n\t\tvar (\n\t\t\tfoundKey   string\n\t\t\tfoundValue any\n\t\t)\n\t\tfor _, field := range tagFields {\n\t\t\tvar (\n\t\t\t\tnameValue  = field.Tag(tagNameName)\n\t\t\t\tshortValue = field.Tag(tagNameShort)\n\t\t\t)\n\t\t\t// If it already has value, it then ignores the default value.\n\t\t\tif value, ok := data[nameValue]; ok {\n\t\t\t\tdata[field.Name()] = value\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif value, ok := data[shortValue]; ok {\n\t\t\t\tdata[field.Name()] = value\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfoundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())\n\t\t\tif foundKey == \"\" {\n\t\t\t\tdata[field.Name()] = field.TagValue\n\t\t\t} else {\n\t\t\t\tif utils.IsEmpty(foundValue) {\n\t\t\t\t\tdata[foundKey] = field.TagValue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_command_run.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/gcfg\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Run calls custom function in os.Args that bound to this command.\n// It exits this process with exit code 1 if any error occurs.\nfunc (c *Command) Run(ctx context.Context) {\n\t_ = c.RunWithValue(ctx)\n}\n\n// RunWithValue calls custom function in os.Args that bound to this command with value output.\n// It exits this process with exit code 1 if any error occurs.\nfunc (c *Command) RunWithValue(ctx context.Context) (value any) {\n\tvalue, err := c.RunWithValueError(ctx)\n\tif err != nil {\n\t\tvar (\n\t\t\tcode   = gerror.Code(err)\n\t\t\tdetail = code.Detail()\n\t\t\tbuffer = bytes.NewBuffer(nil)\n\t\t)\n\t\tif code.Code() == gcode.CodeNotFound.Code() {\n\t\t\tfmt.Fprintf(buffer, \"ERROR: %s\\n\", gstr.Trim(err.Error()))\n\t\t\tif lastCmd, ok := detail.(*Command); ok {\n\t\t\t\tlastCmd.PrintTo(buffer)\n\t\t\t} else {\n\t\t\t\tc.PrintTo(buffer)\n\t\t\t}\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer, \"%+v\\n\", err)\n\t\t}\n\t\tif gtrace.GetTraceID(ctx) == \"\" {\n\t\t\tfmt.Println(buffer.String())\n\t\t\tos.Exit(1)\n\t\t}\n\t\tglog.Stack(false).Fatal(ctx, buffer.String())\n\t}\n\treturn value\n}\n\n// RunWithError calls custom function in os.Args that bound to this command with error output.\nfunc (c *Command) RunWithError(ctx context.Context) (err error) {\n\t_, err = c.RunWithValueError(ctx)\n\treturn\n}\n\n// RunWithValueError calls custom function in os.Args that bound to this command with value and error output.\nfunc (c *Command) RunWithValueError(ctx context.Context) (value any, err error) {\n\treturn c.RunWithSpecificArgs(ctx, os.Args)\n}\n\n// RunWithSpecificArgs calls custom function in specific args that bound to this command with value and error output.\nfunc (c *Command) RunWithSpecificArgs(ctx context.Context, args []string) (value any, err error) {\n\tif len(args) == 0 {\n\t\treturn nil, gerror.NewCode(gcode.CodeInvalidParameter, \"args can not be empty!\")\n\t}\n\tparser, err := ParseArgs(args, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tparsedArgs := parser.GetArgAll()\n\n\t// Exclude the root binary name.\n\tparsedArgs = parsedArgs[1:]\n\n\t// If no args or no sub command, it runs standalone.\n\tif len(parsedArgs) == 0 || len(c.commands) == 0 {\n\t\treturn c.doRun(ctx, args, parser)\n\t}\n\n\t// Find the matched command and run it.\n\t// It here `fromArgIndex` set to 1 to calculate the argument index in to `newCtx`.\n\tlastCmd, foundCmd, newCtx := c.searchCommand(ctx, parsedArgs, 1)\n\tif foundCmd != nil {\n\t\treturn foundCmd.doRun(newCtx, args, parser)\n\t}\n\n\t// Print error and help command if no command found.\n\terr = gerror.NewCodef(\n\t\tgcode.WithCode(gcode.CodeNotFound, lastCmd),\n\t\t`command \"%s\" not found for command \"%s\", command line: %s`,\n\t\tgstr.Join(parsedArgs, \" \"),\n\t\tc.Name,\n\t\tgstr.Join(args, \" \"),\n\t)\n\treturn\n}\n\nfunc (c *Command) doRun(ctx context.Context, args []string, parser *Parser) (value any, err error) {\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodef(gcode.CodeInternalPanic, \"exception recovered: %+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\n\tctx = context.WithValue(ctx, CtxKeyCommand, c)\n\t// Check built-in help command.\n\tif parser.GetOpt(helpOptionName) != nil || parser.GetOpt(helpOptionNameShort) != nil {\n\t\tif c.HelpFunc != nil {\n\t\t\treturn nil, c.HelpFunc(ctx, parser)\n\t\t}\n\t\treturn nil, c.defaultHelpFunc(ctx, parser)\n\t}\n\n\t// OpenTelemetry for command.\n\tvar (\n\t\tspan trace.Span\n\t\ttr   = otel.GetTracerProvider().Tracer(\n\t\t\ttracingInstrumentName,\n\t\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t\t)\n\t)\n\tctx, span = tr.Start(\n\t\totel.GetTextMapPropagator().Extract(\n\t\t\tctx,\n\t\t\tpropagation.MapCarrier(genv.Map()),\n\t\t),\n\t\tgstr.Join(os.Args, \" \"),\n\t\ttrace.WithSpanKind(trace.SpanKindServer),\n\t)\n\tdefer span.End()\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\t// Reparse the original arguments for current command configuration.\n\tparser, err = c.reParse(ctx, args, parser)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Registered command function calling.\n\tif c.Func != nil {\n\t\treturn nil, c.Func(ctx, parser)\n\t}\n\tif c.FuncWithValue != nil {\n\t\treturn c.FuncWithValue(ctx, parser)\n\t}\n\t// If no function defined in current command, it then prints help.\n\tif c.HelpFunc != nil {\n\t\treturn nil, c.HelpFunc(ctx, parser)\n\t}\n\treturn nil, c.defaultHelpFunc(ctx, parser)\n}\n\n// reParse parses the original arguments using option configuration of current command.\nfunc (c *Command) reParse(ctx context.Context, args []string, parser *Parser) (*Parser, error) {\n\tif len(c.Arguments) == 0 {\n\t\treturn parser, nil\n\t}\n\tvar (\n\t\toptionKey        string\n\t\tsupportedOptions = make(map[string]bool)\n\t)\n\tfor _, arg := range c.Arguments {\n\t\tif arg.IsArg {\n\t\t\tcontinue\n\t\t}\n\t\tif arg.Short != \"\" {\n\t\t\toptionKey = fmt.Sprintf(`%s,%s`, arg.Name, arg.Short)\n\t\t} else {\n\t\t\toptionKey = arg.Name\n\t\t}\n\t\tsupportedOptions[optionKey] = !arg.Orphan\n\t}\n\tparser, err := ParseArgs(args, supportedOptions, ParserOption{\n\t\tCaseSensitive: c.CaseSensitive,\n\t\tStrict:        c.Strict,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Retrieve option values from config component if it has \"config\" tag.\n\tif c.Config != \"\" && gcfg.Instance().Available(ctx) {\n\t\tvalue, err := gcfg.Instance().Get(ctx, c.Config)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconfigMap := value.Map()\n\t\tfor optionName := range parser.supportedOptions {\n\t\t\t// The command line has the high priority.\n\t\t\tif parser.GetOpt(optionName) != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Merge the config value into parser.\n\t\t\tfoundKey, foundValue := gutil.MapPossibleItemByKey(configMap, optionName)\n\t\t\tif foundKey != \"\" {\n\t\t\t\tparser.parsedOptions[optionName] = gconv.String(foundValue)\n\t\t\t}\n\t\t}\n\t}\n\treturn parser, nil\n}\n\n// searchCommand recursively searches the command according given arguments.\nfunc (c *Command) searchCommand(\n\tctx context.Context, args []string, fromArgIndex int,\n) (lastCmd, foundCmd *Command, newCtx context.Context) {\n\tif len(args) == 0 {\n\t\treturn c, nil, ctx\n\t}\n\tfor _, cmd := range c.commands {\n\t\t// Recursively searching the command.\n\t\t// String comparison case-sensitive.\n\t\tif cmd.Name == args[0] {\n\t\t\tleftArgs := args[1:]\n\t\t\t// If this command needs argument,\n\t\t\t// it then gives all its left arguments to it using arg index marks.\n\t\t\t//\n\t\t\t// Note that the args here (using default args parsing) could be different with the args\n\t\t\t// that are parsed in command.\n\t\t\tif cmd.hasArgumentFromIndex() || len(leftArgs) == 0 {\n\t\t\t\tctx = context.WithValue(ctx, CtxKeyArgumentsIndex, fromArgIndex+1)\n\t\t\t\treturn c, cmd, ctx\n\t\t\t}\n\t\t\treturn cmd.searchCommand(ctx, leftArgs, fromArgIndex+1)\n\t\t}\n\t}\n\treturn c, nil, ctx\n}\n\nfunc (c *Command) hasArgumentFromIndex() bool {\n\tfor _, arg := range c.Arguments {\n\t\tif arg.IsArg {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (c *Command) hasArgumentFromOption() bool {\n\tfor _, arg := range c.Arguments {\n\t\tif !arg.IsArg {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_parser.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// ParserOption manages the parsing options.\ntype ParserOption struct {\n\tCaseSensitive bool // Marks options parsing in case-sensitive way.\n\tStrict        bool // Whether stops parsing and returns error if invalid option passed.\n}\n\n// Parser for arguments.\ntype Parser struct {\n\toption           ParserOption      // Parse option.\n\tparsedArgs       []string          // As name described.\n\tparsedOptions    map[string]string // As name described.\n\tpassedOptions    map[string]bool   // User passed supported options, like: map[string]bool{\"name,n\":true}\n\tsupportedOptions map[string]bool   // Option [OptionName:WhetherNeedArgument], like: map[string]bool{\"name\":true, \"n\":true}\n\tcommandFuncMap   map[string]func() // Command function map for function handler.\n}\n\n// ParserFromCtx retrieves and returns Parser from context.\nfunc ParserFromCtx(ctx context.Context) *Parser {\n\tif v := ctx.Value(CtxKeyParser); v != nil {\n\t\tif p, ok := v.(*Parser); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Parse creates and returns a new Parser with os.Args and supported options.\n//\n// Note that the parameter `supportedOptions` is as [option name: need argument], which means\n// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.\n//\n// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.\nfunc Parse(supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {\n\tif supportedOptions == nil {\n\t\tcommand.Init(os.Args...)\n\t\treturn &Parser{\n\t\t\tparsedArgs:    GetArgAll(),\n\t\t\tparsedOptions: GetOptAll(),\n\t\t}, nil\n\t}\n\treturn ParseArgs(os.Args, supportedOptions, option...)\n}\n\n// ParseArgs creates and returns a new Parser with given arguments and supported options.\n//\n// Note that the parameter `supportedOptions` is as [option name: need argument], which means\n// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.\n//\n// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.\nfunc ParseArgs(args []string, supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {\n\tif supportedOptions == nil {\n\t\tcommand.Init(args...)\n\t\treturn &Parser{\n\t\t\tparsedArgs:    GetArgAll(),\n\t\t\tparsedOptions: GetOptAll(),\n\t\t}, nil\n\t}\n\tvar parserOption ParserOption\n\tif len(option) > 0 {\n\t\tparserOption = option[0]\n\t}\n\tparser := &Parser{\n\t\toption:           parserOption,\n\t\tparsedArgs:       make([]string, 0),\n\t\tparsedOptions:    make(map[string]string),\n\t\tpassedOptions:    supportedOptions,\n\t\tsupportedOptions: make(map[string]bool),\n\t\tcommandFuncMap:   make(map[string]func()),\n\t}\n\tfor name, needArgument := range supportedOptions {\n\t\tfor _, v := range strings.Split(name, \",\") {\n\t\t\tparser.supportedOptions[strings.TrimSpace(v)] = needArgument\n\t\t}\n\t}\n\n\tfor i := 0; i < len(args); {\n\t\tif option := parser.parseOption(args[i]); option != \"\" {\n\t\t\tarray, _ := gregex.MatchString(`^(.+?)=(.+)$`, option)\n\t\t\tif len(array) == 3 {\n\t\t\t\tif parser.isOptionValid(array[1]) {\n\t\t\t\t\tparser.setOptionValue(array[1], array[2])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif parser.isOptionValid(option) {\n\t\t\t\t\tif parser.isOptionNeedArgument(option) {\n\t\t\t\t\t\tif i < len(args)-1 {\n\t\t\t\t\t\t\tparser.setOptionValue(option, args[i+1])\n\t\t\t\t\t\t\ti += 2\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparser.setOptionValue(option, \"\")\n\t\t\t\t\t\ti++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Multiple options?\n\t\t\t\t\tif array = parser.parseMultiOption(option); len(array) > 0 {\n\t\t\t\t\t\tfor _, v := range array {\n\t\t\t\t\t\t\tparser.setOptionValue(v, \"\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\ti++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t} else if parser.option.Strict {\n\t\t\t\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid option '%s'`, args[i])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tparser.parsedArgs = append(parser.parsedArgs, args[i])\n\t\t}\n\t\ti++\n\t}\n\treturn parser, nil\n}\n\n// parseMultiOption parses option to multiple valid options like: --dav.\n// It returns nil if given option is not multi-option.\nfunc (p *Parser) parseMultiOption(option string) []string {\n\tfor i := 1; i <= len(option); i++ {\n\t\ts := option[:i]\n\t\tif p.isOptionValid(s) && !p.isOptionNeedArgument(s) {\n\t\t\tif i == len(option) {\n\t\t\t\treturn []string{s}\n\t\t\t}\n\t\t\tarray := p.parseMultiOption(option[i:])\n\t\t\tif len(array) == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn append(array, s)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (p *Parser) parseOption(argument string) string {\n\tarray, _ := gregex.MatchString(`^\\-{1,2}(.+)$`, argument)\n\tif len(array) == 2 {\n\t\treturn array[1]\n\t}\n\treturn \"\"\n}\n\nfunc (p *Parser) isOptionValid(name string) bool {\n\t// Case-Sensitive.\n\tif p.option.CaseSensitive {\n\t\t_, ok := p.supportedOptions[name]\n\t\treturn ok\n\t}\n\t// Case-InSensitive.\n\tfor optionName := range p.supportedOptions {\n\t\tif gstr.Equal(optionName, name) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (p *Parser) isOptionNeedArgument(name string) bool {\n\treturn p.supportedOptions[name]\n}\n\n// setOptionValue sets the option value for name and according alias.\nfunc (p *Parser) setOptionValue(name, value string) {\n\t// Accurate option name match.\n\tfor optionName := range p.passedOptions {\n\t\toptionNameAndShort := gstr.SplitAndTrim(optionName, \",\")\n\t\tfor _, optionNameItem := range optionNameAndShort {\n\t\t\tif optionNameItem == name {\n\t\t\t\tfor _, v := range optionNameAndShort {\n\t\t\t\t\tp.parsedOptions[v] = value\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\t// Fuzzy option name match.\n\tfor optionName := range p.passedOptions {\n\t\toptionNameAndShort := gstr.SplitAndTrim(optionName, \",\")\n\t\tfor _, optionNameItem := range optionNameAndShort {\n\t\t\tif strings.EqualFold(optionNameItem, name) {\n\t\t\t\tfor _, v := range optionNameAndShort {\n\t\t\t\t\tp.parsedOptions[v] = value\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// GetOpt returns the option value named `name` as gvar.Var.\nfunc (p *Parser) GetOpt(name string, def ...any) *gvar.Var {\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif v, ok := p.parsedOptions[name]; ok {\n\t\treturn gvar.New(v)\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetOptAll returns all parsed options.\nfunc (p *Parser) GetOptAll() map[string]string {\n\tif p == nil {\n\t\treturn nil\n\t}\n\treturn p.parsedOptions\n}\n\n// GetArg returns the argument at `index` as gvar.Var.\nfunc (p *Parser) GetArg(index int, def ...string) *gvar.Var {\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif index >= 0 && index < len(p.parsedArgs) {\n\t\treturn gvar.New(p.parsedArgs[index])\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// GetArgAll returns all parsed arguments.\nfunc (p *Parser) GetArgAll() []string {\n\tif p == nil {\n\t\treturn nil\n\t}\n\treturn p.parsedArgs\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (p *Parser) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(map[string]any{\n\t\t\"parsedArgs\":       p.parsedArgs,\n\t\t\"parsedOptions\":    p.parsedOptions,\n\t\t\"passedOptions\":    p.passedOptions,\n\t\t\"supportedOptions\": p.supportedOptions,\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_scan.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n\npackage gcmd\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Scan prints `info` to stdout, reads and returns user input, which stops by '\\n'.\nfunc Scan(info ...any) string {\n\tfmt.Print(info...)\n\treturn readline()\n}\n\n// Scanf prints `info` to stdout with `format`, reads and returns user input, which stops by '\\n'.\nfunc Scanf(format string, info ...any) string {\n\tfmt.Printf(format, info...)\n\treturn readline()\n}\n\nfunc readline() string {\n\tvar s string\n\treader := bufio.NewReader(os.Stdin)\n\ts, _ = reader.ReadString('\\n')\n\ts = gstr.Trim(s)\n\treturn s\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n)\n\nfunc ExampleInit() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\tfmt.Printf(`%#v`, gcmd.GetArgAll())\n\n\t// Output:\n\t// []string{\"gf\", \"build\", \"main.go\"}\n}\n\nfunc ExampleGetArg() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\tfmt.Printf(\n\t\t`Arg[0]: \"%v\", Arg[1]: \"%v\", Arg[2]: \"%v\", Arg[3]: \"%v\"`,\n\t\tgcmd.GetArg(0), gcmd.GetArg(1), gcmd.GetArg(2), gcmd.GetArg(3),\n\t)\n\n\t// Output:\n\t// Arg[0]: \"gf\", Arg[1]: \"build\", Arg[2]: \"main.go\", Arg[3]: \"\"\n}\n\nfunc ExampleGetArgAll() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\tfmt.Printf(`%#v`, gcmd.GetArgAll())\n\n\t// Output:\n\t// []string{\"gf\", \"build\", \"main.go\"}\n}\n\nfunc ExampleGetOpt() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\tfmt.Printf(\n\t\t`Opt[\"o\"]: \"%v\", Opt[\"y\"]: \"%v\", Opt[\"d\"]: \"%v\"`,\n\t\tgcmd.GetOpt(\"o\"), gcmd.GetOpt(\"y\"), gcmd.GetOpt(\"d\", \"default value\"),\n\t)\n\n\t// Output:\n\t// Opt[\"o\"]: \"gf.exe\", Opt[\"y\"]: \"\", Opt[\"d\"]: \"default value\"\n}\n\nfunc ExampleGetOpt_def() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\n\tfmt.Println(gcmd.GetOpt(\"s\", \"Def\").String())\n\n\t// Output:\n\t// Def\n}\n\nfunc ExampleGetOptAll() {\n\tgcmd.Init(\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\")\n\tfmt.Printf(`%#v`, gcmd.GetOptAll())\n\n\t// May Output:\n\t// map[string]string{\"o\":\"gf.exe\", \"y\":\"\"}\n}\n\nfunc ExampleGetOptWithEnv() {\n\tfmt.Printf(\"Opt[gf.test]:%s\\n\", gcmd.GetOptWithEnv(\"gf.test\"))\n\t_ = genv.Set(\"GF_TEST\", \"YES\")\n\tfmt.Printf(\"Opt[gf.test]:%s\\n\", gcmd.GetOptWithEnv(\"gf.test\"))\n\n\t// Output:\n\t// Opt[gf.test]:\n\t// Opt[gf.test]:YES\n}\n\nfunc ExampleParse() {\n\tos.Args = []string{\"gf\", \"build\", \"main.go\", \"-o=gf.exe\", \"-y\"}\n\tp, err := gcmd.Parse(g.MapStrBool{\n\t\t\"o,output\": true,\n\t\t\"y,yes\":    false,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(p.GetOpt(\"o\"))\n\tfmt.Println(p.GetOpt(\"output\"))\n\tfmt.Println(p.GetOpt(\"y\") != nil)\n\tfmt.Println(p.GetOpt(\"yes\") != nil)\n\tfmt.Println(p.GetOpt(\"none\") != nil)\n\tfmt.Println(p.GetOpt(\"none\", \"Def\"))\n\n\t// Output:\n\t// gf.exe\n\t// gf.exe\n\t// true\n\t// true\n\t// false\n\t// Def\n}\n\nfunc ExampleCommandFromCtx() {\n\tvar (\n\t\tcommand = gcmd.Command{\n\t\t\tName: \"start\",\n\t\t}\n\t)\n\n\tctx := context.WithValue(gctx.New(), gcmd.CtxKeyCommand, &command)\n\tunAddCtx := context.WithValue(gctx.New(), gcmd.CtxKeyCommand, &gcmd.Command{})\n\tnonKeyCtx := context.WithValue(gctx.New(), \"Testkey\", &gcmd.Command{})\n\n\tfmt.Println(gcmd.CommandFromCtx(ctx).Name)\n\tfmt.Println(gcmd.CommandFromCtx(unAddCtx).Name)\n\tfmt.Println(gcmd.CommandFromCtx(nonKeyCtx) == nil)\n\n\t// Output:\n\t// start\n\t//\n\t// true\n}\n\nfunc ExampleCommand_AddCommand() {\n\tcommandRoot := &gcmd.Command{\n\t\tName: \"gf\",\n\t}\n\tcommandRoot.AddCommand(&gcmd.Command{\n\t\tName: \"start\",\n\t}, &gcmd.Command{})\n\n\tcommandRoot.Print()\n\n\t// Output:\n\t// USAGE\n\t//     gf COMMAND [OPTION]\n\t//\n\t// COMMAND\n\t//     start\n}\n\nfunc ExampleCommand_AddCommand_repeat() {\n\tcommandRoot := &gcmd.Command{\n\t\tName: \"gf\",\n\t}\n\terr := commandRoot.AddCommand(&gcmd.Command{\n\t\tName: \"start\",\n\t}, &gcmd.Command{\n\t\tName: \"stop\",\n\t}, &gcmd.Command{\n\t\tName: \"start\",\n\t})\n\n\tfmt.Println(err)\n\n\t// Output:\n\t// command \"start\" is already added to command \"gf\"\n}\n\nfunc ExampleCommand_AddObject() {\n\tvar (\n\t\tcommand = gcmd.Command{\n\t\t\tName: \"start\",\n\t\t}\n\t)\n\n\tcommand.AddObject(&TestCmdObject{})\n\n\tcommand.Print()\n\n\t// Output:\n\t// USAGE\n\t//     start COMMAND [OPTION]\n\t//\n\t// COMMAND\n\t//     root    root env command\n}\n\nfunc ExampleCommand_AddObject_error() {\n\tvar (\n\t\tcommand = gcmd.Command{\n\t\t\tName: \"start\",\n\t\t}\n\t)\n\n\terr := command.AddObject(&[]string{\"Test\"})\n\n\tfmt.Println(err)\n\n\t// Output:\n\t// input object should be type of struct, but got \"*[]string\"\n}\n\nfunc ExampleCommand_Print() {\n\tcommandRoot := &gcmd.Command{\n\t\tName: \"gf\",\n\t}\n\tcommandRoot.AddCommand(&gcmd.Command{\n\t\tName: \"start\",\n\t}, &gcmd.Command{})\n\n\tcommandRoot.Print()\n\n\t// Output:\n\t// USAGE\n\t//     gf COMMAND [OPTION]\n\t//\n\t// COMMAND\n\t//     start\n}\n\nfunc ExampleScan() {\n\tfmt.Println(gcmd.Scan(\"gf scan\"))\n\n\t// Output:\n\t// gf scan\n}\n\nfunc ExampleScanf() {\n\tfmt.Println(gcmd.Scanf(\"gf %s\", \"scanf\"))\n\n\t// Output:\n\t// gf scanf\n}\n\nfunc ExampleParserFromCtx() {\n\tparser, _ := gcmd.Parse(nil)\n\n\tctx := context.WithValue(gctx.New(), gcmd.CtxKeyParser, parser)\n\tnilCtx := context.WithValue(gctx.New(), \"NilCtxKeyParser\", parser)\n\n\tfmt.Println(gcmd.ParserFromCtx(ctx).GetArgAll())\n\tfmt.Println(gcmd.ParserFromCtx(nilCtx) == nil)\n\n\t// Output:\n\t// [gf build main.go]\n\t// true\n}\n\nfunc ExampleParseArgs() {\n\tp, _ := gcmd.ParseArgs([]string{\n\t\t\"gf\", \"--force\", \"remove\", \"-fq\", \"-p=www\", \"path\", \"-n\", \"root\",\n\t}, nil)\n\n\tfmt.Println(p.GetArgAll())\n\tfmt.Println(p.GetOptAll())\n\n\t// Output:\n\t// [gf path]\n\t// map[force:remove fq: n:root p:www]\n}\n\nfunc ExampleParser_GetArg() {\n\tp, _ := gcmd.ParseArgs([]string{\n\t\t\"gf\", \"--force\", \"remove\", \"-fq\", \"-p=www\", \"path\", \"-n\", \"root\",\n\t}, nil)\n\n\tfmt.Println(p.GetArg(-1, \"Def\").String())\n\tfmt.Println(p.GetArg(-1) == nil)\n\n\t// Output:\n\t// Def\n\t// true\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_feature_object1_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype TestCmdObject struct {\n\tg.Meta `name:\"root\" usage:\"root env/test\" brief:\"root env command\" dc:\"description\" ad:\"ad\"`\n}\n\ntype TestCmdObjectEnvInput struct {\n\tg.Meta `name:\"env\" usage:\"root env\" brief:\"root env command\" dc:\"root env command description\" ad:\"root env command ad\"`\n}\n\ntype TestCmdObjectEnvOutput struct{}\n\ntype TestCmdObjectTestInput struct {\n\tg.Meta  `name:\"test\" usage:\"root test\" brief:\"root test command\" dc:\"root test command description\" ad:\"root test command ad\"`\n\tName    string `name:\"yourname\" v:\"required\" short:\"n\" orphan:\"false\" brief:\"name for test command\" d:\"tom\"`\n\tVersion bool   `name:\"version\" short:\"v\" orphan:\"true\" brief:\"show version\"`\n}\n\ntype TestCmdObjectTestOutput struct {\n\tName    string\n\tVersion bool\n}\n\nfunc (TestCmdObject) Env(ctx context.Context, in TestCmdObjectEnvInput) (out *TestCmdObjectEnvOutput, err error) {\n\treturn\n}\n\nfunc (TestCmdObject) Test(ctx context.Context, in TestCmdObjectTestInput) (out *TestCmdObjectTestOutput, err error) {\n\tout = &TestCmdObjectTestOutput{\n\t\tName:    in.Name,\n\t\tVersion: in.Version,\n\t}\n\treturn\n}\n\nfunc Test_Command_NewFromObject_Help(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tcmd, err = gcmd.NewFromObject(&TestCmdObject{})\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(cmd.Name, \"root\")\n\n\t\tos.Args = []string{\"root\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, nil)\n\t})\n}\n\nfunc Test_Command_NewFromObject_Run(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tcmd, err = gcmd.NewFromObject(&TestCmdObject{})\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(cmd.Name, \"root\")\n\n\t\tos.Args = []string{\"root\", \"test\", \"-n=john\"}\n\n\t\tcmd.Run(ctx)\n\t})\n}\n\nfunc Test_Command_NewFromObject_RunWithValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tcmd, err = gcmd.NewFromObject(&TestCmdObject{})\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(cmd.Name, \"root\")\n\n\t\t// test short name\n\t\tos.Args = []string{\"root\", \"test\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Name\":\"john\",\"Version\":false}`)\n\n\t\t// test name tag name\n\t\tos.Args = []string{\"root\", \"test\", \"-yourname=hailaz\"}\n\t\tvalue1, err1 := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(value1, `{\"Name\":\"hailaz\",\"Version\":false}`)\n\n\t\t// test default tag value\n\t\tos.Args = []string{\"root\", \"test\"}\n\t\tvalue2, err2 := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err2)\n\t\tt.Assert(value2, `{\"Name\":\"tom\",\"Version\":false}`)\n\n\t\t// test name tag and orphan tag true\n\t\tos.Args = []string{\"root\", \"test\", \"-v\"}\n\t\tvalue3, err3 := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err3)\n\t\tt.Assert(value3, `{\"Name\":\"tom\",\"Version\":true}`)\n\t})\n}\n\nfunc Test_Command_NewFromObject_RunWithSpecificArgs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx      = gctx.New()\n\t\t\tcmd, err = gcmd.NewFromObject(&TestCmdObject{})\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(cmd.Name, \"root\")\n\n\t\t// test short name\n\t\targs := []string{\"root\", \"test\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithSpecificArgs(ctx, args)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Name\":\"john\",\"Version\":false}`)\n\n\t\t// test name tag name\n\t\targs = []string{\"root\", \"test\", \"-yourname=hailaz\"}\n\t\tvalue1, err1 := cmd.RunWithSpecificArgs(ctx, args)\n\t\tt.AssertNil(err1)\n\t\tt.Assert(value1, `{\"Name\":\"hailaz\",\"Version\":false}`)\n\n\t\t// test default tag value\n\t\targs = []string{\"root\", \"test\"}\n\t\tvalue2, err2 := cmd.RunWithSpecificArgs(ctx, args)\n\t\tt.AssertNil(err2)\n\t\tt.Assert(value2, `{\"Name\":\"tom\",\"Version\":false}`)\n\n\t\t// test name tag and orphan tag true\n\t\targs = []string{\"root\", \"test\", \"-v\"}\n\t\tvalue3, err3 := cmd.RunWithSpecificArgs(ctx, args)\n\t\tt.AssertNil(err3)\n\t\tt.Assert(value3, `{\"Name\":\"tom\",\"Version\":true}`)\n\n\t\t// test empty args\n\t\tvalue4, err4 := cmd.RunWithSpecificArgs(ctx, nil)\n\t\tt.Assert(err4, \"args can not be empty!\")\n\t\tt.Assert(value4, nil)\n\t})\n}\n\nfunc Test_Command_AddObject(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx     = gctx.New()\n\t\t\tcommand = gcmd.Command{\n\t\t\t\tName: \"start\",\n\t\t\t}\n\t\t)\n\t\terr := command.AddObject(&TestCmdObject{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"start\", \"root\", \"test\", \"-n=john\"}\n\t\tvalue, err := command.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Name\":\"john\",\"Version\":false}`)\n\t})\n}\n\ntype TestObjectForRootTag struct {\n\tg.Meta `name:\"root\" root:\"root\"`\n}\n\ntype TestObjectForRootTagEnvInput struct {\n\tg.Meta `name:\"env\" usage:\"root env\" brief:\"root env command\" dc:\"root env command description\" ad:\"root env command ad\"`\n}\n\ntype TestObjectForRootTagEnvOutput struct{}\n\ntype TestObjectForRootTagTestInput struct {\n\tg.Meta `name:\"root\"`\n\tName   string `v:\"required\" short:\"n\" orphan:\"false\" brief:\"name for test command\"`\n}\n\ntype TestObjectForRootTagTestOutput struct {\n\tContent string\n}\n\nfunc (TestObjectForRootTag) Env(ctx context.Context, in TestObjectForRootTagEnvInput) (out *TestObjectForRootTagEnvOutput, err error) {\n\treturn\n}\n\nfunc (TestObjectForRootTag) Root(ctx context.Context, in TestObjectForRootTagTestInput) (out *TestObjectForRootTagTestOutput, err error) {\n\tout = &TestObjectForRootTagTestOutput{\n\t\tContent: in.Name,\n\t}\n\treturn\n}\n\nfunc Test_Command_RootTag(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(TestObjectForRootTag{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n\t// Pointer.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(&TestObjectForRootTag{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n}\n\ntype TestObjectForNeedArgs struct {\n\tg.Meta `name:\"root\" root:\"root\"`\n}\n\ntype TestObjectForNeedArgsEnvInput struct {\n\tg.Meta `name:\"env\" usage:\"root env\" brief:\"root env command\" dc:\"root env command description\" ad:\"root env command ad\"`\n}\n\ntype TestObjectForNeedArgsEnvOutput struct{}\n\ntype TestObjectForNeedArgsTestInput struct {\n\tg.Meta `name:\"test\"`\n\tArg1   string `arg:\"true\" brief:\"arg1 for test command\"`\n\tArg2   string `arg:\"true\" brief:\"arg2 for test command\"`\n\tName   string `v:\"required\" short:\"n\" orphan:\"false\" brief:\"name for test command\"`\n}\n\ntype TestObjectForNeedArgsTestOutput struct {\n\tArgs []string\n}\n\nfunc (TestObjectForNeedArgs) Env(ctx context.Context, in TestObjectForNeedArgsEnvInput) (out *TestObjectForNeedArgsEnvOutput, err error) {\n\treturn\n}\n\nfunc (TestObjectForNeedArgs) Test(ctx context.Context, in TestObjectForNeedArgsTestInput) (out *TestObjectForNeedArgsTestOutput, err error) {\n\tout = &TestObjectForNeedArgsTestOutput{\n\t\tArgs: []string{in.Arg1, in.Arg2, in.Name},\n\t}\n\treturn\n}\n\nfunc Test_Command_NeedArgs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(TestObjectForNeedArgs{})\n\t\tt.AssertNil(err)\n\n\t\t//os.Args = []string{\"root\", \"test\", \"a\", \"b\", \"c\", \"-h\"}\n\t\t//value, err := cmd.RunWithValueError(ctx)\n\t\t//t.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"test\", \"a\", \"b\", \"c\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Args\":[\"a\",\"b\",\"john\"]}`)\n\t})\n}\n\ntype TestObjectPointerTag struct {\n\tg.Meta `name:\"root\" root:\"root\"`\n}\n\ntype TestObjectPointerTagEnvInput struct {\n\tg.Meta `name:\"env\" usage:\"root env\" brief:\"root env command\" dc:\"root env command description\" ad:\"root env command ad\"`\n}\n\ntype TestObjectPointerTagEnvOutput struct{}\n\ntype TestObjectPointerTagTestInput struct {\n\tg.Meta `name:\"root\"`\n\tName   string `v:\"required\" short:\"n\" orphan:\"false\" brief:\"name for test command\"`\n}\n\ntype TestObjectPointerTagTestOutput struct {\n\tContent string\n}\n\nfunc (c *TestObjectPointerTag) Env(ctx context.Context, in TestObjectPointerTagEnvInput) (out *TestObjectPointerTagEnvOutput, err error) {\n\treturn\n}\n\nfunc (c *TestObjectPointerTag) Root(ctx context.Context, in TestObjectPointerTagTestInput) (out *TestObjectPointerTagTestOutput, err error) {\n\tout = &TestObjectPointerTagTestOutput{\n\t\tContent: in.Name,\n\t}\n\treturn\n}\n\nfunc Test_Command_Pointer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(TestObjectPointerTag{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(&TestObjectPointerTag{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"-n=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n}\n\ntype TestCommandOrphan struct {\n\tg.Meta `name:\"root\" root:\"root\"`\n}\n\ntype TestCommandOrphanIndexInput struct {\n\tg.Meta  `name:\"index\"`\n\tOrphan1 bool `short:\"n1\" orphan:\"true\"`\n\tOrphan2 bool `short:\"n2\" orphan:\"true\"`\n\tOrphan3 bool `short:\"n3\" orphan:\"true\"`\n}\n\ntype TestCommandOrphanIndexOutput struct {\n\tOrphan1 bool\n\tOrphan2 bool\n\tOrphan3 bool\n}\n\nfunc (c *TestCommandOrphan) Index(ctx context.Context, in TestCommandOrphanIndexInput) (out *TestCommandOrphanIndexOutput, err error) {\n\tout = &TestCommandOrphanIndexOutput{\n\t\tOrphan1: in.Orphan1,\n\t\tOrphan2: in.Orphan2,\n\t\tOrphan3: in.Orphan3,\n\t}\n\treturn\n}\n\nfunc Test_Command_Orphan_Parameter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ctx = gctx.New()\n\t\tcmd, err := gcmd.NewFromObject(TestCommandOrphan{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"index\", \"-n1\", \"-n2=0\", \"-n3=1\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.(*TestCommandOrphanIndexOutput).Orphan1, true)\n\t\tt.Assert(value.(*TestCommandOrphanIndexOutput).Orphan2, false)\n\t\tt.Assert(value.(*TestCommandOrphanIndexOutput).Orphan3, true)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_feature_object2_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\ntype commandBuild struct {\n\tg.Meta               `name:\"build\" root:\"build\" args:\"true\" brief:\"{commandBuildBrief}\" dc:\"{commandBuildDc}\" eg:\"{commandBuildEg}\" ad:\"{commandBuildAd}\"`\n\tnodeNameInConfigFile string // nodeNameInConfigFile is the node name for compiler configurations in configuration file.\n\tpackedGoFileName     string // packedGoFileName specifies the file name for packing common folders into one single go file.\n}\n\nconst (\n\tcommandBuildBrief = `cross-building go project for lots of platforms`\n\tcommandBuildEg    = `\ngf build main.go\ngf build main.go --pack public,template\ngf build main.go --cgo\ngf build main.go -m none \ngf build main.go -n my-app -a all -s all\ngf build main.go -n my-app -a amd64,386 -s linux -p .\ngf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin\n`\n\tcommandBuildDc = `\nThe \"build\" command is most commonly used command, which is designed as a powerful wrapper for \n\"go build\" command for convenience cross-compiling usage. \nIt provides much more features for building binary:\n1. Cross-Compiling for many platforms and architectures.\n2. Configuration file support for compiling.\n3. Build-In Variables.\n`\n\tcommandBuildAd = `\nPLATFORMS\n    darwin    amd64,arm64\n    freebsd   386,amd64,arm\n    linux     386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le\n    netbsd    386,amd64,arm\n    openbsd   386,amd64,arm\n    windows   386,amd64\n`\n\t// https://golang.google.cn/doc/install/source\n\tcommandBuildPlatforms = `\n    darwin    amd64\n    darwin    arm64\n    ios       amd64\n    ios       arm64\n    freebsd   386\n    freebsd   amd64\n    freebsd   arm\n    linux     386\n    linux     amd64\n    linux     arm\n    linux     arm64\n    linux     ppc64\n    linux     ppc64le\n    linux     mips\n    linux     mipsle\n    linux     mips64\n    linux     mips64le\n    netbsd    386\n    netbsd    amd64\n    netbsd    arm\n    openbsd   386\n    openbsd   amd64\n    openbsd   arm\n    windows   386\n    windows   amd64\n\tandroid   arm\n\tdragonfly amd64\n\tplan9     386\n\tplan9     amd64\n\tsolaris   amd64\n`\n\tcommandBuildBriefPack = `\ndestination file path for packed file. if extension of the filename is \".go\" and \"-n\" option is given, \nit enables packing SRC to go file, or else it packs SRC into a binary file.\n\n`\n\tcommandGenDaoBriefJsonCase = `\ngenerated json tag case for model struct, cases are as follows:\n| Case            | Example            |\n|---------------- |--------------------|\n| Camel           | AnyKindOfString    | \n| CamelLower      | anyKindOfString    | default\n| Snake           | any_kind_of_string |\n| SnakeScreaming  | ANY_KIND_OF_STRING |\n| SnakeFirstUpper | rgb_code_md5       |\n| Kebab           | any-kind-of-string |\n| KebabScreaming  | ANY-KIND-OF-STRING |\n`\n)\n\nfunc init() {\n\tgtag.Sets(map[string]string{\n\t\t`commandBuildBrief`:          commandBuildBrief,\n\t\t`commandBuildDc`:             commandBuildDc,\n\t\t`commandBuildEg`:             commandBuildEg,\n\t\t`commandBuildAd`:             commandBuildAd,\n\t\t`commandBuildBriefPack`:      commandBuildBriefPack,\n\t\t`commandGenDaoBriefJsonCase`: commandGenDaoBriefJsonCase,\n\t})\n}\n\ntype commandBuildInput struct {\n\tg.Meta   `name:\"build\" config:\"gfcli.build\"`\n\tName     string `short:\"n\" name:\"name\"     brief:\"output binary name\"`\n\tVersion  string `short:\"v\" name:\"version\"  brief:\"output binary version\"`\n\tArch     string `short:\"a\" name:\"arch\"     brief:\"output binary architecture, multiple arch separated with ','\"`\n\tSystem   string `short:\"s\" name:\"system\"   brief:\"output binary system, multiple os separated with ','\"`\n\tOutput   string `short:\"o\" name:\"output\"   brief:\"output binary path, used when building single binary file\"`\n\tPath     string `short:\"p\" name:\"path\"     brief:\"output binary directory path, default is './bin'\" d:\"./bin\"`\n\tExtra    string `short:\"e\" name:\"extra\"    brief:\"extra custom \\\"go build\\\" options\"`\n\tMod      string `short:\"m\" name:\"mod\"      brief:\"like \\\"-mod\\\" option of \\\"go build\\\", use \\\"-m none\\\" to disable go module\"`\n\tCgo      bool   `short:\"c\" name:\"cgo\"      brief:\"enable or disable cgo feature, it's disabled in default\" orphan:\"true\"`\n\tJsonCase string `short:\"j\" name:\"jsonCase\" brief:\"{commandGenDaoBriefJsonCase}\" d:\"CamelLower\"`\n\tPack     string `name:\"pack\" brief:\"{commandBuildBriefPack}\"`\n}\n\ntype commandBuildOutput struct{}\n\nfunc (c commandBuild) Index(ctx context.Context, in commandBuildInput) (out *commandBuildOutput, err error) {\n\treturn\n}\n\nfunc TestNewFromObject(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t)\n\t\tcmd, err := gcmd.NewFromObject(commandBuild{\n\t\t\tnodeNameInConfigFile: \"gfcli.build\",\n\t\t\tpackedGoFileName:     \"build_pack_data.go\",\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"build\", \"-h\"}\n\t\terr = cmd.RunWithError(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_feature_object3_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype TestParamsCase struct {\n\tg.Meta `name:\"root\" root:\"root\"`\n}\n\ntype TestParamsCaseRootInput struct {\n\tg.Meta `name:\"root\"`\n\tName   string\n}\n\ntype TestParamsCaseRootOutput struct {\n\tContent string\n}\n\nfunc (c *TestParamsCase) Root(ctx context.Context, in TestParamsCaseRootInput) (out *TestParamsCaseRootOutput, err error) {\n\tout = &TestParamsCaseRootOutput{\n\t\tContent: in.Name,\n\t}\n\treturn\n}\n\nfunc Test_Command_ParamsCase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ctx = gctx.New()\n\t\tcmd, err := gcmd.NewFromObject(TestParamsCase{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"-name=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_feature_object4_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype TestNoNameTagCase struct {\n\tg.Meta `name:\"root\"`\n}\n\ntype TestNoNameTagCaseRootInput struct {\n\tName string\n}\n\ntype TestNoNameTagCaseRootOutput struct {\n\tContent string\n}\n\nfunc (c *TestNoNameTagCase) TEST(ctx context.Context, in TestNoNameTagCaseRootInput) (out *TestNoNameTagCaseRootOutput, err error) {\n\tout = &TestNoNameTagCaseRootOutput{\n\t\tContent: in.Name,\n\t}\n\treturn\n}\n\nfunc Test_Command_NoNameTagCase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ctx = gctx.New()\n\t\tcmd, err := gcmd.NewFromObject(TestNoNameTagCase{})\n\t\tt.AssertNil(err)\n\n\t\tos.Args = []string{\"root\", \"TEST\", \"-name=john\"}\n\t\tvalue, err := cmd.RunWithValueError(ctx)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value, `{\"Content\":\"john\"}`)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\ntype Issue3390CommandCase1 struct {\n\t*gcmd.Command\n}\n\ntype Issue3390TestCase1 struct {\n\tg.Meta `name:\"index\" ad:\"test\"`\n}\n\ntype Issue3390Case1Input struct {\n\tg.Meta `name:\"index\"`\n\tA      string `short:\"a\" name:\"aa\"`\n\tBe     string `short:\"b\" name:\"bb\"`\n}\n\ntype Issue3390Case1Output struct {\n\tContent string\n}\n\nfunc (c Issue3390TestCase1) Index(ctx context.Context, in Issue3390Case1Input) (out *Issue3390Case1Output, err error) {\n\tout = &Issue3390Case1Output{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\n\nfunc Test_Issue3390_Case1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\troot, err := gcmd.NewFromObject(Issue3390TestCase1{})\n\t\tt.AssertNil(err)\n\t\tcommand := &Issue3390CommandCase1{root}\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tgctx.New(),\n\t\t\t[]string{\"main\", \"-a\", \"aaa\", \"-b\", \"bbb\"},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.(*Issue3390Case1Output).Content, `{\"A\":\"aaa\",\"Be\":\"bbb\"}`)\n\t})\n}\n\ntype Issue3390CommandCase2 struct {\n\t*gcmd.Command\n}\n\ntype Issue3390TestCase2 struct {\n\tg.Meta `name:\"index\" ad:\"test\"`\n}\n\ntype Issue3390Case2Input struct {\n\tg.Meta `name:\"index\"`\n\tA      string `short:\"b\" name:\"bb\"`\n\tBe     string `short:\"a\" name:\"aa\"`\n}\n\ntype Issue3390Case2Output struct {\n\tContent string\n}\n\nfunc (c Issue3390TestCase2) Index(ctx context.Context, in Issue3390Case2Input) (out *Issue3390Case2Output, err error) {\n\tout = &Issue3390Case2Output{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\nfunc Test_Issue3390_Case2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\troot, err := gcmd.NewFromObject(Issue3390TestCase2{})\n\t\tt.AssertNil(err)\n\t\tcommand := &Issue3390CommandCase2{root}\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tgctx.New(),\n\t\t\t[]string{\"main\", \"-a\", \"aaa\", \"-b\", \"bbb\"},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.(*Issue3390Case2Output).Content, `{\"A\":\"bbb\",\"Be\":\"aaa\"}`)\n\t})\n}\n\ntype Issue3390CommandCase3 struct {\n\t*gcmd.Command\n}\n\ntype Issue3390TestCase3 struct {\n\tg.Meta `name:\"index\" ad:\"test\"`\n}\n\ntype Issue3390Case3Input struct {\n\tg.Meta `name:\"index\"`\n\tA      string `short:\"b\"`\n\tBe     string `short:\"a\"`\n}\n\ntype Issue3390Case3Output struct {\n\tContent string\n}\n\nfunc (c Issue3390TestCase3) Index(ctx context.Context, in Issue3390Case3Input) (out *Issue3390Case3Output, err error) {\n\tout = &Issue3390Case3Output{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\nfunc Test_Issue3390_Case3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\troot, err := gcmd.NewFromObject(Issue3390TestCase3{})\n\t\tt.AssertNil(err)\n\t\tcommand := &Issue3390CommandCase3{root}\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tgctx.New(),\n\t\t\t[]string{\"main\", \"-a\", \"aaa\", \"-b\", \"bbb\"},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.(*Issue3390Case3Output).Content, `{\"A\":\"bbb\",\"Be\":\"aaa\"}`)\n\t})\n}\n\ntype Issue3390CommandCase4 struct {\n\t*gcmd.Command\n}\n\ntype Issue3390TestCase4 struct {\n\tg.Meta `name:\"index\" ad:\"test\"`\n}\n\ntype Issue3390Case4Input struct {\n\tg.Meta `name:\"index\"`\n\tA      string `short:\"a\"`\n\tBe     string `short:\"b\"`\n}\n\ntype Issue3390Case4Output struct {\n\tContent string\n}\n\nfunc (c Issue3390TestCase4) Index(ctx context.Context, in Issue3390Case4Input) (out *Issue3390Case4Output, err error) {\n\tout = &Issue3390Case4Output{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\n\nfunc Test_Issue3390_Case4(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\troot, err := gcmd.NewFromObject(Issue3390TestCase4{})\n\t\tt.AssertNil(err)\n\t\tcommand := &Issue3390CommandCase4{root}\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tgctx.New(),\n\t\t\t[]string{\"main\", \"-a\", \"aaa\", \"-b\", \"bbb\"},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value.(*Issue3390Case4Output).Content, `{\"A\":\"aaa\",\"Be\":\"bbb\"}`)\n\t})\n}\n\ntype Issue3417Test struct {\n\tg.Meta `name:\"root\"`\n}\n\ntype Issue3417BuildInput struct {\n\tg.Meta        `name:\"build\" config:\"gfcli.build\"`\n\tFile          string `name:\"FILE\" arg:\"true\"    brief:\"building file path\"`\n\tName          string `short:\"n\"  name:\"name\"    brief:\"output binary name\"`\n\tVersion       string `short:\"v\"  name:\"version\" brief:\"output binary version\"`\n\tArch          string `short:\"a\"  name:\"arch\"    brief:\"output binary architecture, multiple arch separated with ','\"`\n\tSystem        string `short:\"s\"  name:\"system\"  brief:\"output binary system, multiple os separated with ','\"`\n\tOutput        string `short:\"o\"  name:\"output\"  brief:\"output binary path, used when building single binary file\"`\n\tPath          string `short:\"p\"  name:\"path\"    brief:\"output binary directory path, default is '.'\" d:\".\"`\n\tExtra         string `short:\"e\"  name:\"extra\"   brief:\"extra custom \\\"go build\\\" options\"`\n\tMod           string `short:\"m\"  name:\"mod\"     brief:\"like \\\"-mod\\\" option of \\\"go build\\\", use \\\"-m none\\\" to disable go module\"`\n\tCgo           bool   `short:\"c\"  name:\"cgo\"     brief:\"enable or disable cgo feature, it's disabled in default\" orphan:\"true\"`\n\tVarMap        g.Map  `short:\"r\"  name:\"varMap\"  brief:\"custom built embedded variable into binary\"`\n\tPackSrc       string `short:\"ps\" name:\"packSrc\" brief:\"pack one or more folders into one go file before building\"`\n\tPackDst       string `short:\"pd\" name:\"packDst\" brief:\"temporary go file path for pack, this go file will be automatically removed after built\" d:\"internal/packed/build_pack_data.go\"`\n\tExitWhenError bool   `short:\"ew\" name:\"exitWhenError\" brief:\"exit building when any error occurs, specially for multiple arch and system buildings. default is false\" orphan:\"true\"`\n\tDumpENV       bool   `short:\"de\" name:\"dumpEnv\" brief:\"dump current go build environment before building binary\" orphan:\"true\"`\n}\n\ntype Issue3417BuildOutput struct {\n\tContent string\n}\n\nfunc (c *Issue3417Test) Build(ctx context.Context, in Issue3417BuildInput) (out *Issue3417BuildOutput, err error) {\n\tout = &Issue3417BuildOutput{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\n\nfunc Test_Issue3417(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcommand, err := gcmd.NewFromObject(Issue3417Test{})\n\t\tt.AssertNil(err)\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tgctx.New(),\n\t\t\t[]string{\n\t\t\t\t\"gf\", \"build\",\n\t\t\t\t\"-mod\", \"vendor\",\n\t\t\t\t\"-v\", \"0.0.19\",\n\t\t\t\t\"-n\", \"detect_hardware_os\",\n\t\t\t\t\"-a\", \"amd64,arm64\",\n\t\t\t\t\"-s\", \"linux\",\n\t\t\t\t\"-p\", \"./bin\",\n\t\t\t\t\"-e\", \"-trimpath -ldflags\",\n\t\t\t\t\"cmd/v3/main.go\",\n\t\t\t},\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(\n\t\t\tvalue.(*Issue3417BuildOutput).Content,\n\t\t\t`{\"File\":\"cmd/v3/main.go\",\"Name\":\"detect_hardware_os\",\"Version\":\"0.0.19\",\"Arch\":\"amd64,arm64\",\"System\":\"linux\",\"Output\":\"\",\"Path\":\"./bin\",\"Extra\":\"-trimpath -ldflags\",\"Mod\":\"vendor\",\"Cgo\":false,\"VarMap\":null,\"PackSrc\":\"\",\"PackDst\":\"internal/packed/build_pack_data.go\",\"ExitWhenError\":false,\"DumpENV\":false}`,\n\t\t)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3670\ntype (\n\tIssue3670FirstCommand struct {\n\t\t*gcmd.Command\n\t}\n\n\tIssue3670First struct {\n\t\tg.Meta `name:\"first\"`\n\t}\n\n\tIssue3670Second struct {\n\t\tg.Meta `name:\"second\"`\n\t}\n\n\tIssue3670Third struct {\n\t\tg.Meta `name:\"third\"`\n\t\tIssue3670Last\n\t}\n\n\tIssue3670Last struct {\n\t\tg.Meta `name:\"last\"`\n\t}\n\n\tIssue3670LastInput struct {\n\t\tg.Meta  `name:\"last\"`\n\t\tCountry string `name:\"country\" arg:\"true\"`\n\t\tSinger  string `name:\"singer\" arg:\"true\"`\n\t}\n\n\tIssue3670LastOutput struct {\n\t\tContent string\n\t}\n)\n\nfunc (receiver Issue3670Last) LastRecv(ctx context.Context, in Issue3670LastInput) (out *Issue3670LastOutput, err error) {\n\tout = &Issue3670LastOutput{\n\t\tContent: gjson.MustEncodeString(in),\n\t}\n\treturn\n}\n\nfunc Test_Issue3670(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t\terr error\n\t\t)\n\n\t\tthird, err := gcmd.NewFromObject(Issue3670Third{})\n\t\tt.AssertNil(err)\n\n\t\tsecond, err := gcmd.NewFromObject(Issue3670Second{})\n\t\tt.AssertNil(err)\n\t\terr = second.AddCommand(third)\n\t\tt.AssertNil(err)\n\n\t\tfirst, err := gcmd.NewFromObject(Issue3670First{})\n\t\tt.AssertNil(err)\n\t\terr = first.AddCommand(second)\n\t\tt.AssertNil(err)\n\n\t\tcommand := &Issue3670FirstCommand{first}\n\n\t\tvalue, err := command.RunWithSpecificArgs(\n\t\t\tctx,\n\t\t\t[]string{\"main\", \"second\", \"third\", \"last\", \"china\", \"邓丽君\"},\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(value.(*Issue3670LastOutput).Content, `{\"Country\":\"china\",\"Singer\":\"邓丽君\"}`)\n\t})\n}\n\nfunc Test_Issue3701(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\toutputArgs []string\n\t\t\tinputArgs  = []string{\"abc\", \"def\"}\n\t\t\tctx        = gctx.New()\n\t\t\tcmd        = gcmd.Command{\n\t\t\t\tName:  \"main\",\n\t\t\t\tUsage: \"main\",\n\t\t\t\tBrief: \"...\",\n\t\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) (err error) {\n\t\t\t\t\toutputArgs = parser.GetArgAll()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\n\t\t_, err := cmd.RunWithSpecificArgs(ctx, inputArgs)\n\t\tt.AssertNil(err)\n\t\tt.Assert(outputArgs, inputArgs)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_parser_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcmd_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Parse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tos.Args = []string{\"gf\", \"--force\", \"remove\", \"-fq\", \"-p=www\", \"path\", \"-n\", \"root\"}\n\t\tp, err := gcmd.Parse(map[string]bool{\n\t\t\t\"n, name\":   true,\n\t\t\t\"p, prefix\": true,\n\t\t\t\"f,force\":   false,\n\t\t\t\"q,quiet\":   false,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(p.GetArgAll()), 3)\n\t\tt.Assert(p.GetArg(0), \"gf\")\n\t\tt.Assert(p.GetArg(1), \"remove\")\n\t\tt.Assert(p.GetArg(2), \"path\")\n\t\tt.Assert(p.GetArg(2).String(), \"path\")\n\n\t\tt.Assert(len(p.GetOptAll()), 8)\n\t\tt.Assert(p.GetOpt(\"n\"), \"root\")\n\t\tt.Assert(p.GetOpt(\"name\"), \"root\")\n\t\tt.Assert(p.GetOpt(\"p\"), \"www\")\n\t\tt.Assert(p.GetOpt(\"prefix\"), \"www\")\n\t\tt.Assert(p.GetOpt(\"prefix\").String(), \"www\")\n\n\t\tt.Assert(p.GetOpt(\"n\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"name\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"p\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"prefix\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"f\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"force\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"q\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"quiet\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"none\") != nil, false)\n\n\t\t_, err = p.MarshalJSON()\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_ParseArgs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp, err := gcmd.ParseArgs(\n\t\t\t[]string{\"gf\", \"--force\", \"remove\", \"-fq\", \"-p=www\", \"path\", \"-n\", \"root\"},\n\t\t\tmap[string]bool{\n\t\t\t\t\"n, name\":   true,\n\t\t\t\t\"p, prefix\": true,\n\t\t\t\t\"f,force\":   false,\n\t\t\t\t\"q,quiet\":   false,\n\t\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(p.GetArgAll()), 3)\n\t\tt.Assert(p.GetArg(0), \"gf\")\n\t\tt.Assert(p.GetArg(1), \"remove\")\n\t\tt.Assert(p.GetArg(2), \"path\")\n\t\tt.Assert(p.GetArg(2).String(), \"path\")\n\n\t\tt.Assert(len(p.GetOptAll()), 8)\n\t\tt.Assert(p.GetOpt(\"n\"), \"root\")\n\t\tt.Assert(p.GetOpt(\"name\"), \"root\")\n\t\tt.Assert(p.GetOpt(\"p\"), \"www\")\n\t\tt.Assert(p.GetOpt(\"prefix\"), \"www\")\n\t\tt.Assert(p.GetOpt(\"prefix\").String(), \"www\")\n\n\t\tt.Assert(p.GetOpt(\"n\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"name\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"p\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"prefix\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"f\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"force\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"q\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"quiet\") != nil, true)\n\t\tt.Assert(p.GetOpt(\"none\") != nil, false)\n\t})\n}\n"
  },
  {
    "path": "os/gcmd/gcmd_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gcmd_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Default(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcmd.Init([]string{\"gf\", \"--force\", \"remove\", \"-fq\", \"-p=www\", \"path\", \"-n\", \"root\"}...)\n\t\tt.Assert(len(gcmd.GetArgAll()), 2)\n\t\tt.Assert(gcmd.GetArg(1), \"path\")\n\t\tt.Assert(gcmd.GetArg(100, \"test\"), \"test\")\n\t\tt.Assert(gcmd.GetOpt(\"force\"), \"remove\")\n\t\tt.Assert(gcmd.GetOpt(\"n\"), \"root\")\n\t\tt.Assert(gcmd.GetOpt(\"fq\").IsNil(), false)\n\t\tt.Assert(gcmd.GetOpt(\"p\").IsNil(), false)\n\t\tt.Assert(gcmd.GetOpt(\"none\").IsNil(), true)\n\t\tt.Assert(gcmd.GetOpt(\"none\", \"value\"), \"value\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcmd.Init([]string{\"gf\", \"gen\", \"-h\"}...)\n\t\tt.Assert(len(gcmd.GetArgAll()), 2)\n\t\tt.Assert(gcmd.GetOpt(\"h\"), \"\")\n\t\tt.Assert(gcmd.GetOpt(\"h\").IsNil(), false)\n\t})\n}\n\nfunc Test_BuildOptions(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gcmd.BuildOptions(g.MapStrStr{\n\t\t\t\"n\": \"john\",\n\t\t})\n\t\tt.Assert(s, \"-n=john\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gcmd.BuildOptions(g.MapStrStr{\n\t\t\t\"n\": \"john\",\n\t\t}, \"-test\")\n\t\tt.Assert(s, \"-testn=john\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gcmd.BuildOptions(g.MapStrStr{\n\t\t\t\"n1\": \"john\",\n\t\t\t\"n2\": \"huang\",\n\t\t})\n\t\tt.Assert(strings.Contains(s, \"-n1=john\"), true)\n\t\tt.Assert(strings.Contains(s, \"-n2=huang\"), true)\n\t})\n}\n\nfunc Test_GetWithEnv(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgenv.Set(\"TEST\", \"1\")\n\t\tdefer genv.Remove(\"TEST\")\n\t\tt.Assert(gcmd.GetOptWithEnv(\"test\"), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgenv.Set(\"TEST\", \"1\")\n\t\tdefer genv.Remove(\"TEST\")\n\t\tgcmd.Init(\"-test\", \"2\")\n\t\tt.Assert(gcmd.GetOptWithEnv(\"test\"), 2)\n\t})\n}\n\nfunc Test_Command(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t\terr error\n\t\t)\n\t\tcommandRoot := &gcmd.Command{\n\t\t\tName: \"gf\",\n\t\t}\n\t\t// env\n\t\tcommandEnv := &gcmd.Command{\n\t\t\tName: \"env\",\n\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) error {\n\t\t\t\tfmt.Println(\"env\")\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\t// test\n\t\tcommandTest := &gcmd.Command{\n\t\t\tName:        \"test\",\n\t\t\tBrief:       \"test brief\",\n\t\t\tDescription: \"test description current Golang environment variables\",\n\t\t\tExamples: `\ngf get github.com/gogf/gf\ngf get github.com/gogf/gf@latest\ngf get github.com/gogf/gf@master\ngf get golang.org/x/sys\n`,\n\t\t\tArguments: []gcmd.Argument{\n\t\t\t\t{\n\t\t\t\t\tName:   \"my-option\",\n\t\t\t\t\tShort:  \"o\",\n\t\t\t\t\tBrief:  \"It's my custom option\",\n\t\t\t\t\tOrphan: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"another\",\n\t\t\t\t\tShort:  \"a\",\n\t\t\t\t\tBrief:  \"It's my another custom option\",\n\t\t\t\t\tOrphan: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) error {\n\t\t\t\tfmt.Println(\"test\")\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\terr = commandRoot.AddCommand(\n\t\t\tcommandEnv,\n\t\t)\n\t\tif err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\t\terr = commandRoot.AddObject(\n\t\t\tcommandTest,\n\t\t)\n\t\tif err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\n\t\tif err = commandRoot.RunWithError(ctx); err != nil {\n\t\t\tif gerror.Code(err) == gcode.CodeNotFound {\n\t\t\t\tcommandRoot.Print()\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Command_Print(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tctx = gctx.New()\n\t\t\terr error\n\t\t)\n\t\tc := &gcmd.Command{\n\t\t\tName:        \"gf\",\n\t\t\tDescription: `GoFrame Command Line Interface, which is your helpmate for building GoFrame application with convenience.`,\n\t\t\tAdditional: `\nUse 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...' in the tail of their comments.`,\n\t\t}\n\t\t// env\n\t\tcommandEnv := &gcmd.Command{\n\t\t\tName:        \"env\",\n\t\t\tBrief:       \"show current Golang environment variables, long brief.long brief.long brief.long brief.long brief.long brief.long brief.long brief.\",\n\t\t\tDescription: \"show current Golang environment variables\",\n\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) error {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\tif err = c.AddCommand(commandEnv); err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\t\t// get\n\t\tcommandGet := &gcmd.Command{\n\t\t\tName:        \"get\",\n\t\t\tBrief:       \"install or update GF to system in default...\",\n\t\t\tDescription: \"show current Golang environment variables\",\n\n\t\t\tExamples: `\ngf get github.com/gogf/gf\ngf get github.com/gogf/gf@latest\ngf get github.com/gogf/gf@master\ngf get golang.org/x/sys\n`,\n\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) error {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\tif err = c.AddCommand(commandGet); err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\t\t// build\n\t\t//-n, --name       output binary name\n\t\t//-v, --version    output binary version\n\t\t//-a, --arch       output binary architecture, multiple arch separated with ','\n\t\t//-s, --system     output binary system, multiple os separated with ','\n\t\t//-o, --output     output binary path, used when building single binary file\n\t\t//-p, --path       output binary directory path, default is './bin'\n\t\t//-e, --extra      extra custom \"go build\" options\n\t\t//-m, --mod        like \"-mod\" option of \"go build\", use \"-m none\" to disable go module\n\t\t//-c, --cgo        enable or disable cgo feature, it's disabled in default\n\n\t\tcommandBuild := gcmd.Command{\n\t\t\tName:  \"build\",\n\t\t\tUsage: \"gf build FILE [OPTION]\",\n\t\t\tBrief: \"cross-building go project for lots of platforms...\",\n\t\t\tDescription: `\nThe \"build\" command is most commonly used command, which is designed as a powerful wrapper for\n\"go build\" command for convenience cross-compiling usage.\nIt provides much more features for building binary:\n1. Cross-Compiling for many platforms and architectures.\n2. Configuration file support for compiling.\n3. Build-In Variables.\n`,\n\t\t\tExamples: `\ngf build main.go\ngf build main.go --swagger\ngf build main.go --pack public,template\ngf build main.go --cgo\ngf build main.go -m none \ngf build main.go -n my-app -a all -s all\ngf build main.go -n my-app -a amd64,386 -s linux -p .\ngf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin\n`,\n\t\t\tFunc: func(ctx context.Context, parser *gcmd.Parser) error {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\tif err = c.AddCommand(&commandBuild); err != nil {\n\t\t\tg.Log().Fatal(ctx, err)\n\t\t}\n\t\t_ = c.RunWithError(ctx)\n\t})\n}\n\nfunc Test_Command_NotFound(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc0 := &gcmd.Command{\n\t\t\tName: \"c0\",\n\t\t}\n\t\tc1 := &gcmd.Command{\n\t\t\tName: \"c1\",\n\t\t\tFuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (any, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t}\n\t\tc21 := &gcmd.Command{\n\t\t\tName: \"c21\",\n\t\t\tFuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (any, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t}\n\t\tc22 := &gcmd.Command{\n\t\t\tName: \"c22\",\n\t\t\tFuncWithValue: func(ctx context.Context, parser *gcmd.Parser) (any, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t}\n\t\tt.AssertNil(c0.AddCommand(c1))\n\t\tt.AssertNil(c1.AddCommand(c21, c22))\n\n\t\tos.Args = []string{\"c0\", \"c1\", \"c23\", `--test=\"abc\"`}\n\t\terr := c0.RunWithError(gctx.New())\n\t\tt.Assert(err.Error(), `command \"c1 c23\" not found for command \"c0\", command line: c0 c1 c23 --test=\"abc\"`)\n\t})\n}\n"
  },
  {
    "path": "os/gcron/gcron.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gcron implements a cron pattern parser and job runner.\npackage gcron\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\nconst (\n\tStatusReady   = gtimer.StatusReady\n\tStatusRunning = gtimer.StatusRunning\n\tStatusStopped = gtimer.StatusStopped\n\tStatusClosed  = gtimer.StatusClosed\n)\n\nvar (\n\t// Default cron object.\n\tdefaultCron = New()\n)\n\n// SetLogger sets the global logger for cron.\nfunc SetLogger(logger glog.ILogger) {\n\tdefaultCron.SetLogger(logger)\n}\n\n// GetLogger returns the global logger in the cron.\nfunc GetLogger() glog.ILogger {\n\treturn defaultCron.GetLogger()\n}\n\n// Add adds a timed task to default cron object.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn defaultCron.Add(ctx, pattern, job, name...)\n}\n\n// AddSingleton adds a singleton timed task, to default cron object.\n// A singleton timed task is that can only be running one single instance at the same time.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn defaultCron.AddSingleton(ctx, pattern, job, name...)\n}\n\n// AddOnce adds a timed task which can be run only once, to default cron object.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn defaultCron.AddOnce(ctx, pattern, job, name...)\n}\n\n// AddTimes adds a timed task which can be run specified times, to default cron object.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) {\n\treturn defaultCron.AddTimes(ctx, pattern, times, job, name...)\n}\n\n// DelayAdd adds a timed task to default cron object after `delay` time.\nfunc DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tdefaultCron.DelayAdd(ctx, delay, pattern, job, name...)\n}\n\n// DelayAddSingleton adds a singleton timed task after `delay` time to default cron object.\nfunc DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tdefaultCron.DelayAddSingleton(ctx, delay, pattern, job, name...)\n}\n\n// DelayAddOnce adds a timed task after `delay` time to default cron object.\n// This timed task can be run only once.\nfunc DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tdefaultCron.DelayAddOnce(ctx, delay, pattern, job, name...)\n}\n\n// DelayAddTimes adds a timed task after `delay` time to default cron object.\n// This timed task can be run specified times.\nfunc DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) {\n\tdefaultCron.DelayAddTimes(ctx, delay, pattern, times, job, name...)\n}\n\n// Search returns a scheduled task with the specified `name`.\n// It returns nil if no found.\nfunc Search(name string) *Entry {\n\treturn defaultCron.Search(name)\n}\n\n// Remove deletes scheduled task which named `name`.\nfunc Remove(name string) {\n\tdefaultCron.Remove(name)\n}\n\n// Size returns the size of the timed tasks of default cron.\nfunc Size() int {\n\treturn defaultCron.Size()\n}\n\n// Entries return all timed tasks as slice.\nfunc Entries() []*Entry {\n\treturn defaultCron.Entries()\n}\n\n// Start starts running the specified timed task named `name`.\n// If no`name` specified, it starts the entire cron.\nfunc Start(name ...string) {\n\tdefaultCron.Start(name...)\n}\n\n// Stop stops running the specified timed task named `name`.\n// If no`name` specified, it stops the entire cron.\nfunc Stop(name ...string) {\n\tdefaultCron.Stop(name...)\n}\n\n// StopGracefully Blocks and waits all current running jobs done.\nfunc StopGracefully() {\n\tdefaultCron.StopGracefully()\n}\n\n// StopGracefullyNonBlocking stops all running tasks gracefully without blocking,\n// returning a context that callers can use to wait for completion.\nfunc StopGracefullyNonBlocking() context.Context {\n\treturn defaultCron.StopGracefullyNonBlocking()\n}\n"
  },
  {
    "path": "os/gcron/gcron_cron.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// Cron stores all the cron job entries.\ntype Cron struct {\n\tidGen       *gtype.Int64    // Used for unique name generation.\n\tstatus      *gtype.Int      // Timed task status(0: Not Start; 1: Running; 2: Stopped; -1: Closed)\n\tentries     *gmap.StrAnyMap // All timed task entries.\n\tlogger      glog.ILogger    // Logger, it is nil in default.\n\tloggerMu    sync.RWMutex\n\tjobWaiter   sync.WaitGroup // Graceful shutdown when cron jobs are stopped.\n\trunning     bool\n\trunningLock sync.Mutex\n}\n\n// New returns a new Cron object with default settings.\nfunc New() *Cron {\n\treturn &Cron{\n\t\tidGen:   gtype.NewInt64(),\n\t\tstatus:  gtype.NewInt(StatusRunning),\n\t\tentries: gmap.NewStrAnyMap(true),\n\t\trunning: true,\n\t}\n}\n\n// SetLogger sets the logger for cron.\nfunc (c *Cron) SetLogger(logger glog.ILogger) {\n\tc.loggerMu.Lock()\n\tdefer c.loggerMu.Unlock()\n\tc.logger = logger\n}\n\n// GetLogger returns the logger in the cron.\nfunc (c *Cron) GetLogger() glog.ILogger {\n\tc.loggerMu.RLock()\n\tdefer c.loggerMu.RUnlock()\n\treturn c.logger\n}\n\n// AddEntry creates and returns a new Entry object.\nfunc (c *Cron) AddEntry(\n\tctx context.Context,\n\tpattern string,\n\tjob JobFunc,\n\ttimes int,\n\tisSingleton bool,\n\tname ...string,\n) (*Entry, error) {\n\tvar (\n\t\tentryName = \"\"\n\t\tinfinite  = false\n\t)\n\tif len(name) > 0 {\n\t\tentryName = name[0]\n\t}\n\tif times <= 0 {\n\t\tinfinite = true\n\t}\n\treturn c.doAddEntry(doAddEntryInput{\n\t\tName:        entryName,\n\t\tJob:         job,\n\t\tCtx:         ctx,\n\t\tTimes:       times,\n\t\tPattern:     pattern,\n\t\tIsSingleton: isSingleton,\n\t\tInfinite:    infinite,\n\t})\n}\n\n// Add adds a timed task.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc (c *Cron) Add(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn c.AddEntry(ctx, pattern, job, -1, false, name...)\n}\n\n// AddSingleton adds a singleton timed task.\n// A singleton timed task is that can only be running one single instance at the same time.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc (c *Cron) AddSingleton(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn c.AddEntry(ctx, pattern, job, -1, true, name...)\n}\n\n// AddTimes adds a timed task which can be run specified times.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc (c *Cron) AddTimes(ctx context.Context, pattern string, times int, job JobFunc, name ...string) (*Entry, error) {\n\treturn c.AddEntry(ctx, pattern, job, times, false, name...)\n}\n\n// AddOnce adds a timed task which can be run only once.\n// A unique `name` can be bound with the timed task.\n// It returns and error if the `name` is already used.\nfunc (c *Cron) AddOnce(ctx context.Context, pattern string, job JobFunc, name ...string) (*Entry, error) {\n\treturn c.AddEntry(ctx, pattern, job, 1, false, name...)\n}\n\n// DelayAddEntry adds a timed task after `delay` time.\nfunc (c *Cron) DelayAddEntry(ctx context.Context, delay time.Duration, pattern string, job JobFunc, times int, isSingleton bool, name ...string) {\n\tgtimer.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tif _, err := c.AddEntry(ctx, pattern, job, times, isSingleton, name...); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n}\n\n// DelayAdd adds a timed task after `delay` time.\nfunc (c *Cron) DelayAdd(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tgtimer.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tif _, err := c.Add(ctx, pattern, job, name...); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n}\n\n// DelayAddSingleton adds a singleton timed task after `delay` time.\nfunc (c *Cron) DelayAddSingleton(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tgtimer.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tif _, err := c.AddSingleton(ctx, pattern, job, name...); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n}\n\n// DelayAddOnce adds a timed task after `delay` time.\n// This timed task can be run only once.\nfunc (c *Cron) DelayAddOnce(ctx context.Context, delay time.Duration, pattern string, job JobFunc, name ...string) {\n\tgtimer.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tif _, err := c.AddOnce(ctx, pattern, job, name...); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n}\n\n// DelayAddTimes adds a timed task after `delay` time.\n// This timed task can be run specified times.\nfunc (c *Cron) DelayAddTimes(ctx context.Context, delay time.Duration, pattern string, times int, job JobFunc, name ...string) {\n\tgtimer.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tif _, err := c.AddTimes(ctx, pattern, times, job, name...); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n}\n\n// Search returns a scheduled task with the specified `name`.\n// It returns nil if not found.\nfunc (c *Cron) Search(name string) *Entry {\n\tif v := c.entries.Get(name); v != nil {\n\t\treturn v.(*Entry)\n\t}\n\treturn nil\n}\n\n// Start starts running the specified timed task named `name`.\n// If no`name` specified, it starts the entire cron.\nfunc (c *Cron) Start(name ...string) {\n\tif len(name) > 0 {\n\t\tfor _, v := range name {\n\t\t\tif entry := c.Search(v); entry != nil {\n\t\t\t\tentry.Start()\n\t\t\t}\n\t\t}\n\t} else {\n\t\tc.runningLock.Lock()\n\t\tc.status.Set(StatusReady)\n\t\tc.running = true\n\t\tc.runningLock.Unlock()\n\t}\n}\n\n// Stop stops running the specified timed task named `name`.\n// If no`name` specified, it stops the entire cron.\nfunc (c *Cron) Stop(name ...string) {\n\tif len(name) > 0 {\n\t\tfor _, v := range name {\n\t\t\tif entry := c.Search(v); entry != nil {\n\t\t\t\tentry.Stop()\n\t\t\t}\n\t\t}\n\t} else {\n\t\tc.runningLock.Lock()\n\t\tc.status.Set(StatusStopped)\n\t\tc.running = false\n\t\tc.runningLock.Unlock()\n\t}\n}\n\n// StopGracefully Blocks and waits all current running jobs done.\nfunc (c *Cron) StopGracefully() {\n\tctx := c.StopGracefullyNonBlocking()\n\t<-ctx.Done()\n}\n\n// StopGracefullyNonBlocking stops all running tasks gracefully without blocking,\n// returning a context that callers can use to wait for completion.\nfunc (c *Cron) StopGracefullyNonBlocking() context.Context {\n\tctx, cancel := context.WithCancel(context.Background())\n\tgo func() {\n\t\tc.runningLock.Lock()\n\t\tdefer c.runningLock.Unlock()\n\t\tc.status.Set(StatusStopped)\n\t\tc.running = false\n\t\tc.jobWaiter.Wait()\n\t\tcancel()\n\t}()\n\treturn ctx\n}\n\n// Remove deletes scheduled task which named `name`.\nfunc (c *Cron) Remove(name string) {\n\tif v := c.entries.Get(name); v != nil {\n\t\tv.(*Entry).Close()\n\t}\n}\n\n// Close stops and closes current cron.\nfunc (c *Cron) Close() {\n\tc.runningLock.Lock()\n\tdefer c.runningLock.Unlock()\n\tc.status.Set(StatusClosed)\n\tc.running = false\n}\n\n// Size returns the size of the timed tasks.\nfunc (c *Cron) Size() int {\n\treturn c.entries.Size()\n}\n\n// Entries return all timed tasks as slice(order by registered time asc).\nfunc (c *Cron) Entries() []*Entry {\n\tarray := garray.NewSortedArraySize(c.entries.Size(), func(v1, v2 any) int {\n\t\tentry1 := v1.(*Entry)\n\t\tentry2 := v2.(*Entry)\n\t\tif entry1.RegisterTime.Nanosecond() > entry2.RegisterTime.Nanosecond() {\n\t\t\treturn 1\n\t\t}\n\t\treturn -1\n\t}, true)\n\tc.entries.RLockFunc(func(m map[string]any) {\n\t\tfor _, v := range m {\n\t\t\tarray.Add(v.(*Entry))\n\t\t}\n\t})\n\tentries := make([]*Entry, array.Len())\n\tarray.RLockFunc(func(array []any) {\n\t\tfor k, v := range array {\n\t\t\tentries[k] = v.(*Entry)\n\t\t}\n\t})\n\treturn entries\n}\n"
  },
  {
    "path": "os/gcron/gcron_entry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// JobFunc is the timing called job function in cron.\ntype JobFunc = gtimer.JobFunc\n\n// Entry is timing task entry.\ntype Entry struct {\n\tcron         *Cron         // Cron object belonged to.\n\ttimerEntry   *gtimer.Entry // Associated timer Entry.\n\tschedule     *cronSchedule // Timed schedule object.\n\tjobName      string        // Callback function name(address info).\n\ttimes        *gtype.Int    // Running times limit.\n\tinfinite     *gtype.Bool   // No times limit.\n\tName         string        // Entry name.\n\tRegisterTime time.Time     // Registered time.\n\tJob          JobFunc       `json:\"-\"` // Callback function.\n}\n\ntype doAddEntryInput struct {\n\tName        string          // Name names this entry for manual control.\n\tJob         JobFunc         // Job is the callback function for timed task execution.\n\tCtx         context.Context // The context for the job.\n\tTimes       int             // Times specifies the running limit times for the entry.\n\tPattern     string          // Pattern is the crontab style string for scheduler.\n\tIsSingleton bool            // Singleton specifies whether timed task executing in singleton mode.\n\tInfinite    bool            // Infinite specifies whether this entry is running with no times limit.\n}\n\n// doAddEntry creates and returns a new Entry object.\nfunc (c *Cron) doAddEntry(in doAddEntryInput) (*Entry, error) {\n\tif in.Name != \"\" {\n\t\tif c.Search(in.Name) != nil {\n\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\t`duplicated cron job name \"%s\", already exists`,\n\t\t\t\tin.Name,\n\t\t\t)\n\t\t}\n\t}\n\tschedule, err := newSchedule(in.Pattern)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// No limit for `times`, for timer checking scheduling every second.\n\tentry := &Entry{\n\t\tcron:         c,\n\t\tschedule:     schedule,\n\t\tjobName:      runtime.FuncForPC(reflect.ValueOf(in.Job).Pointer()).Name(),\n\t\ttimes:        gtype.NewInt(in.Times),\n\t\tinfinite:     gtype.NewBool(in.Infinite),\n\t\tRegisterTime: time.Now(),\n\t\tJob:          in.Job,\n\t}\n\tif in.Name != \"\" {\n\t\tentry.Name = in.Name\n\t} else {\n\t\tentry.Name = \"cron-\" + gconv.String(c.idGen.Add(1))\n\t}\n\t// When you add a scheduled task, you cannot allow it to run.\n\t// It cannot start running when added to timer.\n\t// It should start running after the entry is added to the Cron entries map, to avoid the task\n\t// from running during adding where the entries do not have the entry information, which might cause panic.\n\tentry.timerEntry = gtimer.AddEntry(\n\t\tin.Ctx,\n\t\ttime.Second,\n\t\tentry.checkAndRun,\n\t\tin.IsSingleton,\n\t\t-1,\n\t\tgtimer.StatusStopped,\n\t)\n\tc.entries.Set(entry.Name, entry)\n\tentry.timerEntry.Start()\n\treturn entry, nil\n}\n\n// IsSingleton return whether this entry is a singleton timed task.\nfunc (e *Entry) IsSingleton() bool {\n\treturn e.timerEntry.IsSingleton()\n}\n\n// SetSingleton sets the entry running in singleton mode.\nfunc (e *Entry) SetSingleton(enabled bool) {\n\te.timerEntry.SetSingleton(enabled)\n}\n\n// SetTimes sets the times which the entry can run.\nfunc (e *Entry) SetTimes(times int) {\n\te.times.Set(times)\n\te.infinite.Set(false)\n}\n\n// Status returns the status of entry.\nfunc (e *Entry) Status() int {\n\treturn e.timerEntry.Status()\n}\n\n// SetStatus sets the status of the entry.\nfunc (e *Entry) SetStatus(status int) int {\n\treturn e.timerEntry.SetStatus(status)\n}\n\n// Start starts running the entry.\nfunc (e *Entry) Start() {\n\te.timerEntry.Start()\n}\n\n// Stop stops running the entry.\nfunc (e *Entry) Stop() {\n\te.timerEntry.Stop()\n}\n\n// Close stops and removes the entry from cron.\nfunc (e *Entry) Close() {\n\te.cron.entries.Remove(e.Name)\n\te.timerEntry.Close()\n}\n\n// checkAndRun is the core timing task check logic.\n// This function is called every second.\nfunc (e *Entry) checkAndRun(ctx context.Context) {\n\tcurrentTime := time.Now()\n\tif !e.schedule.checkMeetAndUpdateLastSeconds(ctx, currentTime) {\n\t\treturn\n\t}\n\tswitch e.cron.status.Val() {\n\tcase StatusStopped:\n\t\treturn\n\n\tcase StatusClosed:\n\t\te.logDebugf(ctx, `cron job \"%s\" is removed`, e.getJobNameWithPattern())\n\t\te.Close()\n\n\tcase StatusReady, StatusRunning:\n\t\te.cron.runningLock.Lock()\n\t\tif e.cron.running {\n\t\t\te.cron.jobWaiter.Add(1)\n\t\t} else {\n\t\t\te.cron.runningLock.Unlock()\n\t\t\te.logDebugf(ctx, `cron job \"%s\" stoped or closed`, e.getJobNameWithPattern())\n\t\t\treturn\n\t\t}\n\t\te.cron.runningLock.Unlock()\n\t\tdefer func() {\n\t\t\te.cron.jobWaiter.Done()\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\t// Exception caught, it logs the error content to logger in default behavior.\n\t\t\t\te.logErrorf(ctx,\n\t\t\t\t\t`cron job \"%s(%s)\" end with error: %+v`,\n\t\t\t\t\te.jobName, e.schedule.pattern, exception,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\te.logDebugf(ctx, `cron job \"%s\" ends`, e.getJobNameWithPattern())\n\t\t\t}\n\t\t\tif e.timerEntry.Status() == StatusClosed {\n\t\t\t\te.Close()\n\t\t\t}\n\t\t}()\n\n\t\t// Running times check.\n\t\tif !e.infinite.Val() {\n\t\t\ttimes := e.times.Add(-1)\n\t\t\tif times <= 0 {\n\t\t\t\tif e.timerEntry.SetStatus(StatusClosed) == StatusClosed || times < 0 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\te.logDebugf(ctx, `cron job \"%s\" starts`, e.getJobNameWithPattern())\n\t\te.Job(ctx)\n\t}\n}\n\nfunc (e *Entry) getJobNameWithPattern() string {\n\treturn fmt.Sprintf(`%s(%s)`, e.jobName, e.schedule.pattern)\n}\n\nfunc (e *Entry) logDebugf(ctx context.Context, format string, v ...any) {\n\tif logger := e.cron.GetLogger(); logger != nil {\n\t\tlogger.Debugf(ctx, format, v...)\n\t}\n}\n\nfunc (e *Entry) logErrorf(ctx context.Context, format string, v ...any) {\n\tlogger := e.cron.GetLogger()\n\tif logger == nil {\n\t\tlogger = glog.DefaultLogger()\n\t}\n\tlogger.Errorf(ctx, format, v...)\n}\n"
  },
  {
    "path": "os/gcron/gcron_schedule.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// cronSchedule is the schedule for cron job.\ntype cronSchedule struct {\n\tcreateTimestamp int64            // Created timestamp in seconds.\n\teverySeconds    int64            // Running interval in seconds.\n\tpattern         string           // The raw cron pattern string that is passed in cron job creation.\n\tignoreSeconds   bool             // Mark the pattern is standard 5 parts crontab pattern instead 6 parts pattern.\n\tsecondMap       map[int]struct{} // Job can run in these second numbers.\n\tminuteMap       map[int]struct{} // Job can run in these minute numbers.\n\thourMap         map[int]struct{} // Job can run in these hour numbers.\n\tdayMap          map[int]struct{} // Job can run in these day numbers.\n\tweekMap         map[int]struct{} // Job can run in these week numbers.\n\tmonthMap        map[int]struct{} // Job can run in these moth numbers.\n\n\t// This field stores the timestamp that meets schedule latest.\n\tlastMeetTimestamp *gtype.Int64\n\n\t// Last timestamp number, for timestamp fix in some latency.\n\tlastCheckTimestamp *gtype.Int64\n}\n\ntype patternItemType int\n\nconst (\n\tpatternItemTypeSecond patternItemType = iota\n\tpatternItemTypeMinute\n\tpatternItemTypeHour\n\tpatternItemTypeDay\n\tpatternItemTypeWeek\n\tpatternItemTypeMonth\n)\n\nconst (\n\t// regular expression for cron pattern, which contains 6 parts of time units.\n\tregexForCron = `^([\\-/\\d\\*,#]+)\\s+([\\-/\\d\\*,]+)\\s+([\\-/\\d\\*,]+)\\s+([\\-/\\d\\*\\?,]+)\\s+([\\-/\\d\\*,A-Za-z]+)\\s+([\\-/\\d\\*\\?,A-Za-z]+)$`\n)\n\nvar (\n\t// Predefined pattern map.\n\tpredefinedPatternMap = map[string]string{\n\t\t\"@yearly\":   \"# 0 0 1 1 *\",\n\t\t\"@annually\": \"# 0 0 1 1 *\",\n\t\t\"@monthly\":  \"# 0 0 1 * *\",\n\t\t\"@weekly\":   \"# 0 0 * * 0\",\n\t\t\"@daily\":    \"# 0 0 * * *\",\n\t\t\"@midnight\": \"# 0 0 * * *\",\n\t\t\"@hourly\":   \"# 0 * * * *\",\n\t}\n\t// Short month name to its number.\n\tmonthShortNameMap = map[string]int{\n\t\t\"jan\": 1,\n\t\t\"feb\": 2,\n\t\t\"mar\": 3,\n\t\t\"apr\": 4,\n\t\t\"may\": 5,\n\t\t\"jun\": 6,\n\t\t\"jul\": 7,\n\t\t\"aug\": 8,\n\t\t\"sep\": 9,\n\t\t\"oct\": 10,\n\t\t\"nov\": 11,\n\t\t\"dec\": 12,\n\t}\n\t// Full month name to its number.\n\tmonthFullNameMap = map[string]int{\n\t\t\"january\":   1,\n\t\t\"february\":  2,\n\t\t\"march\":     3,\n\t\t\"april\":     4,\n\t\t\"may\":       5,\n\t\t\"june\":      6,\n\t\t\"july\":      7,\n\t\t\"august\":    8,\n\t\t\"september\": 9,\n\t\t\"october\":   10,\n\t\t\"november\":  11,\n\t\t\"december\":  12,\n\t}\n\t// Short week name to its number.\n\tweekShortNameMap = map[string]int{\n\t\t\"sun\": 0,\n\t\t\"mon\": 1,\n\t\t\"tue\": 2,\n\t\t\"wed\": 3,\n\t\t\"thu\": 4,\n\t\t\"fri\": 5,\n\t\t\"sat\": 6,\n\t}\n\t// Full week name to its number.\n\tweekFullNameMap = map[string]int{\n\t\t\"sunday\":    0,\n\t\t\"monday\":    1,\n\t\t\"tuesday\":   2,\n\t\t\"wednesday\": 3,\n\t\t\"thursday\":  4,\n\t\t\"friday\":    5,\n\t\t\"saturday\":  6,\n\t}\n)\n\n// newSchedule creates and returns a schedule object for given cron pattern.\nfunc newSchedule(pattern string) (*cronSchedule, error) {\n\tvar currentTimestamp = time.Now().Unix()\n\t// Check given `pattern` if the predefined patterns.\n\tif match, _ := gregex.MatchString(`(@\\w+)\\s*(\\w*)\\s*`, pattern); len(match) > 0 {\n\t\tkey := strings.ToLower(match[1])\n\t\tif v, ok := predefinedPatternMap[key]; ok {\n\t\t\tpattern = v\n\t\t} else if strings.Compare(key, \"@every\") == 0 {\n\t\t\td, err := gtime.ParseDuration(match[2])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn &cronSchedule{\n\t\t\t\tcreateTimestamp:    currentTimestamp,\n\t\t\t\teverySeconds:       int64(d.Seconds()),\n\t\t\t\tpattern:            pattern,\n\t\t\t\tlastMeetTimestamp:  gtype.NewInt64(currentTimestamp),\n\t\t\t\tlastCheckTimestamp: gtype.NewInt64(currentTimestamp),\n\t\t\t}, nil\n\t\t} else {\n\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern: \"%s\"`, pattern)\n\t\t}\n\t}\n\t// Handle given `pattern` as common 6 parts pattern.\n\tmatch, _ := gregex.MatchString(regexForCron, pattern)\n\tif len(match) != 7 {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern: \"%s\"`, pattern)\n\t}\n\tvar (\n\t\terr error\n\t\tcs  = &cronSchedule{\n\t\t\tcreateTimestamp:    currentTimestamp,\n\t\t\teverySeconds:       0,\n\t\t\tpattern:            pattern,\n\t\t\tlastMeetTimestamp:  gtype.NewInt64(currentTimestamp),\n\t\t\tlastCheckTimestamp: gtype.NewInt64(currentTimestamp),\n\t\t}\n\t)\n\n\t// Second.\n\tif match[1] == \"#\" {\n\t\tcs.ignoreSeconds = true\n\t} else {\n\t\tcs.secondMap, err = parsePatternItem(match[1], 0, 59, false, patternItemTypeSecond)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\t// Minute.\n\tcs.minuteMap, err = parsePatternItem(match[2], 0, 59, false, patternItemTypeMinute)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Hour.\n\tcs.hourMap, err = parsePatternItem(match[3], 0, 23, false, patternItemTypeHour)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Day.\n\tcs.dayMap, err = parsePatternItem(match[4], 1, 31, true, patternItemTypeDay)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Month.\n\tcs.monthMap, err = parsePatternItem(match[5], 1, 12, false, patternItemTypeMonth)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Week.\n\tcs.weekMap, err = parsePatternItem(match[6], 0, 6, true, patternItemTypeWeek)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn cs, nil\n}\n\n// parsePatternItem parses every item in the pattern and returns the result as map, which is used for indexing.\nfunc parsePatternItem(\n\titem string, min int, max int,\n\tallowQuestionMark bool, itemType patternItemType,\n) (itemMap map[int]struct{}, err error) {\n\titemMap = make(map[int]struct{}, max-min+1)\n\tif item == \"*\" || (allowQuestionMark && item == \"?\") {\n\t\tfor i := min; i <= max; i++ {\n\t\t\titemMap[i] = struct{}{}\n\t\t}\n\t\treturn itemMap, nil\n\t}\n\t// Example: 1-10/2,11-30/3\n\tvar number int\n\tfor _, itemElem := range strings.Split(item, \",\") {\n\t\tvar (\n\t\t\tinterval      = 1\n\t\t\tintervalArray = strings.Split(itemElem, \"/\")\n\t\t)\n\t\tif len(intervalArray) == 2 {\n\t\t\tif number, err = strconv.Atoi(intervalArray[1]); err != nil {\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, `invalid pattern item: \"%s\"`, itemElem,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tinterval = number\n\t\t\t}\n\t\t}\n\t\tvar (\n\t\t\trangeMin   = min\n\t\t\trangeMax   = max\n\t\t\trangeArray = strings.Split(intervalArray[0], \"-\") // Example: 1-30, JAN-DEC\n\t\t)\n\t\t// Example: 1-30/2\n\t\tif rangeArray[0] != \"*\" {\n\t\t\tif number, err = parseWeekAndMonthNameToInt(rangeArray[0], itemType); err != nil {\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, `invalid pattern item: \"%s\"`, itemElem,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\trangeMin = number\n\t\t\t\tif len(intervalArray) == 1 {\n\t\t\t\t\trangeMax = number\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Example: 1-30/2\n\t\tif len(rangeArray) == 2 {\n\t\t\tif number, err = parseWeekAndMonthNameToInt(rangeArray[1], itemType); err != nil {\n\t\t\t\treturn nil, gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, `invalid pattern item: \"%s\"`, itemElem,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\trangeMax = number\n\t\t\t}\n\t\t}\n\t\tfor i := rangeMin; i <= rangeMax; i += interval {\n\t\t\titemMap[i] = struct{}{}\n\t\t}\n\t}\n\treturn\n}\n\n// parseWeekAndMonthNameToInt parses the field value to a number according to its field type.\nfunc parseWeekAndMonthNameToInt(value string, itemType patternItemType) (int, error) {\n\tif gregex.IsMatchString(`^\\d+$`, value) {\n\t\t// It is pure number.\n\t\tif number, err := strconv.Atoi(value); err == nil {\n\t\t\treturn number, nil\n\t\t}\n\t} else {\n\t\t// Check if it contains letter,\n\t\t// it converts the value to number according to predefined map.\n\t\tswitch itemType {\n\t\tcase patternItemTypeWeek:\n\t\t\tif number, ok := weekShortNameMap[strings.ToLower(value)]; ok {\n\t\t\t\treturn number, nil\n\t\t\t}\n\t\t\tif number, ok := weekFullNameMap[strings.ToLower(value)]; ok {\n\t\t\t\treturn number, nil\n\t\t\t}\n\t\tcase patternItemTypeMonth:\n\t\t\tif number, ok := monthShortNameMap[strings.ToLower(value)]; ok {\n\t\t\t\treturn number, nil\n\t\t\t}\n\t\t\tif number, ok := monthFullNameMap[strings.ToLower(value)]; ok {\n\t\t\t\treturn number, nil\n\t\t\t}\n\t\t}\n\t}\n\treturn 0, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid pattern value: \"%s\"`, value)\n}\n"
  },
  {
    "path": "os/gcron/gcron_schedule_check.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// checkMeetAndUpdateLastSeconds checks if the given time `t` meets the runnable point for the job.\n// This function is called every second.\nfunc (s *cronSchedule) checkMeetAndUpdateLastSeconds(ctx context.Context, currentTime time.Time) (ok bool) {\n\tvar (\n\t\tlastCheckTimestamp = s.getAndUpdateLastCheckTimestamp(ctx, currentTime)\n\t\tlastCheckTime      = gtime.NewFromTimeStamp(lastCheckTimestamp)\n\t\tlastMeetTime       = gtime.NewFromTimeStamp(s.lastMeetTimestamp.Val())\n\t)\n\tdefer func() {\n\t\tif ok {\n\t\t\ts.lastMeetTimestamp.Set(currentTime.Unix())\n\t\t}\n\t}()\n\treturn s.checkMinIntervalAndItemMapMeet(lastMeetTime.Time, lastCheckTime.Time, currentTime)\n}\n\nfunc (s *cronSchedule) checkMinIntervalAndItemMapMeet(\n\tlastMeetTime, lastCheckTime, currentTime time.Time,\n) (ok bool) {\n\tif s.everySeconds != 0 {\n\t\t// It checks using interval.\n\t\tsecondsAfterCreated := lastCheckTime.UnixNano()/1e9 - s.createTimestamp\n\t\tif secondsAfterCreated > 0 {\n\t\t\treturn secondsAfterCreated%s.everySeconds == 0\n\t\t}\n\t\treturn false\n\t}\n\tif !s.checkMeetSecond(lastMeetTime, currentTime) {\n\t\treturn false\n\t}\n\tif !s.checkMeetMinute(currentTime) {\n\t\treturn false\n\t}\n\tif !s.checkMeetHour(currentTime) {\n\t\treturn false\n\t}\n\tif !s.checkMeetDay(currentTime) {\n\t\treturn false\n\t}\n\tif !s.checkMeetMonth(currentTime) {\n\t\treturn false\n\t}\n\tif !s.checkMeetWeek(currentTime) {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (s *cronSchedule) checkMeetSecond(lastMeetTime, currentTime time.Time) (ok bool) {\n\tif s.ignoreSeconds {\n\t\tif currentTime.Unix()-lastMeetTime.Unix() < 60 {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\t// If this pattern is set in precise second time,\n\t\t// it is not allowed executed in the same time.\n\t\tif len(s.secondMap) == 1 && lastMeetTime.Format(time.RFC3339) == currentTime.Format(time.RFC3339) {\n\t\t\treturn false\n\t\t}\n\t\tif !s.keyMatch(s.secondMap, currentTime.Second()) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (s *cronSchedule) checkMeetMinute(currentTime time.Time) (ok bool) {\n\treturn s.keyMatch(s.minuteMap, currentTime.Minute())\n}\n\nfunc (s *cronSchedule) checkMeetHour(currentTime time.Time) (ok bool) {\n\treturn s.keyMatch(s.hourMap, currentTime.Hour())\n}\n\nfunc (s *cronSchedule) checkMeetDay(currentTime time.Time) (ok bool) {\n\treturn s.keyMatch(s.dayMap, currentTime.Day())\n}\n\nfunc (s *cronSchedule) checkMeetMonth(currentTime time.Time) (ok bool) {\n\treturn s.keyMatch(s.monthMap, int(currentTime.Month()))\n}\n\nfunc (s *cronSchedule) checkMeetWeek(currentTime time.Time) (ok bool) {\n\treturn s.keyMatch(s.weekMap, int(currentTime.Weekday()))\n}\n\nfunc (s *cronSchedule) keyMatch(m map[int]struct{}, key int) bool {\n\t_, ok := m[key]\n\treturn ok\n}\n\nfunc (s *cronSchedule) checkItemMapMeet(lastMeetTime, currentTime time.Time) (ok bool) {\n\t// second.\n\tif s.ignoreSeconds {\n\t\tif currentTime.Unix()-lastMeetTime.Unix() < 60 {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\tif !s.keyMatch(s.secondMap, currentTime.Second()) {\n\t\t\treturn false\n\t\t}\n\t}\n\t// minute.\n\tif !s.keyMatch(s.minuteMap, currentTime.Minute()) {\n\t\treturn false\n\t}\n\t// hour.\n\tif !s.keyMatch(s.hourMap, currentTime.Hour()) {\n\t\treturn false\n\t}\n\t// day.\n\tif !s.keyMatch(s.dayMap, currentTime.Day()) {\n\t\treturn false\n\t}\n\t// month.\n\tif !s.keyMatch(s.monthMap, int(currentTime.Month())) {\n\t\treturn false\n\t}\n\t// week.\n\tif !s.keyMatch(s.weekMap, int(currentTime.Weekday())) {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "os/gcron/gcron_schedule_fix.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// getAndUpdateLastCheckTimestamp checks fixes and returns the last timestamp that have delay fix in some seconds.\nfunc (s *cronSchedule) getAndUpdateLastCheckTimestamp(ctx context.Context, t time.Time) int64 {\n\tvar (\n\t\tcurrentTimestamp   = t.Unix()\n\t\tlastCheckTimestamp = s.lastCheckTimestamp.Val()\n\t)\n\tswitch lastCheckTimestamp {\n\t// Often happens, timer triggers in the same second, but the millisecond is different.\n\t// Example:\n\t// lastCheckTimestamp: 2024-03-26 19:47:34.000\n\t// currentTimestamp:   2024-03-26 19:47:34.999\n\tcase currentTimestamp:\n\t\tlastCheckTimestamp += 1\n\n\t// Often happens, no latency.\n\t// Example:\n\t// lastCheckTimestamp: 2024-03-26 19:47:34.000\n\t// currentTimestamp:   2024-03-26 19:47:35.000\n\tcase currentTimestamp - 1:\n\t\tlastCheckTimestamp = currentTimestamp\n\n\t// Latency in 3 seconds, which can be tolerant.\n\t// Example:\n\t// lastCheckTimestamp: 2024-03-26 19:47:31.000、2024-03-26 19:47:32.000\n\t// currentTimestamp:   2024-03-26 19:47:34.000\n\tcase currentTimestamp - 2, currentTimestamp - 3:\n\t\tlastCheckTimestamp += 1\n\n\t// Too much latency, it ignores the fix, the cron job might not be triggered.\n\tdefault:\n\t\t// Too much delay, let's update the last timestamp to current one.\n\t\tintlog.Printf(\n\t\t\tctx,\n\t\t\t`too much latency, last timestamp \"%d\", current \"%d\", latency \"%d\"`,\n\t\t\tlastCheckTimestamp, currentTimestamp, currentTimestamp-lastCheckTimestamp,\n\t\t)\n\t\tlastCheckTimestamp = currentTimestamp\n\t}\n\ts.lastCheckTimestamp.Set(lastCheckTimestamp)\n\treturn lastCheckTimestamp\n}\n"
  },
  {
    "path": "os/gcron/gcron_schedule_next.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"time\"\n)\n\n// Next returns the next time this schedule is activated, greater than the given\n// time.  If no time can be found to satisfy the schedule, return the zero time.\nfunc (s *cronSchedule) Next(lastMeetTime time.Time) time.Time {\n\tif s.everySeconds != 0 {\n\t\tvar (\n\t\t\tdiff  = lastMeetTime.Unix() - s.createTimestamp\n\t\t\tcount = diff/s.everySeconds + 1\n\t\t)\n\t\treturn lastMeetTime.Add(time.Duration(count*s.everySeconds) * time.Second)\n\t}\n\n\tvar currentTime = lastMeetTime\n\tif s.ignoreSeconds {\n\t\t// Start at the earliest possible time (the upcoming minute).\n\t\tcurrentTime = currentTime.Add(1*time.Minute - time.Duration(currentTime.Nanosecond())*time.Nanosecond)\n\t} else {\n\t\t// Start at the earliest possible time (the upcoming second).\n\t\tcurrentTime = currentTime.Add(1*time.Second - time.Duration(currentTime.Nanosecond())*time.Nanosecond)\n\t}\n\n\tvar (\n\t\tloc       = currentTime.Location()\n\t\tyearLimit = currentTime.Year() + 5\n\t)\n\nWRAP:\n\tif currentTime.Year() > yearLimit {\n\t\treturn currentTime // who will care the job that run in five years later\n\t}\n\n\tfor !s.checkMeetMonth(currentTime) {\n\t\tcurrentTime = currentTime.AddDate(0, 1, 0)\n\t\tcurrentTime = time.Date(currentTime.Year(), currentTime.Month(), 1, 0, 0, 0, 0, loc)\n\t\tif currentTime.Month() == time.January {\n\t\t\tgoto WRAP\n\t\t}\n\t}\n\tfor !s.checkMeetWeek(currentTime) || !s.checkMeetDay(currentTime) {\n\t\tcurrentTime = currentTime.AddDate(0, 0, 1)\n\t\tcurrentTime = time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, loc)\n\t\tif currentTime.Day() == 1 {\n\t\t\tgoto WRAP\n\t\t}\n\t}\n\tfor !s.checkMeetHour(currentTime) {\n\t\tcurrentTime = currentTime.Add(time.Hour)\n\t\tcurrentTime = currentTime.Truncate(time.Hour)\n\t\tif currentTime.Hour() == 0 {\n\t\t\tgoto WRAP\n\t\t}\n\t}\n\tfor !s.checkMeetMinute(currentTime) {\n\t\tcurrentTime = currentTime.Add(1 * time.Minute)\n\t\tcurrentTime = currentTime.Truncate(time.Minute)\n\t\tif currentTime.Minute() == 0 {\n\t\t\tgoto WRAP\n\t\t}\n\t}\n\n\tfor !s.checkMeetSecond(lastMeetTime, currentTime) {\n\t\tcurrentTime = currentTime.Add(1 * time.Second)\n\t\tif currentTime.Second() == 0 {\n\t\t\tgoto WRAP\n\t\t}\n\t}\n\treturn currentTime.In(loc)\n}\n"
  },
  {
    "path": "os/gcron/gcron_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gcron\"\n)\n\nfunc Benchmark_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgcron.Add(ctx, \"1 1 1 1 1 1\", func(ctx context.Context) {\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "os/gcron/gcron_z_example_1_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcron\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\nfunc ExampleCron_AddSingleton() {\n\tgcron.AddSingleton(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\tglog.Print(context.TODO(), \"doing\")\n\t\ttime.Sleep(2 * time.Second)\n\t})\n\tselect {}\n}\n\nfunc ExampleCron_gracefulShutdown() {\n\t_, err := gcron.Add(ctx, \"*/2 * * * * *\", func(ctx context.Context) {\n\t\tg.Log().Debug(ctx, \"Every 2s job start\")\n\t\ttime.Sleep(5 * time.Second)\n\t\tg.Log().Debug(ctx, \"Every 2s job after 5 second end\")\n\t}, \"MyCronJob1\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tquit := make(chan os.Signal, 1)\n\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n\tsig := <-quit\n\tglog.Printf(ctx, \"Signal received: %s, stopping cron\", sig)\n\n\tglog.Print(ctx, \"Waiting for all cron jobs to complete...\")\n\tgcron.StopGracefully()\n\tglog.Print(ctx, \"All cron jobs completed\")\n}\n\nfunc ExampleCron_StopGracefullyNonBlocking() {\n\t_, err := gcron.Add(ctx, \"*/2 * * * * *\", func(ctx context.Context) {\n\t\tg.Log().Debug(ctx, \"Every 2s job start\")\n\t\ttime.Sleep(5 * time.Second)\n\t\tg.Log().Debug(ctx, \"Every 2s job after 5 second end\")\n\t}, \"MyCronJob2\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tquit := make(chan os.Signal, 1)\n\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n\tsig := <-quit\n\tglog.Printf(ctx, \"Signal received: %s, stopping cron\", sig)\n\n\tglog.Print(ctx, \"Waiting for all cron jobs to complete...\")\n\tctx := gcron.StopGracefullyNonBlocking()\n\t<-ctx.Done()\n\tglog.Print(ctx, \"All cron jobs completed\")\n}\n"
  },
  {
    "path": "os/gcron/gcron_z_unit_entry_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gcron\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestCron_Entry_Operations(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcron  = gcron.New()\n\t\t\tarray = garray.New(true)\n\t\t)\n\t\tgo func() {\n\t\t\tcron.DelayAddTimes(ctx, 500*time.Millisecond, \"* * * * * *\", 2, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 0)\n\t\t}()\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\tt.Assert(cron.Size(), 1)\n\t\ttime.Sleep(3000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcron  = gcron.New()\n\t\t\tarray = garray.New(true)\n\t\t)\n\t\tvar entry *gcron.Entry\n\t\tgo func() {\n\t\t\tvar err error\n\t\t\tentry, err = cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\t\t\tt.Assert(array.Len(), 0)\n\t\t\tt.Assert(cron.Size(), 1)\n\t\t}()\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 1)\n\t\tentry.Stop()\n\t\ttime.Sleep(5000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 1)\n\t\tentry.Start()\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tt.Assert(cron.Size(), 1)\n\t\tentry.Close()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n"
  },
  {
    "path": "os/gcron/gcron_z_unit_schedule_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestSlash(t *testing.T) {\n\truns := []struct {\n\t\tspec     string\n\t\texpected map[int]struct{}\n\t}{\n\t\t{\"0 0 0 * Feb Mon/2\", map[int]struct{}{1: {}, 3: {}, 5: {}}},\n\t\t{\"0 0 0 * Feb *\", map[int]struct{}{1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 0: {}}},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, c := range runs {\n\t\t\ts, err := newSchedule(c.spec)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\n\t\t\t}\n\t\t\tt.AssertEQ(s.weekMap, c.expected)\n\t\t}\n\t})\n}\n\nfunc TestNext(t *testing.T) {\n\truns := []struct {\n\t\ttime, spec string\n\t\texpected   string\n\t}{\n\t\t// Simple cases\n\t\t{\"Mon Jul 9 14:45 2012\", \"0 0/15 * * * *\", \"Mon Jul 9 15:00 2012\"},\n\t\t{\"Mon Jul 9 14:59 2012\", \"0 0/15 * * * *\", \"Mon Jul 9 15:00 2012\"},\n\t\t{\"Mon Jul 9 14:59:59 2012\", \"0 0/15 * * * *\", \"Mon Jul 9 15:00 2012\"},\n\n\t\t// Wrap around hours\n\t\t{\"Mon Jul 9 15:45 2012\", \"0 20-35/15 * * * *\", \"Mon Jul 9 16:20 2012\"},\n\n\t\t// Wrap around days\n\t\t{\"Mon Jul 9 23:46 2012\", \"0 */15 * * * *\", \"Tue Jul 10 00:00 2012\"},\n\t\t{\"Mon Jul 9 23:45 2012\", \"0 20-35/15 * * * *\", \"Tue Jul 10 00:20 2012\"},\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 * * * *\", \"Tue Jul 10 00:20:15 2012\"},\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 1/2 * * *\", \"Tue Jul 10 01:20:15 2012\"},\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 10-12 * * *\", \"Tue Jul 10 10:20:15 2012\"},\n\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 1/2 */2 * *\", \"Thu Jul 11 01:20:15 2012\"},\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 * 9-20 * *\", \"Wed Jul 10 00:20:15 2012\"},\n\t\t{\"Mon Jul 9 23:35:51 2012\", \"15/35 20-35/15 * 9-20 Jul *\", \"Wed Jul 10 00:20:15 2012\"},\n\n\t\t// Wrap around months\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 9 Apr-Oct ?\", \"Thu Aug 9 00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 */5 Apr,Aug,Oct Mon\", \"Mon Aug 6 00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 */5 Oct Mon\", \"Mon Oct 1 00:00 2012\"},\n\n\t\t// Wrap around years\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 * Feb Mon\", \"Mon Feb 4 00:00 2013\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 * Feb Mon/2\", \"Fri Feb 1 00:00 2013\"},\n\n\t\t// Wrap around minute, hour, day, month, and year\n\t\t{\"Mon Dec 31 23:59:45 2012\", \"0 * * * * *\", \"Tue Jan 1 00:00:00 2013\"},\n\n\t\t// Leap year\n\t\t{\"Mon Jul 9 23:35 2012\", \"0 0 0 29 Feb ?\", \"Mon Feb 29 00:00 2016\"},\n\n\t\t// Predefined pattern map.\n\t\t{\"Mon Jul 9 23:35 2012\", \"@yearly\", \"Sun Jan 1 00:00:00 2013\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@annually\", \"Sun Jan 1 00:00:00 2013\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@monthly\", \"Mon Aug 1 00:00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@weekly\", \"Sun Jul 15 00:00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@daily\", \"Tue Jul 10 00:00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@midnight\", \"Tue Jul 10 00:00:00 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"@hourly\", \"Tue Jul 10 00:00:00 2012\"},\n\n\t\t// Ignore seconds.\n\t\t{\"Mon Jul 9 23:35 2012\", \"# * * * * *\", \"Mon Jul 9 23:36 2012\"},\n\t\t{\"Mon Jul 9 23:35 2012\", \"# */2 * * * *\", \"Mon Jul 9 23:36 2012\"},\n\t}\n\n\tfor _, c := range runs {\n\t\ts, err := newSchedule(c.spec)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\tcontinue\n\t\t}\n\t\t// fmt.Printf(\"%+v\", sched)\n\t\tactual := s.Next(getTime(c.time))\n\t\texpected := getTime(c.expected)\n\t\tif !(actual.Unix() == expected.Unix()) {\n\t\t\tt.Errorf(\n\t\t\t\t\"%s, \\\"%s\\\": (expected) %v != %v (actual)\",\n\t\t\t\tc.time, c.spec, expected, actual,\n\t\t\t)\n\t\t}\n\t}\n}\n\nfunc getTime(value string) time.Time {\n\tif value == \"\" {\n\t\treturn time.Time{}\n\t}\n\n\tvar location = time.Local\n\tif strings.HasPrefix(value, \"TZ=\") {\n\t\tparts := strings.Fields(value)\n\t\tloc, err := time.LoadLocation(parts[0][len(\"TZ=\"):])\n\t\tif err != nil {\n\t\t\tpanic(\"could not parse location:\" + err.Error())\n\t\t}\n\t\tlocation = loc\n\t\tvalue = parts[1]\n\t}\n\n\tvar layouts = []string{\n\t\t\"Mon Jan 2 15:04 2006\",\n\t\t\"Mon Jan 2 15:04:05 2006\",\n\t}\n\tfor _, layout := range layouts {\n\t\tif t, err := time.ParseInLocation(layout, value, location); err == nil {\n\t\t\treturn t\n\t\t}\n\t}\n\tif t, err := time.ParseInLocation(\"2006-01-02T15:04:05-0700\", value, location); err == nil {\n\t\treturn t\n\t}\n\tpanic(\"could not parse time value \" + value)\n}\n"
  },
  {
    "path": "os/gcron/gcron_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gcron_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcron\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc TestCron_Add_Close(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tarray := garray.New(true)\n\t\tg.Log().Debugf(ctx, \"TestCron_Add_Close Add begin  Start time %v \", time.Now().UnixMilli())\n\t\tgo func() {\n\t\t\t_, err1 := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Print(ctx, \"cron1\")\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(err1, nil)\n\t\t}()\n\t\tgo func() {\n\t\t\t_, err2 := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Print(ctx, \"cron2\")\n\t\t\t\tarray.Append(1)\n\t\t\t}, \"test\")\n\t\t\tt.Assert(err2, nil)\n\t\t}()\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tt.Assert(cron.Size(), 2)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 4)\n\t\tcron.Close()\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tfixedLength := array.Len()\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tt.Assert(array.Len(), fixedLength)\n\t})\n}\n\nfunc TestCron_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tcron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {}, \"add\")\n\t\tcron.DelayAdd(ctx, time.Second, \"* * * * * *\", func(ctx context.Context) {}, \"delay_add\")\n\t\tt.Assert(cron.Size(), 1)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(cron.Size(), 2)\n\n\t\tcron.Remove(\"delay_add\")\n\t\tt.Assert(cron.Size(), 1)\n\n\t\tentry1 := cron.Search(\"add\")\n\t\tentry2 := cron.Search(\"test-none\")\n\t\tt.AssertNE(entry1, nil)\n\t\tt.Assert(entry2, nil)\n\t})\n\n\t// test @ error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\t_, err := cron.Add(ctx, \"@aaa\", func(ctx context.Context) {}, \"add\")\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// test @every error\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\t_, err := cron.Add(ctx, \"@every xxx\", func(ctx context.Context) {}, \"add\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestCron_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t}, \"add\")\n\t\t\tt.Assert(array.Len(), 0)\n\t\t}()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tcron.Remove(\"add\")\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t})\n}\n\nfunc TestCron_Add_FixedPattern(t *testing.T) {\n\tfor i := 0; i < 5; i++ {\n\t\tdoTestCronAddFixedPattern(t)\n\t}\n}\n\nfunc doTestCronAddFixedPattern(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tnow    = time.Now()\n\t\t\tcron   = gcron.New()\n\t\t\tarray  = garray.New(true)\n\t\t\texpect = now.Add(time.Second * 2)\n\t\t)\n\t\tdefer cron.Close()\n\t\tvar pattern = fmt.Sprintf(\n\t\t\t`%d %d %d %d %d %s`,\n\t\t\texpect.Second(), expect.Minute(), expect.Hour(), expect.Day(), expect.Month(), expect.Weekday().String(),\n\t\t)\n\t\tcron.SetLogger(g.Log())\n\t\tgo func() {\n\t\t\tg.Log().Debugf(ctx, `pattern: %s`, pattern)\n\t\t\t_, err := cron.Add(ctx, pattern, func(ctx context.Context) {\n\t\t\t\tg.Log().Debugf(ctx, `receive job`)\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t}()\n\t\ttime.Sleep(3500 * time.Millisecond)\n\t\tg.Log().Debug(ctx, `current time`)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestCron_AddSingleton(t *testing.T) {\n\t// un used, can be removed\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tgo func() {\n\t\t\tcron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {}, \"add\")\n\t\t\tcron.DelayAdd(ctx, time.Second, \"* * * * * *\", func(ctx context.Context) {}, \"delay_add\")\n\t\t\tt.Assert(cron.Size(), 1)\n\t\t}()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(cron.Size(), 2)\n\n\t\tcron.Remove(\"delay_add\")\n\t\tt.Assert(cron.Size(), 1)\n\n\t\tentry1 := cron.Search(\"add\")\n\t\tentry2 := cron.Search(\"test-none\")\n\t\tt.AssertNE(entry1, nil)\n\t\tt.Assert(entry2, nil)\n\t})\n\t// keep this\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.AddSingleton(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(50 * time.Second)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 1)\n\t\t}()\n\t\ttime.Sleep(3500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n\n}\n\nfunc TestCron_AddOnce1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.AddOnce(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tcron.AddOnce(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 2)\n\t\t}()\n\t\ttime.Sleep(2500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n\nfunc TestCron_AddOnce2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.AddOnce(ctx, \"@every 2s\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 1)\n\t\t}()\n\t\ttime.Sleep(3000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n\nfunc TestCron_AddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\t_, _ = cron.AddTimes(ctx, \"* * * * * *\", 2, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(3500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n\nfunc TestCron_DelayAdd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.DelayAdd(ctx, 500*time.Millisecond, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 0)\n\t\t}()\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\tt.Assert(cron.Size(), 1)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 1)\n\t})\n}\n\nfunc TestCron_DelayAddSingleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.DelayAddSingleton(ctx, 500*time.Millisecond, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(10 * time.Second)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 0)\n\t\t}()\n\t\ttime.Sleep(2200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 1)\n\t})\n}\n\nfunc TestCron_DelayAddOnce(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.DelayAddOnce(ctx, 500*time.Millisecond, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 0)\n\t\t}()\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\tt.Assert(cron.Size(), 1)\n\t\ttime.Sleep(2200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n\nfunc TestCron_DelayAddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tcron.DelayAddTimes(ctx, 500*time.Millisecond, \"* * * * * *\", 2, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.Assert(cron.Size(), 0)\n\t\t}()\n\t\ttime.Sleep(800 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\tt.Assert(cron.Size(), 1)\n\t\ttime.Sleep(3000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tt.Assert(cron.Size(), 0)\n\t})\n}\n\nfunc TestCron_JobWaiter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := garray.New(true)\n\t\ts2 := garray.New(true)\n\t\tquit := make(chan os.Signal, 1)\n\t\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every second\")\n\t\t\t\ts1.Append(struct{}{})\n\t\t\t}, \"TestCronJobWaiterMyFirstCronJob\")\n\t\t\tt.Assert(err, nil)\n\t\t}()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"*/2 * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job start\")\n\t\t\t\ttime.Sleep(3 * time.Second)\n\t\t\t\ts2.Append(struct{}{})\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job after 3 second end\")\n\t\t\t}, \"TestCronJobMySecondCronJob\")\n\t\t\tt.Assert(err, nil)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(4300 * time.Millisecond) // Ensure that the job is triggered twice\n\t\t\tglog.Print(ctx, \"Sending SIGINT\")\n\t\t\tquit <- syscall.SIGINT // Send SIGINT\n\t\t}()\n\n\t\tsig := <-quit\n\t\tglog.Printf(ctx, \"Signal received: %s, stopping cron\", sig)\n\n\t\tglog.Print(ctx, \"TestCron_JobWaiter Waiting for all cron jobs to complete...\")\n\t\tcron.StopGracefully()\n\t\tglog.Print(ctx, \"All cron jobs completed\")\n\t\tt.Assert(s1.Len(), 4)\n\t\tt.Assert(s2.Len(), 2)\n\t})\n}\n\nfunc TestCron_JobWaiterNonBlocking(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := garray.New(true)\n\t\ts2 := garray.New(true)\n\t\tquit := make(chan os.Signal, 1)\n\t\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every second start\")\n\t\t\t\ts1.Append(struct{}{})\n\t\t\t\tg.Log().Debug(ctx, \"Every second end \")\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\t\t}()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"*/2 * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job start \")\n\t\t\t\ttime.Sleep(3 * time.Second)\n\t\t\t\ts2.Append(struct{}{})\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job after 3 second end \")\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(4300 * time.Millisecond) // Ensure that the job is triggered twice\n\t\t\tglog.Print(ctx, \"Sending SIGINT\")\n\t\t\tquit <- syscall.SIGINT // Send SIGINT\n\t\t}()\n\n\t\tsig := <-quit\n\t\tglog.Printf(ctx, \"Signal received: %s, stopping cron\", sig)\n\t\tglog.Print(ctx, \"TestCron_JobWaiterNonBlocking Waiting for all cron jobs to complete...\")\n\t\tctx := cron.StopGracefullyNonBlocking()\n\t\t<-ctx.Done()\n\t\tglog.Print(ctx, \"All cron jobs completed\")\n\t\tt.Assert(s1.Len(), 4)\n\t\tt.Assert(s2.Len(), 2)\n\t})\n}\n\nfunc TestCron_NoneJobsDoneImmediately(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\n\t\tctx := cron.StopGracefullyNonBlocking()\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-time.After(110 * time.Millisecond):\n\t\t\tt.Error(\"context was not done immediately\")\n\t\t}\n\t})\n}\n\nfunc TestCron_RepeatedCallsStopGracefullyNonBlocking(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\n\t\t_ = cron.StopGracefullyNonBlocking()\n\t\tctx := cron.StopGracefullyNonBlocking()\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-time.After(110 * time.Millisecond):\n\t\t\tt.Error(\"context was not done immediately\")\n\t\t}\n\t})\n}\n\nfunc TestCron_RepeatedCallsStopGracefullyNonBlocking2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := garray.New(true)\n\t\ts2 := garray.New(true)\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tg.Log().Debugf(ctx, \"TestCron_RepeatedCallsStopGracefullyNonBlocking2 Add begin  Start time %v \", time.Now().UnixMilli())\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every second\")\n\t\t\t\ts1.Append(struct{}{})\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\n\t\t}()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"*/2 * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job start\")\n\t\t\t\ttime.Sleep(3 * time.Second)\n\t\t\t\ts2.Append(struct{}{})\n\t\t\t\tg.Log().Debug(ctx, \"Every 2s job after 3 second end\")\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\t\t}()\n\t\ttime.Sleep(4300 * time.Millisecond)\n\t\tg.Log().Debugf(ctx, \"TestCron_RepeatedCallsStopGracefullyNonBlocking2 end time %v \", time.Now().UnixMilli())\n\t\tglog.Print(ctx, \"Waiting for all cron jobs to complete...\")\n\t\t_ = cron.StopGracefullyNonBlocking()\n\t\tctx := cron.StopGracefullyNonBlocking()\n\t\t<-ctx.Done()\n\t\tglog.Print(ctx, \"All cron jobs completed\")\n\t\tt.Assert(s1.Len(), 4)\n\t\tt.Assert(s2.Len(), 2)\n\t})\n}\n\nfunc TestCron_StopGracefullyWithStopStart(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcron := gcron.New()\n\t\tdefer cron.Close()\n\t\tgo func() {\n\t\t\t_, err := cron.Add(ctx, \"* * * * * *\", func(ctx context.Context) {\n\t\t\t\tg.Log().Debug(ctx, \"Every second\")\n\t\t\t})\n\t\t\tt.Assert(err, nil)\n\t\t}()\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tcron.Stop()\n\t\tcron.Start()\n\t\tctx := cron.StopGracefullyNonBlocking()\n\t\t<-ctx.Done()\n\t})\n}\n"
  },
  {
    "path": "os/gctx/gctx.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gctx wraps context.Context and provides extra context features.\npackage gctx\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n)\n\ntype (\n\tCtx    = context.Context // Ctx is a short name alias for context.Context.\n\tStrKey string            // StrKey is a type for warps basic type string as context key.\n)\n\nvar (\n\t// initCtx is the context initialized from process environment.\n\tinitCtx context.Context\n)\n\nfunc init() {\n\t// All environment key-value pairs.\n\tm := make(map[string]string)\n\ti := 0\n\tfor _, s := range os.Environ() {\n\t\ti = strings.IndexByte(s, '=')\n\t\tif i == -1 {\n\t\t\tcontinue\n\t\t}\n\t\tm[s[0:i]] = s[i+1:]\n\t}\n\t// OpenTelemetry from environments.\n\tinitCtx = otel.GetTextMapPropagator().Extract(\n\t\tcontext.Background(),\n\t\tpropagation.MapCarrier(m),\n\t)\n}\n\n// New creates and returns a context which contains context id.\nfunc New() context.Context {\n\treturn WithSpan(context.Background(), \"gctx.New\")\n}\n\n// WithCtx creates and returns a context containing context id upon given parent context `ctx`.\n//\n// Deprecated: use WithSpan instead.\nfunc WithCtx(ctx context.Context) context.Context {\n\tif CtxId(ctx) != \"\" {\n\t\treturn ctx\n\t}\n\tvar span *gtrace.Span\n\tctx, span = gtrace.NewSpan(ctx, \"gctx.WithCtx\")\n\tdefer span.End()\n\treturn ctx\n}\n\n// WithSpan creates and returns a context containing span upon given parent context `ctx`.\nfunc WithSpan(ctx context.Context, spanName string) context.Context {\n\tif CtxId(ctx) != \"\" {\n\t\treturn ctx\n\t}\n\tif spanName == \"\" {\n\t\tspanName = \"gctx.WithSpan\"\n\t}\n\tvar span *gtrace.Span\n\tctx, span = gtrace.NewSpan(ctx, spanName)\n\tdefer span.End()\n\treturn ctx\n}\n\n// CtxId retrieves and returns the context id from context.\nfunc CtxId(ctx context.Context) string {\n\treturn gtrace.GetTraceID(ctx)\n}\n\n// SetInitCtx sets custom initialization context.\n// Note that this function cannot be called in multiple goroutines.\nfunc SetInitCtx(ctx context.Context) {\n\tinitCtx = ctx\n}\n\n// GetInitCtx returns the initialization context.\n// Initialization context is used in `main` or `init` functions.\nfunc GetInitCtx() context.Context {\n\treturn initCtx\n}\n"
  },
  {
    "path": "os/gctx/gctx_never_done.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gctx\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// neverDoneCtx never done.\ntype neverDoneCtx struct {\n\tcontext.Context\n}\n\n// Done forbids the context done from parent context.\nfunc (*neverDoneCtx) Done() <-chan struct{} {\n\treturn nil\n}\n\n// Deadline forbids the context deadline from parent context.\nfunc (*neverDoneCtx) Deadline() (deadline time.Time, ok bool) {\n\treturn time.Time{}, false\n}\n\n// Err forbids the context done from parent context.\nfunc (c *neverDoneCtx) Err() error {\n\treturn nil\n}\n\n// NeverDone wraps and returns a new context object that will be never done,\n// which forbids the context manually done, to make the context can be propagated\n// to asynchronous goroutines.\n//\n// Note that, it does not affect the closing (canceling) of the parent context,\n// as it is a wrapper for its parent, which only affects the next context handling.\nfunc NeverDone(ctx context.Context) context.Context {\n\treturn &neverDoneCtx{ctx}\n}\n"
  },
  {
    "path": "os/gctx/gctx_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gctx_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_NeverDone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx, _ := context.WithDeadline(gctx.New(), time.Now().Add(time.Hour))\n\t\tt.AssertNE(ctx, nil)\n\t\tt.AssertNE(ctx.Done(), nil)\n\t\tt.Assert(ctx.Err(), nil)\n\n\t\ttm, ok := ctx.Deadline()\n\t\tt.AssertNE(tm, time.Time{})\n\t\tt.Assert(ok, true)\n\n\t\tctx = gctx.NeverDone(ctx)\n\t\tt.AssertNE(ctx, nil)\n\t\tt.Assert(ctx.Done(), nil)\n\t\tt.Assert(ctx.Err(), nil)\n\n\t\ttm, ok = ctx.Deadline()\n\t\tt.Assert(tm, time.Time{})\n\t\tt.Assert(ok, false)\n\t})\n}\n"
  },
  {
    "path": "os/gctx/gctx_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gctx_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := gctx.New()\n\t\tt.AssertNE(ctx, nil)\n\t\tt.AssertNE(gctx.CtxId(ctx), \"\")\n\t})\n}\n\nfunc Test_WithCtx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.WithValue(context.TODO(), \"TEST\", 1)\n\t\tctx = gctx.WithSpan(ctx, \"test\")\n\t\tt.AssertNE(gctx.CtxId(ctx), \"\")\n\t\tt.Assert(ctx.Value(\"TEST\"), 1)\n\t})\n}\n\nfunc Test_SetInitCtx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tctx := context.WithValue(context.TODO(), \"TEST\", 1)\n\t\tgctx.SetInitCtx(ctx)\n\t\tt.AssertNE(gctx.GetInitCtx(), \"\")\n\t\tt.Assert(gctx.GetInitCtx().Value(\"TEST\"), 1)\n\t})\n}\n"
  },
  {
    "path": "os/genv/genv.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package genv provides operations for environment variables of system.\npackage genv\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// All returns a copy of strings representing the environment,\n// in the form \"key=value\".\nfunc All() []string {\n\treturn os.Environ()\n}\n\n// Map returns a copy of strings representing the environment as a map.\nfunc Map() map[string]string {\n\treturn MapFromEnv(os.Environ())\n}\n\n// Get creates and returns a Var with the value of the environment variable\n// named by the `key`. It uses the given `def` if the variable does not exist\n// in the environment.\nfunc Get(key string, def ...any) *gvar.Var {\n\tv, ok := os.LookupEnv(key)\n\tif !ok {\n\t\tif len(def) > 0 {\n\t\t\treturn gvar.New(def[0])\n\t\t}\n\t\treturn nil\n\t}\n\treturn gvar.New(v)\n}\n\n// Set sets the value of the environment variable named by the `key`.\n// It returns an error, if any.\nfunc Set(key, value string) (err error) {\n\terr = os.Setenv(key, value)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `set environment key-value failed with key \"%s\", value \"%s\"`, key, value)\n\t}\n\treturn\n}\n\n// SetMap sets the environment variables using map.\nfunc SetMap(m map[string]string) (err error) {\n\tfor k, v := range m {\n\t\tif err = Set(k, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Contains checks whether the environment variable named `key` exists.\nfunc Contains(key string) bool {\n\t_, ok := os.LookupEnv(key)\n\treturn ok\n}\n\n// Remove deletes one or more environment variables.\nfunc Remove(key ...string) (err error) {\n\tfor _, v := range key {\n\t\tif err = os.Unsetenv(v); err != nil {\n\t\t\terr = gerror.Wrapf(err, `delete environment key failed with key \"%s\"`, v)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// GetWithCmd returns the environment value specified `key`.\n// If the environment value does not exist, then it retrieves and returns the value from command line options.\n// It returns the default value `def` if none of them exists.\n//\n// Fetching Rules:\n// 1. Environment arguments are in uppercase format, eg: GF_<package name>_<variable name>；\n// 2. Command line arguments are in lowercase format, eg: gf.<package name>.<variable name>;\nfunc GetWithCmd(key string, def ...any) *gvar.Var {\n\tenvKey := utils.FormatEnvKey(key)\n\tif v := os.Getenv(envKey); v != \"\" {\n\t\treturn gvar.New(v)\n\t}\n\tcmdKey := utils.FormatCmdKey(key)\n\tif v := command.GetOpt(cmdKey); v != \"\" {\n\t\treturn gvar.New(v)\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0])\n\t}\n\treturn nil\n}\n\n// Build builds a map to an environment variable slice.\nfunc Build(m map[string]string) []string {\n\tarray := make([]string, len(m))\n\tindex := 0\n\tfor k, v := range m {\n\t\tarray[index] = k + \"=\" + v\n\t\tindex++\n\t}\n\treturn array\n}\n\n// MapFromEnv converts environment variables from slice to map.\nfunc MapFromEnv(envs []string) map[string]string {\n\tm := make(map[string]string)\n\ti := 0\n\tfor _, s := range envs {\n\t\ti = strings.IndexByte(s, '=')\n\t\tm[s[0:i]] = s[i+1:]\n\t}\n\treturn m\n}\n\n// MapToEnv converts environment variables from map to slice.\nfunc MapToEnv(m map[string]string) []string {\n\tenvs := make([]string, 0)\n\tfor k, v := range m {\n\t\tenvs = append(envs, fmt.Sprintf(`%s=%s`, k, v))\n\t}\n\treturn envs\n}\n\n// Filter filters repeated items from given environment variables.\nfunc Filter(envs []string) []string {\n\treturn MapToEnv(MapFromEnv(envs))\n}\n"
  },
  {
    "path": "os/genv/genv_must.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genv\n\n// MustSet performs as Set, but it panics if any error occurs.\nfunc MustSet(key, value string) {\n\tif err := Set(key, value); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustRemove performs as Remove, but it panics if any error occurs.\nfunc MustRemove(key ...string) {\n\tif err := Remove(key...); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "os/genv/genv_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage genv_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_GEnv_All(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(os.Environ(), genv.All())\n\t})\n}\n\nfunc Test_GEnv_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := os.Setenv(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(genv.Map()[key], \"TEST\")\n\t})\n}\n\nfunc Test_GEnv_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := os.Setenv(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(genv.Get(key).String(), \"TEST\")\n\t})\n}\n\nfunc Test_GEnv_GetVar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := os.Setenv(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(genv.Get(key).String(), \"TEST\")\n\t})\n}\n\nfunc Test_GEnv_Contains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := os.Setenv(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(genv.Contains(key), true)\n\t\tt.AssertEQ(genv.Contains(\"none\"), false)\n\t})\n}\n\nfunc Test_GEnv_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := genv.Set(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(os.Getenv(key), \"TEST\")\n\t})\n}\n\nfunc Test_GEnv_SetMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := genv.SetMap(g.MapStrStr{\n\t\t\t\"K1\": \"TEST1\",\n\t\t\t\"K2\": \"TEST2\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(os.Getenv(\"K1\"), \"TEST1\")\n\t\tt.AssertEQ(os.Getenv(\"K2\"), \"TEST2\")\n\t})\n}\n\nfunc Test_GEnv_Build(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := genv.Build(map[string]string{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.AssertIN(\"k1=v1\", s)\n\t\tt.AssertIN(\"k2=v2\", s)\n\t})\n}\n\nfunc Test_GEnv_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gconv.String(gtime.TimestampNano())\n\t\tkey := \"TEST_ENV_\" + value\n\t\terr := os.Setenv(key, \"TEST\")\n\t\tt.AssertNil(err)\n\t\terr = genv.Remove(key)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(os.Getenv(key), \"\")\n\t})\n}\n\nfunc Test_GetWithCmd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgcmd.Init(\"-test\", \"2\")\n\t\tt.Assert(genv.GetWithCmd(\"TEST\"), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgenv.Set(\"TEST\", \"1\")\n\t\tdefer genv.Remove(\"TEST\")\n\t\tgcmd.Init(\"-test\", \"2\")\n\t\tt.Assert(genv.GetWithCmd(\"test\"), 1)\n\t})\n}\n\nfunc Test_MapFromEnv(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := genv.MapFromEnv([]string{\"a=1\", \"b=2\"})\n\t\tt.Assert(m, g.Map{\"a\": 1, \"b\": 2})\n\t})\n}\n\nfunc Test_MapToEnv(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := genv.MapToEnv(g.MapStrStr{\"a\": \"1\"})\n\t\tt.Assert(s, []string{\"a=1\"})\n\t})\n}\n\nfunc Test_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := genv.Filter([]string{\"a=1\", \"a=3\"})\n\t\tt.Assert(s, []string{\"a=3\"})\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gfile provides easy-to-use operations for file system.\npackage gfile\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\t// Separator for file system.\n\t// It here defines the separator as variable\n\t// to allow it modified by developer if necessary.\n\tSeparator = string(filepath.Separator)\n\n\t// DefaultPermOpen is the default perm for file opening.\n\tDefaultPermOpen = os.FileMode(0666)\n\n\t// DefaultPermCopy is the default perm for file/folder copy.\n\tDefaultPermCopy = os.FileMode(0755)\n)\n\nvar (\n\t// The absolute file path for main package.\n\t// It can be only checked and set once.\n\tmainPkgPath = gtype.NewString()\n\n\t// selfPath is the current running binary path.\n\t// As it is most commonly used, it is so defined as an internal package variable.\n\tselfPath = \"\"\n)\n\nfunc init() {\n\t// Initialize internal package variable: selfPath.\n\tselfPath, _ = exec.LookPath(os.Args[0])\n\tif selfPath != \"\" {\n\t\tselfPath, _ = filepath.Abs(selfPath)\n\t}\n\tif selfPath == \"\" {\n\t\tselfPath, _ = filepath.Abs(os.Args[0])\n\t}\n}\n\n// Mkdir creates directories recursively with given `path`.\n// The parameter `path` is suggested to be an absolute path instead of relative one.\nfunc Mkdir(path string) (err error) {\n\tif err = os.MkdirAll(path, os.ModePerm); err != nil {\n\t\terr = gerror.Wrapf(err, `os.MkdirAll failed for path \"%s\" with perm \"%d\"`, path, os.ModePerm)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Create creates a file with given `path` recursively.\n// The parameter `path` is suggested to be absolute path.\nfunc Create(path string) (*os.File, error) {\n\tdir := Dir(path)\n\tif !Exists(dir) {\n\t\tif err := Mkdir(dir); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfile, err := os.Create(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Create failed for name \"%s\"`, path)\n\t}\n\treturn file, err\n}\n\n// Open opens file/directory READONLY.\nfunc Open(path string) (*os.File, error) {\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Open failed for name \"%s\"`, path)\n\t}\n\treturn file, err\n}\n\n// OpenFile opens file/directory with custom `flag` and `perm`.\n// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.\nfunc OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {\n\tfile, err := os.OpenFile(path, flag, perm)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.OpenFile failed with name \"%s\", flag \"%d\", perm \"%d\"`, path, flag, perm)\n\t}\n\treturn file, err\n}\n\n// OpenWithFlag opens file/directory with default perm and custom `flag`.\n// The default `perm` is 0666.\n// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.\nfunc OpenWithFlag(path string, flag int) (*os.File, error) {\n\tfile, err := OpenFile(path, flag, DefaultPermOpen)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn file, nil\n}\n\n// OpenWithFlagPerm opens file/directory with custom `flag` and `perm`.\n// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.\n// The parameter `perm` is like: 0600, 0666, 0777, etc.\nfunc OpenWithFlagPerm(path string, flag int, perm os.FileMode) (*os.File, error) {\n\tfile, err := OpenFile(path, flag, perm)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn file, nil\n}\n\n// Join joins string array paths with file separator of current system.\nfunc Join(paths ...string) string {\n\tvar s string\n\tfor _, path := range paths {\n\t\tif s != \"\" {\n\t\t\ts += Separator\n\t\t}\n\t\ts += gstr.TrimRight(path, Separator)\n\t}\n\treturn s\n}\n\n// Exists checks whether given `path` exist.\nfunc Exists(path string) bool {\n\tif stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsDir checks whether given `path` a directory.\n// Note that it returns false if the `path` does not exist.\nfunc IsDir(path string) bool {\n\ts, err := os.Stat(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn s.IsDir()\n}\n\n// Pwd returns absolute path of current working directory.\n// Note that it returns an empty string if retrieving current\n// working directory failed.\nfunc Pwd() string {\n\tpath, err := os.Getwd()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn path\n}\n\n// Chdir changes the current working directory to the named directory.\n// If there is an error, it will be of type *PathError.\nfunc Chdir(dir string) (err error) {\n\terr = os.Chdir(dir)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Chdir failed with dir \"%s\"`, dir)\n\t}\n\treturn\n}\n\n// IsFile checks whether given `path` a file, which means it's not a directory.\n// Note that it returns false if the `path` does not exist.\nfunc IsFile(path string) bool {\n\ts, err := Stat(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn !s.IsDir()\n}\n\n// Stat returns a FileInfo describing the named file.\n// If there is an error, it will be of type *PathError.\nfunc Stat(path string) (os.FileInfo, error) {\n\tinfo, err := os.Stat(path)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Stat failed for file \"%s\"`, path)\n\t}\n\treturn info, err\n}\n\n// Move renames (moves) `src` to `dst` path.\n// If `dst` already exists and is not a directory, it'll be replaced.\nfunc Move(src string, dst string) (err error) {\n\terr = os.Rename(src, dst)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Rename failed from \"%s\" to \"%s\"`, src, dst)\n\t}\n\treturn\n}\n\n// Rename is alias of Move.\n// See Move.\nfunc Rename(src string, dst string) error {\n\treturn Move(src, dst)\n}\n\n// DirNames returns sub-file names of given directory `path`.\n// Note that the returned names are NOT absolute paths.\nfunc DirNames(path string) ([]string, error) {\n\tf, err := Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlist, err := f.Readdirnames(-1)\n\t_ = f.Close()\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `Read dir files failed from path \"%s\"`, path)\n\t\treturn nil, err\n\t}\n\treturn list, nil\n}\n\n// Glob returns the names of all files matching pattern or nil\n// if there is no matching file. The syntax of patterns is the same\n// as in Match. The pattern may describe hierarchical names such as\n// /usr/*/bin/ed (assuming the Separator is '/').\n//\n// Glob ignores file system errors such as I/O errors reading directories.\n// The only possible returned error is ErrBadPattern, when pattern\n// is malformed.\nfunc Glob(pattern string, onlyNames ...bool) ([]string, error) {\n\tlist, err := filepath.Glob(pattern)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `filepath.Glob failed for pattern \"%s\"`, pattern)\n\t\treturn nil, err\n\t}\n\tif len(onlyNames) > 0 && onlyNames[0] && len(list) > 0 {\n\t\tarray := make([]string, len(list))\n\t\tfor k, v := range list {\n\t\t\tarray[k] = Basename(v)\n\t\t}\n\t\treturn array, nil\n\t}\n\treturn list, nil\n}\n\n// Remove deletes all file/directory with `path` parameter.\n// If parameter `path` is directory, it deletes it recursively.\n//\n// It does nothing if given `path` does not exist or is empty.\n//\n// Deprecated:\n// As the name Remove for files deleting is ambiguous,\n// please use RemoveFile or RemoveAll for explicit usage instead.\nfunc Remove(path string) (err error) {\n\t// It does nothing if `path` is empty.\n\tif path == \"\" {\n\t\treturn nil\n\t}\n\tif err = os.RemoveAll(path); err != nil {\n\t\terr = gerror.Wrapf(err, `os.RemoveAll failed for path \"%s\"`, path)\n\t}\n\treturn\n}\n\n// RemoveFile removes the named file or (empty) directory.\nfunc RemoveFile(path string) (err error) {\n\tif err = os.Remove(path); err != nil {\n\t\terr = gerror.Wrapf(err, `os.Remove failed for path \"%s\"`, path)\n\t}\n\treturn\n}\n\n// RemoveAll removes path and any children it contains.\n// It removes everything it can but returns the first error\n// it encounters. If the path does not exist, RemoveAll\n// returns nil (no error).\nfunc RemoveAll(path string) (err error) {\n\tif err = os.RemoveAll(path); err != nil {\n\t\terr = gerror.Wrapf(err, `os.RemoveAll failed for path \"%s\"`, path)\n\t}\n\treturn\n}\n\n// IsReadable checks whether given `path` is readable.\nfunc IsReadable(path string) bool {\n\tresult := true\n\tfile, err := os.OpenFile(path, os.O_RDONLY, DefaultPermOpen)\n\tif err != nil {\n\t\tresult = false\n\t}\n\tif file != nil {\n\t\t_ = file.Close()\n\t}\n\treturn result\n}\n\n// IsWritable checks whether given `path` is writable.\n//\n// TODO improve performance; use golang.org/x/sys to cross-plat-form\nfunc IsWritable(path string) bool {\n\tresult := true\n\tif IsDir(path) {\n\t\t// If it's a directory, create a temporary file to test whether it's writable.\n\t\ttmpFile := strings.TrimRight(path, Separator) + Separator + gconv.String(time.Now().UnixNano())\n\t\tif f, err := Create(tmpFile); err != nil || !Exists(tmpFile) {\n\t\t\tresult = false\n\t\t} else {\n\t\t\t_ = f.Close()\n\t\t\t_ = Remove(tmpFile)\n\t\t}\n\t} else {\n\t\t// If it's a file, check if it can open it.\n\t\tfile, err := os.OpenFile(path, os.O_WRONLY, DefaultPermOpen)\n\t\tif err != nil {\n\t\t\tresult = false\n\t\t}\n\t\tif file != nil {\n\t\t\t_ = file.Close()\n\t\t}\n\t}\n\treturn result\n}\n\n// Chmod is alias of os.Chmod.\n// See os.Chmod.\nfunc Chmod(path string, mode os.FileMode) (err error) {\n\terr = os.Chmod(path, mode)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Chmod failed with path \"%s\" and mode \"%s\"`, path, mode)\n\t}\n\treturn\n}\n\n// Abs returns an absolute representation of path.\n// If the path is not absolute it will be joined with the current\n// working directory to turn it into an absolute path. The absolute\n// path name for a given file is not guaranteed to be unique.\n// Abs calls Clean on the result.\nfunc Abs(path string) string {\n\tp, _ := filepath.Abs(path)\n\treturn p\n}\n\n// RealPath converts the given `path` to its absolute path\n// and checks if the file path exists.\n// If the file does not exist, return an empty string.\nfunc RealPath(path string) string {\n\tp, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif !Exists(p) {\n\t\treturn \"\"\n\t}\n\treturn p\n}\n\n// SelfPath returns absolute file path of current running process(binary).\nfunc SelfPath() string {\n\treturn selfPath\n}\n\n// SelfName returns file name of current running process(binary).\nfunc SelfName() string {\n\treturn Basename(SelfPath())\n}\n\n// SelfDir returns absolute directory path of current running process(binary).\nfunc SelfDir() string {\n\treturn filepath.Dir(SelfPath())\n}\n\n// Basename returns the last element of path, which contains file extension.\n// Trailing path separators are removed before extracting the last element.\n// If the path is empty, Base returns \".\".\n// If the path consists entirely of separators, Basename returns a single separator.\n//\n// Example:\n// Basename(\"/var/www/file.js\") -> file.js\n// Basename(\"file.js\")          -> file.js\nfunc Basename(path string) string {\n\treturn filepath.Base(path)\n}\n\n// Name returns the last element of path without file extension.\n//\n// Example:\n// Name(\"/var/www/file.js\") -> file\n// Name(\"file.js\")          -> file\nfunc Name(path string) string {\n\tbase := filepath.Base(path)\n\tif i := strings.LastIndexByte(base, '.'); i != -1 {\n\t\treturn base[:i]\n\t}\n\treturn base\n}\n\n// Dir returns all but the last element of path, typically the path's directory.\n// After dropping the final element, Dir calls Clean on the path and trailing\n// slashes are removed.\n// If the `path` is empty, Dir returns \".\".\n// If the `path` is \".\", Dir treats the path as current working directory.\n// If the `path` consists entirely of separators, Dir returns a single separator.\n// The returned path does not end in a separator unless it is the root directory.\n//\n// Example:\n// Dir(\"/var/www/file.js\") -> \"/var/www\"\n// Dir(\"file.js\")          -> \".\"\nfunc Dir(path string) string {\n\tif path == \".\" {\n\t\treturn filepath.Dir(RealPath(path))\n\t}\n\treturn filepath.Dir(path)\n}\n\n// IsEmpty checks whether the given `path` is empty.\n// If `path` is a folder, it checks if there's any file under it.\n// If `path` is a file, it checks if the file size is zero.\n//\n// Note that it returns true if `path` does not exist.\nfunc IsEmpty(path string) bool {\n\tstat, err := Stat(path)\n\tif err != nil {\n\t\treturn true\n\t}\n\tif stat.IsDir() {\n\t\tfile, err := os.Open(path)\n\t\tif err != nil {\n\t\t\treturn true\n\t\t}\n\t\tif file == nil {\n\t\t\treturn true\n\t\t}\n\t\tdefer file.Close()\n\t\tnames, err := file.Readdirnames(-1)\n\t\tif err != nil {\n\t\t\treturn true\n\t\t}\n\t\treturn len(names) == 0\n\t}\n\treturn stat.Size() == 0\n}\n\n// Ext returns the file name extension used by path.\n// The extension is the suffix beginning at the final dot\n// in the final element of path; it is empty if there is\n// no dot.\n// Note: the result contains symbol '.'.\n//\n// Example:\n// Ext(\"main.go\")  => .go\n// Ext(\"api.json\") => .json\nfunc Ext(path string) string {\n\text := filepath.Ext(path)\n\tif p := strings.IndexByte(ext, '?'); p != -1 {\n\t\text = ext[0:p]\n\t}\n\treturn ext\n}\n\n// ExtName is like function Ext, which returns the file name extension used by path,\n// but the result does not contain symbol '.'.\n//\n// Example:\n// ExtName(\"main.go\")  => go\n// ExtName(\"api.json\") => json\nfunc ExtName(path string) string {\n\treturn strings.TrimLeft(Ext(path), \".\")\n}\n\n// Temp retrieves and returns the temporary directory of current system.\n//\n// The optional parameter `names` specifies the sub-folders/sub-files,\n// which will be joined with current system separator and returned with the path.\nfunc Temp(names ...string) string {\n\tpath := os.TempDir()\n\tfor _, name := range names {\n\t\tpath = Join(path, name)\n\t}\n\treturn path\n}\n"
  },
  {
    "path": "os/gfile/gfile_cache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n)\n\nconst (\n\tdefaultCacheDuration  = \"1m\"             // defaultCacheExpire is the expire time for file content caching in seconds.\n\tcommandEnvKeyForCache = \"gf.gfile.cache\" // commandEnvKeyForCache is the configuration key for command argument or environment configuring cache expire duration.\n)\n\nvar (\n\t// Default expire time for file content caching.\n\tcacheDuration = getCacheDuration()\n\n\t// internalCache is the memory cache for internal usage.\n\tinternalCache = gcache.New()\n)\n\nfunc getCacheDuration() time.Duration {\n\tcacheDurationConfigured := command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheDuration)\n\td, err := time.ParseDuration(cacheDurationConfigured)\n\tif err != nil {\n\t\tpanic(gerror.WrapCodef(\n\t\t\tgcode.CodeInvalidConfiguration,\n\t\t\terr,\n\t\t\t`error parsing string \"%s\" to time duration`,\n\t\t\tcacheDurationConfigured,\n\t\t))\n\t}\n\treturn d\n}\n\n// GetContentsWithCache returns string content of given file by `path` from cache.\n// If there's no content in the cache, it will read it from disk file specified by `path`.\n// The parameter `expire` specifies the caching time for this file content in seconds.\nfunc GetContentsWithCache(path string, duration ...time.Duration) string {\n\treturn string(GetBytesWithCache(path, duration...))\n}\n\n// GetBytesWithCache returns []byte content of given file by `path` from cache.\n// If there's no content in the cache, it will read it from disk file specified by `path`.\n// The parameter `expire` specifies the caching time for this file content in seconds.\nfunc GetBytesWithCache(path string, duration ...time.Duration) []byte {\n\tvar (\n\t\tctx      = context.Background()\n\t\texpire   = cacheDuration\n\t\tcacheKey = commandEnvKeyForCache + path\n\t)\n\n\tif len(duration) > 0 {\n\t\texpire = duration[0]\n\t}\n\tr, _ := internalCache.GetOrSetFuncLock(ctx, cacheKey, func(ctx context.Context) (any, error) {\n\t\tb := GetBytes(path)\n\t\tif b != nil {\n\t\t\t// Adding this `path` to gfsnotify,\n\t\t\t// it will clear its cache if there's any changes of the file.\n\t\t\t_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {\n\t\t\t\t_, err := internalCache.Remove(ctx, cacheKey)\n\t\t\t\tif err != nil {\n\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t}\n\t\t\t\tgfsnotify.Exit()\n\t\t\t})\n\t\t}\n\t\treturn b, nil\n\t}, expire)\n\tif r != nil {\n\t\treturn r.Bytes()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gfile/gfile_contents.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\t// DefaultReadBuffer is the buffer size for reading file content.\n\tDefaultReadBuffer = 1024\n)\n\n// GetContents returns the file content of `path` as string.\n// It returns en empty string if it fails reading.\nfunc GetContents(path string) string {\n\treturn string(GetBytes(path))\n}\n\n// GetBytes returns the file content of `path` as []byte.\n// It returns nil if it fails reading.\nfunc GetBytes(path string) []byte {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil\n\t}\n\treturn data\n}\n\n// putContents puts binary content to file of `path`.\nfunc putContents(path string, data []byte, flag int, perm os.FileMode) error {\n\t// It supports creating file of `path` recursively.\n\tdir := Dir(path)\n\tif !Exists(dir) {\n\t\tif err := Mkdir(dir); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Opening file with given `flag` and `perm`.\n\tf, err := OpenWithFlagPerm(path, flag, perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\t// Write data.\n\tvar n int\n\tif n, err = f.Write(data); err != nil {\n\t\terr = gerror.Wrapf(err, `Write data to file \"%s\" failed`, path)\n\t\treturn err\n\t} else if n < len(data) {\n\t\treturn io.ErrShortWrite\n\t}\n\treturn nil\n}\n\n// Truncate truncates file of `path` to given size by `size`.\nfunc Truncate(path string, size int) (err error) {\n\terr = os.Truncate(path, int64(size))\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `os.Truncate failed for file \"%s\", size \"%d\"`, path, size)\n\t}\n\treturn\n}\n\n// PutContents puts string `content` to file of `path`.\n// It creates file of `path` recursively if it does not exist.\nfunc PutContents(path string, content string) error {\n\treturn putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)\n}\n\n// PutContentsAppend appends string `content` to file of `path`.\n// It creates file of `path` recursively if it does not exist.\nfunc PutContentsAppend(path string, content string) error {\n\treturn putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)\n}\n\n// PutBytes puts binary `content` to file of `path`.\n// It creates file of `path` recursively if it does not exist.\nfunc PutBytes(path string, content []byte) error {\n\treturn putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)\n}\n\n// PutBytesAppend appends binary `content` to file of `path`.\n// It creates file of `path` recursively if it does not exist.\nfunc PutBytesAppend(path string, content []byte) error {\n\treturn putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)\n}\n\n// GetNextCharOffset returns the file offset for given `char` starting from `start`.\nfunc GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {\n\tbuffer := make([]byte, DefaultReadBuffer)\n\toffset := start\n\tfor {\n\t\tif n, err := reader.ReadAt(buffer, offset); n > 0 {\n\t\t\tfor i := 0; i < n; i++ {\n\t\t\t\tif buffer[i] == char {\n\t\t\t\t\treturn int64(i) + offset\n\t\t\t\t}\n\t\t\t}\n\t\t\toffset += int64(n)\n\t\t} else if err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn -1\n}\n\n// GetNextCharOffsetByPath returns the file offset for given `char` starting from `start`.\n// It opens file of `path` for reading with os.O_RDONLY flag and default perm.\nfunc GetNextCharOffsetByPath(path string, char byte, start int64) int64 {\n\tif f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {\n\t\tdefer f.Close()\n\t\treturn GetNextCharOffset(f, char, start)\n\t}\n\treturn -1\n}\n\n// GetBytesTilChar returns the contents of the file as []byte\n// until the next specified byte `char` position.\n//\n// Note: Returned value contains the character of the last position.\nfunc GetBytesTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {\n\tif offset := GetNextCharOffset(reader, char, start); offset != -1 {\n\t\treturn GetBytesByTwoOffsets(reader, start, offset+1), offset\n\t}\n\treturn nil, -1\n}\n\n// GetBytesTilCharByPath returns the contents of the file given by `path` as []byte\n// until the next specified byte `char` position.\n// It opens file of `path` for reading with os.O_RDONLY flag and default perm.\n//\n// Note: Returned value contains the character of the last position.\nfunc GetBytesTilCharByPath(path string, char byte, start int64) ([]byte, int64) {\n\tif f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {\n\t\tdefer f.Close()\n\t\treturn GetBytesTilChar(f, char, start)\n\t}\n\treturn nil, -1\n}\n\n// GetBytesByTwoOffsets returns the binary content as []byte from `start` to `end`.\n// Note: Returned value does not contain the character of the last position, which means\n// it returns content range as [start, end).\nfunc GetBytesByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {\n\tbuffer := make([]byte, end-start)\n\tif _, err := reader.ReadAt(buffer, start); err != nil {\n\t\treturn nil\n\t}\n\treturn buffer\n}\n\n// GetBytesByTwoOffsetsByPath returns the binary content as []byte from `start` to `end`.\n// Note: Returned value does not contain the character of the last position, which means\n// it returns content range as [start, end).\n// It opens file of `path` for reading with os.O_RDONLY flag and default perm.\nfunc GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte {\n\tif f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {\n\t\tdefer f.Close()\n\t\treturn GetBytesByTwoOffsets(f, start, end)\n\t}\n\treturn nil\n}\n\n// ReadLines reads file content line by line, which is passed to the callback function `callback` as string.\n// It matches each line of text, separated by chars '\\r' or '\\n', stripped any trailing end-of-line marker.\n//\n// Note that the parameter passed to callback function might be an empty value, and the last non-empty line\n// will be passed to callback function `callback` even if it has no newline marker.\nfunc ReadLines(file string, callback func(line string) error) error {\n\tf, err := Open(file)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tif err = callback(scanner.Text()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ReadLinesBytes reads file content line by line, which is passed to the callback function `callback` as []byte.\n// It matches each line of text, separated by chars '\\r' or '\\n', stripped any trailing end-of-line marker.\n//\n// Note that the parameter passed to callback function might be an empty value, and the last non-empty line\n// will be passed to callback function `callback` even if it has no newline marker.\nfunc ReadLinesBytes(file string, callback func(bytes []byte) error) error {\n\tf, err := Open(file)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tif err = callback(scanner.Bytes()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gfile/gfile_copy.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// CopyOption is the option for Copy* functions.\ntype CopyOption struct {\n\t// Auto call file sync after source file content copied to target file.\n\tSync bool\n\n\t// Preserve the mode of the original file to the target file.\n\t// If true, the Mode attribute will make no sense.\n\tPreserveMode bool\n\n\t// Destination created file mode.\n\t// The default file mode is DefaultPermCopy if PreserveMode is false.\n\tMode os.FileMode\n}\n\n// Copy file/directory from `src` to `dst`.\n//\n// If `src` is file, it calls CopyFile to implements copy feature,\n// or else it calls CopyDir.\n//\n// If `src` is file, but `dst` already exists and is a folder,\n// it then creates a same name file of `src` in folder `dst`.\n//\n// Eg:\n// Copy(\"/tmp/file1\", \"/tmp/file2\") => /tmp/file1 copied to /tmp/file2\n// Copy(\"/tmp/dir1\",  \"/tmp/dir2\")  => /tmp/dir1  copied to /tmp/dir2\n// Copy(\"/tmp/file1\", \"/tmp/dir2\")  => /tmp/file1 copied to /tmp/dir2/file1\n// Copy(\"/tmp/dir1\",  \"/tmp/file2\") => error\nfunc Copy(src string, dst string, option ...CopyOption) error {\n\tif src == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"source path cannot be empty\")\n\t}\n\tif dst == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"destination path cannot be empty\")\n\t}\n\tsrcStat, srcStatErr := os.Stat(src)\n\tif srcStatErr != nil {\n\t\tif os.IsNotExist(srcStatErr) {\n\t\t\treturn gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\tsrcStatErr,\n\t\t\t\t`the src path \"%s\" does not exist`,\n\t\t\t\tsrc,\n\t\t\t)\n\t\t}\n\t\treturn gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError, srcStatErr, `call os.Stat on \"%s\" failed`, src,\n\t\t)\n\t}\n\tdstStat, dstStatErr := os.Stat(dst)\n\tif dstStatErr != nil && !os.IsNotExist(dstStatErr) {\n\t\treturn gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError, dstStatErr, `call os.Stat on \"%s\" failed`, dst)\n\t}\n\n\tif IsFile(src) {\n\t\tvar isDstExist = false\n\t\tif dstStat != nil && !os.IsNotExist(dstStatErr) {\n\t\t\tisDstExist = true\n\t\t}\n\t\tif isDstExist && dstStat.IsDir() {\n\t\t\tvar (\n\t\t\t\tsrcName = Basename(src)\n\t\t\t\tdstPath = Join(dst, srcName)\n\t\t\t)\n\t\t\treturn CopyFile(src, dstPath, option...)\n\t\t}\n\t\treturn CopyFile(src, dst, option...)\n\t}\n\tif !srcStat.IsDir() && dstStat != nil && dstStat.IsDir() {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`Copy failed: the src path \"%s\" is file, but the dst path \"%s\" is folder`,\n\t\t\tsrc, dst,\n\t\t)\n\t}\n\treturn CopyDir(src, dst, option...)\n}\n\n// CopyFile copies the contents of the file named `src` to the file named\n// by `dst`. The file will be created if it does not exist. If the\n// destination file exists, all it's contents will be replaced by the contents\n// of the source file. The file mode will be copied from the source and\n// the copied data is synced/flushed to stable storage.\n// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04\nfunc CopyFile(src, dst string, option ...CopyOption) (err error) {\n\tvar usedOption = getCopyOption(option...)\n\tif src == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"source file cannot be empty\")\n\t}\n\tif dst == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"destination file cannot be empty\")\n\t}\n\t// If src and dst are the same path, it does nothing.\n\tif src == dst {\n\t\treturn nil\n\t}\n\t// file state check.\n\tsrcStat, srcStatErr := os.Stat(src)\n\tif srcStatErr != nil {\n\t\tif os.IsNotExist(srcStatErr) {\n\t\t\treturn gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\tsrcStatErr,\n\t\t\t\t`the src path \"%s\" does not exist`,\n\t\t\t\tsrc,\n\t\t\t)\n\t\t}\n\t\treturn gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError, srcStatErr, `call os.Stat on \"%s\" failed`, src,\n\t\t)\n\t}\n\tdstStat, dstStatErr := os.Stat(dst)\n\tif dstStatErr != nil && !os.IsNotExist(dstStatErr) {\n\t\treturn gerror.WrapCodef(\n\t\t\tgcode.CodeInternalError, dstStatErr, `call os.Stat on \"%s\" failed`, dst,\n\t\t)\n\t}\n\tif !srcStat.IsDir() && dstStat != nil && dstStat.IsDir() {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`CopyFile failed: the src path \"%s\" is file, but the dst path \"%s\" is folder`,\n\t\t\tsrc, dst,\n\t\t)\n\t}\n\t// copy file logic.\n\tvar inFile *os.File\n\tinFile, err = Open(src)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer func() {\n\t\tif e := inFile.Close(); e != nil {\n\t\t\terr = gerror.Wrapf(e, `file close failed for \"%s\"`, src)\n\t\t}\n\t}()\n\tvar outFile *os.File\n\toutFile, err = Create(dst)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer func() {\n\t\tif e := outFile.Close(); e != nil {\n\t\t\terr = gerror.Wrapf(e, `file close failed for \"%s\"`, dst)\n\t\t}\n\t}()\n\tif _, err = io.Copy(outFile, inFile); err != nil {\n\t\terr = gerror.Wrapf(err, `io.Copy failed from \"%s\" to \"%s\"`, src, dst)\n\t\treturn\n\t}\n\tif usedOption.Sync {\n\t\tif err = outFile.Sync(); err != nil {\n\t\t\terr = gerror.Wrapf(err, `file sync failed for file \"%s\"`, dst)\n\t\t\treturn\n\t\t}\n\t}\n\tif usedOption.PreserveMode {\n\t\tusedOption.Mode = srcStat.Mode().Perm()\n\t}\n\tif err = Chmod(dst, usedOption.Mode); err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\n// CopyDir recursively copies a directory tree, attempting to preserve permissions.\n//\n// Note that, the Source directory must exist and symlinks are ignored and skipped.\nfunc CopyDir(src string, dst string, option ...CopyOption) (err error) {\n\tvar usedOption = getCopyOption(option...)\n\tif src == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"source directory cannot be empty\")\n\t}\n\tif dst == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"destination directory cannot be empty\")\n\t}\n\t// If src and dst are the same path, it does nothing.\n\tif src == dst {\n\t\treturn nil\n\t}\n\tsrc = filepath.Clean(src)\n\tdst = filepath.Clean(dst)\n\tsi, err := Stat(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !si.IsDir() {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"source is not a directory\")\n\t}\n\tif usedOption.PreserveMode {\n\t\tusedOption.Mode = si.Mode().Perm()\n\t}\n\tif !Exists(dst) {\n\t\tif err = os.MkdirAll(dst, usedOption.Mode); err != nil {\n\t\t\terr = gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`create directory failed for path \"%s\", perm \"%s\"`,\n\t\t\t\tdst,\n\t\t\t\tusedOption.Mode,\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t}\n\tentries, err := os.ReadDir(src)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `read directory failed for path \"%s\"`, src)\n\t\treturn\n\t}\n\tfor _, entry := range entries {\n\t\tsrcPath := filepath.Join(src, entry.Name())\n\t\tdstPath := filepath.Join(dst, entry.Name())\n\t\tif entry.IsDir() {\n\t\t\tif err = CopyDir(srcPath, dstPath); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\t// Skip symlinks.\n\t\t\tif entry.Type()&os.ModeSymlink != 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err = CopyFile(srcPath, dstPath, option...); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc getCopyOption(option ...CopyOption) CopyOption {\n\tvar usedOption CopyOption\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tif usedOption.Mode == 0 {\n\t\tusedOption.Mode = DefaultPermCopy\n\t}\n\treturn usedOption\n}\n"
  },
  {
    "path": "os/gfile/gfile_home.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Home returns absolute path of current user's home directory.\n// The optional parameter `names` specifies the sub-folders/sub-files,\n// which will be joined with current system separator and returned with the path.\nfunc Home(names ...string) (string, error) {\n\tpath, err := getHomePath()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tfor _, name := range names {\n\t\tpath += Separator + name\n\t}\n\treturn path, nil\n}\n\n// getHomePath returns absolute path of current user's home directory.\nfunc getHomePath() (string, error) {\n\tu, err := user.Current()\n\tif nil == err {\n\t\treturn u.HomeDir, nil\n\t}\n\tif runtime.GOOS == \"windows\" {\n\t\treturn homeWindows()\n\t}\n\treturn homeUnix()\n}\n\n// homeUnix retrieves and returns the home on unix system.\nfunc homeUnix() (string, error) {\n\tif home := os.Getenv(\"HOME\"); home != \"\" {\n\t\treturn home, nil\n\t}\n\tvar stdout bytes.Buffer\n\tcmd := exec.Command(\"sh\", \"-c\", \"eval echo ~$USER\")\n\tcmd.Stdout = &stdout\n\tif err := cmd.Run(); err != nil {\n\t\terr = gerror.Wrapf(err, `retrieve home directory failed`)\n\t\treturn \"\", err\n\t}\n\n\tresult := strings.TrimSpace(stdout.String())\n\tif result == \"\" {\n\t\treturn \"\", gerror.New(\"blank output when reading home directory\")\n\t}\n\n\treturn result, nil\n}\n\n// homeWindows retrieves and returns the home on windows system.\nfunc homeWindows() (string, error) {\n\tvar (\n\t\tdrive = os.Getenv(\"HOMEDRIVE\")\n\t\tpath  = os.Getenv(\"HOMEPATH\")\n\t\thome  = drive + path\n\t)\n\tif drive == \"\" || path == \"\" {\n\t\thome = os.Getenv(\"USERPROFILE\")\n\t}\n\tif home == \"\" {\n\t\treturn \"\", gerror.New(\"environment keys HOMEDRIVE, HOMEPATH and USERPROFILE are empty\")\n\t}\n\n\treturn home, nil\n}\n"
  },
  {
    "path": "os/gfile/gfile_match.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// MatchGlob reports whether name matches the shell pattern.\n// It extends filepath.Match (https://pkg.go.dev/path/filepath#Match)\n// with support for \"**\" (globstar) pattern, similar to bash's globstar\n// (https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html)\n// and gitignore patterns (https://git-scm.com/docs/gitignore#_pattern_format).\n//\n// Pattern syntax:\n//   - '*'         matches any sequence of non-separator characters\n//   - '**'        matches any sequence of characters including separators (globstar)\n//   - '?'         matches any single non-separator character\n//   - '[abc]'     matches any character in the bracket\n//   - '[a-z]'     matches any character in the range\n//   - '[^abc]'    matches any character not in the bracket (negation)\n//   - '[^a-z]'    matches any character not in the range (negation)\n//\n// Globstar rules:\n//   - \"**\" only has globstar semantics when it appears as a complete path component\n//     (e.g., \"a/**/b\", \"**/a\", \"a/**\", \"**\").\n//   - Patterns like \"a**b\" or \"**a\" treat \"**\" as two regular \"*\" wildcards,\n//     matching only within a single path component.\n//   - Both \"/\" and \"\\\" are treated as path separators (cross-platform support).\n//\n// Error handling:\n//   - Returns an error for malformed patterns (e.g., unclosed brackets \"[abc\").\n//   - Errors from filepath.Match are propagated.\n//\n// Example:\n//\n//\tMatchGlob(\"src/**/*.go\", \"src/foo/bar/main.go\")  => true, nil\n//\tMatchGlob(\"*.go\", \"main.go\")                     => true, nil\n//\tMatchGlob(\"**\", \"any/path/file.go\")              => true, nil\n//\tMatchGlob(\"a**b\", \"axxb\")                        => true, nil  (** as two *)\n//\tMatchGlob(\"a**b\", \"a/b\")                         => false, nil (no separator match)\n//\tMatchGlob(\"[abc]\", \"a\")                          => true, nil\n//\tMatchGlob(\"[\", \"a\")                              => false, error (malformed)\nfunc MatchGlob(pattern, name string) (bool, error) {\n\t// If no **, use standard filepath.Match\n\tif !strings.Contains(pattern, \"**\") {\n\t\treturn filepath.Match(pattern, name)\n\t}\n\treturn matchGlobstar(pattern, name)\n}\n\n// matchGlobstar handles patterns containing \"**\".\nfunc matchGlobstar(pattern, name string) (bool, error) {\n\t// Normalize path separators to / (handle both Windows and Unix)\n\tpattern = strings.ReplaceAll(pattern, \"\\\\\", \"/\")\n\tname = strings.ReplaceAll(name, \"\\\\\", \"/\")\n\n\t// Clean up paths (handles multiple slashes, . and ..)\n\t// Using path.Clean for consistent cross-platform behavior with forward slashes\n\tpattern = path.Clean(pattern)\n\tname = path.Clean(name)\n\n\t// Check if \"**\" appears as a valid globstar (complete path component).\n\t// If not, treat \"**\" as two regular \"*\" wildcards.\n\tif !hasValidGlobstar(pattern) {\n\t\t// Replace \"**\" with a placeholder, then use filepath.Match\n\t\t// Since filepath.Match treats \"*\" as matching non-separator chars,\n\t\t// \"**\" is equivalent to \"*\" in terms of matching (both match any\n\t\t// sequence of non-separator characters).\n\t\tnormalizedPattern := strings.ReplaceAll(pattern, \"**\", \"*\")\n\t\treturn filepath.Match(normalizedPattern, name)\n\t}\n\n\treturn doMatchGlobstar(pattern, name)\n}\n\n// hasValidGlobstar checks if the pattern contains \"**\" as a valid globstar\n// (i.e., as a complete path component). Valid globstar patterns:\n//   - \"**\" (the entire pattern)\n//   - \"**/\" (at the start)\n//   - \"/**\" (at the end)\n//   - \"/**/\" (in the middle)\nfunc hasValidGlobstar(pattern string) bool {\n\t// Check each occurrence of \"**\"\n\tidx := 0\n\tfor {\n\t\tpos := strings.Index(pattern[idx:], \"**\")\n\t\tif pos == -1 {\n\t\t\treturn false\n\t\t}\n\t\tpos += idx\n\n\t\t// Check if this \"**\" is a valid globstar\n\t\tif isValidGlobstarAt(pattern, pos) {\n\t\t\treturn true\n\t\t}\n\n\t\tidx = pos + 2\n\t\tif idx >= len(pattern) {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn false\n}\n\n// isValidGlobstarAt checks if the \"**\" at position pos is a valid globstar.\n// A valid globstar must be a complete path component:\n//   - At start: \"**\" or \"**/\"\n//   - At end: \"/**\"\n//   - In middle: \"/**/\"\nfunc isValidGlobstarAt(pattern string, pos int) bool {\n\t// Check character before \"**\"\n\tif pos > 0 && pattern[pos-1] != '/' {\n\t\treturn false\n\t}\n\n\t// Check character after \"**\"\n\tendPos := pos + 2\n\tif endPos < len(pattern) && pattern[endPos] != '/' {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// findValidGlobstar finds the first valid globstar in the pattern.\n// Returns the position or -1 if not found.\nfunc findValidGlobstar(pattern string) int {\n\tidx := 0\n\tfor {\n\t\tpos := strings.Index(pattern[idx:], \"**\")\n\t\tif pos == -1 {\n\t\t\treturn -1\n\t\t}\n\t\tpos += idx\n\n\t\tif isValidGlobstarAt(pattern, pos) {\n\t\t\treturn pos\n\t\t}\n\n\t\tidx = pos + 2\n\t\tif idx >= len(pattern) {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn -1\n}\n\n// doMatchGlobstar recursively matches pattern with globstar support.\n// Uses memoization to avoid exponential time complexity with multiple \"**\" operators.\nfunc doMatchGlobstar(pattern, name string) (bool, error) {\n\tmemo := make(map[string]bool)\n\treturn doMatchGlobstarMemo(pattern, name, memo)\n}\n\n// doMatchGlobstarMemo is the memoized implementation of globstar matching.\nfunc doMatchGlobstarMemo(pattern, name string, memo map[string]bool) (bool, error) {\n\t// Create cache key\n\tcacheKey := pattern + \"\\x00\" + name\n\tif cached, ok := memo[cacheKey]; ok {\n\t\treturn cached, nil\n\t}\n\n\tresult, err := doMatchGlobstarCore(pattern, name, memo)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tmemo[cacheKey] = result\n\treturn result, nil\n}\n\n// doMatchGlobstarCore contains the core matching logic.\nfunc doMatchGlobstarCore(pattern, name string, memo map[string]bool) (bool, error) {\n\t// Find the first valid globstar\n\tpos := findValidGlobstar(pattern)\n\tif pos == -1 {\n\t\t// No valid globstar, use standard match\n\t\t// Replace any \"**\" with \"*\" since they're not valid globstars\n\t\tnormalizedPattern := strings.ReplaceAll(pattern, \"**\", \"*\")\n\t\treturn filepath.Match(normalizedPattern, name)\n\t}\n\n\t// Split pattern at the valid globstar position\n\tprefix := pattern[:pos]\n\tsuffix := pattern[pos+2:]\n\n\t// Remove trailing slash from prefix\n\tprefix = strings.TrimSuffix(prefix, \"/\")\n\t// Remove leading slash from suffix\n\tsuffix = strings.TrimPrefix(suffix, \"/\")\n\n\t// Match prefix\n\tif prefix != \"\" {\n\t\t// Check if name starts with prefix pattern\n\t\tif !strings.Contains(prefix, \"*\") && !strings.Contains(prefix, \"?\") && !strings.Contains(prefix, \"[\") {\n\t\t\t// Prefix is literal, check directly against full path component\n\t\t\tif !strings.HasPrefix(name, prefix) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t\tif len(name) == len(prefix) {\n\t\t\t\t// Name is exactly the prefix\n\t\t\t\tname = \"\"\n\t\t\t} else {\n\t\t\t\t// Ensure the prefix ends at a path separator boundary\n\t\t\t\tif name[len(prefix)] != '/' {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t\t// Skip the separator as well\n\t\t\t\tname = name[len(prefix)+1:]\n\t\t\t}\n\t\t} else {\n\t\t\t// Prefix contains wildcards, need to match each segment\n\t\t\tprefixParts := strings.Split(prefix, \"/\")\n\t\t\tnameParts := strings.Split(name, \"/\")\n\n\t\t\tif len(nameParts) < len(prefixParts) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tfor i, pp := range prefixParts {\n\t\t\t\tmatched, err := filepath.Match(pp, nameParts[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false, err\n\t\t\t\t}\n\t\t\t\tif !matched {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tname = strings.Join(nameParts[len(prefixParts):], \"/\")\n\t\t}\n\t}\n\n\t// If suffix is empty, \"**\" matches everything remaining\n\tif suffix == \"\" {\n\t\treturn true, nil\n\t}\n\n\t// Try matching \"**\" with 0 to N path segments\n\tif name == \"\" {\n\t\t// No remaining name, check if suffix can match empty\n\t\treturn doMatchGlobstarMemo(suffix, \"\", memo)\n\t}\n\n\tnameParts := strings.Split(name, \"/\")\n\n\t// Try \"**\" matching 0, 1, 2, ... N segments\n\tfor i := 0; i <= len(nameParts); i++ {\n\t\tremaining := strings.Join(nameParts[i:], \"/\")\n\t\tmatched, err := doMatchGlobstarMemo(suffix, remaining, memo)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif matched {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, nil\n}\n"
  },
  {
    "path": "os/gfile/gfile_replace.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// ReplaceFile replaces content for file `path`.\nfunc ReplaceFile(search, replace, path string) error {\n\treturn PutContents(path, gstr.Replace(GetContents(path), search, replace))\n}\n\n// ReplaceFileFunc replaces content for file `path` with callback function `f`.\nfunc ReplaceFileFunc(f func(path, content string) string, path string) error {\n\tdata := GetContents(path)\n\tresult := f(path, data)\n\tif len(data) != len(result) || data != result {\n\t\treturn PutContents(path, result)\n\t}\n\treturn nil\n}\n\n// ReplaceDir replaces content for files under `path`.\n// The parameter `pattern` specifies the file pattern which matches to be replaced.\n// It does replacement recursively if given parameter `recursive` is true.\nfunc ReplaceDir(search, replace, path, pattern string, recursive ...bool) error {\n\tfiles, err := ScanDirFile(path, pattern, recursive...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, file := range files {\n\t\tif err = ReplaceFile(search, replace, file); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn err\n}\n\n// ReplaceDirFunc replaces content for files under `path` with callback function `f`.\n// The parameter `pattern` specifies the file pattern which matches to be replaced.\n// It does replacement recursively if given parameter `recursive` is true.\nfunc ReplaceDirFunc(f func(path, content string) string, path, pattern string, recursive ...bool) error {\n\tfiles, err := ScanDirFile(path, pattern, recursive...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, file := range files {\n\t\tif err = ReplaceFileFunc(f, file); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "os/gfile/gfile_scan.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"path/filepath\"\n\t\"sort\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nconst (\n\t// Max recursive depth for directory scanning.\n\tmaxScanDepth = 100000\n)\n\n// ScanDir returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\nfunc ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {\n\tisRecursive := false\n\tif len(recursive) > 0 {\n\t\tisRecursive = recursive[0]\n\t}\n\tlist, err := doScanDir(0, path, pattern, isRecursive, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\tsort.Strings(list)\n\t}\n\treturn list, nil\n}\n\n// ScanDirFunc returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// The pattern parameter `pattern` supports multiple file name patterns, using the ','\n// symbol to separate multiple patterns.\n//\n// The parameter `recursive` specifies whether scanning the `path` recursively, which\n// means it scans its sub-files and appends the files path to result array if the sub-file\n// is also a folder. It is false in default.\n//\n// The parameter `handler` specifies the callback function handling each sub-file path of\n// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty\n// string, or else it appends the sub-file path to result slice.\nfunc ScanDirFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {\n\tlist, err := doScanDir(0, path, pattern, recursive, handler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\tsort.Strings(list)\n\t}\n\treturn list, nil\n}\n\n// ScanDirFile returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\n//\n// Note that it returns only files, exclusive of directories.\nfunc ScanDirFile(path string, pattern string, recursive ...bool) ([]string, error) {\n\tisRecursive := false\n\tif len(recursive) > 0 {\n\t\tisRecursive = recursive[0]\n\t}\n\tlist, err := doScanDir(0, path, pattern, isRecursive, func(path string) string {\n\t\tif IsDir(path) {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn path\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\tsort.Strings(list)\n\t}\n\treturn list, nil\n}\n\n// ScanDirFileFunc returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// The pattern parameter `pattern` supports multiple file name patterns, using the ','\n// symbol to separate multiple patterns.\n//\n// The parameter `recursive` specifies whether scanning the `path` recursively, which\n// means it scans its sub-files and appends the file paths to result array if the sub-file\n// is also a folder. It is false in default.\n//\n// The parameter `handler` specifies the callback function handling each sub-file path of\n// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty\n// string, or else it appends the sub-file path to result slice.\n//\n// Note that the parameter `path` for `handler` is not a directory but a file.\n// It returns only files, exclusive of directories.\nfunc ScanDirFileFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {\n\tlist, err := doScanDir(0, path, pattern, recursive, func(path string) string {\n\t\tif IsDir(path) {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn handler(path)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\tsort.Strings(list)\n\t}\n\treturn list, nil\n}\n\n// doScanDir is an internal method which scans directory and returns the absolute path\n// list of files that are not sorted.\n//\n// The pattern parameter `pattern` supports multiple file name patterns, using the ','\n// symbol to separate multiple patterns.\n//\n// The parameter `recursive` specifies whether scanning the `path` recursively, which\n// means it scans its sub-files and appends the files path to result array if the sub-file\n// is also a folder. It is false in default.\n//\n// The parameter `handler` specifies the callback function handling each sub-file path of\n// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty\n// string, or else it appends the sub-file path to result slice.\nfunc doScanDir(depth int, path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {\n\tif depth >= maxScanDepth {\n\t\treturn nil, gerror.Newf(\"directory scanning exceeds max recursive depth: %d\", maxScanDepth)\n\t}\n\tvar (\n\t\tlist      []string\n\t\tfile, err = Open(path)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\tnames, err := file.Readdirnames(-1)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `read directory files failed from path \"%s\"`, path)\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tfilePath string\n\t\tpatterns = gstr.SplitAndTrim(pattern, \",\")\n\t)\n\tfor _, name := range names {\n\t\tfilePath = path + Separator + name\n\t\tif IsDir(filePath) && recursive {\n\t\t\tarray, _ := doScanDir(depth+1, filePath, pattern, true, handler)\n\t\t\tif len(array) > 0 {\n\t\t\t\tlist = append(list, array...)\n\t\t\t}\n\t\t}\n\t\t// Handler filtering.\n\t\tif handler != nil {\n\t\t\tfilePath = handler(filePath)\n\t\t\tif filePath == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\t// If it meets pattern, then add it to the result list.\n\t\tfor _, p := range patterns {\n\t\t\tif match, _ := filepath.Match(p, name); match {\n\t\t\t\tif filePath = Abs(filePath); filePath != \"\" {\n\t\t\t\t\tlist = append(list, filePath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn list, nil\n}\n"
  },
  {
    "path": "os/gfile/gfile_search.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Search searches file by name `name` in following paths with priority:\n// prioritySearchPaths, Pwd()、SelfDir()、MainPkgPath().\n// It returns the absolute file path of `name` if found, or en empty string if not found.\nfunc Search(name string, prioritySearchPaths ...string) (realPath string, err error) {\n\t// Check if it's an absolute path.\n\trealPath = RealPath(name)\n\tif realPath != \"\" {\n\t\treturn\n\t}\n\t// Search paths array.\n\tarray := garray.NewStrArray()\n\tarray.Append(prioritySearchPaths...)\n\tarray.Append(Pwd(), SelfDir())\n\tif path := MainPkgPath(); path != \"\" {\n\t\tarray.Append(path)\n\t}\n\t// Remove repeated items.\n\tarray.Unique()\n\t// Do the searching.\n\tarray.RLockFunc(func(array []string) {\n\t\tpath := \"\"\n\t\tfor _, v := range array {\n\t\t\tpath = RealPath(v + Separator + name)\n\t\t\tif path != \"\" {\n\t\t\t\trealPath = path\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t})\n\t// If it fails searching, it returns formatted error.\n\tif realPath == \"\" {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tfmt.Fprintf(buffer, `cannot find \"%s\" in following paths:`, name)\n\t\tarray.RLockFunc(func(array []string) {\n\t\t\tfor k, v := range array {\n\t\t\t\tfmt.Fprintf(buffer, \"\\n%d. %s\", k+1, v)\n\t\t\t}\n\t\t})\n\t\terr = gerror.New(buffer.String())\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gfile/gfile_size.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Size returns the size of file specified by `path` in byte.\nfunc Size(path string) int64 {\n\ts, e := os.Stat(path)\n\tif e != nil {\n\t\treturn 0\n\t}\n\treturn s.Size()\n}\n\n// SizeFormat returns the size of file specified by `path` in format string.\nfunc SizeFormat(path string) string {\n\treturn FormatSize(Size(path))\n}\n\n// ReadableSize formats size of file given by `path`, for more human readable.\nfunc ReadableSize(path string) string {\n\treturn FormatSize(Size(path))\n}\n\n// StrToSize converts formatted size string to its size in bytes.\nfunc StrToSize(sizeStr string) int64 {\n\ti := 0\n\tfor ; i < len(sizeStr); i++ {\n\t\tif sizeStr[i] == '.' || (sizeStr[i] >= '0' && sizeStr[i] <= '9') {\n\t\t\tcontinue\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tvar (\n\t\tunit      = sizeStr[i:]\n\t\tnumber, _ = strconv.ParseFloat(sizeStr[:i], 64)\n\t)\n\tif unit == \"\" {\n\t\treturn int64(number)\n\t}\n\tswitch strings.ToLower(unit) {\n\tcase \"b\", \"bytes\":\n\t\treturn int64(number)\n\tcase \"k\", \"kb\", \"ki\", \"kib\", \"kilobyte\":\n\t\treturn int64(number * 1024)\n\tcase \"m\", \"mb\", \"mi\", \"mib\", \"mebibyte\":\n\t\treturn int64(number * 1024 * 1024)\n\tcase \"g\", \"gb\", \"gi\", \"gib\", \"gigabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024)\n\tcase \"t\", \"tb\", \"ti\", \"tib\", \"terabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024)\n\tcase \"p\", \"pb\", \"pi\", \"pib\", \"petabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024 * 1024)\n\tcase \"e\", \"eb\", \"ei\", \"eib\", \"exabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)\n\tcase \"z\", \"zb\", \"zi\", \"zib\", \"zettabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)\n\tcase \"y\", \"yb\", \"yi\", \"yib\", \"yottabyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)\n\tcase \"bb\", \"brontobyte\":\n\t\treturn int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)\n\t}\n\treturn -1\n}\n\n// FormatSize formats size `raw` for more manually readable.\nfunc FormatSize(raw int64) string {\n\tvar (\n\t\tr         = float64(raw)\n\t\tt float64 = 1024\n\t\td float64 = 1\n\t)\n\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fB\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fK\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fM\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fG\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fT\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fP\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fE\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fZ\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fY\", r/d)\n\t}\n\td *= 1024\n\tt *= 1024\n\tif r < t {\n\t\treturn fmt.Sprintf(\"%.2fBB\", r/d)\n\t}\n\treturn \"TooLarge\"\n}\n"
  },
  {
    "path": "os/gfile/gfile_sort.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n)\n\n// fileSortFunc is the comparison function for files.\n// It sorts the array in order of: directory -> file.\n// If `path1` and `path2` are the same type, it then sorts them as strings.\nfunc fileSortFunc(path1, path2 string) int {\n\tisDirPath1 := IsDir(path1)\n\tisDirPath2 := IsDir(path2)\n\tif isDirPath1 && !isDirPath2 {\n\t\treturn -1\n\t}\n\tif !isDirPath1 && isDirPath2 {\n\t\treturn 1\n\t}\n\tif n := strings.Compare(path1, path2); n != 0 {\n\t\treturn n\n\t} else {\n\t\treturn -1\n\t}\n}\n\n// SortFiles sorts the `files` in order of: directory -> file.\n// Note that the item of `files` should be absolute path.\nfunc SortFiles(files []string) []string {\n\tarray := garray.NewSortedStrArrayComparator(fileSortFunc)\n\tarray.Add(files...)\n\treturn array.Slice()\n}\n"
  },
  {
    "path": "os/gfile/gfile_source.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\t// goRootForFilter is used for stack filtering purpose.\n\tgoRootForFilter = runtime.GOROOT()\n)\n\nfunc init() {\n\tif goRootForFilter != \"\" {\n\t\tgoRootForFilter = strings.ReplaceAll(goRootForFilter, \"\\\\\", \"/\")\n\t}\n}\n\n// MainPkgPath returns absolute file path of package main,\n// which contains the entrance function main.\n//\n// It's only available in develop environment.\n//\n// Note1: Only valid for source development environments,\n// IE only valid for systems that generate this executable.\n//\n// Note2: When the method is called for the first time, if it is in an asynchronous goroutine,\n// the method may not get the main package path.\nfunc MainPkgPath() string {\n\t// It is only for source development environments.\n\tif goRootForFilter == \"\" {\n\t\treturn \"\"\n\t}\n\tpath := mainPkgPath.Val()\n\tif path != \"\" {\n\t\treturn path\n\t}\n\tvar lastFile string\n\tfor i := 1; i < 10000; i++ {\n\t\tif pc, file, _, ok := runtime.Caller(i); ok {\n\t\t\tif goRootForFilter != \"\" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif Ext(file) != \".go\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlastFile = file\n\t\t\t// Check if it is called in package initialization function,\n\t\t\t// in which it here cannot retrieve main package path,\n\t\t\t// it so just returns that can make next check.\n\t\t\tif fn := runtime.FuncForPC(pc); fn != nil {\n\t\t\t\tarray := gstr.Split(fn.Name(), \".\")\n\t\t\t\tif array[0] != \"main\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif gregex.IsMatchString(`package\\s+main\\s+`, GetContents(file)) {\n\t\t\t\tmainPkgPath.Set(Dir(file))\n\t\t\t\treturn Dir(file)\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\t// If it still cannot find the path of the package main,\n\t// it recursively searches the directory and its parents directory of the last go file.\n\t// It's usually necessary for uint testing cases of business project.\n\tif lastFile != \"\" {\n\t\tfor path = Dir(lastFile); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; {\n\t\t\tfiles, _ := ScanDir(path, \"*.go\")\n\t\t\tfor _, v := range files {\n\t\t\t\tif gregex.IsMatchString(`package\\s+main\\s+`, GetContents(v)) {\n\t\t\t\t\tmainPkgPath.Set(path)\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t}\n\t\t\tpath = Dir(path)\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "os/gfile/gfile_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile\n\nimport (\n\t\"os\"\n\t\"time\"\n)\n\n// MTime returns the modification time of file given by `path` in second.\nfunc MTime(path string) time.Time {\n\ts, e := os.Stat(path)\n\tif e != nil {\n\t\treturn time.Time{}\n\t}\n\treturn s.ModTime()\n}\n\n// MTimestamp returns the modification time of file given by `path` in second.\nfunc MTimestamp(path string) int64 {\n\tmtime := MTime(path)\n\tif mtime.IsZero() {\n\t\treturn -1\n\t}\n\treturn mtime.Unix()\n}\n\n// MTimestampMilli returns the modification time of file given by `path` in millisecond.\nfunc MTimestampMilli(path string) int64 {\n\tmtime := MTime(path)\n\tif mtime.IsZero() {\n\t\treturn -1\n\t}\n\treturn mtime.UnixNano() / 1000000\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_cache_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleGetContentsWithCache() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_cache\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// It reads the file content with cache duration of one minute,\n\t// which means it reads from cache after then without any IO operations within on minute.\n\tfmt.Println(gfile.GetContentsWithCache(tempFile, time.Minute))\n\n\t// write new contents will clear its cache\n\tgfile.PutContents(tempFile, \"new goframe example content\")\n\n\t// There's some delay for cache clearing after file content change.\n\ttime.Sleep(time.Second * 1)\n\n\t// read contents\n\tfmt.Println(gfile.GetContentsWithCache(tempFile))\n\n\t// May Output:\n\t// goframe example content\n\t// new goframe example content\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_contents_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleGetContents() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// It reads and returns the file content as string.\n\t// It returns empty string if it fails reading, for example, with permission or IO error.\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n}\n\nfunc ExampleGetBytes() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// It reads and returns the file content as []byte.\n\t// It returns nil if it fails reading, for example, with permission or IO error.\n\tfmt.Println(gfile.GetBytes(tempFile))\n\n\t// Output:\n\t// [103 111 102 114 97 109 101 32 101 120 97 109 112 108 101 32 99 111 110 116 101 110 116]\n}\n\nfunc ExamplePutContents() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// It creates and puts content string into specifies file path.\n\t// It automatically creates directory recursively if it does not exist.\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n}\n\nfunc ExamplePutBytes() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutBytes(tempFile, []byte(\"goframe example content\"))\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n}\n\nfunc ExamplePutContentsAppend() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// It creates and append content string into specifies file path.\n\t// It automatically creates directory recursively if it does not exist.\n\tgfile.PutContentsAppend(tempFile, \" append content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n\t// goframe example content append content\n}\n\nfunc ExamplePutBytesAppend() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// write contents\n\tgfile.PutBytesAppend(tempFile, []byte(\" append\"))\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n\t// goframe example content append\n}\n\nfunc ExampleGetNextCharOffsetByPath() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tindex := gfile.GetNextCharOffsetByPath(tempFile, 'f', 0)\n\tfmt.Println(index)\n\n\t// Output:\n\t// 2\n}\n\nfunc ExampleGetBytesTilCharByPath() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetBytesTilCharByPath(tempFile, 'f', 0))\n\n\t// Output:\n\t// [103 111 102] 2\n}\n\nfunc ExampleGetBytesByTwoOffsetsByPath() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetBytesByTwoOffsetsByPath(tempFile, 0, 7))\n\n\t// Output:\n\t// [103 111 102 114 97 109 101]\n}\n\nfunc ExampleReadLines() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"L1 goframe example content\\nL2 goframe example content\")\n\n\t// read contents\n\tgfile.ReadLines(tempFile, func(text string) error {\n\t\t// Process each line\n\t\tfmt.Println(text)\n\t\treturn nil\n\t})\n\n\t// Output:\n\t// L1 goframe example content\n\t// L2 goframe example content\n}\n\nfunc ExampleReadLinesBytes() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_content\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"L1 goframe example content\\nL2 goframe example content\")\n\n\t// read contents\n\tgfile.ReadLinesBytes(tempFile, func(bytes []byte) error {\n\t\t// Process each line\n\t\tfmt.Println(bytes)\n\t\treturn nil\n\t})\n\n\t// Output:\n\t// [76 49 32 103 111 102 114 97 109 101 32 101 120 97 109 112 108 101 32 99 111 110 116 101 110 116]\n\t// [76 50 32 103 111 102 114 97 109 101 32 101 120 97 109 112 108 101 32 99 111 110 116 101 110 116]\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_copy_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleCopy() {\n\t// init\n\tvar (\n\t\tsrcFileName = \"gfile_example.txt\"\n\t\tsrcTempDir  = gfile.Temp(\"gfile_example_copy_src\")\n\t\tsrcTempFile = gfile.Join(srcTempDir, srcFileName)\n\n\t\t// copy file\n\t\tdstFileName = \"gfile_example_copy.txt\"\n\t\tdstTempFile = gfile.Join(srcTempDir, dstFileName)\n\n\t\t// copy dir\n\t\tdstTempDir = gfile.Temp(\"gfile_example_copy_dst\")\n\t)\n\n\t// write contents\n\tgfile.PutContents(srcTempFile, \"goframe example copy\")\n\n\t// copy file\n\tgfile.Copy(srcTempFile, dstTempFile)\n\n\t// read contents after copy file\n\tfmt.Println(gfile.GetContents(dstTempFile))\n\n\t// copy dir\n\tgfile.Copy(srcTempDir, dstTempDir)\n\n\t// list copy dir file\n\tfList, _ := gfile.ScanDir(dstTempDir, \"*\", false)\n\tfor _, v := range fList {\n\t\tfmt.Println(gfile.Basename(v))\n\t}\n\n\t// Output:\n\t// goframe example copy\n\t// gfile_example.txt\n\t// gfile_example_copy.txt\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_home_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleHome() {\n\t// user's home directory\n\thomePath, _ := gfile.Home()\n\tfmt.Println(homePath)\n\n\t// May Output:\n\t// C:\\Users\\hailaz\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_replace_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleReplaceFile() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_replace\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// It replaces content directly by file path.\n\tgfile.ReplaceFile(\"content\", \"replace word\", tempFile)\n\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n\t// goframe example replace word\n}\n\nfunc ExampleReplaceFileFunc() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_replace\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example 123\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// It replaces content directly by file path and callback function.\n\tgfile.ReplaceFileFunc(func(path, content string) string {\n\t\t// Replace with regular match\n\t\treg, _ := regexp.Compile(`\\d{3}`)\n\t\treturn reg.ReplaceAllString(content, \"[num]\")\n\t}, tempFile)\n\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example 123\n\t// goframe example [num]\n}\n\nfunc ExampleReplaceDir() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_replace\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// It replaces content of all files under specified directory recursively.\n\tgfile.ReplaceDir(\"content\", \"replace word\", tempDir, \"gfile_example.txt\", true)\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example content\n\t// goframe example replace word\n}\n\nfunc ExampleReplaceDirFunc() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_replace\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example 123\")\n\n\t// read contents\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// It replaces content of all files under specified directory with custom callback function recursively.\n\tgfile.ReplaceDirFunc(func(path, content string) string {\n\t\t// Replace with regular match\n\t\treg, _ := regexp.Compile(`\\d{3}`)\n\t\treturn reg.ReplaceAllString(content, \"[num]\")\n\t}, tempDir, \"gfile_example.txt\", true)\n\n\tfmt.Println(gfile.GetContents(tempFile))\n\n\t// Output:\n\t// goframe example 123\n\t// goframe example [num]\n\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_scan_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleScanDir() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_scan_dir\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\n\t\ttempSubDir  = gfile.Join(tempDir, \"sub_dir\")\n\t\ttempSubFile = gfile.Join(tempSubDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\tgfile.PutContents(tempSubFile, \"goframe example content\")\n\n\t// scans directory recursively\n\tlist, _ := gfile.ScanDir(tempDir, \"*\", true)\n\tfor _, v := range list {\n\t\tfmt.Println(gfile.Basename(v))\n\t}\n\n\t// Output:\n\t// gfile_example.txt\n\t// sub_dir\n\t// gfile_example.txt\n}\n\nfunc ExampleScanDirFile() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_scan_dir_file\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\n\t\ttempSubDir  = gfile.Join(tempDir, \"sub_dir\")\n\t\ttempSubFile = gfile.Join(tempSubDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\tgfile.PutContents(tempSubFile, \"goframe example content\")\n\n\t// scans directory recursively exclusive of directories\n\tlist, _ := gfile.ScanDirFile(tempDir, \"*.txt\", true)\n\tfor _, v := range list {\n\t\tfmt.Println(gfile.Basename(v))\n\t}\n\n\t// Output:\n\t// gfile_example.txt\n\t// gfile_example.txt\n}\n\nfunc ExampleScanDirFunc() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_scan_dir_func\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\n\t\ttempSubDir  = gfile.Join(tempDir, \"sub_dir\")\n\t\ttempSubFile = gfile.Join(tempSubDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\tgfile.PutContents(tempSubFile, \"goframe example content\")\n\n\t// scans directory recursively\n\tlist, _ := gfile.ScanDirFunc(tempDir, \"*\", true, func(path string) string {\n\t\t// ignores some files\n\t\tif gfile.Basename(path) == \"gfile_example.txt\" {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn path\n\t})\n\tfor _, v := range list {\n\t\tfmt.Println(gfile.Basename(v))\n\t}\n\n\t// Output:\n\t// sub_dir\n}\n\nfunc ExampleScanDirFileFunc() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_scan_dir_file_func\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\n\t\tfileName1 = \"gfile_example_ignores.txt\"\n\t\ttempFile1 = gfile.Join(tempDir, fileName1)\n\n\t\ttempSubDir  = gfile.Join(tempDir, \"sub_dir\")\n\t\ttempSubFile = gfile.Join(tempSubDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\tgfile.PutContents(tempFile1, \"goframe example content\")\n\tgfile.PutContents(tempSubFile, \"goframe example content\")\n\n\t// scans directory recursively exclusive of directories\n\tlist, _ := gfile.ScanDirFileFunc(tempDir, \"*.txt\", true, func(path string) string {\n\t\t// ignores some files\n\t\tif gfile.Basename(path) == \"gfile_example_ignores.txt\" {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn path\n\t})\n\tfor _, v := range list {\n\t\tfmt.Println(gfile.Basename(v))\n\t}\n\n\t// Output:\n\t// gfile_example.txt\n\t// gfile_example.txt\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_search_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleSearch() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_search\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"goframe example content\")\n\n\t// search file\n\trealPath, _ := gfile.Search(fileName, tempDir)\n\tfmt.Println(gfile.Basename(realPath))\n\n\t// Output:\n\t// gfile_example.txt\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_size_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleSize() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_size\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"0123456789\")\n\tfmt.Println(gfile.Size(tempFile))\n\n\t// Output:\n\t// 10\n}\n\nfunc ExampleSizeFormat() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_size\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"0123456789\")\n\tfmt.Println(gfile.SizeFormat(tempFile))\n\n\t// Output:\n\t// 10.00B\n}\n\nfunc ExampleReadableSize() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example.txt\"\n\t\ttempDir  = gfile.Temp(\"gfile_example_size\")\n\t\ttempFile = gfile.Join(tempDir, fileName)\n\t)\n\n\t// write contents\n\tgfile.PutContents(tempFile, \"01234567899876543210\")\n\tfmt.Println(gfile.ReadableSize(tempFile))\n\n\t// Output:\n\t// 20.00B\n}\n\nfunc ExampleStrToSize() {\n\tsize := gfile.StrToSize(\"100MB\")\n\tfmt.Println(size)\n\n\t// Output:\n\t// 104857600\n}\n\nfunc ExampleFormatSize() {\n\tsizeStr := gfile.FormatSize(104857600)\n\tfmt.Println(sizeStr)\n\tsizeStr0 := gfile.FormatSize(1024)\n\tfmt.Println(sizeStr0)\n\tsizeStr1 := gfile.FormatSize(999999999999999999)\n\tfmt.Println(sizeStr1)\n\n\t// Output:\n\t// 100.00M\n\t// 1.00K\n\t// 888.18P\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_sort_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleSortFiles() {\n\tfiles := []string{\n\t\t\"/aaa/bbb/ccc.txt\",\n\t\t\"/aaa/bbb/\",\n\t\t\"/aaa/\",\n\t\t\"/aaa\",\n\t\t\"/aaa/ccc/ddd.txt\",\n\t\t\"/bbb\",\n\t\t\"/0123\",\n\t\t\"/ddd\",\n\t\t\"/ccc\",\n\t}\n\tsortOut := gfile.SortFiles(files)\n\tfmt.Println(sortOut)\n\n\t// Output:\n\t// [/0123 /aaa /aaa/ /aaa/bbb/ /aaa/bbb/ccc.txt /aaa/ccc/ddd.txt /bbb /ccc /ddd]\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_example_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleMTime() {\n\tt := gfile.MTime(gfile.Temp())\n\tfmt.Println(t)\n\n\t// May Output:\n\t// 2021-11-02 15:18:43.901141 +0800 CST\n}\n\nfunc ExampleMTimestamp() {\n\tt := gfile.MTimestamp(gfile.Temp())\n\tfmt.Println(t)\n\n\t// May Output:\n\t// 1635838398\n}\n\nfunc ExampleMTimestampMilli() {\n\tt := gfile.MTimestampMilli(gfile.Temp())\n\tfmt.Println(t)\n\n\t// May Output:\n\t// 1635838529330\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_exmaple_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nfunc ExampleMkdir() {\n\t// init\n\tvar (\n\t\tpath = gfile.Temp(\"gfile_example_basic_dir\")\n\t)\n\n\t// Creates directory\n\tgfile.Mkdir(path)\n\n\t// Check if directory exists\n\tfmt.Println(gfile.IsDir(path))\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleCreate() {\n\t// init\n\tvar (\n\t\tpath     = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdataByte = make([]byte, 50)\n\t)\n\t// Check whether the file exists\n\tisFile := gfile.IsFile(path)\n\n\tfmt.Println(isFile)\n\n\t// Creates file with given `path` recursively\n\tfileHandle, _ := gfile.Create(path)\n\tdefer fileHandle.Close()\n\n\t// Write some content to file\n\tn, _ := fileHandle.WriteString(\"hello goframe\")\n\n\t// Check whether the file exists\n\tisFile = gfile.IsFile(path)\n\n\tfmt.Println(isFile)\n\n\t// Reads len(b) bytes from the File\n\tfileHandle.ReadAt(dataByte, 0)\n\n\tfmt.Println(string(dataByte[:n]))\n\n\t// Output:\n\t// false\n\t// true\n\t// hello goframe\n}\n\nfunc ExampleOpen() {\n\t// init\n\tvar (\n\t\tpath     = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdataByte = make([]byte, 4096)\n\t)\n\t// Open file or directory with READONLY model\n\tfile, _ := gfile.Open(path)\n\tdefer file.Close()\n\n\t// Read data\n\tn, _ := file.Read(dataByte)\n\n\tfmt.Println(string(dataByte[:n]))\n\n\t// Output:\n\t// hello goframe\n}\n\nfunc ExampleOpenFile() {\n\t// init\n\tvar (\n\t\tpath     = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdataByte = make([]byte, 4096)\n\t)\n\t// Opens file/directory with custom `flag` and `perm`\n\t// Create if file does not exist,it is created in a readable and writable mode,prem 0777\n\topenFile, _ := gfile.OpenFile(path, os.O_CREATE|os.O_RDWR, gfile.DefaultPermCopy)\n\tdefer openFile.Close()\n\n\t// Write some content to file\n\twriteLength, _ := openFile.WriteString(\"hello goframe test open file\")\n\n\tfmt.Println(writeLength)\n\n\t// Read data\n\tn, _ := openFile.ReadAt(dataByte, 0)\n\n\tfmt.Println(string(dataByte[:n]))\n\n\t// Output:\n\t// 28\n\t// hello goframe test open file\n}\n\nfunc ExampleOpenWithFlag() {\n\t// init\n\tvar (\n\t\tpath     = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdataByte = make([]byte, 4096)\n\t)\n\n\t// Opens file/directory with custom `flag`\n\t// Create if file does not exist,it is created in a readable and writable mode with default `perm` is 0666\n\topenFile, _ := gfile.OpenWithFlag(path, os.O_CREATE|os.O_RDWR)\n\tdefer openFile.Close()\n\n\t// Write some content to file\n\twriteLength, _ := openFile.WriteString(\"hello goframe test open file with flag\")\n\n\tfmt.Println(writeLength)\n\n\t// Read data\n\tn, _ := openFile.ReadAt(dataByte, 0)\n\n\tfmt.Println(string(dataByte[:n]))\n\n\t// Output:\n\t// 38\n\t// hello goframe test open file with flag\n}\n\nfunc ExampleJoin() {\n\t// init\n\tvar (\n\t\tdirPath  = gfile.Temp(\"gfile_example_basic_dir\")\n\t\tfilePath = \"file1\"\n\t)\n\n\t// Joins string array paths with file separator of current system.\n\tjoinString := gfile.Join(dirPath, filePath)\n\n\tfmt.Println(joinString)\n\n\t// May Output:\n\t// /tmp/gfile_example_basic_dir/file1\n}\n\nfunc ExampleExists() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\t// Checks whether given `path` exist.\n\tjoinString := gfile.Exists(path)\n\n\tfmt.Println(joinString)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleIsDir() {\n\t// init\n\tvar (\n\t\tpath     = gfile.Temp(\"gfile_example_basic_dir\")\n\t\tfilePath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\t// Checks whether given `path` a directory.\n\tfmt.Println(gfile.IsDir(path))\n\tfmt.Println(gfile.IsDir(filePath))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExamplePwd() {\n\t// Get absolute path of current working directory.\n\tfmt.Println(gfile.Pwd())\n\n\t// May Output:\n\t// xxx/gf/os/gfile\n}\n\nfunc ExampleChdir() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\t// Get current working directory\n\tfmt.Println(gfile.Pwd())\n\n\t// Changes the current working directory to the named directory.\n\tgfile.Chdir(path)\n\n\t// Get current working directory\n\tfmt.Println(gfile.Pwd())\n\n\t// May Output:\n\t// xxx/gf/os/gfile\n\t// /tmp/gfile_example_basic_dir/file1\n}\n\nfunc ExampleIsFile() {\n\t// init\n\tvar (\n\t\tfilePath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdirPath  = gfile.Temp(\"gfile_example_basic_dir\")\n\t)\n\t// Checks whether given `path` a file, which means it's not a directory.\n\tfmt.Println(gfile.IsFile(filePath))\n\tfmt.Println(gfile.IsFile(dirPath))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleStat() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\t// Get a FileInfo describing the named file.\n\tstat, _ := gfile.Stat(path)\n\n\tfmt.Println(stat.Name())\n\tfmt.Println(stat.IsDir())\n\tfmt.Println(stat.Mode())\n\tfmt.Println(stat.ModTime())\n\tfmt.Println(stat.Size())\n\tfmt.Println(stat.Sys())\n\n\t// May Output:\n\t// file1\n\t// false\n\t// -rwxr-xr-x\n\t// 2021-12-02 11:01:27.261441694 +0800 CST\n\t// &{16777220 33261 1 8597857090 501 20 0 [0 0 0 0] {1638414088 192363490} {1638414087 261441694} {1638414087 261441694} {1638413480 485068275} 38 8 4096 0 0 0 [0 0]}\n}\n\nfunc ExampleMove() {\n\t// init\n\tvar (\n\t\tsrcPath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tdstPath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file2\")\n\t)\n\t// Check is file\n\tfmt.Println(gfile.IsFile(dstPath))\n\n\t//  Moves `src` to `dst` path.\n\t// If `dst` already exists and is not a directory, it'll be replaced.\n\tgfile.Move(srcPath, dstPath)\n\n\tfmt.Println(gfile.IsFile(srcPath))\n\tfmt.Println(gfile.IsFile(dstPath))\n\n\t// Output:\n\t// false\n\t// false\n\t// true\n}\n\nfunc ExampleRename() {\n\t// init\n\tvar (\n\t\tsrcPath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file2\")\n\t\tdstPath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\t// Check is file\n\tfmt.Println(gfile.IsFile(dstPath))\n\n\t//  renames (moves) `src` to `dst` path.\n\t// If `dst` already exists and is not a directory, it'll be replaced.\n\tgfile.Rename(srcPath, dstPath)\n\n\tfmt.Println(gfile.IsFile(srcPath))\n\tfmt.Println(gfile.IsFile(dstPath))\n\n\t// Output:\n\t// false\n\t// false\n\t// true\n}\n\nfunc ExampleDirNames() {\n\t// init\n\tvar (\n\t\tpath = gfile.Temp(\"gfile_example_basic_dir\")\n\t)\n\t// Get sub-file names of given directory `path`.\n\tdirNames, _ := gfile.DirNames(path)\n\n\tfmt.Println(dirNames)\n\n\t// May Output:\n\t// [file1]\n}\n\nfunc ExampleGlob() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"*_example_basic_test.go\"\n\t)\n\t// Get sub-file names of given directory `path`.\n\t// Only show file name\n\tmatchNames, _ := gfile.Glob(path, true)\n\n\tfmt.Println(matchNames)\n\n\t// Show full path of the file\n\tmatchNames, _ = gfile.Glob(path, false)\n\n\tfmt.Println(matchNames)\n\n\t// May Output:\n\t// [gfile_z_example_basic_test.go]\n\t// [xxx/gf/os/gfile/gfile_z_example_basic_test.go]\n}\n\nfunc ExampleIsReadable() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/file.log\"\n\t)\n\n\t// Checks whether given `path` is readable.\n\tfmt.Println(gfile.IsReadable(path))\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleIsWritable() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/\"\n\t\tfile = \"file.log\"\n\t)\n\n\t// Checks whether given `path` is writable.\n\tfmt.Println(gfile.IsWritable(path))\n\tfmt.Println(gfile.IsWritable(path + file))\n\n\t// Output:\n\t// true\n\t// true\n}\n\nfunc ExampleChmod() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\n\t// Get a FileInfo describing the named file.\n\tstat, err := gfile.Stat(path)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t}\n\t// Show original mode\n\tfmt.Println(stat.Mode())\n\n\t// Change file model\n\tgfile.Chmod(path, gfile.DefaultPermCopy)\n\n\t// Get a FileInfo describing the named file.\n\tstat, _ = gfile.Stat(path)\n\t// Show the modified mode\n\tfmt.Println(stat.Mode())\n\n\t// Output:\n\t// -rw-r--r--\n\t// -rwxr-xr-x\n}\n\nfunc ExampleAbs() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\n\t// Get an absolute representation of path.\n\tfmt.Println(gfile.Abs(path))\n\n\t// May Output:\n\t// /tmp/gfile_example_basic_dir/file1\n}\n\nfunc ExampleRealPath() {\n\t// init\n\tvar (\n\t\trealPath  = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t\tworryPath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"worryFile\")\n\t)\n\n\t// fetch an absolute representation of path.\n\tfmt.Println(gfile.RealPath(realPath))\n\tfmt.Println(gfile.RealPath(worryPath))\n\n\t// May Output:\n\t// /tmp/gfile_example_basic_dir/file1\n}\n\nfunc ExampleSelfPath() {\n\n\t// Get absolute file path of current running process\n\tfmt.Println(gfile.SelfPath())\n\n\t// May Output:\n\t// xxx/___github_com_gogf_gf_v2_os_gfile__ExampleSelfPath\n}\n\nfunc ExampleSelfName() {\n\n\t// Get file name of current running process\n\tfmt.Println(gfile.SelfName())\n\n\t// May Output:\n\t// ___github_com_gogf_gf_v2_os_gfile__ExampleSelfName\n}\n\nfunc ExampleSelfDir() {\n\n\t// Get absolute directory path of current running process\n\tfmt.Println(gfile.SelfDir())\n\n\t// May Output:\n\t// /private/var/folders/p6/gc_9mm3j229c0mjrjp01gqn80000gn/T\n}\n\nfunc ExampleBasename() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/file.log\"\n\t)\n\n\t// Get the last element of path, which contains file extension.\n\tfmt.Println(gfile.Basename(path))\n\n\t// Output:\n\t// file.log\n}\n\nfunc ExampleName() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/file.log\"\n\t)\n\n\t// Get the last element of path without file extension.\n\tfmt.Println(gfile.Name(path))\n\n\t// Output:\n\t// file\n}\n\nfunc ExampleDir() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\n\t// Get all but the last element of path, typically the path's directory.\n\tfmt.Println(gfile.Dir(path))\n\n\t// May Output:\n\t// /tmp/gfile_example_basic_dir\n}\n\nfunc ExampleIsEmpty() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\n\t// Check whether the `path` is empty\n\tfmt.Println(gfile.IsEmpty(path))\n\n\t// Truncate file\n\tgfile.Truncate(path, 0)\n\n\t// Check whether the `path` is empty\n\tfmt.Println(gfile.IsEmpty(path))\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleExt() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/file.log\"\n\t)\n\n\t// Get the file name extension used by path.\n\tfmt.Println(gfile.Ext(path))\n\n\t// Output:\n\t// .log\n}\n\nfunc ExampleExtName() {\n\t// init\n\tvar (\n\t\tpath = gfile.Pwd() + gfile.Separator + \"testdata/readline/file.log\"\n\t)\n\n\t// Get the file name extension used by path but the result does not contains symbol '.'.\n\tfmt.Println(gfile.ExtName(path))\n\n\t// Output:\n\t// log\n}\n\nfunc ExampleTempDir() {\n\t// init\n\tvar (\n\t\tfileName = \"gfile_example_basic_dir\"\n\t)\n\n\t// fetch an absolute representation of path.\n\tpath := gfile.Temp(fileName)\n\n\tfmt.Println(path)\n\n\t// May Output:\n\t// /tmp/gfile_example_basic_dir\n}\n\nfunc ExampleRemove() {\n\t// init\n\tvar (\n\t\tpath = gfile.Join(gfile.Temp(\"gfile_example_basic_dir\"), \"file1\")\n\t)\n\n\t// Checks whether given `path` a file, which means it's not a directory.\n\tfmt.Println(gfile.IsFile(path))\n\n\t// deletes all file/directory with `path` parameter.\n\tgfile.Remove(path)\n\n\t// Check again\n\tfmt.Println(gfile.IsFile(path))\n\n\t// Output:\n\t// true\n\t// false\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_cache_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_GetContentsWithCache(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar f *os.File\n\t\tvar err error\n\t\tfileName := \"test\"\n\t\tstrTest := \"123\"\n\n\t\tif !gfile.Exists(fileName) {\n\t\t\tf, err = os.CreateTemp(\"\", fileName)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"create file fail\")\n\t\t\t}\n\t\t}\n\n\t\tdefer f.Close()\n\t\tdefer os.Remove(f.Name())\n\n\t\tif gfile.Exists(f.Name()) {\n\t\t\tf, err = gfile.OpenFile(f.Name(), os.O_APPEND|os.O_WRONLY, os.ModeAppend)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"file open fail\", err)\n\t\t\t}\n\n\t\t\terr = gfile.PutContents(f.Name(), strTest)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"write error\", err)\n\t\t\t}\n\n\t\t\tcache := gfile.GetContentsWithCache(f.Name(), 1)\n\t\t\tt.Assert(cache, strTest)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tvar f *os.File\n\t\tvar err error\n\t\tfileName := \"test2\"\n\t\tstrTest := \"123\"\n\n\t\tif !gfile.Exists(fileName) {\n\t\t\tf, err = os.CreateTemp(\"\", fileName)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"create file fail\")\n\t\t\t}\n\t\t}\n\n\t\tdefer f.Close()\n\t\tdefer os.Remove(f.Name())\n\n\t\tif gfile.Exists(f.Name()) {\n\t\t\tcache := gfile.GetContentsWithCache(f.Name())\n\n\t\t\tf, err = gfile.OpenFile(f.Name(), os.O_APPEND|os.O_WRONLY, os.ModeAppend)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"file open fail\", err)\n\t\t\t}\n\n\t\t\terr = gfile.PutContents(f.Name(), strTest)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"write error\", err)\n\t\t\t}\n\n\t\t\tt.Assert(cache, \"\")\n\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t})\n}\n\nfunc Test_GetBytesWithCache(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar f *os.File\n\t\tvar err error\n\t\tfileName := \"test_bytes\"\n\t\tbyteContent := []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f} // \"Hello\"\n\n\t\tif !gfile.Exists(fileName) {\n\t\t\tf, err = os.CreateTemp(\"\", fileName)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"create file fail\")\n\t\t\t}\n\t\t}\n\n\t\tdefer f.Close()\n\t\tdefer os.Remove(f.Name())\n\n\t\tif gfile.Exists(f.Name()) {\n\t\t\terr = gfile.PutBytes(f.Name(), byteContent)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"write error\", err)\n\t\t\t}\n\n\t\t\t// Test GetBytesWithCache with custom duration\n\t\t\tcache := gfile.GetBytesWithCache(f.Name(), time.Second*1)\n\t\t\tt.Assert(cache, byteContent)\n\n\t\t\t// Test cache hit - should return same content\n\t\t\tcache2 := gfile.GetBytesWithCache(f.Name(), time.Second*1)\n\t\t\tt.Assert(cache2, byteContent)\n\t\t}\n\t})\n\n\t// Test with non-existent file\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcache := gfile.GetBytesWithCache(\"/nonexistent_file_12345.txt\")\n\t\tt.Assert(cache, nil)\n\t})\n\n\t// Test with empty file\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar f *os.File\n\t\tvar err error\n\t\tfileName := \"test_bytes_empty\"\n\n\t\tf, err = os.CreateTemp(\"\", fileName)\n\t\tif err != nil {\n\t\t\tt.Error(\"create file fail\")\n\t\t}\n\n\t\tdefer f.Close()\n\t\tdefer os.Remove(f.Name())\n\n\t\t// Read empty file\n\t\tcache := gfile.GetBytesWithCache(f.Name(), time.Second*1)\n\t\tt.Assert(len(cache), 0)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_contents_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc createTestFile(filename, content string) error {\n\tTempDir := testpath()\n\terr := os.WriteFile(TempDir+filename, []byte(content), 0666)\n\treturn err\n}\n\nfunc delTestFiles(filenames string) {\n\tos.RemoveAll(testpath() + filenames)\n}\n\nfunc createDir(paths string) {\n\tTempDir := testpath()\n\tos.Mkdir(TempDir+paths, 0777)\n}\n\nfunc formatpaths(paths []string) []string {\n\tfor k, v := range paths {\n\t\tpaths[k] = filepath.ToSlash(v)\n\t\tpaths[k] = strings.Replace(paths[k], \"./\", \"/\", 1)\n\t}\n\n\treturn paths\n}\n\nfunc formatpath(paths string) string {\n\tpaths = filepath.ToSlash(paths)\n\tpaths = strings.Replace(paths, \"./\", \"/\", 1)\n\treturn paths\n}\n\nfunc testpath() string {\n\treturn gstr.TrimRight(os.TempDir(), \"\\\\/\")\n}\n\nfunc Test_GetContents(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tvar (\n\t\t\tfilepaths string = \"/testfile_t1.txt\"\n\t\t)\n\t\tcreateTestFile(filepaths, \"my name is jroam\")\n\t\tdefer delTestFiles(filepaths)\n\n\t\tt.Assert(gfile.GetContents(testpath()+filepaths), \"my name is jroam\")\n\t\tt.Assert(gfile.GetContents(\"\"), \"\")\n\n\t})\n}\n\nfunc Test_GetBinContents(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths1  = \"/testfile_t1.txt\"\n\t\t\tfilepaths2  = testpath() + \"/testfile_t1_no.txt\"\n\t\t\treadcontent []byte\n\t\t\tstr1        = \"my name is jroam\"\n\t\t)\n\t\tcreateTestFile(filepaths1, str1)\n\t\tdefer delTestFiles(filepaths1)\n\t\treadcontent = gfile.GetBytes(testpath() + filepaths1)\n\t\tt.Assert(readcontent, []byte(str1))\n\n\t\treadcontent = gfile.GetBytes(filepaths2)\n\t\tt.Assert(string(readcontent), \"\")\n\n\t\tt.Assert(string(gfile.GetBytes(filepaths2)), \"\")\n\n\t})\n}\n\nfunc Test_Truncate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths1 = \"/testfile_GetContentsyyui.txt\"\n\t\t\terr        error\n\t\t\tfiles      *os.File\n\t\t)\n\t\tcreateTestFile(filepaths1, \"abcdefghijkmln\")\n\t\tdefer delTestFiles(filepaths1)\n\t\terr = gfile.Truncate(testpath()+filepaths1, 10)\n\t\tt.AssertNil(err)\n\n\t\tfiles, err = os.Open(testpath() + filepaths1)\n\t\tt.AssertNil(err)\n\t\tdefer files.Close()\n\t\tfileinfo, err2 := files.Stat()\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(fileinfo.Size(), 10)\n\n\t\terr = gfile.Truncate(\"\", 10)\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_PutContents(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths   = \"/testfile_PutContents.txt\"\n\t\t\terr         error\n\t\t\treadcontent []byte\n\t\t)\n\t\tcreateTestFile(filepaths, \"a\")\n\t\tdefer delTestFiles(filepaths)\n\n\t\terr = gfile.PutContents(testpath()+filepaths, \"test!\")\n\t\tt.AssertNil(err)\n\n\t\treadcontent, err = os.ReadFile(testpath() + filepaths)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(readcontent), \"test!\")\n\n\t\terr = gfile.PutContents(\"\", \"test!\")\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_PutContentsAppend(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths   = \"/testfile_PutContents.txt\"\n\t\t\terr         error\n\t\t\treadcontent []byte\n\t\t)\n\n\t\tcreateTestFile(filepaths, \"a\")\n\t\tdefer delTestFiles(filepaths)\n\t\terr = gfile.PutContentsAppend(testpath()+filepaths, \"hello\")\n\t\tt.AssertNil(err)\n\n\t\treadcontent, err = os.ReadFile(testpath() + filepaths)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(readcontent), \"ahello\")\n\n\t\terr = gfile.PutContentsAppend(\"\", \"hello\")\n\t\tt.AssertNE(err, nil)\n\n\t})\n\n}\n\nfunc Test_PutBinContents(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths   = \"/testfile_PutContents.txt\"\n\t\t\terr         error\n\t\t\treadcontent []byte\n\t\t)\n\t\tcreateTestFile(filepaths, \"a\")\n\t\tdefer delTestFiles(filepaths)\n\n\t\terr = gfile.PutBytes(testpath()+filepaths, []byte(\"test!!\"))\n\t\tt.AssertNil(err)\n\n\t\treadcontent, err = os.ReadFile(testpath() + filepaths)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(readcontent), \"test!!\")\n\n\t\terr = gfile.PutBytes(\"\", []byte(\"test!!\"))\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_PutBinContentsAppend(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths   = \"/testfile_PutContents.txt\"\n\t\t\terr         error\n\t\t\treadcontent []byte\n\t\t)\n\t\tcreateTestFile(filepaths, \"test!!\")\n\t\tdefer delTestFiles(filepaths)\n\t\terr = gfile.PutBytesAppend(testpath()+filepaths, []byte(\"word\"))\n\t\tt.AssertNil(err)\n\n\t\treadcontent, err = os.ReadFile(testpath() + filepaths)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(readcontent), \"test!!word\")\n\n\t\terr = gfile.PutBytesAppend(\"\", []byte(\"word\"))\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_GetBinContentsByTwoOffsetsByPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths   = \"/testfile_GetContents.txt\"\n\t\t\treadcontent []byte\n\t\t)\n\n\t\tcreateTestFile(filepaths, \"abcdefghijk\")\n\t\tdefer delTestFiles(filepaths)\n\t\treadcontent = gfile.GetBytesByTwoOffsetsByPath(testpath()+filepaths, 2, 5)\n\n\t\tt.Assert(string(readcontent), \"cde\")\n\n\t\treadcontent = gfile.GetBytesByTwoOffsetsByPath(\"\", 2, 5)\n\t\tt.Assert(len(readcontent), 0)\n\n\t})\n\n}\n\nfunc Test_GetNextCharOffsetByPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfilepaths  = \"/testfile_GetContents.txt\"\n\t\t\tlocalindex int64\n\t\t)\n\t\tcreateTestFile(filepaths, \"abcdefghijk\")\n\t\tdefer delTestFiles(filepaths)\n\t\tlocalindex = gfile.GetNextCharOffsetByPath(testpath()+filepaths, 'd', 1)\n\t\tt.Assert(localindex, 3)\n\n\t\tlocalindex = gfile.GetNextCharOffsetByPath(\"\", 'd', 1)\n\t\tt.Assert(localindex, -1)\n\n\t})\n}\n\nfunc Test_GetNextCharOffset(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tlocalindex int64\n\t\t)\n\t\treader := strings.NewReader(\"helloword\")\n\n\t\tlocalindex = gfile.GetNextCharOffset(reader, 'w', 1)\n\t\tt.Assert(localindex, 5)\n\n\t\tlocalindex = gfile.GetNextCharOffset(reader, 'j', 1)\n\t\tt.Assert(localindex, -1)\n\n\t})\n}\n\nfunc Test_GetBinContentsByTwoOffsets(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\treads []byte\n\t\t)\n\t\treader := strings.NewReader(\"helloword\")\n\n\t\treads = gfile.GetBytesByTwoOffsets(reader, 1, 3)\n\t\tt.Assert(string(reads), \"el\")\n\n\t\treads = gfile.GetBytesByTwoOffsets(reader, 10, 30)\n\t\tt.Assert(string(reads), \"\")\n\n\t})\n}\n\nfunc Test_GetBinContentsTilChar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\treads  []byte\n\t\t\tindexs int64\n\t\t)\n\t\treader := strings.NewReader(\"helloword\")\n\n\t\treads, _ = gfile.GetBytesTilChar(reader, 'w', 2)\n\t\tt.Assert(string(reads), \"llow\")\n\n\t\t_, indexs = gfile.GetBytesTilChar(reader, 'w', 20)\n\t\tt.Assert(indexs, -1)\n\n\t})\n}\n\nfunc Test_GetBinContentsTilCharByPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\treads     []byte\n\t\t\tindexs    int64\n\t\t\tfilepaths = \"/testfile_GetContents.txt\"\n\t\t)\n\n\t\tcreateTestFile(filepaths, \"abcdefghijklmn\")\n\t\tdefer delTestFiles(filepaths)\n\n\t\treads, _ = gfile.GetBytesTilCharByPath(testpath()+filepaths, 'c', 2)\n\t\tt.Assert(string(reads), \"c\")\n\n\t\treads, _ = gfile.GetBytesTilCharByPath(testpath()+filepaths, 'y', 1)\n\t\tt.Assert(string(reads), \"\")\n\n\t\t_, indexs = gfile.GetBytesTilCharByPath(testpath()+filepaths, 'x', 1)\n\t\tt.Assert(indexs, -1)\n\n\t})\n}\n\nfunc Test_Home(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\treads string\n\t\t\terr   error\n\t\t)\n\n\t\treads, err = gfile.Home(\"a\", \"b\")\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(reads, \"\")\n\t})\n}\n\nfunc Test_NotFound(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tteatFile := gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/readline/error.log\"\n\t\tcallback := func(line string) error {\n\t\t\treturn nil\n\t\t}\n\t\terr := gfile.ReadLines(teatFile, callback)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReadLines(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\texpectList = []string{\"a\", \"b\", \"c\", \"d\", \"e\"}\n\t\t\tgetList    = make([]string, 0)\n\t\t\tcallback   = func(line string) error {\n\t\t\t\tgetList = append(getList, line)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tteatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/readline/file.log\"\n\t\t)\n\t\terr := gfile.ReadLines(teatFile, callback)\n\t\tt.AssertEQ(getList, expectList)\n\t\tt.AssertEQ(err, nil)\n\t})\n}\n\nfunc Test_ReadLines_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcallback = func(line string) error {\n\t\t\t\treturn gerror.New(\"custom error\")\n\t\t\t}\n\t\t\tteatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/readline/file.log\"\n\t\t)\n\t\terr := gfile.ReadLines(teatFile, callback)\n\t\tt.AssertEQ(err.Error(), \"custom error\")\n\t})\n}\n\nfunc Test_ReadLinesBytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\texpectList = [][]byte{[]byte(\"a\"), []byte(\"b\"), []byte(\"c\"), []byte(\"d\"), []byte(\"e\")}\n\t\t\tgetList    = make([][]byte, 0)\n\t\t\tcallback   = func(line []byte) error {\n\t\t\t\tgetList = append(getList, line)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tteatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/readline/file.log\"\n\t\t)\n\t\terr := gfile.ReadLinesBytes(teatFile, callback)\n\t\tt.AssertEQ(getList, expectList)\n\t\tt.AssertEQ(err, nil)\n\t})\n}\n\nfunc Test_ReadLinesBytes_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tcallback = func(line []byte) error {\n\t\t\t\treturn gerror.New(\"custom error\")\n\t\t\t}\n\t\t\tteatFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + \"testdata/readline/file.log\"\n\t\t)\n\t\terr := gfile.ReadLinesBytes(teatFile, callback)\n\t\tt.AssertEQ(err.Error(), \"custom error\")\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_copy_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Copy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths  = \"/testfile_copyfile1.txt\"\n\t\t\ttopath = \"/testfile_copyfile2.txt\"\n\t\t)\n\n\t\tcreateTestFile(paths, \"\")\n\t\tdefer delTestFiles(paths)\n\n\t\tt.Assert(gfile.Copy(testpath()+paths, testpath()+topath), nil)\n\t\tdefer delTestFiles(topath)\n\n\t\tt.Assert(gfile.IsFile(testpath()+topath), true)\n\t\tt.AssertNE(gfile.Copy(paths, \"\"), nil)\n\t\tt.AssertNE(gfile.Copy(\"\", topath), nil)\n\t})\n}\n\nfunc Test_Copy_File_To_Dir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = gtest.DataPath(\"dir1\", \"file1\")\n\t\t\tdst = gfile.Temp(guid.S(), \"dir2\")\n\t\t)\n\t\terr := gfile.Mkdir(dst)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dst)\n\n\t\terr = gfile.Copy(src, dst)\n\t\tt.AssertNil(err)\n\n\t\texpectPath := gfile.Join(dst, \"file1\")\n\t\tt.Assert(gfile.GetContents(expectPath), gfile.GetContents(src))\n\t})\n}\n\nfunc Test_Copy_Dir_To_File(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = gtest.DataPath(\"dir1\")\n\t\t\tdst = gfile.Temp(guid.S(), \"file2\")\n\t\t)\n\t\tf, err := gfile.Create(dst)\n\t\tt.AssertNil(err)\n\t\tdefer f.Close()\n\t\tdefer gfile.Remove(dst)\n\n\t\terr = gfile.Copy(src, dst)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_CopyFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths  = \"/testfile_copyfile1.txt\"\n\t\t\ttopath = \"/testfile_copyfile2.txt\"\n\t\t)\n\n\t\tcreateTestFile(paths, \"\")\n\t\tdefer delTestFiles(paths)\n\n\t\tt.Assert(gfile.CopyFile(testpath()+paths, testpath()+topath), nil)\n\t\tdefer delTestFiles(topath)\n\n\t\tt.Assert(gfile.IsFile(testpath()+topath), true)\n\t\tt.AssertNE(gfile.CopyFile(paths, \"\"), nil)\n\t\tt.AssertNE(gfile.CopyFile(\"\", topath), nil)\n\t})\n\t// Content replacement.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdst := gfile.Temp(gtime.TimestampNanoStr())\n\t\tsrcContent := \"1\"\n\t\tdstContent := \"1\"\n\t\tt.Assert(gfile.PutContents(src, srcContent), nil)\n\t\tt.Assert(gfile.PutContents(dst, dstContent), nil)\n\t\tt.Assert(gfile.GetContents(src), srcContent)\n\t\tt.Assert(gfile.GetContents(dst), dstContent)\n\n\t\tt.Assert(gfile.CopyFile(src, dst), nil)\n\t\tt.Assert(gfile.GetContents(src), srcContent)\n\t\tt.Assert(gfile.GetContents(dst), srcContent)\n\t})\n\t// Set mode\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc     = \"/testfile_copyfile1.txt\"\n\t\t\tdst     = \"/testfile_copyfile2.txt\"\n\t\t\tdstMode = os.FileMode(0600)\n\t\t)\n\t\tt.AssertNil(createTestFile(src, \"\"))\n\t\tdefer delTestFiles(src)\n\n\t\tt.Assert(gfile.CopyFile(testpath()+src, testpath()+dst, gfile.CopyOption{Mode: dstMode}), nil)\n\t\tdefer delTestFiles(dst)\n\n\t\tdstStat, err := gfile.Stat(testpath() + dst)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dstStat.Mode().Perm(), dstMode)\n\t})\n\t// Preserve src file's mode\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = \"/testfile_copyfile1.txt\"\n\t\t\tdst = \"/testfile_copyfile2.txt\"\n\t\t)\n\t\tt.AssertNil(createTestFile(src, \"\"))\n\t\tdefer delTestFiles(src)\n\n\t\tt.Assert(gfile.CopyFile(testpath()+src, testpath()+dst, gfile.CopyOption{PreserveMode: true}), nil)\n\t\tdefer delTestFiles(dst)\n\n\t\tsrcStat, err := gfile.Stat(testpath() + src)\n\t\tt.AssertNil(err)\n\t\tdstStat, err := gfile.Stat(testpath() + dst)\n\t\tt.AssertNil(err)\n\t\tt.Assert(srcStat.Mode().Perm(), dstStat.Mode().Perm())\n\t})\n}\n\nfunc Test_CopyDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirPath1 = \"/test-copy-dir1\"\n\t\t\tdirPath2 = \"/test-copy-dir2\"\n\t\t)\n\t\thaveList := []string{\n\t\t\t\"t1.txt\",\n\t\t\t\"t2.txt\",\n\t\t}\n\t\tcreateDir(dirPath1)\n\t\tfor _, v := range haveList {\n\t\t\tt.Assert(createTestFile(dirPath1+\"/\"+v, \"\"), nil)\n\t\t}\n\t\tdefer delTestFiles(dirPath1)\n\n\t\tvar (\n\t\t\tyfolder  = testpath() + dirPath1\n\t\t\ttofolder = testpath() + dirPath2\n\t\t)\n\n\t\tif gfile.IsDir(tofolder) {\n\t\t\tt.Assert(gfile.Remove(tofolder), nil)\n\t\t\tt.Assert(gfile.Remove(\"\"), nil)\n\t\t}\n\n\t\tt.Assert(gfile.CopyDir(yfolder, tofolder), nil)\n\t\tdefer delTestFiles(tofolder)\n\n\t\tt.Assert(gfile.IsDir(yfolder), true)\n\n\t\tfor _, v := range haveList {\n\t\t\tt.Assert(gfile.IsFile(yfolder+\"/\"+v), true)\n\t\t}\n\n\t\tt.Assert(gfile.IsDir(tofolder), true)\n\n\t\tfor _, v := range haveList {\n\t\t\tt.Assert(gfile.IsFile(tofolder+\"/\"+v), true)\n\t\t}\n\n\t\tt.Assert(gfile.Remove(tofolder), nil)\n\t\tt.Assert(gfile.Remove(\"\"), nil)\n\t})\n\t// Content replacement.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := gfile.Temp(gtime.TimestampNanoStr(), gtime.TimestampNanoStr())\n\t\tdst := gfile.Temp(gtime.TimestampNanoStr(), gtime.TimestampNanoStr())\n\t\tdefer func() {\n\t\t\tgfile.Remove(src)\n\t\t\tgfile.Remove(dst)\n\t\t}()\n\t\tsrcContent := \"1\"\n\t\tdstContent := \"1\"\n\t\tt.Assert(gfile.PutContents(src, srcContent), nil)\n\t\tt.Assert(gfile.PutContents(dst, dstContent), nil)\n\t\tt.Assert(gfile.GetContents(src), srcContent)\n\t\tt.Assert(gfile.GetContents(dst), dstContent)\n\n\t\terr := gfile.CopyDir(gfile.Dir(src), gfile.Dir(dst))\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(src), srcContent)\n\t\tt.Assert(gfile.GetContents(dst), srcContent)\n\n\t\tt.AssertNE(gfile.CopyDir(gfile.Dir(src), \"\"), nil)\n\t\tt.AssertNE(gfile.CopyDir(\"\", gfile.Dir(dst)), nil)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_match_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_MatchGlob_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Basic glob patterns (no **)\n\t\tmatched, err := gfile.MatchGlob(\"*.go\", \"main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"*.go\", \"main.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\tmatched, err = gfile.MatchGlob(\"test_*.go\", \"test_main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"?est.go\", \"test.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"[abc].go\", \"a.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"[a-z].go\", \"x.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_Globstar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// ** matches everything\n\t\tmatched, err := gfile.MatchGlob(\"**\", \"any/path/to/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**\", \"file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**\", \"\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_GlobstarWithSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// **/*.go - matches .go files in any directory\n\t\tmatched, err := gfile.MatchGlob(\"**/*.go\", \"main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**/*.go\", \"src/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**/*.go\", \"src/foo/bar/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**/*.go\", \"src/main.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n\nfunc Test_MatchGlob_GlobstarWithPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// src/** - matches everything under src/\n\t\tmatched, err := gfile.MatchGlob(\"src/**\", \"src/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**\", \"src/foo/bar/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**\", \"other/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n\nfunc Test_MatchGlob_GlobstarWithPrefixAndSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// src/**/*.go - matches .go files under src/\n\t\tmatched, err := gfile.MatchGlob(\"src/**/*.go\", \"src/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/*.go\", \"src/foo/bar/baz/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/*.go\", \"src/main.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/*.go\", \"other/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n\nfunc Test_MatchGlob_GlobstarMultiple(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Multiple ** in pattern\n\t\tmatched, err := gfile.MatchGlob(\"src/**/test/**/*.go\", \"src/foo/test/bar/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/test/**/*.go\", \"src/test/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/test/**/*.go\", \"src/a/b/test/c/d/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_GlobstarEdgeCases(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// ** at the beginning\n\t\tmatched, err := gfile.MatchGlob(\"**/main.go\", \"main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**/main.go\", \"src/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**/main.go\", \"src/foo/bar/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Hidden directories\n\t\tmatched, err = gfile.MatchGlob(\".*\", \".git\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\".*\", \".vscode\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"_*\", \"_test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_WindowsPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Windows-style paths should also work\n\t\tmatched, err := gfile.MatchGlob(\"src/**/*.go\", \"src\\\\foo\\\\main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src\\\\**\\\\*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_InvalidGlobstar(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// \"**\" not as complete path component should be treated as two \"*\"\n\t\t// \"a**b\" should match \"ab\", \"axb\", \"axxb\", etc. (but not \"a/b\")\n\t\tmatched, err := gfile.MatchGlob(\"a**b\", \"ab\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**b\", \"axb\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**b\", \"axxb\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**b\", \"axxxb\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"a**b\" should NOT match paths with separators\n\t\tmatched, err = gfile.MatchGlob(\"a**b\", \"a/b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**b\", \"ax/yb\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// \"**a\" at start (not valid globstar)\n\t\tmatched, err = gfile.MatchGlob(\"**a\", \"a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**a\", \"xa\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"**a\", \"xxa\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"a**\" at end (not valid globstar)\n\t\tmatched, err = gfile.MatchGlob(\"a**\", \"a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**\", \"ax\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a**\", \"axx\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Mixed valid and invalid globstars\n\t\t// \"src/**a\" - \"**\" is valid globstar, \"a\" is suffix\n\t\tmatched, err = gfile.MatchGlob(\"src/**/a\", \"src/foo/a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"src/**/a\", \"src/a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_PrefixBoundary(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// \"abc/**\" should NOT match \"abcdef/file.go\" (prefix must be complete path component)\n\t\tmatched, err := gfile.MatchGlob(\"abc/**\", \"abcdef/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// \"abc/**\" should match \"abc/file.go\"\n\t\tmatched, err = gfile.MatchGlob(\"abc/**\", \"abc/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"abc/**\" should match \"abc/def/file.go\"\n\t\tmatched, err = gfile.MatchGlob(\"abc/**\", \"abc/def/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"abc/**\" should match \"abc\" (prefix equals name)\n\t\tmatched, err = gfile.MatchGlob(\"abc/**\", \"abc\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"src/foo/**\" should NOT match \"src/foobar/file.go\"\n\t\tmatched, err = gfile.MatchGlob(\"src/foo/**\", \"src/foobar/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// \"src/foo/**\" should match \"src/foo/bar/file.go\"\n\t\tmatched, err = gfile.MatchGlob(\"src/foo/**\", \"src/foo/bar/file.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_MultipleGlobstars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with multiple ** operators - this would be slow without memoization\n\t\tmatched, err := gfile.MatchGlob(\"a/**/b/**/c/**/d.go\", \"a/x/y/b/z/c/w/d.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a/**/b/**/c/**/d.go\", \"a/b/c/d.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a/**/b/**/c/**/d.go\", \"a/1/2/3/b/4/5/c/6/d.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a/**/b/**/c/**/d.go\", \"a/b/c/e.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Deep nesting test\n\t\tmatched, err = gfile.MatchGlob(\"**/*.go\", \"a/b/c/d/e/f/g/h/i/j/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_MalformedPatterns(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Unclosed bracket - should return error\n\t\t_, err := gfile.MatchGlob(\"[\", \"a\")\n\t\tt.AssertNE(err, nil)\n\n\t\t_, err = gfile.MatchGlob(\"[abc\", \"a\")\n\t\tt.AssertNE(err, nil)\n\n\t\t_, err = gfile.MatchGlob(\"[[\", \"a\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Malformed patterns with globstar - errors should propagate\n\t\t_, err = gfile.MatchGlob(\"**/[\", \"a/b\")\n\t\tt.AssertNE(err, nil)\n\n\t\t_, err = gfile.MatchGlob(\"[/**\", \"a/b\")\n\t\tt.AssertNE(err, nil)\n\n\t\t_, err = gfile.MatchGlob(\"a/**/[abc\", \"a/b/c\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Malformed pattern in prefix with wildcards\n\t\t_, err = gfile.MatchGlob(\"[a/**/b\", \"a/x/b\")\n\t\tt.AssertNE(err, nil)\n\n\t\t// Invalid escape sequence on non-Windows (backslash at end)\n\t\t// Note: behavior may vary by platform\n\t\t_, err = gfile.MatchGlob(\"test\\\\\", \"test\")\n\t\t// On Unix, this might not error but won't match\n\t\t// The key is it shouldn't panic\n\n\t\t// Valid patterns should still work\n\t\tmatched, err := gfile.MatchGlob(\"[abc]\", \"a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"[a-z]\", \"m\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Note: filepath.Match uses [^...] for negation, not [!...]\n\t\tmatched, err = gfile.MatchGlob(\"[^abc]\", \"d\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"[^a-z]\", \"1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_MemoizationCache(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test cases that exercise memoization cache hits\n\t\t// Multiple ** with same suffix patterns will trigger cache reuse\n\t\tmatched, err := gfile.MatchGlob(\"a/**/b/**/c\", \"a/x/b/y/c\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// This pattern creates multiple paths that converge to same subproblems\n\t\tmatched, err = gfile.MatchGlob(\"**/a/**/a\", \"x/a/y/a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Deep recursion with cache hits\n\t\tmatched, err = gfile.MatchGlob(\"**/**/**\", \"a/b/c\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_InvalidGlobstarAtEnd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Pattern where \"**\" appears at the very end of string (idx >= len(pattern) after pos+2)\n\t\t// \"x**\" - invalid globstar at end, should be treated as two \"*\"\n\t\tmatched, err := gfile.MatchGlob(\"x**\", \"x\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"x**\", \"xyz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Pattern ending with invalid globstar that exhausts the string\n\t\tmatched, err = gfile.MatchGlob(\"abc**\", \"abc\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"abc**\", \"abcdef\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_PrefixWithWildcards(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Prefix contains wildcards - tests lines 220-236\n\t\t// Pattern: \"s*c/**/file.go\" - prefix \"s*c\" contains wildcard\n\t\tmatched, err := gfile.MatchGlob(\"s*c/**/*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"s?c/**/*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Test line 223-225: name has fewer segments than prefix\n\t\tmatched, err = gfile.MatchGlob(\"a/b/c/**\", \"a/b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\tmatched, err = gfile.MatchGlob(\"a/b/c/**/d\", \"a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Test line 232-234: wildcard prefix doesn't match\n\t\tmatched, err = gfile.MatchGlob(\"x*c/**/*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\tmatched, err = gfile.MatchGlob(\"s?x/**/*.go\", \"src/foo/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Test line 236: name update after prefix match\n\t\tmatched, err = gfile.MatchGlob(\"a*/b*/**/*.go\", \"abc/bcd/efg/main.go\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_EmptyNameWithSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test line 246-249: name becomes empty after prefix match, check if suffix can match empty\n\t\t// \"abc/**\" with name \"abc\" - after prefix match, name is empty\n\t\tmatched, err := gfile.MatchGlob(\"abc/**/\", \"abc\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// \"abc/**/d\" with name \"abc\" - after prefix match, name is empty but suffix is \"d\"\n\t\tmatched, err = gfile.MatchGlob(\"abc/**/d\", \"abc\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Test with wildcard prefix that exactly matches\n\t\tmatched, err = gfile.MatchGlob(\"a*c/**/x\", \"abc\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n\nfunc Test_MatchGlob_FindValidGlobstarExhaust(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test lines 147-152: findValidGlobstar exhausts pattern without finding valid globstar\n\t\t// Pattern with multiple invalid \"**\" that ends exactly at pattern length\n\t\tmatched, err := gfile.MatchGlob(\"a**b**\", \"ab\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"x**y**z\", \"xyz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Pattern where last \"**\" is at the very end but invalid\n\t\tmatched, err = gfile.MatchGlob(\"test**\", \"test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"test**\", \"testing\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_CacheHit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test line 166-168: cache hit scenario\n\t\t// Pattern that creates overlapping subproblems triggering cache hits\n\t\t// \"**/**\" with multiple segments will have cache hits\n\t\tmatched, err := gfile.MatchGlob(\"**/x/**/x\", \"a/x/b/x\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// This pattern specifically creates cache hits due to overlapping subproblems\n\t\t// when trying different combinations of ** matching\n\t\tmatched, err = gfile.MatchGlob(\"**/a/**/b/**/a\", \"x/a/y/b/z/a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Pattern with repeated suffix that will be checked multiple times\n\t\tmatched, err = gfile.MatchGlob(\"**/**/test\", \"a/b/c/test\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Pattern that will cause same subproblem to be solved multiple times\n\t\t// \"**/**/**\" matching \"a/b/c/d\" will have many overlapping subproblems\n\t\tmatched, err = gfile.MatchGlob(\"**/**/**/**\", \"a/b/c/d/e\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_WildcardPrefixShortName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test line 223-225: prefix with wildcards, name has fewer segments\n\t\t// Pattern: \"a*/b*/**/c\" - prefix \"a*/b*\" has 2 segments\n\t\t// Name: \"ax\" - only 1 segment\n\t\tmatched, err := gfile.MatchGlob(\"a*/b*/**/c\", \"ax\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Pattern: \"?/b/c/**/d\" - prefix \"?/b/c\" has 3 segments\n\t\t// Name: \"x/y\" - only 2 segments\n\t\tmatched, err = gfile.MatchGlob(\"?/b/c/**/d\", \"x/y\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Pattern: \"[abc]/[def]/**/x\" - prefix has 2 segments with brackets\n\t\t// Name: \"a\" - only 1 segment\n\t\tmatched, err = gfile.MatchGlob(\"[abc]/[def]/**/x\", \"a\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n\nfunc Test_MatchGlob_InvalidGlobstarInSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test lines 147-152: findValidGlobstar exhausts pattern in recursive call\n\t\t// Pattern \"a/**/b**\" - first \"**\" is valid, suffix \"b**\" has invalid \"**\" at end\n\t\t// When matching suffix \"b**\", findValidGlobstar will iterate and find \"**\" is invalid,\n\t\t// then idx = pos + 2 = 3, len(\"b**\") = 3, so idx >= len(pattern) triggers break\n\t\tmatched, err := gfile.MatchGlob(\"a/**/b**\", \"a/x/bcd\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\tmatched, err = gfile.MatchGlob(\"a/**/b**\", \"a/x/b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Pattern with valid globstar followed by suffix with invalid globstar at end\n\t\tmatched, err = gfile.MatchGlob(\"x/**/y**z\", \"x/a/yabcz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\n\t\t// Multiple invalid globstars in suffix\n\t\tmatched, err = gfile.MatchGlob(\"a/**/x**y**\", \"a/b/xcy\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, true)\n\t})\n}\n\nfunc Test_MatchGlob_MemoizationCacheHit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test line 166-168: cache hit scenario\n\t\t// To trigger cache hit, we need:\n\t\t// 1. Same (pattern, name) pair called twice\n\t\t// 2. First call must complete (not return early)\n\t\t// 3. This happens when matching FAILS and we try all combinations\n\n\t\t// Pattern \"**/**/z\" with name \"a/b/c/d\" (no match)\n\t\t// First ** tries 0,1,2,3,4 segments\n\t\t// For each, second ** tries all remaining combinations\n\t\t// This creates overlapping subproblems that fail:\n\t\t// - (\"**/z\", \"a/b/c/d\"), (\"**/z\", \"b/c/d\"), (\"**/z\", \"c/d\"), (\"**/z\", \"d\"), (\"**/z\", \"\")\n\t\t// - (\"z\", \"a/b/c/d\"), (\"z\", \"b/c/d\"), (\"z\", \"c/d\"), (\"z\", \"d\"), (\"z\", \"\")\n\t\t// When first ** matches 0: check (\"**/z\", \"a/b/c/d\")\n\t\t//   -> second ** matches 0: check (\"z\", \"a/b/c/d\") - false, cached\n\t\t//   -> second ** matches 1: check (\"z\", \"b/c/d\") - false, cached\n\t\t//   -> second ** matches 2: check (\"z\", \"c/d\") - false, cached\n\t\t//   -> second ** matches 3: check (\"z\", \"d\") - false, cached\n\t\t//   -> second ** matches 4: check (\"z\", \"\") - false, cached\n\t\t// When first ** matches 1: check (\"**/z\", \"b/c/d\")\n\t\t//   -> second ** matches 0: check (\"z\", \"b/c/d\") - CACHE HIT!\n\t\tmatched, err := gfile.MatchGlob(\"**/**/z\", \"a/b/c/d\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Another failing pattern that creates cache hits\n\t\tmatched, err = gfile.MatchGlob(\"**/**/**/notexist\", \"a/b/c/d/e\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\n\t\t// Pattern with same suffix appearing multiple times in recursion (failing case)\n\t\tmatched, err = gfile.MatchGlob(\"**/x/**/x/**/x\", \"a/b/c/d/e/f\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(matched, false)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_replace_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_ReplaceFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfileName = \"/testfile_replace_\" + gconv.String(gtime.TimestampNano()) + \".txt\"\n\t\t\tcontent  = \"hello world\"\n\t\t)\n\t\tcreateTestFile(fileName, content)\n\t\tdefer delTestFiles(fileName)\n\n\t\t// Test basic replacement\n\t\terr := gfile.ReplaceFile(\"world\", \"gf\", testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"hello gf\")\n\n\t\t// Test replacement with non-existent search string\n\t\terr = gfile.ReplaceFile(\"notexist\", \"replaced\", testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"hello gf\")\n\n\t\t// Test multiple occurrences replacement\n\t\terr = gfile.PutContents(testpath()+fileName, \"hello hello hello\")\n\t\tt.AssertNil(err)\n\t\terr = gfile.ReplaceFile(\"hello\", \"hi\", testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"hi hi hi\")\n\t})\n}\n\nfunc Test_ReplaceFileFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfileName = \"/testfile_replacefunc_\" + gconv.String(gtime.TimestampNano()) + \".txt\"\n\t\t\tcontent  = \"hello world\"\n\t\t)\n\t\tcreateTestFile(fileName, content)\n\t\tdefer delTestFiles(fileName)\n\n\t\t// Test replacement with callback function\n\t\terr := gfile.ReplaceFileFunc(func(path, content string) string {\n\t\t\tt.Assert(gfile.Basename(path), gfile.Basename(fileName))\n\t\t\treturn content + \" - modified\"\n\t\t}, testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"hello world - modified\")\n\t})\n\n\t// Test when callback returns same content (no write should happen)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfileName = \"/testfile_replacefunc2_\" + gconv.String(gtime.TimestampNano()) + \".txt\"\n\t\t\tcontent  = \"unchanged content\"\n\t\t)\n\t\tcreateTestFile(fileName, content)\n\t\tdefer delTestFiles(fileName)\n\n\t\terr := gfile.ReplaceFileFunc(func(path, content string) string {\n\t\t\treturn content // Return same content\n\t\t}, testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"unchanged content\")\n\t})\n\n\t// Test callback with path parameter\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfileName = \"/testfile_replacefunc3_\" + gconv.String(gtime.TimestampNano()) + \".txt\"\n\t\t\tcontent  = \"test content\"\n\t\t)\n\t\tcreateTestFile(fileName, content)\n\t\tdefer delTestFiles(fileName)\n\n\t\tvar receivedPath string\n\t\terr := gfile.ReplaceFileFunc(func(path, content string) string {\n\t\t\treceivedPath = path\n\t\t\treturn \"new content\"\n\t\t}, testpath()+fileName)\n\t\tt.AssertNil(err)\n\t\tt.Assert(receivedPath, testpath()+fileName)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"new content\")\n\t})\n}\n\nfunc Test_ReplaceDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName  = \"/testdir_replace_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName = dirName + \"/test.txt\"\n\t\t\tcontent  = \"hello world\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateTestFile(fileName, content)\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Test directory replacement with pattern\n\t\terr := gfile.ReplaceDir(\"world\", \"gf\", testpath()+dirName, \"*.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName), \"hello gf\")\n\t})\n\n\t// Test recursive replacement\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName    = \"/testdir_replace_recursive_\" + gconv.String(gtime.TimestampNano())\n\t\t\tsubDirName = dirName + \"/subdir\"\n\t\t\tfileName1  = dirName + \"/test1.txt\"\n\t\t\tfileName2  = subDirName + \"/test2.txt\"\n\t\t\tcontent    = \"hello world\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateDir(subDirName)\n\t\tcreateTestFile(fileName1, content)\n\t\tcreateTestFile(fileName2, content)\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Non-recursive replacement\n\t\terr := gfile.ReplaceDir(\"world\", \"gf\", testpath()+dirName, \"*.txt\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"hello gf\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"hello world\") // Should not be changed\n\n\t\t// Reset content\n\t\terr = gfile.PutContents(testpath()+fileName1, content)\n\t\tt.AssertNil(err)\n\n\t\t// Recursive replacement\n\t\terr = gfile.ReplaceDir(\"world\", \"gf\", testpath()+dirName, \"*.txt\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"hello gf\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"hello gf\")\n\t})\n\n\t// Test with pattern matching\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName   = \"/testdir_replace_pattern_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName1 = dirName + \"/test.txt\"\n\t\t\tfileName2 = dirName + \"/test.log\"\n\t\t\tcontent   = \"hello world\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateTestFile(fileName1, content)\n\t\tcreateTestFile(fileName2, content)\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Only replace in .txt files\n\t\terr := gfile.ReplaceDir(\"world\", \"gf\", testpath()+dirName, \"*.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"hello gf\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"hello world\") // .log should not be changed\n\t})\n\n\t// Test with non-existent directory\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gfile.ReplaceDir(\"search\", \"replace\", \"/nonexistent_dir_12345\", \"*.txt\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceDirFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName   = \"/testdir_replacefunc_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName1 = dirName + \"/test1.txt\"\n\t\t\tfileName2 = dirName + \"/test2.txt\"\n\t\t\tcontent1  = \"content1\"\n\t\t\tcontent2  = \"content2\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateTestFile(fileName1, content1)\n\t\tcreateTestFile(fileName2, content2)\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Test directory replacement with callback function\n\t\tprocessedFiles := make(map[string]bool)\n\t\terr := gfile.ReplaceDirFunc(func(path, content string) string {\n\t\t\tprocessedFiles[gfile.Basename(path)] = true\n\t\t\treturn content + \" - modified\"\n\t\t}, testpath()+dirName, \"*.txt\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"content1 - modified\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"content2 - modified\")\n\t\tt.Assert(processedFiles[\"test1.txt\"], true)\n\t\tt.Assert(processedFiles[\"test2.txt\"], true)\n\t})\n\n\t// Test recursive replacement with callback\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName    = \"/testdir_replacefunc_recursive_\" + gconv.String(gtime.TimestampNano())\n\t\t\tsubDirName = dirName + \"/subdir\"\n\t\t\tfileName1  = dirName + \"/test1.txt\"\n\t\t\tfileName2  = subDirName + \"/test2.txt\"\n\t\t\tcontent    = \"original\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateDir(subDirName)\n\t\tcreateTestFile(fileName1, content)\n\t\tcreateTestFile(fileName2, content)\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Non-recursive\n\t\terr := gfile.ReplaceDirFunc(func(path, content string) string {\n\t\t\treturn \"changed\"\n\t\t}, testpath()+dirName, \"*.txt\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"changed\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"original\") // Should not be changed\n\n\t\t// Reset\n\t\terr = gfile.PutContents(testpath()+fileName1, content)\n\t\tt.AssertNil(err)\n\n\t\t// Recursive\n\t\terr = gfile.ReplaceDirFunc(func(path, content string) string {\n\t\t\treturn \"changed\"\n\t\t}, testpath()+dirName, \"*.txt\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.GetContents(testpath()+fileName1), \"changed\")\n\t\tt.Assert(gfile.GetContents(testpath()+fileName2), \"changed\")\n\t})\n\n\t// Test with non-existent directory\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gfile.ReplaceDirFunc(func(path, content string) string {\n\t\t\treturn content\n\t\t}, \"/nonexistent_dir_12345\", \"*.txt\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_scan_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ScanDir(t *testing.T) {\n\tteatPath := gtest.DataPath()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles, err := gfile.ScanDir(teatPath, \"*\", false)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir1\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir2\", files)\n\t\tt.AssertNE(teatPath+gfile.Separator+\"dir1\"+gfile.Separator+\"file1\", files)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles, err := gfile.ScanDir(teatPath, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir1\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir2\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir1\"+gfile.Separator+\"file1\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir2\"+gfile.Separator+\"file2\", files)\n\t})\n}\n\nfunc Test_ScanDirFunc(t *testing.T) {\n\tteatPath := gtest.DataPath()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles, err := gfile.ScanDirFunc(teatPath, \"*\", true, func(path string) string {\n\t\t\tif gfile.Name(path) != \"file1\" {\n\t\t\t\treturn \"\"\n\t\t\t}\n\t\t\treturn path\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 1)\n\t\tt.Assert(gfile.Name(files[0]), \"file1\")\n\t})\n}\n\nfunc Test_ScanDirFile(t *testing.T) {\n\tteatPath := gtest.DataPath()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles, err := gfile.ScanDirFile(teatPath, \"*\", false)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles, err := gfile.ScanDirFile(teatPath, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.AssertNI(teatPath+gfile.Separator+\"dir1\", files)\n\t\tt.AssertNI(teatPath+gfile.Separator+\"dir2\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir1\"+gfile.Separator+\"file1\", files)\n\t\tt.AssertIN(teatPath+gfile.Separator+\"dir2\"+gfile.Separator+\"file2\", files)\n\t})\n}\n\nfunc Test_ScanDirFileFunc(t *testing.T) {\n\tteatPath := gtest.DataPath()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New()\n\t\tfiles, err := gfile.ScanDirFileFunc(teatPath, \"*\", false, func(path string) string {\n\t\t\tarray.Append(1)\n\t\t\treturn path\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\t\tt.Assert(array.Len(), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New()\n\t\tfiles, err := gfile.ScanDirFileFunc(teatPath, \"*\", true, func(path string) string {\n\t\t\tarray.Append(1)\n\t\t\tif gfile.Basename(path) == \"file1\" {\n\t\t\t\treturn path\n\t\t\t}\n\t\t\treturn \"\"\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 1)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_search_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Search(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1  string = \"/testfiless\"\n\t\t\tpaths2  string = \"./testfile/dirfiles_no\"\n\t\t\ttpath   string\n\t\t\ttpath2  string\n\t\t\ttempstr string\n\t\t\typaths1 string\n\t\t\terr     error\n\t\t)\n\n\t\tcreateDir(paths1)\n\t\tdefer delTestFiles(paths1)\n\t\typaths1 = paths1\n\n\t\ttpath, err = gfile.Search(testpath() + paths1)\n\t\tt.AssertNil(err)\n\n\t\ttpath = filepath.ToSlash(tpath)\n\n\t\t// 自定义优先路径\n\t\ttpath2, err = gfile.Search(testpath() + paths1)\n\t\tt.AssertNil(err)\n\t\ttpath2 = filepath.ToSlash(tpath2)\n\n\t\ttempstr = testpath()\n\t\tpaths1 = tempstr + paths1\n\t\tpaths1 = filepath.ToSlash(paths1)\n\n\t\tt.Assert(tpath, paths1)\n\n\t\tt.Assert(tpath2, tpath)\n\n\t\t// 测试给定目录\n\t\ttpath2, err = gfile.Search(paths1, \"testfiless\")\n\t\ttpath2 = filepath.ToSlash(tpath2)\n\t\ttempss := filepath.ToSlash(paths1)\n\t\tt.Assert(tpath2, tempss)\n\n\t\t// 测试当前目录\n\t\ttempstr, _ = filepath.Abs(\"./\")\n\t\ttempstr = testpath()\n\t\tpaths1 = tempstr + ypaths1\n\t\tpaths1 = filepath.ToSlash(paths1)\n\n\t\tt.Assert(tpath2, paths1)\n\n\t\t// 测试目录不存在时\n\t\t_, err = gfile.Search(paths2)\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_size_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1 string = \"/testfile_t1.txt\"\n\t\t\tsizes  int64\n\t\t)\n\n\t\tcreateTestFile(paths1, \"abcdefghijklmn\")\n\t\tdefer delTestFiles(paths1)\n\n\t\tsizes = gfile.Size(testpath() + paths1)\n\t\tt.Assert(sizes, 14)\n\n\t\tsizes = gfile.Size(\"\")\n\t\tt.Assert(sizes, 0)\n\n\t})\n}\n\nfunc Test_SizeFormat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1 = \"/testfile_t1.txt\"\n\t\t\tsizes  string\n\t\t)\n\n\t\tcreateTestFile(paths1, \"abcdefghijklmn\")\n\t\tdefer delTestFiles(paths1)\n\n\t\tsizes = gfile.SizeFormat(testpath() + paths1)\n\t\tt.Assert(sizes, \"14.00B\")\n\n\t\tsizes = gfile.SizeFormat(\"\")\n\t\tt.Assert(sizes, \"0.00B\")\n\n\t})\n}\n\nfunc Test_StrToSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gfile.StrToSize(\"0.00B\"), 0)\n\t\tt.Assert(gfile.StrToSize(\"16.00B\"), 16)\n\t\tt.Assert(gfile.StrToSize(\"1.00K\"), 1024)\n\t\tt.Assert(gfile.StrToSize(\"1.00KB\"), 1024)\n\t\tt.Assert(gfile.StrToSize(\"1.00KiloByte\"), 1024)\n\t\tt.Assert(gfile.StrToSize(\"15.26M\"), gconv.Int64(15.26*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"15.26MB\"), gconv.Int64(15.26*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"1.49G\"), gconv.Int64(1.49*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"1.49GB\"), gconv.Int64(1.49*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"8.73T\"), gconv.Int64(8.73*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"8.73TB\"), gconv.Int64(8.73*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"8.53P\"), gconv.Int64(8.53*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"8.53PB\"), gconv.Int64(8.53*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"8.01EB\"), gconv.Int64(8.01*1024*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"0.01ZB\"), gconv.Int64(0.01*1024*1024*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"0.01YB\"), gconv.Int64(0.01*1024*1024*1024*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"0.01BB\"), gconv.Int64(0.01*1024*1024*1024*1024*1024*1024*1024*1024*1024))\n\t\tt.Assert(gfile.StrToSize(\"0.01AB\"), gconv.Int64(-1))\n\t\tt.Assert(gfile.StrToSize(\"123456789\"), 123456789)\n\t})\n}\n\nfunc Test_FormatSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gfile.FormatSize(0), \"0.00B\")\n\t\tt.Assert(gfile.FormatSize(16), \"16.00B\")\n\n\t\tt.Assert(gfile.FormatSize(1024), \"1.00K\")\n\n\t\tt.Assert(gfile.FormatSize(16000000), \"15.26M\")\n\n\t\tt.Assert(gfile.FormatSize(1600000000), \"1.49G\")\n\n\t\tt.Assert(gfile.FormatSize(9600000000000), \"8.73T\")\n\t\tt.Assert(gfile.FormatSize(9600000000000000), \"8.53P\")\n\t})\n}\n\nfunc Test_ReadableSize(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tvar (\n\t\t\tpaths1 string = \"/testfile_t1.txt\"\n\t\t)\n\t\tcreateTestFile(paths1, \"abcdefghijklmn\")\n\t\tdefer delTestFiles(paths1)\n\t\tt.Assert(gfile.ReadableSize(testpath()+paths1), \"14.00B\")\n\t\tt.Assert(gfile.ReadableSize(\"\"), \"0.00B\")\n\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_sort_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_SortFiles(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName   = \"/testdir_sort_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName1 = dirName + \"/b.txt\"\n\t\t\tfileName2 = dirName + \"/a.txt\"\n\t\t\tsubDir1   = dirName + \"/subdir_b\"\n\t\t\tsubDir2   = dirName + \"/subdir_a\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateDir(subDir1)\n\t\tcreateDir(subDir2)\n\t\tcreateTestFile(fileName1, \"\")\n\t\tcreateTestFile(fileName2, \"\")\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Test sorting: directories should come before files, then sorted alphabetically\n\t\tfiles := []string{\n\t\t\ttestpath() + fileName1,\n\t\t\ttestpath() + fileName2,\n\t\t\ttestpath() + subDir1,\n\t\t\ttestpath() + subDir2,\n\t\t}\n\t\tsorted := gfile.SortFiles(files)\n\n\t\t// Directories should come first, sorted alphabetically\n\t\tt.Assert(sorted[0], testpath()+subDir2) // subdir_a\n\t\tt.Assert(sorted[1], testpath()+subDir1) // subdir_b\n\t\t// Files should come after, sorted alphabetically\n\t\tt.Assert(sorted[2], testpath()+fileName2) // a.txt\n\t\tt.Assert(sorted[3], testpath()+fileName1) // b.txt\n\t})\n\n\t// Test with only files\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName   = \"/testdir_sort_files_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName1 = dirName + \"/c.txt\"\n\t\t\tfileName2 = dirName + \"/a.txt\"\n\t\t\tfileName3 = dirName + \"/b.txt\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateTestFile(fileName1, \"\")\n\t\tcreateTestFile(fileName2, \"\")\n\t\tcreateTestFile(fileName3, \"\")\n\t\tdefer delTestFiles(dirName)\n\n\t\tfiles := []string{\n\t\t\ttestpath() + fileName1,\n\t\t\ttestpath() + fileName2,\n\t\t\ttestpath() + fileName3,\n\t\t}\n\t\tsorted := gfile.SortFiles(files)\n\n\t\tt.Assert(sorted[0], testpath()+fileName2) // a.txt\n\t\tt.Assert(sorted[1], testpath()+fileName3) // b.txt\n\t\tt.Assert(sorted[2], testpath()+fileName1) // c.txt\n\t})\n\n\t// Test with only directories\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName = \"/testdir_sort_dirs_\" + gconv.String(gtime.TimestampNano())\n\t\t\tsubDir1 = dirName + \"/c_dir\"\n\t\t\tsubDir2 = dirName + \"/a_dir\"\n\t\t\tsubDir3 = dirName + \"/b_dir\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateDir(subDir1)\n\t\tcreateDir(subDir2)\n\t\tcreateDir(subDir3)\n\t\tdefer delTestFiles(dirName)\n\n\t\tfiles := []string{\n\t\t\ttestpath() + subDir1,\n\t\t\ttestpath() + subDir2,\n\t\t\ttestpath() + subDir3,\n\t\t}\n\t\tsorted := gfile.SortFiles(files)\n\n\t\tt.Assert(sorted[0], testpath()+subDir2) // a_dir\n\t\tt.Assert(sorted[1], testpath()+subDir3) // b_dir\n\t\tt.Assert(sorted[2], testpath()+subDir1) // c_dir\n\t})\n\n\t// Test with empty slice\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfiles := []string{}\n\t\tsorted := gfile.SortFiles(files)\n\t\tt.Assert(len(sorted), 0)\n\t})\n\n\t// Test with single element\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName  = \"/testdir_sort_single_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName = dirName + \"/single.txt\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateTestFile(fileName, \"\")\n\t\tdefer delTestFiles(dirName)\n\n\t\tfiles := []string{testpath() + fileName}\n\t\tsorted := gfile.SortFiles(files)\n\n\t\tt.Assert(len(sorted), 1)\n\t\tt.Assert(sorted[0], testpath()+fileName)\n\t})\n\n\t// Test with mixed paths (some may not exist - testing sort behavior)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tdirName  = \"/testdir_sort_mixed_\" + gconv.String(gtime.TimestampNano())\n\t\t\tfileName = dirName + \"/existing.txt\"\n\t\t\tsubDir   = dirName + \"/existing_dir\"\n\t\t)\n\t\tcreateDir(dirName)\n\t\tcreateDir(subDir)\n\t\tcreateTestFile(fileName, \"\")\n\t\tdefer delTestFiles(dirName)\n\n\t\t// Mix of existing dir, existing file\n\t\tfiles := []string{\n\t\t\ttestpath() + fileName,\n\t\t\ttestpath() + subDir,\n\t\t}\n\t\tsorted := gfile.SortFiles(files)\n\n\t\t// Directory should come first\n\t\tt.Assert(sorted[0], testpath()+subDir)\n\t\tt.Assert(sorted[1], testpath()+fileName)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_IsDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpaths := \"/testfile\"\n\t\tcreateDir(paths)\n\t\tdefer delTestFiles(paths)\n\n\t\tt.Assert(gfile.IsDir(testpath()+paths), true)\n\t\tt.Assert(gfile.IsDir(\"./testfile2\"), false)\n\t\tt.Assert(gfile.IsDir(\"./testfile/tt.txt\"), false)\n\t\tt.Assert(gfile.IsDir(\"\"), false)\n\t})\n}\n\nfunc Test_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"/testdir_\" + gconv.String(gtime.TimestampNano())\n\t\tcreateDir(path)\n\t\tdefer delTestFiles(path)\n\n\t\tt.Assert(gfile.IsEmpty(testpath()+path), true)\n\t\tt.Assert(gfile.IsEmpty(testpath()+path+gfile.Separator+\"test.txt\"), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"/testfile_\" + gconv.String(gtime.TimestampNano())\n\t\tcreateTestFile(path, \"\")\n\t\tdefer delTestFiles(path)\n\n\t\tt.Assert(gfile.IsEmpty(testpath()+path), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"/testfile_\" + gconv.String(gtime.TimestampNano())\n\t\tcreateTestFile(path, \"1\")\n\t\tdefer delTestFiles(path)\n\n\t\tt.Assert(gfile.IsEmpty(testpath()+path), false)\n\t})\n}\n\nfunc Test_Create(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr       error\n\t\t\tfilepaths []string\n\t\t\tfileobj   *os.File\n\t\t)\n\t\tfilepaths = append(filepaths, \"/testfile_cc1.txt\")\n\t\tfilepaths = append(filepaths, \"/testfile_cc2.txt\")\n\t\tfor _, v := range filepaths {\n\t\t\tfileobj, err = gfile.Create(testpath() + v)\n\t\t\tdefer delTestFiles(v)\n\t\t\tfileobj.Close()\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttmpPath := gfile.Join(gfile.Temp(), \"test/testfile_cc1.txt\")\n\t\tfileobj, err := gfile.Create(tmpPath)\n\t\tdefer gfile.Remove(tmpPath)\n\t\tt.AssertNE(fileobj, nil)\n\t\tt.AssertNil(err)\n\t\tfileobj.Close()\n\t})\n}\n\nfunc Test_Open(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tfiles   []string\n\t\t\tflags   []bool\n\t\t\tfileobj *os.File\n\t\t)\n\n\t\tfile1 := \"/testfile_nc1.txt\"\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\n\t\tfiles = append(files, file1)\n\t\tflags = append(flags, true)\n\n\t\tfiles = append(files, \"./testfile/file1/c1.txt\")\n\t\tflags = append(flags, false)\n\n\t\tfor k, v := range files {\n\t\t\tfileobj, err = gfile.Open(testpath() + v)\n\t\t\tfileobj.Close()\n\t\t\tif flags[k] {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_OpenFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tfiles   []string\n\t\t\tflags   []bool\n\t\t\tfileobj *os.File\n\t\t)\n\n\t\tfiles = append(files, \"./testfile/file1/nc1.txt\")\n\t\tflags = append(flags, false)\n\n\t\tf1 := \"/testfile_tt.txt\"\n\t\tcreateTestFile(f1, \"\")\n\t\tdefer delTestFiles(f1)\n\n\t\tfiles = append(files, f1)\n\t\tflags = append(flags, true)\n\n\t\tfor k, v := range files {\n\t\t\tfileobj, err = gfile.OpenFile(testpath()+v, os.O_RDWR, 0666)\n\t\t\tfileobj.Close()\n\t\t\tif flags[k] {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_OpenWithFlag(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tfiles   []string\n\t\t\tflags   []bool\n\t\t\tfileobj *os.File\n\t\t)\n\n\t\tfile1 := \"/testfile_t1.txt\"\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfiles = append(files, file1)\n\t\tflags = append(flags, true)\n\n\t\tfiles = append(files, \"/testfiless/dirfiles/t1_no.txt\")\n\t\tflags = append(flags, false)\n\n\t\tfor k, v := range files {\n\t\t\tfileobj, err = gfile.OpenWithFlag(testpath()+v, os.O_RDWR)\n\t\t\tfileobj.Close()\n\t\t\tif flags[k] {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_OpenWithFlagPerm(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tfiles   []string\n\t\t\tflags   []bool\n\t\t\tfileobj *os.File\n\t\t)\n\t\tfile1 := \"/testfile_nc1.txt\"\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfiles = append(files, file1)\n\t\tflags = append(flags, true)\n\n\t\tfiles = append(files, \"/testfileyy/tt.txt\")\n\t\tflags = append(flags, false)\n\n\t\tfor k, v := range files {\n\t\t\tfileobj, err = gfile.OpenWithFlagPerm(testpath()+v, os.O_RDWR, 0666)\n\t\t\tfileobj.Close()\n\t\t\tif flags[k] {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_Exists(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tflag  bool\n\t\t\tfiles []string\n\t\t\tflags []bool\n\t\t)\n\n\t\tfile1 := \"/testfile_GetContents.txt\"\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\n\t\tfiles = append(files, file1)\n\t\tflags = append(flags, true)\n\n\t\tfiles = append(files, \"./testfile/havefile1/tt_no.txt\")\n\t\tflags = append(flags, false)\n\n\t\tfor k, v := range files {\n\t\t\tflag = gfile.Exists(testpath() + v)\n\t\t\tif flags[k] {\n\t\t\t\tt.Assert(flag, true)\n\t\t\t} else {\n\t\t\t\tt.Assert(flag, false)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_Pwd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpaths, err := os.Getwd()\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Pwd(), paths)\n\n\t})\n}\n\nfunc Test_IsFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tflag  bool\n\t\t\tfiles []string\n\t\t\tflags []bool\n\t\t)\n\n\t\tfile1 := \"/testfile_tt.txt\"\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfiles = append(files, file1)\n\t\tflags = append(flags, true)\n\n\t\tdir1 := \"/testfiless\"\n\t\tcreateDir(dir1)\n\t\tdefer delTestFiles(dir1)\n\t\tfiles = append(files, dir1)\n\t\tflags = append(flags, false)\n\n\t\tfiles = append(files, \"./testfiledd/tt1.txt\")\n\t\tflags = append(flags, false)\n\n\t\tfor k, v := range files {\n\t\t\tflag = gfile.IsFile(testpath() + v)\n\t\t\tif flags[k] {\n\t\t\t\tt.Assert(flag, true)\n\t\t\t} else {\n\t\t\t\tt.Assert(flag, false)\n\t\t\t}\n\n\t\t}\n\n\t})\n}\n\nfunc Test_Info(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tpaths  string = \"/testfile_t1.txt\"\n\t\t\tfiles  os.FileInfo\n\t\t\tfiles2 os.FileInfo\n\t\t)\n\n\t\tcreateTestFile(paths, \"\")\n\t\tdefer delTestFiles(paths)\n\t\tfiles, err = gfile.Stat(testpath() + paths)\n\t\tt.AssertNil(err)\n\n\t\tfiles2, err = os.Stat(testpath() + paths)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(files, files2)\n\n\t})\n}\n\nfunc Test_Move(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths     string = \"/ovetest\"\n\t\t\tfilepaths string = \"/testfile_ttn1.txt\"\n\t\t\ttopath    string = \"/testfile_ttn2.txt\"\n\t\t)\n\t\tcreateDir(\"/ovetest\")\n\t\tcreateTestFile(paths+filepaths, \"a\")\n\n\t\tdefer delTestFiles(paths)\n\n\t\tyfile := testpath() + paths + filepaths\n\t\ttofile := testpath() + paths + topath\n\n\t\tt.Assert(gfile.Move(yfile, tofile), nil)\n\n\t\t// 检查移动后的文件是否真实存在\n\t\t_, err := os.Stat(tofile)\n\t\tt.Assert(os.IsNotExist(err), false)\n\n\t})\n}\n\nfunc Test_Rename(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths  string = \"/testfiles\"\n\t\t\typath  string = \"/testfilettm1.txt\"\n\t\t\ttopath string = \"/testfilettm2.txt\"\n\t\t)\n\t\tcreateDir(paths)\n\t\tcreateTestFile(paths+ypath, \"a\")\n\t\tdefer delTestFiles(paths)\n\n\t\typath = testpath() + paths + ypath\n\t\ttopath = testpath() + paths + topath\n\n\t\tt.Assert(gfile.Rename(ypath, topath), nil)\n\t\tt.Assert(gfile.IsFile(topath), true)\n\n\t\tt.AssertNE(gfile.Rename(\"\", \"\"), nil)\n\n\t})\n\n}\n\nfunc Test_DirNames(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths    string = \"/testdirs\"\n\t\t\terr      error\n\t\t\treadlist []string\n\t\t)\n\t\thavelist := []string{\n\t\t\t\"t1.txt\",\n\t\t\t\"t2.txt\",\n\t\t}\n\n\t\t// 创建测试文件\n\t\tcreateDir(paths)\n\t\tfor _, v := range havelist {\n\t\t\tcreateTestFile(paths+\"/\"+v, \"\")\n\t\t}\n\t\tdefer delTestFiles(paths)\n\n\t\treadlist, err = gfile.DirNames(testpath() + paths)\n\n\t\tt.AssertNil(err)\n\t\tt.AssertIN(readlist, havelist)\n\n\t\t_, err = gfile.DirNames(\"\")\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_Glob(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths      string = \"/testfiles/*.txt\"\n\t\t\tdirpath    string = \"/testfiles\"\n\t\t\terr        error\n\t\t\tresultlist []string\n\t\t)\n\n\t\thavelist1 := []string{\n\t\t\t\"t1.txt\",\n\t\t\t\"t2.txt\",\n\t\t}\n\n\t\thavelist2 := []string{\n\t\t\ttestpath() + \"/testfiles/t1.txt\",\n\t\t\ttestpath() + \"/testfiles/t2.txt\",\n\t\t}\n\n\t\t// ===============================构建测试文件\n\t\tcreateDir(dirpath)\n\t\tfor _, v := range havelist1 {\n\t\t\tcreateTestFile(dirpath+\"/\"+v, \"\")\n\t\t}\n\t\tdefer delTestFiles(dirpath)\n\n\t\tresultlist, err = gfile.Glob(testpath()+paths, true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(resultlist, havelist1)\n\n\t\tresultlist, err = gfile.Glob(testpath()+paths, false)\n\n\t\tt.AssertNil(err)\n\t\tt.Assert(formatpaths(resultlist), formatpaths(havelist2))\n\n\t\t_, err = gfile.Glob(\"\", true)\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_Remove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths string = \"/testfile_t1.txt\"\n\t\t)\n\t\tcreateTestFile(paths, \"\")\n\t\tt.Assert(gfile.Remove(testpath()+paths), nil)\n\n\t\tt.Assert(gfile.Remove(\"\"), nil)\n\n\t\tdefer delTestFiles(paths)\n\n\t})\n}\n\nfunc Test_IsReadable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1 string = \"/testfile_GetContents.txt\"\n\t\t\tpaths2 string = \"./testfile_GetContents_no.txt\"\n\t\t)\n\n\t\tcreateTestFile(paths1, \"\")\n\t\tdefer delTestFiles(paths1)\n\n\t\tt.Assert(gfile.IsReadable(testpath()+paths1), true)\n\t\tt.Assert(gfile.IsReadable(paths2), false)\n\n\t})\n}\n\nfunc Test_IsWritable(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1 string = \"/testfile_GetContents.txt\"\n\t\t\tpaths2 string = \"./testfile_GetContents_no.txt\"\n\t\t)\n\n\t\tcreateTestFile(paths1, \"\")\n\t\tdefer delTestFiles(paths1)\n\t\tt.Assert(gfile.IsWritable(testpath()+paths1), true)\n\t\tt.Assert(gfile.IsWritable(paths2), false)\n\n\t})\n}\n\nfunc Test_Chmod(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1 string = \"/testfile_GetContents.txt\"\n\t\t\tpaths2 string = \"./testfile_GetContents_no.txt\"\n\t\t)\n\t\tcreateTestFile(paths1, \"\")\n\t\tdefer delTestFiles(paths1)\n\n\t\tt.Assert(gfile.Chmod(testpath()+paths1, 0777), nil)\n\t\tt.AssertNE(gfile.Chmod(paths2, 0777), nil)\n\n\t})\n}\n\n// 获取绝对目录地址\nfunc Test_RealPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1    string = \"/testfile_files\"\n\t\t\treadlPath string\n\n\t\t\ttempstr string\n\t\t)\n\n\t\tcreateDir(paths1)\n\t\tdefer delTestFiles(paths1)\n\n\t\treadlPath = gfile.RealPath(\"./\")\n\n\t\ttempstr, _ = filepath.Abs(\"./\")\n\n\t\tt.Assert(readlPath, tempstr)\n\n\t\tt.Assert(gfile.RealPath(\"./nodirs\"), \"\")\n\n\t})\n}\n\n// 获取当前执行文件的目录\nfunc Test_SelfPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1    string\n\t\t\treadlPath string\n\t\t\ttempstr   string\n\t\t)\n\t\treadlPath = gfile.SelfPath()\n\t\treadlPath = filepath.ToSlash(readlPath)\n\n\t\ttempstr, _ = filepath.Abs(os.Args[0])\n\t\tpaths1 = filepath.ToSlash(tempstr)\n\t\tpaths1 = strings.Replace(paths1, \"./\", \"/\", 1)\n\n\t\tt.Assert(readlPath, paths1)\n\n\t})\n}\n\nfunc Test_SelfDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1    string\n\t\t\treadlPath string\n\t\t\ttempstr   string\n\t\t)\n\t\treadlPath = gfile.SelfDir()\n\n\t\ttempstr, _ = filepath.Abs(os.Args[0])\n\t\tpaths1 = filepath.Dir(tempstr)\n\n\t\tt.Assert(readlPath, paths1)\n\n\t})\n}\n\nfunc Test_Basename(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1    string = \"/testfilerr_GetContents.txt\"\n\t\t\treadlPath string\n\t\t)\n\n\t\tcreateTestFile(paths1, \"\")\n\t\tdefer delTestFiles(paths1)\n\n\t\treadlPath = gfile.Basename(testpath() + paths1)\n\t\tt.Assert(readlPath, \"testfilerr_GetContents.txt\")\n\n\t})\n}\n\nfunc Test_Dir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1    string = \"/testfiless\"\n\t\t\treadlPath string\n\t\t)\n\t\tcreateDir(paths1)\n\t\tdefer delTestFiles(paths1)\n\n\t\treadlPath = gfile.Dir(testpath() + paths1)\n\n\t\tt.Assert(readlPath, testpath())\n\n\t\tt.Assert(len(gfile.Dir(\".\")) > 0, true)\n\t})\n}\n\nfunc Test_Ext(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tpaths1   string = \"/testfile_GetContents.txt\"\n\t\t\tdirpath1        = \"/testdirs\"\n\t\t)\n\t\tcreateTestFile(paths1, \"\")\n\t\tdefer delTestFiles(paths1)\n\n\t\tcreateDir(dirpath1)\n\t\tdefer delTestFiles(dirpath1)\n\n\t\tt.Assert(gfile.Ext(testpath()+paths1), \".txt\")\n\t\tt.Assert(gfile.Ext(testpath()+dirpath1), \"\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gfile.Ext(\"/var/www/test.js\"), \".js\")\n\t\tt.Assert(gfile.Ext(\"/var/www/test.min.js\"), \".js\")\n\t\tt.Assert(gfile.Ext(\"/var/www/test.js?1\"), \".js\")\n\t\tt.Assert(gfile.Ext(\"/var/www/test.min.js?v1\"), \".js\")\n\t})\n}\n\nfunc Test_ExtName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gfile.ExtName(\"/var/www/test.js\"), \"js\")\n\t\tt.Assert(gfile.ExtName(\"/var/www/test.min.js\"), \"js\")\n\t\tt.Assert(gfile.ExtName(\"/var/www/test.js?v=1\"), \"js\")\n\t\tt.Assert(gfile.ExtName(\"/var/www/test.min.js?v=1\"), \"js\")\n\t})\n}\n\nfunc Test_TempDir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gfile.Temp(), os.TempDir())\n\t})\n}\n\nfunc Test_Mkdir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttpath string = \"/testfile/createdir\"\n\t\t\terr   error\n\t\t)\n\n\t\tdefer delTestFiles(\"/testfile\")\n\n\t\terr = gfile.Mkdir(testpath() + tpath)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.Mkdir(\"\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gfile.Mkdir(testpath() + tpath + \"2/t1\")\n\t\tt.AssertNil(err)\n\n\t})\n}\n\nfunc Test_Stat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ttpath1   = \"/testfile_t1.txt\"\n\t\t\ttpath2   = \"./testfile_t1_no.txt\"\n\t\t\terr      error\n\t\t\tfileiofo os.FileInfo\n\t\t)\n\n\t\tcreateTestFile(tpath1, \"a\")\n\t\tdefer delTestFiles(tpath1)\n\n\t\tfileiofo, err = gfile.Stat(testpath() + tpath1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(fileiofo.Size(), 1)\n\n\t\t_, err = gfile.Stat(tpath2)\n\t\tt.AssertNE(err, nil)\n\n\t})\n}\n\nfunc Test_MainPkgPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\treads := gfile.MainPkgPath()\n\t\tt.Assert(reads, \"\")\n\t})\n}\n\nfunc Test_SelfName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(gfile.SelfName()) > 0, true)\n\t})\n}\n\nfunc Test_RemoveFile_RemoveAll(t *testing.T) {\n\t// safe deleting single file.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(guid.S())\n\t\terr := gfile.PutContents(path, \"1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(path), true)\n\n\t\terr = gfile.RemoveFile(path)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(path), false)\n\t})\n\t// error deleting dir which is not empty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr       error\n\t\t\tdirPath   = gfile.Temp(guid.S())\n\t\t\tfilePath1 = gfile.Join(dirPath, guid.S())\n\t\t\tfilePath2 = gfile.Join(dirPath, guid.S())\n\t\t)\n\t\terr = gfile.PutContents(filePath1, \"1\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(filePath1), true)\n\n\t\terr = gfile.PutContents(filePath2, \"2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(filePath2), true)\n\n\t\terr = gfile.RemoveFile(dirPath)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gfile.Exists(filePath1), true)\n\t\tt.Assert(gfile.Exists(filePath2), true)\n\n\t\terr = gfile.RemoveAll(dirPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Exists(filePath1), false)\n\t\tt.Assert(gfile.Exists(filePath2), false)\n\t})\n}\n\nfunc Test_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Basic join\n\t\tt.Assert(gfile.Join(\"a\", \"b\", \"c\"), \"a\"+gfile.Separator+\"b\"+gfile.Separator+\"c\")\n\n\t\t// Join with trailing separator\n\t\tt.Assert(gfile.Join(\"a\"+gfile.Separator, \"b\"), \"a\"+gfile.Separator+\"b\")\n\n\t\t// Join with empty string\n\t\tt.Assert(gfile.Join(\"\", \"a\", \"b\"), \"a\"+gfile.Separator+\"b\")\n\n\t\t// Join single path\n\t\tt.Assert(gfile.Join(\"single\"), \"single\")\n\n\t\t// Join with absolute path\n\t\tt.Assert(gfile.Join(gfile.Separator+\"root\", \"path\"), gfile.Separator+\"root\"+gfile.Separator+\"path\")\n\n\t\t// Join empty\n\t\tt.Assert(gfile.Join(), \"\")\n\t})\n}\n\nfunc Test_Chdir(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Save current working directory\n\t\toriginalPwd := gfile.Pwd()\n\t\tdefer func() {\n\t\t\t// Restore original working directory\n\t\t\t_ = gfile.Chdir(originalPwd)\n\t\t}()\n\n\t\t// Test changing to temp directory\n\t\ttempDir := gfile.Temp()\n\t\terr := gfile.Chdir(tempDir)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gfile.Pwd(), tempDir)\n\n\t\t// Test changing to non-existent directory\n\t\terr = gfile.Chdir(\"/nonexistent_dir_12345\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Abs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with relative path\n\t\tabsPath := gfile.Abs(\".\")\n\t\tt.Assert(len(absPath) > 0, true)\n\t\tt.Assert(filepath.IsAbs(absPath), true)\n\n\t\t// Test with already absolute path\n\t\ttempDir := gfile.Temp()\n\t\tt.Assert(gfile.Abs(tempDir), tempDir)\n\n\t\t// Test with relative path components\n\t\tabsPath = gfile.Abs(\"./test\")\n\t\tt.Assert(filepath.IsAbs(absPath), true)\n\n\t\t// Test with parent directory reference\n\t\tabsPath = gfile.Abs(\"../test\")\n\t\tt.Assert(filepath.IsAbs(absPath), true)\n\n\t\t// Test with empty string\n\t\tabsPath = gfile.Abs(\"\")\n\t\tt.Assert(len(absPath) > 0, true)\n\t\tt.Assert(filepath.IsAbs(absPath), true)\n\t})\n}\n\nfunc Test_Name(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Test with file extension\n\t\tt.Assert(gfile.Name(\"/var/www/file.js\"), \"file\")\n\t\tt.Assert(gfile.Name(\"file.js\"), \"file\")\n\n\t\t// Test with multiple dots\n\t\tt.Assert(gfile.Name(\"/var/www/file.min.js\"), \"file.min\")\n\t\tt.Assert(gfile.Name(\"archive.tar.gz\"), \"archive.tar\")\n\n\t\t// Test without extension\n\t\tt.Assert(gfile.Name(\"/var/www/file\"), \"file\")\n\t\tt.Assert(gfile.Name(\"file\"), \"file\")\n\n\t\t// Test with hidden file (dot file)\n\t\tt.Assert(gfile.Name(\".gitignore\"), \"\")\n\t\tt.Assert(gfile.Name(\".hidden.txt\"), \".hidden\")\n\n\t\t// Test with directory path\n\t\tt.Assert(gfile.Name(\"/var/www/\"), \"www\")\n\n\t\t// Test with only extension\n\t\tt.Assert(gfile.Name(\".txt\"), \"\")\n\t})\n}\n"
  },
  {
    "path": "os/gfile/gfile_z_unit_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfile_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_MTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tvar (\n\t\t\tfile1   = \"/testfile_t1.txt\"\n\t\t\terr     error\n\t\t\tfileobj os.FileInfo\n\t\t)\n\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfileobj, err = os.Stat(testpath() + file1)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gfile.MTime(testpath()+file1), fileobj.ModTime())\n\t\tt.Assert(gfile.MTime(\"\"), \"\")\n\t})\n}\n\nfunc Test_MTimeMillisecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfile1   = \"/testfile_t1.txt\"\n\t\t\terr     error\n\t\t\tfileobj os.FileInfo\n\t\t)\n\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfileobj, err = os.Stat(testpath() + file1)\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.AssertGE(\n\t\t\tgfile.MTimestampMilli(testpath()+file1),\n\t\t\tfileobj.ModTime().UnixNano()/1000000,\n\t\t)\n\t\tt.Assert(gfile.MTimestampMilli(\"\"), -1)\n\t})\n}\n\nfunc Test_MTimestamp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tfile1   = \"/testfile_mtimestamp.txt\"\n\t\t\terr     error\n\t\t\tfileobj os.FileInfo\n\t\t)\n\n\t\tcreateTestFile(file1, \"\")\n\t\tdefer delTestFiles(file1)\n\t\tfileobj, err = os.Stat(testpath() + file1)\n\t\tt.AssertNil(err)\n\n\t\t// Test MTimestamp returns correct unix timestamp\n\t\ttimestamp := gfile.MTimestamp(testpath() + file1)\n\t\tt.Assert(timestamp, fileobj.ModTime().Unix())\n\t\tt.Assert(timestamp > 0, true)\n\n\t\t// Test with non-existent file\n\t\tt.Assert(gfile.MTimestamp(\"/nonexistent_file_12345.txt\"), -1)\n\n\t\t// Test with empty path\n\t\tt.Assert(gfile.MTimestamp(\"\"), -1)\n\t})\n\n\t// Test MTimestamp with directory\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttempDir := gfile.Temp()\n\t\ttimestamp := gfile.MTimestamp(tempDir)\n\t\tt.Assert(timestamp > 0, true)\n\t})\n}\n"
  },
  {
    "path": "os/gfile/testdata/dir1/file1",
    "content": "file1"
  },
  {
    "path": "os/gfile/testdata/dir2/file2",
    "content": "file2"
  },
  {
    "path": "os/gfile/testdata/readline/file.log",
    "content": "a\nb\nc\nd\ne\n"
  },
  {
    "path": "os/gfpool/gfpool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gfpool provides io-reusable pool for file pointer.\npackage gfpool\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gpool\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n)\n\n// Pool pointer pool.\ntype Pool struct {\n\tid   *gtype.Int    // Pool id, which is used to mark this pool whether recreated.\n\tpool *gpool.Pool   // Underlying pool.\n\tinit *gtype.Bool   // Whether initialized, used for marking this file added to fsnotify, and it can only be added just once.\n\tttl  time.Duration // Time to live for file pointer items.\n}\n\n// File is an item in the pool.\ntype File struct {\n\t*os.File             // Underlying file pointer.\n\tstat     os.FileInfo // State of current file pointer.\n\tpid      int         // Belonging pool id, which is set when file pointer created. It's used to check whether the pool is recreated.\n\tpool     *Pool       // Belonging ool.\n\tflag     int         // Flash for opening file.\n\tperm     os.FileMode // Permission for opening file.\n\tpath     string      // Absolute path of the file.\n}\n\nvar (\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *Pool) bool { return v == nil }\n\t// Global file pointer pool.\n\tpools = gmap.NewKVMapWithChecker[string, *Pool](checker, true)\n)\n"
  },
  {
    "path": "os/gfpool/gfpool_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfpool\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Open creates and returns a file item with given file path, flag and opening permission.\n// It automatically creates an associated file pointer pool internally when it's called first time.\n// It retrieves a file item from the file pointer pool after then.\nfunc Open(path string, flag int, perm os.FileMode, ttl ...time.Duration) (file *File, err error) {\n\tvar fpTTL time.Duration\n\tif len(ttl) > 0 {\n\t\tfpTTL = ttl[0]\n\t}\n\t// DO NOT search the path here wasting performance!\n\t// Leave following codes just for warning you.\n\t//\n\t// path, err = gfile.Search(path)\n\t// if err != nil {\n\t//\treturn nil, err\n\t// }\n\tpool := pools.GetOrSetFuncLock(\n\t\tfmt.Sprintf(\"%s&%d&%d&%d\", path, flag, fpTTL, perm),\n\t\tfunc() *Pool {\n\t\t\treturn New(path, flag, perm, fpTTL)\n\t\t},\n\t)\n\n\treturn pool.File()\n}\n\n// Get returns a file item with given file path, flag and opening permission.\n// It retrieves a file item from the file pointer pool after then.\nfunc Get(path string, flag int, perm os.FileMode, ttl ...time.Duration) (file *File) {\n\tvar fpTTL time.Duration\n\tif len(ttl) > 0 {\n\t\tfpTTL = ttl[0]\n\t}\n\n\tf, found := pools.Search(fmt.Sprintf(\"%s&%d&%d&%d\", path, flag, fpTTL, perm))\n\tif !found {\n\t\treturn nil\n\t}\n\n\tfp, _ := f.pool.Get()\n\treturn fp.(*File)\n}\n\n// Stat returns the FileInfo structure describing file.\nfunc (f *File) Stat() (os.FileInfo, error) {\n\tif f.stat == nil {\n\t\treturn nil, gerror.New(\"file stat is empty\")\n\t}\n\treturn f.stat, nil\n}\n\n// Close puts the file pointer back to the file pointer pool.\nfunc (f *File) Close(close ...bool) error {\n\tif len(close) > 0 && close[0] {\n\t\tf.File.Close()\n\t}\n\n\tif f.pid == f.pool.id.Val() {\n\t\treturn f.pool.pool.Put(f)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gfpool/gfpool_pool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfpool\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gpool\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n)\n\n// New creates and returns a file pointer pool with given file path, flag and opening permission.\n//\n// Note the expiration logic:\n// ttl = 0 : not expired;\n// ttl < 0 : immediate expired after use;\n// ttl > 0 : timeout expired;\n// It is not expired in default.\nfunc New(path string, flag int, perm os.FileMode, ttl ...time.Duration) *Pool {\n\tvar fpTTL time.Duration\n\tif len(ttl) > 0 {\n\t\tfpTTL = ttl[0]\n\t}\n\tp := &Pool{\n\t\tid:   gtype.NewInt(),\n\t\tttl:  fpTTL,\n\t\tinit: gtype.NewBool(),\n\t}\n\tp.pool = newFilePool(p, path, flag, perm, fpTTL)\n\treturn p\n}\n\n// newFilePool creates and returns a file pointer pool with given file path, flag and opening permission.\nfunc newFilePool(p *Pool, path string, flag int, perm os.FileMode, ttl time.Duration) *gpool.Pool {\n\tpool := gpool.New(ttl, func() (any, error) {\n\t\tfile, err := os.OpenFile(path, flag, perm)\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `os.OpenFile failed for file \"%s\", flag \"%d\", perm \"%s\"`, path, flag, perm)\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &File{\n\t\t\tFile: file,\n\t\t\tpid:  p.id.Val(),\n\t\t\tpool: p,\n\t\t\tflag: flag,\n\t\t\tperm: perm,\n\t\t\tpath: path,\n\t\t}, nil\n\t}, func(i any) {\n\t\t_ = i.(*File).File.Close()\n\t})\n\treturn pool\n}\n\n// File retrieves file item from the file pointer pool and returns it. It creates one if\n// the file pointer pool is empty.\n// Note that it should be closed when it will never be used. When it's closed, it is not\n// really closed the underlying file pointer but put back to the file pointer pool.\nfunc (p *Pool) File() (*File, error) {\n\tif v, err := p.pool.Get(); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\tf := v.(*File)\n\t\tf.stat, err = os.Stat(f.path)\n\t\tif f.flag&os.O_CREATE > 0 {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\tif f.File, err = os.OpenFile(f.path, f.flag, f.perm); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t} else {\n\t\t\t\t\t// Retrieve the state of the new created file.\n\t\t\t\t\tif f.stat, err = f.File.Stat(); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif f.flag&os.O_TRUNC > 0 {\n\t\t\tif f.stat.Size() > 0 {\n\t\t\t\tif err = f.Truncate(0); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif f.flag&os.O_APPEND > 0 {\n\t\t\tif _, err = f.Seek(0, 2); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tif _, err = f.Seek(0, 0); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\t// It firstly checks using !p.init.Val() for performance purpose.\n\t\tif !p.init.Val() && p.init.Cas(false, true) {\n\t\t\tvar watchCallback = func(event *gfsnotify.Event) {\n\t\t\t\t// If the file is removed or renamed, recreates the pool by increasing the pool id.\n\t\t\t\tif event.IsRemove() || event.IsRename() {\n\t\t\t\t\t// It drops the old pool.\n\t\t\t\t\tp.id.Add(1)\n\t\t\t\t\t// Clears the pool items staying in the pool.\n\t\t\t\t\tp.pool.Clear()\n\t\t\t\t\t// It uses another adding to drop the file items between the two adding.\n\t\t\t\t\t// Whenever the pool id changes, the pool will be recreated.\n\t\t\t\t\tp.id.Add(1)\n\t\t\t\t}\n\t\t\t}\n\t\t\t_, _ = gfsnotify.Add(f.path, watchCallback, gfsnotify.WatchOption{NoRecursive: true})\n\t\t}\n\t\treturn f, nil\n\t}\n}\n\n// Close closes current file pointer pool.\nfunc (p *Pool) Close() {\n\tp.pool.Close()\n}\n"
  },
  {
    "path": "os/gfpool/gfpool_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfpool\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nfunc Benchmark_OS_Open_Close_ALLFlags(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := os.OpenFile(\"/tmp/bench-test\", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_GFPool_Open_Close_ALLFlags(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := Open(\"/tmp/bench-test\", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_OS_Open_Close_RDWR(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := os.OpenFile(\"/tmp/bench-test\", os.O_RDWR, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_GFPool_Open_Close_RDWR(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := Open(\"/tmp/bench-test\", os.O_RDWR, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_OS_Open_Close_RDONLY(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := os.OpenFile(\"/tmp/bench-test\", os.O_RDONLY, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_GFPool_Open_Close_RDONLY(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tf, err := Open(\"/tmp/bench-test\", os.O_RDONLY, 0666)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tf.Close()\n\t}\n}\n\nfunc Benchmark_Stat(b *testing.B) {\n\tf, err := os.Create(\"/tmp/bench-test-stat\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\tfor i := 0; i < b.N; i++ {\n\t\tf.Stat()\n\t}\n}\n"
  },
  {
    "path": "os/gfpool/gfpool_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfpool_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfpool\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// TestOpen test open file cache\nfunc TestOpen(t *testing.T) {\n\ttestFile := start(\"TestOpen.txt\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tf, err := gfpool.Open(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertEQ(err, nil)\n\t\tf.Close()\n\n\t\tf2, err1 := gfpool.Open(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertEQ(err1, nil)\n\t\tt.AssertEQ(f, f2)\n\t\tf2.Close()\n\t})\n\n\tstop(testFile)\n}\n\n// TestOpenErr test open file error\nfunc TestOpenErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttestErrFile := \"errorPath\"\n\t\t_, err := gfpool.Open(testErrFile, os.O_RDWR, 0666)\n\t\tt.AssertNE(err, nil)\n\n\t\t// delete file error\n\t\ttestFile := start(\"TestOpenDeleteErr.txt\")\n\t\tpool := gfpool.New(testFile, os.O_RDWR, 0666)\n\t\t_, err1 := pool.File()\n\t\tt.AssertEQ(err1, nil)\n\t\tstop(testFile)\n\t\t_, err1 = pool.File()\n\t\tt.AssertNE(err1, nil)\n\n\t\t// append mode delete file error and create again\n\t\ttestFile = start(\"TestOpenCreateErr.txt\")\n\t\tpool = gfpool.New(testFile, os.O_CREATE, 0666)\n\t\t_, err1 = pool.File()\n\t\tt.AssertEQ(err1, nil)\n\t\tstop(testFile)\n\t\t_, err1 = pool.File()\n\t\tt.AssertEQ(err1, nil)\n\n\t\t// append mode delete file error\n\t\ttestFile = start(\"TestOpenAppendErr.txt\")\n\t\tpool = gfpool.New(testFile, os.O_APPEND, 0666)\n\t\t_, err1 = pool.File()\n\t\tt.AssertEQ(err1, nil)\n\t\tstop(testFile)\n\t\t_, err1 = pool.File()\n\t\tt.AssertNE(err1, nil)\n\n\t\t// trunc mode delete file error\n\t\ttestFile = start(\"TestOpenTruncErr.txt\")\n\t\tpool = gfpool.New(testFile, os.O_TRUNC, 0666)\n\t\t_, err1 = pool.File()\n\t\tt.AssertEQ(err1, nil)\n\t\tstop(testFile)\n\t\t_, err1 = pool.File()\n\t\tt.AssertNE(err1, nil)\n\t})\n}\n\n// TestOpenExpire test open file cache expire\nfunc TestOpenExpire(t *testing.T) {\n\ttestFile := start(\"TestOpenExpire.txt\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tf, err := gfpool.Open(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666, 100*time.Millisecond)\n\t\tt.AssertEQ(err, nil)\n\t\tf.Close()\n\n\t\ttime.Sleep(150 * time.Millisecond)\n\t\tf2, err1 := gfpool.Open(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666, 100*time.Millisecond)\n\t\tt.AssertEQ(err1, nil)\n\t\t//t.AssertNE(f, f2)\n\t\tf2.Close()\n\t})\n\n\tstop(testFile)\n}\n\n// TestNewPool test gfpool new function\nfunc TestNewPool(t *testing.T) {\n\ttestFile := start(\"TestNewPool.txt\")\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tf, err := gfpool.Open(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertEQ(err, nil)\n\t\tf.Close()\n\n\t\tpool := gfpool.New(testFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tf2, err1 := pool.File()\n\t\t// pool not equal\n\t\tt.AssertEQ(err1, nil)\n\t\t//t.AssertNE(f, f2)\n\t\tf2.Close()\n\n\t\tpool.Close()\n\t})\n\n\tstop(testFile)\n}\n\n// test before\nfunc start(name string) string {\n\ttestFile := os.TempDir() + string(os.PathSeparator) + name\n\tif gfile.Exists(testFile) {\n\t\tgfile.Remove(testFile)\n\t}\n\tcontent := \"123\"\n\tgfile.PutContents(testFile, content)\n\treturn testFile\n}\n\n// test after\nfunc stop(testFile string) {\n\tif gfile.Exists(testFile) {\n\t\terr := gfile.Remove(testFile)\n\t\tif err != nil {\n\t\t\tglog.Error(context.TODO(), err)\n\t\t}\n\t}\n}\n\nfunc Test_ConcurrentOS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdefer gfile.Remove(path)\n\t\tf1, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f1.Close()\n\n\t\tf2, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f2.Close()\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2200)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdefer gfile.Remove(path)\n\t\tf1, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f1.Close()\n\n\t\tf2, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f2.Close()\n\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2000)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdefer gfile.Remove(path)\n\t\tf1, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f1.Close()\n\n\t\tf2, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f2.Close()\n\n\t\ts1 := \"\"\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\ts1 += \"@1234567890#\"\n\t\t}\n\t\t_, err = f2.Write([]byte(s1))\n\t\tt.AssertNil(err)\n\n\t\ts2 := \"\"\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\ts2 += \"@1234567890#\"\n\t\t}\n\t\t_, err = f2.Write([]byte(s2))\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2000)\n\t})\n\t// DATA RACE\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t//\tdefer gfile.Remove(path)\n\t//\tf1, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t//\tt.AssertNil(err)\n\t//\tdefer f1.Close()\n\t//\n\t//\tf2, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t//\tt.AssertNil(err)\n\t//\tdefer f2.Close()\n\t//\n\t//\twg := sync.WaitGroup{}\n\t//\tch := make(chan struct{})\n\t//\tfor i := 0; i < 1000; i++ {\n\t//\t\twg.Add(1)\n\t//\t\tgo func() {\n\t//\t\t\tdefer wg.Done()\n\t//\t\t\t<-ch\n\t//\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t//\t\t\tt.AssertNil(err)\n\t//\t\t}()\n\t//\t}\n\t//\tfor i := 0; i < 1000; i++ {\n\t//\t\twg.Add(1)\n\t//\t\tgo func() {\n\t//\t\t\tdefer wg.Done()\n\t//\t\t\t<-ch\n\t//\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t//\t\t\tt.AssertNil(err)\n\t//\t\t}()\n\t//\t}\n\t//\tclose(ch)\n\t//\twg.Wait()\n\t//\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2000)\n\t// })\n}\n\nfunc Test_ConcurrentGFPool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tdefer gfile.Remove(path)\n\t\tf1, err := gfpool.Open(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f1.Close()\n\n\t\tf2, err := gfpool.Open(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t\tt.AssertNil(err)\n\t\tdefer f2.Close()\n\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2000)\n\t})\n\t// DATA RACE\n\t// gtest.C(t, func(t *gtest.T) {\n\t//\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t//\tdefer gfile.Remove(path)\n\t//\tf1, err := gfpool.Open(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t//\tt.AssertNil(err)\n\t//\tdefer f1.Close()\n\t//\n\t//\tf2, err := gfpool.Open(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)\n\t//\tt.AssertNil(err)\n\t//\tdefer f2.Close()\n\t//\n\t//\twg := sync.WaitGroup{}\n\t//\tch := make(chan struct{})\n\t//\tfor i := 0; i < 1000; i++ {\n\t//\t\twg.Add(1)\n\t//\t\tgo func() {\n\t//\t\t\tdefer wg.Done()\n\t//\t\t\t<-ch\n\t//\t\t\t_, err = f1.Write([]byte(\"@1234567890#\"))\n\t//\t\t\tt.AssertNil(err)\n\t//\t\t}()\n\t//\t}\n\t//\tfor i := 0; i < 1000; i++ {\n\t//\t\twg.Add(1)\n\t//\t\tgo func() {\n\t//\t\t\tdefer wg.Done()\n\t//\t\t\t<-ch\n\t//\t\t\t_, err = f2.Write([]byte(\"@1234567890#\"))\n\t//\t\t\tt.AssertNil(err)\n\t//\t\t}()\n\t//\t}\n\t//\tclose(ch)\n\t//\twg.Wait()\n\t//\tt.Assert(gstr.Count(gfile.GetContents(path), \"@1234567890#\"), 2000)\n\t// })\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gfsnotify provides a platform-independent interface for file system notifications.\npackage gfsnotify\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/fsnotify/fsnotify\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n)\n\n// Watcher is the monitor for file changes.\ntype Watcher struct {\n\twatcher   *fsnotify.Watcher                            // Underlying fsnotify object.\n\tevents    *gqueue.TQueue[*Event]                       // Used for internal event management.\n\tcache     *gcache.Cache                                // Used for repeated event filter.\n\tnameSet   *gset.StrSet                                 // Used for AddOnce feature.\n\tcallbacks *gmap.KVMap[string, *glist.TList[*Callback]] // Path(file/folder) to callbacks mapping.\n\tcloseChan chan struct{}                                // Used for watcher closing notification.\n}\n\n// Callback is the callback function for Watcher.\ntype Callback struct {\n\tId        int                        // Unique id for callback object.\n\tFunc      func(event *Event)         // Callback function.\n\tPath      string                     // Bound file path (absolute).\n\tname      string                     // Registered name for AddOnce.\n\telem      *glist.TElement[*Callback] // Element in the callbacks of watcher.\n\trecursive bool                       // Is bound to sub-path recursively or not.\n}\n\n// Event is the event produced by underlying fsnotify.\ntype Event struct {\n\tevent   fsnotify.Event // Underlying event.\n\tPath    string         // Absolute file path.\n\tOp      Op             // File operation.\n\tWatcher *Watcher       // Parent watcher.\n}\n\n// WatchOption holds the option for watching.\ntype WatchOption struct {\n\t// NoRecursive explicitly specifies no recursive watching.\n\t// Recursive watching will also watch all its current and following created subfolders and sub-files.\n\t//\n\t// Note that the recursive watching is enabled in default.\n\tNoRecursive bool\n}\n\n// Op is the bits union for file operations.\ntype Op uint32\n\n// internalPanic is the custom panic for internal usage.\ntype internalPanic string\n\nconst (\n\tCREATE Op = 1 << iota\n\tWRITE\n\tREMOVE\n\tRENAME\n\tCHMOD\n)\n\nconst (\n\trepeatEventFilterDuration               = time.Millisecond // Duration for repeated event filter.\n\tcallbackExitEventPanicStr internalPanic = \"exit\"           // Custom exit event for internal usage.\n)\n\nvar (\n\tcallBacksChecker     = func(v *glist.TList[*Callback]) bool { return v == nil }             // callBacksChecker checks whether the value is nil.\n\tcallbackIdMapChecker = func(v *Callback) bool { return v == nil }                           // callbackIdMapChecker checks whether the value is nil.\n\tmu                   sync.Mutex                                                             // Mutex for concurrent safety of defaultWatcher.\n\tdefaultWatcher       *Watcher                                                               // Default watcher.\n\tcallbackIdMap        = gmap.NewKVMapWithChecker[int, *Callback](callbackIdMapChecker, true) // Global callback id to callback function mapping.\n\tcallbackIdGenerator  = gtype.NewInt()                                                       // Atomic id generator for callback.\n)\n\n// New creates and returns a new watcher.\n// Note that the watcher number is limited by the file handle setting of the system.\n// Example: fs.inotify.max_user_instances system variable in linux systems.\n//\n// In most case, you can use the default watcher for usage instead of creating one.\nfunc New() (*Watcher, error) {\n\tw := &Watcher{\n\t\tcache:     gcache.New(),\n\t\tevents:    gqueue.NewTQueue[*Event](),\n\t\tnameSet:   gset.NewStrSet(true),\n\t\tcloseChan: make(chan struct{}),\n\t\tcallbacks: gmap.NewKVMapWithChecker[string, *glist.TList[*Callback]](callBacksChecker, true),\n\t}\n\tif watcher, err := fsnotify.NewWatcher(); err == nil {\n\t\tw.watcher = watcher\n\t} else {\n\t\tintlog.Printf(context.TODO(), \"New watcher failed: %v\", err)\n\t\treturn nil, err\n\t}\n\tgo w.watchLoop()\n\tgo w.eventLoop()\n\treturn w, nil\n}\n\n// Add monitors `path` using default watcher with callback function `callbackFunc`.\n//\n// The parameter `path` can be either a file or a directory path.\n// The optional parameter `recursive` specifies whether monitoring the `path` recursively, which is true in default.\nfunc Add(path string, callbackFunc func(event *Event), option ...WatchOption) (callback *Callback, err error) {\n\tw, err := getDefaultWatcher()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn w.Add(path, callbackFunc, option...)\n}\n\n// AddOnce monitors `path` using default watcher with callback function `callbackFunc` only once using unique name `name`.\n//\n// If AddOnce is called multiple times with the same `name` parameter, `path` is only added to monitor once.\n// It returns error if it's called twice with the same `name`.\n//\n// The parameter `path` can be either a file or a directory path.\n// The optional parameter `recursive` specifies whether monitoring the `path` recursively, which is true in default.\nfunc AddOnce(name, path string, callbackFunc func(event *Event), option ...WatchOption) (callback *Callback, err error) {\n\tw, err := getDefaultWatcher()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn w.AddOnce(name, path, callbackFunc, option...)\n}\n\n// Remove removes all monitoring callbacks of given `path` from watcher recursively.\nfunc Remove(path string) error {\n\tw, err := getDefaultWatcher()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn w.Remove(path)\n}\n\n// RemoveCallback removes specified callback with given id from watcher.\nfunc RemoveCallback(callbackID int) error {\n\tw, err := getDefaultWatcher()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif callback := callbackIdMap.Get(callbackID); callback == nil {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `callback for id %d not found`, callbackID)\n\t}\n\tw.RemoveCallback(callbackID)\n\treturn nil\n}\n\n// Exit is only used in the callback function, which can be used to remove current callback\n// of itself from the watcher.\nfunc Exit() {\n\tpanic(callbackExitEventPanicStr)\n}\n\n// getDefaultWatcher creates and returns the default watcher.\n// This is used for lazy initialization purpose.\nfunc getDefaultWatcher() (*Watcher, error) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tif defaultWatcher != nil {\n\t\treturn defaultWatcher, nil\n\t}\n\tvar err error\n\tdefaultWatcher, err = New()\n\treturn defaultWatcher, err\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify_event.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// ThIs Source Code Form Is subject to the terms of the MIT License.\n// If a copy of the MIT was not dIstributed with thIs file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfsnotify\n\n// String returns current event as string.\nfunc (e *Event) String() string {\n\treturn e.event.String()\n}\n\n// IsCreate checks whether current event contains file/folder create event.\nfunc (e *Event) IsCreate() bool {\n\treturn e.Op == 1 || e.Op&CREATE == CREATE\n}\n\n// IsWrite checks whether current event contains file/folder write event.\nfunc (e *Event) IsWrite() bool {\n\treturn e.Op&WRITE == WRITE\n}\n\n// IsRemove checks whether current event contains file/folder remove event.\nfunc (e *Event) IsRemove() bool {\n\treturn e.Op&REMOVE == REMOVE\n}\n\n// IsRename checks whether current event contains file/folder rename event.\nfunc (e *Event) IsRename() bool {\n\treturn e.Op&RENAME == RENAME\n}\n\n// IsChmod checks whether current event contains file/folder chmod event.\nfunc (e *Event) IsChmod() bool {\n\treturn e.Op&CHMOD == CHMOD\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify_filefunc.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// ThIs Source Code Form Is subject to the terms of the MIT License.\n// If a copy of the MIT was not dIstributed with thIs file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfsnotify\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// fileDir returns all but the last element of path, typically the path's directory.\n// After dropping the final element, Dir calls Clean on the path and trailing\n// slashes are removed.\n// If the path is empty, Dir returns \".\".\n// If the path consists entirely of separators, Dir returns a single separator.\n// The returned path does not end in a separator unless it is the root directory.\nfunc fileDir(path string) string {\n\treturn filepath.Dir(path)\n}\n\n// fileRealPath converts the given `path` to its absolute path\n// and checks if the file path exists.\n// If the file does not exist, return an empty string.\nfunc fileRealPath(path string) string {\n\tp, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\tif !fileExists(p) {\n\t\treturn \"\"\n\t}\n\treturn p\n}\n\n// fileExists checks whether given `path` exist.\nfunc fileExists(path string) bool {\n\tif stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// fileIsDir checks whether given `path` a directory.\nfunc fileIsDir(path string) bool {\n\ts, err := os.Stat(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn s.IsDir()\n}\n\n// fileAllDirs returns all sub-folders including itself of given `path` recursively.\nfunc fileAllDirs(path string) (list []string) {\n\tlist = []string{path}\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn list\n\t}\n\tdefer file.Close()\n\tnames, err := file.Readdirnames(-1)\n\tif err != nil {\n\t\treturn list\n\t}\n\tfor _, name := range names {\n\t\ttempPath := fmt.Sprintf(\"%s%s%s\", path, string(filepath.Separator), name)\n\t\tif fileIsDir(tempPath) {\n\t\t\tif array := fileAllDirs(tempPath); len(array) > 0 {\n\t\t\t\tlist = append(list, array...)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// fileScanDir returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\nfunc fileScanDir(path string, pattern string, recursive ...bool) ([]string, error) {\n\tlist, err := doFileScanDir(path, pattern, recursive...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(list) > 0 {\n\t\tsort.Strings(list)\n\t}\n\treturn list, nil\n}\n\n// doFileScanDir is an internal method which scans directory\n// and returns the absolute path list of files that are not sorted.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\n//\n// It scans directory recursively if given parameter `recursive` is true.\nfunc doFileScanDir(path string, pattern string, recursive ...bool) ([]string, error) {\n\tvar (\n\t\tlist      []string\n\t\tfile, err = os.Open(path)\n\t)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err, `os.Open failed for path \"%s\"`, path)\n\t}\n\tdefer file.Close()\n\tnames, err := file.Readdirnames(-1)\n\tif err != nil {\n\t\treturn nil, gerror.Wrapf(err, `read directory files failed for path \"%s\"`, path)\n\t}\n\tfilePath := \"\"\n\tfor _, name := range names {\n\t\tfilePath = fmt.Sprintf(\"%s%s%s\", path, string(filepath.Separator), name)\n\t\tif fileIsDir(filePath) && len(recursive) > 0 && recursive[0] {\n\t\t\tarray, _ := doFileScanDir(filePath, pattern, true)\n\t\t\tif len(array) > 0 {\n\t\t\t\tlist = append(list, array...)\n\t\t\t}\n\t\t}\n\t\tfor _, p := range strings.Split(pattern, \",\") {\n\t\t\tif match, _ := filepath.Match(strings.TrimSpace(p), name); match {\n\t\t\t\tlist = append(list, filePath)\n\t\t\t}\n\t\t}\n\t}\n\treturn list, nil\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify_watcher.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfsnotify\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// Add monitors `path` with callback function `callbackFunc` to the watcher.\n//\n// The parameter `path` can be either a file or a directory path.\n// The optional parameter `recursive` specifies whether monitoring the `path` recursively,\n// which is true in default.\nfunc (w *Watcher) Add(path string, callbackFunc func(event *Event), option ...WatchOption,\n) (callback *Callback, err error) {\n\treturn w.AddOnce(\"\", path, callbackFunc, option...)\n}\n\n// AddOnce monitors `path` with callback function `callbackFunc` only once using unique name\n// `name` to the watcher. If AddOnce is called multiple times with the same `name` parameter,\n// `path` is only added to monitor once.\n//\n// It returns error if it's called twice with the same `name`.\n//\n// The parameter `path` can be either a file or a directory path.\n// The optional parameter `recursive` specifies whether monitoring the `path` recursively,\n// which is true in default.\nfunc (w *Watcher) AddOnce(name, path string, callbackFunc func(event *Event), option ...WatchOption,\n) (callback *Callback, err error) {\n\tvar watchOption = w.getWatchOption(option...)\n\tw.nameSet.AddIfNotExistFuncLock(name, func() bool {\n\t\t// Firstly add the path to watcher.\n\t\t//\n\t\t// A path can only be watched once; watching it more than once is a no-op and will\n\t\t// not return an error.\n\t\tcallback, err = w.addWithCallbackFunc(\n\t\t\tname, path, callbackFunc, option...,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\n\t\t// If it's recursive adding, it then adds all sub-folders to the monitor.\n\t\t// NOTE:\n\t\t// 1. It only recursively adds **folders** to the monitor, NOT files,\n\t\t//    because if the folders are monitored and their sub-files are also monitored.\n\t\t// 2. It bounds no callbacks to the folders, because it will search the callbacks\n\t\t//    from its parent recursively if any event produced.\n\t\tif fileIsDir(path) && !watchOption.NoRecursive {\n\t\t\tfor _, subPath := range fileAllDirs(path) {\n\t\t\t\tif fileIsDir(subPath) {\n\t\t\t\t\tif watchAddErr := w.watcher.Add(subPath); watchAddErr != nil {\n\t\t\t\t\t\terr = gerror.Wrapf(\n\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\t`add watch failed for path \"%s\", err: %s`,\n\t\t\t\t\t\t\tsubPath, watchAddErr.Error(),\n\t\t\t\t\t\t)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tintlog.Printf(context.TODO(), \"watcher adds monitor for: %s\", subPath)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif name == \"\" {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\treturn\n}\n\nfunc (w *Watcher) getWatchOption(option ...WatchOption) WatchOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn WatchOption{}\n}\n\n// addWithCallbackFunc adds the path to underlying monitor, creates and returns a callback object.\n// Very note that if it calls multiple times with the same `path`, the latest one will overwrite the previous one.\nfunc (w *Watcher) addWithCallbackFunc(name, path string, callbackFunc func(event *Event), option ...WatchOption,\n) (callback *Callback, err error) {\n\tvar watchOption = w.getWatchOption(option...)\n\t// Check and convert the given path to absolute path.\n\tif realPath := fileRealPath(path); realPath == \"\" {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `\"%s\" does not exist`, path)\n\t} else {\n\t\tpath = realPath\n\t}\n\t// Create callback object.\n\tcallback = &Callback{\n\t\tId:        callbackIdGenerator.Add(1),\n\t\tFunc:      callbackFunc,\n\t\tPath:      path,\n\t\tname:      name,\n\t\trecursive: !watchOption.NoRecursive,\n\t}\n\t// Register the callback to watcher.\n\tw.callbacks.LockFunc(func(m map[string]*glist.TList[*Callback]) {\n\t\tlist, ok := m[path]\n\t\tif !ok {\n\t\t\tlist = glist.NewT[*Callback](true)\n\t\t\tm[path] = list\n\t\t}\n\t\tcallback.elem = list.PushBack(callback)\n\t})\n\t// Add the path to underlying monitor.\n\tif err = w.watcher.Add(path); err != nil {\n\t\terr = gerror.Wrapf(err, `add watch failed for path \"%s\"`, path)\n\t} else {\n\t\tintlog.Printf(context.TODO(), \"watcher adds monitor for: %s\", path)\n\t}\n\t// Add the callback to global callback map.\n\tcallbackIdMap.Set(callback.Id, callback)\n\treturn\n}\n\n// Close closes the watcher.\nfunc (w *Watcher) Close() {\n\tclose(w.closeChan)\n\tif err := w.watcher.Close(); err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t}\n\tw.events.Close()\n}\n\n// Remove removes watching and all callbacks associated with the `path` recursively.\n// Note that, it's recursive in default if given `path` is a directory.\nfunc (w *Watcher) Remove(path string) error {\n\tvar (\n\t\terr          error\n\t\tsubPaths     []string\n\t\tremovedPaths = make([]string, 0)\n\t)\n\tremovedPaths = append(removedPaths, path)\n\tif fileIsDir(path) {\n\t\tsubPaths, err = fileScanDir(path, \"*\", true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tremovedPaths = append(removedPaths, subPaths...)\n\t}\n\n\tfor _, removedPath := range removedPaths {\n\t\t// remove the callbacks of the path.\n\t\tif value := w.callbacks.Remove(removedPath); value != nil {\n\t\t\tfor {\n\t\t\t\tif item := value.PopFront(); item != nil {\n\t\t\t\t\tcallbackIdMap.Remove(item.Id)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// remove the monitor of the path from underlying monitor.\n\t\tif watcherRemoveErr := w.watcher.Remove(removedPath); watcherRemoveErr != nil {\n\t\t\terr = gerror.Wrapf(\n\t\t\t\terr,\n\t\t\t\t`remove watch failed for path \"%s\", err: %s`,\n\t\t\t\tremovedPath, watcherRemoveErr.Error(),\n\t\t\t)\n\t\t}\n\t}\n\treturn err\n}\n\n// RemoveCallback removes callback with given callback id from watcher.\n//\n// Note that, it auto removes the path watching if there's no callback bound on it.\nfunc (w *Watcher) RemoveCallback(callbackID int) {\n\tif callback := callbackIdMap.Get(callbackID); callback != nil {\n\t\tif r := w.callbacks.Get(callback.Path); r != nil {\n\t\t\tr.Remove(callback.elem)\n\t\t}\n\t\tcallbackIdMap.Remove(callbackID)\n\t\tif callback.name != \"\" {\n\t\t\tw.nameSet.Remove(callback.name)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify_watcher_loop.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfsnotify\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// watchLoop starts the loop for event listening from underlying inotify monitor.\nfunc (w *Watcher) watchLoop() {\n\tfor {\n\t\tselect {\n\t\t// close event.\n\t\tcase <-w.closeChan:\n\t\t\treturn\n\n\t\t// event listening.\n\t\tcase ev, ok := <-w.watcher.Events:\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// filter the repeated event in custom duration.\n\t\t\tvar cacheFunc = func(ctx context.Context) (value any, err error) {\n\t\t\t\tw.events.Push(&Event{\n\t\t\t\t\tevent:   ev,\n\t\t\t\t\tPath:    ev.Name,\n\t\t\t\t\tOp:      Op(ev.Op),\n\t\t\t\t\tWatcher: w,\n\t\t\t\t})\n\t\t\t\treturn struct{}{}, nil\n\t\t\t}\n\t\t\t_, err := w.cache.SetIfNotExist(\n\t\t\t\tcontext.Background(),\n\t\t\t\tev.String(),\n\t\t\t\tcacheFunc,\n\t\t\t\trepeatEventFilterDuration,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t}\n\n\t\t// error occurs in underlying watcher.\n\t\tcase err := <-w.watcher.Errors:\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t}\n}\n\n// eventLoop is the core event handler.\nfunc (w *Watcher) eventLoop() {\n\tvar (\n\t\terr error\n\t\tctx = context.TODO()\n\t)\n\tfor {\n\t\tif v := w.events.Pop(); v != nil {\n\t\t\t// If there's no any callback of this path, it removes it from monitor,\n\t\t\t// as a path watching without callback is meaningless.\n\t\t\tcallbacks := w.getCallbacksForPath(v.Path)\n\t\t\tif len(callbacks) == 0 {\n\t\t\t\t_ = w.watcher.Remove(v.Path)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase v.IsRemove():\n\t\t\t\t// It should check again the existence of the path.\n\t\t\t\t// It adds it back to the monitor if it still exists.\n\t\t\t\tif fileExists(v.Path) {\n\t\t\t\t\t// A watch will be automatically removed if the watched path is deleted or\n\t\t\t\t\t// renamed.\n\t\t\t\t\t//\n\t\t\t\t\t// It here adds the path back to monitor.\n\t\t\t\t\t// We need no worry about the repeat adding.\n\t\t\t\t\tif err = w.watcher.Add(v.Path); err != nil {\n\t\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\"fake remove event, watcher re-adds monitor for: %s\",\n\t\t\t\t\t\t\tv.Path,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\t// Change the event to RENAME, which means it renames itself to its origin name.\n\t\t\t\t\tv.Op = RENAME\n\t\t\t\t}\n\n\t\t\tcase v.IsRename():\n\t\t\t\t// It should check again the existence of the path.\n\t\t\t\t// It adds it back to the monitor if it still exists.\n\t\t\t\t// Especially Some editors might do RENAME and then CHMOD when it's editing file.\n\t\t\t\tif fileExists(v.Path) {\n\t\t\t\t\t// A watch will be automatically removed if the watched path is deleted or\n\t\t\t\t\t// renamed.\n\t\t\t\t\t//\n\t\t\t\t\t// It might lose the monitoring for the path, so we add the path back to monitor.\n\t\t\t\t\t// We need no worry about the repeat adding.\n\t\t\t\t\tif err = w.watcher.Add(v.Path); err != nil {\n\t\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\"fake rename event, watcher re-adds monitor for: %s\",\n\t\t\t\t\t\t\tv.Path,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\t// Change the event to CHMOD.\n\t\t\t\t\tv.Op = CHMOD\n\t\t\t\t}\n\n\t\t\tcase v.IsCreate():\n\t\t\t\t// =================================================================================\n\t\t\t\t// Note that it here just adds the path to monitor without any callback registering,\n\t\t\t\t// because its parent already has the callbacks.\n\t\t\t\t// =================================================================================\n\t\t\t\tif w.checkRecursiveWatchingInCreatingEvent(v.Path) {\n\t\t\t\t\t// It handles only folders, watching folders also watching its sub files.\n\t\t\t\t\tfor _, subPath := range fileAllDirs(v.Path) {\n\t\t\t\t\t\tif fileIsDir(subPath) {\n\t\t\t\t\t\t\tif err = w.watcher.Add(subPath); err != nil {\n\t\t\t\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\"folder creation event, watcher adds monitor for: %s\",\n\t\t\t\t\t\t\t\t\tsubPath,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Calling the callbacks in multiple goroutines.\n\t\t\tfor _, callback := range callbacks {\n\t\t\t\tgo w.doCallback(v, callback)\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// checkRecursiveWatchingInCreatingEvent checks and returns whether recursive adding given `path` to watcher\n// in creating event.\nfunc (w *Watcher) checkRecursiveWatchingInCreatingEvent(path string) bool {\n\tif !fileIsDir(path) {\n\t\treturn false\n\t}\n\tvar (\n\t\tparentDirPath string\n\t\tdirPath       = path\n\t)\n\tfor {\n\t\tparentDirPath = fileDir(dirPath)\n\t\tif parentDirPath == dirPath {\n\t\t\tbreak\n\t\t}\n\t\tif callbackItem := w.callbacks.Get(parentDirPath); callbackItem != nil {\n\t\t\tfor _, node := range callbackItem.FrontAll() {\n\t\t\t\tif node.recursive {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdirPath = parentDirPath\n\t}\n\treturn false\n}\n\nfunc (w *Watcher) doCallback(event *Event, callback *Callback) {\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tswitch exception {\n\t\t\tcase callbackExitEventPanicStr:\n\t\t\t\tw.RemoveCallback(callback.Id)\n\t\t\tdefault:\n\t\t\t\tif e, ok := exception.(error); ok {\n\t\t\t\t\tpanic(gerror.WrapCode(gcode.CodeInternalPanic, e))\n\t\t\t\t}\n\t\t\t\tpanic(exception)\n\t\t\t}\n\t\t}\n\t}()\n\tcallback.Func(event)\n}\n\n// getCallbacksForPath searches and returns all callbacks with given `path`.\n//\n// It also searches its parents for callbacks if they're recursive.\nfunc (w *Watcher) getCallbacksForPath(path string) (callbacks []*Callback) {\n\t// Firstly add the callbacks of itself.\n\tif item := w.callbacks.Get(path); item != nil {\n\t\tcallbacks = append(callbacks, item.FrontAll()...)\n\t}\n\t// ============================================================================================================\n\t// Secondly searches its direct parent for callbacks.\n\t//\n\t// Note that it is SPECIAL handling here, which is the different between `recursive` and `not recursive` logic\n\t// for direct parent folder of `path` that events are from.\n\t// ============================================================================================================\n\tdirPath := fileDir(path)\n\tif item := w.callbacks.Get(dirPath); item != nil {\n\t\tcallbacks = append(callbacks, item.FrontAll()...)\n\t}\n\n\t// Lastly searches all the parents of directory of `path` recursively for callbacks.\n\tfor {\n\t\tparentDirPath := fileDir(dirPath)\n\t\tif parentDirPath == dirPath {\n\t\t\tbreak\n\t\t}\n\t\tif item := w.callbacks.Get(parentDirPath); item != nil {\n\t\t\tfor _, node := range item.FrontAll() {\n\t\t\t\tif node.recursive {\n\t\t\t\t\tcallbacks = append(callbacks, node)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdirPath = parentDirPath\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gfsnotify/gfsnotify_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gfsnotify_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestWatcher_AddOnce(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalue := gtype.New()\n\t\tpath := gfile.Temp(gconv.String(gtime.TimestampNano()))\n\t\terr := gfile.PutContents(path, \"init\")\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tcallback1, err := gfsnotify.AddOnce(\"mywatch\", path, func(event *gfsnotify.Event) {\n\t\t\tvalue.Set(1)\n\t\t})\n\t\tt.AssertNil(err)\n\t\tcallback2, err := gfsnotify.AddOnce(\"mywatch\", path, func(event *gfsnotify.Event) {\n\t\t\tvalue.Set(2)\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(callback2, nil)\n\n\t\terr = gfile.PutContents(path, \"1\")\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(value, 1)\n\n\t\terr = gfsnotify.RemoveCallback(callback1.Id)\n\t\tt.AssertNil(err)\n\n\t\terr = gfile.PutContents(path, \"2\")\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(value, 1)\n\t})\n}\n\nfunc TestWatcher_AddRemove(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath1 := gfile.Temp() + gfile.Separator + gconv.String(gtime.TimestampNano())\n\t\tpath2 := gfile.Temp() + gfile.Separator + gconv.String(gtime.TimestampNano()) + \"2\"\n\t\tgfile.PutContents(path1, \"1\")\n\t\tdefer func() {\n\t\t\tgfile.Remove(path1)\n\t\t\tgfile.Remove(path2)\n\t\t}()\n\t\tv := gtype.NewInt(1)\n\t\tcallback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) {\n\t\t\tif event.IsWrite() {\n\t\t\t\tv.Set(2)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif event.IsRename() {\n\t\t\t\tv.Set(3)\n\t\t\t\tgfsnotify.Exit()\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(callback, nil)\n\n\t\tgfile.PutContents(path1, \"2\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 2)\n\n\t\tgfile.Rename(path1, path2)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath1 := gfile.Temp() + gfile.Separator + gconv.String(gtime.TimestampNano())\n\t\tgfile.PutContents(path1, \"1\")\n\t\tdefer func() {\n\t\t\tgfile.Remove(path1)\n\t\t}()\n\t\tv := gtype.NewInt(1)\n\t\tcallback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) {\n\t\t\tif event.IsWrite() {\n\t\t\t\tv.Set(2)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif event.IsRemove() {\n\t\t\t\tv.Set(4)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(callback, nil)\n\n\t\tgfile.PutContents(path1, \"2\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 2)\n\n\t\tgfile.Remove(path1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 4)\n\n\t\tgfile.PutContents(path1, \"1\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 4)\n\t})\n}\n\nfunc TestWatcher_Callback1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath1 := gfile.Temp(gtime.TimestampNanoStr())\n\t\tgfile.PutContents(path1, \"1\")\n\t\tdefer func() {\n\t\t\tgfile.Remove(path1)\n\t\t}()\n\t\tv := gtype.NewInt(1)\n\t\tcallback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) {\n\t\t\tif event.IsWrite() {\n\t\t\t\tv.Set(2)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(callback, nil)\n\n\t\tgfile.PutContents(path1, \"2\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 2)\n\n\t\tv.Set(3)\n\t\tgfsnotify.RemoveCallback(callback.Id)\n\t\tgfile.PutContents(path1, \"3\")\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v.Val(), 3)\n\t})\n}\n\nfunc TestWatcher_Callback2(t *testing.T) {\n\t// multiple callbacks\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath1 := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.Assert(gfile.PutContents(path1, \"1\"), nil)\n\t\tdefer func() {\n\t\t\tgfile.Remove(path1)\n\t\t}()\n\t\tv1 := gtype.NewInt(1)\n\t\tv2 := gtype.NewInt(1)\n\t\tcallback1, err1 := gfsnotify.Add(path1, func(event *gfsnotify.Event) {\n\t\t\tif event.IsWrite() {\n\t\t\t\tv1.Set(2)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\tcallback2, err2 := gfsnotify.Add(path1, func(event *gfsnotify.Event) {\n\t\t\tif event.IsWrite() {\n\t\t\t\tv2.Set(2)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.AssertNE(callback1, nil)\n\t\tt.AssertNE(callback2, nil)\n\n\t\tt.Assert(gfile.PutContents(path1, \"2\"), nil)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v1.Val(), 2)\n\t\tt.Assert(v2.Val(), 2)\n\n\t\tv1.Set(3)\n\t\tv2.Set(3)\n\t\tgfsnotify.RemoveCallback(callback1.Id)\n\t\tt.Assert(gfile.PutContents(path1, \"3\"), nil)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(v1.Val(), 3)\n\t\tt.Assert(v2.Val(), 2)\n\t})\n}\n\nfunc TestWatcher_WatchFolderWithRecursively(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tarray   = garray.New(true)\n\t\t\tdirPath = gfile.Temp(gtime.TimestampNanoStr())\n\t\t)\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(dirPath)\n\n\t\t_, err = gfsnotify.Add(dirPath, func(event *gfsnotify.Event) {\n\t\t\t//fmt.Println(event.String())\n\t\t\tarray.Append(1)\n\t\t})\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.Assert(array.Len(), 0)\n\n\t\tsubDirPath := gfile.Join(dirPath, gtime.TimestampNanoStr())\n\t\terr = gfile.Mkdir(subDirPath)\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.Assert(array.Len(), 1)\n\n\t\tf, err := gfile.Create(gfile.Join(subDirPath, gtime.TimestampNanoStr()))\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(f.Close())\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestWatcher_WatchFolderWithoutRecursively(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tarray   = garray.New(true)\n\t\t\tdirPath = gfile.Temp(gtime.TimestampNanoStr())\n\t\t)\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\n\t\t_, err = gfsnotify.Add(dirPath, func(event *gfsnotify.Event) {\n\t\t\t// fmt.Println(event.String())\n\t\t\tarray.Append(1)\n\t\t}, gfsnotify.WatchOption{NoRecursive: true})\n\t\tt.AssertNil(err)\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.Assert(array.Len(), 0)\n\n\t\tf, err := gfile.Create(gfile.Join(dirPath, \"1\"))\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(f.Close())\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestWatcher_WatchClose(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr     error\n\t\t\tdirPath = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\twatcher *gfsnotify.Watcher\n\t\t)\n\n\t\terr = gfile.Mkdir(dirPath)\n\t\tt.AssertNil(err)\n\n\t\twatcher, err = gfsnotify.New()\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(watcher, nil)\n\n\t\ttime.Sleep(time.Millisecond * 100)\n\t\twatcher.Close()\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package glog implements powerful and easy-to-use leveled logging functionality.\npackage glog\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/os/grpool\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// ILogger is the API interface for logger.\ntype ILogger interface {\n\tPrint(ctx context.Context, v ...any)\n\tPrintf(ctx context.Context, format string, v ...any)\n\tDebug(ctx context.Context, v ...any)\n\tDebugf(ctx context.Context, format string, v ...any)\n\tInfo(ctx context.Context, v ...any)\n\tInfof(ctx context.Context, format string, v ...any)\n\tNotice(ctx context.Context, v ...any)\n\tNoticef(ctx context.Context, format string, v ...any)\n\tWarning(ctx context.Context, v ...any)\n\tWarningf(ctx context.Context, format string, v ...any)\n\tError(ctx context.Context, v ...any)\n\tErrorf(ctx context.Context, format string, v ...any)\n\tCritical(ctx context.Context, v ...any)\n\tCriticalf(ctx context.Context, format string, v ...any)\n\tPanic(ctx context.Context, v ...any)\n\tPanicf(ctx context.Context, format string, v ...any)\n\tFatal(ctx context.Context, v ...any)\n\tFatalf(ctx context.Context, format string, v ...any)\n}\n\nconst (\n\tcommandEnvKeyForDebug = \"gf.glog.debug\"\n)\n\nvar (\n\t// Ensure Logger implements ILogger.\n\t_ ILogger = &Logger{}\n\n\t// Default logger object, for package method usage.\n\tdefaultLogger = New()\n\n\t// Goroutine pool for async logging output.\n\t// It uses only one asynchronous worker to ensure log sequence.\n\tasyncPool = grpool.New(1)\n\n\t// defaultDebug enables debug level or not in default,\n\t// which can be configured using command option or system environment.\n\tdefaultDebug = true\n)\n\nfunc init() {\n\tdefaultDebug = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForDebug, \"true\"))\n\tSetDebug(defaultDebug)\n}\n\n// DefaultLogger returns the default logger.\nfunc DefaultLogger() *Logger {\n\treturn defaultLogger\n}\n\n// SetDefaultLogger sets the default logger for package glog.\n// Note that there might be concurrent safety issue if calls this function\n// in different goroutines.\nfunc SetDefaultLogger(l *Logger) {\n\tdefaultLogger = l\n}\n"
  },
  {
    "path": "os/glog/glog_api.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport \"context\"\n\n// Print prints `v` with newline using fmt.Sprintln.\n// The parameter `v` can be multiple variables.\nfunc Print(ctx context.Context, v ...any) {\n\tdefaultLogger.Print(ctx, v...)\n}\n\n// Printf prints `v` with format `format` using fmt.Sprintf.\n// The parameter `v` can be multiple variables.\nfunc Printf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Printf(ctx, format, v...)\n}\n\n// Fatal prints the logging content with [FATA] header and newline, then exit the current process.\nfunc Fatal(ctx context.Context, v ...any) {\n\tdefaultLogger.Fatal(ctx, v...)\n}\n\n// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.\nfunc Fatalf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Fatalf(ctx, format, v...)\n}\n\n// Panic prints the logging content with [PANI] header and newline, then panics.\nfunc Panic(ctx context.Context, v ...any) {\n\tdefaultLogger.Panic(ctx, v...)\n}\n\n// Panicf prints the logging content with [PANI] header, custom format and newline, then panics.\nfunc Panicf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Panicf(ctx, format, v...)\n}\n\n// Info prints the logging content with [INFO] header and newline.\nfunc Info(ctx context.Context, v ...any) {\n\tdefaultLogger.Info(ctx, v...)\n}\n\n// Infof prints the logging content with [INFO] header, custom format and newline.\nfunc Infof(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Infof(ctx, format, v...)\n}\n\n// Debug prints the logging content with [DEBU] header and newline.\nfunc Debug(ctx context.Context, v ...any) {\n\tdefaultLogger.Debug(ctx, v...)\n}\n\n// Debugf prints the logging content with [DEBU] header, custom format and newline.\nfunc Debugf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Debugf(ctx, format, v...)\n}\n\n// Notice prints the logging content with [NOTI] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Notice(ctx context.Context, v ...any) {\n\tdefaultLogger.Notice(ctx, v...)\n}\n\n// Noticef prints the logging content with [NOTI] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Noticef(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Noticef(ctx, format, v...)\n}\n\n// Warning prints the logging content with [WARN] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Warning(ctx context.Context, v ...any) {\n\tdefaultLogger.Warning(ctx, v...)\n}\n\n// Warningf prints the logging content with [WARN] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Warningf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Warningf(ctx, format, v...)\n}\n\n// Error prints the logging content with [ERRO] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Error(ctx context.Context, v ...any) {\n\tdefaultLogger.Error(ctx, v...)\n}\n\n// Errorf prints the logging content with [ERRO] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Errorf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Errorf(ctx, format, v...)\n}\n\n// Critical prints the logging content with [CRIT] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Critical(ctx context.Context, v ...any) {\n\tdefaultLogger.Critical(ctx, v...)\n}\n\n// Criticalf prints the logging content with [CRIT] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc Criticalf(ctx context.Context, format string, v ...any) {\n\tdefaultLogger.Criticalf(ctx, format, v...)\n}\n"
  },
  {
    "path": "os/glog/glog_chaining.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"io\"\n)\n\n// Expose returns the default logger of package glog.\nfunc Expose() *Logger {\n\treturn defaultLogger\n}\n\n// To is a chaining function,\n// which redirects current logging content output to the sepecified `writer`.\nfunc To(writer io.Writer) *Logger {\n\treturn defaultLogger.To(writer)\n}\n\n// Path is a chaining function,\n// which sets the directory path to `path` for current logging content output.\nfunc Path(path string) *Logger {\n\treturn defaultLogger.Path(path)\n}\n\n// Cat is a chaining function,\n// which sets the category to `category` for current logging content output.\nfunc Cat(category string) *Logger {\n\treturn defaultLogger.Cat(category)\n}\n\n// File is a chaining function,\n// which sets file name `pattern` for the current logging content output.\nfunc File(pattern string) *Logger {\n\treturn defaultLogger.File(pattern)\n}\n\n// Level is a chaining function,\n// which sets logging level for the current logging content output.\nfunc Level(level int) *Logger {\n\treturn defaultLogger.Level(level)\n}\n\n// LevelStr is a chaining function,\n// which sets logging level for the current logging content output using level string.\nfunc LevelStr(levelStr string) *Logger {\n\treturn defaultLogger.LevelStr(levelStr)\n}\n\n// Skip is a chaining function,\n// which sets stack skip for the current logging content output.\n// It also affects the caller file path checks when line number printing enabled.\nfunc Skip(skip int) *Logger {\n\treturn defaultLogger.Skip(skip)\n}\n\n// Stack is a chaining function,\n// which sets stack options for the current logging content output .\nfunc Stack(enabled bool, skip ...int) *Logger {\n\treturn defaultLogger.Stack(enabled, skip...)\n}\n\n// StackWithFilter is a chaining function,\n// which sets stack filter for the current logging content output .\nfunc StackWithFilter(filter string) *Logger {\n\treturn defaultLogger.StackWithFilter(filter)\n}\n\n// Stdout is a chaining function,\n// which enables/disables stdout for the current logging content output.\n// It's enabled in default.\nfunc Stdout(enabled ...bool) *Logger {\n\treturn defaultLogger.Stdout(enabled...)\n}\n\n// Header is a chaining function,\n// which enables/disables log header for the current logging content output.\n// It's enabled in default.\nfunc Header(enabled ...bool) *Logger {\n\treturn defaultLogger.Header(enabled...)\n}\n\n// Line is a chaining function,\n// which enables/disables printing its caller file along with its line number.\n// The parameter `long` specified whether print the long absolute file path, eg: /a/b/c/d.go:23.\nfunc Line(long ...bool) *Logger {\n\treturn defaultLogger.Line(long...)\n}\n\n// Async is a chaining function,\n// which enables/disables async logging output feature.\nfunc Async(enabled ...bool) *Logger {\n\treturn defaultLogger.Async(enabled...)\n}\n"
  },
  {
    "path": "os/glog/glog_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"context\"\n\t\"io\"\n)\n\n// SetConfig set configurations for the defaultLogger.\nfunc SetConfig(config Config) error {\n\treturn defaultLogger.SetConfig(config)\n}\n\n// SetConfigWithMap set configurations with map for the defaultLogger.\nfunc SetConfigWithMap(m map[string]any) error {\n\treturn defaultLogger.SetConfigWithMap(m)\n}\n\n// SetPath sets the directory path for file logging.\nfunc SetPath(path string) error {\n\treturn defaultLogger.SetPath(path)\n}\n\n// GetPath returns the logging directory path for file logging.\n// It returns empty string if no directory path set.\nfunc GetPath() string {\n\treturn defaultLogger.GetPath()\n}\n\n// SetFile sets the file name `pattern` for file logging.\n// Datetime pattern can be used in `pattern`, eg: access-{Ymd}.log.\n// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log\nfunc SetFile(pattern string) {\n\tdefaultLogger.SetFile(pattern)\n}\n\n// SetLevel sets the default logging level.\nfunc SetLevel(level int) {\n\tdefaultLogger.SetLevel(level)\n}\n\n// GetLevel returns the default logging level value.\nfunc GetLevel() int {\n\treturn defaultLogger.GetLevel()\n}\n\n// SetWriter sets the customized logging `writer` for logging.\n// The `writer` object should implements the io.Writer interface.\n// Developer can use customized logging `writer` to redirect logging output to another service,\n// eg: kafka, mysql, mongodb, etc.\nfunc SetWriter(writer io.Writer) {\n\tdefaultLogger.SetWriter(writer)\n}\n\n// GetWriter returns the customized writer object, which implements the io.Writer interface.\n// It returns nil if no customized writer set.\nfunc GetWriter() io.Writer {\n\treturn defaultLogger.GetWriter()\n}\n\n// SetDebug enables/disables the debug level for default defaultLogger.\n// The debug level is enabled in default.\nfunc SetDebug(debug bool) {\n\tdefaultLogger.SetDebug(debug)\n}\n\n// SetAsync enables/disables async logging output feature for default defaultLogger.\nfunc SetAsync(enabled bool) {\n\tdefaultLogger.SetAsync(enabled)\n}\n\n// SetStdoutPrint sets whether ouptput the logging contents to stdout, which is true in default.\nfunc SetStdoutPrint(enabled bool) {\n\tdefaultLogger.SetStdoutPrint(enabled)\n}\n\n// SetHeaderPrint sets whether output header of the logging contents, which is true in default.\nfunc SetHeaderPrint(enabled bool) {\n\tdefaultLogger.SetHeaderPrint(enabled)\n}\n\n// SetPrefix sets prefix string for every logging content.\n// Prefix is part of header, which means if header output is shut, no prefix will be output.\nfunc SetPrefix(prefix string) {\n\tdefaultLogger.SetPrefix(prefix)\n}\n\n// SetFlags sets extra flags for logging output features.\nfunc SetFlags(flags int) {\n\tdefaultLogger.SetFlags(flags)\n}\n\n// GetFlags returns the flags of defaultLogger.\nfunc GetFlags() int {\n\treturn defaultLogger.GetFlags()\n}\n\n// SetCtxKeys sets the context keys for defaultLogger. The keys is used for retrieving values\n// from context and printing them to logging content.\n//\n// Note that multiple calls of this function will overwrite the previous set context keys.\nfunc SetCtxKeys(keys ...any) {\n\tdefaultLogger.SetCtxKeys(keys...)\n}\n\n// GetCtxKeys retrieves and returns the context keys for logging.\nfunc GetCtxKeys() []any {\n\treturn defaultLogger.GetCtxKeys()\n}\n\n// PrintStack prints the caller stack,\n// the optional parameter `skip` specify the skipped stack offset from the end point.\nfunc PrintStack(ctx context.Context, skip ...int) {\n\tdefaultLogger.PrintStack(ctx, skip...)\n}\n\n// GetStack returns the caller stack content,\n// the optional parameter `skip` specify the skipped stack offset from the end point.\nfunc GetStack(skip ...int) string {\n\treturn defaultLogger.GetStack(skip...)\n}\n\n// SetStack enables/disables the stack feature in failure logging outputs.\nfunc SetStack(enabled bool) {\n\tdefaultLogger.SetStack(enabled)\n}\n\n// SetLevelStr sets the logging level by level string.\nfunc SetLevelStr(levelStr string) error {\n\treturn defaultLogger.SetLevelStr(levelStr)\n}\n\n// SetLevelPrefix sets the prefix string for specified level.\nfunc SetLevelPrefix(level int, prefix string) {\n\tdefaultLogger.SetLevelPrefix(level, prefix)\n}\n\n// SetLevelPrefixes sets the level to prefix string mapping for the defaultLogger.\nfunc SetLevelPrefixes(prefixes map[int]string) {\n\tdefaultLogger.SetLevelPrefixes(prefixes)\n}\n\n// GetLevelPrefix returns the prefix string for specified level.\nfunc GetLevelPrefix(level int) string {\n\treturn defaultLogger.GetLevelPrefix(level)\n}\n\n// SetHandlers sets the logging handlers for default defaultLogger.\nfunc SetHandlers(handlers ...Handler) {\n\tdefaultLogger.SetHandlers(handlers...)\n}\n\n// SetWriterColorEnable sets the file logging with color\nfunc SetWriterColorEnable(enabled bool) {\n\tdefaultLogger.SetWriterColorEnable(enabled)\n}\n"
  },
  {
    "path": "os/glog/glog_instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport \"github.com/gogf/gf/v2/container/gmap\"\n\nconst (\n\t// DefaultName is the default group name for instance usage.\n\tDefaultName = \"default\"\n)\n\nvar (\n\t// Checker function for instances map.\n\tchecker = func(v *Logger) bool { return v == nil }\n\t// Instances map.\n\tinstances = gmap.NewKVMapWithChecker[string, *Logger](checker, true)\n)\n\n// Instance returns an instance of Logger with default settings.\n// The parameter `name` is the name for the instance.\nfunc Instance(name ...string) *Logger {\n\tkey := DefaultName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tkey = name[0]\n\t}\n\treturn instances.GetOrSetFuncLock(key, New)\n}\n"
  },
  {
    "path": "os/glog/glog_logger.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/internal/consts\"\n\t\"github.com/gogf/gf/v2/internal/errors\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfpool\"\n\t\"github.com/gogf/gf/v2/os/gmlock\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Logger is the struct for logging management.\ntype Logger struct {\n\tparent *Logger // Parent logger, if it is not empty, it means the logger is used in chaining function.\n\tconfig Config  // Logger configuration.\n}\n\nconst (\n\tdefaultFileFormat                 = `{Y-m-d}.log`\n\tdefaultTimeFormat                 = \"2006-01-02T15:04:05.000Z07:00\"\n\tdefaultFileFlags                  = os.O_CREATE | os.O_WRONLY | os.O_APPEND\n\tdefaultFilePerm                   = os.FileMode(0666)\n\tdefaultFileExpire                 = time.Minute\n\tpathFilterKey                     = \"/os/glog/glog\"\n\tmemoryLockPrefixForPrintingToFile = \"glog.printToFile:\"\n)\n\nconst (\n\tF_ASYNC      = 1 << iota // Print logging content asynchronously。\n\tF_FILE_LONG              // Print full file name and line number: /a/b/c/d.go:23.\n\tF_FILE_SHORT             // Print final file name element and line number: d.go:23. overrides F_FILE_LONG.\n\tF_TIME_DATE              // Print the date in the local time zone: 2009-01-23.\n\tF_TIME_TIME              // Print the time in the local time zone: 01:23:23.\n\tF_TIME_MILLI             // Print the time with milliseconds in the local time zone: 01:23:23.675.\n\tF_CALLER_FN              // Print Caller function name and package: main.main\n\tF_TIME_STD   = F_TIME_DATE | F_TIME_MILLI\n)\n\n// New creates and returns a custom logger.\nfunc New() *Logger {\n\treturn &Logger{\n\t\tconfig: DefaultConfig(),\n\t}\n}\n\n// NewWithWriter creates and returns a custom logger with io.Writer.\nfunc NewWithWriter(writer io.Writer) *Logger {\n\tl := New()\n\tl.SetWriter(writer)\n\treturn l\n}\n\n// Clone returns a new logger, which a `shallow copy` of the current logger.\n// Note that the attribute `config` of the cloned one is the shallow copy of current one.\nfunc (l *Logger) Clone() *Logger {\n\treturn &Logger{\n\t\tconfig: l.config,\n\t\tparent: l,\n\t}\n}\n\n// getFilePath returns the logging file path.\n// The logging file name must have extension name of \"log\".\nfunc (l *Logger) getFilePath(now time.Time) string {\n\t// Content containing \"{}\" in the file name is formatted using gtime.\n\tfile, _ := gregex.ReplaceStringFunc(`{.+?}`, l.config.File, func(s string) string {\n\t\treturn gtime.New(now).Format(strings.Trim(s, \"{}\"))\n\t})\n\tfile = gfile.Join(l.config.Path, file)\n\treturn file\n}\n\n// print prints `s` to defined writer, logging file or passed `std`.\nfunc (l *Logger) print(ctx context.Context, level int, stack string, values ...any) {\n\t// Lazy initialize for rotation feature.\n\t// It uses atomic reading operation to enhance the performance checking.\n\t// It here uses CAP for performance and concurrent safety.\n\t// It just initializes once for each logger.\n\tif l.config.RotateSize > 0 || l.config.RotateExpire > 0 {\n\t\tif !l.config.rotatedHandlerInitialized.Val() && l.config.rotatedHandlerInitialized.Cas(false, true) {\n\t\t\tl.rotateChecksTimely(ctx)\n\t\t\tintlog.Printf(ctx, \"logger rotation initialized: every %s\", l.config.RotateCheckInterval.String())\n\t\t}\n\t}\n\n\tvar (\n\t\tnow   = time.Now()\n\t\tinput = &HandlerInput{\n\t\t\tinternalHandlerInfo: internalHandlerInfo{\n\t\t\t\tindex: -1,\n\t\t\t},\n\t\t\tLogger: l,\n\t\t\tBuffer: bytes.NewBuffer(nil),\n\t\t\tTime:   now,\n\t\t\tColor:  defaultLevelColor[level],\n\t\t\tLevel:  level,\n\t\t\tStack:  stack,\n\t\t\tValues: values,\n\t\t}\n\t)\n\n\t// Logging handlers.\n\tif len(l.config.Handlers) > 0 {\n\t\tinput.handlers = append(input.handlers, l.config.Handlers...)\n\t} else if defaultHandler != nil {\n\t\tinput.handlers = []Handler{defaultHandler}\n\t}\n\tinput.handlers = append(input.handlers, doFinalPrint)\n\n\t// Time.\n\ttimeFormat := \"\"\n\tif l.config.TimeFormat != \"\" {\n\t\ttimeFormat = l.config.TimeFormat\n\t} else {\n\t\tif l.config.Flags&F_TIME_DATE > 0 {\n\t\t\ttimeFormat += \"2006-01-02\"\n\t\t}\n\t\tif l.config.Flags&F_TIME_TIME > 0 {\n\t\t\tif timeFormat != \"\" {\n\t\t\t\ttimeFormat += \" \"\n\t\t\t}\n\t\t\ttimeFormat += \"15:04:05\"\n\t\t}\n\t\tif l.config.Flags&F_TIME_MILLI > 0 {\n\t\t\tif timeFormat != \"\" {\n\t\t\t\ttimeFormat += \" \"\n\t\t\t}\n\t\t\ttimeFormat += \"15:04:05.000\"\n\t\t}\n\t}\n\n\tif len(timeFormat) > 0 {\n\t\tinput.TimeFormat = now.Format(timeFormat)\n\t}\n\n\t// Level string.\n\tinput.LevelFormat = l.GetLevelPrefix(level)\n\n\t// Caller path and Fn name.\n\tif l.config.Flags&(F_FILE_LONG|F_FILE_SHORT|F_CALLER_FN) > 0 {\n\t\tcallerFnName, path, line := gdebug.CallerWithFilter(\n\t\t\t[]string{consts.StackFilterKeyForGoFrame},\n\t\t\tl.config.StSkip,\n\t\t)\n\t\tif l.config.Flags&F_CALLER_FN > 0 {\n\t\t\tif len(callerFnName) > 2 {\n\t\t\t\tinput.CallerFunc = fmt.Sprintf(`[%s]`, callerFnName)\n\t\t\t}\n\t\t}\n\t\tif line >= 0 && len(path) > 1 {\n\t\t\tif l.config.Flags&F_FILE_LONG > 0 {\n\t\t\t\tinput.CallerPath = fmt.Sprintf(`%s:%d:`, path, line)\n\t\t\t}\n\t\t\tif l.config.Flags&F_FILE_SHORT > 0 {\n\t\t\t\tinput.CallerPath = fmt.Sprintf(`%s:%d:`, gfile.Basename(path), line)\n\t\t\t}\n\t\t}\n\t}\n\t// Prefix.\n\tif len(l.config.Prefix) > 0 {\n\t\tinput.Prefix = l.config.Prefix\n\t}\n\n\t// Convert value to string.\n\tif ctx != nil {\n\t\t// Tracing values.\n\t\tspanCtx := trace.SpanContextFromContext(ctx)\n\t\tif traceId := spanCtx.TraceID(); traceId.IsValid() {\n\t\t\tinput.TraceId = traceId.String()\n\t\t}\n\t\t// Context values.\n\t\tif len(l.config.CtxKeys) > 0 {\n\t\t\tfor _, ctxKey := range l.config.CtxKeys {\n\t\t\t\tvar ctxValue any\n\t\t\t\tif ctxValue = ctx.Value(ctxKey); ctxValue == nil {\n\t\t\t\t\tctxValue = ctx.Value(gctx.StrKey(gconv.String(ctxKey)))\n\t\t\t\t}\n\t\t\t\tif ctxValue != nil {\n\t\t\t\t\tif input.CtxStr != \"\" {\n\t\t\t\t\t\tinput.CtxStr += \", \"\n\t\t\t\t\t}\n\t\t\t\t\tinput.CtxStr += gconv.String(ctxValue)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif l.config.Flags&F_ASYNC > 0 {\n\t\tinput.IsAsync = true\n\t\terr := asyncPool.Add(ctx, func(ctx context.Context) {\n\t\t\tinput.Next(ctx)\n\t\t})\n\t\tif err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t} else {\n\t\tinput.Next(ctx)\n\t}\n}\n\n// doFinalPrint outputs the logging content according configuration.\nfunc (l *Logger) doFinalPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer {\n\tvar buffer *bytes.Buffer\n\t// Allow output to stdout?\n\tif l.config.StdoutPrint {\n\t\tif buf := l.printToStdout(ctx, input); buf != nil {\n\t\t\tbuffer = buf\n\t\t}\n\t}\n\n\t// Output content to disk file.\n\tif l.config.Path != \"\" {\n\t\tif buf := l.printToFile(ctx, input.Time, input); buf != nil {\n\t\t\tbuffer = buf\n\t\t}\n\t}\n\n\t// Used custom writer.\n\tif l.config.Writer != nil {\n\t\t// Output to custom writer.\n\t\tif buf := l.printToWriter(ctx, input); buf != nil {\n\t\t\tbuffer = buf\n\t\t}\n\t}\n\treturn buffer\n}\n\n// printToWriter writes buffer to writer.\nfunc (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) *bytes.Buffer {\n\tif l.config.Writer != nil {\n\t\tvar buffer = input.getRealBuffer(l.config.WriterColorEnable)\n\t\tif _, err := l.config.Writer.Write(buffer.Bytes()); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t\treturn buffer\n\t}\n\treturn nil\n}\n\n// printToStdout outputs logging content to stdout.\nfunc (l *Logger) printToStdout(ctx context.Context, input *HandlerInput) *bytes.Buffer {\n\tif l.config.StdoutPrint {\n\t\tvar (\n\t\t\terr    error\n\t\t\tbuffer = input.getRealBuffer(!l.config.StdoutColorDisabled)\n\t\t)\n\t\t// This will lose color in Windows os system. DO NOT USE.\n\t\t// if _, err := os.Stdout.Write(input.getRealBuffer(true).Bytes()); err != nil {\n\n\t\t// This will print color in Windows os system.\n\t\tif _, err = fmt.Fprint(color.Output, buffer.String()); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t\treturn buffer\n\t}\n\treturn nil\n}\n\n// printToFile outputs logging content to disk file.\nfunc (l *Logger) printToFile(ctx context.Context, t time.Time, in *HandlerInput) *bytes.Buffer {\n\tvar (\n\t\tbuffer        = in.getRealBuffer(l.config.WriterColorEnable)\n\t\tlogFilePath   = l.getFilePath(t)\n\t\tmemoryLockKey = memoryLockPrefixForPrintingToFile + logFilePath\n\t)\n\tgmlock.Lock(memoryLockKey)\n\tdefer gmlock.Unlock(memoryLockKey)\n\n\t// Rotation file size checks.\n\tif l.config.RotateSize > 0 && gfile.Size(logFilePath) > l.config.RotateSize {\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tfile := l.createFpInPool(ctx, logFilePath)\n\t\t\tif file == nil {\n\t\t\t\tintlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath)\n\t\t\t\treturn buffer\n\t\t\t}\n\n\t\t\tif _, err := file.Write(buffer.Bytes()); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\n\t\t\tif err := file.Close(true); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t\tl.rotateFileBySize(ctx, t)\n\n\t\t\treturn buffer\n\t\t}\n\n\t\tl.rotateFileBySize(ctx, t)\n\t}\n\t// Logging content outputting to disk file.\n\tif file := l.createFpInPool(ctx, logFilePath); file == nil {\n\t\tintlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath)\n\t} else {\n\t\tif _, err := file.Write(buffer.Bytes()); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t\tif err := file.Close(); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}\n\treturn buffer\n}\n\n// createFpInPool retrieves and returns a file pointer from file pool.\nfunc (l *Logger) createFpInPool(ctx context.Context, path string) *gfpool.File {\n\tfile, err := gfpool.Open(\n\t\tpath,\n\t\tdefaultFileFlags,\n\t\tdefaultFilePerm,\n\t\tdefaultFileExpire,\n\t)\n\tif err != nil {\n\t\t// panic(err)\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t}\n\treturn file\n}\n\n// getFpFromPool retrieves and returns a file pointer from file pool.\nfunc (l *Logger) getFpFromPool(ctx context.Context, path string) *gfpool.File {\n\tfile := gfpool.Get(\n\t\tpath,\n\t\tdefaultFileFlags,\n\t\tdefaultFilePerm,\n\t\tdefaultFileExpire,\n\t)\n\tif file == nil {\n\t\tintlog.Errorf(ctx, `can not find the file, path:%s`, path)\n\t}\n\treturn file\n}\n\n// printStd prints content `s` without stack.\nfunc (l *Logger) printStd(ctx context.Context, level int, values ...any) {\n\t// nil logger, print nothing\n\tif l == nil {\n\t\treturn\n\t}\n\tl.print(ctx, level, \"\", values...)\n}\n\n// printErr prints content `s` with stack check.\nfunc (l *Logger) printErr(ctx context.Context, level int, values ...any) {\n\t// nil logger, print nothing\n\tif l == nil {\n\t\treturn\n\t}\n\tvar stack string\n\tif l.config.StStatus == 1 {\n\t\tstack = l.GetStack()\n\t}\n\t// In matter of sequence, do not use stderr here, but use the same stdout.\n\tl.print(ctx, level, stack, values...)\n}\n\n// format formats `values` using fmt.Sprintf.\nfunc (l *Logger) format(format string, values ...any) string {\n\treturn fmt.Sprintf(format, values...)\n}\n\n// PrintStack prints the caller stack,\n// the optional parameter `skip` specify the skipped stack offset from the end point.\nfunc (l *Logger) PrintStack(ctx context.Context, skip ...int) {\n\tif s := l.GetStack(skip...); s != \"\" {\n\t\tl.Print(ctx, \"Stack:\\n\"+s)\n\t} else {\n\t\tl.Print(ctx)\n\t}\n}\n\n// GetStack returns the caller stack content,\n// the optional parameter `skip` specify the skipped stack offset from the end point.\nfunc (l *Logger) GetStack(skip ...int) string {\n\tstackSkip := l.config.StSkip\n\tif len(skip) > 0 {\n\t\tstackSkip += skip[0]\n\t}\n\tfilters := []string{pathFilterKey}\n\tif l.config.StFilter != \"\" {\n\t\tfilters = append(filters, l.config.StFilter)\n\t}\n\t// Whether filter framework error stacks.\n\tif errors.IsStackModeBrief() {\n\t\tfilters = append(filters, consts.StackFilterKeyForGoFrame)\n\t}\n\treturn gdebug.StackWithFilters(filters, stackSkip)\n}\n"
  },
  {
    "path": "os/glog/glog_logger_api.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n)\n\n// Print prints `v` with newline using fmt.Sprintln.\n// The parameter `v` can be multiple variables.\nfunc (l *Logger) Print(ctx context.Context, v ...any) {\n\tl.printStd(ctx, LEVEL_NONE, v...)\n}\n\n// Printf prints `v` with format `format` using fmt.Sprintf.\n// The parameter `v` can be multiple variables.\nfunc (l *Logger) Printf(ctx context.Context, format string, v ...any) {\n\tl.printStd(ctx, LEVEL_NONE, l.format(format, v...))\n}\n\n// Fatal prints the logging content with [FATA] header and newline, then exit the current process.\nfunc (l *Logger) Fatal(ctx context.Context, v ...any) {\n\tl.printErr(ctx, LEVEL_FATA, v...)\n\tos.Exit(1)\n}\n\n// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.\nfunc (l *Logger) Fatalf(ctx context.Context, format string, v ...any) {\n\tl.printErr(ctx, LEVEL_FATA, l.format(format, v...))\n\tos.Exit(1)\n}\n\n// Panic prints the logging content with [PANI] header and newline, then panics.\nfunc (l *Logger) Panic(ctx context.Context, v ...any) {\n\tl.printErr(ctx, LEVEL_PANI, v...)\n\tpanic(fmt.Sprint(v...))\n}\n\n// Panicf prints the logging content with [PANI] header, custom format and newline, then panics.\nfunc (l *Logger) Panicf(ctx context.Context, format string, v ...any) {\n\tl.printErr(ctx, LEVEL_PANI, l.format(format, v...))\n\tpanic(l.format(format, v...))\n}\n\n// Info prints the logging content with [INFO] header and newline.\nfunc (l *Logger) Info(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_INFO) {\n\t\tl.printStd(ctx, LEVEL_INFO, v...)\n\t}\n}\n\n// Infof prints the logging content with [INFO] header, custom format and newline.\nfunc (l *Logger) Infof(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_INFO) {\n\t\tl.printStd(ctx, LEVEL_INFO, l.format(format, v...))\n\t}\n}\n\n// Debug prints the logging content with [DEBU] header and newline.\nfunc (l *Logger) Debug(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_DEBU) {\n\t\tl.printStd(ctx, LEVEL_DEBU, v...)\n\t}\n}\n\n// Debugf prints the logging content with [DEBU] header, custom format and newline.\nfunc (l *Logger) Debugf(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_DEBU) {\n\t\tl.printStd(ctx, LEVEL_DEBU, l.format(format, v...))\n\t}\n}\n\n// Notice prints the logging content with [NOTI] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Notice(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_NOTI) {\n\t\tl.printStd(ctx, LEVEL_NOTI, v...)\n\t}\n}\n\n// Noticef prints the logging content with [NOTI] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Noticef(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_NOTI) {\n\t\tl.printStd(ctx, LEVEL_NOTI, l.format(format, v...))\n\t}\n}\n\n// Warning prints the logging content with [WARN] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Warning(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_WARN) {\n\t\tl.printStd(ctx, LEVEL_WARN, v...)\n\t}\n}\n\n// Warningf prints the logging content with [WARN] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Warningf(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_WARN) {\n\t\tl.printStd(ctx, LEVEL_WARN, l.format(format, v...))\n\t}\n}\n\n// Error prints the logging content with [ERRO] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Error(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_ERRO) {\n\t\tl.printErr(ctx, LEVEL_ERRO, v...)\n\t}\n}\n\n// Errorf prints the logging content with [ERRO] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Errorf(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_ERRO) {\n\t\tl.printErr(ctx, LEVEL_ERRO, l.format(format, v...))\n\t}\n}\n\n// Critical prints the logging content with [CRIT] header and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Critical(ctx context.Context, v ...any) {\n\tif l.checkLevel(LEVEL_CRIT) {\n\t\tl.printErr(ctx, LEVEL_CRIT, v...)\n\t}\n}\n\n// Criticalf prints the logging content with [CRIT] header, custom format and newline.\n// It also prints caller stack info if stack feature is enabled.\nfunc (l *Logger) Criticalf(ctx context.Context, format string, v ...any) {\n\tif l.checkLevel(LEVEL_CRIT) {\n\t\tl.printErr(ctx, LEVEL_CRIT, l.format(format, v...))\n\t}\n}\n\n// checkLevel checks whether the given `level` could be output.\nfunc (l *Logger) checkLevel(level int) bool {\n\t// nil logger, print nothing\n\tif l == nil {\n\t\treturn false\n\t}\n\treturn l.config.Level&level > 0\n}\n"
  },
  {
    "path": "os/glog/glog_logger_chaining.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// To is a chaining function,\n// which redirects current logging content output to the specified `writer`.\nfunc (l *Logger) To(writer io.Writer) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetWriter(writer)\n\treturn logger\n}\n\n// Path is a chaining function,\n// which sets the directory path to `path` for current logging content output.\n//\n// Note that the parameter `path` is a directory path, not a file path.\nfunc (l *Logger) Path(path string) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tif path != \"\" {\n\t\tif err := logger.SetPath(path); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\treturn logger\n}\n\n// Cat is a chaining function,\n// which sets the category to `category` for current logging content output.\n// Param `category` can be hierarchical, eg: module/user.\nfunc (l *Logger) Cat(category string) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tif logger.config.Path != \"\" {\n\t\tif err := logger.SetPath(gfile.Join(logger.config.Path, category)); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\treturn logger\n}\n\n// File is a chaining function,\n// which sets file name `pattern` for the current logging content output.\nfunc (l *Logger) File(file string) *Logger {\n\tif file == \"\" {\n\t\treturn l\n\t}\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetFile(file)\n\treturn logger\n}\n\n// Level is a chaining function,\n// which sets logging level for the current logging content output.\nfunc (l *Logger) Level(level int) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetLevel(level)\n\treturn logger\n}\n\n// LevelStr is a chaining function,\n// which sets logging level for the current logging content output using level string.\nfunc (l *Logger) LevelStr(levelStr string) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tif err := logger.SetLevelStr(levelStr); err != nil {\n\t\tpanic(err)\n\t}\n\treturn logger\n}\n\n// Skip is a chaining function,\n// which sets stack skip for the current logging content output.\n// It also affects the caller file path checks when line number printing enabled.\nfunc (l *Logger) Skip(skip int) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetStackSkip(skip)\n\treturn logger\n}\n\n// Stack is a chaining function,\n// which sets stack options for the current logging content output .\nfunc (l *Logger) Stack(enabled bool, skip ...int) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetStack(enabled)\n\tif len(skip) > 0 {\n\t\tlogger.SetStackSkip(skip[0])\n\t}\n\treturn logger\n}\n\n// StackWithFilter is a chaining function,\n// which sets stack filter for the current logging content output .\nfunc (l *Logger) StackWithFilter(filter string) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tlogger.SetStack(true)\n\tlogger.SetStackFilter(filter)\n\treturn logger\n}\n\n// Stdout is a chaining function,\n// which enables/disables stdout for the current logging content output.\n// It's enabled in default.\nfunc (l *Logger) Stdout(enabled ...bool) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\t// stdout printing is enabled if `enabled` is not passed.\n\tif len(enabled) > 0 && !enabled[0] {\n\t\tlogger.config.StdoutPrint = false\n\t} else {\n\t\tlogger.config.StdoutPrint = true\n\t}\n\treturn logger\n}\n\n// Header is a chaining function,\n// which enables/disables log header for the current logging content output.\n// It's enabled in default.\nfunc (l *Logger) Header(enabled ...bool) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\t// header is enabled if `enabled` is not passed.\n\tif len(enabled) > 0 && !enabled[0] {\n\t\tlogger.SetHeaderPrint(false)\n\t} else {\n\t\tlogger.SetHeaderPrint(true)\n\t}\n\treturn logger\n}\n\n// Line is a chaining function,\n// which enables/disables printing its caller file path along with its line number.\n// The parameter `long` specified whether print the long absolute file path, eg: /a/b/c/d.go:23,\n// or else short one: d.go:23.\nfunc (l *Logger) Line(long ...bool) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\tif len(long) > 0 && long[0] {\n\t\tlogger.config.Flags |= F_FILE_LONG\n\t} else {\n\t\tlogger.config.Flags |= F_FILE_SHORT\n\t}\n\treturn logger\n}\n\n// Async is a chaining function,\n// which enables/disables async logging output feature.\nfunc (l *Logger) Async(enabled ...bool) *Logger {\n\tlogger := (*Logger)(nil)\n\tif l.parent == nil {\n\t\tlogger = l.Clone()\n\t} else {\n\t\tlogger = l\n\t}\n\t// async feature is enabled if `enabled` is not passed.\n\tif len(enabled) > 0 && !enabled[0] {\n\t\tlogger.SetAsync(false)\n\t} else {\n\t\tlogger.SetAsync(true)\n\t}\n\treturn logger\n}\n"
  },
  {
    "path": "os/glog/glog_logger_color.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport \"github.com/fatih/color\"\n\nconst (\n\tCOLOR_BLACK = 30 + iota\n\tCOLOR_RED\n\tCOLOR_GREEN\n\tCOLOR_YELLOW\n\tCOLOR_BLUE\n\tCOLOR_MAGENTA\n\tCOLOR_CYAN\n\tCOLOR_WHITE\n)\n\n// Foreground Hi-Intensity text colors\nconst (\n\tCOLOR_HI_BLACK = 90 + iota\n\tCOLOR_HI_RED\n\tCOLOR_HI_GREEN\n\tCOLOR_HI_YELLOW\n\tCOLOR_HI_BLUE\n\tCOLOR_HI_MAGENTA\n\tCOLOR_HI_CYAN\n\tCOLOR_HI_WHITE\n)\n\n// defaultLevelColor defines the default level and its mapping prefix string.\nvar defaultLevelColor = map[int]int{\n\tLEVEL_DEBU: COLOR_YELLOW,\n\tLEVEL_INFO: COLOR_GREEN,\n\tLEVEL_NOTI: COLOR_CYAN,\n\tLEVEL_WARN: COLOR_MAGENTA,\n\tLEVEL_ERRO: COLOR_RED,\n\tLEVEL_CRIT: COLOR_HI_RED,\n\tLEVEL_PANI: COLOR_HI_RED,\n\tLEVEL_FATA: COLOR_HI_RED,\n}\n\n// getColoredStr returns a string that is colored by given color.\nfunc (l *Logger) getColoredStr(c int, s string) string {\n\treturn color.New(color.Attribute(c)).Sprint(s)\n}\n\nfunc (l *Logger) getColorByLevel(level int) int {\n\treturn defaultLevelColor[level]\n}\n"
  },
  {
    "path": "os/glog/glog_logger_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Config is the configuration object for logger.\ntype Config struct {\n\tHandlers             []Handler      `json:\"-\"`                    // Logger handlers which implement feature similar as middleware.\n\tWriter               io.Writer      `json:\"-\"`                    // Customized io.Writer.\n\tFlags                int            `json:\"flags\"`                // Extra flags for logging output features.\n\tTimeFormat           string         `json:\"timeFormat\"`           // Logging time format\n\tPath                 string         `json:\"path\"`                 // Logging directory path.\n\tFile                 string         `json:\"file\"`                 // Format pattern for logging file.\n\tLevel                int            `json:\"level\"`                // Output level.\n\tPrefix               string         `json:\"prefix\"`               // Prefix string for every logging content.\n\tStSkip               int            `json:\"stSkip\"`               // Skipping count for stack.\n\tStStatus             int            `json:\"stStatus\"`             // Stack status(1: enabled - default; 0: disabled)\n\tStFilter             string         `json:\"stFilter\"`             // Stack string filter.\n\tCtxKeys              []any          `json:\"ctxKeys\"`              // Context keys for logging, which is used for value retrieving from context.\n\tHeaderPrint          bool           `json:\"header\"`               // Print header or not(true in default).\n\tStdoutPrint          bool           `json:\"stdout\"`               // Output to stdout or not(true in default).\n\tLevelPrint           bool           `json:\"levelPrint\"`           // Print level format string or not(true in default).\n\tLevelPrefixes        map[int]string `json:\"levelPrefixes\"`        // Logging level to its prefix string mapping.\n\tRotateSize           int64          `json:\"rotateSize\"`           // Rotate the logging file if its size > 0 in bytes.\n\tRotateExpire         time.Duration  `json:\"rotateExpire\"`         // Rotate the logging file if its mtime exceeds this duration.\n\tRotateBackupLimit    int            `json:\"rotateBackupLimit\"`    // Max backup for rotated files, default is 0, means no backups.\n\tRotateBackupExpire   time.Duration  `json:\"rotateBackupExpire\"`   // Max expires for rotated files, which is 0 in default, means no expiration.\n\tRotateBackupCompress int            `json:\"rotateBackupCompress\"` // Compress level for rotated files using gzip algorithm. It's 0 in default, means no compression.\n\tRotateCheckInterval  time.Duration  `json:\"rotateCheckInterval\"`  // Asynchronously checks the backups and expiration at intervals. It's 1 hour in default.\n\tStdoutColorDisabled  bool           `json:\"stdoutColorDisabled\"`  // Logging level prefix with color to writer or not (false in default).\n\tWriterColorEnable    bool           `json:\"writerColorEnable\"`    // Logging level prefix with color to writer or not (false in default).\n\tinternalConfig\n}\n\ntype internalConfig struct {\n\trotatedHandlerInitialized *gtype.Bool // Whether the rotation feature initialized.\n}\n\n// DefaultConfig returns the default configuration for logger.\nfunc DefaultConfig() Config {\n\tc := Config{\n\t\tFile:                defaultFileFormat,\n\t\tFlags:               F_TIME_STD,\n\t\tTimeFormat:          defaultTimeFormat,\n\t\tLevel:               LEVEL_ALL,\n\t\tCtxKeys:             []any{},\n\t\tStStatus:            1,\n\t\tHeaderPrint:         true,\n\t\tStdoutPrint:         true,\n\t\tLevelPrint:          true,\n\t\tLevelPrefixes:       make(map[int]string, len(defaultLevelPrefixes)),\n\t\tRotateCheckInterval: time.Hour,\n\t\tinternalConfig: internalConfig{\n\t\t\trotatedHandlerInitialized: gtype.NewBool(),\n\t\t},\n\t}\n\tfor k, v := range defaultLevelPrefixes {\n\t\tc.LevelPrefixes[k] = v\n\t}\n\tif !defaultDebug {\n\t\tc.Level = c.Level & ^LEVEL_DEBU\n\t}\n\treturn c\n}\n\n// GetConfig returns the configuration of current Logger.\nfunc (l *Logger) GetConfig() Config {\n\treturn l.config\n}\n\n// SetConfig set configurations for the logger.\nfunc (l *Logger) SetConfig(config Config) error {\n\tl.config = config\n\t// Necessary validation.\n\tif config.Path != \"\" {\n\t\tif err := l.SetPath(config.Path); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\treturn err\n\t\t}\n\t}\n\tintlog.Printf(context.TODO(), \"SetConfig: %+v\", l.config)\n\treturn nil\n}\n\n// SetConfigWithMap set configurations with map for the logger.\nfunc (l *Logger) SetConfigWithMap(m map[string]any) error {\n\tif len(m) == 0 {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"configuration cannot be empty\")\n\t}\n\t// The m now is a shallow copy of m.\n\t// A little tricky, isn't it?\n\tm = gutil.MapCopy(m)\n\t// Change string configuration to int value for level.\n\tlevelKey, levelValue := gutil.MapPossibleItemByKey(m, \"Level\")\n\tif levelValue != nil {\n\t\tif level, ok := levelStringMap[strings.ToUpper(gconv.String(levelValue))]; ok {\n\t\t\tm[levelKey] = level\n\t\t} else {\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid level string: %v`, levelValue)\n\t\t}\n\t}\n\t// Change string configuration to int value for file rotation size.\n\trotateSizeKey, rotateSizeValue := gutil.MapPossibleItemByKey(m, \"RotateSize\")\n\tif rotateSizeValue != nil {\n\t\tm[rotateSizeKey] = gfile.StrToSize(gconv.String(rotateSizeValue))\n\t\tif m[rotateSizeKey] == -1 {\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidConfiguration, `invalid rotate size: %v`, rotateSizeValue)\n\t\t}\n\t}\n\tif err := gconv.Struct(m, &l.config); err != nil {\n\t\treturn err\n\t}\n\treturn l.SetConfig(l.config)\n}\n\n// SetDebug enables/disables the debug level for logger.\n// The debug level is enabled in default.\nfunc (l *Logger) SetDebug(debug bool) {\n\tif debug {\n\t\tl.config.Level = l.config.Level | LEVEL_DEBU\n\t} else {\n\t\tl.config.Level = l.config.Level & ^LEVEL_DEBU\n\t}\n}\n\n// SetAsync enables/disables async logging output feature.\nfunc (l *Logger) SetAsync(enabled bool) {\n\tif enabled {\n\t\tl.config.Flags = l.config.Flags | F_ASYNC\n\t} else {\n\t\tl.config.Flags = l.config.Flags & ^F_ASYNC\n\t}\n}\n\n// SetFlags sets extra flags for logging output features.\nfunc (l *Logger) SetFlags(flags int) {\n\tl.config.Flags = flags\n}\n\n// GetFlags returns the flags of logger.\nfunc (l *Logger) GetFlags() int {\n\treturn l.config.Flags\n}\n\n// SetStack enables/disables the stack feature in failure logging outputs.\nfunc (l *Logger) SetStack(enabled bool) {\n\tif enabled {\n\t\tl.config.StStatus = 1\n\t} else {\n\t\tl.config.StStatus = 0\n\t}\n}\n\n// SetStackSkip sets the stack offset from the end point.\nfunc (l *Logger) SetStackSkip(skip int) {\n\tl.config.StSkip = skip\n}\n\n// SetStackFilter sets the stack filter from the end point.\nfunc (l *Logger) SetStackFilter(filter string) {\n\tl.config.StFilter = filter\n}\n\n// SetCtxKeys sets the context keys for logger. The keys is used for retrieving values\n// from context and printing them to logging content.\n//\n// Note that multiple calls of this function will overwrite the previous set context keys.\nfunc (l *Logger) SetCtxKeys(keys ...any) {\n\tl.config.CtxKeys = keys\n}\n\n// AppendCtxKeys appends extra keys to logger.\n// It ignores the key if it is already appended to the logger previously.\nfunc (l *Logger) AppendCtxKeys(keys ...any) {\n\tvar isExist bool\n\tfor _, key := range keys {\n\t\tisExist = false\n\t\tfor _, ctxKey := range l.config.CtxKeys {\n\t\t\tif ctxKey == key {\n\t\t\t\tisExist = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !isExist {\n\t\t\tl.config.CtxKeys = append(l.config.CtxKeys, key)\n\t\t}\n\t}\n}\n\n// GetCtxKeys retrieves and returns the context keys for logging.\nfunc (l *Logger) GetCtxKeys() []any {\n\treturn l.config.CtxKeys\n}\n\n// SetWriter sets the customized logging `writer` for logging.\n// The `writer` object should implement the io.Writer interface.\n// Developer can use customized logging `writer` to redirect logging output to another service,\n// eg: kafka, mysql, mongodb, etc.\nfunc (l *Logger) SetWriter(writer io.Writer) {\n\tl.config.Writer = writer\n}\n\n// GetWriter returns the customized writer object, which implements the io.Writer interface.\n// It returns nil if no writer previously set.\nfunc (l *Logger) GetWriter() io.Writer {\n\treturn l.config.Writer\n}\n\n// SetPath sets the directory path for file logging.\nfunc (l *Logger) SetPath(path string) error {\n\tif path == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"logging path is empty\")\n\t}\n\tif !gfile.Exists(path) {\n\t\tif err := gfile.Mkdir(path); err != nil {\n\t\t\treturn gerror.Wrapf(err, `Mkdir \"%s\" failed in PWD \"%s\"`, path, gfile.Pwd())\n\t\t}\n\t}\n\tl.config.Path = strings.TrimRight(path, gfile.Separator)\n\treturn nil\n}\n\n// GetPath returns the logging directory path for file logging.\n// It returns empty string if no directory path set.\nfunc (l *Logger) GetPath() string {\n\treturn l.config.Path\n}\n\n// SetFile sets the file name `pattern` for file logging.\n// Datetime pattern can be used in `pattern`, eg: access-{Ymd}.log.\n// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log\nfunc (l *Logger) SetFile(pattern string) {\n\tl.config.File = pattern\n}\n\n// SetTimeFormat sets the time format for the logging time.\nfunc (l *Logger) SetTimeFormat(timeFormat string) {\n\tl.config.TimeFormat = timeFormat\n}\n\n// SetStdoutPrint sets whether output the logging contents to stdout, which is true in default.\nfunc (l *Logger) SetStdoutPrint(enabled bool) {\n\tl.config.StdoutPrint = enabled\n}\n\n// SetHeaderPrint sets whether output header of the logging contents, which is true in default.\nfunc (l *Logger) SetHeaderPrint(enabled bool) {\n\tl.config.HeaderPrint = enabled\n}\n\n// SetLevelPrint sets whether output level string of the logging contents, which is true in default.\nfunc (l *Logger) SetLevelPrint(enabled bool) {\n\tl.config.LevelPrint = enabled\n}\n\n// SetPrefix sets prefix string for every logging content.\n// Prefix is part of header, which means if header output is shut, no prefix will be output.\nfunc (l *Logger) SetPrefix(prefix string) {\n\tl.config.Prefix = prefix\n}\n\n// SetHandlers sets the logging handlers for current logger.\nfunc (l *Logger) SetHandlers(handlers ...Handler) {\n\tl.config.Handlers = handlers\n}\n\n// SetWriterColorEnable enables file/writer logging with color.\nfunc (l *Logger) SetWriterColorEnable(enabled bool) {\n\tl.config.WriterColorEnable = enabled\n}\n\n// SetStdoutColorDisabled disables stdout logging with color.\nfunc (l *Logger) SetStdoutColorDisabled(disabled bool) {\n\tl.config.StdoutColorDisabled = disabled\n}\n"
  },
  {
    "path": "os/glog/glog_logger_handler.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Handler is function handler for custom logging content outputs.\ntype Handler func(ctx context.Context, in *HandlerInput)\n\n// HandlerInput is the input parameter struct for logging Handler.\n//\n// The logging content is consisted in:\n// TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath Content Values Stack\n//\n// The header in the logging content is:\n// TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath\ntype HandlerInput struct {\n\tinternalHandlerInfo\n\n\t// Current Logger object.\n\tLogger *Logger\n\n\t// Buffer for logging content outputs.\n\tBuffer *bytes.Buffer\n\n\t// (ReadOnly) Logging time, which is the time that logging triggers.\n\tTime time.Time\n\n\t// Formatted time string for output, like \"2016-01-09 12:00:00\".\n\tTimeFormat string\n\n\t// (ReadOnly) Using color constant value, like COLOR_RED, COLOR_BLUE, etc.\n\t// Example: 34\n\tColor int\n\n\t// (ReadOnly) Using level, like LEVEL_INFO, LEVEL_ERRO, etc.\n\t// Example: 256\n\tLevel int\n\n\t// Formatted level string for output, like \"DEBU\", \"ERRO\", etc.\n\t// Example: ERRO\n\tLevelFormat string\n\n\t// The source function name that calls logging, only available if F_CALLER_FN set.\n\tCallerFunc string\n\n\t// The source file path and its line number that calls logging,\n\t// only available if F_FILE_SHORT or F_FILE_LONG set.\n\tCallerPath string\n\n\t// The retrieved context value string from context, only available if Config.CtxKeys configured.\n\t// It's empty if no Config.CtxKeys configured.\n\tCtxStr string\n\n\t// Trace id, only available if OpenTelemetry is enabled, or else it's an empty string.\n\tTraceId string\n\n\t// Custom prefix string in logging content header part.\n\t// Note that, it takes no effect if HeaderPrint is disabled.\n\tPrefix string\n\n\t// Custom logging content for logging.\n\tContent string\n\n\t// The passed un-formatted values array to logger.\n\tValues []any\n\n\t// Stack string produced by logger, only available if Config.StStatus configured.\n\t// Note that there are usually multiple lines in stack content.\n\tStack string\n\n\t// IsAsync marks it is in asynchronous logging.\n\tIsAsync bool\n}\n\ntype internalHandlerInfo struct {\n\tindex    int       // Middleware handling index for internal usage.\n\thandlers []Handler // Handler array calling bu index.\n}\n\n// defaultHandler is the default handler for package.\nvar defaultHandler Handler\n\n// doFinalPrint is a handler for logging content printing.\n// This handler outputs logging content to file/stdout/write if any of them configured.\nfunc doFinalPrint(ctx context.Context, in *HandlerInput) {\n\tbuffer := in.Logger.doFinalPrint(ctx, in)\n\tif in.Buffer.Len() == 0 {\n\t\tin.Buffer = buffer\n\t}\n}\n\n// SetDefaultHandler sets default handler for package.\nfunc SetDefaultHandler(handler Handler) {\n\tdefaultHandler = handler\n}\n\n// GetDefaultHandler returns the default handler of package.\nfunc GetDefaultHandler() Handler {\n\treturn defaultHandler\n}\n\n// Next calls the next logging handler in middleware way.\nfunc (in *HandlerInput) Next(ctx context.Context) {\n\tin.index++\n\tif in.index < len(in.handlers) {\n\t\tin.handlers[in.index](ctx, in)\n\t}\n}\n\n// String returns the logging content formatted by default logging handler.\nfunc (in *HandlerInput) String(withColor ...bool) string {\n\tformatWithColor := false\n\tif len(withColor) > 0 {\n\t\tformatWithColor = withColor[0]\n\t}\n\treturn in.getDefaultBuffer(formatWithColor).String()\n}\n\n// ValuesContent converts and returns values as string content.\nfunc (in *HandlerInput) ValuesContent() string {\n\tvar (\n\t\tbuffer       = bytes.NewBuffer(nil)\n\t\tvalueContent string\n\t)\n\tfor _, v := range in.Values {\n\t\tvalueContent = gconv.String(v)\n\t\tif len(valueContent) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif buffer.Len() == 0 {\n\t\t\tbuffer.WriteString(valueContent)\n\t\t\tcontinue\n\t\t}\n\t\tif buffer.Bytes()[buffer.Len()-1] != '\\n' {\n\t\t\tbuffer.WriteString(\" \" + valueContent)\n\t\t\tcontinue\n\t\t}\n\t\t// Remove one blank line(\\n\\n).\n\t\tif valueContent[0] == '\\n' {\n\t\t\tvalueContent = valueContent[1:]\n\t\t}\n\t\tbuffer.WriteString(valueContent)\n\t}\n\treturn buffer.String()\n}\n\nfunc (in *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer {\n\tbuffer := bytes.NewBuffer(nil)\n\tif in.Logger.config.HeaderPrint {\n\t\tif in.TimeFormat != \"\" {\n\t\t\tbuffer.WriteString(in.TimeFormat)\n\t\t}\n\t\tif in.Logger.config.LevelPrint && in.LevelFormat != \"\" {\n\t\t\tvar levelStr = \"[\" + in.LevelFormat + \"]\"\n\t\t\tif withColor {\n\t\t\t\tin.addStringToBuffer(buffer, in.Logger.getColoredStr(\n\t\t\t\t\tin.Logger.getColorByLevel(in.Level), levelStr,\n\t\t\t\t))\n\t\t\t} else {\n\t\t\t\tin.addStringToBuffer(buffer, levelStr)\n\t\t\t}\n\t\t}\n\t}\n\tif in.TraceId != \"\" {\n\t\tin.addStringToBuffer(buffer, \"{\"+in.TraceId+\"}\")\n\t}\n\tif in.CtxStr != \"\" {\n\t\tin.addStringToBuffer(buffer, \"{\"+in.CtxStr+\"}\")\n\t}\n\tif in.Logger.config.HeaderPrint {\n\t\tif in.Prefix != \"\" {\n\t\t\tin.addStringToBuffer(buffer, in.Prefix)\n\t\t}\n\t\tif in.CallerFunc != \"\" {\n\t\t\tin.addStringToBuffer(buffer, in.CallerFunc)\n\t\t}\n\t\tif in.CallerPath != \"\" {\n\t\t\tin.addStringToBuffer(buffer, in.CallerPath)\n\t\t}\n\t}\n\n\tif in.Content != \"\" {\n\t\tin.addStringToBuffer(buffer, in.Content)\n\t}\n\n\tif len(in.Values) > 0 {\n\t\tin.addStringToBuffer(buffer, in.ValuesContent())\n\t}\n\n\tif in.Stack != \"\" {\n\t\tin.addStringToBuffer(buffer, \"\\nStack:\\n\"+in.Stack)\n\t}\n\t// avoid a single space at the end of a line.\n\tbuffer.WriteString(\"\\n\")\n\treturn buffer\n}\n\nfunc (in *HandlerInput) getRealBuffer(withColor bool) *bytes.Buffer {\n\tif in.Buffer.Len() > 0 {\n\t\treturn in.Buffer\n\t}\n\treturn in.getDefaultBuffer(withColor)\n}\n\nfunc (in *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, strings ...string) {\n\tfor _, s := range strings {\n\t\tif buffer.Len() > 0 {\n\t\t\tbuffer.WriteByte(' ')\n\t\t}\n\t\tbuffer.WriteString(s)\n\t}\n}\n"
  },
  {
    "path": "os/glog/glog_logger_handler_json.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// HandlerOutputJson is the structure outputting logging content as single json.\ntype HandlerOutputJson struct {\n\tTime       string `json:\"\"`           // Formatted time string, like \"2016-01-09 12:00:00\".\n\tTraceId    string `json:\",omitempty\"` // Trace id, only available if tracing is enabled.\n\tCtxStr     string `json:\",omitempty\"` // The retrieved context value string from context, only available if Config.CtxKeys configured.\n\tLevel      string `json:\"\"`           // Formatted level string, like \"DEBU\", \"ERRO\", etc. Eg: ERRO\n\tCallerPath string `json:\",omitempty\"` // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set.\n\tCallerFunc string `json:\",omitempty\"` // The source function name that calls logging, only available if F_CALLER_FN set.\n\tPrefix     string `json:\",omitempty\"` // Custom prefix string for logging content.\n\tContent    string `json:\"\"`           // Content is the main logging content, containing error stack string produced by logger.\n\tStack      string `json:\",omitempty\"` // Stack string produced by logger, only available if Config.StStatus configured.\n}\n\n// HandlerJson is a handler for output logging content as a single json string.\nfunc HandlerJson(ctx context.Context, in *HandlerInput) {\n\toutput := HandlerOutputJson{\n\t\tTime:       in.TimeFormat,\n\t\tTraceId:    in.TraceId,\n\t\tCtxStr:     in.CtxStr,\n\t\tLevel:      in.LevelFormat,\n\t\tCallerFunc: in.CallerFunc,\n\t\tCallerPath: in.CallerPath,\n\t\tPrefix:     in.Prefix,\n\t\tContent:    in.Content,\n\t\tStack:      in.Stack,\n\t}\n\tif len(in.Values) > 0 {\n\t\tif output.Content != \"\" {\n\t\t\toutput.Content += \" \"\n\t\t}\n\t\toutput.Content += in.ValuesContent()\n\t}\n\t// Output json content.\n\tjsonBytes, err := json.Marshal(output)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tin.Buffer.Write(jsonBytes)\n\tin.Buffer.Write([]byte(\"\\n\"))\n\tin.Next(ctx)\n}\n"
  },
  {
    "path": "os/glog/glog_logger_handler_structure.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"strconv\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype structuredBuffer struct {\n\tin     *HandlerInput\n\tbuffer *bytes.Buffer\n}\n\nconst (\n\tstructureKeyTime       = \"Time\"\n\tstructureKeyLevel      = \"Level\"\n\tstructureKeyPrefix     = \"Prefix\"\n\tstructureKeyContent    = \"Content\"\n\tstructureKeyTraceId    = \"TraceId\"\n\tstructureKeyCallerFunc = \"CallerFunc\"\n\tstructureKeyCallerPath = \"CallerPath\"\n\tstructureKeyCtxStr     = \"CtxStr\"\n\tstructureKeyStack      = \"Stack\"\n)\n\n// Copied from encoding/json/tables.go.\n//\n// safeSet holds the value true if the ASCII character with the given array\n// position can be represented inside a JSON string without any further\n// escaping.\n//\n// All values are true except for the ASCII control characters (0-31), the\n// double quote (\"), and the backslash character (\"\\\").\nvar safeSet = [utf8.RuneSelf]bool{\n\t' ':      true,\n\t'!':      true,\n\t'\"':      false,\n\t'#':      true,\n\t'$':      true,\n\t'%':      true,\n\t'&':      true,\n\t'\\'':     true,\n\t'(':      true,\n\t')':      true,\n\t'*':      true,\n\t'+':      true,\n\t',':      true,\n\t'-':      true,\n\t'.':      true,\n\t'/':      true,\n\t'0':      true,\n\t'1':      true,\n\t'2':      true,\n\t'3':      true,\n\t'4':      true,\n\t'5':      true,\n\t'6':      true,\n\t'7':      true,\n\t'8':      true,\n\t'9':      true,\n\t':':      true,\n\t';':      true,\n\t'<':      true,\n\t'=':      true,\n\t'>':      true,\n\t'?':      true,\n\t'@':      true,\n\t'A':      true,\n\t'B':      true,\n\t'C':      true,\n\t'D':      true,\n\t'E':      true,\n\t'F':      true,\n\t'G':      true,\n\t'H':      true,\n\t'I':      true,\n\t'J':      true,\n\t'K':      true,\n\t'L':      true,\n\t'M':      true,\n\t'N':      true,\n\t'O':      true,\n\t'P':      true,\n\t'Q':      true,\n\t'R':      true,\n\t'S':      true,\n\t'T':      true,\n\t'U':      true,\n\t'V':      true,\n\t'W':      true,\n\t'X':      true,\n\t'Y':      true,\n\t'Z':      true,\n\t'[':      true,\n\t'\\\\':     false,\n\t']':      true,\n\t'^':      true,\n\t'_':      true,\n\t'`':      true,\n\t'a':      true,\n\t'b':      true,\n\t'c':      true,\n\t'd':      true,\n\t'e':      true,\n\t'f':      true,\n\t'g':      true,\n\t'h':      true,\n\t'i':      true,\n\t'j':      true,\n\t'k':      true,\n\t'l':      true,\n\t'm':      true,\n\t'n':      true,\n\t'o':      true,\n\t'p':      true,\n\t'q':      true,\n\t'r':      true,\n\t's':      true,\n\t't':      true,\n\t'u':      true,\n\t'v':      true,\n\t'w':      true,\n\t'x':      true,\n\t'y':      true,\n\t'z':      true,\n\t'{':      true,\n\t'|':      true,\n\t'}':      true,\n\t'~':      true,\n\t'\\u007f': true,\n}\n\n// HandlerStructure is a handler for output logging content as a structured string.\nfunc HandlerStructure(ctx context.Context, in *HandlerInput) {\n\ts := newStructuredBuffer(in)\n\tin.Buffer.Write(s.Bytes())\n\tin.Buffer.Write([]byte(\"\\n\"))\n\tin.Next(ctx)\n}\n\nfunc newStructuredBuffer(in *HandlerInput) *structuredBuffer {\n\treturn &structuredBuffer{\n\t\tin:     in,\n\t\tbuffer: bytes.NewBuffer(nil),\n\t}\n}\n\nfunc (buf *structuredBuffer) Bytes() []byte {\n\tbuf.addValue(structureKeyTime, buf.in.TimeFormat)\n\tif buf.in.TraceId != \"\" {\n\t\tbuf.addValue(structureKeyTraceId, buf.in.TraceId)\n\t}\n\tif buf.in.CtxStr != \"\" {\n\t\tbuf.addValue(structureKeyCtxStr, buf.in.CtxStr)\n\t}\n\tif buf.in.LevelFormat != \"\" {\n\t\tbuf.addValue(structureKeyLevel, buf.in.LevelFormat)\n\t}\n\tif buf.in.CallerPath != \"\" {\n\t\tbuf.addValue(structureKeyCallerPath, buf.in.CallerPath)\n\t}\n\tif buf.in.CallerFunc != \"\" {\n\t\tbuf.addValue(structureKeyCallerFunc, buf.in.CallerFunc)\n\t}\n\tif buf.in.Prefix != \"\" {\n\t\tbuf.addValue(structureKeyPrefix, buf.in.Prefix)\n\t}\n\t// If the values cannot be the pair, move the first one to content.\n\tvalues := buf.in.Values\n\tif len(values)%2 != 0 {\n\t\tif buf.in.Content != \"\" {\n\t\t\tbuf.in.Content += \" \"\n\t\t}\n\t\tbuf.in.Content += gconv.String(values[0])\n\t\tvalues = values[1:]\n\t}\n\tif buf.in.Content != \"\" {\n\t\tbuf.addValue(structureKeyContent, buf.in.Content)\n\t}\n\t// Values pairs.\n\tfor i := 0; i < len(values); i += 2 {\n\t\tbuf.addValue(values[i], values[i+1])\n\t}\n\tif buf.in.Stack != \"\" {\n\t\tbuf.addValue(structureKeyStack, buf.in.Stack)\n\t}\n\tcontentBytes := buf.buffer.Bytes()\n\tbuf.buffer.Reset()\n\tcontentBytes = bytes.ReplaceAll(contentBytes, []byte{'\\n'}, []byte{' '})\n\treturn contentBytes\n}\n\nfunc (buf *structuredBuffer) addValue(k, v any) {\n\tvar (\n\t\tks = gconv.String(k)\n\t\tvs = gconv.String(v)\n\t)\n\tif buf.buffer.Len() > 0 {\n\t\tbuf.buffer.WriteByte(' ')\n\t}\n\tbuf.appendString(ks)\n\tbuf.buffer.WriteByte('=')\n\tbuf.appendString(vs)\n}\n\nfunc (buf *structuredBuffer) appendString(s string) {\n\tif buf.needsQuoting(s) {\n\t\ts = strconv.Quote(s)\n\t}\n\tbuf.buffer.WriteString(s)\n}\n\nfunc (buf *structuredBuffer) needsQuoting(s string) bool {\n\tif len(s) == 0 {\n\t\treturn true\n\t}\n\tfor i := 0; i < len(s); {\n\t\tb := s[i]\n\t\tif b < utf8.RuneSelf {\n\t\t\t// Quote anything except a backslash that would need quoting in a\n\t\t\t// JSON string, as well as space and '='\n\t\t\tif b != '\\\\' && (b == ' ' || b == '=' || !safeSet[b]) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\t\tr, size := utf8.DecodeRuneInString(s[i:])\n\t\tif r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {\n\t\t\treturn true\n\t\t}\n\t\ti += size\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "os/glog/glog_logger_level.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Note that the LEVEL_PANI and LEVEL_FATA levels are not used for logging output,\n// but for prefix configurations.\nconst (\n\tLEVEL_ALL  = LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT\n\tLEVEL_DEV  = LEVEL_ALL\n\tLEVEL_PROD = LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT\n\tLEVEL_NONE = 0\n\tLEVEL_DEBU = 1 << iota // 16\n\tLEVEL_INFO             // 32\n\tLEVEL_NOTI             // 64\n\tLEVEL_WARN             // 128\n\tLEVEL_ERRO             // 256\n\tLEVEL_CRIT             // 512\n\tLEVEL_PANI             // 1024\n\tLEVEL_FATA             // 2048\n)\n\n// defaultLevelPrefixes defines the default level and its mapping prefix string.\nvar defaultLevelPrefixes = map[int]string{\n\tLEVEL_DEBU: \"DEBU\",\n\tLEVEL_INFO: \"INFO\",\n\tLEVEL_NOTI: \"NOTI\",\n\tLEVEL_WARN: \"WARN\",\n\tLEVEL_ERRO: \"ERRO\",\n\tLEVEL_CRIT: \"CRIT\",\n\tLEVEL_PANI: \"PANI\",\n\tLEVEL_FATA: \"FATA\",\n}\n\n// levelStringMap defines level string name to its level mapping.\nvar levelStringMap = map[string]int{\n\t\"ALL\":      LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"DEV\":      LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"DEVELOP\":  LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"PROD\":     LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"PRODUCT\":  LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"DEBU\":     LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"DEBUG\":    LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"INFO\":     LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"NOTI\":     LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"NOTICE\":   LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"WARN\":     LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"WARNING\":  LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,\n\t\"ERRO\":     LEVEL_ERRO | LEVEL_CRIT,\n\t\"ERROR\":    LEVEL_ERRO | LEVEL_CRIT,\n\t\"CRIT\":     LEVEL_CRIT,\n\t\"CRITICAL\": LEVEL_CRIT,\n}\n\n// SetLevel sets the logging level.\n// Note that levels ` LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA ` cannot be removed for logging content,\n// which are automatically added to levels.\nfunc (l *Logger) SetLevel(level int) {\n\tl.config.Level = level | LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA\n}\n\n// GetLevel returns the logging level value.\nfunc (l *Logger) GetLevel() int {\n\treturn l.config.Level\n}\n\n// SetLevelStr sets the logging level by level string.\nfunc (l *Logger) SetLevelStr(levelStr string) error {\n\tif level, ok := levelStringMap[strings.ToUpper(levelStr)]; ok {\n\t\tl.config.Level = level\n\t} else {\n\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid level string: %s`, levelStr)\n\t}\n\treturn nil\n}\n\n// SetLevelPrefix sets the prefix string for specified level.\nfunc (l *Logger) SetLevelPrefix(level int, prefix string) {\n\tl.config.LevelPrefixes[level] = prefix\n}\n\n// SetLevelPrefixes sets the level to prefix string mapping for the logger.\nfunc (l *Logger) SetLevelPrefixes(prefixes map[int]string) {\n\tfor k, v := range prefixes {\n\t\tl.config.LevelPrefixes[k] = v\n\t}\n}\n\n// GetLevelPrefix returns the prefix string for specified level.\nfunc (l *Logger) GetLevelPrefix(level int) string {\n\treturn l.config.LevelPrefixes[level]\n}\n\n// getLevelPrefixWithBrackets returns the prefix string with brackets for specified level.\nfunc (l *Logger) getLevelPrefixWithBrackets(level int) string {\n\tlevelStr := \"\"\n\tif s, ok := l.config.LevelPrefixes[level]; ok {\n\t\tlevelStr = \"[\" + s + \"]\"\n\t}\n\treturn levelStr\n}\n"
  },
  {
    "path": "os/glog/glog_logger_rotate.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gmlock\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nconst (\n\tmemoryLockPrefixForRotating = \"glog.rotateChecksTimely:\"\n)\n\n// rotateFileBySize rotates the current logging file according to the\n// configured rotation size.\nfunc (l *Logger) rotateFileBySize(ctx context.Context, now time.Time) {\n\tif l.config.RotateSize <= 0 {\n\t\treturn\n\t}\n\tif err := l.doRotateFile(ctx, l.getFilePath(now)); err != nil {\n\t\t// panic(err)\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t}\n}\n\n// doRotateFile rotates the given logging file.\nfunc (l *Logger) doRotateFile(ctx context.Context, filePath string) error {\n\tmemoryLockKey := \"glog.doRotateFile:\" + filePath\n\tif !gmlock.TryLock(memoryLockKey) {\n\t\treturn nil\n\t}\n\tdefer gmlock.Unlock(memoryLockKey)\n\n\tintlog.PrintFunc(ctx, func() string {\n\t\treturn fmt.Sprintf(`start rotating file by size: %s, file: %s`, gfile.SizeFormat(filePath), filePath)\n\t})\n\tdefer intlog.PrintFunc(ctx, func() string {\n\t\treturn fmt.Sprintf(`done rotating file by size: %s, size: %s`, gfile.SizeFormat(filePath), filePath)\n\t})\n\n\t// No backups, it then just removes the current logging file.\n\tif l.config.RotateBackupLimit == 0 {\n\t\tif err := gfile.RemoveFile(filePath); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tintlog.Printf(\n\t\t\tctx,\n\t\t\t`%d size exceeds, no backups set, remove original logging file: %s`,\n\t\t\tl.config.RotateSize, filePath,\n\t\t)\n\t\treturn nil\n\t}\n\t// Else it creates new backup files.\n\tvar (\n\t\tdirPath     = gfile.Dir(filePath)\n\t\tfileName    = gfile.Name(filePath)\n\t\tfileExtName = gfile.ExtName(filePath)\n\t\tnewFilePath = \"\"\n\t)\n\t// Rename the logging file by adding extra datetime information to microseconds, like:\n\t// access.log          -> access.20200326101301899002.log\n\t// access.20200326.log -> access.20200326.20200326101301899002.log\n\tfor {\n\t\tvar (\n\t\t\tnow   = gtime.Now()\n\t\t\tmicro = now.Microsecond() % 1000\n\t\t)\n\t\tif micro == 0 {\n\t\t\tmicro = 101\n\t\t} else {\n\t\t\tfor micro < 100 {\n\t\t\t\tmicro *= 10\n\t\t\t}\n\t\t}\n\t\tnewFilePath = gfile.Join(\n\t\t\tdirPath,\n\t\t\tfmt.Sprintf(\n\t\t\t\t`%s.%s%d.%s`,\n\t\t\t\tfileName, now.Format(\"YmdHisu\"), micro, fileExtName,\n\t\t\t),\n\t\t)\n\t\tif !gfile.Exists(newFilePath) {\n\t\t\tbreak\n\t\t} else {\n\t\t\tintlog.Printf(ctx, `rotation file exists, continue: %s`, newFilePath)\n\t\t}\n\t}\n\tintlog.Printf(ctx, \"rotating file by size from %s to %s\", filePath, newFilePath)\n\tif err := gfile.Rename(filePath, newFilePath); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// rotateChecksTimely timely checks the backups expiration and the compression.\nfunc (l *Logger) rotateChecksTimely(ctx context.Context) {\n\tdefer gtimer.AddOnce(ctx, l.config.RotateCheckInterval, l.rotateChecksTimely)\n\n\t// Checks whether file rotation not enabled.\n\tif l.config.RotateSize <= 0 && l.config.RotateExpire == 0 {\n\t\tintlog.Printf(\n\t\t\tctx,\n\t\t\t\"logging rotation ignore checks: RotateSize: %d, RotateExpire: %s\",\n\t\t\tl.config.RotateSize, l.config.RotateExpire.String(),\n\t\t)\n\t\treturn\n\t}\n\n\t// It here uses memory lock to guarantee the concurrent safety.\n\tmemoryLockKey := memoryLockPrefixForRotating + l.config.Path\n\tif !gmlock.TryLock(memoryLockKey) {\n\t\treturn\n\t}\n\tdefer gmlock.Unlock(memoryLockKey)\n\n\tvar (\n\t\tnow        = time.Now()\n\t\tpattern    = \"*.log, *.gz\"\n\t\tfiles, err = gfile.ScanDirFile(l.config.Path, pattern, true)\n\t)\n\tif err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t}\n\tintlog.Printf(ctx, \"logging rotation start checks: %+v\", files)\n\t// get file name regex pattern\n\t// access-{y-m-d}-test.log => access-$-test.log => access-\\$-test\\.log => access-(.+?)-test\\.log\n\tfileNameRegexPattern, _ := gregex.ReplaceString(`{.+?}`, \"$\", l.config.File)\n\tfileNameRegexPattern = gregex.Quote(fileNameRegexPattern)\n\tfileNameRegexPattern = strings.ReplaceAll(fileNameRegexPattern, \"\\\\$\", \"(.+?)\")\n\t// =============================================================\n\t// Rotation of expired file checks.\n\t// =============================================================\n\tif l.config.RotateExpire > 0 {\n\t\tvar (\n\t\t\tmtime         time.Time\n\t\t\tsubDuration   time.Duration\n\t\t\texpireRotated bool\n\t\t)\n\t\tfor _, file := range files {\n\t\t\t// ignore backup file\n\t\t\tif gregex.IsMatchString(`.+\\.\\d{20}\\.log`, gfile.Basename(file)) || gfile.ExtName(file) == \"gz\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// ignore not matching file\n\t\t\tif !gregex.IsMatchString(fileNameRegexPattern, file) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmtime = gfile.MTime(file)\n\t\t\tsubDuration = now.Sub(mtime)\n\t\t\tif subDuration > l.config.RotateExpire {\n\t\t\t\tfunc() {\n\t\t\t\t\tmemoryLockFileKey := memoryLockPrefixForPrintingToFile + file\n\t\t\t\t\tif !gmlock.TryLock(memoryLockFileKey) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tdefer gmlock.Unlock(memoryLockFileKey)\n\t\t\t\t\texpireRotated = true\n\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t`%v - %v = %v > %v, rotation expire logging file: %s`,\n\t\t\t\t\t\tnow, mtime, subDuration, l.config.RotateExpire, file,\n\t\t\t\t\t)\n\t\t\t\t\tif err = l.doRotateFile(ctx, file); err != nil {\n\t\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\t\t}\n\t\tif expireRotated {\n\t\t\t// Update the files array.\n\t\t\tfiles, err = gfile.ScanDirFile(l.config.Path, pattern, true)\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// =============================================================\n\t// Rotated file compression.\n\t// =============================================================\n\tneedCompressFileArray := garray.NewStrArray()\n\tif l.config.RotateBackupCompress > 0 {\n\t\tfor _, file := range files {\n\t\t\t// Eg: access.20200326101301899002.log.gz\n\t\t\tif gfile.ExtName(file) == \"gz\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// ignore not matching file\n\t\t\toriginalLoggingFilePath, _ := gregex.ReplaceString(`\\.\\d{20}`, \"\", file)\n\t\t\tif !gregex.IsMatchString(fileNameRegexPattern, originalLoggingFilePath) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Eg:\n\t\t\t// access.20200326101301899002.log\n\t\t\tif gregex.IsMatchString(`.+\\.\\d{20}\\.log`, gfile.Basename(file)) {\n\t\t\t\tneedCompressFileArray.Append(file)\n\t\t\t}\n\t\t}\n\t\tif needCompressFileArray.Len() > 0 {\n\t\t\tneedCompressFileArray.Iterator(func(_ int, path string) bool {\n\t\t\t\terr := gcompress.GzipFile(path, path+\".gz\")\n\t\t\t\tif err == nil {\n\t\t\t\t\tintlog.Printf(ctx, `compressed done, remove original logging file: %s`, path)\n\t\t\t\t\tif err = gfile.RemoveFile(path); err != nil {\n\t\t\t\t\t\tintlog.Print(ctx, err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tintlog.Print(ctx, err)\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t})\n\t\t\t// Update the files array.\n\t\t\tfiles, err = gfile.ScanDirFile(l.config.Path, pattern, true)\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// =============================================================\n\t// Backups count limitation and expiration checks.\n\t// =============================================================\n\tbackupFiles := garray.NewSortedArray(func(a, b any) int {\n\t\t// Sorted by rotated/backup file mtime.\n\t\t// The older rotated/backup file is put in the head of array.\n\t\tvar (\n\t\t\tfile1  = a.(string)\n\t\t\tfile2  = b.(string)\n\t\t\tresult = gfile.MTimestampMilli(file1) - gfile.MTimestampMilli(file2)\n\t\t)\n\t\tif result <= 0 {\n\t\t\treturn -1\n\t\t}\n\t\treturn 1\n\t})\n\tif l.config.RotateBackupLimit > 0 || l.config.RotateBackupExpire > 0 {\n\t\tfor _, file := range files {\n\t\t\t// ignore not matching file\n\t\t\toriginalLoggingFilePath, _ := gregex.ReplaceString(`\\.\\d{20}`, \"\", file)\n\t\t\tif !gregex.IsMatchString(fileNameRegexPattern, originalLoggingFilePath) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif gregex.IsMatchString(`.+\\.\\d{20}\\.log`, gfile.Basename(file)) {\n\t\t\t\tbackupFiles.Add(file)\n\t\t\t}\n\t\t}\n\t\tintlog.Printf(ctx, `calculated backup files array: %+v`, backupFiles)\n\t\tdiff := backupFiles.Len() - l.config.RotateBackupLimit\n\t\tfor i := 0; i < diff; i++ {\n\t\t\tpath, _ := backupFiles.PopLeft()\n\t\t\tintlog.Printf(ctx, `remove exceeded backup limit file: %s`, path)\n\t\t\tif err = gfile.RemoveFile(path.(string)); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t}\n\t\t// Backups expiration checking.\n\t\tif l.config.RotateBackupExpire > 0 {\n\t\t\tvar (\n\t\t\t\tmtime       time.Time\n\t\t\t\tsubDuration time.Duration\n\t\t\t)\n\t\t\tbackupFiles.Iterator(func(_ int, v any) bool {\n\t\t\t\tpath := v.(string)\n\t\t\t\tmtime = gfile.MTime(path)\n\t\t\t\tsubDuration = now.Sub(mtime)\n\t\t\t\tif subDuration > l.config.RotateBackupExpire {\n\t\t\t\t\tintlog.Printf(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t`%v - %v = %v > %v, remove expired backup file: %s`,\n\t\t\t\t\t\tnow, mtime, subDuration, l.config.RotateBackupExpire, path,\n\t\t\t\t\t)\n\t\t\t\t\tif err = gfile.RemoveFile(path); err != nil {\n\t\t\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t\t\t}\n\t\t\t\t\treturn true\n\t\t\t\t} else {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/glog/glog_logger_writer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n)\n\n// Write implements the io.Writer interface.\n// It just prints the content using Print.\nfunc (l *Logger) Write(p []byte) (n int, err error) {\n\tl.Header(false).Print(context.TODO(), string(bytes.TrimRight(p, \"\\r\\n\")))\n\treturn len(p), nil\n}\n"
  },
  {
    "path": "os/glog/glog_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog_test\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n)\n\nfunc ExampleContext() {\n\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"123456789\")\n\tg.Log().Error(ctx, \"runtime error\")\n\n\t// May Output:\n\t// 2020-06-08 20:17:03.630 [ERRO] {Trace-Id: 123456789} runtime error\n\t// Stack:\n\t// ...\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_SetConfigWithMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tm := map[string]any{\n\t\t\t\"path\":     \"/var/log\",\n\t\t\t\"level\":    \"all\",\n\t\t\t\"stdout\":   false,\n\t\t\t\"StStatus\": 0,\n\t\t}\n\t\terr := l.SetConfigWithMap(m)\n\t\tt.AssertNil(err)\n\t\tt.Assert(l.config.Path, m[\"path\"])\n\t\tt.Assert(l.config.Level, LEVEL_ALL)\n\t\tt.Assert(l.config.StdoutPrint, m[\"stdout\"])\n\t})\n}\n\nfunc Test_SetConfigWithMap_LevelStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tl := New()\n\t\tm := map[string]any{\n\t\t\t\"level\": \"all\",\n\t\t}\n\t\terr := l.SetConfigWithMap(m)\n\t\tt.AssertNil(err)\n\n\t\tl.SetWriter(buffer)\n\n\t\tl.Debug(ctx, \"test\")\n\t\tl.Warning(ctx, \"test\")\n\t\tt.Assert(strings.Contains(buffer.String(), \"DEBU\"), true)\n\t\tt.Assert(strings.Contains(buffer.String(), \"WARN\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tl := New()\n\t\tm := map[string]any{\n\t\t\t\"level\": \"warn\",\n\t\t}\n\t\terr := l.SetConfigWithMap(m)\n\t\tt.AssertNil(err)\n\t\tl.SetWriter(buffer)\n\t\tl.Debug(ctx, \"test\")\n\t\tl.Warning(ctx, \"test\")\n\t\tt.Assert(strings.Contains(buffer.String(), \"DEBU\"), false)\n\t\tt.Assert(strings.Contains(buffer.String(), \"WARN\"), true)\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_Print(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Print(ctx, 1, 2, 3)\n\t\tl.Printf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"[\"), 0)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Debug(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Debug(ctx, 1, 2, 3)\n\t\tl.Debugf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_DEBU]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Info(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Info(ctx, 1, 2, 3)\n\t\tl.Infof(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_INFO]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Notice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Notice(ctx, 1, 2, 3)\n\t\tl.Noticef(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_NOTI]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Warning(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Warning(ctx, 1, 2, 3)\n\t\tl.Warningf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_WARN]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Error(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := NewWithWriter(w)\n\t\tl.Error(ctx, 1, 2, 3)\n\t\tl.Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_LevelPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := New()\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_DEBU), defaultLevelPrefixes[LEVEL_DEBU])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_INFO), defaultLevelPrefixes[LEVEL_INFO])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_NOTI), defaultLevelPrefixes[LEVEL_NOTI])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_WARN), defaultLevelPrefixes[LEVEL_WARN])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_ERRO), defaultLevelPrefixes[LEVEL_ERRO])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_CRIT), defaultLevelPrefixes[LEVEL_CRIT])\n\t\tl.SetLevelPrefix(LEVEL_DEBU, \"debug\")\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_DEBU), \"debug\")\n\t\tl.SetLevelPrefixes(map[int]string{\n\t\t\tLEVEL_CRIT: \"critical\",\n\t\t})\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_DEBU), \"debug\")\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_INFO), defaultLevelPrefixes[LEVEL_INFO])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_NOTI), defaultLevelPrefixes[LEVEL_NOTI])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_WARN), defaultLevelPrefixes[LEVEL_WARN])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_ERRO), defaultLevelPrefixes[LEVEL_ERRO])\n\t\tt.Assert(l.GetLevelPrefix(LEVEL_CRIT), \"critical\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tl := New()\n\t\tl.SetWriter(buffer)\n\t\tl.Debug(ctx, \"test1\")\n\t\tt.Assert(gstr.Contains(buffer.String(), defaultLevelPrefixes[LEVEL_DEBU]), true)\n\n\t\tbuffer.Reset()\n\n\t\tl.SetLevelPrefix(LEVEL_DEBU, \"debug\")\n\t\tl.Debug(ctx, \"test2\")\n\t\tt.Assert(gstr.Contains(buffer.String(), defaultLevelPrefixes[LEVEL_DEBU]), false)\n\t\tt.Assert(gstr.Contains(buffer.String(), \"debug\"), true)\n\n\t\tbuffer.Reset()\n\t\tl.SetLevelPrefixes(map[int]string{\n\t\t\tLEVEL_ERRO: \"error\",\n\t\t})\n\t\tl.Error(ctx, \"test3\")\n\t\tt.Assert(gstr.Contains(buffer.String(), defaultLevelPrefixes[LEVEL_ERRO]), false)\n\t\tt.Assert(gstr.Contains(buffer.String(), \"error\"), true)\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_logger_chaining_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_To(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tTo(w).Error(ctx, 1, 2, 3)\n\t\tTo(w).Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Path(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tPath(path).File(file).Stdout(false).Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Cat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcat := \"category\"\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Cat(cat).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tPath(path).File(file).Cat(cat).Stdout(false).Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, cat, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 2)\n\t})\n}\n\nfunc Test_Level(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Level(LEVEL_PROD).Stdout(false).Debug(ctx, 1, 2, 3)\n\t\tPath(path).File(file).Level(LEVEL_PROD).Stdout(false).Debug(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_DEBU]), 0)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 0)\n\t})\n}\n\nfunc Test_Skip(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Skip(10).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tPath(path).File(file).Stdout(false).Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tfmt.Println(content)\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 2)\n\t\t//t.Assert(gstr.Count(content, \"Stack\"), 1)\n\t})\n}\n\nfunc Test_Stack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Stack(false).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tPath(path).File(file).Stdout(false).Errorf(ctx, \"%d %d %d\", 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tfmt.Println(content)\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 2)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 2)\n\t\t//t.Assert(gstr.Count(content, \"Stack\"), 1)\n\t})\n}\n\nfunc Test_StackWithFilter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).StackWithFilter(\"none\").Stdout(false).Error(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tfmt.Println(ctx, content)\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t\t//t.Assert(gstr.Count(content, \"Stack\"), 1)\n\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).StackWithFilter(\"/gf/\").Stdout(false).Error(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tfmt.Println(ctx, content)\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t\t//t.Assert(gstr.Count(content, \"Stack\"), 0)\n\t})\n}\n\nfunc Test_Header(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Header(true).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Header(false).Stdout(false).Error(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_ERRO]), 0)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t})\n}\n\nfunc Test_Line(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Line(true).Stdout(false).Debug(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tfmt.Println(content)\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_DEBU]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t\t//t.Assert(gstr.Count(content, \".go\"), 1)\n\t\t//t.Assert(gstr.Contains(content, gfile.Separator), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Line(false).Stdout(false).Debug(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_DEBU]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t\t//t.Assert(gstr.Count(content, \".go\"), 1)\n\t\t//t.Assert(gstr.Contains(content, gfile.Separator), false)\n\t})\n}\n\nfunc Test_Async(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Async().Stdout(false).Debug(ctx, 1, 2, 3)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_DEBU]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := gfile.Temp(gtime.TimestampNanoStr())\n\t\tfile := fmt.Sprintf(`%d.log`, gtime.TimestampNano())\n\n\t\terr := gfile.Mkdir(path)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(path)\n\n\t\tPath(path).File(file).Async(false).Stdout(false).Debug(ctx, 1, 2, 3)\n\t\tcontent := gfile.GetContents(gfile.Join(path, file))\n\t\tt.Assert(gstr.Count(content, defaultLevelPrefixes[LEVEL_DEBU]), 1)\n\t\tt.Assert(gstr.Count(content, \"1 2 3\"), 1)\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_logger_handler_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar arrayForHandlerTest1 = garray.NewStrArray()\n\nfunc customHandler1(ctx context.Context, input *glog.HandlerInput) {\n\tarrayForHandlerTest1.Append(input.String(false))\n\tinput.Next(ctx)\n}\n\nfunc TestLogger_SetHandlers1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetHandlers(customHandler1)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Print(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 1)\n\n\t\tt.Assert(arrayForHandlerTest1.Len(), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest1.At(0), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest1.At(0), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest1.At(0), \"1 2 3\"), 1)\n\t})\n}\n\nvar arrayForHandlerTest2 = garray.NewStrArray()\n\nfunc customHandler2(ctx context.Context, input *glog.HandlerInput) {\n\tarrayForHandlerTest2.Append(input.String(false))\n}\n\nfunc TestLogger_SetHandlers2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetHandlers(customHandler2)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Print(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"1234567890\"), 0)\n\t\tt.Assert(gstr.Count(w.String(), \"abcdefg\"), 0)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 0)\n\n\t\tt.Assert(arrayForHandlerTest2.Len(), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest2.At(0), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest2.At(0), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(arrayForHandlerTest2.At(0), \"1 2 3\"), 1)\n\t})\n}\n\nfunc TestLogger_SetHandlers_HandlerJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetHandlers(glog.HandlerJson)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Debug(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), `\"CtxStr\":\"1234567890, abcdefg\"`), 1)\n\t\tt.Assert(gstr.Count(w.String(), `\"Content\":\"1 2 3\"`), 1)\n\t\tt.Assert(gstr.Count(w.String(), `\"Level\":\"DEBU\"`), 1)\n\t})\n}\n\nfunc TestLogger_SetHandlers_HandlerStructure(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetHandlers(glog.HandlerStructure)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Debug(ctx, \"debug\", \"uid\", 1000)\n\t\tl.Info(ctx, \"info\", \"' '\", `\"\\n`)\n\n\t\tt.Assert(gstr.Count(w.String(), \"uid=1000\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"Content=debug\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), `\"' '\"=\"\\\"\\\\n\"`), 1)\n\t\tt.Assert(gstr.Count(w.String(), `CtxStr=\"1234567890, abcdefg\"`), 2)\n\t})\n}\n\nfunc Test_SetDefaultHandler(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldHandler := glog.GetDefaultHandler()\n\t\tglog.SetDefaultHandler(func(ctx context.Context, in *glog.HandlerInput) {\n\t\t\tglog.HandlerJson(ctx, in)\n\t\t})\n\t\tdefer glog.SetDefaultHandler(oldHandler)\n\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Debug(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), `\"1 2 3\"`), 1)\n\t\tt.Assert(gstr.Count(w.String(), `\"DEBU\"`), 1)\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_logger_rotate_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_Rotate_Size(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tp := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr := l.SetConfigWithMap(g.Map{\n\t\t\t\"Path\":                 p,\n\t\t\t\"File\":                 \"access.log\",\n\t\t\t\"StdoutPrint\":          false,\n\t\t\t\"RotateSize\":           10,\n\t\t\t\"RotateBackupLimit\":    2,\n\t\t\t\"RotateBackupExpire\":   5 * time.Second,\n\t\t\t\"RotateBackupCompress\": 9,\n\t\t\t\"RotateCheckInterval\":  time.Second, // For unit testing only.\n\t\t})\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(p)\n\n\t\ts := \"1234567890abcdefg\"\n\t\tfor i := 0; i < 8; i++ {\n\t\t\tl.Print(ctx, s)\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\n\t\tlogFiles, err := gfile.ScanDirFile(p, \"access*\")\n\t\tt.AssertNil(err)\n\n\t\tfor _, v := range logFiles {\n\t\t\tcontent := gfile.GetContents(v)\n\t\t\tt.AssertIN(gstr.Count(content, s), []int{1, 2})\n\t\t}\n\n\t\ttime.Sleep(time.Second * 3)\n\n\t\tfiles, err := gfile.ScanDirFile(p, \"*.gz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 2)\n\n\t\ttime.Sleep(time.Second * 5)\n\t\tfiles, err = gfile.ScanDirFile(p, \"*.gz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\t})\n}\n\nfunc Test_Rotate_Expire(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tp := gfile.Temp(gtime.TimestampNanoStr())\n\t\terr := l.SetConfigWithMap(g.Map{\n\t\t\t\"Path\":                 p,\n\t\t\t\"File\":                 \"access.log\",\n\t\t\t\"StdoutPrint\":          false,\n\t\t\t\"RotateExpire\":         time.Second,\n\t\t\t\"RotateBackupLimit\":    2,\n\t\t\t\"RotateBackupExpire\":   5 * time.Second,\n\t\t\t\"RotateBackupCompress\": 9,\n\t\t\t\"RotateCheckInterval\":  time.Second, // For unit testing only.\n\t\t})\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(p)\n\n\t\ts := \"1234567890abcdefg\"\n\t\tfor i := 0; i < 10; i++ {\n\t\t\tl.Print(ctx, s)\n\t\t}\n\n\t\tfiles, err := gfile.ScanDirFile(p, \"*.gz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\n\t\tt.Assert(gstr.Count(gfile.GetContents(gfile.Join(p, \"access.log\")), s), 10)\n\n\t\ttime.Sleep(time.Second * 3)\n\n\t\tfilenames, err := gfile.ScanDirFile(p, \"*\")\n\t\tt.Log(filenames, err)\n\t\tfiles, err = gfile.ScanDirFile(p, \"*.gz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 1)\n\n\t\tt.Assert(gstr.Count(gfile.GetContents(gfile.Join(p, \"access.log\")), s), 0)\n\n\t\ttime.Sleep(time.Second * 5)\n\t\tfiles, err = gfile.ScanDirFile(p, \"*.gz\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 0)\n\t})\n}\n"
  },
  {
    "path": "os/glog/glog_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage glog_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc TestCase(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(glog.Instance(), nil)\n\t})\n}\n\nfunc TestDefaultLogger(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(defaultLog, nil)\n\t\tlog := glog.New()\n\t\tglog.SetDefaultLogger(log)\n\t\tt.AssertEQ(glog.DefaultLogger(), defaultLog)\n\t\tt.AssertEQ(glog.Expose(), defaultLog)\n\t})\n}\n\nfunc TestAPI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.Print(ctx, \"Print\")\n\t\tglog.Printf(ctx, \"%s\", \"Printf\")\n\t\tglog.Info(ctx, \"Info\")\n\t\tglog.Infof(ctx, \"%s\", \"Infof\")\n\t\tglog.Debug(ctx, \"Debug\")\n\t\tglog.Debugf(ctx, \"%s\", \"Debugf\")\n\t\tglog.Notice(ctx, \"Notice\")\n\t\tglog.Noticef(ctx, \"%s\", \"Noticef\")\n\t\tglog.Warning(ctx, \"Warning\")\n\t\tglog.Warningf(ctx, \"%s\", \"Warningf\")\n\t\tglog.Error(ctx, \"Error\")\n\t\tglog.Errorf(ctx, \"%s\", \"Errorf\")\n\t\tglog.Critical(ctx, \"Critical\")\n\t\tglog.Criticalf(ctx, \"%s\", \"Criticalf\")\n\t})\n}\n\nfunc TestChaining(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(glog.Cat(\"module\"), nil)\n\t\tt.AssertNE(glog.File(\"test.log\"), nil)\n\t\tt.AssertNE(glog.Level(glog.LEVEL_ALL), nil)\n\t\tt.AssertNE(glog.LevelStr(\"all\"), nil)\n\t\tt.AssertNE(glog.Skip(1), nil)\n\t\tt.AssertNE(glog.Stack(false), nil)\n\t\tt.AssertNE(glog.StackWithFilter(\"none\"), nil)\n\t\tt.AssertNE(glog.Stdout(false), nil)\n\t\tt.AssertNE(glog.Header(false), nil)\n\t\tt.AssertNE(glog.Line(false), nil)\n\t\tt.AssertNE(glog.Async(false), nil)\n\t})\n}\n\nfunc Test_SetFile(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetFile(\"test.log\")\n\t})\n}\n\nfunc Test_SetTimeFormat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\n\t\tl.SetTimeFormat(\"2006-01-02T15:04:05.000Z07:00\")\n\t\tl.Debug(ctx, \"test\")\n\n\t\tt.AssertGE(len(strings.Split(w.String(), \"[DEBU]\")), 1)\n\t\tdatetime := strings.Trim(strings.Split(w.String(), \"[DEBU]\")[0], \" \")\n\n\t\t_, err := time.Parse(\"2006-01-02T15:04:05.000Z07:00\", datetime)\n\t\tt.AssertNil(err)\n\t\t_, err = time.Parse(\"2006-01-02 15:04:05.000\", datetime)\n\t\tt.AssertNE(err, nil)\n\t\t_, err = time.Parse(\"Mon, 02 Jan 2006 15:04:05 -0700\", datetime)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_SetLevel(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetLevel(glog.LEVEL_ALL)\n\t\tt.Assert(glog.GetLevel()&glog.LEVEL_ALL, glog.LEVEL_ALL)\n\t})\n}\n\nfunc Test_SetAsync(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetAsync(false)\n\t})\n}\n\nfunc Test_SetStdoutPrint(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetStdoutPrint(false)\n\t})\n}\n\nfunc Test_SetHeaderPrint(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetHeaderPrint(false)\n\t})\n}\n\nfunc Test_SetPrefix(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetPrefix(\"log_prefix\")\n\t})\n}\n\nfunc Test_SetConfigWithMap(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(glog.SetConfigWithMap(map[string]any{\n\t\t\t\"level\": \"all\",\n\t\t}), nil)\n\t})\n}\n\nfunc Test_SetPath(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(glog.SetPath(\"/var/log\"), nil)\n\t\tt.Assert(glog.GetPath(), \"/var/log\")\n\t})\n}\n\nfunc Test_SetWriter(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetWriter(os.Stdout)\n\t\tt.Assert(glog.GetWriter(), os.Stdout)\n\t})\n}\n\nfunc Test_SetFlags(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetFlags(glog.F_ASYNC)\n\t\tt.Assert(glog.GetFlags(), glog.F_ASYNC)\n\t})\n}\n\nfunc Test_SetCtxKeys(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetCtxKeys(\"SpanId\", \"TraceId\")\n\t\tt.Assert(glog.GetCtxKeys(), []string{\"SpanId\", \"TraceId\"})\n\t})\n}\n\nfunc Test_PrintStack(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.PrintStack(ctx, 1)\n\t})\n}\n\nfunc Test_SetStack(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetStack(true)\n\t\tt.Assert(glog.GetStack(1), \"\")\n\t})\n}\n\nfunc Test_SetLevelStr(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(glog.SetLevelStr(\"all\"), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tt.AssertNE(l.SetLevelStr(\"test\"), nil)\n\t})\n}\n\nfunc Test_SetLevelPrefix(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetLevelPrefix(glog.LEVEL_ALL, \"LevelPrefix\")\n\t\tt.Assert(glog.GetLevelPrefix(glog.LEVEL_ALL), \"LevelPrefix\")\n\t})\n}\n\nfunc Test_SetLevelPrefixes(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetLevelPrefixes(map[int]string{\n\t\t\tglog.LEVEL_ALL: \"ALL_Prefix\",\n\t\t})\n\t})\n}\n\nfunc Test_SetHandlers(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetHandlers(func(ctx context.Context, in *glog.HandlerInput) {\n\t\t})\n\t})\n}\n\nfunc Test_SetWriterColorEnable(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tglog.SetWriterColorEnable(true)\n\t})\n}\n\nfunc Test_Instance(t *testing.T) {\n\tdefaultLog := glog.DefaultLogger().Clone()\n\tdefer glog.SetDefaultLogger(defaultLog)\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(glog.Instance(\"gf\"), nil)\n\t})\n}\n\nfunc Test_GetConfig(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig := glog.DefaultLogger().GetConfig()\n\t\tt.Assert(config.Path, \"\")\n\t\tt.Assert(config.StdoutPrint, true)\n\t})\n}\n\nfunc Test_Write(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlen, err := l.Write([]byte(\"GoFrame\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(len, 7)\n\t})\n}\n\nfunc Test_Chaining_To(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.DefaultLogger().Clone()\n\t\tlogTo := l.To(os.Stdout)\n\t\tt.AssertNE(logTo, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogTo := l.To(os.Stdout)\n\t\tt.AssertNE(logTo, nil)\n\t})\n}\n\nfunc Test_Chaining_Path(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.DefaultLogger().Clone()\n\t\tlogPath := l.Path(\"./\")\n\t\tt.AssertNE(logPath, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogPath := l.Path(\"./\")\n\t\tt.AssertNE(logPath, nil)\n\t})\n}\n\nfunc Test_Chaining_Cat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogCat := l.Cat(\".gf\")\n\t\tt.AssertNE(logCat, nil)\n\t})\n}\n\nfunc Test_Chaining_Level(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogLevel := l.Level(glog.LEVEL_ALL)\n\t\tt.AssertNE(logLevel, nil)\n\t})\n}\n\nfunc Test_Chaining_LevelStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogLevelStr := l.LevelStr(\"all\")\n\t\tt.AssertNE(logLevelStr, nil)\n\t})\n}\n\nfunc Test_Chaining_Skip(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogSkip := l.Skip(1)\n\t\tt.AssertNE(logSkip, nil)\n\t})\n}\n\nfunc Test_Chaining_Stack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogStack := l.Stack(true)\n\t\tt.AssertNE(logStack, nil)\n\t})\n}\n\nfunc Test_Chaining_StackWithFilter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogStackWithFilter := l.StackWithFilter(\"gtest\")\n\t\tt.AssertNE(logStackWithFilter, nil)\n\t})\n}\n\nfunc Test_Chaining_Stdout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogStdout := l.Stdout(true)\n\t\tt.AssertNE(logStdout, nil)\n\t})\n}\n\nfunc Test_Chaining_Header(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogHeader := l.Header(true)\n\t\tt.AssertNE(logHeader, nil)\n\t})\n}\n\nfunc Test_Chaining_Line(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogLine := l.Line(true)\n\t\tt.AssertNE(logLine, nil)\n\t})\n}\n\nfunc Test_Chaining_Async(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tlogAsync := l.Async(true)\n\t\tt.AssertNE(logAsync, nil)\n\t})\n}\n\nfunc Test_Config_SetDebug(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tl.SetDebug(false)\n\t})\n}\n\nfunc Test_Config_AppendCtxKeys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tl.AppendCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tl.AppendCtxKeys(\"Trace-Id-New\", \"Span-Id-New\", \"Test\")\n\t})\n}\n\nfunc Test_Config_SetPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tt.AssertNE(l.SetPath(\"\"), nil)\n\t})\n}\n\nfunc Test_Config_SetStdoutColorDisabled(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tl := glog.New()\n\t\tl.SetStdoutColorDisabled(false)\n\t})\n}\n\nfunc Test_Ctx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tl.SetCtxKeys(\"Trace-Id\", \"Span-Id\", \"Test\")\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Print(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 1)\n\t})\n}\n\nfunc Test_Ctx_Config(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tw := bytes.NewBuffer(nil)\n\t\tl := glog.NewWithWriter(w)\n\t\tm := map[string]any{\n\t\t\t\"CtxKeys\": g.SliceStr{\"Trace-Id\", \"Span-Id\", \"Test\"},\n\t\t}\n\t\tvar nilMap map[string]any\n\n\t\terr := l.SetConfigWithMap(m)\n\t\tt.AssertNil(err)\n\t\terr = l.SetConfigWithMap(nilMap)\n\t\tt.AssertNE(err, nil)\n\n\t\tctx := context.WithValue(context.Background(), \"Trace-Id\", \"1234567890\")\n\t\tctx = context.WithValue(ctx, \"Span-Id\", \"abcdefg\")\n\n\t\tl.Print(ctx, 1, 2, 3)\n\t\tt.Assert(gstr.Count(w.String(), \"1234567890\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"abcdefg\"), 1)\n\t\tt.Assert(gstr.Count(w.String(), \"1 2 3\"), 1)\n\t})\n}\n\nfunc Test_Concurrent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := 1000\n\t\tl := glog.New()\n\t\ts := \"@1234567890#\"\n\t\tf := \"test.log\"\n\t\tp := gfile.Temp(gtime.TimestampNanoStr())\n\t\tt.Assert(l.SetPath(p), nil)\n\t\tdefer gfile.Remove(p)\n\t\twg := sync.WaitGroup{}\n\t\tch := make(chan struct{})\n\t\tfor i := 0; i < c; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\t\t\t\t<-ch\n\t\t\t\tl.File(f).Stdout(false).Print(ctx, s)\n\t\t\t}()\n\t\t}\n\t\tclose(ch)\n\t\twg.Wait()\n\t\tcontent := gfile.GetContents(gfile.Join(p, f))\n\t\tt.Assert(gstr.Count(content, s), c)\n\t})\n}\n"
  },
  {
    "path": "os/gmetric/gmetric.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmetric provides interface definitions and simple api for metric feature.\npackage gmetric\n\nimport (\n\t\"context\"\n)\n\n// MetricType is the type of metric.\ntype MetricType string\n\nconst (\n\tMetricTypeCounter                 MetricType = `Counter`                 // Counter.\n\tMetricTypeUpDownCounter           MetricType = `UpDownCounter`           // UpDownCounter.\n\tMetricTypeHistogram               MetricType = `Histogram`               // Histogram.\n\tMetricTypeObservableCounter       MetricType = `ObservableCounter`       // ObservableCounter.\n\tMetricTypeObservableUpDownCounter MetricType = `ObservableUpDownCounter` // ObservableUpDownCounter.\n\tMetricTypeObservableGauge         MetricType = `ObservableGauge`         // ObservableGauge.\n)\n\nconst (\n\t// MetricNamePattern is the regular expression pattern for validating metric name.\n\tMetricNamePattern = `[\\w\\.\\-\\/]`\n)\n\n// Provider manages all Metric exporting.\n// Be caution that the Histogram buckets could not be customized if the creation of the Histogram\n// is before the creation of Provider.\ntype Provider interface {\n\t// SetAsGlobal sets current provider as global meter provider for current process,\n\t// which makes the following metrics creating on this Provider, especially the metrics created in runtime.\n\tSetAsGlobal()\n\n\t// MeterPerformer creates and returns the MeterPerformer that can produce kinds of metric Performer.\n\tMeterPerformer(config MeterOption) MeterPerformer\n\n\t// ForceFlush flushes all pending metrics.\n\t//\n\t// This method honors the deadline or cancellation of ctx. An appropriate\n\t// error will be returned in these situations. There is no guaranteed that all\n\t// metrics be flushed or all resources have been released in these situations.\n\tForceFlush(ctx context.Context) error\n\n\t// Shutdown shuts down the Provider flushing all pending metrics and\n\t// releasing any held computational resources.\n\tShutdown(ctx context.Context) error\n}\n\n// MeterPerformer manages all Metric performers creating.\ntype MeterPerformer interface {\n\t// CounterPerformer creates and returns a CounterPerformer that performs\n\t// the operations for Counter metric.\n\tCounterPerformer(name string, option MetricOption) (CounterPerformer, error)\n\n\t// UpDownCounterPerformer creates and returns a UpDownCounterPerformer that performs\n\t// the operations for UpDownCounter metric.\n\tUpDownCounterPerformer(name string, option MetricOption) (UpDownCounterPerformer, error)\n\n\t// HistogramPerformer creates and returns a HistogramPerformer that performs\n\t// the operations for Histogram metric.\n\tHistogramPerformer(name string, option MetricOption) (HistogramPerformer, error)\n\n\t// ObservableCounterPerformer creates and returns an ObservableCounterPerformer that performs\n\t// the operations for ObservableCounter metric.\n\tObservableCounterPerformer(name string, option MetricOption) (ObservableCounterPerformer, error)\n\n\t// ObservableUpDownCounterPerformer creates and returns an ObservableUpDownCounterPerformer that performs\n\t// the operations for ObservableUpDownCounter metric.\n\tObservableUpDownCounterPerformer(name string, option MetricOption) (ObservableUpDownCounterPerformer, error)\n\n\t// ObservableGaugePerformer creates and returns an ObservableGaugePerformer that performs\n\t// the operations for ObservableGauge metric.\n\tObservableGaugePerformer(name string, option MetricOption) (ObservableGaugePerformer, error)\n\n\t// RegisterCallback registers callback on certain metrics.\n\t// A callback is bound to certain component and version, it is called when the associated metrics are read.\n\t// Multiple callbacks on the same component and version will be called by their registered sequence.\n\tRegisterCallback(callback Callback, canBeCallbackMetrics ...ObservableMetric) error\n}\n\n// MetricOption holds the basic options for creating a metric.\ntype MetricOption struct {\n\t// Help provides information about this Histogram.\n\t// This is an optional configuration for a metric.\n\tHelp string\n\n\t// Unit is the unit for metric value.\n\t// This is an optional configuration for a metric.\n\tUnit string\n\n\t// Attributes holds the constant key-value pair description metadata for this metric.\n\t// This is an optional configuration for a metric.\n\tAttributes Attributes\n\n\t// Buckets defines the buckets into which observations are counted.\n\t// For Histogram metric only.\n\t// A histogram metric uses default buckets if no explicit buckets configured.\n\tBuckets []float64\n\n\t// Callback function for metric, which is called when metric value changes.\n\t// For observable metric only.\n\t// If an observable metric has either Callback attribute nor global callback configured, it does nothing.\n\tCallback MetricCallback\n}\n\n// Metric models a single sample value with its metadata being exported.\ntype Metric interface {\n\t// Info returns the basic information of a Metric.\n\tInfo() MetricInfo\n}\n\n// MetricInfo exports information of the Metric.\ntype MetricInfo interface {\n\tKey() string                // Key returns the unique string key of the metric.\n\tName() string               // Name returns the name of the metric.\n\tHelp() string               // Help returns the help description of the metric.\n\tUnit() string               // Unit returns the unit name of the metric.\n\tType() MetricType           // Type returns the type of the metric.\n\tAttributes() Attributes     // Attributes returns the constant attribute slice of the metric.\n\tInstrument() InstrumentInfo // InstrumentInfo returns the instrument info of the metric.\n}\n\n// InstrumentInfo exports the instrument information of a metric.\ntype InstrumentInfo interface {\n\tName() string    // Name returns the instrument name of the metric.\n\tVersion() string // Version returns the instrument version of the metric.\n}\n\n// Counter is a Metric that represents a single numerical value that can ever\n// goes up.\ntype Counter interface {\n\tMetric\n\tCounterPerformer\n}\n\n// CounterPerformer performs operations for Counter metric.\ntype CounterPerformer interface {\n\t// Inc increments the counter by 1. Use Add to increment it by arbitrary\n\t// non-negative values.\n\tInc(ctx context.Context, option ...Option)\n\n\t// Add adds the given value to the counter. It panics if the value is < 0.\n\tAdd(ctx context.Context, increment float64, option ...Option)\n}\n\n// UpDownCounter is a Metric that represents a single numerical value that can ever\n// goes up or down.\ntype UpDownCounter interface {\n\tMetric\n\tUpDownCounterPerformer\n}\n\n// UpDownCounterPerformer performs operations for UpDownCounter metric.\ntype UpDownCounterPerformer interface {\n\t// Inc increments the counter by 1. Use Add to increment it by arbitrary\n\t// non-negative values.\n\tInc(ctx context.Context, option ...Option)\n\n\t// Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary values.\n\tDec(ctx context.Context, option ...Option)\n\n\t// Add adds the given value to the counter. It panics if the value is < 0.\n\tAdd(ctx context.Context, increment float64, option ...Option)\n}\n\n// Histogram counts individual observations from an event or sample stream in\n// configurable static buckets (or in dynamic sparse buckets as part of the\n// experimental Native Histograms, see below for more details). Similar to a\n// Summary, it also provides a sum of observations and an observation count.\ntype Histogram interface {\n\tMetric\n\tHistogramPerformer\n\n\t// Buckets returns the bucket slice of the Histogram.\n\tBuckets() []float64\n}\n\n// HistogramPerformer performs operations for Histogram metric.\ntype HistogramPerformer interface {\n\t// Record adds a single value to the histogram.\n\t// The value is usually positive or zero.\n\tRecord(increment float64, option ...Option)\n}\n\n// ObservableCounter is an instrument used to asynchronously\n// record float64 measurements once per collection cycle. Observations are only\n// made within a callback for this instrument. The value observed is assumed\n// the to be the cumulative sum of the count.\ntype ObservableCounter interface {\n\tMetric\n\tObservableCounterPerformer\n}\n\n// ObservableUpDownCounter is used to synchronously record float64 measurements during a computational\n// operation.\ntype ObservableUpDownCounter interface {\n\tMetric\n\tObservableUpDownCounterPerformer\n}\n\n// ObservableGauge is an instrument used to asynchronously record\n// instantaneous float64 measurements once per collection cycle. Observations\n// are only made within a callback for this instrument.\ntype ObservableGauge interface {\n\tMetric\n\tObservableGaugePerformer\n}\n\ntype (\n\t// ObservableCounterPerformer is performer for observable ObservableCounter.\n\tObservableCounterPerformer = ObservableMetric\n\n\t// ObservableUpDownCounterPerformer is performer for observable ObservableUpDownCounter.\n\tObservableUpDownCounterPerformer = ObservableMetric\n\n\t// ObservableGaugePerformer is performer for observable ObservableGauge.\n\tObservableGaugePerformer = ObservableMetric\n)\n\n// ObservableMetric is an instrument used to asynchronously record\n// instantaneous float64 measurements once per collection cycle.\ntype ObservableMetric interface {\n\tobservable()\n}\n\n// MetricInitializer manages the initialization for Metric.\n// It is called internally in metric interface implements.\ntype MetricInitializer interface {\n\t// Init initializes the Metric in Provider creation.\n\t// It sets the metric performer which really takes action.\n\tInit(provider Provider) error\n}\n\n// PerformerExporter exports internal Performer of Metric.\n// It is called internally in metric interface implements.\ntype PerformerExporter interface {\n\t// Performer exports internal Performer of Metric.\n\t// This is usually used by metric implements.\n\tPerformer() any\n}\n\n// MetricCallback is automatically called when metric reader starts reading the metric value.\ntype MetricCallback func(ctx context.Context, obs MetricObserver) error\n\n// Callback is a function registered with a Meter that makes observations for\n// the set of instruments it is registered with. The Observer parameter is used\n// to record measurement observations for these instruments.\ntype Callback func(ctx context.Context, obs Observer) error\n\n// Observer sets the value for certain initialized Metric.\ntype Observer interface {\n\t// Observe observes the value for certain initialized Metric.\n\t// It adds the value to total result if the observed Metrics is type of Counter.\n\t// It sets the value as the result if the observed Metrics is type of Gauge.\n\tObserve(m ObservableMetric, value float64, option ...Option)\n}\n\n// MetricObserver sets the value for bound Metric.\ntype MetricObserver interface {\n\t// Observe observes the value for certain initialized Metric.\n\t// It adds the value to total result if the observed Metrics is type of Counter.\n\t// It sets the value as the result if the observed Metrics is type of Gauge.\n\tObserve(value float64, option ...Option)\n}\n\nvar (\n\t// metrics stores all created Metric by current package.\n\tallMetrics = make([]Metric, 0)\n)\n\n// IsEnabled returns whether the metrics feature is enabled.\nfunc IsEnabled() bool {\n\treturn globalProvider != nil\n}\n\n// GetAllMetrics returns all Metric that created by current package.\nfunc GetAllMetrics() []Metric {\n\treturn allMetrics\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_attribute.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// Attributes is a slice of Attribute.\ntype Attributes []Attribute\n\n// Attribute is the key-value pair item for Metric.\ntype Attribute interface {\n\tKey() string // The key for this attribute.\n\tValue() any  // The value for this attribute.\n}\n\n// AttributeKey is the attribute key.\ntype AttributeKey string\n\n// Option holds the option for perform a metric operation.\ntype Option struct {\n\t// Attributes holds the dynamic key-value pair metadata.\n\tAttributes Attributes\n}\n\n// localAttribute implements interface Attribute.\ntype localAttribute struct {\n\tkey   string\n\tvalue any\n}\n\nvar (\n\thostname    string\n\tprocessPath string\n)\n\nfunc init() {\n\thostname, _ = os.Hostname()\n\tprocessPath = gfile.SelfPath()\n}\n\n// CommonAttributes returns the common used attributes for an instrument.\nfunc CommonAttributes() Attributes {\n\treturn Attributes{\n\t\tNewAttribute(`os.host.name`, hostname),\n\t\tNewAttribute(`process.path`, processPath),\n\t}\n}\n\n// NewAttribute creates and returns an Attribute by given `key` and `value`.\nfunc NewAttribute(key string, value any) Attribute {\n\treturn &localAttribute{\n\t\tkey:   key,\n\t\tvalue: value,\n\t}\n}\n\n// Key returns the key of the attribute.\nfunc (l *localAttribute) Key() string {\n\treturn l.key\n}\n\n// Value returns the value of the attribute.\nfunc (l *localAttribute) Value() any {\n\treturn l.value\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (l *localAttribute) MarshalJSON() ([]byte, error) {\n\treturn []byte(fmt.Sprintf(`{\"%s\":%#v}`, l.key, l.value)), nil\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (attrs Attributes) String() string {\n\tbs, _ := attrs.MarshalJSON()\n\treturn string(bs)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (attrs Attributes) MarshalJSON() ([]byte, error) {\n\tvar (\n\t\tbs     []byte\n\t\terr    error\n\t\tbuffer = bytes.NewBuffer(nil)\n\t)\n\tbuffer.WriteByte('[')\n\tfor _, attr := range attrs {\n\t\tbs, err = json.Marshal(attr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif buffer.Len() > 1 {\n\t\t\tbuffer.WriteByte(',')\n\t\t}\n\t\tbuffer.Write(bs)\n\t}\n\tbuffer.WriteByte(']')\n\treturn buffer.Bytes(), nil\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_attribute_map.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// AttributeMap contains the attribute key and value as map for easy filtering.\ntype AttributeMap map[string]any\n\n// Sets adds given attribute map to current map.\nfunc (m AttributeMap) Sets(attrMap map[string]any) {\n\tfor k, v := range attrMap {\n\t\tm[k] = v\n\t}\n}\n\n// Pick picks and returns attributes by given attribute keys.\nfunc (m AttributeMap) Pick(keys ...string) Attributes {\n\tvar attrs = make(Attributes, 0)\n\tfor _, key := range keys {\n\t\tvalue, ok := m[key]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tattrs = append(attrs, NewAttribute(key, value))\n\t}\n\treturn attrs\n}\n\n// PickEx picks and returns attributes of which the given attribute keys does not in given `keys`.\nfunc (m AttributeMap) PickEx(keys ...string) Attributes {\n\tvar (\n\t\texKeyMap = make(map[string]struct{})\n\t\tattrs    = make(Attributes, 0)\n\t)\n\tfor _, key := range keys {\n\t\texKeyMap[key] = struct{}{}\n\t}\n\tfor k, v := range m {\n\t\t_, ok := exKeyMap[k]\n\t\tif ok {\n\t\t\tcontinue\n\t\t}\n\t\tattrs = append(attrs, NewAttribute(k, v))\n\t}\n\treturn attrs\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_global_attributes.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// SetGlobalAttributesOption binds the global attributes to certain instrument.\ntype SetGlobalAttributesOption struct {\n\t// Instrument specifies the instrument name.\n\tInstrument string\n\n\t// Instrument specifies the instrument version.\n\tInstrumentVersion string\n\n\t// InstrumentPattern specifies instrument by regular expression on Instrument name.\n\t// Example:\n\t// 1. given `.+` will match all instruments.\n\t// 2. given `github.com/gogf/gf.+` will match all goframe instruments.\n\tInstrumentPattern string\n}\n\n// GetGlobalAttributesOption binds the global attributes to certain instrument.\ntype GetGlobalAttributesOption struct {\n\tInstrument        string // Instrument specifies the instrument name.\n\tInstrumentVersion string // Instrument specifies the instrument version.\n}\n\ntype globalAttributeItem struct {\n\tAttributes\n\tSetGlobalAttributesOption\n}\n\nvar (\n\tglobalAttributesMu sync.Mutex\n\t// globalAttributes stores the global attributes to a map.\n\tglobalAttributes = make([]globalAttributeItem, 0)\n)\n\n// SetGlobalAttributes appends global attributes according `SetGlobalAttributesOption`.\n// It appends global attributes to all metrics if given `SetGlobalAttributesOption` is empty.\n// It appends global attributes to certain instrument by given `SetGlobalAttributesOption`.\nfunc SetGlobalAttributes(attrs Attributes, option SetGlobalAttributesOption) {\n\tglobalAttributesMu.Lock()\n\tdefer globalAttributesMu.Unlock()\n\tglobalAttributes = append(\n\t\tglobalAttributes, globalAttributeItem{\n\t\t\tAttributes:                attrs,\n\t\t\tSetGlobalAttributesOption: option,\n\t\t},\n\t)\n}\n\n// GetGlobalAttributes retrieves and returns the global attributes by `GetGlobalAttributesOption`.\n// It returns the global attributes if given `GetGlobalAttributesOption` is empty.\n// It returns global attributes of certain instrument if `GetGlobalAttributesOption` is not empty.\nfunc GetGlobalAttributes(option GetGlobalAttributesOption) Attributes {\n\tglobalAttributesMu.Lock()\n\tdefer globalAttributesMu.Unlock()\n\tvar attributes = make(Attributes, 0)\n\tfor _, attrItem := range globalAttributes {\n\t\t// instrument name.\n\t\tif attrItem.InstrumentPattern != \"\" {\n\t\t\tif !gregex.IsMatchString(attrItem.InstrumentPattern, option.Instrument) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\tif (attrItem.Instrument != \"\" || option.Instrument != \"\") &&\n\t\t\t\tattrItem.Instrument != option.Instrument {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\t// instrument version.\n\t\tif (attrItem.InstrumentVersion != \"\" || option.InstrumentVersion != \"\") &&\n\t\t\tattrItem.InstrumentVersion != option.InstrumentVersion {\n\t\t\tcontinue\n\t\t}\n\t\tattributes = append(attributes, attrItem.Attributes...)\n\t}\n\treturn attributes\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localMeter for Meter implements.\ntype localMeter struct {\n\tMeterOption\n}\n\n// MeterOption holds the creation option for a Meter.\ntype MeterOption struct {\n\t// Instrument is the instrumentation name to bind this Metric to a global MeterProvider.\n\t// This is an optional configuration for a metric.\n\tInstrument string\n\n\t// InstrumentVersion is the instrumentation version to bind this Metric to a global MeterProvider.\n\t// This is an optional configuration for a metric.\n\tInstrumentVersion string\n\n\t// Attributes holds the constant key-value pair description metadata for all metrics of Meter.\n\t// This is an optional configuration for a meter.\n\tAttributes Attributes\n}\n\n// newMeter creates and returns a Meter implementer.\nfunc newMeter(option MeterOption) Meter {\n\treturn &localMeter{\n\t\tMeterOption: option,\n\t}\n}\n\n// Performer creates and returns the Performer of the Meter.\nfunc (meter *localMeter) Performer() MeterPerformer {\n\tif globalProvider == nil {\n\t\treturn nil\n\t}\n\treturn globalProvider.MeterPerformer(meter.MeterOption)\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_callback.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// CallbackItem is the global callback item registered.\ntype CallbackItem struct {\n\tCallback    Callback           // Global callback.\n\tMetrics     []ObservableMetric // Callback on certain metrics.\n\tMeterOption MeterOption        // MeterOption is the option that the meter holds.\n\tProvider    Provider           // Provider is the Provider that the callback item is bound to.\n}\n\nvar (\n\t// Registered callbacks.\n\tglobalCallbackItems = make([]CallbackItem, 0)\n)\n\n// RegisterCallback registers callback on certain metrics.\n// A callback is bound to certain component and version, it is called when the associated metrics are read.\n// Multiple callbacks on the same component and version will be called by their registered sequence.\nfunc (meter *localMeter) RegisterCallback(callback Callback, observableMetrics ...ObservableMetric) error {\n\tif len(observableMetrics) == 0 {\n\t\treturn nil\n\t}\n\tglobalCallbackItems = append(globalCallbackItems, CallbackItem{\n\t\tCallback:    callback,\n\t\tMetrics:     observableMetrics,\n\t\tMeterOption: meter.MeterOption,\n\t})\n\treturn nil\n}\n\n// MustRegisterCallback performs as RegisterCallback, but it panics if any error occurs.\nfunc (meter *localMeter) MustRegisterCallback(callback Callback, observableMetrics ...ObservableMetric) {\n\terr := meter.RegisterCallback(callback, observableMetrics...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// GetRegisteredCallbacks retrieves and returns the registered global callbacks.\n// It truncates the callback slice is the callbacks are returned.\nfunc GetRegisteredCallbacks() []CallbackItem {\n\titems := globalCallbackItems\n\tglobalCallbackItems = globalCallbackItems[:0]\n\treturn items\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_counter.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localCounter is the local implements for interface Counter.\ntype localCounter struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tCounterPerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localCounter)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localCounter)(nil)\n)\n\n// Counter creates and returns a new Counter.\nfunc (meter *localMeter) Counter(name string, option MetricOption) (Counter, error) {\n\tm, err := meter.newMetric(MetricTypeCounter, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcounter := &localCounter{\n\t\tMetric:           m,\n\t\tMeterOption:      meter.MeterOption,\n\t\tMetricOption:     option,\n\t\tCounterPerformer: newNoopCounterPerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = counter.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, counter)\n\treturn counter, nil\n}\n\n// MustCounter creates and returns a new Counter.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustCounter(name string, option MetricOption) Counter {\n\tm, err := meter.Counter(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localCounter) Init(provider Provider) (err error) {\n\tif _, ok := l.CounterPerformer.(noopCounterPerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.CounterPerformer, err = provider.MeterPerformer(l.MeterOption).CounterPerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localCounter) Performer() any {\n\treturn l.CounterPerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_histogram.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localHistogram is the local implements for interface Histogram.\ntype localHistogram struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tHistogramPerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localHistogram)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localHistogram)(nil)\n)\n\n// Histogram creates and returns a new Histogram.\nfunc (meter *localMeter) Histogram(name string, option MetricOption) (Histogram, error) {\n\tm, err := meter.newMetric(MetricTypeHistogram, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\thistogram := &localHistogram{\n\t\tMetric:             m,\n\t\tMeterOption:        meter.MeterOption,\n\t\tMetricOption:       option,\n\t\tHistogramPerformer: newNoopHistogramPerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = histogram.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, histogram)\n\treturn histogram, nil\n}\n\n// MustHistogram creates and returns a new Histogram.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustHistogram(name string, option MetricOption) Histogram {\n\tm, err := meter.Histogram(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localHistogram) Init(provider Provider) (err error) {\n\tif _, ok := l.HistogramPerformer.(noopHistogramPerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.HistogramPerformer, err = provider.MeterPerformer(l.MeterOption).HistogramPerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn err\n}\n\n// Buckets returns the bucket slice of the Histogram.\nfunc (l *localHistogram) Buckets() []float64 {\n\treturn l.MetricOption.Buckets\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localHistogram) Performer() any {\n\treturn l.HistogramPerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_metric_info.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport \"fmt\"\n\n// localMetricInfo implements interface MetricInfo.\ntype localMetricInfo struct {\n\tMetricType\n\tMetricOption\n\tInstrumentInfo\n\tMetricName string\n}\n\n// newMetricInfo creates and returns a MetricInfo.\nfunc (meter *localMeter) newMetricInfo(\n\tmetricType MetricType, metricName string, metricOption MetricOption,\n) MetricInfo {\n\treturn &localMetricInfo{\n\t\tMetricName:     metricName,\n\t\tMetricType:     metricType,\n\t\tMetricOption:   metricOption,\n\t\tInstrumentInfo: meter.newInstrumentInfo(),\n\t}\n}\n\n// Name returns the name of the metric.\nfunc (l *localMetricInfo) Name() string {\n\treturn l.MetricName\n}\n\n// Help returns the help description of the metric.\nfunc (l *localMetricInfo) Help() string {\n\treturn l.MetricOption.Help\n}\n\n// Unit returns the unit name of the metric.\nfunc (l *localMetricInfo) Unit() string {\n\treturn l.MetricOption.Unit\n}\n\n// Type returns the type of the metric.\nfunc (l *localMetricInfo) Type() MetricType {\n\treturn l.MetricType\n}\n\n// Attributes returns the constant attribute slice of the metric.\nfunc (l *localMetricInfo) Attributes() Attributes {\n\treturn l.MetricOption.Attributes\n}\n\n// Instrument returns the instrument info of the metric.\nfunc (l *localMetricInfo) Instrument() InstrumentInfo {\n\treturn l.InstrumentInfo\n}\n\nfunc (l *localMetricInfo) Key() string {\n\tif l.Instrument().Name() != \"\" && l.Instrument().Version() != \"\" {\n\t\treturn fmt.Sprintf(\n\t\t\t`%s@%s:%s`,\n\t\t\tl.Instrument().Name(),\n\t\t\tl.Instrument().Version(),\n\t\t\tl.Name(),\n\t\t)\n\t}\n\tif l.Instrument().Name() != \"\" && l.Instrument().Version() == \"\" {\n\t\treturn fmt.Sprintf(\n\t\t\t`%s:%s`,\n\t\t\tl.Instrument().Name(),\n\t\t\tl.Name(),\n\t\t)\n\t}\n\treturn l.Name()\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_metric_instrument.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localMetricInstrument implements interface MetricInstrument.\ntype localInstrumentInfo struct {\n\tname    string\n\tversion string\n}\n\n// newInstrumentInfo creates and returns a MetricInstrument.\nfunc (meter *localMeter) newInstrumentInfo() InstrumentInfo {\n\treturn &localInstrumentInfo{\n\t\tname:    meter.Instrument,\n\t\tversion: meter.InstrumentVersion,\n\t}\n}\n\n// Name returns the instrument name of the metric.\nfunc (l *localInstrumentInfo) Name() string {\n\treturn l.name\n}\n\n// Version returns the instrument version of the metric.\nfunc (l *localInstrumentInfo) Version() string {\n\treturn l.version\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_observable_counter.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localObservableCounter is the local implements for interface ObservableCounter.\ntype localObservableCounter struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tObservableCounterPerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localObservableCounter)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localObservableCounter)(nil)\n)\n\n// ObservableCounter creates and returns a new ObservableCounter.\nfunc (meter *localMeter) ObservableCounter(name string, option MetricOption) (ObservableCounter, error) {\n\tm, err := meter.newMetric(MetricTypeObservableCounter, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tobservableCounter := &localObservableCounter{\n\t\tMetric:                     m,\n\t\tMeterOption:                meter.MeterOption,\n\t\tMetricOption:               option,\n\t\tObservableCounterPerformer: newNoopObservableCounterPerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = observableCounter.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, observableCounter)\n\treturn observableCounter, nil\n}\n\n// MustObservableCounter creates and returns a new ObservableCounter.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustObservableCounter(name string, option MetricOption) ObservableCounter {\n\tm, err := meter.ObservableCounter(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localObservableCounter) Init(provider Provider) (err error) {\n\tif _, ok := l.ObservableCounterPerformer.(noopObservableCounterPerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.ObservableCounterPerformer, err = provider.MeterPerformer(l.MeterOption).ObservableCounterPerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn err\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localObservableCounter) Performer() any {\n\treturn l.ObservableCounterPerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_observable_gauge.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localObservableGauge is the local implements for interface ObservableGauge.\ntype localObservableGauge struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tObservableGaugePerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localObservableGauge)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localObservableGauge)(nil)\n)\n\n// ObservableGauge creates and returns a new ObservableGauge.\nfunc (meter *localMeter) ObservableGauge(name string, option MetricOption) (ObservableGauge, error) {\n\tm, err := meter.newMetric(MetricTypeObservableGauge, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tobservableGauge := &localObservableGauge{\n\t\tMetric:                   m,\n\t\tMeterOption:              meter.MeterOption,\n\t\tMetricOption:             option,\n\t\tObservableGaugePerformer: newNoopObservableGaugePerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = observableGauge.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, observableGauge)\n\treturn observableGauge, nil\n}\n\n// MustObservableGauge creates and returns a new ObservableGauge.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustObservableGauge(name string, option MetricOption) ObservableGauge {\n\tm, err := meter.ObservableGauge(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localObservableGauge) Init(provider Provider) (err error) {\n\tif _, ok := l.ObservableGaugePerformer.(noopObservableGaugePerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.ObservableGaugePerformer, err = provider.MeterPerformer(l.MeterOption).ObservableGaugePerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn err\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localObservableGauge) Performer() any {\n\treturn l.ObservableGaugePerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_observable_updown_counter.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localObservableUpDownCounter is the local implements for interface ObservableUpDownCounter.\ntype localObservableUpDownCounter struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tObservableUpDownCounterPerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localObservableUpDownCounter)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localObservableUpDownCounter)(nil)\n)\n\n// ObservableUpDownCounter creates and returns a new ObservableUpDownCounter.\nfunc (meter *localMeter) ObservableUpDownCounter(name string, option MetricOption) (ObservableUpDownCounter, error) {\n\tm, err := meter.newMetric(MetricTypeObservableUpDownCounter, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tobservableUpDownCounter := &localObservableUpDownCounter{\n\t\tMetric:                           m,\n\t\tMeterOption:                      meter.MeterOption,\n\t\tMetricOption:                     option,\n\t\tObservableUpDownCounterPerformer: newNoopObservableUpDownCounterPerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = observableUpDownCounter.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, observableUpDownCounter)\n\treturn observableUpDownCounter, nil\n}\n\n// MustObservableUpDownCounter creates and returns a new ObservableUpDownCounter.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustObservableUpDownCounter(name string, option MetricOption) ObservableUpDownCounter {\n\tm, err := meter.ObservableCounter(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localObservableUpDownCounter) Init(provider Provider) (err error) {\n\tif _, ok := l.ObservableUpDownCounterPerformer.(noopObservableUpDownCounterPerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.ObservableUpDownCounterPerformer, err = provider.MeterPerformer(l.MeterOption).ObservableUpDownCounterPerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn err\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localObservableUpDownCounter) Performer() any {\n\treturn l.ObservableUpDownCounterPerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_meter_updown_counter.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// localUpDownCounter is the local implements for interface UpDownCounter.\ntype localUpDownCounter struct {\n\tMetric\n\tMeterOption\n\tMetricOption\n\tUpDownCounterPerformer\n}\n\nvar (\n\t// Check the implements for interface MetricInitializer.\n\t_ MetricInitializer = (*localUpDownCounter)(nil)\n\t// Check the implements for interface PerformerExporter.\n\t_ PerformerExporter = (*localUpDownCounter)(nil)\n)\n\n// UpDownCounter creates and returns a new Counter.\nfunc (meter *localMeter) UpDownCounter(name string, option MetricOption) (UpDownCounter, error) {\n\tm, err := meter.newMetric(MetricTypeUpDownCounter, name, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tupdownCounter := &localUpDownCounter{\n\t\tMetric:                 m,\n\t\tMeterOption:            meter.MeterOption,\n\t\tMetricOption:           option,\n\t\tUpDownCounterPerformer: newNoopUpDownCounterPerformer(),\n\t}\n\tif globalProvider != nil {\n\t\tif err = updownCounter.Init(globalProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tallMetrics = append(allMetrics, updownCounter)\n\treturn updownCounter, nil\n}\n\n// MustUpDownCounter creates and returns a new Counter.\n// It panics if any error occurs.\nfunc (meter *localMeter) MustUpDownCounter(name string, option MetricOption) UpDownCounter {\n\tm, err := meter.UpDownCounter(name, option)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// Init initializes the Metric in Provider creation.\nfunc (l *localUpDownCounter) Init(provider Provider) (err error) {\n\tif _, ok := l.UpDownCounterPerformer.(noopUpDownCounterPerformer); !ok {\n\t\t// already initialized.\n\t\treturn\n\t}\n\tl.UpDownCounterPerformer, err = provider.MeterPerformer(l.MeterOption).UpDownCounterPerformer(\n\t\tl.Info().Name(),\n\t\tl.MetricOption,\n\t)\n\treturn\n}\n\n// Performer implements interface PerformerExporter, which exports internal Performer of Metric.\n// This is usually used by metric implements.\nfunc (l *localUpDownCounter) Performer() any {\n\treturn l.UpDownCounterPerformer\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_metric.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport (\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// localMetric implements interface Metric.\ntype localMetric struct {\n\tMetricInfo\n}\n\n// newMetric creates and returns an object that implements interface Metric.\nfunc (meter *localMeter) newMetric(\n\tmetricType MetricType, metricName string, metricOption MetricOption,\n) (Metric, error) {\n\tif metricName == \"\" {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`error creating %s metric while given name is empty, option: %s`,\n\t\t\tmetricType, gjson.MustEncodeString(metricOption),\n\t\t)\n\t}\n\tif !gregex.IsMatchString(MetricNamePattern, metricName) {\n\t\treturn nil, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid metric name \"%s\", should match regular expression pattern \"%s\"`,\n\t\t\tmetricName, MetricNamePattern,\n\t\t)\n\t}\n\treturn &localMetric{\n\t\tMetricInfo: meter.newMetricInfo(metricType, metricName, metricOption),\n\t}, nil\n}\n\n// Info returns the basic information of a Metric.\nfunc (l *localMetric) Info() MetricInfo {\n\treturn l.MetricInfo\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport \"context\"\n\n// noopCounterPerformer is an implementer for interface CounterPerformer with no truly operations.\ntype noopCounterPerformer struct{}\n\n// newNoopCounterPerformer creates and returns a CounterPerformer with no truly operations.\nfunc newNoopCounterPerformer() CounterPerformer {\n\treturn noopCounterPerformer{}\n}\n\n// Inc increments the counter by 1.\nfunc (noopCounterPerformer) Inc(ctx context.Context, option ...Option) {}\n\n// Add adds the given value to the counter. It panics if the value is < 0.\nfunc (noopCounterPerformer) Add(ctx context.Context, increment float64, option ...Option) {}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_histogram_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// noopHistogramPerformer is an implementer for interface HistogramPerformer with no truly operations.\ntype noopHistogramPerformer struct{}\n\n// newNoopHistogramPerformer creates and returns a HistogramPerformer with no truly operations.\nfunc newNoopHistogramPerformer() HistogramPerformer {\n\treturn noopHistogramPerformer{}\n}\n\n// Record adds a single value to the histogram. The value is usually positive or zero.\nfunc (noopHistogramPerformer) Record(increment float64, option ...Option) {}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_observable_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// noopObservableCounterPerformer is an implementer for interface ObservableCounterPerformer with no truly operations.\ntype noopObservableCounterPerformer struct{}\n\n// newNoopObservableCounterPerformer creates and returns a ObservableCounterPerformer with no truly operations.\nfunc newNoopObservableCounterPerformer() ObservableCounterPerformer {\n\treturn noopObservableCounterPerformer{}\n}\n\nfunc (noopObservableCounterPerformer) observable() {}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_observable_gauge_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// noopObservableGaugePerformer is an implementer for interface ObservableGaugePerformer with no truly operations.\ntype noopObservableGaugePerformer struct{}\n\n// newNoopObservableGaugePerformer creates and returns a ObservableGaugePerformer with no truly operations.\nfunc newNoopObservableGaugePerformer() ObservableGaugePerformer {\n\treturn noopObservableGaugePerformer{}\n}\n\nfunc (noopObservableGaugePerformer) observable() {}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_observable_updown_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// noopObservableUpDownCounterPerformer is an implementer for interface ObservableUpDownCounterPerformer\n// with no truly operations.\ntype noopObservableUpDownCounterPerformer struct{}\n\n// newNoopObservableUpDownCounterPerformer creates and returns a ObservableUpDownCounterPerformer\n// with no truly operations.\nfunc newNoopObservableUpDownCounterPerformer() ObservableUpDownCounterPerformer {\n\treturn noopObservableUpDownCounterPerformer{}\n}\n\nfunc (noopObservableUpDownCounterPerformer) observable() {}\n"
  },
  {
    "path": "os/gmetric/gmetric_noop_updown_counter_performer.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport \"context\"\n\n// noopUpDownCounterPerformer is an implementer for interface CounterPerformer with no truly operations.\ntype noopUpDownCounterPerformer struct{}\n\n// newNoopUpDownCounterPerformer creates and returns a CounterPerformer with no truly operations.\nfunc newNoopUpDownCounterPerformer() UpDownCounterPerformer {\n\treturn noopUpDownCounterPerformer{}\n}\n\n// Inc increments the counter by 1.\nfunc (noopUpDownCounterPerformer) Inc(ctx context.Context, option ...Option) {}\n\n// Dec decrements the counter by 1.\nfunc (noopUpDownCounterPerformer) Dec(ctx context.Context, option ...Option) {}\n\n// Add adds the given value to the counter.\nfunc (noopUpDownCounterPerformer) Add(ctx context.Context, increment float64, option ...Option) {}\n"
  },
  {
    "path": "os/gmetric/gmetric_provider.go",
    "content": "// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\n// GlobalProvider hold the entry for creating Meter and Metric.\n// The GlobalProvider has only one function for Meter creating, which is designed for convenient usage.\ntype GlobalProvider interface {\n\t// Meter creates and returns the Meter by given MeterOption.\n\tMeter(option MeterOption) Meter\n}\n\n// Meter hold the functions for kinds of Metric creating.\ntype Meter interface {\n\t// Counter creates and returns a new Counter.\n\tCounter(name string, option MetricOption) (Counter, error)\n\n\t// UpDownCounter creates and returns a new UpDownCounter.\n\tUpDownCounter(name string, option MetricOption) (UpDownCounter, error)\n\n\t// Histogram creates and returns a new Histogram.\n\tHistogram(name string, option MetricOption) (Histogram, error)\n\n\t// ObservableCounter creates and returns a new ObservableCounter.\n\tObservableCounter(name string, option MetricOption) (ObservableCounter, error)\n\n\t// ObservableUpDownCounter creates and returns a new ObservableUpDownCounter.\n\tObservableUpDownCounter(name string, option MetricOption) (ObservableUpDownCounter, error)\n\n\t// ObservableGauge creates and returns a new ObservableGauge.\n\tObservableGauge(name string, option MetricOption) (ObservableGauge, error)\n\n\t// MustCounter creates and returns a new Counter.\n\t// It panics if any error occurs.\n\tMustCounter(name string, option MetricOption) Counter\n\n\t// MustUpDownCounter creates and returns a new UpDownCounter.\n\t// It panics if any error occurs.\n\tMustUpDownCounter(name string, option MetricOption) UpDownCounter\n\n\t// MustHistogram creates and returns a new Histogram.\n\t// It panics if any error occurs.\n\tMustHistogram(name string, option MetricOption) Histogram\n\n\t// MustObservableCounter creates and returns a new ObservableCounter.\n\t// It panics if any error occurs.\n\tMustObservableCounter(name string, option MetricOption) ObservableCounter\n\n\t// MustObservableUpDownCounter creates and returns a new ObservableUpDownCounter.\n\t// It panics if any error occurs.\n\tMustObservableUpDownCounter(name string, option MetricOption) ObservableUpDownCounter\n\n\t// MustObservableGauge creates and returns a new ObservableGauge.\n\t// It panics if any error occurs.\n\tMustObservableGauge(name string, option MetricOption) ObservableGauge\n\n\t// RegisterCallback registers callback on certain metrics.\n\t// A callback is bound to certain component and version, it is called when the associated metrics are read.\n\t// Multiple callbacks on the same component and version will be called by their registered sequence.\n\tRegisterCallback(callback Callback, canBeCallbackMetrics ...ObservableMetric) error\n\n\t// MustRegisterCallback performs as RegisterCallback, but it panics if any error occurs.\n\tMustRegisterCallback(callback Callback, canBeCallbackMetrics ...ObservableMetric)\n}\n\ntype localGlobalProvider struct {\n}\n\nvar (\n\t// globalProvider is the provider for global usage.\n\tglobalProvider Provider\n)\n\n// GetGlobalProvider retrieves the GetGlobalProvider instance.\nfunc GetGlobalProvider() GlobalProvider {\n\treturn &localGlobalProvider{}\n}\n\n// SetGlobalProvider registers `provider` as the global Provider,\n// which means the following metrics creating will be base on the global provider.\nfunc SetGlobalProvider(provider Provider) {\n\tglobalProvider = provider\n}\n\n// Meter creates and returns the Meter by given MeterOption.\nfunc (l *localGlobalProvider) Meter(option MeterOption) Meter {\n\treturn newMeter(option)\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc truncateGlobalAttributes() {\n\tglobalAttributesMu.Lock()\n\tdefer globalAttributesMu.Unlock()\n\tglobalAttributes = make([]globalAttributeItem, 0)\n}\n\nfunc Test_GlobalAttributes(t *testing.T) {\n\tdefer truncateGlobalAttributes()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"global\", \"gl\"),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"\",\n\t\t\tInstrumentVersion: \"\",\n\t\t\tInstrumentPattern: \"\",\n\t\t})\n\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"a\", 1),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_a\",\n\t\t\tInstrumentVersion: \"v1.0\",\n\t\t\tInstrumentPattern: \"\",\n\t\t})\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"b\", 2),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_bb\",\n\t\t\tInstrumentVersion: \"v1.1\",\n\t\t\tInstrumentPattern: \"\",\n\t\t})\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"c\", 3),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_bb\",\n\t\t\tInstrumentVersion: \"v1.1\",\n\t\t\tInstrumentPattern: \"\",\n\t\t})\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"d\", 4),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"\",\n\t\t\tInstrumentVersion: \"v1.0\",\n\t\t\tInstrumentPattern: \"ins.+\",\n\t\t})\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"e\", 5),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"\",\n\t\t\tInstrumentVersion: \"v1.0\",\n\t\t\tInstrumentPattern: \"ins_b.+\",\n\t\t})\n\t\tSetGlobalAttributes(Attributes{\n\t\t\tNewAttribute(\"f\", 6),\n\t\t}, SetGlobalAttributesOption{\n\t\t\tInstrument:        \"\",\n\t\t\tInstrumentVersion: \"v1.1\",\n\t\t\tInstrumentPattern: \"ins_b.+\",\n\t\t})\n\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"\",\n\t\t\tInstrumentVersion: \"\",\n\t\t}), Attributes{\n\t\t\tNewAttribute(\"global\", \"gl\"),\n\t\t})\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_a\",\n\t\t\tInstrumentVersion: \"\",\n\t\t}), Attributes{})\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_a\",\n\t\t\tInstrumentVersion: \"1.1\",\n\t\t}), Attributes{})\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_bb\",\n\t\t\tInstrumentVersion: \"v1.0\",\n\t\t}), Attributes{\n\t\t\tNewAttribute(\"d\", 4),\n\t\t\tNewAttribute(\"e\", 5),\n\t\t})\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_bb\",\n\t\t\tInstrumentVersion: \"v1.1\",\n\t\t}), Attributes{\n\t\t\tNewAttribute(\"b\", 2),\n\t\t\tNewAttribute(\"c\", 3),\n\t\t\tNewAttribute(\"f\", 6),\n\t\t})\n\t\tt.Assert(GetGlobalAttributes(GetGlobalAttributesOption{\n\t\t\tInstrument:        \"ins_cc\",\n\t\t\tInstrumentVersion: \"v1.1\",\n\t\t}), Attributes{})\n\t})\n}\n"
  },
  {
    "path": "os/gmetric/gmetric_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmetric_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gmetric\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Counter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmeterOption = gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.0\",\n\t\t\t}\n\t\t\tmetricName   = \"goframe.metric.demo.counter\"\n\t\t\tmetricOption = gmetric.MetricOption{\n\t\t\t\tHelp: \"This is a simple demo for Counter usage\",\n\t\t\t\tUnit: \"%\",\n\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\tgmetric.NewAttribute(\"const_label_a\", 1),\n\t\t\t\t},\n\t\t\t}\n\t\t\tmeter   = gmetric.GetGlobalProvider().Meter(meterOption)\n\t\t\tcounter = meter.MustCounter(metricName, metricOption)\n\t\t)\n\t\tt.Assert(counter.Info().Name(), metricName)\n\t\tt.Assert(counter.Info().Help(), metricOption.Help)\n\t\tt.Assert(counter.Info().Unit(), metricOption.Unit)\n\t\tt.Assert(counter.Info().Attributes(), metricOption.Attributes)\n\t\tt.Assert(counter.Info().Instrument().Name(), meterOption.Instrument)\n\t\tt.Assert(counter.Info().Instrument().Version(), meterOption.InstrumentVersion)\n\t})\n}\n\nfunc Test_Histogram(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmeterOption = gmetric.MeterOption{\n\t\t\t\tInstrument:        \"github.com/gogf/gf/example/metric/basic\",\n\t\t\t\tInstrumentVersion: \"v1.0\",\n\t\t\t}\n\t\t\tmetricName   = \"goframe.metric.demo.histogram\"\n\t\t\tmetricOption = gmetric.MetricOption{\n\t\t\t\tHelp: \"This is a simple demo for Histogram usage\",\n\t\t\t\tUnit: \"%\",\n\t\t\t\tAttributes: gmetric.Attributes{\n\t\t\t\t\tgmetric.NewAttribute(\"const_label_a\", 1),\n\t\t\t\t},\n\t\t\t\tBuckets: []float64{0, 10, 20, 50, 100, 500, 1000, 2000, 5000, 10000},\n\t\t\t}\n\t\t\tmeter     = gmetric.GetGlobalProvider().Meter(meterOption)\n\t\t\thistogram = meter.MustHistogram(metricName, metricOption)\n\t\t)\n\t\tt.Assert(histogram.Info().Name(), metricName)\n\t\tt.Assert(histogram.Info().Help(), metricOption.Help)\n\t\tt.Assert(histogram.Info().Unit(), metricOption.Unit)\n\t\tt.Assert(histogram.Info().Attributes(), metricOption.Attributes)\n\t\tt.Assert(histogram.Info().Instrument().Name(), meterOption.Instrument)\n\t\tt.Assert(histogram.Info().Instrument().Version(), meterOption.InstrumentVersion)\n\t\tt.Assert(histogram.Buckets(), metricOption.Buckets)\n\t})\n}\n\nfunc Test_CommonAttributes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcommonAttributes := gmetric.CommonAttributes()\n\t\tt.AssertGT(len(commonAttributes), 1)\n\t\tfmt.Println(commonAttributes)\n\t})\n}\n"
  },
  {
    "path": "os/gmlock/gmlock.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmlock implements a concurrent-safe memory-based locker.\npackage gmlock\n\nvar (\n\t// Default locker.\n\tlocker = New()\n)\n\n// Lock locks the `key` with writing lock.\n// If there's a write/reading lock the `key`,\n// it will blocks until the lock is released.\nfunc Lock(key string) {\n\tlocker.Lock(key)\n}\n\n// TryLock tries locking the `key` with writing lock,\n// it returns true if success, or if there's a write/reading lock the `key`,\n// it returns false.\nfunc TryLock(key string) bool {\n\treturn locker.TryLock(key)\n}\n\n// Unlock unlocks the writing lock of the `key`.\nfunc Unlock(key string) {\n\tlocker.Unlock(key)\n}\n\n// RLock locks the `key` with reading lock.\n// If there's a writing lock on `key`,\n// it will blocks until the writing lock is released.\nfunc RLock(key string) {\n\tlocker.RLock(key)\n}\n\n// TryRLock tries locking the `key` with reading lock.\n// It returns true if success, or if there's a writing lock on `key`, it returns false.\nfunc TryRLock(key string) bool {\n\treturn locker.TryRLock(key)\n}\n\n// RUnlock unlocks the reading lock of the `key`.\nfunc RUnlock(key string) {\n\tlocker.RUnlock(key)\n}\n\n// LockFunc locks the `key` with writing lock and callback function `f`.\n// If there's a write/reading lock the `key`,\n// it will blocks until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc LockFunc(key string, f func()) {\n\tlocker.LockFunc(key, f)\n}\n\n// RLockFunc locks the `key` with reading lock and callback function `f`.\n// If there's a writing lock the `key`,\n// it will blocks until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc RLockFunc(key string, f func()) {\n\tlocker.RLockFunc(key, f)\n}\n\n// TryLockFunc locks the `key` with writing lock and callback function `f`.\n// It returns true if success, or else if there's a write/reading lock the `key`, it return false.\n//\n// It releases the lock after `f` is executed.\nfunc TryLockFunc(key string, f func()) bool {\n\treturn locker.TryLockFunc(key, f)\n}\n\n// TryRLockFunc locks the `key` with reading lock and callback function `f`.\n// It returns true if success, or else if there's a writing lock the `key`, it returns false.\n//\n// It releases the lock after `f` is executed.\nfunc TryRLockFunc(key string, f func()) bool {\n\treturn locker.TryRLockFunc(key, f)\n}\n\n// Remove removes mutex with given `key`.\nfunc Remove(key string) {\n\tlocker.Remove(key)\n}\n"
  },
  {
    "path": "os/gmlock/gmlock_locker.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmlock\n\nimport (\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\nvar checker = func(v *sync.RWMutex) bool { return v == nil }\n\n// Locker is a memory based locker.\n// Note that there's no cache expire mechanism for mutex in locker.\n// You need remove certain mutex manually when you do not want use it anymore.\ntype Locker struct {\n\tm *gmap.KVMap[string, *sync.RWMutex]\n}\n\n// New creates and returns a new memory locker.\n// A memory locker can lock/unlock with dynamic string key.\nfunc New() *Locker {\n\treturn &Locker{\n\t\tm: gmap.NewKVMapWithChecker[string, *sync.RWMutex](checker, true),\n\t}\n}\n\n// Lock locks the `key` with writing lock.\n// If there's a write/reading lock the `key`,\n// it will block until the lock is released.\nfunc (l *Locker) Lock(key string) {\n\tl.getOrNewMutex(key).Lock()\n}\n\n// TryLock tries locking the `key` with writing lock,\n// it returns true if success, or it returns false if there's a writing/reading lock the `key`.\nfunc (l *Locker) TryLock(key string) bool {\n\treturn l.getOrNewMutex(key).TryLock()\n}\n\n// Unlock unlocks the writing lock of the `key`.\nfunc (l *Locker) Unlock(key string) {\n\tif v := l.m.Get(key); v != nil {\n\t\tv.Unlock()\n\t}\n}\n\n// RLock locks the `key` with reading lock.\n// If there's a writing lock on `key`,\n// it will blocks until the writing lock is released.\nfunc (l *Locker) RLock(key string) {\n\tl.getOrNewMutex(key).RLock()\n}\n\n// TryRLock tries locking the `key` with reading lock.\n// It returns true if success, or if there's a writing lock on `key`, it returns false.\nfunc (l *Locker) TryRLock(key string) bool {\n\treturn l.getOrNewMutex(key).TryRLock()\n}\n\n// RUnlock unlocks the reading lock of the `key`.\nfunc (l *Locker) RUnlock(key string) {\n\tif v := l.m.Get(key); v != nil {\n\t\tv.RUnlock()\n\t}\n}\n\n// LockFunc locks the `key` with writing lock and callback function `f`.\n// If there's a write/reading lock the `key`,\n// it will block until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc (l *Locker) LockFunc(key string, f func()) {\n\tl.Lock(key)\n\tdefer l.Unlock(key)\n\tf()\n}\n\n// RLockFunc locks the `key` with reading lock and callback function `f`.\n// If there's a writing lock the `key`,\n// it will block until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc (l *Locker) RLockFunc(key string, f func()) {\n\tl.RLock(key)\n\tdefer l.RUnlock(key)\n\tf()\n}\n\n// TryLockFunc locks the `key` with writing lock and callback function `f`.\n// It returns true if success, or else if there's a write/reading lock the `key`, it return false.\n//\n// It releases the lock after `f` is executed.\nfunc (l *Locker) TryLockFunc(key string, f func()) bool {\n\tif l.TryLock(key) {\n\t\tdefer l.Unlock(key)\n\t\tf()\n\t\treturn true\n\t}\n\treturn false\n}\n\n// TryRLockFunc locks the `key` with reading lock and callback function `f`.\n// It returns true if success, or else if there's a writing lock the `key`, it returns false.\n//\n// It releases the lock after `f` is executed.\nfunc (l *Locker) TryRLockFunc(key string, f func()) bool {\n\tif l.TryRLock(key) {\n\t\tdefer l.RUnlock(key)\n\t\tf()\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Remove removes mutex with given `key` from locker.\nfunc (l *Locker) Remove(key string) {\n\tl.m.Remove(key)\n}\n\n// Clear removes all mutexes from locker.\nfunc (l *Locker) Clear() {\n\tl.m.Clear()\n}\n\n// getOrNewMutex returns the mutex of given `key` if it exists,\n// or else creates and returns a new one.\nfunc (l *Locker) getOrNewMutex(key string) *sync.RWMutex {\n\treturn l.m.GetOrSetFuncLock(key, func() *sync.RWMutex {\n\t\treturn &sync.RWMutex{}\n\t})\n}\n"
  },
  {
    "path": "os/gmlock/gmlock_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmlock_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gmlock\"\n)\n\nvar (\n\tlockKey = \"This is the lock key for gmlock.\"\n)\n\nfunc Benchmark_GMLock_Lock_Unlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmlock.Lock(lockKey)\n\t\tgmlock.Unlock(lockKey)\n\t}\n}\n\nfunc Benchmark_GMLock_RLock_RUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmlock.RLock(lockKey)\n\t\tgmlock.RUnlock(lockKey)\n\t}\n}\n\nfunc Benchmark_GMLock_TryLock_Unlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tif gmlock.TryLock(lockKey) {\n\t\t\tgmlock.Unlock(lockKey)\n\t\t}\n\t}\n}\n\nfunc Benchmark_GMLock_TryRLock_RUnlock(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tif gmlock.TryRLock(lockKey) {\n\t\t\tgmlock.RUnlock(lockKey)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/gmlock/gmlock_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmlock_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gmlock\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Locker_Lock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tgmlock.Remove(key)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLock\"\n\t\tarray := garray.New(true)\n\t\tlock := gmlock.New()\n\t\tgo func() {\n\t\t\tlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\tlock.Unlock(key)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tlock.Clear()\n\t})\n\n}\n\nfunc Test_Locker_TryLock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testTryLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(150 * time.Millisecond)\n\t\t\tif gmlock.TryLock(key) {\n\t\t\t\tarray.Append(1)\n\t\t\t\tgmlock.Unlock(key)\n\t\t\t}\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(400 * time.Millisecond)\n\t\t\tif gmlock.TryLock(key) {\n\t\t\t\tarray.Append(1)\n\t\t\t\tgmlock.Unlock(key)\n\t\t\t}\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n}\n\nfunc Test_Locker_LockFunc(t *testing.T) {\n\t//no expire\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockFunc\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.LockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t}) //\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.LockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1) //\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_Locker_TryLockFunc(t *testing.T) {\n\t//no expire\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testTryLockFunc\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.TryLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.TryLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tgmlock.TryLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(150 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(400 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_Multiple_Goroutine(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tch := make(chan struct{})\n\t\tnum := 1000\n\t\twait := sync.WaitGroup{}\n\t\twait.Add(num)\n\t\tfor i := 0; i < num; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wait.Done()\n\t\t\t\t<-ch\n\t\t\t\tgmlock.Lock(\"test\")\n\t\t\t\tdefer gmlock.Unlock(\"test\")\n\t\t\t\ttime.Sleep(time.Millisecond)\n\t\t\t}()\n\t\t}\n\t\tclose(ch)\n\t\twait.Wait()\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tch := make(chan struct{})\n\t\tnum := 100\n\t\twait := sync.WaitGroup{}\n\t\twait.Add(num * 2)\n\t\tfor i := 0; i < num; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wait.Done()\n\t\t\t\t<-ch\n\t\t\t\tgmlock.Lock(\"test\")\n\t\t\t\tdefer gmlock.Unlock(\"test\")\n\t\t\t\ttime.Sleep(time.Millisecond)\n\t\t\t}()\n\t\t}\n\t\tfor i := 0; i < num; i++ {\n\t\t\tgo func() {\n\t\t\t\tdefer wait.Done()\n\t\t\t\t<-ch\n\t\t\t\tgmlock.RLock(\"test\")\n\t\t\t\tdefer gmlock.RUnlock(\"test\")\n\t\t\t\ttime.Sleep(time.Millisecond)\n\t\t\t}()\n\t\t}\n\t\tclose(ch)\n\t\twait.Wait()\n\t})\n}\n\nfunc Test_Locker_RLock(t *testing.T) {\n\t// RLock before Lock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testRLockBeforeLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.RLock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.RUnlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n\t// Lock before RLock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeRLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLock(key)\n\t\t\tarray.Append(1)\n\t\t\tgmlock.RUnlock(key)\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n\t// Lock before RLocks\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeRLocks\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.RUnlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.RUnlock(key)\n\t\t}()\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc Test_Locker_TryRLock(t *testing.T) {\n\t// Lock before TryRLock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeTryRLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tif gmlock.TryRLock(key) {\n\t\t\t\tarray.Append(1)\n\t\t\t\tgmlock.RUnlock(key)\n\t\t\t}\n\t\t}()\n\t\ttime.Sleep(150 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n\n\t// Lock before TryRLocks\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeTryRLocks\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tif gmlock.TryRLock(key) {\n\t\t\t\tarray.Append(1)\n\t\t\t\tgmlock.RUnlock(key)\n\t\t\t}\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tif gmlock.TryRLock(key) {\n\t\t\t\tarray.Append(1)\n\t\t\t\tgmlock.RUnlock(key)\n\t\t\t}\n\t\t}()\n\t\ttime.Sleep(150 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_Locker_RLockFunc(t *testing.T) {\n\t// RLockFunc before Lock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testRLockFuncBeforeLock\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.RLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\ttime.Sleep(150 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n\t// Lock before RLockFunc\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeRLockFunc\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n\t// Lock before RLockFuncs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeRLockFuncs\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.RLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc Test_Locker_TryRLockFunc(t *testing.T) {\n\t// Lock before TryRLockFunc\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeTryRLockFunc\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.TryRLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n\n\t// Lock before TryRLockFuncs\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkey := \"testLockBeforeTryRLockFuncs\"\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tgmlock.Lock(key)\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\tgmlock.Unlock(key)\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tgmlock.TryRLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tgmlock.TryRLockFunc(key, func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gmutex/gmutex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmutex inherits and extends sync.Mutex and sync.RWMutex with more futures.\n//\n// Note that, it is refracted using stdlib mutex of package sync from GoFrame version v2.5.2.\npackage gmutex\n\n// New creates and returns a new mutex.\n//\n// Deprecated: use Mutex or RWMutex instead.\nfunc New() *RWMutex {\n\treturn &RWMutex{}\n}\n"
  },
  {
    "path": "os/gmutex/gmutex_mutex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmutex\n\nimport \"sync\"\n\n// Mutex is a high level Mutex, which implements more rich features for mutex.\ntype Mutex struct {\n\tsync.Mutex\n}\n\n// LockFunc locks the mutex for writing with given callback function `f`.\n// If there's a write/reading lock the mutex, it will block until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc (m *Mutex) LockFunc(f func()) {\n\tm.Lock()\n\tdefer m.Unlock()\n\tf()\n}\n\n// TryLockFunc tries locking the mutex for writing with given callback function `f`.\n// it returns true immediately if success, or if there's a write/reading lock on the mutex,\n// it returns false immediately.\n//\n// It releases the lock after `f` is executed.\nfunc (m *Mutex) TryLockFunc(f func()) (result bool) {\n\tif m.TryLock() {\n\t\tresult = true\n\t\tdefer m.Unlock()\n\t\tf()\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gmutex/gmutex_rwmutex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmutex\n\nimport \"sync\"\n\n// RWMutex is a high level RWMutex, which implements more rich features for mutex.\ntype RWMutex struct {\n\tsync.RWMutex\n}\n\n// LockFunc locks the mutex for writing with given callback function `f`.\n// If there's a write/reading lock the mutex, it will block until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc (m *RWMutex) LockFunc(f func()) {\n\tm.Lock()\n\tdefer m.Unlock()\n\tf()\n}\n\n// RLockFunc locks the mutex for reading with given callback function `f`.\n// If there's a writing lock the mutex, it will block until the lock is released.\n//\n// It releases the lock after `f` is executed.\nfunc (m *RWMutex) RLockFunc(f func()) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\tf()\n}\n\n// TryLockFunc tries locking the mutex for writing with given callback function `f`.\n// it returns true immediately if success, or if there's a write/reading lock on the mutex,\n// it returns false immediately.\n//\n// It releases the lock after `f` is executed.\nfunc (m *RWMutex) TryLockFunc(f func()) (result bool) {\n\tif m.TryLock() {\n\t\tresult = true\n\t\tdefer m.Unlock()\n\t\tf()\n\t}\n\treturn\n}\n\n// TryRLockFunc tries locking the mutex for reading with given callback function `f`.\n// It returns true immediately if success, or if there's a writing lock on the mutex,\n// it returns false immediately.\n//\n// It releases the lock after `f` is executed.\nfunc (m *RWMutex) TryRLockFunc(f func()) (result bool) {\n\tif m.TryRLock() {\n\t\tresult = true\n\t\tdefer m.RUnlock()\n\t\tf()\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gmutex/gmutex_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmutex_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gmutex\"\n)\n\nvar (\n\tmu   = sync.Mutex{}\n\trwmu = sync.RWMutex{}\n\tgmu  = gmutex.New()\n)\n\nfunc Benchmark_Mutex_LockUnlock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tmu.Lock()\n\t\t\tmu.Unlock()\n\t\t}\n\t})\n}\n\nfunc Benchmark_RWMutex_LockUnlock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\trwmu.Lock()\n\t\t\trwmu.Unlock()\n\t\t}\n\t})\n}\n\nfunc Benchmark_RWMutex_RLockRUnlock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\trwmu.RLock()\n\t\t\trwmu.RUnlock()\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMutex_LockUnlock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tgmu.Lock()\n\t\t\tgmu.Unlock()\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMutex_TryLock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tif gmu.TryLock() {\n\t\t\t\tgmu.Unlock()\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMutex_RLockRUnlock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tgmu.RLock()\n\t\t\tgmu.RUnlock()\n\t\t}\n\t})\n}\n\nfunc Benchmark_GMutex_TryRLock(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tif gmu.TryRLock() {\n\t\t\t\tgmu.RUnlock()\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "os/gmutex/gmutex_z_unit_mutex_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmutex_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gmutex\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Mutex_Unlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.Mutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(400 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc Test_Mutex_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.Mutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_Mutex_TryLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.Mutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.TryLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(400 * time.Millisecond)\n\t\t\tmu.TryLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gmutex/gmutex_z_unit_rwmutex_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmutex_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gmutex\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_RWMutex_RUnlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tmu.RLockFunc(func() {\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t})\n\t})\n\n\t// RLock before Lock\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tmu.RLock()\n\t\tgo func() {\n\t\t\tmu.Lock()\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\tmu.Unlock()\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tmu.RUnlock()\n\t})\n}\n\nfunc Test_RWMutex_IsLocked(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tgo func() {\n\t\t\tmu.RLockFunc(func() {\n\t\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t})\n}\n\nfunc Test_RWMutex_Unlock(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(400 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc Test_RWMutex_LockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_RWMutex_TryLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.TryLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(400 * time.Millisecond)\n\t\t\tmu.TryLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc Test_RWMutex_RLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.RLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmu := gmutex.RWMutex{}\n\t\tarray := garray.New(true)\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.RLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.RLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tgo func() {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tmu.RLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc Test_RWMutex_TryRLockFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmu    = gmutex.RWMutex{}\n\t\t\tarray = garray.New(true)\n\t\t)\n\t\t// First writing lock\n\t\tgo func() {\n\t\t\tmu.LockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t\tglog.Print(context.TODO(), \"lock1 done\")\n\t\t\t\ttime.Sleep(2000 * time.Millisecond)\n\t\t\t})\n\t\t}()\n\t\t// This goroutine never gets the lock.\n\t\tgo func() {\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tmu.TryRLockFunc(func() {\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t}()\n\t\tfor index := 0; index < 1000; index++ {\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(4000 * time.Millisecond)\n\t\t\t\tmu.TryRLockFunc(func() {\n\t\t\t\t\tarray.Append(1)\n\t\t\t\t})\n\t\t\t}()\n\t\t}\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttime.Sleep(2000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1001)\n\t})\n}\n"
  },
  {
    "path": "os/gproc/gproc.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gproc implements management and communication for processes.\npackage gproc\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tenvKeyPPid            = \"GPROC_PPID\"\n\ttracingInstrumentName = \"github.com/gogf/gf/v2/os/gproc.Process\"\n)\n\nvar (\n\tprocessPid       = os.Getpid() // processPid is the pid of current process.\n\tprocessStartTime = time.Now()  // processStartTime is the start time of current process.\n)\n\n// Pid returns the pid of current process.\nfunc Pid() int {\n\treturn processPid\n}\n\n// PPid returns the custom parent pid if exists, or else it returns the system parent pid.\nfunc PPid() int {\n\tif !IsChild() {\n\t\treturn Pid()\n\t}\n\tppidValue := os.Getenv(envKeyPPid)\n\tif ppidValue != \"\" && ppidValue != \"0\" {\n\t\treturn gconv.Int(ppidValue)\n\t}\n\treturn PPidOS()\n}\n\n// PPidOS returns the system parent pid of current process.\n// Note that the difference between PPidOS and PPid function is that the PPidOS returns\n// the system ppid, but the PPid functions may return the custom pid by gproc if the custom\n// ppid exists.\nfunc PPidOS() int {\n\treturn os.Getppid()\n}\n\n// IsChild checks and returns whether current process is a child process.\n// A child process is forked by another gproc process.\nfunc IsChild() bool {\n\tppidValue := os.Getenv(envKeyPPid)\n\treturn ppidValue != \"\" && ppidValue != \"0\"\n}\n\n// SetPPid sets custom parent pid for current process.\nfunc SetPPid(ppid int) error {\n\tif ppid > 0 {\n\t\treturn os.Setenv(envKeyPPid, gconv.String(ppid))\n\t} else {\n\t\treturn os.Unsetenv(envKeyPPid)\n\t}\n}\n\n// StartTime returns the start time of current process.\nfunc StartTime() time.Time {\n\treturn processStartTime\n}\n\n// Uptime returns the duration which current process has been running\nfunc Uptime() time.Duration {\n\treturn time.Since(processStartTime)\n}\n\n// SearchBinary searches the binary `file` in current working folder and PATH environment.\nfunc SearchBinary(file string) string {\n\t// Check if it is absolute path of exists at current working directory.\n\tif gfile.Exists(file) {\n\t\treturn file\n\t}\n\treturn SearchBinaryPath(file)\n}\n\n// SearchBinaryPath searches the binary `file` in PATH environment.\nfunc SearchBinaryPath(file string) string {\n\tarray := ([]string)(nil)\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\tenvPath := genv.Get(\"PATH\", genv.Get(\"Path\")).String()\n\t\tif gstr.Contains(envPath, \";\") {\n\t\t\tarray = gstr.SplitAndTrim(envPath, \";\")\n\t\t} else if gstr.Contains(envPath, \":\") {\n\t\t\tarray = gstr.SplitAndTrim(envPath, \":\")\n\t\t}\n\t\tif gfile.Ext(file) != \".exe\" {\n\t\t\tfile += \".exe\"\n\t\t}\n\n\tdefault:\n\t\tarray = gstr.SplitAndTrim(genv.Get(\"PATH\").String(), \":\")\n\t}\n\tif len(array) > 0 {\n\t\tpath := \"\"\n\t\tfor _, v := range array {\n\t\t\tpath = v + gfile.Separator + file\n\t\t\tif gfile.Exists(path) && gfile.IsFile(path) {\n\t\t\t\treturn path\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "os/gproc/gproc_comm.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// MsgRequest is the request structure for process communication.\ntype MsgRequest struct {\n\tSenderPid   int    // Sender PID.\n\tReceiverPid int    // Receiver PID.\n\tGroup       string // Message group name.\n\tData        []byte // Request data.\n}\n\n// MsgResponse is the response structure for process communication.\ntype MsgResponse struct {\n\tCode    int    // 1: OK; Other: Error.\n\tMessage string // Response message.\n\tData    []byte // Response data.\n}\n\nconst (\n\tdefaultFolderNameForProcComm = \"gf_pid_port_mapping\" // Default folder name for storing pid to port mapping files.\n\tdefaultGroupNameForProcComm  = \"\"                    // Default group name.\n\tdefaultTcpPortForProcComm    = 10000                 // Starting port number for receiver listening.\n\tmaxLengthForProcMsgQueue     = 10000                 // Max size for each message queue of the group.\n)\n\nvar (\n\t// checker is used for checking whether the value is nil.\n\tchecker = func(v *gqueue.TQueue[*MsgRequest]) bool { return v == nil }\n\t// commReceiveQueues is the group name to queue map for storing received data.\n\t// The value of the map is type of *gqueue.TQueue[*MsgRequest].\n\tcommReceiveQueues = gmap.NewKVMapWithChecker[string, *gqueue.TQueue[*MsgRequest]](checker, true)\n\n\t// commPidFolderPath specifies the folder path storing pid to port mapping files.\n\tcommPidFolderPath string\n\n\t// commPidFolderPathOnce is used for lazy calculation for `commPidFolderPath` is necessary.\n\tcommPidFolderPathOnce sync.Once\n)\n\n// getConnByPid creates and returns a TCP connection for specified pid.\nfunc getConnByPid(pid int) (*gtcp.PoolConn, error) {\n\tport := getPortByPid(pid)\n\tif port > 0 {\n\t\tif conn, err := gtcp.NewPoolConn(fmt.Sprintf(\"127.0.0.1:%d\", port)); err == nil {\n\t\t\treturn conn, nil\n\t\t} else {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn nil, gerror.Newf(`could not find port for pid \"%d\"`, pid)\n}\n\n// getPortByPid returns the listening port for specified pid.\n// It returns 0 if no port found for the specified pid.\nfunc getPortByPid(pid int) int {\n\tpath := getCommFilePath(pid)\n\tif path == \"\" {\n\t\treturn 0\n\t}\n\treturn gconv.Int(gfile.GetContentsWithCache(path))\n}\n\n// getCommFilePath returns the pid to port mapping file path for given pid.\nfunc getCommFilePath(pid int) string {\n\tpath, err := getCommPidFolderPath()\n\tif err != nil {\n\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\treturn \"\"\n\t}\n\treturn gfile.Join(path, gconv.String(pid))\n}\n\n// getCommPidFolderPath retrieves and returns the available directory for storing pid mapping files.\nfunc getCommPidFolderPath() (folderPath string, err error) {\n\tcommPidFolderPathOnce.Do(func() {\n\t\tavailablePaths := []string{\n\t\t\t\"/var/tmp\",\n\t\t\t\"/var/run\",\n\t\t}\n\t\tif path, _ := gfile.Home(\".config\"); path != \"\" {\n\t\t\tavailablePaths = append(availablePaths, path)\n\t\t}\n\t\tavailablePaths = append(availablePaths, gfile.Temp())\n\t\tfor _, availablePath := range availablePaths {\n\t\t\tcheckPath := gfile.Join(availablePath, defaultFolderNameForProcComm)\n\t\t\tif !gfile.Exists(checkPath) && gfile.Mkdir(checkPath) != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif gfile.IsWritable(checkPath) {\n\t\t\t\tcommPidFolderPath = checkPath\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif commPidFolderPath == \"\" {\n\t\t\terr = gerror.Newf(\n\t\t\t\t`cannot find available folder for storing pid to port mapping files in paths: %+v`,\n\t\t\t\tavailablePaths,\n\t\t\t)\n\t\t}\n\t})\n\tfolderPath = commPidFolderPath\n\treturn\n}\n"
  },
  {
    "path": "os/gproc/gproc_comm_receive.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/gogf/gf/v2/container/gqueue\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\t// tcpListened marks whether the receiving listening service started.\n\ttcpListened = gtype.NewBool()\n)\n\n// Receive blocks and receives message from other process using local TCP listening.\n// Note that, it only enables the TCP listening service when this function called.\nfunc Receive(group ...string) *MsgRequest {\n\t// Use atomic operations to guarantee only one receiver goroutine listening.\n\tif tcpListened.Cas(false, true) {\n\t\tgo receiveTcpListening()\n\t}\n\tvar groupName string\n\tif len(group) > 0 {\n\t\tgroupName = group[0]\n\t} else {\n\t\tgroupName = defaultGroupNameForProcComm\n\t}\n\tqueue := commReceiveQueues.GetOrSetFuncLock(groupName, func() *gqueue.TQueue[*MsgRequest] {\n\t\treturn gqueue.NewTQueue[*MsgRequest](maxLengthForProcMsgQueue)\n\t})\n\treturn queue.Pop()\n}\n\n// receiveTcpListening scans local for available port and starts listening.\nfunc receiveTcpListening() {\n\tvar (\n\t\tlisten  *net.TCPListener\n\t\tconn    net.Conn\n\t\tport    = gtcp.MustGetFreePort()\n\t\taddress = fmt.Sprintf(\"127.0.0.1:%d\", port)\n\t)\n\ttcpAddress, err := net.ResolveTCPAddr(\"tcp\", address)\n\tif err != nil {\n\t\tpanic(gerror.Wrap(err, `net.ResolveTCPAddr failed`))\n\t}\n\tlisten, err = net.ListenTCP(\"tcp\", tcpAddress)\n\tif err != nil {\n\t\tpanic(gerror.Wrapf(err, `net.ListenTCP failed for address \"%s\"`, address))\n\t}\n\t// Save the port to the pid file.\n\tif err = gfile.PutContents(getCommFilePath(Pid()), gconv.String(port)); err != nil {\n\t\tpanic(err)\n\t}\n\t// Start listening.\n\tfor {\n\t\tif conn, err = listen.Accept(); err != nil {\n\t\t\tglog.Error(context.TODO(), err)\n\t\t} else if conn != nil {\n\t\t\tgo receiveTcpHandler(gtcp.NewConnByNetConn(conn))\n\t\t}\n\t}\n}\n\n// receiveTcpHandler is the connection handler for receiving data.\nfunc receiveTcpHandler(conn *gtcp.Conn) {\n\tvar (\n\t\tctx      = context.TODO()\n\t\tresult   []byte\n\t\tresponse MsgResponse\n\t)\n\tfor {\n\t\tresponse.Code = 0\n\t\tresponse.Message = \"\"\n\t\tresponse.Data = nil\n\t\tbuffer, err := conn.RecvPkg()\n\t\tif len(buffer) > 0 {\n\t\t\t// Package decoding.\n\t\t\tmsg := new(MsgRequest)\n\t\t\tif err = json.UnmarshalUseNumber(buffer, msg); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif msg.ReceiverPid != Pid() {\n\t\t\t\t// Not mine package.\n\t\t\t\tresponse.Message = fmt.Sprintf(\n\t\t\t\t\t\"receiver pid not match, target: %d, current: %d\",\n\t\t\t\t\tmsg.ReceiverPid, Pid(),\n\t\t\t\t)\n\t\t\t} else if v := commReceiveQueues.Get(msg.Group); v == nil {\n\t\t\t\t// Group check.\n\t\t\t\tresponse.Message = fmt.Sprintf(\"group [%s] does not exist\", msg.Group)\n\t\t\t} else {\n\t\t\t\t// Push to buffer queue.\n\t\t\t\tresponse.Code = 1\n\t\t\t\tv.Push(msg)\n\t\t\t}\n\t\t} else {\n\t\t\t// Empty package.\n\t\t\tresponse.Message = \"empty package\"\n\t\t}\n\t\tif err == nil {\n\t\t\tresult, err = json.Marshal(response)\n\t\t\tif err != nil {\n\t\t\t\tglog.Error(ctx, err)\n\t\t\t}\n\t\t\tif err = conn.SendPkg(result); err != nil {\n\t\t\t\tglog.Error(ctx, err)\n\t\t\t}\n\t\t} else {\n\t\t\t// Just close the connection if any error occurs.\n\t\t\tif err = conn.Close(); err != nil {\n\t\t\t\tglog.Error(ctx, err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/gproc/gproc_comm_send.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"io\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/net/gtcp\"\n)\n\n// Send sends data to specified process of given pid.\nfunc Send(pid int, data []byte, group ...string) error {\n\tmsg := MsgRequest{\n\t\tSenderPid:   Pid(),\n\t\tReceiverPid: pid,\n\t\tGroup:       defaultGroupNameForProcComm,\n\t\tData:        data,\n\t}\n\tif len(group) > 0 {\n\t\tmsg.Group = group[0]\n\t}\n\tmsgBytes, err := json.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar conn *gtcp.PoolConn\n\tconn, err = getConnByPid(pid)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\t// Do the sending.\n\tvar result []byte\n\tresult, err = conn.SendRecvPkg(msgBytes, gtcp.PkgOption{\n\t\tRetry: gtcp.Retry{\n\t\t\tCount: 3,\n\t\t},\n\t})\n\tif len(result) > 0 {\n\t\tresponse := new(MsgResponse)\n\t\tif err = json.UnmarshalUseNumber(result, response); err == nil {\n\t\t\tif response.Code != 1 {\n\t\t\t\terr = gerror.New(response.Message)\n\t\t\t}\n\t\t}\n\t}\n\t// EOF is not really an error.\n\tif err == io.EOF {\n\t\terr = nil\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "os/gproc/gproc_manager.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Manager is a process manager maintaining multiple processes.\ntype Manager struct {\n\tprocesses *gmap.IntAnyMap // Process id to Process object mapping.\n}\n\n// NewManager creates and returns a new process manager.\nfunc NewManager() *Manager {\n\treturn &Manager{\n\t\tprocesses: gmap.NewIntAnyMap(true),\n\t}\n}\n\n// NewProcess creates and returns a Process object.\nfunc (m *Manager) NewProcess(path string, args []string, environment []string) *Process {\n\tp := NewProcess(path, args, environment)\n\tp.Manager = m\n\treturn p\n}\n\n// GetProcess retrieves and returns a Process object.\n// It returns nil if it does not find the process with given `pid`.\nfunc (m *Manager) GetProcess(pid int) *Process {\n\tif v := m.processes.Get(pid); v != nil {\n\t\treturn v.(*Process)\n\t}\n\treturn nil\n}\n\n// AddProcess adds a process to current manager.\n// It does nothing if the process with given `pid` does not exist.\nfunc (m *Manager) AddProcess(pid int) {\n\tif m.processes.Get(pid) == nil {\n\t\tif process, err := os.FindProcess(pid); err == nil {\n\t\t\tp := m.NewProcess(\"\", nil, nil)\n\t\t\tp.Process = process\n\t\t\tm.processes.Set(pid, p)\n\t\t}\n\t}\n}\n\n// RemoveProcess removes a process from current manager.\nfunc (m *Manager) RemoveProcess(pid int) {\n\tm.processes.Remove(pid)\n}\n\n// Processes retrieves and returns all processes in current manager.\nfunc (m *Manager) Processes() []*Process {\n\tprocesses := make([]*Process, 0)\n\tm.processes.RLockFunc(func(m map[int]any) {\n\t\tfor _, v := range m {\n\t\t\tprocesses = append(processes, v.(*Process))\n\t\t}\n\t})\n\treturn processes\n}\n\n// Pids retrieves and returns all process id array in current manager.\nfunc (m *Manager) Pids() []int {\n\treturn m.processes.Keys()\n}\n\n// WaitAll waits until all process exit.\nfunc (m *Manager) WaitAll() {\n\tprocesses := m.Processes()\n\tif len(processes) > 0 {\n\t\tfor _, p := range processes {\n\t\t\t_ = p.Wait()\n\t\t}\n\t}\n}\n\n// KillAll kills all processes in current manager.\nfunc (m *Manager) KillAll() error {\n\tfor _, p := range m.Processes() {\n\t\tif err := p.Kill(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// SignalAll sends a signal `sig` to all processes in current manager.\nfunc (m *Manager) SignalAll(sig os.Signal) error {\n\tfor _, p := range m.Processes() {\n\t\tif err := p.Signal(sig); err != nil {\n\t\t\terr = gerror.Wrapf(err, `send signal to process failed for pid \"%d\" with signal \"%s\"`, p.Process.Pid, sig)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Send sends data bytes to all processes in current manager.\nfunc (m *Manager) Send(data []byte) {\n\tfor _, p := range m.Processes() {\n\t\t_ = p.Send(data)\n\t}\n}\n\n// SendTo sneds data bytes to specified processe in current manager.\nfunc (m *Manager) SendTo(pid int, data []byte) error {\n\treturn Send(pid, data)\n}\n\n// Clear removes all processes in current manager.\nfunc (m *Manager) Clear() {\n\tm.processes.Clear()\n}\n\n// Size returns the size of processes in current manager.\nfunc (m *Manager) Size() int {\n\treturn m.processes.Size()\n}\n"
  },
  {
    "path": "os/gproc/gproc_must.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"context\"\n\t\"io\"\n)\n\n// MustShell performs as Shell, but it panics if any error occurs.\nfunc MustShell(ctx context.Context, cmd string, out io.Writer, in io.Reader) {\n\tif err := Shell(ctx, cmd, out, in); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustShellRun performs as ShellRun, but it panics if any error occurs.\nfunc MustShellRun(ctx context.Context, cmd string) {\n\tif err := ShellRun(ctx, cmd); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustShellExec performs as ShellExec, but it panics if any error occurs.\nfunc MustShellExec(ctx context.Context, cmd string, environment ...[]string) string {\n\tresult, err := ShellExec(ctx, cmd, environment...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "os/gproc/gproc_process.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/net/gtrace\"\n\t\"github.com/gogf/gf/v2/os/genv\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Process is the struct for a single process.\ntype Process struct {\n\texec.Cmd\n\tManager *Manager\n\tPPid    int\n}\n\n// NewProcess creates and returns a new Process.\nfunc NewProcess(path string, args []string, environment ...[]string) *Process {\n\tenv := os.Environ()\n\tif len(environment) > 0 {\n\t\tenv = append(env, environment[0]...)\n\t}\n\tprocess := &Process{\n\t\tManager: nil,\n\t\tPPid:    os.Getpid(),\n\t\tCmd: exec.Cmd{\n\t\t\tArgs:       []string{path},\n\t\t\tPath:       path,\n\t\t\tStdin:      os.Stdin,\n\t\t\tStdout:     os.Stdout,\n\t\t\tStderr:     os.Stderr,\n\t\t\tEnv:        env,\n\t\t\tExtraFiles: make([]*os.File, 0),\n\t\t},\n\t}\n\tprocess.Dir, _ = os.Getwd()\n\tif len(args) > 0 {\n\t\t// Exclude of current binary path.\n\t\tstart := 0\n\t\tif strings.EqualFold(path, args[0]) {\n\t\t\tstart = 1\n\t\t}\n\t\tprocess.Args = append(process.Args, args[start:]...)\n\t}\n\treturn process\n}\n\n// NewProcessCmd creates and returns a process with given command and optional environment variable array.\nfunc NewProcessCmd(cmd string, environment ...[]string) *Process {\n\treturn NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment...)\n}\n\n// Start starts executing the process in non-blocking way.\n// It returns the pid if success, or else it returns an error.\nfunc (p *Process) Start(ctx context.Context) (int, error) {\n\tif p.Process != nil {\n\t\treturn p.Pid(), nil\n\t}\n\t// OpenTelemetry for command.\n\tvar (\n\t\tspan trace.Span\n\t\ttr   = otel.GetTracerProvider().Tracer(\n\t\t\ttracingInstrumentName,\n\t\t\ttrace.WithInstrumentationVersion(gf.VERSION),\n\t\t)\n\t)\n\tctx, span = tr.Start(\n\t\totel.GetTextMapPropagator().Extract(\n\t\t\tctx,\n\t\t\tpropagation.MapCarrier(genv.Map()),\n\t\t),\n\t\tgstr.Join(os.Args, \" \"),\n\t\ttrace.WithSpanKind(trace.SpanKindInternal),\n\t)\n\tdefer span.End()\n\tspan.SetAttributes(gtrace.CommonLabels()...)\n\n\t// OpenTelemetry propagation.\n\ttracingEnv := tracingEnvFromCtx(ctx)\n\tif len(tracingEnv) > 0 {\n\t\tp.Env = append(p.Env, tracingEnv...)\n\t}\n\tp.Env = append(p.Env, fmt.Sprintf(\"%s=%d\", envKeyPPid, p.PPid))\n\tp.Env = genv.Filter(p.Env)\n\n\t// On Windows, this works and doesn't work on other platforms\n\tif runtime.GOOS == \"windows\" {\n\t\tjoinProcessArgs(p)\n\t}\n\n\tif err := p.Cmd.Start(); err == nil {\n\t\tif p.Manager != nil {\n\t\t\tp.Manager.processes.Set(p.Process.Pid, p)\n\t\t}\n\t\treturn p.Process.Pid, nil\n\t} else {\n\t\treturn 0, err\n\t}\n}\n\n// Run executes the process in blocking way.\nfunc (p *Process) Run(ctx context.Context) error {\n\tif _, err := p.Start(ctx); err == nil {\n\t\treturn p.Wait()\n\t} else {\n\t\treturn err\n\t}\n}\n\n// Pid retrieves and returns the PID for the process.\nfunc (p *Process) Pid() int {\n\tif p.Process != nil {\n\t\treturn p.Process.Pid\n\t}\n\treturn 0\n}\n\n// Send sends custom data to the process.\nfunc (p *Process) Send(data []byte) error {\n\tif p.Process != nil {\n\t\treturn Send(p.Process.Pid, data)\n\t}\n\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"invalid process\")\n}\n\n// Release releases any resources associated with the Process p,\n// rendering it unusable in the future.\n// Release only needs to be called if Wait is not.\nfunc (p *Process) Release() error {\n\treturn p.Process.Release()\n}\n\n// Kill causes the Process to exit immediately.\nfunc (p *Process) Kill() (err error) {\n\terr = p.Process.Kill()\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `kill process failed for pid \"%d\"`, p.Process.Pid)\n\t\treturn err\n\t}\n\tif p.Manager != nil {\n\t\tp.Manager.processes.Remove(p.Pid())\n\t}\n\tif runtime.GOOS != \"windows\" {\n\t\tif err = p.Process.Release(); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t}\n\t// It ignores this error, just log it.\n\t_, err = p.Process.Wait()\n\tintlog.Errorf(context.TODO(), `%+v`, err)\n\treturn nil\n}\n\n// Signal sends a signal to the Process.\n// Sending Interrupt on Windows is not implemented.\nfunc (p *Process) Signal(sig os.Signal) error {\n\treturn p.Process.Signal(sig)\n}\n"
  },
  {
    "path": "os/gproc/gproc_process_newprocess.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build !windows\n\npackage gproc\n\n// Do nothing, just set it on the Windows platform\nfunc joinProcessArgs(p *Process) {}\n"
  },
  {
    "path": "os/gproc/gproc_process_newprocess_windows.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build windows\n\npackage gproc\n\nimport (\n\t\"syscall\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Set the underlying parameters directly on the Windows platform\nfunc joinProcessArgs(p *Process) {\n\tp.SysProcAttr = &syscall.SysProcAttr{}\n\tp.SysProcAttr.CmdLine = gstr.Join(p.Args, \" \")\n}\n"
  },
  {
    "path": "os/gproc/gproc_shell.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"runtime\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/propagation\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\n// Shell executes command `cmd` synchronously with given input pipe `in` and output pipe `out`.\n// The command `cmd` reads the input parameters from input pipe `in`, and writes its output automatically\n// to output pipe `out`.\nfunc Shell(ctx context.Context, cmd string, out io.Writer, in io.Reader) error {\n\tp := NewProcess(\n\t\tgetShell(),\n\t\tappend([]string{getShellOption()}, parseCommand(cmd)...),\n\t)\n\tp.Stdin = in\n\tp.Stdout = out\n\treturn p.Run(ctx)\n}\n\n// ShellRun executes given command `cmd` synchronously and outputs the command result to the stdout.\nfunc ShellRun(ctx context.Context, cmd string) error {\n\tp := NewProcess(\n\t\tgetShell(),\n\t\tappend([]string{getShellOption()}, parseCommand(cmd)...),\n\t)\n\treturn p.Run(ctx)\n}\n\n// ShellExec executes given command `cmd` synchronously and returns the command result.\nfunc ShellExec(ctx context.Context, cmd string, environment ...[]string) (result string, err error) {\n\tvar (\n\t\tbuf = bytes.NewBuffer(nil)\n\t\tp   = NewProcess(\n\t\t\tgetShell(),\n\t\t\tappend([]string{getShellOption()}, parseCommand(cmd)...),\n\t\t\tenvironment...,\n\t\t)\n\t)\n\tp.Stdout = buf\n\tp.Stderr = buf\n\terr = p.Run(ctx)\n\tresult = buf.String()\n\treturn\n}\n\n// parseCommand parses command `cmd` into slice arguments.\n//\n// Note that it just parses the `cmd` for \"cmd.exe\" binary in windows, but it is not necessary\n// parsing the `cmd` for other systems using \"bash\"/\"sh\" binary.\nfunc parseCommand(cmd string) (args []string) {\n\treturn []string{cmd}\n}\n\n// getShell returns the shell command depending on current working operating system.\n// It returns \"cmd.exe\" for windows, and \"bash\" or \"sh\" for others.\nfunc getShell() string {\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\treturn SearchBinary(\"cmd.exe\")\n\n\tdefault:\n\t\t// Check the default binary storage path.\n\t\tif gfile.Exists(\"/bin/bash\") {\n\t\t\treturn \"/bin/bash\"\n\t\t}\n\t\tif gfile.Exists(\"/bin/sh\") {\n\t\t\treturn \"/bin/sh\"\n\t\t}\n\t\t// Else search the env PATH.\n\t\tpath := SearchBinary(\"bash\")\n\t\tif path == \"\" {\n\t\t\tpath = SearchBinary(\"sh\")\n\t\t}\n\t\treturn path\n\t}\n}\n\n// getShellOption returns the shell option depending on current working operating system.\n// It returns \"/c\" for windows, and \"-c\" for others.\nfunc getShellOption() string {\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\treturn \"/c\"\n\n\tdefault:\n\t\treturn \"-c\"\n\t}\n}\n\n// tracingEnvFromCtx converts OpenTelemetry propagation data as environment variables.\nfunc tracingEnvFromCtx(ctx context.Context) []string {\n\tvar (\n\t\ta = make([]string, 0)\n\t\tm = make(map[string]string)\n\t)\n\totel.GetTextMapPropagator().Inject(ctx, propagation.MapCarrier(m))\n\tfor k, v := range m {\n\t\ta = append(a, fmt.Sprintf(`%s=%s`, k, v))\n\t}\n\treturn a\n}\n"
  },
  {
    "path": "os/gproc/gproc_signal.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gproc\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"syscall\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// SigHandler defines a function type for signal handling.\ntype SigHandler func(sig os.Signal)\n\nvar (\n\t// Use internal variable to guarantee concurrent safety\n\t// when multiple Listen happen.\n\tlistenOnce        = sync.Once{}\n\twaitChan          = make(chan struct{})\n\tsignalChan        = make(chan os.Signal, 1)\n\tsignalHandlerMu   sync.Mutex\n\tsignalHandlerMap  = make(map[os.Signal][]SigHandler)\n\tshutdownSignalMap = map[os.Signal]struct{}{\n\t\tsyscall.SIGINT:  {},\n\t\tsyscall.SIGQUIT: {},\n\t\tsyscall.SIGKILL: {},\n\t\tsyscall.SIGTERM: {},\n\t\tsyscall.SIGABRT: {},\n\t}\n)\n\nfunc init() {\n\tfor sig := range shutdownSignalMap {\n\t\tsignalHandlerMap[sig] = make([]SigHandler, 0)\n\t}\n}\n\n// AddSigHandler adds custom signal handler for custom one or more signals.\nfunc AddSigHandler(handler SigHandler, signals ...os.Signal) {\n\tsignalHandlerMu.Lock()\n\tdefer signalHandlerMu.Unlock()\n\tfor _, sig := range signals {\n\t\tsignalHandlerMap[sig] = append(signalHandlerMap[sig], handler)\n\t}\n\tnotifySignals()\n}\n\n// AddSigHandlerShutdown adds custom signal handler for shutdown signals:\n// syscall.SIGINT,\n// syscall.SIGQUIT,\n// syscall.SIGKILL,\n// syscall.SIGTERM,\n// syscall.SIGABRT.\nfunc AddSigHandlerShutdown(handler ...SigHandler) {\n\tsignalHandlerMu.Lock()\n\tdefer signalHandlerMu.Unlock()\n\tfor _, h := range handler {\n\t\tfor sig := range shutdownSignalMap {\n\t\t\tsignalHandlerMap[sig] = append(signalHandlerMap[sig], h)\n\t\t}\n\t}\n\tnotifySignals()\n}\n\n// Listen blocks and does signal listening and handling.\nfunc Listen() {\n\tlistenOnce.Do(func() {\n\t\tgo listen()\n\t})\n\n\t<-waitChan\n}\n\nfunc listen() {\n\tdefer close(waitChan)\n\n\tvar (\n\t\tctx = context.Background()\n\t\twg  = sync.WaitGroup{}\n\t\tsig os.Signal\n\t)\n\tfor {\n\t\tsig = <-signalChan\n\t\tintlog.Printf(ctx, `signal received: %s`, sig.String())\n\t\tif handlers := getHandlersBySignal(sig); len(handlers) > 0 {\n\t\t\tfor _, handler := range handlers {\n\t\t\t\twg.Add(1)\n\t\t\t\tvar (\n\t\t\t\t\tcurrentHandler = handler\n\t\t\t\t\tcurrentSig     = sig\n\t\t\t\t)\n\t\t\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\t\t\tdefer wg.Done()\n\t\t\t\t\tcurrentHandler(currentSig)\n\t\t\t\t}, func(ctx context.Context, exception error) {\n\t\t\t\t\tintlog.Errorf(ctx, `execute signal handler failed: %+v`, exception)\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\t// If it is shutdown signal, it exits this signal listening.\n\t\tif _, ok := shutdownSignalMap[sig]; ok {\n\t\t\tintlog.Printf(\n\t\t\t\tctx,\n\t\t\t\t`receive shutdown signal \"%s\", waiting all signal handler done`,\n\t\t\t\tsig.String(),\n\t\t\t)\n\t\t\t// Wait until signal handlers done.\n\t\t\twg.Wait()\n\t\t\tintlog.Print(ctx, `all signal handler done, exit process`)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc notifySignals() {\n\tvar signals = make([]os.Signal, 0)\n\tfor s := range signalHandlerMap {\n\t\tsignals = append(signals, s)\n\t}\n\tsignal.Notify(signalChan, signals...)\n}\n\nfunc getHandlersBySignal(sig os.Signal) []SigHandler {\n\tsignalHandlerMu.Lock()\n\tdefer signalHandlerMu.Unlock()\n\treturn signalHandlerMap[sig]\n}\n"
  },
  {
    "path": "os/gproc/gproc_z_signal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n//go:build linux\n\npackage gproc\n\nimport (\n\t\"os\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Signal(t *testing.T) {\n\tgo Listen()\n\n\t// non shutdown signal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsigRec := make(chan os.Signal, 1)\n\t\tAddSigHandler(func(sig os.Signal) {\n\t\t\tsigRec <- sig\n\t\t}, syscall.SIGUSR1, syscall.SIGUSR2)\n\n\t\tsendSignal(syscall.SIGUSR1)\n\t\tselect {\n\t\tcase s := <-sigRec:\n\t\t\tt.AssertEQ(s, syscall.SIGUSR1)\n\t\t\tt.AssertEQ(false, isWaitChClosed())\n\t\tcase <-time.After(time.Second):\n\t\t\tt.Error(\"signal SIGUSR1 handler timeout\")\n\t\t}\n\n\t\tsendSignal(syscall.SIGUSR2)\n\t\tselect {\n\t\tcase s := <-sigRec:\n\t\t\tt.AssertEQ(s, syscall.SIGUSR2)\n\t\t\tt.AssertEQ(false, isWaitChClosed())\n\t\tcase <-time.After(time.Second):\n\t\t\tt.Error(\"signal SIGUSR2 handler timeout\")\n\t\t}\n\n\t\tsendSignal(syscall.SIGHUP)\n\t\tselect {\n\t\tcase <-sigRec:\n\t\t\tt.Error(\"signal SIGHUP should not be listen\")\n\t\tcase <-time.After(time.Millisecond * 100):\n\t\t}\n\n\t\t// multiple listen\n\t\tgo Listen()\n\t\tgo Listen()\n\t\tsendSignal(syscall.SIGUSR1)\n\t\tcnt := 0\n\t\ttimeout := time.After(time.Second)\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-sigRec:\n\t\t\t\tcnt++\n\t\t\tcase <-timeout:\n\t\t\t\tif cnt == 0 {\n\t\t\t\t\tt.Error(\"signal SIGUSR2 handler timeout\")\n\t\t\t\t}\n\t\t\t\tif cnt != 1 {\n\t\t\t\t\tt.Error(\"multi Listen() repetitive execution\")\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\t// test shutdown signal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsigRec := make(chan os.Signal, 1)\n\t\tAddSigHandlerShutdown(func(sig os.Signal) {\n\t\t\tsigRec <- sig\n\t\t})\n\n\t\tsendSignal(syscall.SIGTERM)\n\t\t// wait the listen done\n\t\ttime.Sleep(time.Second)\n\n\t\tselect {\n\t\tcase s := <-sigRec:\n\t\t\tt.AssertEQ(s, syscall.SIGTERM)\n\t\t\tt.AssertEQ(true, isWaitChClosed())\n\t\tcase <-time.After(time.Second):\n\t\t\tt.Error(\"signal SIGUSR2 handler timeout\")\n\t\t}\n\t})\n}\n\nfunc sendSignal(sig os.Signal) {\n\tsignalChan <- sig\n}\n\nfunc isWaitChClosed() bool {\n\tselect {\n\tcase _, ok := <-waitChan:\n\t\treturn !ok\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "os/gproc/gproc_z_unit_process_windows_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\n//go:build windows\n\npackage gproc_test\n\nimport (\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ProcessRun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbinary := gproc.SearchBinary(\"go\")\n\t\tt.AssertNE(binary, \"\")\n\t\tvar command = gproc.NewProcess(binary, nil)\n\n\t\ttestPath := gtest.DataPath(\"gobuild\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\toutput := filepath.Join(testPath, \"main.exe\")\n\n\t\tcommand.Args = append(command.Args, \"build\")\n\t\tcommand.Args = append(command.Args, `-ldflags=\"-X 'main.TestString=\\\"test string\\\"'\"`)\n\t\tcommand.Args = append(command.Args, \"-o\", output)\n\t\tcommand.Args = append(command.Args, filename)\n\n\t\terr := command.Run(gctx.GetInitCtx())\n\t\tt.AssertNil(err)\n\n\t\texists := gfile.Exists(output)\n\t\tt.Assert(exists, true)\n\t\tdefer gfile.Remove(output)\n\n\t\trunCmd := gproc.NewProcess(output, nil)\n\t\tvar buf strings.Builder\n\t\trunCmd.Stdout = &buf\n\t\trunCmd.Stderr = &buf\n\t\terr = runCmd.Run(gctx.GetInitCtx())\n\t\tt.Assert(err, nil)\n\t\tt.Assert(buf.String(), `\"test string\"`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbinary := gproc.SearchBinary(\"go\")\n\t\tt.AssertNE(binary, \"\")\n\t\t// NewProcess(path,args) path： It's best not to have spaces\n\t\tvar command = gproc.NewProcess(binary, nil)\n\n\t\ttestPath := gtest.DataPath(\"gobuild\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\toutput := filepath.Join(testPath, \"main.exe\")\n\n\t\tcommand.Args = append(command.Args, \"build\")\n\t\tcommand.Args = append(command.Args, `-ldflags=\"-s -w\"`)\n\t\tcommand.Args = append(command.Args, \"-o\", output)\n\t\tcommand.Args = append(command.Args, filename)\n\n\t\terr := command.Run(gctx.GetInitCtx())\n\t\tt.AssertNil(err)\n\n\t\texists := gfile.Exists(output)\n\t\tt.Assert(exists, true)\n\n\t\tdefer gfile.Remove(output)\n\t})\n}\n"
  },
  {
    "path": "os/gproc/gproc_z_unit_shell_windows_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\n//go:build windows\n\npackage gproc_test\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_ShellExec_GoBuild_Windows(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttestPath := gtest.DataPath(\"gobuild\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\toutput := filepath.Join(testPath, \"main.exe\")\n\t\tcmd := fmt.Sprintf(`go build -ldflags=\"-s -w\" -o %s  %s`, output, filename)\n\n\t\terr := gproc.ShellRun(gctx.New(), cmd)\n\t\tt.Assert(err, nil)\n\n\t\texists := gfile.Exists(output)\n\t\tt.Assert(exists, true)\n\n\t\tdefer gfile.Remove(output)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttestPath := gtest.DataPath(\"gobuild\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\toutput := filepath.Join(testPath, \"main.exe\")\n\t\tcmd := fmt.Sprintf(`go build -ldflags=\"-X 'main.TestString=\\\"test string\\\"'\" -o %s %s`, output, filename)\n\n\t\terr := gproc.ShellRun(gctx.New(), cmd)\n\t\tt.Assert(err, nil)\n\n\t\texists := gfile.Exists(output)\n\t\tt.Assert(exists, true)\n\t\tdefer gfile.Remove(output)\n\n\t\tresult, err := gproc.ShellExec(gctx.New(), output)\n\t\tt.Assert(err, nil)\n\t\tt.Assert(result, `\"test string\"`)\n\t})\n\n}\n\nfunc Test_ShellExec_SpaceDir_Windows(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttestPath := gtest.DataPath(\"shellexec\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\t// go build -o test.exe main.go\n\t\tcmd := fmt.Sprintf(`go build -o test.exe %s`, filename)\n\t\tr, err := gproc.ShellExec(gctx.New(), cmd)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, \"\")\n\n\t\texists := gfile.Exists(filename)\n\t\tt.Assert(exists, true)\n\n\t\toutputDir := filepath.Join(testPath, \"testdir\")\n\t\toutput := filepath.Join(outputDir, \"test.exe\")\n\t\terr = gfile.Move(\"test.exe\", output)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(output)\n\n\t\texpectContent := \"123\"\n\t\ttestOutput := filepath.Join(testPath, \"space dir\", \"test.txt\")\n\t\tcmd = fmt.Sprintf(`%s -c %s -o \"%s\"`, output, expectContent, testOutput)\n\t\tr, err = gproc.ShellExec(gctx.New(), cmd)\n\t\tt.AssertNil(err)\n\n\t\texists = gfile.Exists(testOutput)\n\t\tt.Assert(exists, true)\n\t\tdefer gfile.Remove(testOutput)\n\n\t\tcontents := gfile.GetContents(testOutput)\n\t\tt.Assert(contents, expectContent)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttestPath := gtest.DataPath(\"shellexec\")\n\t\tfilename := filepath.Join(testPath, \"main.go\")\n\t\t// go build -o test.exe main.go\n\t\tcmd := fmt.Sprintf(`go build -o test.exe %s`, filename)\n\t\tr, err := gproc.ShellExec(gctx.New(), cmd)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, \"\")\n\n\t\texists := gfile.Exists(filename)\n\t\tt.Assert(exists, true)\n\n\t\toutputDir := filepath.Join(testPath, \"space dir\")\n\t\toutput := filepath.Join(outputDir, \"test.exe\")\n\t\terr = gfile.Move(\"test.exe\", output)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(output)\n\n\t\texpectContent := \"123\"\n\t\ttestOutput := filepath.Join(testPath, \"testdir\", \"test.txt\")\n\t\tcmd = fmt.Sprintf(`\"%s\" -c %s -o %s`, output, expectContent, testOutput)\n\t\tr, err = gproc.ShellExec(gctx.New(), cmd)\n\t\tt.AssertNil(err)\n\n\t\texists = gfile.Exists(testOutput)\n\t\tt.Assert(exists, true)\n\t\tdefer gfile.Remove(testOutput)\n\n\t\tcontents := gfile.GetContents(testOutput)\n\t\tt.Assert(contents, expectContent)\n\n\t})\n}\n"
  },
  {
    "path": "os/gproc/gproc_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gproc_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gproc\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tenvKeyPPid = \"GPROC_PPID\"\n)\n\nfunc Test_ShellExec(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts, err := gproc.ShellExec(gctx.New(), `echo 123`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, \"123\\n\")\n\t})\n\t// error\n\tgtest.C(t, func(t *gtest.T) {\n\t\t_, err := gproc.ShellExec(gctx.New(), `NoneExistCommandCall`)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Pid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(os.Getpid(), gproc.Pid())\n\t})\n}\n\nfunc Test_IsChild(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\toriginalPPid := os.Getenv(envKeyPPid)\n\t\tdefer os.Setenv(envKeyPPid, originalPPid)\n\n\t\tos.Setenv(envKeyPPid, \"1234\")\n\t\tt.Assert(true, gproc.IsChild())\n\n\t\tos.Unsetenv(envKeyPPid)\n\t\tt.Assert(false, gproc.IsChild())\n\t})\n}\n\nfunc Test_SetPPid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gproc.SetPPid(1234)\n\t\tt.AssertNil(err)\n\t\tt.Assert(\"1234\", os.Getenv(envKeyPPid))\n\n\t\terr = gproc.SetPPid(0)\n\t\tt.AssertNil(err)\n\t\tt.Assert(\"\", os.Getenv(envKeyPPid))\n\t})\n}\n\nfunc Test_StartTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := gproc.StartTime()\n\t\tt.Assert(result, gproc.StartTime())\n\t})\n}\n\nfunc Test_Uptime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := gproc.Uptime()\n\t\tt.AssertGT(result, 0)\n\t})\n}\n\nfunc Test_SearchBinary_FoundInPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttempDir := t.TempDir()\n\t\ttempFile := filepath.Join(tempDir, \"testbinary\")\n\t\tgfile.Create(tempFile)\n\t\tos.Chmod(tempFile, 0755)\n\n\t\toriginalPath := os.Getenv(\"PATH\")\n\t\tos.Setenv(\"PATH\", tempDir+string(os.PathListSeparator)+originalPath)\n\t\tdefer os.Setenv(\"PATH\", originalPath)\n\n\t\tresult := gproc.SearchBinary(\"testbinary\")\n\t\tt.Assert(result, tempFile)\n\t})\n}\n\nfunc Test_SearchBinary_NotFound(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := gproc.SearchBinary(\"nonexistentbinary\")\n\t\tt.Assert(result, \"\")\n\t})\n}\n\nfunc Test_SearchBinaryPath_FoundInPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttempDir := t.TempDir()\n\t\ttempFile := filepath.Join(tempDir, \"testbinary\")\n\t\tgfile.Create(tempFile)\n\t\tos.Chmod(tempFile, 0755)\n\n\t\toriginalPath := os.Getenv(\"PATH\")\n\t\tos.Setenv(\"PATH\", tempDir+string(os.PathListSeparator)+originalPath)\n\t\tdefer os.Setenv(\"PATH\", originalPath)\n\n\t\tresult := gproc.SearchBinaryPath(\"testbinary\")\n\t\tt.Assert(result, tempFile)\n\t})\n}\n\nfunc Test_SearchBinaryPath_NotFound(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tresult := gproc.SearchBinaryPath(\"nonexistentbinary\")\n\t\tt.Assert(result, \"\")\n\t})\n}\n\nfunc Test_PPidOS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tppid := gproc.PPidOS()\n\t\texpectedPpid := os.Getppid()\n\t\tt.Assert(ppid, expectedPpid)\n\t})\n}\n\nfunc Test_PPid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcustomPPid := 12345\n\t\tos.Setenv(\"GPROC_PPID\", gconv.String(customPPid))\n\t\tdefer os.Unsetenv(\"GPROC_PPID\")\n\n\t\tt.Assert(gproc.PPid(), customPPid)\n\t})\n}\n"
  },
  {
    "path": "os/gproc/testdata/gobuild/main.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage main\n\nvar (\n\tTestString string\n)\n\nfunc main() {\n\tprint(TestString)\n}\n"
  },
  {
    "path": "os/gproc/testdata/shellexec/main.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tvar content string\n\tvar output string\n\tflag.StringVar(&content, \"c\", \"\", \"写入内容\")\n\tflag.StringVar(&output, \"o\", \"\", \"写入路径\")\n\tflag.Parse()\n\tfmt.Println(os.Args)\n\tfmt.Println(content)\n\tfmt.Println(output)\n\tif output != \"\" {\n\t\tfile, err := os.Create(output)\n\t\tif err != nil {\n\t\t\tpanic(\"create file fail: \" + err.Error())\n\t\t}\n\t\tdefer file.Close()\n\t\tfile.WriteString(content)\n\t}\n}\n"
  },
  {
    "path": "os/gres/gres.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gres provides resource management and packing/unpacking feature between files and bytes.\npackage gres\n\nconst (\n\t// Separator for directories.\n\tSeparator = \"/\"\n)\n\nvar (\n\t// Default resource object.\n\tdefaultResource = Instance()\n)\n\n// Add unpacks and adds the `content` into the default resource object.\n// The unnecessary parameter `prefix` indicates the prefix\n// for each file storing into current resource object.\nfunc Add(content string, prefix ...string) error {\n\treturn defaultResource.Add(content, prefix...)\n}\n\n// Load loads, unpacks and adds the data from `path` into the default resource object.\n// The unnecessary parameter `prefix` indicates the prefix\n// for each file storing into current resource object.\nfunc Load(path string, prefix ...string) error {\n\treturn defaultResource.Load(path, prefix...)\n}\n\n// Get returns the file with given path.\nfunc Get(path string) *File {\n\treturn defaultResource.Get(path)\n}\n\n// GetWithIndex searches file with `path`, if the file is directory\n// it then does index files searching under this directory.\n//\n// GetWithIndex is usually used for http static file service.\nfunc GetWithIndex(path string, indexFiles []string) *File {\n\treturn defaultResource.GetWithIndex(path, indexFiles)\n}\n\n// GetContent directly returns the content of `path` in default resource object.\nfunc GetContent(path string) []byte {\n\treturn defaultResource.GetContent(path)\n}\n\n// Contains checks whether the `path` exists in the default resource object.\nfunc Contains(path string) bool {\n\treturn defaultResource.Contains(path)\n}\n\n// IsEmpty checks and returns whether the resource manager is empty.\nfunc IsEmpty() bool {\n\treturn defaultResource.tree.IsEmpty()\n}\n\n// ScanDir returns the files under the given path, the parameter `path` should be a folder type.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\n//\n// It scans directory recursively if given parameter `recursive` is true.\nfunc ScanDir(path string, pattern string, recursive ...bool) []*File {\n\treturn defaultResource.ScanDir(path, pattern, recursive...)\n}\n\n// ScanDirFile returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// Note that it returns only files, exclusive of directories.\nfunc ScanDirFile(path string, pattern string, recursive ...bool) []*File {\n\treturn defaultResource.ScanDirFile(path, pattern, recursive...)\n}\n\n// Export exports and saves specified path `src` and all its sub files to specified system path `dst` recursively.\nfunc Export(src, dst string, option ...ExportOption) error {\n\treturn defaultResource.Export(src, dst, option...)\n}\n\n// Dump prints the files of the default resource object.\nfunc Dump() {\n\tdefaultResource.Dump()\n}\n"
  },
  {
    "path": "os/gres/gres_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// File is a file in a zip file.\ntype File struct {\n\tfile     *zip.File\n\treader   *bytes.Reader\n\tresource *Resource\n}\n\n// Name returns the name of the file.\nfunc (f *File) Name() string {\n\treturn f.file.Name\n}\n\n// Open returns a ReadCloser that provides access to the File's contents.\n// Multiple files may be read concurrently.\nfunc (f *File) Open() (io.ReadCloser, error) {\n\treturn f.file.Open()\n}\n\n// Content returns the content of the file.\nfunc (f *File) Content() []byte {\n\treader, err := f.Open()\n\tif err != nil {\n\t\treturn nil\n\t}\n\tdefer reader.Close()\n\tbuffer := bytes.NewBuffer(nil)\n\tif _, err = io.Copy(buffer, reader); err != nil {\n\t\treturn nil\n\t}\n\treturn buffer.Bytes()\n}\n\n// FileInfo returns an os.FileInfo for the FileHeader.\nfunc (f *File) FileInfo() os.FileInfo {\n\treturn f.file.FileInfo()\n}\n\n// Export exports and saves all its sub files to specified system path `dst` recursively.\nfunc (f *File) Export(dst string, option ...ExportOption) error {\n\treturn f.resource.Export(f.Name(), dst, option...)\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\nfunc (f File) MarshalJSON() ([]byte, error) {\n\tinfo := f.FileInfo()\n\treturn json.Marshal(map[string]any{\n\t\t\"name\": f.Name(),\n\t\t\"size\": info.Size(),\n\t\t\"time\": info.ModTime(),\n\t\t\"file\": !info.IsDir(),\n\t})\n}\n"
  },
  {
    "path": "os/gres/gres_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbase64\"\n\t\"github.com/gogf/gf/v2/encoding/gcompress\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nconst (\n\tpackedGoSourceTemplate = `\npackage %s\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"%s\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n`\n)\n\n// Option contains the extra options for Pack functions.\ntype Option struct {\n\tPrefix   string // The file path prefix for each file item in resource manager.\n\tKeepPath bool   // Keep the passed path when packing, usually for relative path.\n}\n\n// Pack packs the path specified by `srcPaths` into bytes.\n// The unnecessary parameter `keyPrefix` indicates the prefix for each file\n// packed into the result bytes.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\n//\n// Deprecated: use PackWithOption instead.\nfunc Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {\n\toption := Option{}\n\tif len(keyPrefix) > 0 && keyPrefix[0] != \"\" {\n\t\toption.Prefix = keyPrefix[0]\n\t}\n\treturn PackWithOption(srcPaths, option)\n}\n\n// PackWithOption packs the path specified by `srcPaths` into bytes.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\nfunc PackWithOption(srcPaths string, option Option) ([]byte, error) {\n\tvar buffer = bytes.NewBuffer(nil)\n\terr := zipPathWriter(srcPaths, buffer, option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Gzip the data bytes to reduce the size.\n\treturn gcompress.Gzip(buffer.Bytes(), 9)\n}\n\n// PackToFile packs the path specified by `srcPaths` to target file `dstPath`.\n// The unnecessary parameter `keyPrefix` indicates the prefix for each file\n// packed into the result bytes.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\n//\n// Deprecated: use PackToFileWithOption instead.\nfunc PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {\n\tdata, err := Pack(srcPaths, keyPrefix...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn gfile.PutBytes(dstPath, data)\n}\n\n// PackToFileWithOption packs the path specified by `srcPaths` to target file `dstPath`.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\nfunc PackToFileWithOption(srcPaths, dstPath string, option Option) error {\n\tdata, err := PackWithOption(srcPaths, option)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn gfile.PutBytes(dstPath, data)\n}\n\n// PackToGoFile packs the path specified by `srcPaths` to target go file `goFilePath`\n// with given package name `pkgName`.\n//\n// The unnecessary parameter `keyPrefix` indicates the prefix for each file\n// packed into the result bytes.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\n//\n// Deprecated: use PackToGoFileWithOption instead.\nfunc PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {\n\tdata, err := Pack(srcPath, keyPrefix...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn gfile.PutContents(\n\t\tgoFilePath,\n\t\tfmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),\n\t)\n}\n\n// PackToGoFileWithOption packs the path specified by `srcPaths` to target go file `goFilePath`\n// with given package name `pkgName`.\n//\n// Note that parameter `srcPaths` supports multiple paths join with ','.\nfunc PackToGoFileWithOption(srcPath, goFilePath, pkgName string, option Option) error {\n\tdata, err := PackWithOption(srcPath, option)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn gfile.PutContents(\n\t\tgoFilePath,\n\t\tfmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),\n\t)\n}\n\n// Unpack unpacks the content specified by `path` to []*File.\nfunc Unpack(path string) ([]*File, error) {\n\trealPath, err := gfile.Search(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn UnpackContent(gfile.GetContents(realPath))\n}\n\n// UnpackContent unpacks the content to []*File.\nfunc UnpackContent(content string) ([]*File, error) {\n\tvar (\n\t\terr  error\n\t\tdata []byte\n\t)\n\tif isHexStr(content) {\n\t\t// It here keeps compatible with old version packing string using hex string.\n\t\t// TODO remove this support in the future.\n\t\tdata, err = gcompress.UnGzip(hexStrToBytes(content))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if isBase64(content) {\n\t\t// New version packing string using base64.\n\t\tb, err := gbase64.DecodeString(content)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata, err = gcompress.UnGzip(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tdata, err = gcompress.UnGzip([]byte(content))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `create zip reader failed`)\n\t\treturn nil, err\n\t}\n\tarray := make([]*File, len(reader.File))\n\tfor i, file := range reader.File {\n\t\tarray[i] = &File{file: file}\n\t}\n\treturn array, nil\n}\n\n// isBase64 checks and returns whether given content `s` is base64 string.\n// It returns true if `s` is base64 string, or false if not.\nfunc isBase64(s string) bool {\n\tvar r bool\n\tfor i := 0; i < len(s); i++ {\n\t\tr = (s[i] >= '0' && s[i] <= '9') ||\n\t\t\t(s[i] >= 'a' && s[i] <= 'z') ||\n\t\t\t(s[i] >= 'A' && s[i] <= 'Z') ||\n\t\t\t(s[i] == '+' || s[i] == '-') ||\n\t\t\t(s[i] == '_' || s[i] == '/') || s[i] == '='\n\t\tif !r {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// isHexStr checks and returns whether given content `s` is hex string.\n// It returns true if `s` is hex string, or false if not.\nfunc isHexStr(s string) bool {\n\tvar r bool\n\tfor i := 0; i < len(s); i++ {\n\t\tr = (s[i] >= '0' && s[i] <= '9') ||\n\t\t\t(s[i] >= 'a' && s[i] <= 'f') ||\n\t\t\t(s[i] >= 'A' && s[i] <= 'F')\n\t\tif !r {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// hexStrToBytes converts hex string content to []byte.\nfunc hexStrToBytes(s string) []byte {\n\tsrc := []byte(s)\n\tdst := make([]byte, hex.DecodedLen(len(src)))\n\t_, _ = hex.Decode(dst, src)\n\treturn dst\n}\n"
  },
  {
    "path": "os/gres/gres_func_zip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport (\n\t\"archive/zip\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/fileinfo\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// ZipPathWriter compresses `paths` to `writer` using zip compressing algorithm.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\n//\n// Note that the parameter `paths` can be either a directory or a file, which\n// supports multiple paths join with ','.\nfunc zipPathWriter(paths string, writer io.Writer, option ...Option) error {\n\tzipWriter := zip.NewWriter(writer)\n\tdefer zipWriter.Close()\n\tfor _, path := range strings.Split(paths, \",\") {\n\t\tpath = strings.TrimSpace(path)\n\t\tif err := doZipPathWriter(path, zipWriter, option...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// doZipPathWriter compresses the file of given `path` and writes the content to `zipWriter`.\n// The parameter `exclude` specifies the exclusive file path that is not compressed to `zipWriter`,\n// commonly the destination zip file path.\n// The unnecessary parameter `prefix` indicates the path prefix for zip file.\nfunc doZipPathWriter(srcPath string, zipWriter *zip.Writer, option ...Option) error {\n\tvar (\n\t\terr          error\n\t\tfiles        []string\n\t\tusedOption   Option\n\t\tabsolutePath string\n\t)\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\tabsolutePath, err = gfile.Search(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif gfile.IsDir(absolutePath) {\n\t\tfiles, err = gfile.ScanDir(absolutePath, \"*\", true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tfiles = []string{absolutePath}\n\t}\n\theaderPrefix := usedOption.Prefix\n\tif headerPrefix != \"/\" {\n\t\theaderPrefix = strings.TrimRight(headerPrefix, `\\/`)\n\t}\n\tif headerPrefix != \"\" && gfile.IsDir(absolutePath) {\n\t\theaderPrefix += \"/\"\n\t}\n\n\tif headerPrefix == \"\" {\n\t\tif usedOption.KeepPath {\n\t\t\t// It keeps the path from file system to zip info in resource manager.\n\t\t\t// Usually for relative path, it makes little sense for absolute path.\n\t\t\theaderPrefix = srcPath\n\t\t} else {\n\t\t\theaderPrefix = gfile.Basename(absolutePath)\n\t\t}\n\t}\n\theaderPrefix = strings.ReplaceAll(headerPrefix, `//`, `/`)\n\tfor _, file := range files {\n\t\t// It here calculates the file name prefix, especially packing the directory.\n\t\t// Eg:\n\t\t// path: dir1\n\t\t// file: dir1/dir2/file\n\t\t// file[len(absolutePath):] => /dir2/file\n\t\t// gfile.Dir(subFilePath)   => /dir2\n\t\tvar subFilePath string\n\t\t// Normal handling: remove the `absolutePath`(source directory path) for file.\n\t\tsubFilePath = file[len(absolutePath):]\n\t\tif subFilePath != \"\" {\n\t\t\tsubFilePath = gfile.Dir(subFilePath)\n\t\t}\n\t\tif err = zipFile(file, headerPrefix+subFilePath, zipWriter); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Add all directories to zip archive.\n\tif headerPrefix != \"\" {\n\t\tvar (\n\t\t\tname    string\n\t\t\ttmpPath = headerPrefix\n\t\t)\n\t\tfor {\n\t\t\tname = strings.ReplaceAll(gfile.Basename(tmpPath), `\\`, `/`)\n\t\t\terr = zipFileVirtual(fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), tmpPath, zipWriter)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif tmpPath == `/` || !strings.Contains(tmpPath, `/`) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttmpPath = gfile.Dir(tmpPath)\n\t\t}\n\t}\n\treturn nil\n}\n\n// zipFile compresses the file of given `path` and writes the content to `zw`.\n// The parameter `prefix` indicates the path prefix for zip file.\nfunc zipFile(path string, prefix string, zw *zip.Writer) error {\n\tprefix = strings.ReplaceAll(prefix, `//`, `/`)\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn gerror.Wrapf(err, `os.Open failed for path \"%s\"`, path)\n\t}\n\tdefer file.Close()\n\n\tinfo, err := file.Stat()\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `read file stat failed for path \"%s\"`, path)\n\t\treturn err\n\t}\n\n\theader, err := createFileHeader(info, prefix)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !info.IsDir() {\n\t\t// Default compression level.\n\t\theader.Method = zip.Deflate\n\t}\n\t// Zip header containing the info of a zip file.\n\twriter, err := zw.CreateHeader(header)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `create zip header failed for %#v`, header)\n\t\treturn err\n\t}\n\tif !info.IsDir() {\n\t\tif _, err = io.Copy(writer, file); err != nil {\n\t\t\terr = gerror.Wrapf(err, `io.Copy failed for file \"%s\"`, path)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {\n\theader, err := createFileHeader(info, \"\")\n\tif err != nil {\n\t\treturn err\n\t}\n\theader.Name = path\n\tif _, err = zw.CreateHeader(header); err != nil {\n\t\terr = gerror.Wrapf(err, `create zip header failed for %#v`, header)\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {\n\theader, err := zip.FileInfoHeader(info)\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `create file header failed for name \"%s\"`, info.Name())\n\t\treturn nil, err\n\t}\n\tif len(prefix) > 0 {\n\t\theader.Name = prefix + `/` + header.Name\n\t\theader.Name = strings.ReplaceAll(header.Name, `\\`, `/`)\n\t\theader.Name, _ = gregex.ReplaceString(`/{2,}`, `/`, header.Name)\n\t}\n\treturn header, nil\n}\n"
  },
  {
    "path": "os/gres/gres_http_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Close implements interface of http.File.\nfunc (f *File) Close() error {\n\treturn nil\n}\n\n// Readdir implements Readdir interface of http.File.\nfunc (f *File) Readdir(count int) ([]os.FileInfo, error) {\n\tfiles := f.resource.ScanDir(f.Name(), \"*\", false)\n\tif len(files) > 0 {\n\t\tif count <= 0 || count > len(files) {\n\t\t\tcount = len(files)\n\t\t}\n\t\tinfos := make([]os.FileInfo, count)\n\t\tfor k, v := range files {\n\t\t\tinfos[k] = v.FileInfo()\n\t\t}\n\t\treturn infos, nil\n\t}\n\treturn nil, nil\n}\n\n// Stat implements Stat interface of http.File.\nfunc (f *File) Stat() (os.FileInfo, error) {\n\treturn f.FileInfo(), nil\n}\n\n// Read implements the io.Reader interface.\nfunc (f *File) Read(b []byte) (n int, err error) {\n\treader, err := f.getReader()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif n, err = reader.Read(b); err != nil {\n\t\terr = gerror.Wrapf(err, `read content failed`)\n\t}\n\treturn\n}\n\n// Seek implements the io.Seeker interface.\nfunc (f *File) Seek(offset int64, whence int) (n int64, err error) {\n\treader, err := f.getReader()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif n, err = reader.Seek(offset, whence); err != nil {\n\t\terr = gerror.Wrapf(err, `seek failed for offset %d, whence %d`, offset, whence)\n\t}\n\treturn\n}\n\nfunc (f *File) getReader() (*bytes.Reader, error) {\n\tif f.reader == nil {\n\t\tf.reader = bytes.NewReader(f.Content())\n\t}\n\treturn f.reader, nil\n}\n"
  },
  {
    "path": "os/gres/gres_instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport \"github.com/gogf/gf/v2/container/gmap\"\n\nconst (\n\t// DefaultName default group name for instance usage.\n\tDefaultName = \"default\"\n)\n\nvar (\n\t// checker checks whether the value is nil.\n\tchecker = func(v *Resource) bool { return v == nil }\n\t// Instances map.\n\tinstances = gmap.NewKVMapWithChecker[string, *Resource](checker, true)\n)\n\n// Instance returns an instance of Resource.\n// The parameter `name` is the name for the instance.\nfunc Instance(name ...string) *Resource {\n\tkey := DefaultName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tkey = name[0]\n\t}\n\treturn instances.GetOrSetFuncLock(key, New)\n}\n"
  },
  {
    "path": "os/gres/gres_resource.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gtree\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Resource is the resource manager for the file system.\ntype Resource struct {\n\ttree *gtree.BTree\n}\n\nconst (\n\tdefaultTreeM = 100\n)\n\n// New creates and returns a new resource object.\nfunc New() *Resource {\n\treturn &Resource{\n\t\ttree: gtree.NewBTree(defaultTreeM, func(v1, v2 any) int {\n\t\t\treturn strings.Compare(v1.(string), v2.(string))\n\t\t}),\n\t}\n}\n\n// Add unpacks and adds the `content` into current resource object.\n// The unnecessary parameter `prefix` indicates the prefix\n// for each file storing into current resource object.\nfunc (r *Resource) Add(content string, prefix ...string) error {\n\tfiles, err := UnpackContent(content)\n\tif err != nil {\n\t\tintlog.Printf(context.TODO(), \"Add resource files failed: %v\", err)\n\t\treturn err\n\t}\n\tnamePrefix := \"\"\n\tif len(prefix) > 0 {\n\t\tnamePrefix = prefix[0]\n\t}\n\tfor i := 0; i < len(files); i++ {\n\t\tfiles[i].resource = r\n\t\tr.tree.Set(namePrefix+files[i].file.Name, files[i])\n\t}\n\tintlog.Printf(context.TODO(), \"Add %d files to resource manager\", r.tree.Size())\n\treturn nil\n}\n\n// Load loads, unpacks and adds the data from `path` into current resource object.\n// The unnecessary parameter `prefix` indicates the prefix\n// for each file storing into current resource object.\nfunc (r *Resource) Load(path string, prefix ...string) error {\n\trealPath, err := gfile.Search(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn r.Add(gfile.GetContents(realPath), prefix...)\n}\n\n// Get returns the file with given path.\nfunc (r *Resource) Get(path string) *File {\n\tif path == \"\" {\n\t\treturn nil\n\t}\n\tpath = strings.ReplaceAll(path, \"\\\\\", \"/\")\n\tpath = strings.ReplaceAll(path, \"//\", \"/\")\n\tif path != \"/\" {\n\t\tfor path[len(path)-1] == '/' {\n\t\t\tpath = path[:len(path)-1]\n\t\t}\n\t}\n\tresult := r.tree.Get(path)\n\tif result != nil {\n\t\treturn result.(*File)\n\t}\n\treturn nil\n}\n\n// GetWithIndex searches file with `path`, if the file is directory\n// it then does index files searching under this directory.\n//\n// GetWithIndex is usually used for http static file service.\nfunc (r *Resource) GetWithIndex(path string, indexFiles []string) *File {\n\t// Necessary for double char '/' replacement in prefix.\n\tpath = strings.ReplaceAll(path, \"\\\\\", \"/\")\n\tpath = strings.ReplaceAll(path, \"//\", \"/\")\n\tif path != \"/\" {\n\t\tfor path[len(path)-1] == '/' {\n\t\t\tpath = path[:len(path)-1]\n\t\t}\n\t}\n\tif file := r.Get(path); file != nil {\n\t\tif len(indexFiles) > 0 && file.FileInfo().IsDir() {\n\t\t\tvar f *File\n\t\t\tfor _, name := range indexFiles {\n\t\t\t\tif f = r.Get(path + \"/\" + name); f != nil {\n\t\t\t\t\treturn f\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn file\n\t}\n\treturn nil\n}\n\n// GetContent directly returns the content of `path`.\nfunc (r *Resource) GetContent(path string) []byte {\n\tfile := r.Get(path)\n\tif file != nil {\n\t\treturn file.Content()\n\t}\n\treturn nil\n}\n\n// Contains checks whether the `path` exists in current resource object.\nfunc (r *Resource) Contains(path string) bool {\n\treturn r.Get(path) != nil\n}\n\n// IsEmpty checks and returns whether the resource manager is empty.\nfunc (r *Resource) IsEmpty() bool {\n\treturn r.tree.IsEmpty()\n}\n\n// ScanDir returns the files under the given path, the parameter `path` should be a folder type.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\n//\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// Note that the returned files does not contain given parameter `path`.\nfunc (r *Resource) ScanDir(path string, pattern string, recursive ...bool) []*File {\n\tisRecursive := false\n\tif len(recursive) > 0 {\n\t\tisRecursive = recursive[0]\n\t}\n\treturn r.doScanDir(path, pattern, isRecursive, false)\n}\n\n// ScanDirFile returns all sub-files with absolute paths of given `path`,\n// It scans directory recursively if given parameter `recursive` is true.\n//\n// Note that it returns only files, exclusive of directories.\nfunc (r *Resource) ScanDirFile(path string, pattern string, recursive ...bool) []*File {\n\tisRecursive := false\n\tif len(recursive) > 0 {\n\t\tisRecursive = recursive[0]\n\t}\n\treturn r.doScanDir(path, pattern, isRecursive, true)\n}\n\n// doScanDir is an internal method which scans directory\n// and returns the absolute path list of files that are not sorted.\n//\n// The pattern parameter `pattern` supports multiple file name patterns,\n// using the ',' symbol to separate multiple patterns.\n//\n// It scans directory recursively if given parameter `recursive` is true.\nfunc (r *Resource) doScanDir(path string, pattern string, recursive bool, onlyFile bool) []*File {\n\tpath = strings.ReplaceAll(path, \"\\\\\", \"/\")\n\tpath = strings.ReplaceAll(path, \"//\", \"/\")\n\tif path != \"/\" {\n\t\tfor path[len(path)-1] == '/' {\n\t\t\tpath = path[:len(path)-1]\n\t\t}\n\t}\n\tvar (\n\t\tname     = \"\"\n\t\tfiles    = make([]*File, 0)\n\t\tlength   = len(path)\n\t\tpatterns = strings.Split(pattern, \",\")\n\t)\n\tfor i := 0; i < len(patterns); i++ {\n\t\tpatterns[i] = strings.TrimSpace(patterns[i])\n\t}\n\t// Used for type checking for first entry.\n\tfirst := true\n\tr.tree.IteratorFrom(path, true, func(key, value any) bool {\n\t\tif first {\n\t\t\tif !value.(*File).FileInfo().IsDir() {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfirst = false\n\t\t}\n\t\tif onlyFile && value.(*File).FileInfo().IsDir() {\n\t\t\treturn true\n\t\t}\n\t\tname = key.(string)\n\t\tif len(name) <= length {\n\t\t\treturn true\n\t\t}\n\t\tif path != name[:length] {\n\t\t\treturn false\n\t\t}\n\t\t// To avoid of, eg: /i18n and /i18n-dir\n\t\tif !first && name[length] != '/' {\n\t\t\treturn true\n\t\t}\n\t\tif !recursive {\n\t\t\tif strings.IndexByte(name[length+1:], '/') != -1 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\tfor _, p := range patterns {\n\t\t\tif match, err := filepath.Match(p, gfile.Basename(name)); err == nil && match {\n\t\t\t\tfiles = append(files, value.(*File))\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\treturn files\n}\n\n// ExportOption is the option for function Export.\ntype ExportOption struct {\n\tRemovePrefix string // Remove the prefix of file name from resource.\n}\n\n// Export exports and saves specified path `srcPath` and all its sub files to specified system path `dstPath` recursively.\nfunc (r *Resource) Export(src, dst string, option ...ExportOption) error {\n\tvar (\n\t\terr          error\n\t\tname         string\n\t\tpath         string\n\t\texportOption ExportOption\n\t\tfiles        []*File\n\t)\n\n\tif r.Get(src).FileInfo().IsDir() {\n\t\tfiles = r.doScanDir(src, \"*\", true, false)\n\t} else {\n\t\tfiles = append(files, r.Get(src))\n\t}\n\n\tif len(option) > 0 {\n\t\texportOption = option[0]\n\t}\n\tfor _, file := range files {\n\t\tname = file.Name()\n\t\tif exportOption.RemovePrefix != \"\" {\n\t\t\tname = gstr.TrimLeftStr(name, exportOption.RemovePrefix)\n\t\t}\n\t\tname = gstr.Trim(name, `\\/`)\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tpath = gfile.Join(dst, name)\n\t\tif file.FileInfo().IsDir() {\n\t\t\terr = gfile.Mkdir(path)\n\t\t} else {\n\t\t\terr = gfile.PutBytes(path, file.Content())\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Dump prints the files of current resource object.\nfunc (r *Resource) Dump() {\n\tvar info os.FileInfo\n\tr.tree.Iterator(func(key, value any) bool {\n\t\tinfo = value.(*File).FileInfo()\n\t\tfmt.Printf(\n\t\t\t\"%v %8s %s\\n\",\n\t\t\tgtime.New(info.ModTime()).ISO8601(),\n\t\t\tgfile.FormatSize(info.Size()),\n\t\t\tkey,\n\t\t)\n\t\treturn true\n\t})\n\tfmt.Printf(\"TOTAL FILES: %d\\n\", r.tree.Size())\n}\n"
  },
  {
    "path": "os/gres/gres_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gres_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t_ \"github.com/gogf/gf/v2/os/gres/testdata/data\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_PackFolderToGoFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath    = gtest.DataPath(\"files\")\n\t\t\tgoFilePath = gfile.Temp(gtime.TimestampNanoStr(), \"testdata.go\")\n\t\t\tpkgName    = \"testdata\"\n\t\t\terr        = gres.PackToGoFile(srcPath, goFilePath, pkgName)\n\t\t)\n\t\tt.AssertNil(err)\n\t\t_ = gfile.Remove(goFilePath)\n\t})\n}\n\nfunc Test_PackMultiFilesToGoFile(t *testing.T) {\n\tgres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath    = gtest.DataPath(\"files\")\n\t\t\tgoFilePath = gfile.Temp(gtime.TimestampNanoStr(), \"data.go\")\n\t\t\tpkgName    = \"data\"\n\t\t\tarray, err = gfile.ScanDir(srcPath, \"*\", false)\n\t\t)\n\t\tt.AssertNil(err)\n\t\terr = gres.PackToGoFile(strings.Join(array, \",\"), goFilePath, pkgName)\n\t\tt.AssertNil(err)\n\t\tdefer gfile.Remove(goFilePath)\n\n\t\tt.AssertNil(gfile.CopyFile(goFilePath, gtest.DataPath(\"data/data.go\")))\n\t})\n}\n\nfunc Test_Pack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath   = gtest.DataPath(\"files\")\n\t\t\tdata, err = gres.Pack(srcPath)\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\tr := gres.New()\n\t\terr = r.Add(string(data))\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Contains(\"files/\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath   = gtest.DataPath(\"files\")\n\t\t\tdata, err = gres.Pack(srcPath, \"/\")\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\tr := gres.New()\n\t\terr = r.Add(string(data))\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Contains(\"/root/\"), true)\n\t})\n}\n\nfunc Test_PackToFile(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath = gtest.DataPath(\"files\")\n\t\t\tdstPath = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr     = gres.PackToFile(srcPath, dstPath)\n\t\t)\n\t\tt.AssertNil(err)\n\n\t\tdefer gfile.Remove(dstPath)\n\n\t\tr := gres.New()\n\t\terr = r.Load(dstPath)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Contains(\"files\"), true)\n\t})\n}\n\nfunc Test_PackWithPrefix1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath    = gtest.DataPath(\"files\")\n\t\t\tgoFilePath = gfile.Temp(gtime.TimestampNanoStr(), \"testdata.go\")\n\t\t\tpkgName    = \"testdata\"\n\t\t\terr        = gres.PackToGoFile(srcPath, goFilePath, pkgName, \"www/gf-site/test\")\n\t\t)\n\t\tt.AssertNil(err)\n\t\t_ = gfile.Remove(goFilePath)\n\t})\n}\n\nfunc Test_PackWithPrefix2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath    = gtest.DataPath(\"files\")\n\t\t\tgoFilePath = gfile.Temp(gtime.TimestampNanoStr(), \"testdata.go\")\n\t\t\tpkgName    = \"testdata\"\n\t\t\terr        = gres.PackToGoFile(srcPath, goFilePath, pkgName, \"/var/www/gf-site/test\")\n\t\t)\n\t\tt.AssertNil(err)\n\t\t_ = gfile.Remove(goFilePath)\n\t})\n}\n\nfunc Test_Unpack(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrcPath    = gtest.DataPath(\"testdata.txt\")\n\t\t\tfiles, err = gres.Unpack(srcPath)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 63)\n\t})\n}\n\nfunc Test_Basic(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gres.Get(\"none\"), nil)\n\t\tt.Assert(gres.Contains(\"none\"), false)\n\t\tt.Assert(gres.Contains(\"dir1\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir1/test1\"\n\t\tfile := gres.Get(path)\n\t\tt.AssertNE(file, nil)\n\t\tt.Assert(file.Name(), path)\n\n\t\tinfo := file.FileInfo()\n\t\tt.AssertNE(info, nil)\n\t\tt.Assert(info.IsDir(), false)\n\t\tt.Assert(info.Name(), \"test1\")\n\n\t\trc, err := file.Open()\n\t\tt.AssertNil(err)\n\t\tdefer rc.Close()\n\n\t\tb := make([]byte, 5)\n\t\tn, err := rc.Read(b)\n\t\tt.Assert(n, 5)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), \"test1\")\n\n\t\tt.Assert(file.Content(), \"test1 content\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir2\"\n\t\tfile := gres.Get(path)\n\t\tt.AssertNE(file, nil)\n\t\tt.Assert(file.Name(), path)\n\n\t\tinfo := file.FileInfo()\n\t\tt.AssertNE(info, nil)\n\t\tt.Assert(info.IsDir(), true)\n\t\tt.Assert(info.Name(), \"dir2\")\n\n\t\trc, err := file.Open()\n\t\tt.AssertNil(err)\n\t\tdefer rc.Close()\n\n\t\tt.Assert(file.Content(), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir2/test2\"\n\t\tfile := gres.Get(path)\n\t\tt.AssertNE(file, nil)\n\t\tt.Assert(file.Name(), path)\n\t\tt.Assert(file.Content(), \"test2 content\")\n\t})\n}\n\nfunc Test_Get(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNE(gres.Get(\"dir1/test1\"), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfile := gres.GetWithIndex(\"dir1\", g.SliceStr{\"test1\"})\n\t\tt.AssertNE(file, nil)\n\t\tt.Assert(file.Name(), \"dir1/test1\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gres.GetContent(\"dir1\"), \"\")\n\t\tt.Assert(gres.GetContent(\"dir1/test1\"), \"test1 content\")\n\t})\n}\n\nfunc Test_ScanDir(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir1\"\n\t\tfiles := gres.ScanDir(path, \"*\", false)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir1\"\n\t\tfiles := gres.ScanDir(path, \"*\", true)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 3)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir1\"\n\t\tfiles := gres.ScanDir(path, \"*.*\", true)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 1)\n\t\tt.Assert(files[0].Name(), \"dir1/sub/sub-test1.txt\")\n\t\tt.Assert(files[0].Content(), \"sub-test1 content\")\n\t})\n}\n\nfunc Test_ScanDirFile(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir2\"\n\t\tfiles := gres.ScanDirFile(path, \"*\", false)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir2\"\n\t\tfiles := gres.ScanDirFile(path, \"*\", true)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpath := \"dir2\"\n\t\tfiles := gres.ScanDirFile(path, \"*.*\", true)\n\t\tt.AssertNE(files, nil)\n\t\tt.Assert(len(files), 1)\n\t\tt.Assert(files[0].Name(), \"dir2/sub/sub-test2.txt\")\n\t\tt.Assert(files[0].Content(), \"sub-test2 content\")\n\t})\n}\n\nfunc Test_Export(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Export(src, dst)\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 14)\n\n\t\tname := `template-res/index.html`\n\t\tt.Assert(gfile.GetContents(gfile.Join(dst, name)), gres.GetContent(name))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Export(src, dst, gres.ExportOption{\n\t\t\t\tRemovePrefix: `template-res`,\n\t\t\t})\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 13)\n\n\t\tnameInRes := `template-res/index.html`\n\t\tnameInSys := `index.html`\n\t\tt.Assert(gfile.GetContents(gfile.Join(dst, nameInSys)), gres.GetContent(nameInRes))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res/layout1/container.html`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Export(src, dst, gres.ExportOption{\n\t\t\t\tRemovePrefix: `template-res`,\n\t\t\t})\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 2)\n\t})\n}\n\nfunc Test_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gres.IsEmpty(), false)\n\t})\n}\n\nfunc TestFile_Name(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res`\n\t\t)\n\t\tt.Assert(gres.Get(src).Name(), src)\n\t})\n}\n\nfunc TestFile_Export(t *testing.T) {\n\t// gres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Get(src).Export(dst)\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 14)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Get(src).Export(dst, gres.ExportOption{\n\t\t\t\tRemovePrefix: `template-res`,\n\t\t\t})\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 13)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsrc = `template-res/layout1/container.html`\n\t\t\tdst = gfile.Temp(gtime.TimestampNanoStr())\n\t\t\terr = gres.Get(src).Export(dst, gres.ExportOption{\n\t\t\t\tRemovePrefix: `template-res`,\n\t\t\t})\n\t\t)\n\t\tdefer gfile.Remove(dst)\n\t\tt.AssertNil(err)\n\t\tfiles, err := gfile.ScanDir(dst, \"*\", true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(files), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gres/testdata/data/data.go",
    "content": "package data\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/7RaCThU+//+Zl9DlrQhyiBjGCLJUsgy9i1KZTBEjDCytaCUJSmFSttFkbJGXJWuyj7IlrQoCpF9RIT+D66cM2aQ3/33PNd9PI/zvu/n/X7O93vO57xGGFo6HsAEmMAAzskIQP6tAczAzg3v4OSItPPyJLi5omZ+kyK4ubqYm9GDFe3bHQ5IVOghUdqSZUYZ5ka11aXV+g0oFKoRpVOJLNWR1EFatIZJ6eqXSZ5vMzEyMtIuk6yyAPfk5NCNsq9kX8lmo2Xlc+tljGkwCISoY6LtRXlzGjoAfv0ywjAymWnIv7MAADgAAKir5Jmn0tVXygnv9J8KNJ0TuGdOoDRj22lygQB0yT8wgwpkJxc4rcwy/ZjtFAb0L+eK/AsNx+Cbw/DAec5bB4OkY7b/RZlGc2WazZV5/fkF+/nrQC6RCy4Rsgj/lTqTOXUWc+p+BKorLb4ILDB1i64AAJfdb8LajAkwA3snDxmUp5ft9OVN71MOUF9A8i7lg1w+9R+SgPMkyEgRfAhzfSqlX4vUQUrJmGlXVW/Rqdyy4neNBQ8vbV897fFCHCyzHNPYc7iUMUNoVSe5p9tzId/o/sVcvmPo/80xNMwxNGXHTOZV5x8pQLtkx9DTjqHhjs3H1FfNKlmyY+hlOMYKmIGTzDY80t7JA4XDL9M0CALqEM7FxQ2+X7eWa1eWle3JMDcaBDKXwYrZ6jy+OdvxAAA4/4jA283DxZ6MQKIaVa5jnGFuxMIIJbjB5YUgJ1jEA2fs/+qBM/ZfD3yx8zzINTHye79t1L3uS0nEfUEFqWPv8w4wc87KfeIgYSU0fQr+CdmMHzCyaTsyTYz8suzeku4p6waAWYqbOw+68AEAOJbuiIfXMhzhhSP86wj0jPzdE/nSv2xfBG9YLb//jV+mzpwbLsc2im2YrvdPiGbcgB3Gs72Rn9Hx/Hw4O8QN3Leex6sX7Y+VUAq/Q0h1g2UYsmYeyL+eOHu64X9rTWmfOoyMZrzJmlpA78K6O/7Rec4rfjd1wUbW/MW7hALfjDWU+GYsypprGOucOZNYejCT5HyLm2S2Zxkm8c8D+dckH0hzZ2Wml1Yai2GQElXE6ofm6HpZIxPtSkyVYRkRk2sugdSpyzHKyv2cVSaXXfrw81R9GWXT957/jJmuQxt3SK07nsGi9rtETj++SEMAgOGfqpux9H9UJz59t/rPWC8/xikQG6FiSS80K25MVC/agEzc/DOACSJuCU975LVxzV7u4OSCQ+HwC23geeWkcA8TtfEjnOpzd6udN1JNEAAg9Ac0ztil7pGh93c8E0MU6e7sLDvvVJ00LLaCZpaYp7jCUgYAIL4gMSeM2MNrKVvRDCm95BPybeO5CWpCEgCAWPQtYY5y+hakcPPNu9UJakFto5qK4jaFG+puGvYYt6bQ/34cUDFCPZICAEguSMxNTmy25z+/gUL0fE8YG4R9uDQtMrPmbH+ey1Ch39wuVaZWXocFADgt2LXMUKnLaNvfyzr1/P//1rUwFmcsNRYqXUu/iWRfkt1h6g95MDF2FDo61bRbls7r4UWNd4lda7ct/zASACC2tOaZ4pxpWhjtXLWzR9O0r//QKN1VvvU2gY5plq6zuTxiMwBg4x/Rme35D+kW2CWX/0bm4eZGQNl5ei7jeFsFuRzlSfB1wUnNAk3VWmuSPH0ca1dUb6lBVj3QzTGRlpdIzmBgjUm0uPxVtN3+boeV+Kak9uhEPivPBprfW6BEs23XVgAAekHxLLPsTq5YR9wy5HPDAFAubo5uUkfwjr/1u8T6bqs/vK4kCR0dKrw95tUVDSsH4ml+daz0sGupiZxDWamkg6h/U4mHEXfTQ56yqK37zIRPK/Jkbf4ZZVd+NOrO9REPgz7faq9mknUjqaRv8rjqyEhB+s/JjtDMR3J8dDpBAATcZmZwZQWA8/HIpxMACHmq5NMA0I19u/Ybre7jO1OPiqobPr+kAytDu5uVA4b03IGNm/iab6Ue2dJarU48YufVPBG7JsQI//TuHN04IUZguRhM+9P4SbJe4q2VXzjoo8o1es9gOfsFV73euiEkIXjrm4BioaCGv5yNzEOkmNgYEvjpVtXyuQ7ROnJqb+fk4As/f7rw2PHjfxU4/iVXbM5vjcGw3g0L2MgpwUajE9xpiGsZN0smXjopOuomIHcx1PFCpyQ6gqV5ovjvurSHBKELgtdUqyO3iw89O5dMFNzf4sRzRfD8ylPq5thfDFz9J2WGvrGlq+qKfMJqoISDtXEy2CNi4wcV+a5qjHnnflA9+bZzMlJ91PirNi0DV4lwvLtkvNQu3rQ78Slp8SmBwSIXHLm08/JlWYY5ap61yDHE7CbVNrzLoV13cY3GwbWf13K72CQNK4yf/Sr4hD5CTXT0162n20320/pakM5OfNQ4+YLZZ1No8e1Plvn2LL0SXLuTDmgWTq4ej/PI9U/kPaWXmHXksXpdcILNr9U/+wKwv6703/pG+zNTNV+Ipzt9fz098vFQHy1QKxQ9pPyAsf9SAiu7kpj7qMR3iZy7x1Vzza13Htv7Vczo43lDme5hEf/HB0RM/UMKJtb8nERYKKi0hntpZgZruTziOLdD4e7LMzuFI4MQyn0VFaJMPyyvnLr/bbQ/8IDyw/fZ9B2uaTHnAp5sbu4mOg9uV+g5U+fTQxqx24OpcgyL1fvq9wV/9nRHzMErVte/gWaTYRF78VhWxXSuMydiLU8WBG2sL41ttFK9byVtzrvuvb9t/4iX7YWXClfeX2ZSzv9KWiPByHo5R24tXic/+6bgenWlmgDXYAEfppr+o26iONa0by9t8HFlNI1NBKE2ZPyeN10mwY2JL66GsFWcEr6a2y0h8vrJBsk0riL3UxfDzqN1Eew+Sbz1BH2tcGSRJtP1UDOLp2/81u/tlesJauU8qqL1YbeqpF6q2WRlzfk8DTx3oOE5rEhKW03deof7h4h2dgEWviaba8Rz6U1an2moxHzUQr+YcAgernrLzyVOODjEcciolelpBfFxwpeLvzBrdT0CTxqGmQzeZeDfv5XAJ3X0fldHZPB6fZG6L9F4kk6/ePbP7zWvPaNuP4qZWKOp/f1cCMeuh53uqtVj/bz8xpsYOf8uRyCdqtVfPKV37DqSpOdzXofBRfFVrqG3cO2oyeP03k6z7estv5ftx/Zbu3U4W6c+HH4xJFa4KjyfnfHxC9EV6j2qiqetJ/95EXsVgbLryRpevf+NGffAirj15eGWRVdbcJ/MJIcILfeeYF4NBHbJyBz6kh6svskREf7Gey3C+hXiULosXmgXviiuyrlfrZDxjK4Ie8PYhvcco8KHHXYjglvsLBWyhz6YC6ladCTdwinyH7mmqHF3OLZefufG73asiY/Ues40HC7NV1qXpzi0gSbweeYBTEpThXrCKmkPrFBh0NlG9r4L7uvuWGj75tgpNUikB7urNliVWZzdEGv70fjm9k1PxtsjXk1OGDV1C4yjOlUMU+4f9HM8EFod2n242bIrq0X7GuFMeJfcsHqd0XHt72XJfO8J4xdv+iO5uW3KHq6SFBTUrojyp9+dNPBhwlne/7N1sNUz88kjYd7F7xAVft7xN6wcUSckfblF2MISq588YrY9qthfnLLy09mWq9cmtd6VjCdE/azSu1cSclkhSvPMfZZzyIf5H0P6HwqWZDl5bHvYYiNeeSGN582prCwR5Wf+1x//nfP2+0Dwx32E5AJSa1tAGF3qGcujfhb1Ai2yd1ZUx0di1QR+ZB/Jk/d3IX5/p3dC17oyfGC1VlXk1hD6fHpmwW3CJAkPvdgeua6QCZcbjtrNPJG5oVosAh2DObnaxysPvXzayF+H69fn8CcNKip4b4+WP6ob67HaN1A9J5u0e/fuXQO7B0iGD9QyxukMlYhKDfYZmgWmsUwcUW7VYpIDza266wv0ffI6nBUOD75rf7u79p/hn4dxf7Oz9/09jiymNV8RWci3/5pCIxuPab6oYKNAsf7Q1QanlDOleY4nx3KaPl2TV45GSQvdlgmxO9gRk79Xize1+RXmnx+/8Ne4a8NLiw/ZJ6eHFV5/PlyzVp37XQm7oAXBXt6LxbPADGFenH8jxSp+MLw5kj0iXo9ph5s8L0dzp8e+zrR/KmSUiDvxEg4W//xg5VpLj4o3RNHru5n5rWQYelNn4H1I5KK11hdlkc9qrt6Bx4KEMyubiopaj2g9TEp1UCrtrbFOfql3uc1FJ27ic/y1RGXLTzZ9MY4bLbLeNCn2WnP2T4TQcmq5pOQ+iRS+hJbniO8VRDLlCvgM5mUJc2/9nm3//k57+aemm6GhbG9P9NDi0pBWtio/nB7ZvJuIe5mLXZPattfrI5+dSNi1z9vSi2IfsH5LFmrcWHSjuydW7xkqNyguwpAOoy9p8LrgjZngxsY26dMyxzQCTdkjTDvYXmHptp3sOyv7pShUZTRB17ty8+6DkqMrlZ+eKEXvix28NliwO6ODpJ14rUpO+UDvd1mjo40Oo5iLte45NN/y25vH8kbzCLksZ7PidvXkJu4r+RB059nJX70tA2O6/s+T/gpbx26AGLgrfrMzIa9uW9IN0sC59GPeE5d74tpKyi1bM6tr4yLs2yr2WDxJYrzQnS2v3k1A7Hhx8xg918/bryvwkWMmws+Su6+nv9mxJ+nQ084NBjqj9azP72lMBiSdbhA4UHAuVcbOhZHXzzr1vEztidOBBlZ1Zkz9fZeEfXeE9evpcVxUj+N525kdU6UkePztBsR4j79ml2acsJAlD0ENU7/fR0hBumXvS7t3q94m8icPtPfkt9nVlwpts7TYe6nU7213llS9SfR6mVwOtLdQe422nX/xi3sKLMgsROVIVVTayFeHrfxdpI/2jqHViFGOPQYVzJmrJ9TO+ESs0rOOE1bZNPINE0k0CwyOjy1Hu3OGrOYOECrZcr1A43bplxtKp3/eJVg/Zavft4+2W6xBydTjWNVaAZkPz/u2vmNxw62liSsQ5T/o07aCUCza2KRh2C/9frtr2Q+cytch7U2khJiRwkun8ltGiILE9kfPmo61kXT1ijLsRRGcRR+Ovvc/lnmbkDO0S+Ugg0TJQJXQMMGpNZd3dd9N0cdSaaQIY5EhFc7xZo9hmQl2+ie5hbiWtGxieVJU/zZcS1rz66orD66cMtG19orPGnoofWBTtvv9CuR3jNcnUp9sTESFOT7vidW67uM/3CzKhhjv6SPKqlGpPu13xHw96epVk9G3X7Y1HTQcs3aoMmrNTVfOHCfwCzelV2cq3v2gh7iU98op3tVqwjlkyw3XVoH96a+x+3XSNtVrIc6OFWiyv9zTSaR9kY4qz9g3bBVRr9Svubn0yQ4PA/aRlsDhd4XIv1c9CDnmbPNYw/GaN+NEbM8+U3xW/tiqFp0jpqe9Ay6u/8t/pwE+kydVNJzflyBbs0lMpcSz713wqqIgP+NxoWct6+qLBV7exvW6Nr5qsv1S7uYZdC3hoMfZpFO+Sh9UJjI2ywXSbxPOH67p2dJVe13zYioDsq/J9MexCy8tkYjVwTbvS+tOcBWs3fbxo+ANwoCtuxfBRebuqxEFp2wlw0R8VOTHwrHyoHrTX+rCoZNpxxkErpjy+vKin6e9GFEr6m1uZShqSuWOLt4lMZnGzk5jwcGLJ37X/vpGnv8on5vpCf3Ht47GJvtwJTzIzRluKB5scEBdYxCMdl/fIuspgc9nun5C+jVOWmaHcqNl+g/tnAAD1gO3NuxjI6idZGivZ13zqTN191e9ySfJZ/SjMqOxtqM8HB1jgx4xB55m2d4P3d/HmG8WbnL0XaxF5yli7RfRzPOEQYNMbXyOblZ4kJJKx5nn9dWnfjiO7A1v18AIeAlGM1efvmFu0ycdiYslSepUrQ8PyNTlKOgMk8shNkWEs3AqK3IVMdRrtmFwpFv1SYXXe9+v3zxgWGt6KTGHEx9qev0Aekvt5siO3MHbO0SsP6/fjnormn9iEGEQO1zIez9Dy5HBOpDm+H0zgyOk8rxAuYk3n7s/n31Hd6WYa0h4D/ZssC2mgId+B0u3XO8QOnKNZ64YZ8OjYefH6cyXPnhgMCe6bg7HNBSjj9fX5HSDePduDVXW8q32dH5vcLL6BzWfymK8keVbVM+9agq5whqp5snhHqbiljp8IKAVbaMV16iKYXS5kbRhl2qSQEH2+HaiT5pd3x7WyD7bOASm+uzu/tw+lWg9NmTNnbE9zye5fw+Z+24HZLABcJl9oTcfjt9vPnh7nI/UIQLkDVWyqsa1WIiN7pMjOrgIDNCcEc9XW7s+g2Xjc4tol4MXJw1j+hINtYr2RoQnPN8XFu5p1jYeWLjVJycpi8+BZMQgWNiX8uPut7SuwpvhpxQK2D8KIk4Lhhb4+7XrD67T2cuwwb+/9hHR0r/3m5eDILPjs7x0YZZ4m+CdVS8V1icolJ7yutH1bPeP3gnW2YqwPT/MzgEAHi36yWiqomXMXFYDZkDAuR5xwRJw06/tFEwZlDRGWYiVaZuXEjE6qUZi/350NdeuIOo00P6eZz2NEQMiAIANC7648pATumB93bz+/dz4Z6+wIlSgUHZueALWCY/zgNeRkmago19BxJgb6VZVb9EhEjFIk5TUtqwy6WzP4RFW96EhT/asmmrp7M8paQaVmHupc7O6zYzv+hQAADILChKiJsjBzY2wgJqKapTOnBTSCIc7NR1mxUrai4+aqOo4hMPaU9dRrq2vN6NjZkwonU064kWgqmXM/0LdVgAAanlaZv4P15JlTBjwXhnKdsS8VKysMvNzVqDxvVDxo9YsLCws8puvbla8d7R3FK8Z+vc9FpXQ6NE7m+XHOI0zwrq6ourfB11/GWVGv/lCQb3wnbd7pdYdD1kjrzMqHm2UYIKu4InyXBUe7hodRSLprpIlmYRflmbfWdrwepdcV5J9DPbaxZhbB4MaQDJdCn7d8RCMy1DhCbrfhZZXXdwYBQAYW05jo5fR2FQ8Q1PsI7Kembsf97oMVfKSfR38Ay5KvZIF74k5Lknlph3/AxelXkhJqyJiqsT1dWYbs7ZCrKzS2OTV/dS2XaWdbaIO7cE8X24zb7nT1hErdHjuMzvdaAfjVF8aLLhca6hpccU6LefL+aaF8KZ/yFDw0mtoSDYbbiVRv2f6O/rK/5EOTYWObOVsVX3byOnmnzBsZHQLnDQraHho5zRDM1hTls/+Swyc+rl4OowcDxqZ4oHh3Z2HR5bjmoOinLGaHdP/2qm1AlBNXM3J+Qv9wAwabeKDyQmfw6CWuCIHgyaRuGBgUjRggWzUQoWxwAojwnAoVEV5Sj4L0LOTnRZQSjHB1wiaNoKboge5nEqKiRwMGjNigYFlzILB40oLuUEHc2NqhyfLJi3VB9WZS9EL+gDNEMF9OAG5nEo2iRwMGh6C+9A6CwYPIS3dB3l6QJ44ou4DK8wHd3pAJXEEVw8NB8GteAhHoJQ4IgeDBoHgYDwMYLF00dJr84KCwZJEcDnQoA9cTi4cgVKSiBwMGumBg21iBIslhZZe21koGCwTBJcDje3wwuSUwREoZILIsaD5HDgWmgksEvtZqLKVsMqioVjk+R6yfQqSvYGfTW/ngVDK95DjQbM1cDxdZrCE/M7Si8wnw4Plc+CioGkYfpioX/NAKORzyOGg+RU43A0WsHigZqFNiQm2KW1nBZQiMHA10C/+8BPTd/ZyihEYchxo7ASO8wmGQ55xIceBZkk4YThWbIB6ZIUcBpoMgT/kEGEwFGIo5FDQ5AY3DEqTHSwYLFloqZhhS9UPRVrSWsG9kV4JqOc+yGGgYQs4TAwUhjzYMU8NJD8Bh1nJAajnNMhhoEEFuL1BUBgK0YulIw2QIZGnKpZ+T9lwAkqBiaU+9NziBJQCE/A6oPGFVbA6miGXUwhMLKSDBabDmgtQzj6QnV2QaSDc0RswgPnZB3Ik6BSOA4YUKwCozhKX/gDmJAjI53dwAdDR2mqYgERBsOj8biFneWDO8gqBxYZzcGHQuZgITJgNFShqw7l5L46QSZcQ/H6ghkxpOjLv/IIMreCwvhvB0odm5LDQEREcll4YLH3+tfSV6qUMi6a6UtBpEFyhoghY+rSJHBY6+IHD3qEGuxQ/oTMcOCzXJrD0GdJCfq6B+XmDGizZOAguEzqr2QST2bMQHqVxEDk0dC4Dh7beDP5s9LPQRsQG24gqyKAhGxI9w9QfqQAV0MgFwErRqd/+LwAA//+ohVRS+zcAAA==\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "os/gres/testdata/example/boot/data.go",
    "content": "package boot\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"1f8b08000000000002ff0af066661161e060606048cea809604002420c9c0cc9f9796999e9fa104aaf243f37273484958191cbbb3e8e2bba38b5a82cb528964b414141c13125a528b5b818c4b45550b2b2b0b0b050024b04831505e5e79780240a4a9372329395b8b8a2cb3253cb619a5d52d3124b734adc327352418a32f352522bf44a0a7294a0b23999b99925a945c520b315a29554aa957414946a9562b9b8b8b802bcd939b81c64d7b63330308030c23fad68fe6183fb07ec072feffa389066642508cdd6e9a89a05193819208ed787382fa3041a16973cebe33c527372f21541a6859dd19acb06b68c905320a611e1940c2cf152929a5b90935892aa0f0f2bb041a2de50b728a854ebe525e6a6d6821d75255b6e263f0303033f5e477120998bc7598c4c22cc8804831cf42087c1c09246108927f9201b842d7860c1cee070016e1092ab109a4131851cea8228aee06564c0136fc43b221a6e0e564780e2083994518362062303be18c3e70a0e14577c403208c91dac6c1007b3314c666460d06702f100010000ffffc7c852f1d8030000\"); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "os/gres/testdata/example/files/config/config.toml",
    "content": "\n[server]\n    Address    = \":8888\"\n    ServerRoot = \"public\"\n\n[viewer]\n    DefaultFile = \"index.tpl\"\n    Delimiters  =  [\"${\", \"}\"]\n\n\n\n"
  },
  {
    "path": "os/gres/testdata/example/files/public/index.html",
    "content": "Hello!"
  },
  {
    "path": "os/gres/testdata/example/files/template/index.tpl",
    "content": "Hello ${.name}!"
  },
  {
    "path": "os/gres/testdata/files/config-custom/config.toml",
    "content": "viewpath = \"/home/www/templates\"\n[redis]\n    disk  = \"127.0.0.1:6379,4\"\n    cache = \"127.0.0.1:6379,5\""
  },
  {
    "path": "os/gres/testdata/files/config-custom/my.ini",
    "content": "viewpath = \"/home/www/templates\"\n[redis]\n    disk  = \"127.0.0.1:6379,6\"\n    cache = \"127.0.0.1:6379,7\""
  },
  {
    "path": "os/gres/testdata/files/config-res/config.toml",
    "content": "viewpath = \"/home/www/templates\"\n[redis]\n    disk  = \"127.0.0.1:6379,0\"\n    cache = \"127.0.0.1:6379,1\""
  },
  {
    "path": "os/gres/testdata/files/config-res/my.ini",
    "content": "viewpath = \"/home/www/templates\"\n[redis]\n    disk  = \"127.0.0.1:6379,2\"\n    cache = \"127.0.0.1:6379,3\""
  },
  {
    "path": "os/gres/testdata/files/dir1/sub/sub-test1.txt",
    "content": "sub-test1 content"
  },
  {
    "path": "os/gres/testdata/files/dir1/test1",
    "content": "test1 content"
  },
  {
    "path": "os/gres/testdata/files/dir2/sub/sub-test2.txt",
    "content": "sub-test2 content"
  },
  {
    "path": "os/gres/testdata/files/dir2/test2",
    "content": "test2 content"
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/en/hello.toml",
    "content": "\nhello = \"Hello\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/en/world.toml",
    "content": "\nworld = \"World\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/ja/hello.yaml",
    "content": "\nhello: \"こんにちは\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/ja/world.yaml",
    "content": "world: \"世界\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/ru/hello.ini",
    "content": "hello = \"Привет\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/ru/world.ini",
    "content": "world = \"мир\""
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/zh-CN/hello.json",
    "content": "{\n    \"hello\": \"你好\"\n}"
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/zh-CN/world.json",
    "content": "{\n    \"world\": \"世界\"\n}"
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/zh-TW/hello.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <hello>你好</hello>\n</i18n>"
  },
  {
    "path": "os/gres/testdata/files/i18n-dir/zh-TW/world.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <world>世界</world>\n</i18n>"
  },
  {
    "path": "os/gres/testdata/files/i18n-file/en.toml",
    "content": "\nhello = \"Hello\"\nworld = \"World\""
  },
  {
    "path": "os/gres/testdata/files/i18n-file/ja.yaml",
    "content": "\nhello: \"こんにちは\"\nworld: \"世界\""
  },
  {
    "path": "os/gres/testdata/files/i18n-file/ru.ini",
    "content": "hello = \"Привет\"\nworld = \"мир\""
  },
  {
    "path": "os/gres/testdata/files/i18n-file/zh-CN.json",
    "content": "{\n  \"hello\": \"你好\",\n  \"world\": \"世界\"\n}"
  },
  {
    "path": "os/gres/testdata/files/i18n-file/zh-TW.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<i18n>\n    <hello>你好</hello>\n    <world>世界</world>\n</i18n>"
  },
  {
    "path": "os/gres/testdata/files/i18n-res/en.toml",
    "content": "\nhello = \"Hello\"\nworld = \"World\""
  },
  {
    "path": "os/gres/testdata/files/i18n-res/ja.toml",
    "content": "\nhello = \"こんにちは\"\nworld = \"世界\""
  },
  {
    "path": "os/gres/testdata/files/i18n-res/ru.toml",
    "content": "\nhello = \"Привет\"\nworld = \"мир\""
  },
  {
    "path": "os/gres/testdata/files/i18n-res/zh-CN.toml",
    "content": "hello = \"你好\"\nworld = \"世界\""
  },
  {
    "path": "os/gres/testdata/files/i18n-res/zh-TW.toml",
    "content": "hello = \"你好\"\nworld = \"世界\""
  },
  {
    "path": "os/gres/testdata/files/root/css/style.css",
    "content": "* {\n    font-size: 32px;\n    text-align: center;\n}"
  },
  {
    "path": "os/gres/testdata/files/root/index.html",
    "content": "<html>\n\t<head>\n\t\t<link rel=\"stylesheet\" href=\"css/style.css\" type=\"text/css\" />\n\t</head>\n\t<body>\n\t<div><img src=\"image/logo.png\"></div>\n\tThis is the index from gres.\n\t</body>\n</html>"
  },
  {
    "path": "os/gres/testdata/files/template-res/index.html",
    "content": "It's the index template file."
  },
  {
    "path": "os/gres/testdata/files/template-res/layout1/container.html",
    "content": "{{define \"container\"}}\n<h1>CONTAINER</h1>\n{{end}}"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout1/footer.html",
    "content": "{{define \"footer\"}}\n<h1>FOOTER</h1>\n{{end}}"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout1/header.html",
    "content": "{{define \"header\"}}\n    <h1>HEADER</h1>\n{{end}}"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout1/layout.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>GoFrame Layout</title>\n    {{template \"header\"}}\n</head>\n<body>\n    <div class=\"container\">\n    {{template \"container\"}}\n    </div>\n    <div class=\"footer\">\n    {{template \"footer\"}}\n    </div>\n</body>\n</html>"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout2/footer.html",
    "content": "<h1>FOOTER</h1>"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout2/header.html",
    "content": "<h1>HEADER</h1>"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout2/layout.html",
    "content": "{{include \"header.html\" .}}\n{{include .mainTpl .}}\n{{include \"footer.html\" .}}"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout2/main/main1.html",
    "content": "<h1>MAIN1</h1>"
  },
  {
    "path": "os/gres/testdata/files/template-res/layout2/main/main2.html",
    "content": "<h1>MAIN2</h1>"
  },
  {
    "path": "os/gres/testdata/testdata.go",
    "content": "package testdata\n\nimport \"github.com/gogf/gf/v2/os/gres\"\n\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/7SaCTTU6xvH3+xZQpYUIWKQMQyRZCnKMpaxRonGGjHCyNaCUpakFCptF0W61ogkXZV935KUohDZR0Tof8rF/MaMJt1/59TUyfk83/f7Pu9veeaLRlHTcAIGAMBl95toQPCLGawGDk4u9p4IWzesg5OjqQktWNX6JsUKjaJnIPxB8ggOIgTc1ssT5+b6SxIDGLF3gpAESJP+/ZcUzs3V5Se1e7uDlUSlLhyhJVmOzjBFN9SW1eo1IxCIFoR2NbxMW1IbbtYZJqWjVy55vssIjUZrlUvWmIF7cnLIFtk62TrZbKSsfG6TjCEVCgYTdUy0uShvSkUDwPfvP7SaaMi3mQEAHJbVuoGMVldfKSes038q03hR5t5FmdL0Xad/LZOHSOb/zUv0okiTRZHXn12w+7VI4g76f5hotKjPbFHf10B1JWJ9SzuccUGfnZOHzAqOyBoIAOHpZbOC08G3BPLjNxxn74mTkcL54BbtktJrgGvDpWRMtGpqt2hXb1m1sN7CB5e2rwMAsC9biQ1a6WeFRTppcgi16iwHAICFcieRf+ok8r9wEglxEknaSaMl6/WP5Kf+TSeRP51EQp1cStZTzSr9HSedZLZhKXCSWNoaCABu5+SxIIzy7WBfAkHYY/9oRwg4iEP2Li5u0EtVZ4VWdXn53gxT9CiQuQxWzZvm8dnZlvOn4b9fxtvNw8WOqIxELaJC2zDDFM1IT1jmBrsXjLgMRa44Y/4bV5wx/7rii1niSq4R2u/Ntkn3xo+lEfcFFKSOvcmzWs02L73AQcJCEACwfgUl5xyClPxpUKYR2i/L9jX+nrJOAJgvdHOntQs3AID1dz3y8FqBR7ykOP96RHgPWeibfOnvNs+DN66TP/DKL1N70R+XY5vENgIAuFdQbs4fyC1rvn/yM3qenQ9nIfDH/vPA43W/7CHOpYX8DsHV9f/osQqK+tclZ0837ILulO4f91D0nFtZP7bXu6jxjn90nvOqhUNQuIkp/9edRLbqnFmkqs6ZlrXYVJY5i7YxDqBmiatSapvJ3hXYxk8G9a9tPgSHISszvazaUAwFl6ipqn1gimySRRtpVaNqDMqrULmmEnDtxhx0Vu6HrHK57LIHH36sNaP854n1n7PXdWzTDine4xmMagvLZfPjjjQAABisTOOcyX+oUfznGfef2wz5KTb+2AgVc1rBeYlTorrR+kQSl+4IK1Tij7+uYDPWLaUg7LHL3RvyKvDhHkZq00fY1BcPua03XE0AACD428WcMZReckPv73gqBivW2dlbft6pNmlcbBXVfHnOkkpzGQCA+LLluUmU9/Ci5Go2V5pWsoD4mvPMCDEjCQCAUfhOs1j455klcVqXXCFwakFdk7sVxQ8WbWy8aTBg2JlCu/BIo4JGPJQCAEguW3496fIme//zsxai63vCUD/s7aWfUjPrzw7nuYwV+S1e4srVKhoxAACnZQWvhQj+//UjUR1nDLk6ZHqRdjPerjS7x9if4EnG0FHw6I9W3PI7lT28yFWmsA9tt+UfhgMAxJatygWtOteCkMKLK56/P/109x8qpbvKt14n0DDMF+xtr4gQAQBs+s2CJnv/w4LLPb17uLnh/ug96AcAYevpuYKLKs8SCMIT5+tiLzWP+7HyBqPkn3dnrcraLfXwmr91coyk5SWSM+iYYhLNLn8S7ba722MhvjmpOzqR28KzmWrhYifRbtO3FQCAXHYhbFANTq4Yx5XcH9aTwCBc3BzdpI5gHRfW4hLru63pMG9pEjI6VGh7TN0VDQuHqtM86hjpcdcyIzmH8jJJB1H/1lIPNEfrA87yqK37TYROK3JmiXyLsq04GnXn+oSH/pBvrVc73rIFXzo0e1x1YqIw/dtsT2jmQzluGu0gAAJur6ZzZQKA7fHE+xMACHqq5FMB0I95veEztc7jOz+eLlU3fnhBA9aE9rcrB4zpuoODbuLrP5d5ZEtrdjpxip1X84TtmhHD/TO4c3LTjBiO8WIw9TfDgmTdxFtrPrLSRlVoDJ7BsA0LrH25dWNIQvDWVwElgkHNfzmjTUOkGJjpEnho1jZwu45RO7JpbWdj5Q4/f7ro2PHjfxU6/iVXYspjiUIx3Q0L2MQmwUylHdxrYN8xbZJcdemk6KQbv9zFUMcLvZLICMb2mZJHjWkPcIIXBK6p1kZuFx97ei65SuBAhxPnFYHza06pm2K+07EPn5QZ+8ycrqoj/B6jgRAK1rKXwRwRm7ZW5L6qMeWd+1b15Ove2Uj1ScNPWtR07KVC8e6S8VK7uNLuxKekxacEBgtfcGTXysuXZRxnrX/aIUcXswff0NyWQ817cb2G9YYPGzhcDiaNK0yf/SRQQBuhJjr5/daT7UYHqH3N8Gdn3mmcfL7aZ3Noye335vl2jIMS7HuSrHYXza6bjvPI9U/kOqWbmHXksXpjcMLB7+u+DQVgvl8ZvvWZ+lumar4gZ3/6gSZa+OOxIWqgViR6SPlv+uFLCUwsSmLukxJfJHLuHlfNNbXceWzfJzH0u/MGMv3jwv6PrYSN/UMKZ9Z/m4WZKah0hnvtzgzWdHnIem6Hwt0XZ3YKRQbBlIcqK0UZvppfOXX/8+RwoJXygzfZtD2uaTHnAgpE2vurnEe3KwycafQZwE/Y7kXVOIbF6n7y+4g9e7onxvqKxfXPoN1oXNhOPJZJMZ39zIlY85OFQZuaymJbLFTvW0ibcvG+8bcZnvCyufBC4cqbywzK+Z/w6yXomS7nyG3Aaudn3xTgU1eqD3AN5vdhqB8+6iZqz5T2+cVBbFw5VUsrTrALHr/3VZ9RcEvi86shzJWnhK7m9ksIvyzYKJnGXux+6mLYeaQOjMUniasJp6cZDi/ezXA91MTsySs/vn2DcgNBnWxHVTTf7lGV1E01ma2uP5+ngeUINDiHEU7pqm/kc7h/qMrWNsDM10ikXjyX1qjzqYZKzDtN5PMZh+Dxmtc87OI46zHWQ+hOhieVVY8TPl78jtqg4xF40iDMaPQuHc+BrThuqaP3+3oig/n0hBs/RmPx2sPi2d++1L/0jLr9MGZm/W6tL+dCWHc96HVXrZ0a5uIx3EzP9qgCBneqVX/+hNax70iSrs95bToXxbpcA2+hhkmjx+mDvSbb+cy/lB/ADFu69Thbpj4Yfz4mVrQ2PJ+F/vFz0VXqA6qKpy1n/3keexWGsB3IGl934JUJx8iqOL6KcPPiqx32700kx3Ad9wpQdSOBfTIyhz6mB6tvdoSFv/LeALOsgx1Kl8UK7sIWx9U4D6sV0Z/REWZpntr4hnVS6LDDHlhwh625QvbYW1NBVbOepFv2ijxHrilq3B2PbZLfuemLLVPiQ7WBM82Hy/KVePMUxzZSBT7LtEKltFaqJ6yV9sAIFgWdbWEZuuDOe8dMyzfHVqlZIj3YXbXZotzs7MZYm3eGN7dvLpjujqibnUG39vNPI3pVDFLuW/s5WoXWhvYfbjfvy+rQuoY7E94nN67eiD6u9aU8mfsNbvriTX84B8fB8gdrJQUEtCqj/Gn3JI28nXGW9/9gGWzx1HT2SJh3SRus0s87/oaFI+KEpC+HMHNYYm3Bw9U2RxWHS1LWvD/bcfXarGZb6XRC1Lca3XulIZcVonafuc94Dv4g/13I8AOB0iwnj20POg6KV19I43x1KitLWPmp//XHj3JefxkJfrcfl1yI7+wKCKNJPWN+1M+sib9D9s6q2vhIjBr/1+wjefL+LlVf2nRP6FhWh4+s06yJ3BpCm0+7WmCbEF7CQzd2QK4vZMblhqNWO2dkbqgmI3/PaE6u1vHqQy+etPA02g/rsfrjRxUVvLdHyx/VifVY5xuonpON37Nnz66RPSN4g7/VMqZpDJSqlJrtMnYXGscysEa51YpJjrR36vAV6vnk9TgrHB5t6369p+Gf8W+H7R+xsAw9moaXUJuuiiziPnBNoYWZ0zhfVKCFv0Rv7GqzU8qZsjzHk1M5re+vyStHI6QFb8uE2Fr3xOTv0+RKba9D/fP1O/YaR0N4Wckhu+T0sKLrz8brN6hztJWyCJjh7OS9GD0LTWCmJfk3UiziR8PbI1ki4nUZdrjJc7G293rs7037p1JGqWonVsLB7J+vTOwbaBHxBghaPTcTvzV0Y68a9b0PCV+01PyoLPxBzdU78FiQUGZ1a3Fx5xHNB0mpDkplg/WWyS90L3e5aMfNfIi/lqhs/v7gUIzjJrOsV62Kg5ZswzMh1GyaLim5BZFCl5DyrPGDAnCGXH6f0bwsIY6tX7Lt3tzprnjfejM0lPn1iQFq+zS4hY3KV6eHB9tm4l7kYtandu3zesdtKxx27cO29OLYv5k+Jwu2bCq+0T8Qq/sUkRsUF2FAg9KT1H9Z+MpEYFNLl/RpmWMagcYsEcY9zHUYmm0nh87KfiwOVZlM0PGuFtljLTm5RvnJiTLk/tjRa6OFezJ68FqJ12rklK0Gv8iij7Y4TKIuNrjnUH3O726fypvMw+Uyns2K2zWQm7i/9G3Qnacnvw92jEzp+D9L+iuMl0UfNnJX/GZvQl7jtqQb+JFz6ce8Zy4PxHWVVph3ZtY2xEXYdVXuNStIor/Qny2v3o+D7Xh+8xgt+7fbLyuxkVNGQk+T+6+nv9qxN+nQk96N+tqTTUzP7mnMBiSdbua3KjyXKmPrQs/lZ5l6XqbhxOlAfYtGE4bhoUtCvjvChnV1WS+qx3G+7s2OqVESOP56I2x6wH933+44IUFzTpwaqumAj6CCdMe+F7Zta18n8iSPdA/kd9k2lQluMzfbd6nM73V/llSTUTSfTC4r0luwu17L1r/k+T0FRngWrHqiJipt4pPDVp4+/Ds7x9Ba2CTrXv3K1ZnrZtTO+ESs1bWME1LZPPEZFVllEhgcH1uBdGcLWccRIFi65Xqhxu2yjzeUTn+7i7N8wty0fz91v1izkrHHsZoN/DJvnw1tbWN0s99AFVcoymPt07UKVyLa0qphMCz9Zrtr+Vd7lU9jWpvxCTETRZdO5XdMVAlUdT982nqsC6+jW5xhJwpjK3579I3/sczbuJyxXSrWdBKlIzWC4zinzlyudUM3RR9LpeEjDIXHVNim2z3GZWZYaAtyi+w70rKrKpKihrfZd6S1v6y58veVU0Y6ll7xWWMPpK02Z7vfr4R/QXm9xw/JxkRUmmLzCix4+49/dTMrH6O/pwcrr0Wk+nTfEfP1pGlSTUbeftHVam0wZelQg+7MTVfOnMbxCLWm12Yq3n2rC7uUV+cU72ox4xyy5YZrJ/+B9JeYA9ppm5s0YWenCnezvNjbW0X9PB1RkbF/3CKiSWl4t0hZwQ4PfZaJjsDxtiL4o7V/hxxzPvhYw/GaN/1M7MB+Y2xW/tTaDu0jxqe9Ay7y/eW/Ux+byZkqGs7ji5Ot3yymUuo51Ba8tjjIz3Ba8GkHb1MJ/4vb9oOuLXWtNh8r3DyDriVYe5xNOuWr9FZlJkNELpB2m1D+eP3Alr6G67svptLBh1qNvx678MIcDlsXfPBNWeMJ9sIN2969E7iBG7Fx98K5yNytm1BwylYySMRGRb4rmqoIajL+ri4UOpt2nI7/ijGXLxfyWdrzCbXiwfZOuuLWVI7okl0Ss2ksLFRmrFzYqi9an17J8xzldjM+off41tHYZB/2hL9zc8abS0abHRDX6ASi3fk6ZD0lsPkM109Iv7SXltmh3GKe/lUrJ0CfyerWxv3MOLWTdN1NTOvf96bu+aQ7W5B8Ri8qMxpjM8nJ2jM16hFj9STL5n7ogSH6fJNwo6NtsWa9p6oaPopmnseN6mdqYXN0ssKDlFR6zjxrqj311XFiX3i3BorfSyB6de3pG6YHh6Qj7WPxkto1fOEBmTqshb1hcjlVrRHhjGzKiuzFdE27u1D2+FtNSUXXB9/wiYwYNBhfSsxhw4YaX7dCbmkQiezJHb29Q9jyA992xGvR/BOjMP3Y8SKu+xmajnSWgVTH75voH8FX5AXKzbz60P/hbBvNlRL2MaG9mLPBNqhCTtodjP1yg2PIyPWeuWJszQ/HnR+nr7701gOFOtF3czymuQR5vKk+px/Eu/drqDJVbLWj8XtlL6tnvfuJLMobXrFF9Vxda8gVpkg1T1b3MBW31HGrgE7kQc24FlUUvcuNpI27VJP4C7Ont1f5pNkO7WWKHLKJg6Fqz+4Zzh1SidZlhtffmdr7bJZjYS49dDsggxmAyyyUvcHOvf9g7ex9pA7hCN5gJWvqXUsEmWneOyKDi8EI1RnxfLUNfBmMm56ZRbtYX5w1iBlKNNAs3hcRnvBsf1i4p0nXdGDRVp+cpCxuBzyaTqBoKOXr3c9pfUU3w08pFLK8E4CdFggt9Pfr1hvl1d5Ht9F/uOFhlbn/4GcvB4HVjk/z0oUY4w8G76x5ocCXoFB2yutG39M9XwdnmObXhRn4anIOAPCQwvdcnL3rERcM7s9eDuchpAwalTREmImVa5mWVaG0U9Fi/369bKpVWaXdTL0wy3oSIwaEAQAbl9XNvbSkC8bXzQsnswL9ImRhCFs3LA7jhLX3gK4lJU1fW6+yCmWK1qmp3aJdVYWCG6WkdmWVS2d7jk8wuY+NebJk1ddKZ39ISdOvRt1LXZzVidC3DSkAAGSWlSREXpKDmxtuGT2VtQjtRTH4CVZ3ckpMSpS0fj2iWkbJIXuMHXklFVp6unNK5oaE0tn4I144smqm/C80bgUAIFaqZu4TqibLEDfivSaU+YhpmVh5deaHrEDDe6HiRy0ZGRkZ5UWuiijeOzo4id0d+ugeo0po9OQdEfkpNsOMsL6+qKY3QddfRJnQilwobBK683qfFO/xkPXy2pPi0egEI2QlZ5Tn2vBw1+goPF5nrSzeKPyyNMvOsuaXu+T6kuxiMNcuxtyyDmoGyTQpWN7jISiXsaITNAtLrai5uCkKADC1shZHrqDFyfqGJNlPRL2zeDr3uYxVcxF9+fhb1Uj1TBa0NxarSSq37vijaqR6IiWtpgpVI66nPd+iDZVi5dWGRnX3U7t2lfV2iTp0B3N+vL16y52unljBw4vBAZrJHvofHaq/7LbxklfjinFayZf3ossTf/4hQ8JRr7Ex2WyooVV6Az+/xl/zxwWRZAoS7aCNqm8XcUEAEqw8jAkL0s4X/MlLUInBLHVnFRUnNfmM3fywc2Dnj08yiTvyCA4IQp0IsTRxN0+a844w0SawQAIgMTCCNIlkSoyYShhA2wChKq4ClGTjiIGEYTEeCPA9EZAifYTZLg4ILpgKLJs3W24nGCE7IUINSCfDyAPWQAAOEABRngm6HsLsFh9kPfeXQMgkw4iRhKEtNgiSiwaQj4BR7o8bIQa5An8yIIBl/SFMZEH9+bIEQibvRYwkjGJB/bGmBeSDXZT782gBQ5TiWgSQym0tAqYgAKIUF3kV7BCIKh1YNsUFNYUwagX1+SwpDqkUFzGSMFYFRQ6SRJJIbFG+WlN6sGw6CyqNMDYFlXaDFIdUOosYSRiQgiLZGABl6SvKV+u7FAnJWUGlEYageCHSikhxSOSsiImEaScoUXo1oChKtdxaOSFrvbqUSJyZIrqkEiSZoDfGj2RQpDJTxFTCpBKUuo8RUJyJonzZdSSpkMwTVCBhtogfIpCXCVCaeSKGEqaBoNCn5KBLQ0rLLZoVsmgbZrBMrAgqjTBlsQ4iLXkpZUmMg5hGGOKB0rhYwC9zQ8Q0wmQON4R2mQSNKAZEDCPM2UAfyVjWAEqiPcRAwhzMegjwHGkgUVhnuZ1YC+Eps4LlsjTEIML4ChR0BwoiDsssUUSQSIGCBNjActkXYhBh8IMLAoqGgkjEWShn0bGDXyRVKH/48F5gEYVQKH04y4MAiEIo0BURhkGgz/YzSyAkQijLaWKDaApcC5bLkxDd7ghmq9D2LiOBWZonIeYRzjSh+1YmAH4xn6Xc9tuCgPxMFCqIcFgJXWDXEsjviuKGiDLfBH498ISKI5w0ikDPMFkYuYHnkldegtmhEIS9TQj8zuRyyW2OYAwIBT8jDyY1VCIGEw7doGC0MPidmSLle6a0Gfx6ggdVSThfg6oMIQujyFfCURoUPE4eTImvhFMxKNhOBPzOXG45X3khvo6SBxON2KBSCadfohCpGqLgd0dsxHDCSRcUnkMBHEneC1LDsnkvvu8UhYElozNauh//qwpUwRYOAGx+PPqA/wUAAP//sdDZV6M6AAA=\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n"
  },
  {
    "path": "os/gres/testdata/testdata.txt",
    "content": "H4sIAAAAAAAC/7SaCTTU6xvH3+xZQpYUIWKQMQyRZCnKMpaxRonGGjHCyNaCUpakFCptF0W61ogkXZV935KUohDZR0Tof8rF/MaMJt1/59TUyfk83/f7Pu9veeaLRlHTcAIGAMBl95toQPCLGawGDk4u9p4IWzesg5OjqQktWNX6JsUKjaJnIPxB8ggOIgTc1ssT5+b6SxIDGLF3gpAESJP+/ZcUzs3V5Se1e7uDlUSlLhyhJVmOzjBFN9SW1eo1IxCIFoR2NbxMW1IbbtYZJqWjVy55vssIjUZrlUvWmIF7cnLIFtk62TrZbKSsfG6TjCEVCgYTdUy0uShvSkUDwPfvP7SaaMi3mQEAHJbVuoGMVldfKSes038q03hR5t5FmdL0Xad/LZOHSOb/zUv0okiTRZHXn12w+7VI4g76f5hotKjPbFHf10B1JWJ9SzuccUGfnZOHzAqOyBoIAOHpZbOC08G3BPLjNxxn74mTkcL54BbtktJrgGvDpWRMtGpqt2hXb1m1sN7CB5e2rwMAsC9biQ1a6WeFRTppcgi16iwHAICFcieRf+ok8r9wEglxEknaSaMl6/WP5Kf+TSeRP51EQp1cStZTzSr9HSedZLZhKXCSWNoaCABu5+SxIIzy7WBfAkHYY/9oRwg4iEP2Li5u0EtVZ4VWdXn53gxT9CiQuQxWzZvm8dnZlvOn4b9fxtvNw8WOqIxELaJC2zDDFM1IT1jmBrsXjLgMRa44Y/4bV5wx/7rii1niSq4R2u/Ntkn3xo+lEfcFFKSOvcmzWs02L73AQcJCEACwfgUl5xyClPxpUKYR2i/L9jX+nrJOAJgvdHOntQs3AID1dz3y8FqBR7ykOP96RHgPWeibfOnvNs+DN66TP/DKL1N70R+XY5vENgIAuFdQbs4fyC1rvn/yM3qenQ9nIfDH/vPA43W/7CHOpYX8DsHV9f/osQqK+tclZ0837ILulO4f91D0nFtZP7bXu6jxjn90nvOqhUNQuIkp/9edRLbqnFmkqs6ZlrXYVJY5i7YxDqBmiatSapvJ3hXYxk8G9a9tPgSHISszvazaUAwFl6ipqn1gimySRRtpVaNqDMqrULmmEnDtxhx0Vu6HrHK57LIHH36sNaP854n1n7PXdWzTDine4xmMagvLZfPjjjQAABisTOOcyX+oUfznGfef2wz5KTb+2AgVc1rBeYlTorrR+kQSl+4IK1Tij7+uYDPWLaUg7LHL3RvyKvDhHkZq00fY1BcPua03XE0AACD428WcMZReckPv73gqBivW2dlbft6pNmlcbBXVfHnOkkpzGQCA+LLluUmU9/Ci5Go2V5pWsoD4mvPMCDEjCQCAUfhOs1j455klcVqXXCFwakFdk7sVxQ8WbWy8aTBg2JlCu/BIo4JGPJQCAEguW3496fIme//zsxai63vCUD/s7aWfUjPrzw7nuYwV+S1e4srVKhoxAACnZQWvhQj+//UjUR1nDLk6ZHqRdjPerjS7x9if4EnG0FHw6I9W3PI7lT28yFWmsA9tt+UfhgMAxJatygWtOteCkMKLK56/P/109x8qpbvKt14n0DDMF+xtr4gQAQBs+s2CJnv/w4LLPb17uLnh/ug96AcAYevpuYKLKs8SCMIT5+tiLzWP+7HyBqPkn3dnrcraLfXwmr91coyk5SWSM+iYYhLNLn8S7ba722MhvjmpOzqR28KzmWrhYifRbtO3FQCAXHYhbFANTq4Yx5XcH9aTwCBc3BzdpI5gHRfW4hLru63pMG9pEjI6VGh7TN0VDQuHqtM86hjpcdcyIzmH8jJJB1H/1lIPNEfrA87yqK37TYROK3JmiXyLsq04GnXn+oSH/pBvrVc73rIFXzo0e1x1YqIw/dtsT2jmQzluGu0gAAJur6ZzZQKA7fHE+xMACHqq5FMB0I95veEztc7jOz+eLlU3fnhBA9aE9rcrB4zpuoODbuLrP5d5ZEtrdjpxip1X84TtmhHD/TO4c3LTjBiO8WIw9TfDgmTdxFtrPrLSRlVoDJ7BsA0LrH25dWNIQvDWVwElgkHNfzmjTUOkGJjpEnho1jZwu45RO7JpbWdj5Q4/f7ro2PHjfxU6/iVXYspjiUIx3Q0L2MQmwUylHdxrYN8xbZJcdemk6KQbv9zFUMcLvZLICMb2mZJHjWkPcIIXBK6p1kZuFx97ei65SuBAhxPnFYHza06pm2K+07EPn5QZ+8ycrqoj/B6jgRAK1rKXwRwRm7ZW5L6qMeWd+1b15Ove2Uj1ScNPWtR07KVC8e6S8VK7uNLuxKekxacEBgtfcGTXysuXZRxnrX/aIUcXswff0NyWQ817cb2G9YYPGzhcDiaNK0yf/SRQQBuhJjr5/daT7UYHqH3N8Gdn3mmcfL7aZ3Noye335vl2jIMS7HuSrHYXza6bjvPI9U/kOqWbmHXksXpjcMLB7+u+DQVgvl8ZvvWZ+lumar4gZ3/6gSZa+OOxIWqgViR6SPlv+uFLCUwsSmLukxJfJHLuHlfNNbXceWzfJzH0u/MGMv3jwv6PrYSN/UMKZ9Z/m4WZKah0hnvtzgzWdHnIem6Hwt0XZ3YKRQbBlIcqK0UZvppfOXX/8+RwoJXygzfZtD2uaTHnAgpE2vurnEe3KwycafQZwE/Y7kXVOIbF6n7y+4g9e7onxvqKxfXPoN1oXNhOPJZJMZ39zIlY85OFQZuaymJbLFTvW0ibcvG+8bcZnvCyufBC4cqbywzK+Z/w6yXomS7nyG3Aaudn3xTgU1eqD3AN5vdhqB8+6iZqz5T2+cVBbFw5VUsrTrALHr/3VZ9RcEvi86shzJWnhK7m9ksIvyzYKJnGXux+6mLYeaQOjMUniasJp6cZDi/ezXA91MTsySs/vn2DcgNBnWxHVTTf7lGV1E01ma2uP5+ngeUINDiHEU7pqm/kc7h/qMrWNsDM10ikXjyX1qjzqYZKzDtN5PMZh+Dxmtc87OI46zHWQ+hOhieVVY8TPl78jtqg4xF40iDMaPQuHc+BrThuqaP3+3oig/n0hBs/RmPx2sPi2d++1L/0jLr9MGZm/W6tL+dCWHc96HVXrZ0a5uIx3EzP9qgCBneqVX/+hNax70iSrs95bToXxbpcA2+hhkmjx+mDvSbb+cy/lB/ADFu69Thbpj4Yfz4mVrQ2PJ+F/vFz0VXqA6qKpy1n/3keexWGsB3IGl934JUJx8iqOL6KcPPiqx32700kx3Ad9wpQdSOBfTIyhz6mB6tvdoSFv/LeALOsgx1Kl8UK7sIWx9U4D6sV0Z/REWZpntr4hnVS6LDDHlhwh625QvbYW1NBVbOepFv2ijxHrilq3B2PbZLfuemLLVPiQ7WBM82Hy/KVePMUxzZSBT7LtEKltFaqJ6yV9sAIFgWdbWEZuuDOe8dMyzfHVqlZIj3YXbXZotzs7MZYm3eGN7dvLpjujqibnUG39vNPI3pVDFLuW/s5WoXWhvYfbjfvy+rQuoY7E94nN67eiD6u9aU8mfsNbvriTX84B8fB8gdrJQUEtCqj/Gn3JI28nXGW9/9gGWzx1HT2SJh3SRus0s87/oaFI+KEpC+HMHNYYm3Bw9U2RxWHS1LWvD/bcfXarGZb6XRC1Lca3XulIZcVonafuc94Dv4g/13I8AOB0iwnj20POg6KV19I43x1KitLWPmp//XHj3JefxkJfrcfl1yI7+wKCKNJPWN+1M+sib9D9s6q2vhIjBr/1+wjefL+LlVf2nRP6FhWh4+s06yJ3BpCm0+7WmCbEF7CQzd2QK4vZMblhqNWO2dkbqgmI3/PaE6u1vHqQy+etPA02g/rsfrjRxUVvLdHyx/VifVY5xuonpON37Nnz66RPSN4g7/VMqZpDJSqlJrtMnYXGscysEa51YpJjrR36vAV6vnk9TgrHB5t6369p+Gf8W+H7R+xsAw9moaXUJuuiiziPnBNoYWZ0zhfVKCFv0Rv7GqzU8qZsjzHk1M5re+vyStHI6QFb8uE2Fr3xOTv0+RKba9D/fP1O/YaR0N4Wckhu+T0sKLrz8brN6hztJWyCJjh7OS9GD0LTWCmJfk3UiziR8PbI1ki4nUZdrjJc7G293rs7037p1JGqWonVsLB7J+vTOwbaBHxBghaPTcTvzV0Y68a9b0PCV+01PyoLPxBzdU78FiQUGZ1a3Fx5xHNB0mpDkplg/WWyS90L3e5aMfNfIi/lqhs/v7gUIzjJrOsV62Kg5ZswzMh1GyaLim5BZFCl5DyrPGDAnCGXH6f0bwsIY6tX7Lt3tzprnjfejM0lPn1iQFq+zS4hY3KV6eHB9tm4l7kYtandu3zesdtKxx27cO29OLYv5k+Jwu2bCq+0T8Qq/sUkRsUF2FAg9KT1H9Z+MpEYFNLl/RpmWMagcYsEcY9zHUYmm0nh87KfiwOVZlM0PGuFtljLTm5RvnJiTLk/tjRa6OFezJ68FqJ12rklK0Gv8iij7Y4TKIuNrjnUH3O726fypvMw+Uyns2K2zWQm7i/9G3Qnacnvw92jEzp+D9L+iuMl0UfNnJX/GZvQl7jtqQb+JFz6ce8Zy4PxHWVVph3ZtY2xEXYdVXuNStIor/Qny2v3o+D7Xh+8xgt+7fbLyuxkVNGQk+T+6+nv9qxN+nQk96N+tqTTUzP7mnMBiSdbua3KjyXKmPrQs/lZ5l6XqbhxOlAfYtGE4bhoUtCvjvChnV1WS+qx3G+7s2OqVESOP56I2x6wH933+44IUFzTpwaqumAj6CCdMe+F7Zta18n8iSPdA/kd9k2lQluMzfbd6nM73V/llSTUTSfTC4r0luwu17L1r/k+T0FRngWrHqiJipt4pPDVp4+/Ds7x9Ba2CTrXv3K1ZnrZtTO+ESs1bWME1LZPPEZFVllEhgcH1uBdGcLWccRIFi65Xqhxu2yjzeUTn+7i7N8wty0fz91v1izkrHHsZoN/DJvnw1tbWN0s99AFVcoymPt07UKVyLa0qphMCz9Zrtr+Vd7lU9jWpvxCTETRZdO5XdMVAlUdT982nqsC6+jW5xhJwpjK3579I3/sczbuJyxXSrWdBKlIzWC4zinzlyudUM3RR9LpeEjDIXHVNim2z3GZWZYaAtyi+w70rKrKpKihrfZd6S1v6y58veVU0Y6ll7xWWMPpK02Z7vfr4R/QXm9xw/JxkRUmmLzCix4+49/dTMrH6O/pwcrr0Wk+nTfEfP1pGlSTUbeftHVam0wZelQg+7MTVfOnMbxCLWm12Yq3n2rC7uUV+cU72ox4xyy5YZrJ/+B9JeYA9ppm5s0YWenCnezvNjbW0X9PB1RkbF/3CKiSWl4t0hZwQ4PfZaJjsDxtiL4o7V/hxxzPvhYw/GaN/1M7MB+Y2xW/tTaDu0jxqe9Ay7y/eW/Ux+byZkqGs7ji5Ot3yymUuo51Ba8tjjIz3Ba8GkHb1MJ/4vb9oOuLXWtNh8r3DyDriVYe5xNOuWr9FZlJkNELpB2m1D+eP3Alr6G67svptLBh1qNvx678MIcDlsXfPBNWeMJ9sIN2969E7iBG7Fx98K5yNytm1BwylYySMRGRb4rmqoIajL+ri4UOpt2nI7/ijGXLxfyWdrzCbXiwfZOuuLWVI7okl0Ss2ksLFRmrFzYqi9an17J8xzldjM+off41tHYZB/2hL9zc8abS0abHRDX6ASi3fk6ZD0lsPkM109Iv7SXltmh3GKe/lUrJ0CfyerWxv3MOLWTdN1NTOvf96bu+aQ7W5B8Ri8qMxpjM8nJ2jM16hFj9STL5n7ogSH6fJNwo6NtsWa9p6oaPopmnseN6mdqYXN0ssKDlFR6zjxrqj311XFiX3i3BorfSyB6de3pG6YHh6Qj7WPxkto1fOEBmTqshb1hcjlVrRHhjGzKiuzFdE27u1D2+FtNSUXXB9/wiYwYNBhfSsxhw4YaX7dCbmkQiezJHb29Q9jyA992xGvR/BOjMP3Y8SKu+xmajnSWgVTH75voH8FX5AXKzbz60P/hbBvNlRL2MaG9mLPBNqhCTtodjP1yg2PIyPWeuWJszQ/HnR+nr7701gOFOtF3czymuQR5vKk+px/Eu/drqDJVbLWj8XtlL6tnvfuJLMobXrFF9Vxda8gVpkg1T1b3MBW31HGrgE7kQc24FlUUvcuNpI27VJP4C7Ont1f5pNkO7WWKHLKJg6Fqz+4Zzh1SidZlhtffmdr7bJZjYS49dDsggxmAyyyUvcHOvf9g7ex9pA7hCN5gJWvqXUsEmWneOyKDi8EI1RnxfLUNfBmMm56ZRbtYX5w1iBlKNNAs3hcRnvBsf1i4p0nXdGDRVp+cpCxuBzyaTqBoKOXr3c9pfUU3w08pFLK8E4CdFggt9Pfr1hvl1d5Ht9F/uOFhlbn/4GcvB4HVjk/z0oUY4w8G76x5ocCXoFB2yutG39M9XwdnmObXhRn4anIOAPCQwvdcnL3rERcM7s9eDuchpAwalTREmImVa5mWVaG0U9Fi/369bKpVWaXdTL0wy3oSIwaEAQAbl9XNvbSkC8bXzQsnswL9ImRhCFs3LA7jhLX3gK4lJU1fW6+yCmWK1qmp3aJdVYWCG6WkdmWVS2d7jk8wuY+NebJk1ddKZ39ISdOvRt1LXZzVidC3DSkAAGSWlSREXpKDmxtuGT2VtQjtRTH4CVZ3ckpMSpS0fj2iWkbJIXuMHXklFVp6unNK5oaE0tn4I144smqm/C80bgUAIFaqZu4TqibLEDfivSaU+YhpmVh5deaHrEDDe6HiRy0ZGRkZ5UWuiijeOzo4id0d+ugeo0po9OQdEfkpNsOMsL6+qKY3QddfRJnQilwobBK683qfFO/xkPXy2pPi0egEI2QlZ5Tn2vBw1+goPF5nrSzeKPyyNMvOsuaXu+T6kuxiMNcuxtyyDmoGyTQpWN7jISiXsaITNAtLrai5uCkKADC1shZHrqDFyfqGJNlPRL2zeDr3uYxVcxF9+fhb1Uj1TBa0NxarSSq37vijaqR6IiWtpgpVI66nPd+iDZVi5dWGRnX3U7t2lfV2iTp0B3N+vL16y52unljBw4vBAZrJHvofHaq/7LbxklfjinFayZf3ossTf/4hQ8JRr7Ex2WyooVV6Az+/xl/zxwWRZAoS7aCNqm8XcUEAEqw8jAkL0s4X/MlLUInBLHVnFRUnNfmM3fywc2Dnj08yiTvyCA4IQp0IsTRxN0+a844w0SawQAIgMTCCNIlkSoyYShhA2wChKq4ClGTjiIGEYTEeCPA9EZAifYTZLg4ILpgKLJs3W24nGCE7IUINSCfDyAPWQAAOEABRngm6HsLsFh9kPfeXQMgkw4iRhKEtNgiSiwaQj4BR7o8bIQa5An8yIIBl/SFMZEH9+bIEQibvRYwkjGJB/bGmBeSDXZT782gBQ5TiWgSQym0tAqYgAKIUF3kV7BCIKh1YNsUFNYUwagX1+SwpDqkUFzGSMFYFRQ6SRJJIbFG+WlN6sGw6CyqNMDYFlXaDFIdUOosYSRiQgiLZGABl6SvKV+u7FAnJWUGlEYageCHSikhxSOSsiImEaScoUXo1oChKtdxaOSFrvbqUSJyZIrqkEiSZoDfGj2RQpDJTxFTCpBKUuo8RUJyJonzZdSSpkMwTVCBhtogfIpCXCVCaeSKGEqaBoNCn5KBLQ0rLLZoVsmgbZrBMrAgqjTBlsQ4iLXkpZUmMg5hGGOKB0rhYwC9zQ8Q0wmQON4R2mQSNKAZEDCPM2UAfyVjWAEqiPcRAwhzMegjwHGkgUVhnuZ1YC+Eps4LlsjTEIML4ChR0BwoiDsssUUSQSIGCBNjActkXYhBh8IMLAoqGgkjEWShn0bGDXyRVKH/48F5gEYVQKH04y4MAiEIo0BURhkGgz/YzSyAkQijLaWKDaApcC5bLkxDd7ghmq9D2LiOBWZonIeYRzjSh+1YmAH4xn6Xc9tuCgPxMFCqIcFgJXWDXEsjviuKGiDLfBH498ISKI5w0ikDPMFkYuYHnkldegtmhEIS9TQj8zuRyyW2OYAwIBT8jDyY1VCIGEw7doGC0MPidmSLle6a0Gfx6ggdVSThfg6oMIQujyFfCURoUPE4eTImvhFMxKNhOBPzOXG45X3khvo6SBxON2KBSCadfohCpGqLgd0dsxHDCSRcUnkMBHEneC1LDsnkvvu8UhYElozNauh//qwpUwRYOAGx+PPqA/wUAAP//sdDZV6M6AAA="
  },
  {
    "path": "os/grpool/grpool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package grpool implements a goroutine reusable pool.\npackage grpool\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/glist\"\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\n// Func is the pool function which contains context parameter.\ntype Func func(ctx context.Context)\n\n// RecoverFunc is the pool runtime panic recover function which contains context parameter.\ntype RecoverFunc func(ctx context.Context, exception error)\n\n// Pool manages the goroutines using pool.\ntype Pool struct {\n\tlimit  int                          // Max goroutine count limit.\n\tcount  *gtype.Int                   // Current running goroutine count.\n\tlist   *glist.TList[*localPoolItem] // List for asynchronous job adding purpose.\n\tclosed *gtype.Bool                  // Is pool closed or not.\n}\n\n// localPoolItem is the job item storing in job list.\ntype localPoolItem struct {\n\tCtx  context.Context // Context.\n\tFunc Func            // Job function.\n}\n\nconst (\n\tminSupervisorTimerDuration = 500 * time.Millisecond\n\tmaxSupervisorTimerDuration = 1500 * time.Millisecond\n)\n\n// Default goroutine pool.\nvar (\n\tdefaultPool = New()\n)\n\n// New creates and returns a new goroutine pool object.\n// The parameter `limit` is used to limit the max goroutine count,\n// which is not limited in default.\nfunc New(limit ...int) *Pool {\n\tvar (\n\t\tpool = &Pool{\n\t\t\tlimit:  -1,\n\t\t\tcount:  gtype.NewInt(),\n\t\t\tlist:   glist.NewT[*localPoolItem](true),\n\t\t\tclosed: gtype.NewBool(),\n\t\t}\n\t\ttimerDuration = grand.D(\n\t\t\tminSupervisorTimerDuration,\n\t\t\tmaxSupervisorTimerDuration,\n\t\t)\n\t)\n\tif len(limit) > 0 && limit[0] > 0 {\n\t\tpool.limit = limit[0]\n\t}\n\tgtimer.Add(context.Background(), timerDuration, pool.supervisor)\n\treturn pool\n}\n\n// Add pushes a new job to the default goroutine pool.\n// The job will be executed asynchronously.\nfunc Add(ctx context.Context, f Func) error {\n\treturn defaultPool.Add(ctx, f)\n}\n\n// AddWithRecover pushes a new job to the default pool with specified recover function.\n//\n// The optional `recoverFunc` is called when any panic during executing of `userFunc`.\n// If `recoverFunc` is not passed or given nil, it ignores the panic from `userFunc`.\n// The job will be executed asynchronously.\nfunc AddWithRecover(ctx context.Context, userFunc Func, recoverFunc RecoverFunc) error {\n\treturn defaultPool.AddWithRecover(ctx, userFunc, recoverFunc)\n}\n\n// Size returns current goroutine count of default goroutine pool.\nfunc Size() int {\n\treturn defaultPool.Size()\n}\n\n// Jobs returns current job count of default goroutine pool.\nfunc Jobs() int {\n\treturn defaultPool.Jobs()\n}\n"
  },
  {
    "path": "os/grpool/grpool_pool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpool\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Add pushes a new job to the pool.\n// The job will be executed asynchronously.\nfunc (p *Pool) Add(ctx context.Context, f Func) error {\n\tfor p.closed.Val() {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\"goroutine defaultPool is already closed\",\n\t\t)\n\t}\n\tp.list.PushFront(&localPoolItem{\n\t\tCtx:  ctx,\n\t\tFunc: f,\n\t})\n\t// Check and fork new worker.\n\tp.checkAndForkNewGoroutineWorker()\n\treturn nil\n}\n\n// AddWithRecover pushes a new job to the pool with specified recover function.\n//\n// The optional `recoverFunc` is called when any panic during executing of `userFunc`.\n// If `recoverFunc` is not passed or given nil, it ignores the panic from `userFunc`.\n// The job will be executed asynchronously.\nfunc (p *Pool) AddWithRecover(ctx context.Context, userFunc Func, recoverFunc RecoverFunc) error {\n\treturn p.Add(ctx, func(ctx context.Context) {\n\t\tdefer func() {\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\tif recoverFunc != nil {\n\t\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\t\trecoverFunc(ctx, v)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trecoverFunc(ctx, gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tuserFunc(ctx)\n\t})\n}\n\n// Cap returns the capacity of the pool.\n// This capacity is defined when pool is created.\n// It returns -1 if there's no limit.\nfunc (p *Pool) Cap() int {\n\treturn p.limit\n}\n\n// Size returns current goroutine count of the pool.\nfunc (p *Pool) Size() int {\n\treturn p.count.Val()\n}\n\n// Jobs returns current job count of the pool.\n// Note that, it does not return worker/goroutine count but the job/task count.\nfunc (p *Pool) Jobs() int {\n\treturn p.list.Size()\n}\n\n// IsClosed returns if pool is closed.\nfunc (p *Pool) IsClosed() bool {\n\treturn p.closed.Val()\n}\n\n// Close closes the goroutine pool, which makes all goroutines exit.\nfunc (p *Pool) Close() {\n\tp.closed.Set(true)\n}\n\n// checkAndForkNewGoroutineWorker checks and creates a new goroutine worker.\n// Note that the worker dies if the job function panics and the job has no recover handling.\nfunc (p *Pool) checkAndForkNewGoroutineWorker() {\n\t// Check whether fork new goroutine or not.\n\tvar n int\n\tfor {\n\t\tn = p.count.Val()\n\t\tif p.limit != -1 && n >= p.limit {\n\t\t\t// No need fork new goroutine.\n\t\t\treturn\n\t\t}\n\t\tif p.count.Cas(n, n+1) {\n\t\t\t// Use CAS to guarantee atomicity.\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Create job function in goroutine.\n\tgo p.asynchronousWorker()\n}\n\nfunc (p *Pool) asynchronousWorker() {\n\tdefer p.count.Add(-1)\n\t// Harding working, one by one, job never empty, worker never die.\n\tfor !p.closed.Val() {\n\t\tlistItem := p.list.PopBack()\n\t\tif listItem == nil {\n\t\t\treturn\n\t\t}\n\t\tlistItem.Func(listItem.Ctx)\n\t}\n}\n"
  },
  {
    "path": "os/grpool/grpool_supervisor.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpool\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// supervisor checks the job list and fork new worker goroutine to handle the job\n// if there are jobs but no workers in pool.\nfunc (p *Pool) supervisor(_ context.Context) {\n\tif p.IsClosed() {\n\t\tgtimer.Exit()\n\t}\n\tif p.list.Size() > 0 && p.count.Val() == 0 {\n\t\tvar number = p.list.Size()\n\t\tif p.limit > 0 {\n\t\t\tnumber = p.limit\n\t\t}\n\t\tfor i := 0; i < number; i++ {\n\t\t\tp.checkAndForkNewGoroutineWorker()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/grpool/grpool_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage grpool_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/grpool\"\n)\n\nvar (\n\tctx = context.TODO()\n\tn   = 500000\n)\n\nfunc increment(ctx context.Context) {\n\tfor i := 0; i < 1000000; i++ {\n\t}\n}\n\nfunc BenchmarkGrpool_1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrpool.Add(ctx, increment)\n\t}\n}\n\nfunc BenchmarkGoroutine_1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgo increment(ctx)\n\t}\n}\n\nfunc BenchmarkGrpool2(b *testing.B) {\n\tb.N = n\n\tfor i := 0; i < b.N; i++ {\n\t\tgrpool.Add(ctx, increment)\n\t}\n}\n\nfunc BenchmarkGoroutine2(b *testing.B) {\n\tb.N = n\n\tfor i := 0; i < b.N; i++ {\n\t\tgo increment(ctx)\n\t}\n}\n"
  },
  {
    "path": "os/grpool/grpool_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grpool_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/grpool\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr   error\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t\tsize  = 100\n\t\t)\n\t\twg.Add(size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\terr = grpool.Add(ctx, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t\twg.Done()\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\twg.Wait()\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tt.Assert(array.Len(), size)\n\t\tt.Assert(grpool.Jobs(), 0)\n\t\tt.Assert(grpool.Size(), 0)\n\t})\n}\n\nfunc Test_Limit1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t\tsize  = 100\n\t\t\tpool  = grpool.New(10)\n\t\t)\n\t\twg.Add(size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tpool.Add(ctx, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t\twg.Done()\n\t\t\t})\n\t\t}\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), size)\n\t})\n}\n\nfunc Test_Limit2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr   error\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t\tsize  = 100\n\t\t\tpool  = grpool.New(1)\n\t\t)\n\t\twg.Add(size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\terr = pool.Add(ctx, func(ctx context.Context) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tarray.Append(1)\n\t\t\t})\n\t\t\tt.AssertNil(err)\n\t\t}\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), size)\n\t})\n}\n\nfunc Test_Limit3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tarray = garray.NewArray(true)\n\t\t\tsize  = 1000\n\t\t\tpool  = grpool.New(100)\n\t\t)\n\t\tt.Assert(pool.Cap(), 100)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tpool.Add(ctx, func(ctx context.Context) {\n\t\t\t\tarray.Append(1)\n\t\t\t\ttime.Sleep(2 * time.Second)\n\t\t\t})\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t\tt.Assert(pool.Size(), 100)\n\t\tt.Assert(pool.Jobs(), 900)\n\t\tt.Assert(array.Len(), 100)\n\t\tpool.Close()\n\t\ttime.Sleep(2 * time.Second)\n\t\tt.Assert(pool.Size(), 0)\n\t\tt.Assert(pool.Jobs(), 900)\n\t\tt.Assert(array.Len(), 100)\n\t\tt.Assert(pool.IsClosed(), true)\n\t\tt.AssertNE(pool.Add(ctx, func(ctx context.Context) {}), nil)\n\t})\n}\n\nfunc Test_AddWithRecover(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr   error\n\t\t\tarray = garray.NewArray(true)\n\t\t)\n\t\terr = grpool.AddWithRecover(ctx, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\tpanic(1)\n\t\t}, func(ctx context.Context, err error) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\tt.AssertNil(err)\n\t\terr = grpool.AddWithRecover(ctx, func(ctx context.Context) {\n\t\t\tpanic(1)\n\t\t\tarray.Append(1)\n\t\t}, nil)\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gsession/gsession.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gsession implements manager and storage features for sessions.\npackage gsession\n\nimport (\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nvar (\n\t// ErrorDisabled is used for marking certain interface function not used.\n\tErrorDisabled = gerror.NewWithOption(gerror.Option{\n\t\tText: \"this feature is disabled in this storage\",\n\t\tCode: gcode.CodeNotSupported,\n\t})\n)\n\n// NewSessionId creates and returns a new and unique session id string,\n// which is in 32 bytes.\nfunc NewSessionId() string {\n\treturn guid.S()\n}\n"
  },
  {
    "path": "os/gsession/gsession_manager.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Manager for sessions.\ntype Manager struct {\n\tttl     time.Duration // TTL for sessions.\n\tstorage Storage       // Storage interface for session storage.\n}\n\n// New creates and returns a new session manager.\nfunc New(ttl time.Duration, storage ...Storage) *Manager {\n\tm := &Manager{\n\t\tttl: ttl,\n\t}\n\tif len(storage) > 0 && storage[0] != nil {\n\t\tm.storage = storage[0]\n\t} else {\n\t\t// It uses StorageFile in default.\n\t\tm.storage = NewStorageFile(DefaultStorageFilePath, ttl)\n\t}\n\treturn m\n}\n\n// New creates or fetches the session for given session id.\n// The parameter `sessionId` is optional, it creates a new one if not it's passed\n// depending on Storage.New.\nfunc (m *Manager) New(ctx context.Context, sessionId ...string) *Session {\n\tvar id string\n\tif len(sessionId) > 0 && sessionId[0] != \"\" {\n\t\tid = sessionId[0]\n\t}\n\treturn &Session{\n\t\tid:      id,\n\t\tctx:     ctx,\n\t\tmanager: m,\n\t}\n}\n\n// SetStorage sets the session storage for manager.\nfunc (m *Manager) SetStorage(storage Storage) {\n\tm.storage = storage\n}\n\n// GetStorage returns the session storage of current manager.\nfunc (m *Manager) GetStorage() Storage {\n\treturn m.storage\n}\n\n// SetTTL the TTL for the session manager.\nfunc (m *Manager) SetTTL(ttl time.Duration) {\n\tm.ttl = ttl\n}\n\n// GetTTL returns the TTL of the session manager.\nfunc (m *Manager) GetTTL() time.Duration {\n\treturn m.ttl\n}\n"
  },
  {
    "path": "os/gsession/gsession_session.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// Session struct for storing single session data, which is bound to a single request.\n// The Session struct is the interface with user, but the Storage is the underlying adapter designed interface\n// for functionality implements.\ntype Session struct {\n\tid      string          // Session id. It retrieves the session if id is custom specified.\n\tctx     context.Context // Context for current session. Please note that, session lives along with context.\n\tdata    *gmap.StrAnyMap // Current Session data, which is retrieved from Storage.\n\tdirty   bool            // Used to mark session is modified.\n\tstart   bool            // Used to mark session is started.\n\tmanager *Manager        // Parent session Manager.\n\n\t// idFunc is a callback function used for creating custom session id.\n\t// This is called if session id is empty ever when session starts.\n\tidFunc func(ttl time.Duration) (id string)\n}\n\n// init does the lazy initialization for session, which retrieves the session if session id is specified,\n// or else it creates a new empty session.\nfunc (s *Session) init() error {\n\tif s.start {\n\t\treturn nil\n\t}\n\tvar err error\n\t// Session retrieving.\n\tif s.id != \"\" {\n\t\t// Retrieve stored session data from storage.\n\t\tif s.manager.storage != nil {\n\t\t\ts.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.GetTTL())\n\t\t\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\t\t\tintlog.Errorf(s.ctx, `session restoring failed for id \"%s\": %+v`, s.id, err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\t// Session id creation.\n\tif s.id == \"\" {\n\t\tif s.idFunc != nil {\n\t\t\t// Use custom session id creating function.\n\t\t\ts.id = s.idFunc(s.manager.ttl)\n\t\t} else {\n\t\t\t// Use default session id creating function of storage.\n\t\t\ts.id, err = s.manager.storage.New(s.ctx, s.manager.ttl)\n\t\t\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\t\t\tintlog.Errorf(s.ctx, \"create session id failed: %+v\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// If session storage does not implements id generating functionality,\n\t\t\t// it then uses default session id creating function.\n\t\t\tif s.id == \"\" {\n\t\t\t\ts.id = NewSessionId()\n\t\t\t}\n\t\t}\n\t}\n\tif s.data == nil {\n\t\ts.data = gmap.NewStrAnyMap(true)\n\t}\n\ts.start = true\n\treturn nil\n}\n\n// Close closes current session and updates its ttl in the session manager.\n// If this session is dirty, it also exports it to storage.\n//\n// NOTE that this function must be called ever after a session request done.\nfunc (s *Session) Close() error {\n\tif s.manager.storage == nil {\n\t\treturn nil\n\t}\n\tif s.start && s.id != \"\" {\n\t\tsize := s.data.Size()\n\t\tif s.dirty {\n\t\t\terr := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl)\n\t\t\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if size > 0 {\n\t\t\terr := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl)\n\t\t\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Set sets key-value pair to this session.\nfunc (s *Session) Set(key string, value any) (err error) {\n\tif err = s.init(); err != nil {\n\t\treturn err\n\t}\n\tif err = s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil {\n\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\treturn err\n\t\t}\n\t\ts.data.Set(key, value)\n\t}\n\ts.dirty = true\n\treturn nil\n}\n\n// SetMap batch sets the session using map.\nfunc (s *Session) SetMap(data map[string]any) (err error) {\n\tif err = s.init(); err != nil {\n\t\treturn err\n\t}\n\tif err = s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil {\n\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\treturn err\n\t\t}\n\t\ts.data.Sets(data)\n\t}\n\ts.dirty = true\n\treturn nil\n}\n\n// Remove removes key along with its value from this session.\nfunc (s *Session) Remove(keys ...string) (err error) {\n\tif s.id == \"\" {\n\t\treturn nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn err\n\t}\n\tfor _, key := range keys {\n\t\tif err = s.manager.storage.Remove(s.ctx, s.id, key); err != nil {\n\t\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ts.data.Remove(key)\n\t\t}\n\t}\n\ts.dirty = true\n\treturn nil\n}\n\n// RemoveAll deletes all key-value pairs from this session.\nfunc (s *Session) RemoveAll() (err error) {\n\tif s.id == \"\" {\n\t\treturn nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn err\n\t}\n\tif err = s.manager.storage.RemoveAll(s.ctx, s.id); err != nil {\n\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Remove data from memory.\n\tif s.data != nil {\n\t\ts.data.Clear()\n\t}\n\ts.dirty = true\n\treturn nil\n}\n\n// Id returns the session id for this session.\n// It creates and returns a new session id if the session id is not passed in initialization.\nfunc (s *Session) Id() (id string, err error) {\n\tif err = s.init(); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn s.id, nil\n}\n\n// SetId sets custom session before session starts.\n// It returns error if it is called after session starts.\nfunc (s *Session) SetId(id string) error {\n\tif s.start {\n\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"session already started\")\n\t}\n\ts.id = id\n\treturn nil\n}\n\n// SetIdFunc sets custom session id creating function before session starts.\n// It returns error if it is called after session starts.\nfunc (s *Session) SetIdFunc(f func(ttl time.Duration) string) error {\n\tif s.start {\n\t\treturn gerror.NewCode(gcode.CodeInvalidOperation, \"session already started\")\n\t}\n\ts.idFunc = f\n\treturn nil\n}\n\n// Data returns all data as map.\n// Note that it's using value copy internally for concurrent-safe purpose.\nfunc (s *Session) Data() (sessionData map[string]any, err error) {\n\tif s.id == \"\" {\n\t\treturn map[string]any{}, nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn nil, err\n\t}\n\tsessionData, err = s.manager.storage.Data(s.ctx, s.id)\n\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\tintlog.Errorf(s.ctx, `%+v`, err)\n\t}\n\tif sessionData != nil {\n\t\treturn sessionData, nil\n\t}\n\treturn s.data.Map(), nil\n}\n\n// Size returns the size of the session.\nfunc (s *Session) Size() (size int, err error) {\n\tif s.id == \"\" {\n\t\treturn 0, nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn 0, err\n\t}\n\tsize, err = s.manager.storage.GetSize(s.ctx, s.id)\n\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\tintlog.Errorf(s.ctx, `%+v`, err)\n\t}\n\tif size > 0 {\n\t\treturn size, nil\n\t}\n\treturn s.data.Size(), nil\n}\n\n// Contains checks whether key exist in the session.\nfunc (s *Session) Contains(key string) (ok bool, err error) {\n\tif s.id == \"\" {\n\t\treturn false, nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn false, err\n\t}\n\tv, err := s.Get(key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn !v.IsNil(), nil\n}\n\n// IsDirty checks whether there's any data changes in the session.\nfunc (s *Session) IsDirty() bool {\n\treturn s.dirty\n}\n\n// Get retrieves session value with given key.\n// It returns `def` if the key does not exist in the session if `def` is given,\n// or else it returns nil.\nfunc (s *Session) Get(key string, def ...any) (value *gvar.Var, err error) {\n\tif s.id == \"\" {\n\t\treturn nil, nil\n\t}\n\tif err = s.init(); err != nil {\n\t\treturn nil, err\n\t}\n\tv, err := s.manager.storage.Get(s.ctx, s.id, key)\n\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\tintlog.Errorf(s.ctx, `%+v`, err)\n\t\treturn nil, err\n\t}\n\tif v != nil {\n\t\treturn gvar.New(v), nil\n\t}\n\tif v = s.data.Get(key); v != nil {\n\t\treturn gvar.New(v), nil\n\t}\n\tif len(def) > 0 {\n\t\treturn gvar.New(def[0]), nil\n\t}\n\treturn nil, nil\n}\n\n// MustId performs as function Id, but it panics if any error occurs.\nfunc (s *Session) MustId() string {\n\tid, err := s.Id()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn id\n}\n\n// MustGet performs as function Get, but it panics if any error occurs.\nfunc (s *Session) MustGet(key string, def ...any) *gvar.Var {\n\tv, err := s.Get(key, def...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// MustSet performs as function Set, but it panics if any error occurs.\nfunc (s *Session) MustSet(key string, value any) {\n\terr := s.Set(key, value)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustSetMap performs as function SetMap, but it panics if any error occurs.\nfunc (s *Session) MustSetMap(data map[string]any) {\n\terr := s.SetMap(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// MustContains performs as function Contains, but it panics if any error occurs.\nfunc (s *Session) MustContains(key string) bool {\n\tb, err := s.Contains(key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn b\n}\n\n// MustData performs as function Data, but it panics if any error occurs.\nfunc (s *Session) MustData() map[string]any {\n\tm, err := s.Data()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// MustSize performs as function Size, but it panics if any error occurs.\nfunc (s *Session) MustSize() int {\n\tsize, err := s.Size()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn size\n}\n\n// MustRemove performs as function Remove, but it panics if any error occurs.\nfunc (s *Session) MustRemove(keys ...string) {\n\terr := s.Remove(keys...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// RegenerateId regenerates a new session id for current session.\n// It keeps the session data and updates the session id with a new one.\n// This is commonly used to prevent session fixation attacks and increase security.\n//\n// The parameter `deleteOld` specifies whether to delete the old session data:\n// - If true: the old session data will be deleted immediately\n// - If false: the old session data will be kept and expire according to its TTL\nfunc (s *Session) RegenerateId(deleteOld bool) (newId string, err error) {\n\tif err = s.init(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Generate new session id\n\tif s.idFunc != nil {\n\t\tnewId = s.idFunc(s.manager.ttl)\n\t} else {\n\t\tnewId, err = s.manager.storage.New(s.ctx, s.manager.ttl)\n\t\tif err != nil && !gerror.Is(err, ErrorDisabled) {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif newId == \"\" {\n\t\t\tnewId = NewSessionId()\n\t\t}\n\t}\n\n\t// If using storage, need to copy data to new id\n\tif s.manager.storage != nil {\n\t\tif err = s.manager.storage.SetSession(s.ctx, newId, s.data, s.manager.ttl); err != nil {\n\t\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t}\n\t\t// Delete old session data if requested\n\t\tif deleteOld {\n\t\t\tif err = s.manager.storage.RemoveAll(s.ctx, s.id); err != nil {\n\t\t\t\tif !gerror.Is(err, ErrorDisabled) {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Update session id\n\ts.id = newId\n\ts.dirty = true\n\treturn newId, nil\n}\n\n// MustRegenerateId performs as function RegenerateId, but it panics if any error occurs.\nfunc (s *Session) MustRegenerateId(deleteOld bool) string {\n\tnewId, err := s.RegenerateId(deleteOld)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn newId\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\n// Storage is the interface definition for session storage.\ntype Storage interface {\n\t// New creates a custom session id.\n\t// This function can be used for custom session creation.\n\tNew(ctx context.Context, ttl time.Duration) (sessionId string, err error)\n\n\t// Get retrieves and returns certain session value with given key.\n\t// It returns nil if the key does not exist in the session.\n\tGet(ctx context.Context, sessionId string, key string) (value any, err error)\n\n\t// GetSize retrieves and returns the size of key-value pairs from storage.\n\tGetSize(ctx context.Context, sessionId string) (size int, err error)\n\n\t// Data retrieves all key-value pairs as map from storage.\n\tData(ctx context.Context, sessionId string) (sessionData map[string]any, err error)\n\n\t// Set sets one key-value session pair to the storage.\n\t// The parameter `ttl` specifies the TTL for the session id.\n\tSet(ctx context.Context, sessionId string, key string, value any, ttl time.Duration) error\n\n\t// SetMap batch sets key-value session pairs as map to the storage.\n\t// The parameter `ttl` specifies the TTL for the session id.\n\tSetMap(ctx context.Context, sessionId string, mapData map[string]any, ttl time.Duration) error\n\n\t// Remove deletes key-value pair from specified session from storage.\n\tRemove(ctx context.Context, sessionId string, key string) error\n\n\t// RemoveAll deletes session from storage.\n\tRemoveAll(ctx context.Context, sessionId string) error\n\n\t// GetSession returns the session data as `*gmap.StrAnyMap` for given session from storage.\n\t//\n\t// The parameter `ttl` specifies the TTL for this session.\n\t// The parameter `data` is the current old session data stored in memory,\n\t// and for some storage it might be nil if memory storage is disabled.\n\t//\n\t// This function is called ever when session starts.\n\t// It returns nil if the session does not exist or its TTL is expired.\n\tGetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error)\n\n\t// SetSession updates the data for specified session id.\n\t// This function is called ever after session, which is changed dirty, is closed.\n\t// This copy all session data map from memory to storage.\n\tSetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error\n\n\t// UpdateTTL updates the TTL for specified session id.\n\t// This function is called ever after session, which is not dirty, is closed.\n\tUpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage_base.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n)\n\n// StorageBase is a base implement for Session Storage.\ntype StorageBase struct{}\n\n// New creates a session id.\n// This function can be used for custom session creation.\nfunc (s *StorageBase) New(ctx context.Context, ttl time.Duration) (id string, err error) {\n\treturn \"\", ErrorDisabled\n}\n\n// Get retrieves certain session value with given key.\n// It returns nil if the key does not exist in the session.\nfunc (s *StorageBase) Get(ctx context.Context, sessionId string, key string) (value any, err error) {\n\treturn nil, ErrorDisabled\n}\n\n// Data retrieves all key-value pairs as map from storage.\nfunc (s *StorageBase) Data(ctx context.Context, sessionId string) (sessionData map[string]any, err error) {\n\treturn nil, ErrorDisabled\n}\n\n// GetSize retrieves the size of key-value pairs from storage.\nfunc (s *StorageBase) GetSize(ctx context.Context, sessionId string) (size int, err error) {\n\treturn 0, ErrorDisabled\n}\n\n// Set sets key-value session pair to the storage.\n// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).\nfunc (s *StorageBase) Set(ctx context.Context, sessionId string, key string, value any, ttl time.Duration) error {\n\treturn ErrorDisabled\n}\n\n// SetMap batch sets key-value session pairs with map to the storage.\n// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).\nfunc (s *StorageBase) SetMap(ctx context.Context, sessionId string, mapData map[string]any, ttl time.Duration) error {\n\treturn ErrorDisabled\n}\n\n// Remove deletes key with its value from storage.\nfunc (s *StorageBase) Remove(ctx context.Context, sessionId string, key string) error {\n\treturn ErrorDisabled\n}\n\n// RemoveAll deletes session from storage.\nfunc (s *StorageBase) RemoveAll(ctx context.Context, sessionId string) error {\n\treturn ErrorDisabled\n}\n\n// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.\n//\n// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.\n// The parameter `data` is the current old session data stored in memory,\n// and for some storage it might be nil if memory storage is disabled.\n//\n// This function is called ever when session starts.\nfunc (s *StorageBase) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {\n\treturn nil, ErrorDisabled\n}\n\n// SetSession updates the data map for specified session id.\n// This function is called ever after session, which is changed dirty, is closed.\n// This copy all session data map from memory to storage.\nfunc (s *StorageBase) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {\n\treturn ErrorDisabled\n}\n\n// UpdateTTL updates the TTL for specified session id.\n// This function is called ever after session, which is not dirty, is closed.\n// It just adds the session id to the async handling queue.\nfunc (s *StorageBase) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {\n\treturn ErrorDisabled\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage_file.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/crypto/gaes\"\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// StorageFile implements the Session Storage interface with file system.\ntype StorageFile struct {\n\tStorageBase\n\tpath          string        // Session file storage folder path.\n\tttl           time.Duration // Session TTL.\n\tcryptoKey     []byte        // Used when enable crypto feature.\n\tcryptoEnabled bool          // Used when enable crypto feature.\n\tupdatingIdSet *gset.StrSet  // To be batched updated session id set.\n}\n\nconst (\n\tDefaultStorageFileCryptoEnabled        = false\n\tDefaultStorageFileUpdateTTLInterval    = 10 * time.Second\n\tDefaultStorageFileClearExpiredInterval = time.Hour\n)\n\nvar (\n\tDefaultStorageFilePath      = gfile.Temp(\"gsessions\")\n\tDefaultStorageFileCryptoKey = []byte(\"Session storage file crypto key!\")\n)\n\n// NewStorageFile creates and returns a file storage object for session.\nfunc NewStorageFile(path string, ttl time.Duration) *StorageFile {\n\tvar (\n\t\tctx         = context.TODO()\n\t\tstoragePath = DefaultStorageFilePath\n\t)\n\tif path != \"\" {\n\t\tstoragePath, _ = gfile.Search(path)\n\t\tif storagePath == \"\" {\n\t\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, `\"%s\" does not exist`, path))\n\t\t}\n\t\tif !gfile.IsWritable(storagePath) {\n\t\t\tpanic(gerror.NewCodef(gcode.CodeInvalidParameter, `\"%s\" is not writable`, path))\n\t\t}\n\t}\n\tif storagePath != \"\" {\n\t\tif err := gfile.Mkdir(storagePath); err != nil {\n\t\t\tpanic(gerror.Wrapf(err, `Mkdir \"%s\" failed in PWD \"%s\"`, path, gfile.Pwd()))\n\t\t}\n\t}\n\ts := &StorageFile{\n\t\tpath:          storagePath,\n\t\tttl:           ttl,\n\t\tcryptoKey:     DefaultStorageFileCryptoKey,\n\t\tcryptoEnabled: DefaultStorageFileCryptoEnabled,\n\t\tupdatingIdSet: gset.NewStrSet(true),\n\t}\n\n\tgtimer.AddSingleton(ctx, DefaultStorageFileUpdateTTLInterval, s.timelyUpdateSessionTTL)\n\tgtimer.AddSingleton(ctx, DefaultStorageFileClearExpiredInterval, s.timelyClearExpiredSessionFile)\n\treturn s\n}\n\n// timelyUpdateSessionTTL batch updates the TTL for sessions timely.\nfunc (s *StorageFile) timelyUpdateSessionTTL(ctx context.Context) {\n\tvar (\n\t\tsessionId string\n\t\terr       error\n\t)\n\t// Batch updating sessions.\n\tfor {\n\t\tif sessionId = s.updatingIdSet.Pop(); sessionId == \"\" {\n\t\t\tbreak\n\t\t}\n\t\tif err = s.updateSessionTTl(context.TODO(), sessionId); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t}\n}\n\n// timelyClearExpiredSessionFile deletes all expired files timely.\nfunc (s *StorageFile) timelyClearExpiredSessionFile(ctx context.Context) {\n\tfiles, err := gfile.ScanDirFile(s.path, \"*.session\", false)\n\tif err != nil {\n\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\treturn\n\t}\n\tfor _, file := range files {\n\t\tif err = s.checkAndClearSessionFile(ctx, file); err != nil {\n\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t}\n\t}\n}\n\n// SetCryptoKey sets the crypto key for session storage.\n// The crypto key is used when crypto feature is enabled.\nfunc (s *StorageFile) SetCryptoKey(key []byte) {\n\ts.cryptoKey = key\n}\n\n// SetCryptoEnabled enables/disables the crypto feature for session storage.\nfunc (s *StorageFile) SetCryptoEnabled(enabled bool) {\n\ts.cryptoEnabled = enabled\n}\n\n// sessionFilePath returns the storage file path for given session id.\nfunc (s *StorageFile) sessionFilePath(sessionId string) string {\n\treturn gfile.Join(s.path, sessionId) + \".session\"\n}\n\n// RemoveAll deletes all key-value pairs from storage.\nfunc (s *StorageFile) RemoveAll(ctx context.Context, sessionId string) error {\n\treturn gfile.RemoveAll(s.sessionFilePath(sessionId))\n}\n\n// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.\n//\n// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.\n// The parameter `data` is the current old session data stored in memory,\n// and for some storage it might be nil if memory storage is disabled.\n//\n// This function is called ever when session starts.\nfunc (s *StorageFile) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (sessionData *gmap.StrAnyMap, err error) {\n\tvar (\n\t\tpath    = s.sessionFilePath(sessionId)\n\t\tcontent = gfile.GetBytes(path)\n\t)\n\t// It updates the TTL only if the session file already exists.\n\tif len(content) > 8 {\n\t\ttimestampMilli := gbinary.DecodeToInt64(content[:8])\n\t\tif timestampMilli+ttl.Nanoseconds()/1e6 < gtime.TimestampMilli() {\n\t\t\treturn nil, nil\n\t\t}\n\t\tcontent = content[8:]\n\t\t// Decrypt with AES.\n\t\tif s.cryptoEnabled {\n\t\t\tcontent, err = gaes.Decrypt(content, DefaultStorageFileCryptoKey)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tvar m map[string]any\n\t\tif err = json.UnmarshalUseNumber(content, &m); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif m == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn gmap.NewStrAnyMapFrom(m, true), nil\n\t}\n\treturn nil, nil\n}\n\n// SetSession updates the data map for specified session id.\n// This function is called ever after session, which is changed dirty, is closed.\n// This copy all session data map from memory to storage.\nfunc (s *StorageFile) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageFile.SetSession: %s, %v, %v\", sessionId, sessionData, ttl)\n\tpath := s.sessionFilePath(sessionId)\n\tcontent, err := json.Marshal(sessionData)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Encrypt with AES.\n\tif s.cryptoEnabled {\n\t\tcontent, err = gaes.Encrypt(content, DefaultStorageFileCryptoKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfile, err := gfile.OpenWithFlagPerm(\n\t\tpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\tif _, err = file.Write(gbinary.EncodeInt64(gtime.TimestampMilli())); err != nil {\n\t\terr = gerror.Wrapf(err, `write data failed to file \"%s\"`, path)\n\t\treturn err\n\t}\n\tif _, err = file.Write(content); err != nil {\n\t\terr = gerror.Wrapf(err, `write data failed to file \"%s\"`, path)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// UpdateTTL updates the TTL for specified session id.\n// This function is called ever after session, which is not dirty, is closed.\n// It just adds the session id to the async handling queue.\nfunc (s *StorageFile) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageFile.UpdateTTL: %s, %v\", sessionId, ttl)\n\tif ttl >= DefaultStorageFileUpdateTTLInterval {\n\t\ts.updatingIdSet.Add(sessionId)\n\t}\n\treturn nil\n}\n\n// updateSessionTTL updates the TTL for specified session id.\nfunc (s *StorageFile) updateSessionTTl(ctx context.Context, sessionId string) error {\n\tintlog.Printf(ctx, \"StorageFile.updateSession: %s\", sessionId)\n\tpath := s.sessionFilePath(sessionId)\n\tfile, err := gfile.OpenWithFlag(path, os.O_WRONLY)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err = file.WriteAt(gbinary.EncodeInt64(gtime.TimestampMilli()), 0); err != nil {\n\t\terr = gerror.Wrapf(err, `write data failed to file \"%s\"`, path)\n\t\treturn err\n\t}\n\treturn file.Close()\n}\n\nfunc (s *StorageFile) checkAndClearSessionFile(ctx context.Context, path string) (err error) {\n\tvar (\n\t\tfile                *os.File\n\t\treadBytesCount      int\n\t\ttimestampMilliBytes = make([]byte, 8)\n\t)\n\tfile, err = gfile.OpenWithFlag(path, os.O_RDONLY)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Read the session file updated timestamp in milliseconds.\n\treadBytesCount, err = file.Read(timestampMilliBytes)\n\tif err != nil {\n\t\treturn\n\t}\n\tif readBytesCount != 8 {\n\t\treturn gerror.Newf(`invalid read bytes count \"%d\", expect \"8\"`, readBytesCount)\n\t}\n\t// Remove expired session file.\n\tvar (\n\t\tttlInMilliseconds     = s.ttl.Nanoseconds() / 1e6\n\t\tfileTimestampMilli    = gbinary.DecodeToInt64(timestampMilliBytes)\n\t\tcurrentTimestampMilli = gtime.TimestampMilli()\n\t)\n\tif fileTimestampMilli+ttlInMilliseconds < currentTimestampMilli {\n\t\tintlog.PrintFunc(ctx, func() string {\n\t\t\treturn fmt.Sprintf(\n\t\t\t\t`clear expired session file \"%s\": updated datetime \"%s\", ttl \"%s\"`,\n\t\t\t\tpath, gtime.NewFromTimeStamp(fileTimestampMilli), s.ttl,\n\t\t\t)\n\t\t})\n\t\treturn gfile.RemoveFile(path)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage_memory.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/os/gcache\"\n)\n\n// StorageMemory implements the Session Storage interface with memory.\ntype StorageMemory struct {\n\tStorageBase\n\t// cache is the memory data cache for session TTL,\n\t// which is available only if the Storage does not store any session data in synchronizing.\n\t// Please refer to the implements of StorageFile, StorageMemory and StorageRedis.\n\t//\n\t// Its value is type of `*gmap.StrAnyMap`.\n\tcache *gcache.Cache\n}\n\n// NewStorageMemory creates and returns a file storage object for session.\nfunc NewStorageMemory() *StorageMemory {\n\treturn &StorageMemory{\n\t\tcache: gcache.New(),\n\t}\n}\n\n// RemoveAll deletes session from storage.\nfunc (s *StorageMemory) RemoveAll(ctx context.Context, sessionId string) error {\n\t_, err := s.cache.Remove(ctx, sessionId)\n\treturn err\n}\n\n// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.\n//\n// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.\n// The parameter `data` is the current old session data stored in memory,\n// and for some storage it might be nil if memory storage is disabled.\n//\n// This function is called ever when session starts.\nfunc (s *StorageMemory) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {\n\t// Retrieve memory session data from manager.\n\tvar (\n\t\tv   *gvar.Var\n\t\terr error\n\t)\n\tv, err = s.cache.Get(ctx, sessionId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v != nil {\n\t\treturn v.Val().(*gmap.StrAnyMap), nil\n\t}\n\treturn gmap.NewStrAnyMap(true), nil\n}\n\n// SetSession updates the data map for specified session id.\n// This function is called ever after session, which is changed dirty, is closed.\n// This copy all session data map from memory to storage.\nfunc (s *StorageMemory) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {\n\treturn s.cache.Set(ctx, sessionId, sessionData, ttl)\n}\n\n// UpdateTTL updates the TTL for specified session id.\n// This function is called ever after session, which is not dirty, is closed.\n// It just adds the session id to the async handling queue.\nfunc (s *StorageMemory) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {\n\t_, err := s.cache.UpdateExpire(ctx, sessionId, ttl)\n\treturn err\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage_redis.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\n// StorageRedis implements the Session Storage interface with redis.\ntype StorageRedis struct {\n\tStorageBase\n\tredis         *gredis.Redis   // Redis client for session storage.\n\tprefix        string          // Redis key prefix for session id.\n\tupdatingIdMap *gmap.StrIntMap // Updating TTL set for session id.\n}\n\nconst (\n\t// DefaultStorageRedisLoopInterval is the interval updating TTL for session ids\n\t// in last duration.\n\tDefaultStorageRedisLoopInterval = 10 * time.Second\n)\n\n// NewStorageRedis creates and returns a redis storage object for session.\nfunc NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis {\n\tif redis == nil {\n\t\tpanic(\"redis instance for storage cannot be empty\")\n\t\treturn nil\n\t}\n\ts := &StorageRedis{\n\t\tredis:         redis,\n\t\tupdatingIdMap: gmap.NewStrIntMap(true),\n\t}\n\tif len(prefix) > 0 && prefix[0] != \"\" {\n\t\ts.prefix = prefix[0]\n\t}\n\t// Batch updates the TTL for session ids timely.\n\tgtimer.AddSingleton(context.Background(), DefaultStorageRedisLoopInterval, func(ctx context.Context) {\n\t\tintlog.Print(context.TODO(), \"StorageRedis.timer start\")\n\t\tvar (\n\t\t\terr        error\n\t\t\tsessionId  string\n\t\t\tttlSeconds int\n\t\t)\n\t\tfor {\n\t\t\tif sessionId, ttlSeconds = s.updatingIdMap.Pop(); sessionId == \"\" {\n\t\t\t\tbreak\n\t\t\t} else {\n\t\t\t\tif err = s.doUpdateExpireForSession(context.TODO(), sessionId, ttlSeconds); err != nil {\n\t\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tintlog.Print(context.TODO(), \"StorageRedis.timer end\")\n\t})\n\treturn s\n}\n\n// RemoveAll deletes all key-value pairs from storage.\nfunc (s *StorageRedis) RemoveAll(ctx context.Context, sessionId string) error {\n\t_, err := s.redis.Del(ctx, s.sessionIdToRedisKey(sessionId))\n\treturn err\n}\n\n// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.\n//\n// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.\n// The parameter `data` is the current old session data stored in memory,\n// and for some storage it might be nil if memory storage is disabled.\n//\n// This function is called ever when session starts.\nfunc (s *StorageRedis) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {\n\tintlog.Printf(ctx, \"StorageRedis.GetSession: %s, %v\", sessionId, ttl)\n\tr, err := s.redis.Get(ctx, s.sessionIdToRedisKey(sessionId))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcontent := r.Bytes()\n\tif len(content) == 0 {\n\t\treturn nil, nil\n\t}\n\tvar m map[string]any\n\tif err = json.UnmarshalUseNumber(content, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\treturn gmap.NewStrAnyMapFrom(m, true), nil\n}\n\n// SetSession updates the data map for specified session id.\n// This function is called ever after session, which is changed dirty, is closed.\n// This copy all session data map from memory to storage.\nfunc (s *StorageRedis) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageRedis.SetSession: %s, %v, %v\", sessionId, sessionData, ttl)\n\tcontent, err := json.Marshal(sessionData)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = s.redis.SetEX(ctx, s.sessionIdToRedisKey(sessionId), content, int64(ttl.Seconds()))\n\treturn err\n}\n\n// UpdateTTL updates the TTL for specified session id.\n// This function is called ever after session, which is not dirty, is closed.\n// It just adds the session id to the async handling queue.\nfunc (s *StorageRedis) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageRedis.UpdateTTL: %s, %v\", sessionId, ttl)\n\tif ttl >= DefaultStorageRedisLoopInterval {\n\t\ts.updatingIdMap.Set(sessionId, int(ttl.Seconds()))\n\t}\n\treturn nil\n}\n\n// doUpdateExpireForSession updates the TTL for session id.\nfunc (s *StorageRedis) doUpdateExpireForSession(ctx context.Context, sessionId string, ttlSeconds int) error {\n\tintlog.Printf(ctx, \"StorageRedis.doUpdateTTL: %s, %d\", sessionId, ttlSeconds)\n\t_, err := s.redis.Expire(ctx, s.sessionIdToRedisKey(sessionId), int64(ttlSeconds))\n\treturn err\n}\n\n// sessionIdToRedisKey converts and returns the redis key for given session id.\nfunc (s *StorageRedis) sessionIdToRedisKey(sessionId string) string {\n\treturn s.prefix + sessionId\n}\n"
  },
  {
    "path": "os/gsession/gsession_storage_redis_hashtable.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/database/gredis\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// StorageRedisHashTable implements the Session Storage interface with redis hash table.\ntype StorageRedisHashTable struct {\n\tStorageBase\n\tredis  *gredis.Redis // Redis client for session storage.\n\tprefix string        // Redis key prefix for session id.\n}\n\n// NewStorageRedisHashTable creates and returns a redis hash table storage object for session.\nfunc NewStorageRedisHashTable(redis *gredis.Redis, prefix ...string) *StorageRedisHashTable {\n\tif redis == nil {\n\t\tpanic(\"redis instance for storage cannot be empty\")\n\t\treturn nil\n\t}\n\ts := &StorageRedisHashTable{\n\t\tredis: redis,\n\t}\n\tif len(prefix) > 0 && prefix[0] != \"\" {\n\t\ts.prefix = prefix[0]\n\t}\n\treturn s\n}\n\n// Get retrieves session value with given key.\n// It returns nil if the key does not exist in the session.\nfunc (s *StorageRedisHashTable) Get(ctx context.Context, sessionId string, key string) (value any, err error) {\n\tv, err := s.redis.HGet(ctx, s.sessionIdToRedisKey(sessionId), key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v.IsNil() {\n\t\treturn nil, nil\n\t}\n\treturn v.String(), nil\n}\n\n// Data retrieves all key-value pairs as map from storage.\nfunc (s *StorageRedisHashTable) Data(ctx context.Context, sessionId string) (data map[string]any, err error) {\n\tm, err := s.redis.HGetAll(ctx, s.sessionIdToRedisKey(sessionId))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn m.Map(), nil\n}\n\n// GetSize retrieves the size of key-value pairs from storage.\nfunc (s *StorageRedisHashTable) GetSize(ctx context.Context, sessionId string) (size int, err error) {\n\tv, err := s.redis.HLen(ctx, s.sessionIdToRedisKey(sessionId))\n\treturn int(v), err\n}\n\n// Set sets key-value session pair to the storage.\n// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).\nfunc (s *StorageRedisHashTable) Set(ctx context.Context, sessionId string, key string, value any, ttl time.Duration) error {\n\t_, err := s.redis.HSet(ctx, s.sessionIdToRedisKey(sessionId), map[string]any{\n\t\tkey: value,\n\t})\n\treturn err\n}\n\n// SetMap batch sets key-value session pairs with map to the storage.\n// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).\nfunc (s *StorageRedisHashTable) SetMap(ctx context.Context, sessionId string, data map[string]any, ttl time.Duration) error {\n\terr := s.redis.HMSet(ctx, s.sessionIdToRedisKey(sessionId), data)\n\treturn err\n}\n\n// Remove deletes key with its value from storage.\nfunc (s *StorageRedisHashTable) Remove(ctx context.Context, sessionId string, key string) error {\n\t_, err := s.redis.HDel(ctx, s.sessionIdToRedisKey(sessionId), key)\n\treturn err\n}\n\n// RemoveAll deletes all key-value pairs from storage.\nfunc (s *StorageRedisHashTable) RemoveAll(ctx context.Context, sessionId string) error {\n\t_, err := s.redis.Del(ctx, s.sessionIdToRedisKey(sessionId))\n\treturn err\n}\n\n// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.\n//\n// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.\n// The parameter `data` is the current old session data stored in memory,\n// and for some storage it might be nil if memory storage is disabled.\n//\n// This function is called ever when session starts.\nfunc (s *StorageRedisHashTable) GetSession(ctx context.Context, sessionId string, ttl time.Duration) (*gmap.StrAnyMap, error) {\n\tintlog.Printf(ctx, \"StorageRedisHashTable.GetSession: %s, %v\", sessionId, ttl)\n\tv, err := s.redis.Exists(ctx, s.sessionIdToRedisKey(sessionId))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif v > 0 {\n\t\t// It does not store the session data in memory, it so returns an empty map.\n\t\t// It retrieves session data items directly through redis server each time.\n\t\treturn gmap.NewStrAnyMap(true), nil\n\t}\n\treturn nil, nil\n}\n\n// SetSession updates the data map for specified session id.\n// This function is called ever after session, which is changed dirty, is closed.\n// This copy all session data map from memory to storage.\nfunc (s *StorageRedisHashTable) SetSession(ctx context.Context, sessionId string, sessionData *gmap.StrAnyMap, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageRedisHashTable.SetSession: %s, %v\", sessionId, ttl)\n\t_, err := s.redis.Expire(ctx, s.sessionIdToRedisKey(sessionId), int64(ttl.Seconds()))\n\treturn err\n}\n\n// UpdateTTL updates the TTL for specified session id.\n// This function is called ever after session, which is not dirty, is closed.\n// It just adds the session id to the async handling queue.\nfunc (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, sessionId string, ttl time.Duration) error {\n\tintlog.Printf(ctx, \"StorageRedisHashTable.UpdateTTL: %s, %v\", sessionId, ttl)\n\t_, err := s.redis.Expire(ctx, s.sessionIdToRedisKey(sessionId), int64(ttl.Seconds()))\n\treturn err\n}\n\n// sessionIdToRedisKey converts and returns the redis key for given session id.\nfunc (s *StorageRedisHashTable) sessionIdToRedisKey(sessionId string) string {\n\treturn s.prefix + sessionId\n}\n"
  },
  {
    "path": "os/gsession/gsession_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession_test\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n)\n\nfunc ExampleNew() {\n\tmanager := gsession.New(time.Second)\n\tfmt.Println(manager.GetTTL())\n\n\t// Output:\n\t// 1s\n}\n\nfunc ExampleManager_SetStorage() {\n\tmanager := gsession.New(time.Second)\n\tmanager.SetStorage(gsession.NewStorageMemory())\n\tfmt.Println(manager.GetTTL())\n\n\t// Output:\n\t// 1s\n}\n\nfunc ExampleManager_GetStorage() {\n\tmanager := gsession.New(time.Second, gsession.NewStorageMemory())\n\tsize, _ := manager.GetStorage().GetSize(gctx.New(), \"id\")\n\tfmt.Println(size)\n\n\t// Output:\n\t// 0\n}\n\nfunc ExampleManager_SetTTL() {\n\tmanager := gsession.New(time.Second)\n\tmanager.SetTTL(time.Minute)\n\tfmt.Println(manager.GetTTL())\n\n\t// Output:\n\t// 1m0s\n}\n\nfunc ExampleSession_Set() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts := manager.New(gctx.New())\n\tfmt.Println(s.Set(\"key\", \"val\") == nil)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleSession_SetMap() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts := manager.New(gctx.New())\n\tfmt.Println(s.SetMap(map[string]any{}) == nil)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleSession_Remove() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts1 := manager.New(gctx.New())\n\tfmt.Println(s1.Remove(\"key\"))\n\n\ts2 := manager.New(gctx.New(), \"Remove\")\n\tfmt.Println(s2.Remove(\"key\"))\n\n\t// Output:\n\t// <nil>\n\t// <nil>\n}\n\nfunc ExampleSession_RemoveAll() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts1 := manager.New(gctx.New())\n\tfmt.Println(s1.RemoveAll())\n\n\ts2 := manager.New(gctx.New(), \"Remove\")\n\tfmt.Println(s2.RemoveAll())\n\n\t// Output:\n\t// <nil>\n\t// <nil>\n}\n\nfunc ExampleSession_Id() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts := manager.New(gctx.New(), \"Id\")\n\tid, _ := s.Id()\n\tfmt.Println(id)\n\n\t// Output:\n\t// Id\n}\n\nfunc ExampleSession_SetId() {\n\tnilSession := &gsession.Session{}\n\tfmt.Println(nilSession.SetId(\"id\"))\n\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts := manager.New(gctx.New())\n\ts.Id()\n\tfmt.Println(s.SetId(\"id\"))\n\n\t// Output:\n\t// <nil>\n\t// session already started\n}\n\nfunc ExampleSession_SetIdFunc() {\n\tnilSession := &gsession.Session{}\n\tfmt.Println(nilSession.SetIdFunc(func(ttl time.Duration) string {\n\t\treturn \"id\"\n\t}))\n\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\ts := manager.New(gctx.New())\n\ts.Id()\n\tfmt.Println(s.SetIdFunc(func(ttl time.Duration) string {\n\t\treturn \"id\"\n\t}))\n\n\t// Output:\n\t// <nil>\n\t// session already started\n}\n\nfunc ExampleSession_Data() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\n\ts1 := manager.New(gctx.New())\n\tdata1, _ := s1.Data()\n\tfmt.Println(data1)\n\n\ts2 := manager.New(gctx.New(), \"id_data\")\n\tdata2, _ := s2.Data()\n\tfmt.Println(data2)\n\n\t// Output:\n\t// map[]\n\t// map[]\n}\n\nfunc ExampleSession_Size() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\n\ts1 := manager.New(gctx.New())\n\tsize1, _ := s1.Size()\n\tfmt.Println(size1)\n\n\ts2 := manager.New(gctx.New(), \"Size\")\n\tsize2, _ := s2.Size()\n\tfmt.Println(size2)\n\n\t// Output:\n\t// 0\n\t// 0\n}\n\nfunc ExampleSession_Contains() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\n\ts1 := manager.New(gctx.New())\n\tnotContains, _ := s1.Contains(\"Contains\")\n\tfmt.Println(notContains)\n\n\ts2 := manager.New(gctx.New(), \"Contains\")\n\tcontains, _ := s2.Contains(\"Contains\")\n\tfmt.Println(contains)\n\n\t// Output:\n\t// false\n\t// false\n}\n\nfunc ExampleStorageFile_SetCryptoKey() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tstorage.SetCryptoKey([]byte(\"key\"))\n\n\tsize, _ := storage.GetSize(gctx.New(), \"id\")\n\tfmt.Println(size)\n\n\t// Output:\n\t// 0\n}\n\nfunc ExampleStorageFile_SetCryptoEnabled() {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tstorage.SetCryptoEnabled(true)\n\n\tsize, _ := storage.GetSize(gctx.New(), \"id\")\n\tfmt.Println(size)\n\n\t// Output:\n\t// 0\n}\n\nfunc ExampleStorageFile_UpdateTTL() {\n\tvar (\n\t\tctx = gctx.New()\n\t)\n\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tfmt.Println(storage.UpdateTTL(ctx, \"id\", time.Second*15))\n\n\ttime.Sleep(time.Second * 11)\n\n\t// Output:\n\t// <nil>\n}\n\nfunc ExampleStorageRedis_Get() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\tval, _ := storage.Get(gctx.New(), \"id\", \"key\")\n\tfmt.Println(val)\n\n\t// May Output:\n\t// <nil>\n}\n\nfunc ExampleStorageRedis_Data() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\tval, _ := storage.Data(gctx.New(), \"id\")\n\tfmt.Println(val)\n\n\t// May Output:\n\t// map[]\n}\n\nfunc ExampleStorageRedis_GetSize() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\tval, _ := storage.GetSize(gctx.New(), \"id\")\n\tfmt.Println(val)\n\n\t// May Output:\n\t// 0\n}\n\nfunc ExampleStorageRedis_Remove() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\terr := storage.Remove(gctx.New(), \"id\", \"key\")\n\tfmt.Println(err != nil)\n\n\t// May Output:\n\t// true\n}\n\nfunc ExampleStorageRedis_RemoveAll() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\terr := storage.RemoveAll(gctx.New(), \"id\")\n\tfmt.Println(err != nil)\n\n\t// May Output:\n\t// true\n}\n\nfunc ExampleStorageRedis_UpdateTTL() {\n\tstorage := gsession.NewStorageRedis(g.Redis())\n\terr := storage.UpdateTTL(gctx.New(), \"id\", time.Second*15)\n\tfmt.Println(err)\n\n\ttime.Sleep(time.Second * 11)\n\n\t// May Output:\n\t// <nil>\n}\n\nfunc ExampleStorageRedisHashTable_Get() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\tv, err := storage.Get(gctx.New(), \"id\", \"key\")\n\n\tfmt.Println(v)\n\tfmt.Println(err)\n\n\t// May Output:\n\t// <nil>\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_Data() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\tdata, err := storage.Data(gctx.New(), \"id\")\n\n\tfmt.Println(data)\n\tfmt.Println(err)\n\n\t// May Output:\n\t// map[]\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_GetSize() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\tsize, err := storage.GetSize(gctx.New(), \"id\")\n\n\tfmt.Println(size)\n\tfmt.Println(err)\n\n\t// May Output:\n\t// 0\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_Remove() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\terr := storage.Remove(gctx.New(), \"id\", \"key\")\n\n\tfmt.Println(err)\n\n\t// May Output:\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_RemoveAll() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\terr := storage.RemoveAll(gctx.New(), \"id\")\n\n\tfmt.Println(err)\n\n\t// May Output:\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_GetSession() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\tdata, err := storage.GetSession(gctx.New(), \"id\", time.Second)\n\n\tfmt.Println(data)\n\tfmt.Println(err)\n\n\t// May Output:\n\t//\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_SetSession() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\tstrAnyMap := gmap.StrAnyMap{}\n\n\terr := storage.SetSession(gctx.New(), \"id\", &strAnyMap, time.Second)\n\n\tfmt.Println(err)\n\n\t// May Output:\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n\nfunc ExampleStorageRedisHashTable_UpdateTTL() {\n\tstorage := gsession.NewStorageRedisHashTable(g.Redis())\n\n\terr := storage.UpdateTTL(gctx.New(), \"id\", time.Second)\n\n\tfmt.Println(err)\n\n\t// May Output:\n\t// redis adapter is not set, missing configuration or adapter register? possible reference: https://github.com/gogf/gf/tree/master/contrib/nosql/redis\n}\n"
  },
  {
    "path": "os/gsession/gsession_z_unit_storage_file_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_StorageFile(t *testing.T) {\n\tstorage := gsession.NewStorageFile(\"\", time.Second)\n\tmanager := gsession.New(time.Second, storage)\n\tsessionId := \"\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO())\n\t\tdefer s.Close()\n\t\ts.Set(\"k1\", \"v1\")\n\t\ts.Set(\"k2\", \"v2\")\n\t\ts.MustSet(\"k3\", \"v3\")\n\t\ts.MustSet(\"k4\", \"v4\")\n\t\ts.SetMap(g.Map{\n\t\t\t\"kmap1\": \"kval1\",\n\t\t\t\"kmap2\": \"kval2\",\n\t\t})\n\t\ts.MustSetMap(g.Map{\n\t\t\t\"kmap3\": \"kval3\",\n\t\t\t\"kmap4\": \"kval4\",\n\t\t})\n\t\tt.Assert(s.IsDirty(), true)\n\t\tsessionId = s.MustId()\n\t})\n\n\ttime.Sleep(500 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO(), sessionId)\n\t\tt.Assert(s.MustGet(\"k1\"), \"v1\")\n\t\tt.Assert(s.MustGet(\"k2\"), \"v2\")\n\t\tt.Assert(s.MustGet(\"k3\"), \"v3\")\n\t\tt.Assert(s.MustGet(\"k4\"), \"v4\")\n\t\tt.Assert(len(s.MustData()), 8)\n\t\tt.Assert(s.MustData()[\"k1\"], \"v1\")\n\t\tt.Assert(s.MustData()[\"k4\"], \"v4\")\n\t\tt.Assert(s.MustId(), sessionId)\n\t\tt.Assert(s.MustSize(), 8)\n\t\tt.Assert(s.MustContains(\"k1\"), true)\n\t\tt.Assert(s.MustContains(\"k3\"), true)\n\t\tt.Assert(s.MustContains(\"k5\"), false)\n\t\ts.Remove(\"k4\")\n\t\ts.MustRemove(\"k4\")\n\t\tt.Assert(s.MustSize(), 7)\n\t\tt.Assert(s.MustContains(\"k3\"), true)\n\t\tt.Assert(s.MustContains(\"k4\"), false)\n\t\ts.RemoveAll()\n\t\tt.Assert(s.MustSize(), 0)\n\t\tt.Assert(s.MustContains(\"k1\"), false)\n\t\tt.Assert(s.MustContains(\"k2\"), false)\n\t\ts.SetMap(g.Map{\n\t\t\t\"k5\": \"v5\",\n\t\t\t\"k6\": \"v6\",\n\t\t})\n\t\tt.Assert(s.MustSize(), 2)\n\t\tt.Assert(s.MustContains(\"k5\"), true)\n\t\tt.Assert(s.MustContains(\"k6\"), true)\n\t})\n\n\ttime.Sleep(1000 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO(), sessionId)\n\t\tt.Assert(s.MustSize(), 0)\n\t\tt.Assert(s.MustGet(\"k5\"), nil)\n\t\tt.Assert(s.MustGet(\"k6\"), nil)\n\t})\n}\n"
  },
  {
    "path": "os/gsession/gsession_z_unit_storage_memory_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gsession\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_StorageMemory(t *testing.T) {\n\tstorage := gsession.NewStorageMemory()\n\tmanager := gsession.New(time.Second, storage)\n\tsessionId := \"\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO())\n\t\tdefer s.Close()\n\t\ts.Set(\"k1\", \"v1\")\n\t\ts.Set(\"k2\", \"v2\")\n\t\ts.SetMap(g.Map{\n\t\t\t\"k3\": \"v3\",\n\t\t\t\"k4\": \"v4\",\n\t\t})\n\t\tt.Assert(s.IsDirty(), true)\n\t\tsessionId = s.MustId()\n\t})\n\n\ttime.Sleep(500 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO(), sessionId)\n\t\tt.Assert(s.MustGet(\"k1\"), \"v1\")\n\t\tt.Assert(s.MustGet(\"k2\"), \"v2\")\n\t\tt.Assert(s.MustGet(\"k3\"), \"v3\")\n\t\tt.Assert(s.MustGet(\"k4\"), \"v4\")\n\t\tt.Assert(len(s.MustData()), 4)\n\t\tt.Assert(s.MustData()[\"k1\"], \"v1\")\n\t\tt.Assert(s.MustData()[\"k4\"], \"v4\")\n\t\tt.Assert(s.MustId(), sessionId)\n\t\tt.Assert(s.MustSize(), 4)\n\t\tt.Assert(s.MustContains(\"k1\"), true)\n\t\tt.Assert(s.MustContains(\"k3\"), true)\n\t\tt.Assert(s.MustContains(\"k5\"), false)\n\t\ts.Remove(\"k4\")\n\t\tt.Assert(s.MustSize(), 3)\n\t\tt.Assert(s.MustContains(\"k3\"), true)\n\t\tt.Assert(s.MustContains(\"k4\"), false)\n\t\ts.RemoveAll()\n\t\tt.Assert(s.MustSize(), 0)\n\t\tt.Assert(s.MustContains(\"k1\"), false)\n\t\tt.Assert(s.MustContains(\"k2\"), false)\n\t\ts.SetMap(g.Map{\n\t\t\t\"k5\": \"v5\",\n\t\t\t\"k6\": \"v6\",\n\t\t})\n\t\tt.Assert(s.MustSize(), 2)\n\t\tt.Assert(s.MustContains(\"k5\"), true)\n\t\tt.Assert(s.MustContains(\"k6\"), true)\n\t})\n\n\ttime.Sleep(1000 * time.Millisecond)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := manager.New(context.TODO(), sessionId)\n\t\tt.Assert(s.MustSize(), 0)\n\t\tt.Assert(s.MustGet(\"k5\"), nil)\n\t\tt.Assert(s.MustGet(\"k6\"), nil)\n\t})\n}\n"
  },
  {
    "path": "os/gsession/gsession_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gsession\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar ctx = context.TODO()\n\nfunc Test_NewSessionId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tid1 := NewSessionId()\n\t\tid2 := NewSessionId()\n\t\tt.AssertNE(id1, id2)\n\t\tt.Assert(len(id1), 32)\n\t})\n}\n\nfunc Test_Session_RegenerateId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 1. Test with memory storage\n\t\tstorage := NewStorageMemory()\n\t\tmanager := New(time.Hour, storage)\n\t\tsession := manager.New(ctx)\n\n\t\t// Store some data\n\t\terr := session.Set(\"key1\", \"value1\")\n\t\tt.AssertNil(err)\n\t\terr = session.Set(\"key2\", \"value2\")\n\t\tt.AssertNil(err)\n\n\t\t// Get original session id\n\t\toldId := session.MustId()\n\n\t\t// Test regenerate with deleteOld = true\n\t\tnewId1, err := session.RegenerateId(true)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(oldId, newId1)\n\n\t\t// Verify data is preserved\n\t\tv1 := session.MustGet(\"key1\")\n\t\tt.Assert(v1.String(), \"value1\")\n\t\tv2 := session.MustGet(\"key2\")\n\t\tt.Assert(v2.String(), \"value2\")\n\n\t\t// Verify old session is deleted\n\t\toldSession := manager.New(ctx)\n\t\terr = oldSession.SetId(oldId)\n\t\tt.AssertNil(err)\n\t\tv3 := oldSession.MustGet(\"key1\")\n\t\tt.Assert(v3.IsNil(), true)\n\n\t\t// Test regenerate with deleteOld = false\n\t\tcurrentId := newId1\n\t\tnewId2, err := session.RegenerateId(false)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(currentId, newId2)\n\n\t\t// Verify data is preserved in new session\n\t\tv4 := session.MustGet(\"key1\")\n\t\tt.Assert(v4.String(), \"value1\")\n\n\t\t// Create another session instance with the previous id\n\t\tprevSession := manager.New(ctx)\n\t\terr = prevSession.SetId(currentId)\n\t\tt.AssertNil(err)\n\t\t// Data should still be accessible in previous session\n\t\tv5 := prevSession.MustGet(\"key1\")\n\t\tt.Assert(v5.String(), \"value1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 2. Test with custom id function\n\t\tstorage := NewStorageMemory()\n\t\tmanager := New(time.Hour, storage)\n\t\tsession := manager.New(ctx)\n\n\t\tcustomId := \"custom_session_id\"\n\t\terr := session.SetIdFunc(func(ttl time.Duration) string {\n\t\t\treturn customId\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tnewId, err := session.RegenerateId(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(newId, customId)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 3. Test with disabled storage\n\t\tstorage := &StorageBase{} // implements Storage interface but all methods return ErrorDisabled\n\t\tmanager := New(time.Hour, storage)\n\t\tsession := manager.New(ctx)\n\n\t\t// Should still work even with disabled storage\n\t\tnewId, err := session.RegenerateId(true)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(newId), 32)\n\t})\n}\n\n// Test MustRegenerateId\nfunc Test_Session_MustRegenerateId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstorage := NewStorageMemory()\n\t\tmanager := New(time.Hour, storage)\n\t\tsession := manager.New(ctx)\n\n\t\t// Normal case should not panic\n\t\tt.AssertNil(session.Set(\"key\", \"value\"))\n\t\tnewId := session.MustRegenerateId(true)\n\t\tt.Assert(len(newId), 32)\n\n\t\t// Test with disabled storage (should not panic)\n\t\tstorage2 := &StorageBase{}\n\t\tmanager2 := New(time.Hour, storage2)\n\t\tsession2 := manager2.New(ctx)\n\t\tnewId2 := session2.MustRegenerateId(true)\n\t\tt.Assert(len(newId2), 32)\n\t})\n}\n"
  },
  {
    "path": "os/gspath/gspath.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gspath implements file index and search for folders.\n//\n// It searches file internally with high performance in order by the directory adding sequence.\n// Note that:\n// If caching feature enabled, there would be a searching delay after adding/deleting files.\npackage gspath\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// SPath manages the path searching feature.\ntype SPath struct {\n\tpaths *garray.StrArray // The searching directories array.\n\tcache *gmap.StrStrMap  // Searching cache map, it is not enabled if it's nil.\n}\n\n// SPathCacheItem is a cache item for searching.\ntype SPathCacheItem struct {\n\tpath  string // Absolute path for file/dir.\n\tisDir bool   // Is directory or not.\n}\n\nvar (\n\t// checker is the checking function for checking the value is nil or not.\n\tchecker = func(v *SPath) bool { return v == nil }\n\t// Path to searching object mapping, used for instance management.\n\tpathsMap = gmap.NewKVMapWithChecker[string, *SPath](checker, true)\n)\n\n// New creates and returns a new path searching manager.\nfunc New(path string, cache bool) *SPath {\n\tsp := &SPath{\n\t\tpaths: garray.NewStrArray(true),\n\t}\n\tif cache {\n\t\tsp.cache = gmap.NewStrStrMap(true)\n\t}\n\tif len(path) > 0 {\n\t\t_, _ = sp.Add(path)\n\t}\n\treturn sp\n}\n\n// Get creates and returns an instance of searching manager for given path.\n// The parameter `cache` specifies whether using cache feature for this manager.\n// If cache feature is enabled, it asynchronously and recursively scans the path\n// and updates all sub files/folders to the cache using package gfsnotify.\nfunc Get(root string, cache bool) *SPath {\n\tif root == \"\" {\n\t\troot = \"/\"\n\t}\n\treturn pathsMap.GetOrSetFuncLock(root, func() *SPath {\n\t\treturn New(root, cache)\n\t})\n}\n\n// Search searches file `name` under path `root`.\n// The parameter `root` should be an absolute path. It will not automatically\n// convert `root` to absolute path for performance reason.\n// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.\n// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also\n// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,\n// or else it returns `filePath`.\nfunc Search(root string, name string, indexFiles ...string) (filePath string, isDir bool) {\n\treturn Get(root, false).Search(name, indexFiles...)\n}\n\n// SearchWithCache searches file `name` under path `root` with cache feature enabled.\n// The parameter `root` should be an absolute path. It will not automatically\n// convert `root` to absolute path for performance reason.\n// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.\n// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also\n// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,\n// or else it returns `filePath`.\nfunc SearchWithCache(root string, name string, indexFiles ...string) (filePath string, isDir bool) {\n\treturn Get(root, true).Search(name, indexFiles...)\n}\n\n// Set deletes all other searching directories and sets the searching directory for this manager.\nfunc (sp *SPath) Set(path string) (realPath string, err error) {\n\trealPath = gfile.RealPath(path)\n\tif realPath == \"\" {\n\t\trealPath, _ = sp.Search(path)\n\t\tif realPath == \"\" {\n\t\t\trealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path)\n\t\t}\n\t}\n\tif realPath == \"\" {\n\t\treturn realPath, gerror.NewCodef(gcode.CodeInvalidParameter, `path \"%s\" does not exist`, path)\n\t}\n\t// The set path must be a directory.\n\tif gfile.IsDir(realPath) {\n\t\trealPath = strings.TrimRight(realPath, gfile.Separator)\n\t\tif sp.paths.Search(realPath) != -1 {\n\t\t\tfor _, v := range sp.paths.Slice() {\n\t\t\t\tsp.removeMonitorByPath(v)\n\t\t\t}\n\t\t}\n\t\tintlog.Print(context.TODO(), \"paths clear:\", sp.paths)\n\t\tsp.paths.Clear()\n\t\tif sp.cache != nil {\n\t\t\tsp.cache.Clear()\n\t\t}\n\t\tsp.paths.Append(realPath)\n\t\tsp.updateCacheByPath(realPath)\n\t\tsp.addMonitorByPath(realPath)\n\t\treturn realPath, nil\n\t} else {\n\t\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, path+\" should be a folder\")\n\t}\n}\n\n// Add adds more searching directory to the manager.\n// The manager will search file in added order.\nfunc (sp *SPath) Add(path string) (realPath string, err error) {\n\trealPath = gfile.RealPath(path)\n\tif realPath == \"\" {\n\t\trealPath, _ = sp.Search(path)\n\t\tif realPath == \"\" {\n\t\t\trealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path)\n\t\t}\n\t}\n\tif realPath == \"\" {\n\t\treturn realPath, gerror.NewCodef(gcode.CodeInvalidParameter, `path \"%s\" does not exist`, path)\n\t}\n\t// The added path must be a directory.\n\tif gfile.IsDir(realPath) {\n\t\t// fmt.Println(\"gspath:\", realPath, sp.paths.Search(realPath))\n\t\t// It will not add twice for the same directory.\n\t\tif sp.paths.Search(realPath) < 0 {\n\t\t\trealPath = strings.TrimRight(realPath, gfile.Separator)\n\t\t\tsp.paths.Append(realPath)\n\t\t\tsp.updateCacheByPath(realPath)\n\t\t\tsp.addMonitorByPath(realPath)\n\t\t}\n\t\treturn realPath, nil\n\t} else {\n\t\treturn \"\", gerror.NewCode(gcode.CodeInvalidParameter, path+\" should be a folder\")\n\t}\n}\n\n// Search searches file `name` in the manager.\n// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.\n// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also\n// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,\n// or else it returns `filePath`.\nfunc (sp *SPath) Search(name string, indexFiles ...string) (filePath string, isDir bool) {\n\t// No cache enabled.\n\tif sp.cache == nil {\n\t\tsp.paths.LockFunc(func(array []string) {\n\t\t\tpath := \"\"\n\t\t\tfor _, v := range array {\n\t\t\t\tpath = gfile.Join(v, name)\n\t\t\t\tif stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {\n\t\t\t\t\tpath = gfile.Abs(path)\n\t\t\t\t\t// Security check: the result file path must be under the searching directory.\n\t\t\t\t\tif len(path) >= len(v) && path[:len(v)] == v {\n\t\t\t\t\t\tfilePath = path\n\t\t\t\t\t\tisDir = stat.IsDir()\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tif len(indexFiles) > 0 && isDir {\n\t\t\tif name == \"/\" {\n\t\t\t\tname = \"\"\n\t\t\t}\n\t\t\tpath := \"\"\n\t\t\tfor _, file := range indexFiles {\n\t\t\t\tpath = filePath + gfile.Separator + file\n\t\t\t\tif gfile.Exists(path) {\n\t\t\t\t\tfilePath = path\n\t\t\t\t\tisDir = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\t// Using cache feature.\n\tname = sp.formatCacheName(name)\n\tif v := sp.cache.Get(name); v != \"\" {\n\t\tfilePath, isDir = sp.parseCacheValue(v)\n\t\tif len(indexFiles) > 0 && isDir {\n\t\t\tif name == \"/\" {\n\t\t\t\tname = \"\"\n\t\t\t}\n\t\t\tfor _, file := range indexFiles {\n\t\t\t\tif v = sp.cache.Get(name + \"/\" + file); v != \"\" {\n\t\t\t\t\treturn sp.parseCacheValue(v)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// Remove deletes the `path` from cache files of the manager.\n// The parameter `path` can be either an absolute path or just a relative file name.\nfunc (sp *SPath) Remove(path string) {\n\tif sp.cache == nil {\n\t\treturn\n\t}\n\tif gfile.Exists(path) {\n\t\tfor _, v := range sp.paths.Slice() {\n\t\t\tname := gstr.Replace(path, v, \"\")\n\t\t\tname = sp.formatCacheName(name)\n\t\t\tsp.cache.Remove(name)\n\t\t}\n\t} else {\n\t\tname := sp.formatCacheName(path)\n\t\tsp.cache.Remove(name)\n\t}\n}\n\n// Paths returns all searching directories.\nfunc (sp *SPath) Paths() []string {\n\treturn sp.paths.Slice()\n}\n\n// AllPaths returns all paths cached in the manager.\nfunc (sp *SPath) AllPaths() []string {\n\tif sp.cache == nil {\n\t\treturn nil\n\t}\n\tpaths := sp.cache.Keys()\n\tif len(paths) > 0 {\n\t\tsort.Strings(paths)\n\t}\n\treturn paths\n}\n\n// Size returns the count of the searching directories.\nfunc (sp *SPath) Size() int {\n\treturn sp.paths.Len()\n}\n"
  },
  {
    "path": "os/gspath/gspath_cache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gspath implements file index and search for folders.\n//\n\npackage gspath\n\nimport (\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// updateCacheByPath adds all files under `path` recursively.\nfunc (sp *SPath) updateCacheByPath(path string) {\n\tif sp.cache == nil {\n\t\treturn\n\t}\n\tsp.addToCache(path, path)\n}\n\n// formatCacheName formats `name` with following rules:\n// 1. The separator is unified to char '/'.\n// 2. The name should be started with '/' (similar as HTTP URI).\nfunc (sp *SPath) formatCacheName(name string) string {\n\tif runtime.GOOS != \"linux\" {\n\t\tname = gstr.Replace(name, \"\\\\\", \"/\")\n\t}\n\treturn \"/\" + strings.Trim(name, \"./\")\n}\n\n// nameFromPath converts `filePath` to cache name.\nfunc (sp *SPath) nameFromPath(filePath, rootPath string) string {\n\tname := gstr.Replace(filePath, rootPath, \"\")\n\tname = sp.formatCacheName(name)\n\treturn name\n}\n\n// makeCacheValue formats `filePath` to cache value.\nfunc (sp *SPath) makeCacheValue(filePath string, isDir bool) string {\n\tif isDir {\n\t\treturn filePath + \"_D_\"\n\t}\n\treturn filePath + \"_F_\"\n}\n\n// parseCacheValue parses cache value to file path and type.\nfunc (sp *SPath) parseCacheValue(value string) (filePath string, isDir bool) {\n\tif value[len(value)-2 : len(value)-1][0] == 'F' {\n\t\treturn value[:len(value)-3], false\n\t}\n\treturn value[:len(value)-3], true\n}\n\n// addToCache adds an item to cache.\n// If `filePath` is a directory, it also adds its all sub files/directories recursively\n// to the cache.\nfunc (sp *SPath) addToCache(filePath, rootPath string) {\n\t// Add itself firstly.\n\tidDir := gfile.IsDir(filePath)\n\tsp.cache.SetIfNotExist(\n\t\tsp.nameFromPath(filePath, rootPath), sp.makeCacheValue(filePath, idDir),\n\t)\n\t// If it's a directory, it adds all of its sub files/directories.\n\tif idDir {\n\t\tif files, err := gfile.ScanDir(filePath, \"*\", true); err == nil {\n\t\t\t// fmt.Println(\"gspath add to cache:\", filePath, files)\n\t\t\tfor _, path := range files {\n\t\t\t\tsp.cache.SetIfNotExist(sp.nameFromPath(path, rootPath), sp.makeCacheValue(path, gfile.IsDir(path)))\n\t\t\t}\n\t\t}\n\t}\n}\n\n// addMonitorByPath adds gfsnotify monitoring recursively.\n// When the files under the directory are updated, the cache will be updated meanwhile.\n// Note that since the listener is added recursively, if you delete a directory, the files (including the directory)\n// under the directory will also generate delete events, which means it will generate N+1 events in total\n// if a directory deleted and there are N files under it.\nfunc (sp *SPath) addMonitorByPath(path string) {\n\tif sp.cache == nil {\n\t\treturn\n\t}\n\t_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {\n\t\t// glog.Debug(event.String())\n\t\tswitch {\n\t\tcase event.IsRemove():\n\t\t\tsp.cache.Remove(sp.nameFromPath(event.Path, path))\n\n\t\tcase event.IsRename():\n\t\t\tif !gfile.Exists(event.Path) {\n\t\t\t\tsp.cache.Remove(sp.nameFromPath(event.Path, path))\n\t\t\t}\n\n\t\tcase event.IsCreate():\n\t\t\tsp.addToCache(event.Path, path)\n\t\t}\n\t})\n}\n\n// removeMonitorByPath removes gfsnotify monitoring of `path` recursively.\nfunc (sp *SPath) removeMonitorByPath(path string) {\n\tif sp.cache == nil {\n\t\treturn\n\t}\n\t_ = gfsnotify.Remove(path)\n}\n"
  },
  {
    "path": "os/gspath/gspath_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gspath_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gspath\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestSPath_Api(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpwd := gfile.Pwd()\n\t\troot := pwd\n\t\tgfile.Create(gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tdefer gfile.Remove(gfile.Join(root, \"gf_tmp\"))\n\t\tfp, isDir := gspath.Search(root, \"gf_tmp\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\"))\n\t\tt.Assert(isDir, true)\n\t\tfp, isDir = gspath.Search(root, \"gf_tmp\", \"gf.txt\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.Assert(isDir, false)\n\n\t\tfp, isDir = gspath.SearchWithCache(root, \"gf_tmp\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\"))\n\t\tt.Assert(isDir, true)\n\t\tfp, isDir = gspath.SearchWithCache(root, \"gf_tmp\", \"gf.txt\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.Assert(isDir, false)\n\t})\n}\n\nfunc TestSPath_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpwd := gfile.Pwd()\n\t\troot := pwd\n\n\t\tgfile.Create(gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tdefer gfile.Remove(gfile.Join(root, \"gf_tmp\"))\n\t\tgsp := gspath.New(root, false)\n\t\trealPath, err := gsp.Add(gfile.Join(root, \"gf_tmp\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(realPath, gfile.Join(root, \"gf_tmp\"))\n\t\trealPath, err = gsp.Add(\"gf_tmp1\")\n\t\tt.Assert(err != nil, true)\n\t\tt.Assert(realPath, \"\")\n\t\trealPath, err = gsp.Add(gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.Assert(err != nil, true)\n\t\tt.Assert(realPath, \"\")\n\n\t\tgsp.Remove(\"gf_tmp1\")\n\n\t\tt.Assert(gsp.Size(), 2)\n\t\tt.Assert(len(gsp.Paths()), 2)\n\t\tt.Assert(len(gsp.AllPaths()), 0)\n\t\trealPath, err = gsp.Set(gfile.Join(root, \"gf_tmp1\"))\n\t\tt.Assert(err != nil, true)\n\t\tt.Assert(realPath, \"\")\n\t\trealPath, err = gsp.Set(gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(realPath, \"\")\n\n\t\trealPath, err = gsp.Set(root)\n\t\tt.AssertNil(err)\n\t\tt.Assert(realPath, root)\n\n\t\tfp, isDir := gsp.Search(\"gf_tmp\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\"))\n\t\tt.Assert(isDir, true)\n\t\tfp, isDir = gsp.Search(\"gf_tmp\", \"gf.txt\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.Assert(isDir, false)\n\t\tfp, isDir = gsp.Search(\"/\", \"gf.txt\")\n\t\tt.Assert(fp, root)\n\t\tt.Assert(isDir, true)\n\n\t\tgsp = gspath.New(root, true)\n\t\trealPath, err = gsp.Add(gfile.Join(root, \"gf_tmp\"))\n\t\tt.AssertNil(err)\n\t\tt.Assert(realPath, gfile.Join(root, \"gf_tmp\"))\n\n\t\tgfile.Mkdir(gfile.Join(root, \"gf_tmp1\"))\n\t\tgfile.Rename(gfile.Join(root, \"gf_tmp1\"), gfile.Join(root, \"gf_tmp2\"))\n\t\tgfile.Rename(gfile.Join(root, \"gf_tmp2\"), gfile.Join(root, \"gf_tmp1\"))\n\t\tdefer gfile.Remove(gfile.Join(root, \"gf_tmp1\"))\n\t\trealPath, err = gsp.Add(\"gf_tmp1\")\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(realPath, gfile.Join(root, \"gf_tmp1\"))\n\n\t\trealPath, err = gsp.Add(\"gf_tmp3\")\n\t\tt.Assert(err != nil, true)\n\t\tt.Assert(realPath, \"\")\n\n\t\tgsp.Remove(gfile.Join(root, \"gf_tmp\"))\n\t\tgsp.Remove(gfile.Join(root, \"gf_tmp1\"))\n\t\tgsp.Remove(gfile.Join(root, \"gf_tmp3\"))\n\t\tt.Assert(gsp.Size(), 3)\n\t\tt.Assert(len(gsp.Paths()), 3)\n\n\t\tgsp.AllPaths()\n\t\tgsp.Set(root)\n\t\tfp, isDir = gsp.Search(\"gf_tmp\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\"))\n\t\tt.Assert(isDir, true)\n\n\t\tfp, isDir = gsp.Search(\"gf_tmp\", \"gf.txt\")\n\t\tt.Assert(fp, gfile.Join(root, \"gf_tmp\", \"gf.txt\"))\n\t\tt.Assert(isDir, false)\n\t})\n}\n"
  },
  {
    "path": "os/gstructs/gstructs.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gstructs provides functions for struct information retrieving.\npackage gstructs\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Type wraps reflect.Type for additional features.\ntype Type struct {\n\treflect.Type\n}\n\n// Field contains information of a struct field .\ntype Field struct {\n\tValue reflect.Value       // The underlying value of the field.\n\tField reflect.StructField // The underlying field of the field.\n\n\t// Retrieved tag name. It depends TagValue.\n\tTagName string\n\n\t// Retrieved tag value.\n\t// There might be more than one tags in the field,\n\t// but only one can be retrieved according to calling function rules.\n\tTagValue string\n}\n\n// FieldsInput is the input parameter struct type for function Fields.\ntype FieldsInput struct {\n\t// Pointer should be type of struct/*struct.\n\t// TODO this attribute name is not suitable, which would make confuse.\n\tPointer any\n\n\t// RecursiveOption specifies the way retrieving the fields recursively if the attribute\n\t// is an embedded struct. It is RecursiveOptionNone in default.\n\tRecursiveOption RecursiveOption\n}\n\n// FieldMapInput is the input parameter struct type for function FieldMap.\ntype FieldMapInput struct {\n\t// Pointer should be type of struct/*struct.\n\t// TODO this attribute name is not suitable, which would make confuse.\n\tPointer any\n\n\t// PriorityTagArray specifies the priority tag array for retrieving from high to low.\n\t// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.\n\tPriorityTagArray []string\n\n\t// RecursiveOption specifies the way retrieving the fields recursively if the attribute\n\t// is an embedded struct. It is RecursiveOptionNone in default.\n\tRecursiveOption RecursiveOption\n}\n\ntype RecursiveOption int\n\nconst (\n\tRecursiveOptionNone          RecursiveOption = iota // No recursively retrieving fields as map if the field is an embedded struct.\n\tRecursiveOptionEmbedded                             // Recursively retrieving fields as map if the field is an embedded struct.\n\tRecursiveOptionEmbeddedNoTag                        // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag.\n)\n\n// Fields retrieves and returns the fields of `pointer` as slice.\nfunc Fields(in FieldsInput) ([]Field, error) {\n\tvar (\n\t\tok                   bool\n\t\tfieldFilterMap       = make(map[string]struct{})\n\t\tretrievedFields      = make([]Field, 0)\n\t\tcurrentLevelFieldMap = make(map[string]Field)\n\t\trangeFields, err     = getFieldValues(in.Pointer)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor index := 0; index < len(rangeFields); index++ {\n\t\tfield := rangeFields[index]\n\t\tcurrentLevelFieldMap[field.Name()] = field\n\t}\n\n\tfor index := 0; index < len(rangeFields); index++ {\n\t\tfield := rangeFields[index]\n\t\tif _, ok = fieldFilterMap[field.Name()]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tif field.IsEmbedded() {\n\t\t\tif in.RecursiveOption != RecursiveOptionNone {\n\t\t\t\tswitch in.RecursiveOption {\n\t\t\t\tcase RecursiveOptionEmbeddedNoTag:\n\t\t\t\t\tif field.TagStr() != \"\" {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tfallthrough\n\n\t\t\t\tcase RecursiveOptionEmbedded:\n\t\t\t\t\tstructFields, err := Fields(FieldsInput{\n\t\t\t\t\t\tPointer:         field.Value,\n\t\t\t\t\t\tRecursiveOption: in.RecursiveOption,\n\t\t\t\t\t})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\t// The current level fields can overwrite the sub-struct fields with the same name.\n\t\t\t\t\tfor i := 0; i < len(structFields); i++ {\n\t\t\t\t\t\tvar (\n\t\t\t\t\t\t\tstructField = structFields[i]\n\t\t\t\t\t\t\tfieldName   = structField.Name()\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif _, ok = fieldFilterMap[fieldName]; ok {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfieldFilterMap[fieldName] = struct{}{}\n\t\t\t\t\t\tif v, ok := currentLevelFieldMap[fieldName]; !ok {\n\t\t\t\t\t\t\tretrievedFields = append(retrievedFields, structField)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tretrievedFields = append(retrievedFields, v)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tfieldFilterMap[field.Name()] = struct{}{}\n\t\tretrievedFields = append(retrievedFields, field)\n\t}\n\treturn retrievedFields, nil\n}\n\n// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.\n//\n// The parameter `pointer` should be type of struct/*struct.\n//\n// The parameter `priority` specifies the priority tag array for retrieving from high to low.\n// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.\n//\n// The parameter `recursive` specifies whether retrieving the fields recursively if the attribute\n// is an embedded struct.\n//\n// Note that it only retrieves the exported attributes with first letter upper-case from struct.\nfunc FieldMap(in FieldMapInput) (map[string]Field, error) {\n\tfields, err := getFieldValues(in.Pointer)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\ttagValue string\n\t\tmapField = make(map[string]Field)\n\t)\n\tfor _, field := range fields {\n\t\t// Only retrieve exported attributes.\n\t\tif !field.IsExported() {\n\t\t\tcontinue\n\t\t}\n\t\ttagValue = \"\"\n\t\tfor _, p := range in.PriorityTagArray {\n\t\t\ttagValue = field.Tag(p)\n\t\t\tif tagValue != \"\" && tagValue != \"-\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\ttempField := field\n\t\ttempField.TagValue = tagValue\n\t\tif tagValue != \"\" {\n\t\t\tmapField[tagValue] = tempField\n\t\t} else {\n\t\t\tif in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {\n\t\t\t\tswitch in.RecursiveOption {\n\t\t\t\tcase RecursiveOptionEmbeddedNoTag:\n\t\t\t\t\tif field.TagStr() != \"\" {\n\t\t\t\t\t\tmapField[field.Name()] = tempField\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tfallthrough\n\n\t\t\t\tcase RecursiveOptionEmbedded:\n\t\t\t\t\tm, err := FieldMap(FieldMapInput{\n\t\t\t\t\t\tPointer:          field.Value,\n\t\t\t\t\t\tPriorityTagArray: in.PriorityTagArray,\n\t\t\t\t\t\tRecursiveOption:  in.RecursiveOption,\n\t\t\t\t\t})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tfor k, v := range m {\n\t\t\t\t\t\tif _, ok := mapField[k]; !ok {\n\t\t\t\t\t\t\ttempV := v\n\t\t\t\t\t\t\tmapField[k] = tempV\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmapField[field.Name()] = tempField\n\t\t\t}\n\t\t}\n\t}\n\treturn mapField, nil\n}\n\n// StructType retrieves and returns the struct Type of specified struct/*struct.\n// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.\nfunc StructType(object any) (*Type, error) {\n\t// if already reflect.Type\n\tif reflectType, ok := object.(reflect.Type); ok {\n\t\tfor reflectType.Kind() == reflect.Pointer {\n\t\t\treflectType = reflectType.Elem()\n\t\t}\n\t\tif reflectType.Kind() == reflect.Struct {\n\t\t\treturn &Type{\n\t\t\t\tType: reflectType,\n\t\t\t}, nil\n\t\t}\n\t}\n\n\tvar (\n\t\treflectValue reflect.Value\n\t\treflectKind  reflect.Kind\n\t\treflectType  reflect.Type\n\t)\n\tif rv, ok := object.(reflect.Value); ok {\n\t\treflectValue = rv\n\t} else {\n\t\treflectValue = reflect.ValueOf(object)\n\t}\n\treflectKind = reflectValue.Kind()\n\tfor {\n\t\tswitch reflectKind {\n\t\tcase reflect.Pointer:\n\t\t\tif !reflectValue.IsValid() || reflectValue.IsNil() {\n\t\t\t\t// If pointer is type of *struct and nil, then automatically create a temporary struct.\n\t\t\t\treflectValue = reflect.New(reflectValue.Type().Elem()).Elem()\n\t\t\t\treflectKind = reflectValue.Kind()\n\t\t\t} else {\n\t\t\t\treflectValue = reflectValue.Elem()\n\t\t\t\treflectKind = reflectValue.Kind()\n\t\t\t}\n\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\treflectValue = reflect.New(reflectValue.Type().Elem()).Elem()\n\t\t\treflectKind = reflectValue.Kind()\n\n\t\tdefault:\n\t\t\tgoto exitLoop\n\t\t}\n\t}\n\nexitLoop:\n\tif reflectKind != reflect.Struct {\n\t\treturn nil, gerror.Newf(\n\t\t\t`invalid object kind \"%s\", kind of \"struct\" is required`,\n\t\t\treflectKind,\n\t\t)\n\t}\n\treflectType = reflectValue.Type()\n\treturn &Type{\n\t\tType: reflectType,\n\t}, nil\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_field.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// Tag returns the value associated with key in the tag string. If there is no\n// such key in the tag, Tag returns the empty string.\nfunc (f *Field) Tag(key string) string {\n\ts := f.Field.Tag.Get(key)\n\tif s != \"\" {\n\t\ts = gtag.Parse(s)\n\t}\n\treturn s\n}\n\n// TagLookup returns the value associated with key in the tag string.\n// If the key is present in the tag the value (which may be empty)\n// is returned. Otherwise, the returned value will be the empty string.\n// The ok return value reports whether the value was explicitly set in\n// the tag string. If the tag does not have the conventional format,\n// the value returned by Lookup is unspecified.\nfunc (f *Field) TagLookup(key string) (value string, ok bool) {\n\tvalue, ok = f.Field.Tag.Lookup(key)\n\tif ok && value != \"\" {\n\t\tvalue = gtag.Parse(value)\n\t}\n\treturn\n}\n\n// IsEmbedded returns true if the given field is an anonymous field (embedded)\nfunc (f *Field) IsEmbedded() bool {\n\treturn f.Field.Anonymous\n}\n\n// TagStr returns the tag string of the field.\nfunc (f *Field) TagStr() string {\n\treturn string(f.Field.Tag)\n}\n\n// TagMap returns all the tag of the field along with its value string as map.\nfunc (f *Field) TagMap() map[string]string {\n\tdata := ParseTag(f.TagStr())\n\tfor k, v := range data {\n\t\tdata[k] = utils.StripSlashes(gtag.Parse(v))\n\t}\n\treturn data\n}\n\n// IsExported returns true if the given field is exported.\nfunc (f *Field) IsExported() bool {\n\treturn f.Field.PkgPath == \"\"\n}\n\n// Name returns the name of the given field.\nfunc (f *Field) Name() string {\n\treturn f.Field.Name\n}\n\n// Type returns the type of the given field.\n// Note that this Type is not reflect.Type. If you need reflect.Type, please use Field.Type().Type.\nfunc (f *Field) Type() Type {\n\treturn Type{\n\t\tType: f.Field.Type,\n\t}\n}\n\n// Kind returns the reflect.Kind for Value of Field `f`.\nfunc (f *Field) Kind() reflect.Kind {\n\treturn f.Value.Kind()\n}\n\n// OriginalKind retrieves and returns the original reflect.Kind for Value of Field `f`.\nfunc (f *Field) OriginalKind() reflect.Kind {\n\tvar (\n\t\treflectType = f.Value.Type()\n\t\treflectKind = reflectType.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectType = reflectType.Elem()\n\t\treflectKind = reflectType.Kind()\n\t}\n\n\treturn reflectKind\n}\n\n// OriginalValue retrieves and returns the original reflect.Value of Field `f`.\nfunc (f *Field) OriginalValue() reflect.Value {\n\tvar (\n\t\treflectValue = f.Value\n\t\treflectType  = reflectValue.Type()\n\t\treflectKind  = reflectType.Kind()\n\t)\n\n\tfor reflectKind == reflect.Pointer && !f.IsNil() {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Type().Kind()\n\t}\n\n\treturn reflectValue\n}\n\n// IsEmpty checks and returns whether the value of this Field is empty.\nfunc (f *Field) IsEmpty() bool {\n\treturn empty.IsEmpty(f.Value)\n}\n\n// IsNil checks and returns whether the value of this Field is nil.\nfunc (f *Field) IsNil(traceSource ...bool) bool {\n\treturn empty.IsNil(f.Value, traceSource...)\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_field_tag.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// TagJsonName returns the `json` tag name string of the field.\nfunc (f *Field) TagJsonName() string {\n\tif jsonTag := f.Tag(gtag.Json); jsonTag != \"\" {\n\t\treturn strings.Split(jsonTag, \",\")[0]\n\t}\n\treturn \"\"\n}\n\n// TagDefault returns the most commonly used tag `default/d` value of the field.\nfunc (f *Field) TagDefault() string {\n\tv := f.Tag(gtag.Default)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.DefaultShort)\n\t}\n\treturn v\n}\n\n// TagParam returns the most commonly used tag `param/p` value of the field.\nfunc (f *Field) TagParam() string {\n\tv := f.Tag(gtag.Param)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.ParamShort)\n\t}\n\treturn v\n}\n\n// TagValid returns the most commonly used tag `valid/v` value of the field.\nfunc (f *Field) TagValid() string {\n\tv := f.Tag(gtag.Valid)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.ValidShort)\n\t}\n\treturn v\n}\n\n// TagDescription returns the most commonly used tag `description/des/dc` value of the field.\nfunc (f *Field) TagDescription() string {\n\tv := f.Tag(gtag.Description)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.DescriptionShort)\n\t}\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.DescriptionShort2)\n\t}\n\treturn v\n}\n\n// TagSummary returns the most commonly used tag `summary/sum/sm` value of the field.\nfunc (f *Field) TagSummary() string {\n\tv := f.Tag(gtag.Summary)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.SummaryShort)\n\t}\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.SummaryShort2)\n\t}\n\treturn v\n}\n\n// TagAdditional returns the most commonly used tag `additional/ad` value of the field.\nfunc (f *Field) TagAdditional() string {\n\tv := f.Tag(gtag.Additional)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.AdditionalShort)\n\t}\n\treturn v\n}\n\n// TagExample returns the most commonly used tag `example/eg` value of the field.\nfunc (f *Field) TagExample() string {\n\tv := f.Tag(gtag.Example)\n\tif v == \"\" {\n\t\tv = f.Tag(gtag.ExampleShort)\n\t}\n\treturn v\n}\n\n// TagIn returns the most commonly used tag `in` value of the field.\nfunc (f *Field) TagIn() string {\n\tv := f.Tag(gtag.In)\n\treturn v\n}\n\n// TagPriorityName checks and returns tag name that matches the name item in `gtag.StructTagPriority`.\n// It or else returns attribute field Name if it doesn't have a tag name by `gtag.StructsTagPriority`.\nfunc (f *Field) TagPriorityName() string {\n\tname := f.Name()\n\tfor _, tagName := range gtag.StructTagPriority {\n\t\tif tagValue := f.Tag(tagName); tagValue != \"\" {\n\t\t\t// Strip tag options after comma, e.g., json:\"name,omitempty\" -> \"name\".\n\t\t\ttagValue = strings.Split(tagValue, \",\")[0]\n\t\t\tif tagValue != \"\" {\n\t\t\t\tname = tagValue\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn name\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_tag.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// ParseTag parses tag string into map.\n// For example:\n// ParseTag(`v:\"required\" p:\"id\" d:\"1\"`) => map[v:required p:id d:1].\nfunc ParseTag(tag string) map[string]string {\n\tvar (\n\t\tkey  string\n\t\tdata = make(map[string]string)\n\t)\n\tfor tag != \"\" {\n\t\t// Skip leading space.\n\t\ti := 0\n\t\tfor i < len(tag) && tag[i] == ' ' {\n\t\t\ti++\n\t\t}\n\t\ttag = tag[i:]\n\t\tif tag == \"\" {\n\t\t\tbreak\n\t\t}\n\t\t// Scan to colon. A space, a quote or a control character is a syntax error.\n\t\t// Strictly speaking, control chars include the range [0x7f, 0x9f], not just\n\t\t// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters\n\t\t// as it is simpler to inspect the tag's bytes than the tag's runes.\n\t\ti = 0\n\t\tfor i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '\"' && tag[i] != 0x7f {\n\t\t\ti++\n\t\t}\n\t\tif i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '\"' {\n\t\t\tbreak\n\t\t}\n\t\tkey = tag[:i]\n\t\ttag = tag[i+1:]\n\n\t\t// Scan quoted string to find value.\n\t\ti = 1\n\t\tfor i < len(tag) && tag[i] != '\"' {\n\t\t\tif tag[i] == '\\\\' {\n\t\t\t\ti++\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t\tif i >= len(tag) {\n\t\t\tbreak\n\t\t}\n\t\tquotedValue := tag[:i+1]\n\t\ttag = tag[i+1:]\n\t\tvalue, err := strconv.Unquote(quotedValue)\n\t\tif err != nil {\n\t\t\tpanic(gerror.WrapCodef(gcode.CodeInvalidParameter, err, `error parsing tag \"%s\"`, tag))\n\t\t}\n\t\tdata[key] = gtag.Parse(value)\n\t}\n\treturn data\n}\n\n// TagFields retrieves and returns struct tags as []Field from `pointer`.\n//\n// The parameter `pointer` should be type of struct/*struct.\n//\n// Note that,\n// 1. It only retrieves the exported attributes with first letter upper-case from struct.\n// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.\nfunc TagFields(pointer any, priority []string) ([]Field, error) {\n\treturn getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{})\n}\n\n// TagMapName retrieves and returns struct tags as map[tag]attribute from `pointer`.\n//\n// The parameter `pointer` should be type of struct/*struct.\n//\n// Note that,\n// 1. It only retrieves the exported attributes with first letter upper-case from struct.\n// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.\n// 3. If one field has no specified tag, it uses its field name as result map key.\nfunc TagMapName(pointer any, priority []string) (map[string]string, error) {\n\tfields, err := TagFields(pointer, priority)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttagMap := make(map[string]string, len(fields))\n\tfor _, field := range fields {\n\t\ttagMap[field.TagValue] = field.Name()\n\t}\n\treturn tagMap, nil\n}\n\n// TagMapField retrieves struct tags as map[tag]Field from `pointer`, and returns it.\n// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.\n//\n// Note that,\n// 1. It only retrieves the exported attributes with first letter upper-case from struct.\n// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.\n// 3. If one field has no specified tag, it uses its field name as result map key.\nfunc TagMapField(object any, priority []string) (map[string]Field, error) {\n\tfields, err := TagFields(object, priority)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttagMap := make(map[string]Field, len(fields))\n\tfor _, field := range fields {\n\t\ttagField := field\n\t\ttagMap[field.TagValue] = tagField\n\t}\n\treturn tagMap, nil\n}\n\nfunc getFieldValues(structObject any) ([]Field, error) {\n\tvar (\n\t\treflectValue reflect.Value\n\t\treflectKind  reflect.Kind\n\t)\n\tif v, ok := structObject.(reflect.Value); ok {\n\t\treflectValue = v\n\t\treflectKind = reflectValue.Kind()\n\t} else {\n\t\treflectValue = reflect.ValueOf(structObject)\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tfor {\n\t\tswitch reflectKind {\n\t\tcase reflect.Pointer:\n\t\t\tif !reflectValue.IsValid() || reflectValue.IsNil() {\n\t\t\t\t// If pointer is type of *struct and nil, then automatically create a temporary struct.\n\t\t\t\treflectValue = reflect.New(reflectValue.Type().Elem()).Elem()\n\t\t\t\treflectKind = reflectValue.Kind()\n\t\t\t} else {\n\t\t\t\treflectValue = reflectValue.Elem()\n\t\t\t\treflectKind = reflectValue.Kind()\n\t\t\t}\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\treflectValue = reflect.New(reflectValue.Type().Elem()).Elem()\n\t\t\treflectKind = reflectValue.Kind()\n\t\tdefault:\n\t\t\tgoto exitLoop\n\t\t}\n\t}\n\nexitLoop:\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tif reflectKind != reflect.Struct {\n\t\treturn nil, gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"given value should be either type of struct/*struct/[]struct/[]*struct\",\n\t\t)\n\t}\n\tvar (\n\t\tstructType = reflectValue.Type()\n\t\tlength     = reflectValue.NumField()\n\t\tfields     = make([]Field, length)\n\t)\n\tfor i := 0; i < length; i++ {\n\t\tfields[i] = Field{\n\t\t\tValue: reflectValue.Field(i),\n\t\t\tField: structType.Field(i),\n\t\t}\n\t}\n\treturn fields, nil\n}\n\nfunc getFieldValuesByTagPriority(\n\tpointer any, priority []string, repeatedTagFilteringMap map[string]struct{},\n) ([]Field, error) {\n\tfields, err := getFieldValues(pointer)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\ttagName   string\n\t\ttagValue  string\n\t\ttagFields = make([]Field, 0)\n\t)\n\tfor _, field := range fields {\n\t\t// Only retrieve exported attributes.\n\t\tif !field.IsExported() {\n\t\t\tcontinue\n\t\t}\n\t\ttagValue = \"\"\n\t\tfor _, p := range priority {\n\t\t\ttagName = p\n\t\t\ttagValue = field.Tag(p)\n\t\t\tif tagValue != \"\" && tagValue != \"-\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif tagValue != \"\" {\n\t\t\t// Filter repeated tag.\n\t\t\tif _, ok := repeatedTagFilteringMap[tagValue]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttagField := field\n\t\t\ttagField.TagName = tagName\n\t\t\ttagField.TagValue = tagValue\n\t\t\ttagFields = append(tagFields, tagField)\n\t\t}\n\t\t// If this is an embedded attribute, it retrieves the tags recursively.\n\t\tif field.IsEmbedded() && field.OriginalKind() == reflect.Struct {\n\t\t\tsubTagFields, err := getFieldValuesByTagPriority(field.Value, priority, repeatedTagFilteringMap)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t} else {\n\t\t\t\ttagFields = append(tagFields, subTagFields...)\n\t\t\t}\n\t\t}\n\t}\n\treturn tagFields, nil\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_type.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs\n\n// Signature returns a unique string as this type.\nfunc (t Type) Signature() string {\n\treturn t.PkgPath() + \"/\" + t.String()\n}\n\n// FieldKeys returns the keys of current struct/map.\nfunc (t Type) FieldKeys() []string {\n\tkeys := make([]string, t.NumField())\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tkeys[i] = t.Field(i).Name\n\t}\n\treturn keys\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n)\n\ntype User struct {\n\tId   int\n\tName string `params:\"name\"`\n\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n}\n\nvar (\n\tuser           = new(User)\n\tuserNilPointer *User\n)\n\nfunc Benchmark_ReflectTypeOf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treflect.TypeOf(user).String()\n\t}\n}\n\nfunc Benchmark_TagFields(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgstructs.TagFields(user, []string{\"params\", \"my-tag1\"})\n\t}\n}\n\nfunc Benchmark_TagFields_NilPointer(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgstructs.TagFields(&userNilPointer, []string{\"params\", \"my-tag1\"})\n\t}\n}\n"
  },
  {
    "path": "os/gstructs/gstructs_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstructs_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `params:\"name\"`\n\t\t\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n\t\t}\n\t\tvar user User\n\t\tm, _ := gstructs.TagMapName(user, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"params\", \"my-tag1\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"my-tag1\", \"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass1\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"my-tag2\", \"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass2\": \"Pass\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tPass1 string `params:\"password1\"`\n\t\t\tPass2 string `params:\"password2\"`\n\t\t}\n\t\ttype UserWithBase struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t\tBase `params:\"base\"`\n\t\t}\n\t\tuser := new(UserWithBase)\n\t\tm, _ := gstructs.TagMapName(user, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\n\t\t\t\"base\":      \"Base\",\n\t\t\t\"password1\": \"Pass1\",\n\t\t\t\"password2\": \"Pass2\",\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tPass1 string `params:\"password1\"`\n\t\t\tPass2 string `params:\"password2\"`\n\t\t}\n\t\ttype UserWithEmbeddedAttribute struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t\tBase\n\t\t}\n\t\ttype UserWithoutEmbeddedAttribute struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t\tPass Base\n\t\t}\n\t\tuser1 := new(UserWithEmbeddedAttribute)\n\t\tuser2 := new(UserWithoutEmbeddedAttribute)\n\t\tm, _ := gstructs.TagMapName(user1, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\"password1\": \"Pass1\", \"password2\": \"Pass2\"})\n\t\tm, _ = gstructs.TagMapName(user2, []string{\"params\"})\n\t\tt.Assert(m, g.Map{})\n\t})\n}\n\nfunc Test_StructOfNilPointer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `params:\"name\"`\n\t\t\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n\t\t}\n\t\tvar user *User\n\t\tm, _ := gstructs.TagMapName(user, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"params\", \"my-tag1\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"my-tag1\", \"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass1\": \"Pass\"})\n\t\tm, _ = gstructs.TagMapName(&user, []string{\"my-tag2\", \"params\"})\n\t\tt.Assert(m, g.Map{\"name\": \"Name\", \"pass2\": \"Pass\"})\n\t})\n}\n\nfunc Test_Fields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `params:\"name\"`\n\t\t\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n\t\t}\n\t\tvar user *User\n\t\tfields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         user,\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.Assert(len(fields), 3)\n\t\tt.Assert(fields[0].Name(), \"Id\")\n\t\tt.Assert(fields[1].Name(), \"Name\")\n\t\tt.Assert(fields[1].Tag(\"params\"), \"name\")\n\t\tt.Assert(fields[2].Name(), \"Pass\")\n\t\tt.Assert(fields[2].Tag(\"my-tag1\"), \"pass1\")\n\t\tt.Assert(fields[2].Tag(\"my-tag2\"), \"pass2\")\n\t\tt.Assert(fields[2].Tag(\"params\"), \"pass\")\n\t})\n}\n\nfunc Test_Fields_WithEmbedded1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\ttype A struct {\n\t\t\tSite  string\n\t\t\tB     // Should be put here to validate its index.\n\t\t\tScore int64\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0].Name(), `Site`)\n\t\tt.Assert(r[1].Name(), `Name`)\n\t\tt.Assert(r[2].Name(), `Age`)\n\t\tt.Assert(r[3].Name(), `Score`)\n\t})\n}\n\nfunc Test_Fields_WithEmbedded2(t *testing.T) {\n\ttype MetaNode struct {\n\t\tId          uint   `orm:\"id,primary\"  description:\"\"`\n\t\tCapacity    string `orm:\"capacity\"    description:\"Capacity string\"`\n\t\tAllocatable string `orm:\"allocatable\" description:\"Allocatable string\"`\n\t\tStatus      string `orm:\"status\"      description:\"Status string\"`\n\t}\n\ttype MetaNodeZone struct {\n\t\tNodes    uint\n\t\tClusters uint\n\t\tDisk     uint\n\t\tCpu      uint\n\t\tMemory   uint\n\t\tZone     string\n\t}\n\n\ttype MetaNodeItem struct {\n\t\tMetaNode\n\t\tCapacity    []MetaNodeZone `dc:\"Capacity []MetaNodeZone\"`\n\t\tAllocatable []MetaNodeZone `dc:\"Allocatable []MetaNodeZone\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(MetaNodeItem),\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0].Name(), `Id`)\n\t\tt.Assert(r[1].Name(), `Capacity`)\n\t\tt.Assert(r[1].TagStr(), `dc:\"Capacity []MetaNodeZone\"`)\n\t\tt.Assert(r[2].Name(), `Allocatable`)\n\t\tt.Assert(r[2].TagStr(), `dc:\"Allocatable []MetaNodeZone\"`)\n\t\tt.Assert(r[3].Name(), `Status`)\n\t})\n}\n\n// Filter repeated fields when there is embedded struct.\nfunc Test_Fields_WithEmbedded_Filter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\ttype A struct {\n\t\t\tName  string\n\t\t\tSite  string\n\t\t\tAge   string\n\t\t\tB     // Should be put here to validate its index.\n\t\t\tScore int64\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(r), 4)\n\t\tt.Assert(r[0].Name(), `Name`)\n\t\tt.Assert(r[1].Name(), `Site`)\n\t\tt.Assert(r[2].Name(), `Age`)\n\t\tt.Assert(r[3].Name(), `Score`)\n\t})\n}\n\nfunc Test_FieldMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `params:\"name\"`\n\t\t\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n\t\t}\n\t\tvar user *User\n\t\tm, _ := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\t\tPointer:          user,\n\t\t\tPriorityTagArray: []string{\"params\"},\n\t\t\tRecursiveOption:  gstructs.RecursiveOptionEmbedded,\n\t\t})\n\t\tt.Assert(len(m), 3)\n\t\t_, ok := m[\"Id\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = m[\"Name\"]\n\t\tt.Assert(ok, false)\n\t\t_, ok = m[\"name\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = m[\"Pass\"]\n\t\tt.Assert(ok, false)\n\t\t_, ok = m[\"pass\"]\n\t\tt.Assert(ok, true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `params:\"name\"`\n\t\t\tPass string `my-tag1:\"pass1\" my-tag2:\"pass2\" params:\"pass\"`\n\t\t}\n\t\tvar user *User\n\t\tm, _ := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\t\tPointer:          user,\n\t\t\tPriorityTagArray: nil,\n\t\t\tRecursiveOption:  gstructs.RecursiveOptionEmbedded,\n\t\t})\n\t\tt.Assert(len(m), 3)\n\t\t_, ok := m[\"Id\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = m[\"Name\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = m[\"name\"]\n\t\tt.Assert(ok, false)\n\t\t_, ok = m[\"Pass\"]\n\t\tt.Assert(ok, true)\n\t\t_, ok = m[\"pass\"]\n\t\tt.Assert(ok, false)\n\t})\n}\n\nfunc Test_StructType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tB\n\t\t}\n\t\tr, err := gstructs.StructType(new(A))\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.A`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tB\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).B)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\t*B\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).B)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.String(), `gstructs_test.B`)\n\t})\n\t// Error.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\t*B\n\t\t\tId int\n\t\t}\n\t\t_, err := gstructs.StructType(new(A).Id)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_StructTypeBySlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tArray []*B\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).Array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tArray []B\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).Array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tArray *[]B\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).Array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.Signature(), `github.com/gogf/gf/v2/os/gstructs_test/gstructs_test.B`)\n\t})\n}\n\nfunc TestType_FieldKeys(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tId   int\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tArray []*B\n\t\t}\n\t\tr, err := gstructs.StructType(new(A).Array)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r.FieldKeys(), g.Slice{\"Id\", \"Name\"})\n\t})\n}\n\nfunc TestType_TagMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tId   int    `d:\"123\" description:\"I love gf\"`\n\t\t\tName string `v:\"required\" description:\"应用Id\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagMap()[\"d\"], `123`)\n\t\tt.Assert(r[0].TagMap()[\"description\"], `I love gf`)\n\t\tt.Assert(r[1].TagMap()[\"v\"], `required`)\n\t\tt.Assert(r[1].TagMap()[\"description\"], `应用Id`)\n\t})\n}\n\nfunc TestType_TagJsonName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName string `json:\"name,omitempty\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 1)\n\t\tt.Assert(r[0].TagJsonName(), `name`)\n\t})\n}\n\nfunc TestType_TagDefault(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `default:\"john\"`\n\t\t\tName2 string `d:\"john\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagDefault(), `john`)\n\t\tt.Assert(r[1].TagDefault(), `john`)\n\t})\n}\n\nfunc TestType_TagParam(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `param:\"name\"`\n\t\t\tName2 string `p:\"name\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagParam(), `name`)\n\t\tt.Assert(r[1].TagParam(), `name`)\n\t})\n}\n\nfunc TestType_TagValid(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `valid:\"required\"`\n\t\t\tName2 string `v:\"required\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagValid(), `required`)\n\t\tt.Assert(r[1].TagValid(), `required`)\n\t})\n}\n\nfunc TestType_TagDescription(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `description:\"my name\"`\n\t\t\tName2 string `des:\"my name\"`\n\t\t\tName3 string `dc:\"my name\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0].TagDescription(), `my name`)\n\t\tt.Assert(r[1].TagDescription(), `my name`)\n\t\tt.Assert(r[2].TagDescription(), `my name`)\n\t})\n}\n\nfunc TestType_TagSummary(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `summary:\"my name\"`\n\t\t\tName2 string `sum:\"my name\"`\n\t\t\tName3 string `sm:\"my name\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 3)\n\t\tt.Assert(r[0].TagSummary(), `my name`)\n\t\tt.Assert(r[1].TagSummary(), `my name`)\n\t\tt.Assert(r[2].TagSummary(), `my name`)\n\t})\n}\n\nfunc TestType_TagAdditional(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `additional:\"my name\"`\n\t\t\tName2 string `ad:\"my name\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagAdditional(), `my name`)\n\t\tt.Assert(r[1].TagAdditional(), `my name`)\n\t})\n}\n\nfunc TestType_TagExample(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName  string `example:\"john\"`\n\t\t\tName2 string `eg:\"john\"`\n\t\t}\n\t\tr, err := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         new(A),\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(r), 2)\n\t\tt.Assert(r[0].TagExample(), `john`)\n\t\tt.Assert(r[1].TagExample(), `john`)\n\t})\n}\n\nfunc Test_Fields_TagPriorityName(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName  string `gconv:\"name_gconv\" c:\"name_c\"`\n\t\t\tAge   uint   `p:\"name_p\" param:\"age_param\"`\n\t\t\tPass  string `json:\"pass_json\"`\n\t\t\tIsMen bool\n\t\t}\n\t\tvar user *User\n\t\tfields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         user,\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.Assert(fields[0].TagPriorityName(), \"name_gconv\")\n\t\tt.Assert(fields[1].TagPriorityName(), \"age_param\")\n\t\tt.Assert(fields[2].TagPriorityName(), \"pass_json\")\n\t\tt.Assert(fields[3].TagPriorityName(), \"IsMen\")\n\t})\n\t// Tag with omitempty option should return name only, not \"name,omitempty\".\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName string `json:\"user_name,omitempty\"`\n\t\t\tAge  uint   `gconv:\"age,string\" json:\"age_json\"`\n\t\t}\n\t\tvar user *User\n\t\tfields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         user,\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.Assert(fields[0].TagPriorityName(), \"user_name\")\n\t\tt.Assert(fields[1].TagPriorityName(), \"age\")\n\t})\n\t// Empty tag name with options (e.g., gconv:\",omitempty\") should fallthrough to next priority tag.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tName string `gconv:\",omitempty\" json:\"name_json\"`\n\t\t\tAge  uint   `gconv:\",string\" param:\",omitempty\" json:\"age_json\"`\n\t\t}\n\t\tvar user *User\n\t\tfields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\t\tPointer:         user,\n\t\t\tRecursiveOption: 0,\n\t\t})\n\t\tt.Assert(fields[0].TagPriorityName(), \"name_json\")\n\t\tt.Assert(fields[1].TagPriorityName(), \"age_json\")\n\t})\n}\n"
  },
  {
    "path": "os/gtime/gtime.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtime provides functionality for measuring and displaying time.\n//\n// This package should keep much less dependencies with other packages.\npackage gtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nconst (\n\t// Short writes for common usage durations.\n\n\tD  = 24 * time.Hour\n\tH  = time.Hour\n\tM  = time.Minute\n\tS  = time.Second\n\tMS = time.Millisecond //nolint:staticcheck\n\tUS = time.Microsecond\n\tNS = time.Nanosecond\n\n\t// Regular expression1(datetime separator supports '-', '/', '.').\n\t// Eg:\n\t// \"2017-12-14 04:51:34 +0805 LMT\",\n\t// \"2017-12-14 04:51:34 +0805 LMT\",\n\t// \"2006-01-02T15:04:05Z07:00\",\n\t// \"2014-01-17T01:19:15+08:00\",\n\t// \"2018-02-09T20:46:17.897Z\",\n\t// \"2018-02-09 20:46:17.897\",\n\t// \"2018-02-09T20:46:17Z\",\n\t// \"2018-02-09 20:46:17\",\n\t// \"2018/10/31 - 16:38:46\"\n\t// \"2018-02-09\",\n\t// \"2018.02.09\",\n\ttimeRegexPattern1 = `(\\d{4}[-/\\.]\\d{1,2}[-/\\.]\\d{1,2})[:\\sT-]*(\\d{0,2}:{0,1}\\d{0,2}:{0,1}\\d{0,2}){0,1}\\.{0,1}(\\d{0,9})([\\sZ]{0,1})([\\+-]{0,1})([:\\d]*)`\n\n\t// Regular expression2(datetime separator supports '-', '/', '.').\n\t// Eg:\n\t// 01-Nov-2018 11:50:28\n\t// 01/Nov/2018 11:50:28\n\t// 01.Nov.2018 11:50:28\n\t// 01.Nov.2018:11:50:28\n\ttimeRegexPattern2 = `(\\d{1,2}[-/\\.][A-Za-z]{3,}[-/\\.]\\d{4})[:\\sT-]*(\\d{0,2}:{0,1}\\d{0,2}:{0,1}\\d{0,2}){0,1}\\.{0,1}(\\d{0,9})([\\sZ]{0,1})([\\+-]{0,1})([:\\d]*)`\n\n\t// Regular expression3(time).\n\t// Eg:\n\t// 11:50:28\n\t// 11:50:28.897\n\ttimeRegexPattern3 = `(\\d{2}):(\\d{2}):(\\d{2})\\.{0,1}(\\d{0,9})`\n)\n\nvar (\n\t// It's more high performance using regular expression\n\t// than time.ParseInLocation to parse the datetime string.\n\ttimeRegex1 = regexp.MustCompile(timeRegexPattern1)\n\ttimeRegex2 = regexp.MustCompile(timeRegexPattern2)\n\ttimeRegex3 = regexp.MustCompile(timeRegexPattern3)\n\n\t// Month words to arabic numerals mapping.\n\tmonthMap = map[string]int{\n\t\t\"jan\":       1,\n\t\t\"feb\":       2,\n\t\t\"mar\":       3,\n\t\t\"apr\":       4,\n\t\t\"may\":       5,\n\t\t\"jun\":       6,\n\t\t\"jul\":       7,\n\t\t\"aug\":       8,\n\t\t\"sep\":       9,\n\t\t\"sept\":      9,\n\t\t\"oct\":       10,\n\t\t\"nov\":       11,\n\t\t\"dec\":       12,\n\t\t\"january\":   1,\n\t\t\"february\":  2,\n\t\t\"march\":     3,\n\t\t\"april\":     4,\n\t\t\"june\":      6,\n\t\t\"july\":      7,\n\t\t\"august\":    8,\n\t\t\"september\": 9,\n\t\t\"october\":   10,\n\t\t\"november\":  11,\n\t\t\"december\":  12,\n\t}\n)\n\n// Timestamp retrieves and returns the timestamp in seconds.\nfunc Timestamp() int64 {\n\treturn Now().Timestamp()\n}\n\n// TimestampMilli retrieves and returns the timestamp in milliseconds.\nfunc TimestampMilli() int64 {\n\treturn Now().TimestampMilli()\n}\n\n// TimestampMicro retrieves and returns the timestamp in microseconds.\nfunc TimestampMicro() int64 {\n\treturn Now().TimestampMicro()\n}\n\n// TimestampNano retrieves and returns the timestamp in nanoseconds.\nfunc TimestampNano() int64 {\n\treturn Now().TimestampNano()\n}\n\n// TimestampStr is a convenience method which retrieves and returns\n// the timestamp in seconds as string.\nfunc TimestampStr() string {\n\treturn Now().TimestampStr()\n}\n\n// TimestampMilliStr is a convenience method which retrieves and returns\n// the timestamp in milliseconds as string.\nfunc TimestampMilliStr() string {\n\treturn Now().TimestampMilliStr()\n}\n\n// TimestampMicroStr is a convenience method which retrieves and returns\n// the timestamp in microseconds as string.\nfunc TimestampMicroStr() string {\n\treturn Now().TimestampMicroStr()\n}\n\n// TimestampNanoStr is a convenience method which retrieves and returns\n// the timestamp in nanoseconds as string.\nfunc TimestampNanoStr() string {\n\treturn Now().TimestampNanoStr()\n}\n\n// Date returns current date in string like \"2006-01-02\".\nfunc Date() string {\n\treturn time.Now().Format(\"2006-01-02\")\n}\n\n// Datetime returns current datetime in string like \"2006-01-02 15:04:05\".\nfunc Datetime() string {\n\treturn time.Now().Format(\"2006-01-02 15:04:05\")\n}\n\n// ISO8601 returns current datetime in ISO8601 format like \"2006-01-02T15:04:05-07:00\".\nfunc ISO8601() string {\n\treturn time.Now().Format(\"2006-01-02T15:04:05-07:00\")\n}\n\n// RFC822 returns current datetime in RFC822 format like \"Mon, 02 Jan 06 15:04 MST\".\nfunc RFC822() string {\n\treturn time.Now().Format(\"Mon, 02 Jan 06 15:04 MST\")\n}\n\n// parseDateStr parses the string to year, month and day numbers.\nfunc parseDateStr(s string) (year, month, day int) {\n\tarray := strings.Split(s, \"-\")\n\tif len(array) < 3 {\n\t\tarray = strings.Split(s, \"/\")\n\t}\n\tif len(array) < 3 {\n\t\tarray = strings.Split(s, \".\")\n\t}\n\t// Parsing failed.\n\tif len(array) < 3 {\n\t\treturn\n\t}\n\t// Checking the year in head or tail.\n\tif utils.IsNumeric(array[1]) {\n\t\tyear, _ = strconv.Atoi(array[0])\n\t\tmonth, _ = strconv.Atoi(array[1])\n\t\tday, _ = strconv.Atoi(array[2])\n\t} else {\n\t\tif v, ok := monthMap[strings.ToLower(array[1])]; ok {\n\t\t\tmonth = v\n\t\t} else {\n\t\t\treturn\n\t\t}\n\t\tyear, _ = strconv.Atoi(array[2])\n\t\tday, _ = strconv.Atoi(array[0])\n\t}\n\treturn\n}\n\n// StrToTime converts string to *Time object. It also supports timestamp string.\n// The parameter `format` is unnecessary, which specifies the format for converting like \"Y-m-d H:i:s\".\n// If `format` is given, it acts as same as function StrToTimeFormat.\n// If `format` is not given, it converts string as a \"standard\" datetime string.\n// Note that, it fails and returns error if there's no date string in `str`.\nfunc StrToTime(str string, format ...string) (*Time, error) {\n\tif str == \"\" {\n\t\treturn &Time{wrapper{time.Time{}}}, nil\n\t}\n\tif len(format) > 0 {\n\t\treturn StrToTimeFormat(str, format[0])\n\t}\n\tif isTimestampStr(str) {\n\t\ttimestamp, _ := strconv.ParseInt(str, 10, 64)\n\t\treturn NewFromTimeStamp(timestamp), nil\n\t}\n\tvar (\n\t\tyear, month, day     int\n\t\thour, min, sec, nsec int\n\t\tmatch                []string\n\t\tlocal                = time.Local\n\t)\n\tif match = timeRegex1.FindStringSubmatch(str); len(match) > 0 && match[1] != \"\" {\n\t\tyear, month, day = parseDateStr(match[1])\n\t} else if match = timeRegex2.FindStringSubmatch(str); len(match) > 0 && match[1] != \"\" {\n\t\tyear, month, day = parseDateStr(match[1])\n\t} else if match = timeRegex3.FindStringSubmatch(str); len(match) > 0 && match[1] != \"\" {\n\t\thour, _ = strconv.Atoi(match[1])\n\t\tmin, _ = strconv.Atoi(match[2])\n\t\tsec, _ = strconv.Atoi(match[3])\n\t\tnsec, _ = strconv.Atoi(match[4])\n\t\tif hour > 23 || min > 59 || sec > 59 {\n\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time string \"%s\"`, str)\n\t\t}\n\t\tfor i := 0; i < 9-len(match[4]); i++ {\n\t\t\tnsec *= 10\n\t\t}\n\t\treturn NewFromTime(time.Date(0, time.Month(1), 1, hour, min, sec, nsec, local)), nil\n\t} else {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported time converting for string \"%s\"`, str)\n\t}\n\n\t// Time\n\tif len(match[2]) > 0 {\n\t\tparts := strings.Split(match[2], \":\")\n\t\tif len(parts) >= 1 && parts[0] != \"\" {\n\t\t\thour, _ = strconv.Atoi(parts[0])\n\t\t}\n\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\tmin, _ = strconv.Atoi(parts[1])\n\t\t}\n\t\tif len(parts) >= 3 && parts[2] != \"\" {\n\t\t\tsec, _ = strconv.Atoi(parts[2])\n\t\t}\n\t\tif hour > 23 || min > 59 || sec > 59 {\n\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time string \"%s\"`, str)\n\t\t}\n\t}\n\t// Nanoseconds, check and perform bits filling\n\tif len(match[3]) > 0 {\n\t\tnsec, _ = strconv.Atoi(match[3])\n\t\tfor i := 0; i < 9-len(match[3]); i++ {\n\t\t\tnsec *= 10\n\t\t}\n\t}\n\t// If there's zone information in the string,\n\t// it then performs time zone conversion, which converts the time zone to UTC.\n\tif match[4] != \"\" && match[6] == \"\" {\n\t\tmatch[6] = \"000000\"\n\t}\n\t// If there's offset in the string, it then firstly processes the offset.\n\tif match[6] != \"\" {\n\t\tzone := strings.ReplaceAll(match[6], \":\", \"\")\n\t\tzone = strings.TrimLeft(zone, \"+-\")\n\t\tif len(zone) <= 6 {\n\t\t\tzone += strings.Repeat(\"0\", 6-len(zone))\n\t\t\th, _ := strconv.Atoi(zone[0:2])\n\t\t\tm, _ := strconv.Atoi(zone[2:4])\n\t\t\ts, _ := strconv.Atoi(zone[4:6])\n\t\t\tif h > 24 || m > 59 || s > 59 {\n\t\t\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid zone string \"%s\"`, match[6])\n\t\t\t}\n\t\t\toperation := match[5]\n\t\t\tif operation != \"+\" && operation != \"-\" {\n\t\t\t\toperation = \"-\"\n\t\t\t}\n\t\t\t// Comparing the given time zone whether equals to current time zone,\n\t\t\t_, localOffset := time.Now().Zone()\n\t\t\tzoneOffset := h*3600 + m*60 + s\n\t\t\tif operation == \"-\" {\n\t\t\t\tzoneOffset = -zoneOffset\n\t\t\t}\n\t\t\t// Comparing in seconds.\n\t\t\tif localOffset != zoneOffset {\n\t\t\t\tlocal = time.FixedZone(\"\", zoneOffset)\n\t\t\t}\n\t\t}\n\t}\n\tif month <= 0 || day <= 0 {\n\t\treturn nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time string \"%s\"`, str)\n\t}\n\treturn NewFromTime(time.Date(year, time.Month(month), day, hour, min, sec, nsec, local)), nil\n}\n\n// ConvertZone converts time in string `strTime` from `fromZone` to `toZone`.\n// The parameter `fromZone` is unnecessary, it is current time zone in default.\nfunc ConvertZone(strTime string, toZone string, fromZone ...string) (*Time, error) {\n\tt, err := StrToTime(strTime)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar l *time.Location\n\tif len(fromZone) > 0 {\n\t\tif l, err = time.LoadLocation(fromZone[0]); err != nil {\n\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for name \"%s\"`, fromZone[0])\n\t\t\treturn nil, err\n\t\t} else {\n\t\t\tt.Time = time.Date(t.Year(), time.Month(t.Month()), t.Day(), t.Hour(), t.Minute(), t.Time.Second(), t.Time.Nanosecond(), l)\n\t\t}\n\t}\n\tif l, err = time.LoadLocation(toZone); err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for name \"%s\"`, toZone)\n\t\treturn nil, err\n\t} else {\n\t\treturn t.ToLocation(l), nil\n\t}\n}\n\n// StrToTimeFormat parses string `str` to *Time object with given format `format`.\n// The parameter `format` is like \"Y-m-d H:i:s\".\nfunc StrToTimeFormat(str string, format string) (*Time, error) {\n\treturn StrToTimeLayout(str, formatToStdLayout(format))\n}\n\n// StrToTimeLayout parses string `str` to *Time object with given format `layout`.\n// The parameter `layout` is in stdlib format like \"2006-01-02 15:04:05\".\nfunc StrToTimeLayout(str string, layout string) (*Time, error) {\n\tif t, err := time.ParseInLocation(layout, str, time.Local); err == nil {\n\t\treturn NewFromTime(t), nil\n\t} else {\n\t\treturn nil, gerror.WrapCodef(\n\t\t\tgcode.CodeInvalidParameter, err,\n\t\t\t`time.ParseInLocation failed for layout \"%s\" and value \"%s\"`,\n\t\t\tlayout, str,\n\t\t)\n\t}\n}\n\n// ParseTimeFromContent retrieves time information for content string, it then parses and returns it\n// as *Time object.\n// It returns the first time information if there are more than one time string in the content.\n// It only retrieves and parses the time information with given first matched `format` if it's passed.\nfunc ParseTimeFromContent(content string, format ...string) *Time {\n\tvar (\n\t\terr   error\n\t\tmatch []string\n\t)\n\tif len(format) > 0 {\n\t\tfor _, item := range format {\n\t\t\tmatch, err = gregex.MatchString(formatToRegexPattern(item), content)\n\t\t\tif err != nil {\n\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t}\n\t\t\tif len(match) > 0 {\n\t\t\t\treturn NewFromStrFormat(match[0], item)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif match = timeRegex1.FindStringSubmatch(content); len(match) >= 1 {\n\t\t\treturn NewFromStr(strings.Trim(match[0], \"./_- \\n\\r\"))\n\t\t} else if match = timeRegex2.FindStringSubmatch(content); len(match) >= 1 {\n\t\t\treturn NewFromStr(strings.Trim(match[0], \"./_- \\n\\r\"))\n\t\t} else if match = timeRegex3.FindStringSubmatch(content); len(match) >= 1 {\n\t\t\treturn NewFromStr(strings.Trim(match[0], \"./_- \\n\\r\"))\n\t\t}\n\t}\n\treturn nil\n}\n\n// ParseDuration parses a duration string.\n// A duration string is a possibly signed sequence of\n// decimal numbers, each with optional fraction and a unit suffix,\n// such as \"300ms\", \"-1.5h\", \"1d\" or \"2h45m\".\n// Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\", \"d\".\n//\n// Very note that it supports unit \"d\" more than function time.ParseDuration.\nfunc ParseDuration(s string) (duration time.Duration, err error) {\n\tvar num int64\n\tif utils.IsNumeric(s) {\n\t\tnum, err = strconv.ParseInt(s, 10, 64)\n\t\tif err != nil {\n\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.ParseInt failed for string \"%s\"`, s)\n\t\t\treturn 0, err\n\t\t}\n\t\treturn time.Duration(num), nil\n\t}\n\tmatch, err := gregex.MatchString(`^([\\-\\d]+)[dD](.*)$`, s)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif len(match) == 3 {\n\t\tnum, err = strconv.ParseInt(match[1], 10, 64)\n\t\tif err != nil {\n\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.ParseInt failed for string \"%s\"`, match[1])\n\t\t\treturn 0, err\n\t\t}\n\t\ts = fmt.Sprintf(`%dh%s`, num*24, match[2])\n\t\tduration, err = time.ParseDuration(s)\n\t\tif err != nil {\n\t\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.ParseDuration failed for string \"%s\"`, s)\n\t\t}\n\t\treturn\n\t}\n\tduration, err = time.ParseDuration(s)\n\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.ParseDuration failed for string \"%s\"`, s)\n\treturn\n}\n\n// FuncCost calculates the cost time of function `f` in nanoseconds.\nfunc FuncCost(f func()) time.Duration {\n\tt := time.Now()\n\tf()\n\treturn time.Since(t)\n}\n\n// isTimestampStr checks and returns whether given string a timestamp string.\nfunc isTimestampStr(s string) bool {\n\tlength := len(s)\n\tif length == 0 {\n\t\treturn false\n\t}\n\tfor i := 0; i < len(s); i++ {\n\t\tif s[i] < '0' || s[i] > '9' {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "os/gtime/gtime_format.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime\n\nimport (\n\t\"bytes\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nvar (\n\t// Refer: http://php.net/manual/en/function.date.php\n\tformats = map[byte]string{\n\t\t'd': \"02\",                        // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31.\n\t\t'D': \"Mon\",                       // Day: A textual representation of a day, three letters. Eg: Mon through Sun.\n\t\t'w': \"Monday\",                    // Day: Numeric representation of the day of the week. Eg: 0 (for Sunday) through 6 (for Saturday).\n\t\t'N': \"Monday\",                    // Day: ISO-8601 numeric representation of the day of the week. Eg: 1 (for Monday) through 7 (for Sunday).\n\t\t'j': \"=j=02\",                     // Day: Day of the month without leading zeros. Eg: 1 to 31.\n\t\t'S': \"02\",                        // Day: English ordinal suffix for the day of the month, 2 characters. Eg: st, nd, rd or th. Works well with j.\n\t\t'l': \"Monday\",                    // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday.\n\t\t'z': \"\",                          // Day: The day of the year (starting from 0). Eg: 0 through 365.\n\t\t'W': \"\",                          // Week: ISO-8601 week number of year, weeks starting on Monday. Eg: 42 (the 42nd week in the year).\n\t\t'F': \"January\",                   // Month: A full textual representation of a month, such as January or March. Eg: January through December.\n\t\t'm': \"01\",                        // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12.\n\t\t'M': \"Jan\",                       // Month: A short textual representation of a month, three letters. Eg: Jan through Dec.\n\t\t'n': \"1\",                         // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12.\n\t\t't': \"\",                          // Month: Number of days in the given month. Eg: 28 through 31.\n\t\t'Y': \"2006\",                      // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003.\n\t\t'y': \"06\",                        // Year: A two-digit representation of a year. Eg: 99 or 03.\n\t\t'a': \"pm\",                        // Time: Lowercase Ante meridiem and Post meridiem. Eg: am or pm.\n\t\t'A': \"PM\",                        // Time: Uppercase Ante meridiem and Post meridiem. Eg: AM or PM.\n\t\t'g': \"3\",                         // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12.\n\t\t'G': \"=G=15\",                     // Time: 24-hour format of an hour without leading zeros. Eg: 0 through 23.\n\t\t'h': \"03\",                        // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12.\n\t\t'H': \"15\",                        // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23.\n\t\t'i': \"04\",                        // Time: Minutes with leading zeros. Eg: 00 to 59.\n\t\t's': \"05\",                        // Time: Seconds with leading zeros. Eg: 00 through 59.\n\t\t'u': \"=u=.000\",                   // Time: Milliseconds. Eg: 234, 678.\n\t\t'U': \"\",                          // Time: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).\n\t\t'O': \"-0700\",                     // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200.\n\t\t'P': \"-07:00\",                    // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00.\n\t\t'T': \"MST\",                       // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ...\n\t\t'c': \"2006-01-02T15:04:05-07:00\", // Format: ISO 8601 date. Eg: 2004-02-12T15:19:21+00:00.\n\t\t'r': \"Mon, 02 Jan 06 15:04 MST\",  // Format: RFC 2822 formatted date. Eg: Thu, 21 Dec 2000 16:01:07 +0200.\n\t}\n\n\t// Week to number mapping.\n\tweekMap = map[string]string{\n\t\t\"Sunday\":    \"0\",\n\t\t\"Monday\":    \"1\",\n\t\t\"Tuesday\":   \"2\",\n\t\t\"Wednesday\": \"3\",\n\t\t\"Thursday\":  \"4\",\n\t\t\"Friday\":    \"5\",\n\t\t\"Saturday\":  \"6\",\n\t}\n\n\t// Day count of each month which is not in leap year.\n\tdayOfMonth = []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}\n)\n\n// Format formats and returns the formatted result with custom `format`.\n// Refer method Layout if you want to follow stdlib layout.\nfunc (t *Time) Format(format string) string {\n\tif t == nil {\n\t\treturn \"\"\n\t}\n\trunes := []rune(format)\n\tbuffer := bytes.NewBuffer(nil)\n\tfor i := 0; i < len(runes); {\n\t\tswitch runes[i] {\n\t\tcase '\\\\':\n\t\t\tif i < len(runes)-1 {\n\t\t\t\tbuffer.WriteRune(runes[i+1])\n\t\t\t\ti += 2\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn buffer.String()\n\t\t\t}\n\t\tcase 'W':\n\t\t\tbuffer.WriteString(strconv.Itoa(t.WeeksOfYear()))\n\t\tcase 'z':\n\t\t\tbuffer.WriteString(strconv.Itoa(t.DayOfYear()))\n\t\tcase 't':\n\t\t\tbuffer.WriteString(strconv.Itoa(t.DaysInMonth()))\n\t\tcase 'U':\n\t\t\tbuffer.WriteString(strconv.FormatInt(t.Unix(), 10))\n\t\tdefault:\n\t\t\tif runes[i] > 255 {\n\t\t\t\tbuffer.WriteRune(runes[i])\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif f, ok := formats[byte(runes[i])]; ok {\n\t\t\t\tresult := t.Time.Format(f)\n\t\t\t\t// Particular chars should be handled here.\n\t\t\t\tswitch runes[i] {\n\t\t\t\tcase 'j':\n\t\t\t\t\tfor _, s := range []string{\"=j=0\", \"=j=\"} {\n\t\t\t\t\t\tresult = strings.ReplaceAll(result, s, \"\")\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.WriteString(result)\n\t\t\t\tcase 'G':\n\t\t\t\t\tfor _, s := range []string{\"=G=0\", \"=G=\"} {\n\t\t\t\t\t\tresult = strings.ReplaceAll(result, s, \"\")\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.WriteString(result)\n\t\t\t\tcase 'u':\n\t\t\t\t\tbuffer.WriteString(strings.ReplaceAll(result, \"=u=.\", \"\"))\n\t\t\t\tcase 'w':\n\t\t\t\t\tbuffer.WriteString(weekMap[result])\n\t\t\t\tcase 'N':\n\t\t\t\t\tbuffer.WriteString(strings.ReplaceAll(weekMap[result], \"0\", \"7\"))\n\t\t\t\tcase 'S':\n\t\t\t\t\tbuffer.WriteString(formatMonthDaySuffixMap(result))\n\t\t\t\tdefault:\n\t\t\t\t\tbuffer.WriteString(result)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbuffer.WriteRune(runes[i])\n\t\t\t}\n\t\t}\n\t\ti++\n\t}\n\treturn buffer.String()\n}\n\n// FormatNew formats and returns a new Time object with given custom `format`.\nfunc (t *Time) FormatNew(format string) *Time {\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn NewFromStr(t.Format(format))\n}\n\n// FormatTo formats `t` with given custom `format`.\nfunc (t *Time) FormatTo(format string) *Time {\n\tif t == nil {\n\t\treturn nil\n\t}\n\tt.Time = NewFromStr(t.Format(format)).Time\n\treturn t\n}\n\n// Layout formats the time with stdlib layout and returns the formatted result.\nfunc (t *Time) Layout(layout string) string {\n\tif t == nil {\n\t\treturn \"\"\n\t}\n\treturn t.Time.Format(layout)\n}\n\n// LayoutNew formats the time with stdlib layout and returns the new Time object.\nfunc (t *Time) LayoutNew(layout string) *Time {\n\tif t == nil {\n\t\treturn nil\n\t}\n\tnewTime, err := StrToTimeLayout(t.Layout(layout), layout)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn newTime\n}\n\n// LayoutTo formats `t` with stdlib layout.\nfunc (t *Time) LayoutTo(layout string) *Time {\n\tif t == nil {\n\t\treturn nil\n\t}\n\tnewTime, err := StrToTimeLayout(t.Layout(layout), layout)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tt.Time = newTime.Time\n\treturn t\n}\n\n// IsLeapYear checks whether the time is leap year.\nfunc (t *Time) IsLeapYear() bool {\n\tyear := t.Year()\n\tif (year%4 == 0 && year%100 != 0) || year%400 == 0 {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// DayOfYear checks and returns the position of the day for the year.\nfunc (t *Time) DayOfYear() int {\n\tvar (\n\t\tday   = t.Day()\n\t\tmonth = t.Month()\n\t)\n\tif t.IsLeapYear() {\n\t\tif month > 2 {\n\t\t\treturn dayOfMonth[month-1] + day\n\t\t}\n\t\treturn dayOfMonth[month-1] + day - 1\n\t}\n\treturn dayOfMonth[month-1] + day - 1\n}\n\n// DaysInMonth returns the day count of the current month.\nfunc (t *Time) DaysInMonth() int {\n\tswitch t.Month() {\n\tcase 1, 3, 5, 7, 8, 10, 12:\n\t\treturn 31\n\tcase 4, 6, 9, 11:\n\t\treturn 30\n\t}\n\tif t.IsLeapYear() {\n\t\treturn 29\n\t}\n\treturn 28\n}\n\n// WeeksOfYear returns the point of current week for the year.\nfunc (t *Time) WeeksOfYear() int {\n\t_, week := t.ISOWeek()\n\treturn week\n}\n\n// formatToStdLayout converts the custom format to stdlib layout.\nfunc formatToStdLayout(format string) string {\n\tb := bytes.NewBuffer(nil)\n\tfor i := 0; i < len(format); {\n\t\tswitch format[i] {\n\t\tcase '\\\\':\n\t\t\tif i < len(format)-1 {\n\t\t\t\tb.WriteByte(format[i+1])\n\t\t\t\ti += 2\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn b.String()\n\t\t\t}\n\n\t\tdefault:\n\t\t\tif f, ok := formats[format[i]]; ok {\n\t\t\t\t// Handle particular chars.\n\t\t\t\tswitch format[i] {\n\t\t\t\tcase 'j':\n\t\t\t\t\tb.WriteString(\"2\")\n\t\t\t\tcase 'G':\n\t\t\t\t\tb.WriteString(\"15\")\n\t\t\t\tcase 'u':\n\t\t\t\t\tif i > 0 && format[i-1] == '.' {\n\t\t\t\t\t\tb.WriteString(\"000\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tb.WriteString(\".000\")\n\t\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tb.WriteString(f)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tb.WriteByte(format[i])\n\t\t\t}\n\t\t\ti++\n\t\t}\n\t}\n\treturn b.String()\n}\n\n// formatToRegexPattern converts the custom format to its corresponding regular expression.\nfunc formatToRegexPattern(format string) string {\n\ts := regexp.QuoteMeta(formatToStdLayout(format))\n\ts, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)\n\ts, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)\n\ts, _ = gregex.ReplaceString(`\\s+`, `\\s+`, s)\n\treturn s\n}\n\n// formatMonthDaySuffixMap returns the short english word for current day.\nfunc formatMonthDaySuffixMap(day string) string {\n\tswitch day {\n\tcase \"01\", \"21\", \"31\":\n\t\treturn \"st\"\n\tcase \"02\", \"22\":\n\t\treturn \"nd\"\n\tcase \"03\", \"23\":\n\t\treturn \"rd\"\n\tdefault:\n\t\treturn \"th\"\n\t}\n}\n"
  },
  {
    "path": "os/gtime/gtime_sql.go",
    "content": "package gtime\n\nimport (\n\t\"database/sql/driver\"\n)\n\n// Scan implements interface used by Scan in package database/sql for Scanning value\n// from database to local golang variable.\nfunc (t *Time) Scan(value any) error {\n\tif t == nil {\n\t\treturn nil\n\t}\n\tnewTime := New(value)\n\t*t = *newTime\n\treturn nil\n}\n\n// Value is the interface providing the Value method for package database/sql/driver\n// for retrieving value from golang variable to database.\nfunc (t *Time) Value() (driver.Value, error) {\n\tif t == nil {\n\t\treturn nil, nil\n\t}\n\tif t.IsZero() {\n\t\treturn nil, nil\n\t}\n\n\tif t.Year() == 0 {\n\t\t// Only time.\n\t\treturn t.Format(\"15:04:05\"), nil\n\t}\n\n\treturn t.Time, nil\n}\n"
  },
  {
    "path": "os/gtime/gtime_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Time is a wrapper for time.Time for additional features.\ntype Time struct {\n\twrapper\n}\n\n// iUnixNano is an interface definition commonly for custom time.Time wrapper.\ntype iUnixNano interface {\n\tUnixNano() int64\n}\n\n// New creates and returns a Time object with given parameter.\n// The optional parameter is the time object which can be type of: time.Time/*time.Time, string or integer.\n// Example:\n// New(\"2024-10-29\")\n// New(1390876568)\n// New(t) // The t is type of time.Time.\nfunc New(param ...any) *Time {\n\tif len(param) > 0 {\n\t\tswitch r := param[0].(type) {\n\t\tcase time.Time:\n\t\t\treturn NewFromTime(r)\n\n\t\tcase *time.Time:\n\t\t\tif r != nil {\n\t\t\t\treturn NewFromTime(*r)\n\t\t\t}\n\n\t\tcase Time:\n\t\t\treturn &r\n\n\t\tcase *Time:\n\t\t\treturn r\n\n\t\tcase string:\n\t\t\tif len(param) > 1 {\n\t\t\t\tswitch t := param[1].(type) {\n\t\t\t\tcase string:\n\t\t\t\t\treturn NewFromStrFormat(r, t)\n\t\t\t\tcase []byte:\n\t\t\t\t\treturn NewFromStrFormat(r, string(t))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn NewFromStr(r)\n\n\t\tcase []byte:\n\t\t\tif len(param) > 1 {\n\t\t\t\tswitch t := param[1].(type) {\n\t\t\t\tcase string:\n\t\t\t\t\treturn NewFromStrFormat(string(r), t)\n\t\t\t\tcase []byte:\n\t\t\t\t\treturn NewFromStrFormat(string(r), string(t))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn NewFromStr(string(r))\n\n\t\tcase int:\n\t\t\treturn NewFromTimeStamp(int64(r))\n\n\t\tcase int64:\n\t\t\treturn NewFromTimeStamp(r)\n\n\t\tdefault:\n\t\t\tif v, ok := r.(iUnixNano); ok {\n\t\t\t\treturn NewFromTimeStamp(v.UnixNano())\n\t\t\t}\n\t\t}\n\t}\n\treturn &Time{\n\t\twrapper{time.Time{}},\n\t}\n}\n\n// Now creates and returns a time object of now.\nfunc Now() *Time {\n\treturn &Time{\n\t\twrapper{time.Now()},\n\t}\n}\n\n// NewFromTime creates and returns a Time object with given time.Time object.\nfunc NewFromTime(t time.Time) *Time {\n\treturn &Time{\n\t\twrapper{t},\n\t}\n}\n\n// NewFromStr creates and returns a Time object with given string.\n// Note that it returns nil if there's error occurs.\nfunc NewFromStr(str string) *Time {\n\tif t, err := StrToTime(str); err == nil {\n\t\treturn t\n\t}\n\treturn nil\n}\n\n// NewFromStrFormat creates and returns a Time object with given string and\n// custom format like: Y-m-d H:i:s.\n// Note that it returns nil if there's error occurs.\nfunc NewFromStrFormat(str string, format string) *Time {\n\tif t, err := StrToTimeFormat(str, format); err == nil {\n\t\treturn t\n\t}\n\treturn nil\n}\n\n// NewFromStrLayout creates and returns a Time object with given string and\n// stdlib layout like: 2006-01-02 15:04:05.\n// Note that it returns nil if there's error occurs.\nfunc NewFromStrLayout(str string, layout string) *Time {\n\tif t, err := StrToTimeLayout(str, layout); err == nil {\n\t\treturn t\n\t}\n\treturn nil\n}\n\n// NewFromTimeStamp creates and returns a Time object with given timestamp,\n// which can be in seconds to nanoseconds.\n// Eg: 1600443866 and 1600443866199266000 are both considered as valid timestamp number.\nfunc NewFromTimeStamp(timestamp int64) *Time {\n\tif timestamp == 0 {\n\t\treturn &Time{}\n\t}\n\tvar sec, nano int64\n\tif timestamp > 1e9 {\n\t\tfor timestamp < 1e18 {\n\t\t\ttimestamp *= 10\n\t\t}\n\t\tsec = timestamp / 1e9\n\t\tnano = timestamp % 1e9\n\t} else {\n\t\tsec = timestamp\n\t}\n\treturn &Time{\n\t\twrapper{time.Unix(sec, nano)},\n\t}\n}\n\n// Timestamp returns the timestamp in seconds.\nfunc (t *Time) Timestamp() int64 {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.UnixNano() / 1e9\n}\n\n// TimestampMilli returns the timestamp in milliseconds.\nfunc (t *Time) TimestampMilli() int64 {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.UnixNano() / 1e6\n}\n\n// TimestampMicro returns the timestamp in microseconds.\nfunc (t *Time) TimestampMicro() int64 {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.UnixNano() / 1e3\n}\n\n// TimestampNano returns the timestamp in nanoseconds.\nfunc (t *Time) TimestampNano() int64 {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.UnixNano()\n}\n\n// TimestampStr is a convenience method which retrieves and returns\n// the timestamp in seconds as string.\nfunc (t *Time) TimestampStr() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\treturn strconv.FormatInt(t.Timestamp(), 10)\n}\n\n// TimestampMilliStr is a convenience method which retrieves and returns\n// the timestamp in milliseconds as string.\nfunc (t *Time) TimestampMilliStr() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\treturn strconv.FormatInt(t.TimestampMilli(), 10)\n}\n\n// TimestampMicroStr is a convenience method which retrieves and returns\n// the timestamp in microseconds as string.\nfunc (t *Time) TimestampMicroStr() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\treturn strconv.FormatInt(t.TimestampMicro(), 10)\n}\n\n// TimestampNanoStr is a convenience method which retrieves and returns\n// the timestamp in nanoseconds as string.\nfunc (t *Time) TimestampNanoStr() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\treturn strconv.FormatInt(t.TimestampNano(), 10)\n}\n\n// Month returns the month of the year specified by t.\nfunc (t *Time) Month() int {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn int(t.Time.Month())\n}\n\n// Second returns the second offset within the minute specified by t,\n// in the range [0, 59].\nfunc (t *Time) Second() int {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.Time.Second()\n}\n\n// Millisecond returns the millisecond offset within the second specified by t,\n// in the range [0, 999].\nfunc (t *Time) Millisecond() int {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.Time.Nanosecond() / 1e6\n}\n\n// Microsecond returns the microsecond offset within the second specified by t,\n// in the range [0, 999999].\nfunc (t *Time) Microsecond() int {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.Time.Nanosecond() / 1e3\n}\n\n// Nanosecond returns the nanosecond offset within the second specified by t,\n// in the range [0, 999999999].\nfunc (t *Time) Nanosecond() int {\n\tif t.IsZero() {\n\t\treturn 0\n\t}\n\treturn t.Time.Nanosecond()\n}\n\n// String returns current time object as string.\nfunc (t *Time) String() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\treturn t.wrapper.String()\n}\n\n// IsZero reports whether t represents the zero time instant,\n// January 1, year 1, 00:00:00 UTC.\nfunc (t *Time) IsZero() bool {\n\tif t == nil {\n\t\treturn true\n\t}\n\treturn t.Time.IsZero()\n}\n\n// Clone returns a new Time object which is a clone of current time object.\nfunc (t *Time) Clone() *Time {\n\treturn New(t.Time)\n}\n\n// Add adds the duration to current time.\nfunc (t *Time) Add(d time.Duration) *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.Add(d)\n\treturn newTime\n}\n\n// AddStr parses the given duration as string and adds it to current time.\nfunc (t *Time) AddStr(duration string) (*Time, error) {\n\tif d, err := time.ParseDuration(duration); err != nil {\n\t\terr = gerror.Wrapf(err, `time.ParseDuration failed for string \"%s\"`, duration)\n\t\treturn nil, err\n\t} else {\n\t\treturn t.Add(d), nil\n\t}\n}\n\n// UTC converts current time to UTC timezone.\nfunc (t *Time) UTC() *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.UTC()\n\treturn newTime\n}\n\n// ISO8601 formats the time as ISO8601 and returns it as string.\nfunc (t *Time) ISO8601() string {\n\treturn t.Layout(\"2006-01-02T15:04:05-07:00\")\n}\n\n// RFC822 formats the time as RFC822 and returns it as string.\nfunc (t *Time) RFC822() string {\n\treturn t.Layout(\"Mon, 02 Jan 06 15:04 MST\")\n}\n\n// AddDate adds year, month and day to the time.\nfunc (t *Time) AddDate(years int, months int, days int) *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.AddDate(years, months, days)\n\treturn newTime\n}\n\n// Round returns the result of rounding t to the nearest multiple of d (since the zero time).\n// The rounding behavior for halfway values is to round up.\n// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged.\n//\n// Round operates on the time as an absolute duration since the\n// zero time; it does not operate on the presentation form of the\n// time. Thus, Round(Hour) may return a time with a non-zero\n// minute, depending on the time's Location.\nfunc (t *Time) Round(d time.Duration) *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.Round(d)\n\treturn newTime\n}\n\n// Truncate returns the result of rounding t down to a multiple of d (since the zero time).\n// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged.\n//\n// Truncate operates on the time as an absolute duration since the\n// zero time; it does not operate on the presentation form of the\n// time. Thus, Truncate(Hour) may return a time with a non-zero\n// minute, depending on the time's Location.\nfunc (t *Time) Truncate(d time.Duration) *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.Truncate(d)\n\treturn newTime\n}\n\n// Equal reports whether t and u represent the same time instant.\n// Two times can be equal even if they are in different locations.\n// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.\n// See the documentation on the Time type for the pitfalls of using == with\n// Time values; most code should use Equal instead.\nfunc (t *Time) Equal(u *Time) bool {\n\tswitch {\n\tcase t == nil && u != nil:\n\t\treturn false\n\tcase t == nil && u == nil:\n\t\treturn true\n\tcase t != nil && u == nil:\n\t\treturn false\n\tdefault:\n\t\treturn t.Time.Equal(u.Time)\n\t}\n}\n\n// Before reports whether the time instant t is before u.\nfunc (t *Time) Before(u *Time) bool {\n\treturn t.Time.Before(u.Time)\n}\n\n// After reports whether the time instant t is after u.\nfunc (t *Time) After(u *Time) bool {\n\tswitch {\n\tcase t == nil:\n\t\treturn false\n\tcase t != nil && u == nil:\n\t\treturn true\n\tdefault:\n\t\treturn t.Time.After(u.Time)\n\t}\n}\n\n// Sub returns the duration t-u. If the result exceeds the maximum (or minimum)\n// value that can be stored in a Duration, the maximum (or minimum) duration\n// will be returned.\n// To compute t-d for a duration d, use t.Add(-d).\nfunc (t *Time) Sub(u *Time) time.Duration {\n\tif t == nil || u == nil {\n\t\treturn 0\n\t}\n\treturn t.Time.Sub(u.Time)\n}\n\n// StartOfMinute clones and returns a new time of which the seconds is set to 0.\nfunc (t *Time) StartOfMinute() *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.Truncate(time.Minute)\n\treturn newTime\n}\n\n// StartOfHour clones and returns a new time of which the hour, minutes and seconds are set to 0.\nfunc (t *Time) StartOfHour() *Time {\n\ty, m, d := t.Date()\n\tnewTime := t.Clone()\n\tnewTime.Time = time.Date(y, m, d, newTime.Hour(), 0, 0, 0, newTime.Location())\n\treturn newTime\n}\n\n// StartOfDay clones and returns a new time which is the start of day, its time is set to 00:00:00.\nfunc (t *Time) StartOfDay() *Time {\n\ty, m, d := t.Date()\n\tnewTime := t.Clone()\n\tnewTime.Time = time.Date(y, m, d, 0, 0, 0, 0, newTime.Location())\n\treturn newTime\n}\n\n// StartOfWeek clones and returns a new time which is the first day of week and its time is set to\n// 00:00:00.\nfunc (t *Time) StartOfWeek() *Time {\n\tweekday := int(t.Weekday())\n\treturn t.StartOfDay().AddDate(0, 0, -weekday)\n}\n\n// StartOfMonth clones and returns a new time which is the first day of the month and its is set to\n// 00:00:00\nfunc (t *Time) StartOfMonth() *Time {\n\ty, m, _ := t.Date()\n\tnewTime := t.Clone()\n\tnewTime.Time = time.Date(y, m, 1, 0, 0, 0, 0, newTime.Location())\n\treturn newTime\n}\n\n// StartOfQuarter clones and returns a new time which is the first day of the quarter and its time is set\n// to 00:00:00.\nfunc (t *Time) StartOfQuarter() *Time {\n\tmonth := t.StartOfMonth()\n\toffset := (int(month.Month()) - 1) % 3\n\treturn month.AddDate(0, -offset, 0)\n}\n\n// StartOfHalf clones and returns a new time which is the first day of the half year and its time is set\n// to 00:00:00.\nfunc (t *Time) StartOfHalf() *Time {\n\tmonth := t.StartOfMonth()\n\toffset := (int(month.Month()) - 1) % 6\n\treturn month.AddDate(0, -offset, 0)\n}\n\n// StartOfYear clones and returns a new time which is the first day of the year and its time is set to\n// 00:00:00.\nfunc (t *Time) StartOfYear() *Time {\n\ty, _, _ := t.Date()\n\tnewTime := t.Clone()\n\tnewTime.Time = time.Date(y, time.January, 1, 0, 0, 0, 0, newTime.Location())\n\treturn newTime\n}\n\n// getPrecisionDelta returns the precision parameter for time calculation depending on `withNanoPrecision` option.\nfunc getPrecisionDelta(withNanoPrecision ...bool) time.Duration {\n\tif len(withNanoPrecision) > 0 && withNanoPrecision[0] {\n\t\treturn time.Nanosecond\n\t}\n\treturn time.Second\n}\n\n// EndOfMinute clones and returns a new time of which the seconds is set to 59.\nfunc (t *Time) EndOfMinute(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfMinute().Add(time.Minute - getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfHour clones and returns a new time of which the minutes and seconds are both set to 59.\nfunc (t *Time) EndOfHour(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfHour().Add(time.Hour - getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfDay clones and returns a new time which is the end of day the and its time is set to 23:59:59.\nfunc (t *Time) EndOfDay(withNanoPrecision ...bool) *Time {\n\ty, m, d := t.Date()\n\tnewTime := t.Clone()\n\tnewTime.Time = time.Date(\n\t\ty, m, d, 23, 59, 59, int(time.Second-getPrecisionDelta(withNanoPrecision...)), newTime.Location(),\n\t)\n\treturn newTime\n}\n\n// EndOfWeek clones and returns a new time which is the end of week and its time is set to 23:59:59.\nfunc (t *Time) EndOfWeek(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfWeek().AddDate(0, 0, 7).Add(-getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfMonth clones and returns a new time which is the end of the month and its time is set to 23:59:59.\nfunc (t *Time) EndOfMonth(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfMonth().AddDate(0, 1, 0).Add(-getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfQuarter clones and returns a new time which is end of the quarter and its time is set to 23:59:59.\nfunc (t *Time) EndOfQuarter(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfQuarter().AddDate(0, 3, 0).Add(-getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfHalf clones and returns a new time which is the end of the half year and its time is set to 23:59:59.\nfunc (t *Time) EndOfHalf(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfHalf().AddDate(0, 6, 0).Add(-getPrecisionDelta(withNanoPrecision...))\n}\n\n// EndOfYear clones and returns a new time which is the end of the year and its time is set to 23:59:59.\nfunc (t *Time) EndOfYear(withNanoPrecision ...bool) *Time {\n\treturn t.StartOfYear().AddDate(1, 0, 0).Add(-getPrecisionDelta(withNanoPrecision...))\n}\n\n// MarshalJSON implements the interface MarshalJSON for json.Marshal.\n// Note that, DO NOT use `(t *Time) MarshalJSON() ([]byte, error)` as it looses interface\n// implement of `MarshalJSON` for struct of Time.\nfunc (t Time) MarshalJSON() ([]byte, error) {\n\treturn []byte(`\"` + t.String() + `\"`), nil\n}\n\n// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.\nfunc (t *Time) UnmarshalJSON(b []byte) error {\n\tif len(b) == 0 {\n\t\tt.Time = time.Time{}\n\t\treturn nil\n\t}\n\tnewTime, err := StrToTime(string(bytes.Trim(b, `\"`)))\n\tif err != nil {\n\t\treturn err\n\t}\n\tt.Time = newTime.Time\n\treturn nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface.\n// Note that it overwrites the same implementer of `time.Time`.\nfunc (t *Time) UnmarshalText(data []byte) error {\n\tvTime := New(data)\n\tif vTime != nil {\n\t\t*t = *vTime\n\t\treturn nil\n\t}\n\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time value: %s`, data)\n}\n\n// NoValidation marks this struct object will not be validated by package gvalid.\nfunc (t *Time) NoValidation() {}\n\n// DeepCopy implements interface for deep copy of current type.\nfunc (t *Time) DeepCopy() any {\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn New(t.Time)\n}\n"
  },
  {
    "path": "os/gtime/gtime_time_wrapper.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime\n\nimport (\n\t\"time\"\n)\n\n// wrapper is a wrapper for stdlib struct time.Time.\n// It's used for overwriting some functions of time.Time, for example: String.\ntype wrapper struct {\n\ttime.Time\n}\n\n// String overwrites the String function of time.Time.\nfunc (t wrapper) String() string {\n\tif t.IsZero() {\n\t\treturn \"\"\n\t}\n\tif t.Year() == 0 {\n\t\t// Only time.\n\t\treturn t.Format(\"15:04:05\")\n\t}\n\treturn t.Format(\"2006-01-02 15:04:05\")\n}\n"
  },
  {
    "path": "os/gtime/gtime_time_zone.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\tsetTimeZoneMu   sync.Mutex\n\tsetTimeZoneName string\n\tzoneMap         = make(map[string]*time.Location)\n\tzoneMu          sync.RWMutex\n)\n\n// SetTimeZone sets the time zone for current whole process.\n// The parameter `zone` is an area string specifying corresponding time zone,\n// eg: Asia/Shanghai.\n//\n// PLEASE VERY NOTE THAT:\n// 1. This should be called before package \"time\" import.\n// 2. This function should be called once.\n// 3. Please refer to issue: https://github.com/golang/go/issues/34814\nfunc SetTimeZone(zone string) (err error) {\n\tsetTimeZoneMu.Lock()\n\tdefer setTimeZoneMu.Unlock()\n\tif setTimeZoneName != \"\" && !strings.EqualFold(zone, setTimeZoneName) {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t`process timezone already set using \"%s\"`,\n\t\t\tsetTimeZoneName,\n\t\t)\n\t}\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tsetTimeZoneName = zone\n\t\t}\n\t}()\n\n\t// It is already set to time.Local.\n\tif strings.EqualFold(zone, time.Local.String()) {\n\t\treturn\n\t}\n\n\t// Load zone info from specified name.\n\tlocation, err := time.LoadLocation(zone)\n\tif err != nil {\n\t\terr = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for zone \"%s\"`, zone)\n\t\treturn err\n\t}\n\n\t// Update the time.Local for once.\n\ttime.Local = location\n\n\t// Update the timezone environment for *nix systems.\n\tvar (\n\t\tenvKey   = \"TZ\"\n\t\tenvValue = location.String()\n\t)\n\tif err = os.Setenv(envKey, envValue); err != nil {\n\t\terr = gerror.WrapCodef(\n\t\t\tgcode.CodeUnknown,\n\t\t\terr,\n\t\t\t`set environment failed with key \"%s\", value \"%s\"`,\n\t\t\tenvKey, envValue,\n\t\t)\n\t}\n\treturn\n}\n\n// ToLocation converts current time to specified location.\nfunc (t *Time) ToLocation(location *time.Location) *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.In(location)\n\treturn newTime\n}\n\n// ToZone converts current time to specified zone like: Asia/Shanghai.\nfunc (t *Time) ToZone(zone string) (*Time, error) {\n\tif location, err := t.getLocationByZoneName(zone); err == nil {\n\t\treturn t.ToLocation(location), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\nfunc (t *Time) getLocationByZoneName(name string) (location *time.Location, err error) {\n\tzoneMu.RLock()\n\tlocation = zoneMap[name]\n\tzoneMu.RUnlock()\n\tif location == nil {\n\t\tlocation, err = time.LoadLocation(name)\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `time.LoadLocation failed for name \"%s\"`, name)\n\t\t}\n\t\tif location != nil {\n\t\t\tzoneMu.Lock()\n\t\t\tzoneMap[name] = location\n\t\t\tzoneMu.Unlock()\n\t\t}\n\t}\n\treturn\n}\n\n// Local converts the time to local timezone.\nfunc (t *Time) Local() *Time {\n\tnewTime := t.Clone()\n\tnewTime.Time = newTime.Time.Local()\n\treturn newTime\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\nfunc Benchmark_Timestamp(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.Timestamp()\n\t}\n}\n\nfunc Benchmark_TimestampMilli(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.TimestampMilli()\n\t}\n}\n\nfunc Benchmark_TimestampMicro(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.TimestampMicro()\n\t}\n}\n\nfunc Benchmark_TimestampNano(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.TimestampNano()\n\t}\n}\n\nfunc Benchmark_StrToTime(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.StrToTime(\"2018-02-09T20:46:17.897Z\")\n\t}\n}\n\nfunc Benchmark_StrToTime_Format(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.StrToTime(\"2018-02-09 20:46:17.897\", \"Y-m-d H:i:su\")\n\t}\n}\n\nfunc Benchmark_StrToTime_Layout(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.StrToTimeLayout(\"2018-02-09T20:46:17.897Z\", time.RFC3339)\n\t}\n}\n\nfunc Benchmark_ParseTimeFromContent(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.ParseTimeFromContent(\"2018-02-09T20:46:17.897Z\")\n\t}\n}\n\nfunc Benchmark_NewFromTimeStamp(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.NewFromTimeStamp(1542674930)\n\t}\n}\n\nfunc Benchmark_Date(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.Date()\n\t}\n}\n\nfunc Benchmark_Datetime(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgtime.Datetime()\n\t}\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_example_basic_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// New creates and returns a Time object with given parameter.\n// The optional parameter can be type of: time.Time/*time.Time, string or integer.\nfunc ExampleSetTimeZone() {\n\tgtime.SetTimeZone(\"Asia/Shanghai\")\n\tfmt.Println(gtime.Datetime())\n\t// May Output:\n\t// 2018-08-08 08:08:08\n}\n\nfunc ExampleTimestamp() {\n\tfmt.Println(gtime.Timestamp())\n\n\t// May Output:\n\t// 1636359252\n}\n\nfunc ExampleTimestampMilli() {\n\tfmt.Println(gtime.TimestampMilli())\n\n\t// May Output:\n\t// 1636359252000\n}\n\nfunc ExampleTimestampMicro() {\n\tfmt.Println(gtime.TimestampMicro())\n\n\t// May Output:\n\t// 1636359252000000\n}\n\nfunc ExampleTimestampNano() {\n\tfmt.Println(gtime.TimestampNano())\n\n\t// May Output:\n\t// 1636359252000000000\n}\n\nfunc ExampleTimestampStr() {\n\tfmt.Println(gtime.TimestampStr())\n\n\t// May Output:\n\t// 1636359252\n}\n\nfunc ExampleDate() {\n\tfmt.Println(gtime.Date())\n\n\t// May Output:\n\t// 2006-01-02\n}\n\nfunc ExampleDatetime() {\n\tfmt.Println(gtime.Datetime())\n\n\t// May Output:\n\t// 2006-01-02 15:04:05\n}\n\nfunc ExampleISO8601() {\n\tfmt.Println(gtime.ISO8601())\n\n\t// May Output:\n\t// 2006-01-02T15:04:05-07:00\n}\n\nfunc ExampleRFC822() {\n\tfmt.Println(gtime.RFC822())\n\n\t// May Output:\n\t// Mon, 02 Jan 06 15:04 MST\n}\n\nfunc ExampleStrToTime() {\n\tres, _ := gtime.StrToTime(\"2006-01-02T15:04:05-07:00\", \"Y-m-d H:i:s\")\n\tfmt.Println(res)\n\n\t// May Output:\n\t// 2006-01-02 15:04:05\n}\n\nfunc ExampleConvertZone() {\n\tres, _ := gtime.ConvertZone(\"2006-01-02 15:04:05\", \"Asia/Tokyo\", \"Asia/Shanghai\")\n\tfmt.Println(res)\n\n\t// Output:\n\t// 2006-01-02 16:04:05\n}\n\nfunc ExampleStrToTimeFormat() {\n\tres, _ := gtime.StrToTimeFormat(\"2006-01-02 15:04:05\", \"Y-m-d H:i:s\")\n\tfmt.Println(res)\n\n\t// Output:\n\t// 2006-01-02 15:04:05\n}\n\nfunc ExampleStrToTimeLayout() {\n\tres, _ := gtime.StrToTimeLayout(\"2018-08-08\", \"2006-01-02\")\n\tfmt.Println(res)\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n}\n\n// ParseDuration parses a duration string.\n// A duration string is a possibly signed sequence of\n// decimal numbers, each with optional fraction and a unit suffix,\n// such as \"300ms\", \"-1.5h\", \"1d\" or \"2h45m\".\n// Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\", \"d\".\n//\n// Very note that it supports unit \"d\" more than function time.ParseDuration.\nfunc ExampleParseDuration() {\n\tres, _ := gtime.ParseDuration(\"+10h\")\n\tfmt.Println(res)\n\n\t// Output:\n\t// 10h0m0s\n}\n\nfunc ExampleTime_Format() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.Format(\"Y-m-d\"))\n\tfmt.Println(gt1.Format(\"l\"))\n\tfmt.Println(gt1.Format(\"F j, Y, g:i a\"))\n\tfmt.Println(gt1.Format(\"j, n, Y\"))\n\tfmt.Println(gt1.Format(\"h-i-s, j-m-y, it is w Day z\"))\n\tfmt.Println(gt1.Format(\"D M j G:i:s T Y\"))\n\n\t// Output:\n\t// 2018-08-08\n\t// Wednesday\n\t// August 8, 2018, 8:08 am\n\t// 8, 8, 2018\n\t// 08-08-08, 8-08-18, 0831 0808 3 Wedam18 219\n\t// Wed Aug 8 8:08:08 CST 2018\n}\n\nfunc ExampleTime_FormatNew() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.FormatNew(\"Y-m-d\"))\n\tfmt.Println(gt1.FormatNew(\"Y-m-d H:i\"))\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n\t// 2018-08-08 08:08:00\n}\n\nfunc ExampleTime_FormatTo() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.FormatTo(\"Y-m-d\"))\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n}\n\nfunc ExampleTime_Layout() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.Layout(\"2006-01-02\"))\n\n\t// Output:\n\t// 2018-08-08\n}\n\nfunc ExampleTime_LayoutNew() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.LayoutNew(\"2006-01-02\"))\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n}\n\nfunc ExampleTime_LayoutTo() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.LayoutTo(\"2006-01-02\"))\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n}\n\nfunc ExampleTime_IsLeapYear() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.IsLeapYear())\n\n\t// Output:\n\t// false\n}\n\nfunc ExampleTime_DayOfYear() {\n\tgt1 := gtime.New(\"2018-01-08 08:08:08\")\n\n\tfmt.Println(gt1.DayOfYear())\n\n\t// Output:\n\t// 7\n}\n\n// DaysInMonth returns the day count of current month.\nfunc ExampleTime_DaysInMonth() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.DaysInMonth())\n\n\t// Output:\n\t// 31\n}\n\n// WeeksOfYear returns the point of current week for the year.\nfunc ExampleTime_WeeksOfYear() {\n\tgt1 := gtime.New(\"2018-01-08 08:08:08\")\n\n\tfmt.Println(gt1.WeeksOfYear())\n\n\t// Output:\n\t// 2\n}\n\nfunc ExampleTime_ToZone() {\n\tgt1 := gtime.Now()\n\tgt2, _ := gt1.ToZone(\"Asia/Shanghai\")\n\tgt3, _ := gt1.ToZone(\"Asia/Tokyo\")\n\n\tfmt.Println(gt2)\n\tfmt.Println(gt3)\n\n\t// May Output:\n\t// 2021-11-11 17:10:10\n\t// 2021-11-11 18:10:10\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_example_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\nfunc ExampleNew_curTime() {\n\tcurTime := \"2018-08-08 08:08:08\"\n\ttimer, _ := time.Parse(\"2006-01-02 15:04:05\", curTime)\n\tt1 := gtime.New(&timer)\n\tt2 := gtime.New(curTime)\n\tt3 := gtime.New(curTime, \"Y-m-d H:i:s\")\n\tt4 := gtime.New(curTime)\n\tt5 := gtime.New(1533686888)\n\tt6 := gtime.New(\"08:08:08\")\n\n\tfmt.Println(t1)\n\tfmt.Println(t2)\n\tfmt.Println(t3)\n\tfmt.Println(t4)\n\tfmt.Println(t5)\n\tfmt.Println(t6)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n\t// 2018-08-08 08:08:08\n\t// 2018-08-08 08:08:08\n\t// 2018-08-08 08:08:08\n\t// 2018-08-08 08:08:08\n\t// 08:08:08\n}\n\nfunc ExampleNew_format() {\n\tfmt.Println(gtime.New(\"20220629133225\", \"YmdHis\").Format(\"Y-m-d H:i:s\"))\n\n\t// Output:\n\t// 2022-06-29 13:32:25\n}\n\n// Now creates and returns a time object of now.\nfunc ExampleNow() {\n\tt := gtime.Now()\n\tfmt.Println(t)\n\n\t// May Output:\n\t// 2021-11-06 13:41:08\n}\n\n// NewFromTime creates and returns a Time object with given time.Time object.\nfunc ExampleNewFromTime() {\n\ttimer, _ := time.Parse(\"2006-01-02 15:04:05\", \"2018-08-08 08:08:08\")\n\tnTime := gtime.NewFromTime(timer)\n\n\tfmt.Println(nTime)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n}\n\n// NewFromStr creates and returns a Time object with given string.\n// Note that it returns nil if there's error occurs.\nfunc ExampleNewFromStr() {\n\tt1 := gtime.NewFromStr(\"2018-08-08 08:08:08\")\n\tt2 := gtime.NewFromStr(\"08:08:08\")\n\n\tfmt.Println(t1)\n\tfmt.Println(t2)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n\t// 08:08:08\n}\n\n// NewFromStrFormat creates and returns a Time object with given string and\n// custom format like: Y-m-d H:i:s.\n// Note that it returns nil if there's error occurs.\nfunc ExampleNewFromStrFormat() {\n\tt := gtime.NewFromStrFormat(\"2018-08-08 08:08:08\", \"Y-m-d H:i:s\")\n\tfmt.Println(t)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n}\n\n// NewFromStrLayout creates and returns a Time object with given string and\n// stdlib layout like: 2006-01-02 15:04:05.\n// Note that it returns nil if there's error occurs.\nfunc ExampleNewFromStrLayout() {\n\tt := gtime.NewFromStrLayout(\"2018-08-08 08:08:08\", \"2006-01-02 15:04:05\")\n\tfmt.Println(t)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n}\n\n// NewFromTimeStamp creates and returns a Time object with given timestamp,\n// which can be in seconds to nanoseconds.\n// Eg: 1600443866 and 1600443866199266000 are both considered as valid timestamp number.\nfunc ExampleNewFromTimeStamp() {\n\tt1 := gtime.NewFromTimeStamp(1533686888)\n\tt2 := gtime.NewFromTimeStamp(1533686888000)\n\n\tfmt.Println(t1.String() == t2.String())\n\tfmt.Println(t1)\n\n\t// Output:\n\t// true\n\t// 2018-08-08 08:08:08\n}\n\n// Timestamp returns the timestamp in seconds.\nfunc ExampleTime_Timestamp() {\n\tt := gtime.Timestamp()\n\n\tfmt.Println(t)\n\n\t// May output:\n\t// 1533686888\n}\n\n// Timestamp returns the timestamp in milliseconds.\nfunc ExampleTime_TimestampMilli() {\n\tt := gtime.TimestampMilli()\n\n\tfmt.Println(t)\n\n\t// May output:\n\t// 1533686888000\n}\n\n// Timestamp returns the timestamp in microseconds.\nfunc ExampleTime_TimestampMicro() {\n\tt := gtime.TimestampMicro()\n\n\tfmt.Println(t)\n\n\t// May output:\n\t// 1533686888000000\n}\n\n// Timestamp returns the timestamp in nanoseconds.\nfunc ExampleTime_TimestampNano() {\n\tt := gtime.TimestampNano()\n\n\tfmt.Println(t)\n\n\t// May output:\n\t// 1533686888000000\n}\n\n// TimestampStr is a convenience method which retrieves and returns\n// the timestamp in seconds as string.\nfunc ExampleTime_TimestampStr() {\n\tt := gtime.TimestampStr()\n\n\tfmt.Println(reflect.TypeOf(t))\n\n\t// Output:\n\t// string\n}\n\n// Month returns the month of the year specified by t.\nfunc ExampleTime_Month() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tt1 := gt.Month()\n\n\tfmt.Println(t1)\n\n\t// Output:\n\t// 8\n}\n\n// Second returns the second offset within the minute specified by t,\n// in the range [0, 59].\nfunc ExampleTime_Second() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tt1 := gt.Second()\n\n\tfmt.Println(t1)\n\n\t// Output:\n\t// 8\n}\n\n// String returns current time object as string.\nfunc ExampleTime_String() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\tt1 := gt1.String()\n\tgt2 := gtime.New(\"08:08:08\")\n\n\tfmt.Println(t1)\n\tfmt.Println(reflect.TypeOf(t1))\n\tfmt.Println(gt2)\n\n\t// Output:\n\t// 2018-08-08 08:08:08\n\t// string\n\t// 08:08:08\n}\n\n// IsZero reports whether t represents the zero time instant,\n// January 1, year 1, 00:00:00 UTC.\nfunc ExampleTime_IsZero() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\tgt2 := gtime.New(\"00:00:00\")\n\ttimer, _ := time.Parse(\"15:04:05\", \"00:00:00\")\n\tgt3 := gtime.NewFromTime(timer)\n\n\tfmt.Println(gt1.IsZero())\n\tfmt.Println(gt2.IsZero())\n\tfmt.Println(timer.IsZero()) // stdlib is also false\n\tfmt.Println(gt3.IsZero())\n\n\t// Output:\n\t// false\n\t// false\n\t// false\n\t// false\n}\n\n// Add adds the duration to current time.\nfunc ExampleTime_Add() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tgt1 := gt.Add(time.Duration(10) * time.Second)\n\n\tfmt.Println(gt1)\n\n\t// Output:\n\t// 2018-08-08 08:08:18\n}\n\n// AddStr parses the given duration as string and adds it to current time.\n// Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\nfunc ExampleTime_AddStr() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tgt1, _ := gt.AddStr(\"10s\")\n\n\tfmt.Println(gt1)\n\n\t// Output:\n\t// 2018-08-08 08:08:18\n}\n\n// AddDate adds year, month and day to the time.\nfunc ExampleTime_AddDate() {\n\tvar (\n\t\tyear  = 1\n\t\tmonth = 2\n\t\tday   = 3\n\t)\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tgt = gt.AddDate(year, month, day)\n\n\tfmt.Println(gt)\n\n\t// Output:\n\t// 2019-10-11 08:08:08\n}\n\n// Round returns the result of rounding t to the nearest multiple of d (since the zero time).\n// The rounding behavior for halfway values is to round up.\n// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged.\n//\n// Round operates on the time as an absolute duration since the\n// zero time; it does not operate on the presentation form of the\n// time. Thus, Round(Hour) may return a time with a non-zero\n// minute, depending on the time's Location.\nfunc ExampleTime_Round() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tt := gt.Round(time.Duration(10) * time.Second)\n\n\tfmt.Println(t)\n\n\t// Output:\n\t// 2018-08-08 08:08:10\n}\n\n// Truncate returns the result of rounding t down to a multiple of d (since the zero time).\n// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged.\n//\n// Truncate operates on the time as an absolute duration since the\n// zero time; it does not operate on the presentation form of the\n// time. Thus, Truncate(Hour) may return a time with a non-zero\n// minute, depending on the time's Location.\nfunc ExampleTime_Truncate() {\n\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\tt := gt.Truncate(time.Duration(10) * time.Second)\n\n\tfmt.Println(t)\n\n\t// Output:\n\t// 2018-08-08 08:08:00\n}\n\n// Equal reports whether t and u represent the same time instant.\n// Two times can be equal even if they are in different locations.\n// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.\n// See the documentation on the Time type for the pitfalls of using == with\n// Time values; most code should use Equal instead.\nfunc ExampleTime_Equal() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\tgt2 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.Equal(gt2))\n\n\t// Output:\n\t// true\n}\n\n// Before reports whether the time instant t is before u.\nfunc ExampleTime_Before() {\n\tgt1 := gtime.New(\"2018-08-07\")\n\tgt2 := gtime.New(\"2018-08-08\")\n\n\tfmt.Println(gt1.Before(gt2))\n\n\t// Output:\n\t// true\n}\n\n// After reports whether the time instant t is after u.\nfunc ExampleTime_After() {\n\tgt1 := gtime.New(\"2018-08-07\")\n\tgt2 := gtime.New(\"2018-08-08\")\n\n\tfmt.Println(gt1.After(gt2))\n\n\t// Output:\n\t// false\n}\n\n// Sub returns the duration t-u. If the result exceeds the maximum (or minimum)\n// value that can be stored in a Duration, the maximum (or minimum) duration\n// will be returned.\n// To compute t-d for a duration d, use t.Add(-d).\nfunc ExampleTime_Sub() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\tgt2 := gtime.New(\"2018-08-08 08:08:10\")\n\n\tfmt.Println(gt2.Sub(gt1))\n\n\t// Output:\n\t// 2s\n}\n\n// StartOfMinute clones and returns a new time of which the seconds is set to 0.\nfunc ExampleTime_StartOfMinute() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfMinute())\n\n\t// Output:\n\t// 2018-08-08 08:08:00\n}\n\nfunc ExampleTime_StartOfHour() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfHour())\n\n\t// Output:\n\t// 2018-08-08 08:00:00\n}\n\nfunc ExampleTime_StartOfDay() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfDay())\n\n\t// Output:\n\t// 2018-08-08 00:00:00\n}\n\nfunc ExampleTime_StartOfWeek() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfWeek())\n\n\t// Output:\n\t// 2018-08-05 00:00:00\n}\n\nfunc ExampleTime_StartOfQuarter() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfQuarter())\n\n\t// Output:\n\t// 2018-07-01 00:00:00\n}\n\nfunc ExampleTime_StartOfHalf() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfHalf())\n\n\t// Output:\n\t// 2018-07-01 00:00:00\n}\n\nfunc ExampleTime_StartOfYear() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.StartOfYear())\n\n\t// Output:\n\t// 2018-01-01 00:00:00\n}\n\nfunc ExampleTime_EndOfMinute() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfMinute())\n\n\t// Output:\n\t// 2018-08-08 08:08:59\n}\n\nfunc ExampleTime_EndOfHour() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfHour())\n\n\t// Output:\n\t// 2018-08-08 08:59:59\n}\n\nfunc ExampleTime_EndOfDay() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfDay())\n\n\t// Output:\n\t// 2018-08-08 23:59:59\n}\n\nfunc ExampleTime_EndOfWeek() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfWeek())\n\n\t// Output:\n\t// 2018-08-11 23:59:59\n}\n\nfunc ExampleTime_EndOfMonth() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfMonth())\n\n\t// Output:\n\t// 2018-08-31 23:59:59\n}\n\nfunc ExampleTime_EndOfQuarter() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfQuarter())\n\n\t// Output:\n\t// 2018-09-30 23:59:59\n}\n\nfunc ExampleTime_EndOfHalf() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfHalf())\n\n\t// Output:\n\t// 2018-12-31 23:59:59\n}\n\nfunc ExampleTime_EndOfYear() {\n\tgt1 := gtime.New(\"2018-08-08 08:08:08\")\n\n\tfmt.Println(gt1.EndOfYear())\n\n\t// Output:\n\t// 2018-12-31 23:59:59\n}\n\nfunc ExampleTime_MarshalJSON() {\n\ttype Person struct {\n\t\tName     string      `json:\"name\"`\n\t\tBirthday *gtime.Time `json:\"birthday\"`\n\t}\n\tp := new(Person)\n\tp.Name = \"goframe\"\n\tp.Birthday = gtime.New(\"2018-08-08 08:08:08\")\n\tj, _ := json.Marshal(p)\n\tfmt.Println(string(j))\n\n\t// Output:\n\t// {\"name\":\"goframe\",\"birthday\":\"2018-08-08 08:08:08\"}\n}\n\nfunc ExampleTime_UnmarshalJSON() {\n\ttype Person struct {\n\t\tName     string      `json:\"name\"`\n\t\tBirthday *gtime.Time `json:\"birthday\"`\n\t}\n\tp := new(Person)\n\tsrc := `{\"name\":\"goframe\",\"birthday\":\"2018-08-08 08:08:08\"}`\n\tjson.Unmarshal([]byte(src), p)\n\n\tfmt.Println(p)\n\n\t// Output\n\t// &{goframe 2018-08-08 08:08:08}\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_feature_json_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Json_Pointer(t *testing.T) {\n\t// Marshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime *gtime.Time\n\t\t}\n\t\tb, err := json.Marshal(MyTime{\n\t\t\tMyTime: gtime.NewFromStr(\"2006-01-02 15:04:05\"),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"2006-01-02 15:04:05\"}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := json.Marshal(g.Map{\n\t\t\t\"MyTime\": gtime.NewFromStr(\"2006-01-02 15:04:05\"),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"2006-01-02 15:04:05\"}`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb, err := json.Marshal(g.Map{\n\t\t\t\"MyTime\": *gtime.NewFromStr(\"2006-01-02 15:04:05\"),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"2006-01-02 15:04:05\"}`)\n\t})\n\t// Marshal nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime *gtime.Time\n\t\t}\n\t\tb, err := json.Marshal(&MyTime{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":null}`)\n\t})\n\t// Marshal nil with json omitempty\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime *gtime.Time `json:\"time,omitempty\"`\n\t\t}\n\t\tb, err := json.Marshal(&MyTime{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{}`)\n\t})\n\t// Unmarshal\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tmyTime gtime.Time\n\t\t\terr    = json.UnmarshalUseNumber([]byte(`\"2006-01-02 15:04:05\"`), &myTime)\n\t\t)\n\t\tt.AssertNil(err)\n\t\tt.Assert(myTime.String(), \"2006-01-02 15:04:05\")\n\t})\n}\n\nfunc Test_Json_Struct(t *testing.T) {\n\t// Marshal struct.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime gtime.Time\n\t\t}\n\t\tb, err := json.Marshal(MyTime{\n\t\t\tMyTime: *gtime.NewFromStr(\"2006-01-02 15:04:05\"),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"2006-01-02 15:04:05\"}`)\n\t})\n\t// Marshal pointer.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime gtime.Time\n\t\t}\n\t\tb, err := json.Marshal(&MyTime{\n\t\t\tMyTime: *gtime.NewFromStr(\"2006-01-02 15:04:05\"),\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"2006-01-02 15:04:05\"}`)\n\t})\n\t// Marshal nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime gtime.Time\n\t\t}\n\t\tb, err := json.Marshal(MyTime{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"MyTime\":\"\"}`)\n\t})\n\t// Marshal nil omitempty\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype MyTime struct {\n\t\t\tMyTime gtime.Time `json:\"time,omitempty\"`\n\t\t}\n\t\tb, err := json.Marshal(MyTime{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"time\":\"\"}`)\n\t})\n\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_feature_sql_test.go",
    "content": "package gtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestTime_Scan(t1 *testing.T) {\n\tgtest.C(t1, func(t *gtest.T) {\n\t\ttt := gtime.Time{}\n\t\t// test string\n\t\ts := gtime.Now().String()\n\t\tt.Assert(tt.Scan(s), nil)\n\t\tt.Assert(tt.String(), s)\n\t\t// test nano\n\t\tn := gtime.TimestampNano()\n\t\tt.Assert(tt.Scan(n), nil)\n\t\tt.Assert(tt.TimestampNano(), n)\n\t\t// test nil\n\t\tnone := (*gtime.Time)(nil)\n\t\tt.Assert(none.Scan(nil), nil)\n\t\tt.Assert(none, nil)\n\t})\n\n}\n\nfunc TestTime_Value(t1 *testing.T) {\n\tgtest.C(t1, func(t *gtest.T) {\n\t\ttt := gtime.Now()\n\t\ts, err := tt.Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, tt.Time)\n\t\t// test nil\n\t\tnone := (*gtime.Time)(nil)\n\t\ts, err = none.Value()\n\t\tt.AssertNil(err)\n\t\tt.Assert(s, nil)\n\n\t})\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_format_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Format(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp, err := gtime.StrToTime(\"2006-01-11 15:04:05\", \"Y-m-d H:i:s\")\n\t\ttimeTemp.ToZone(\"Asia/Shanghai\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\tt.Assert(timeTemp.Format(\"\\\\T\\\\i\\\\m\\\\e中文Y-m-j G:i:s.u\\\\\"), \"Time中文2006-01-11 15:04:05.000\")\n\n\t\tt.Assert(timeTemp.Format(\"d D j l\"), \"11 Wed 11 Wednesday\")\n\n\t\tt.Assert(timeTemp.Format(\"F m M n\"), \"January 01 Jan 1\")\n\n\t\tt.Assert(timeTemp.Format(\"Y y\"), \"2006 06\")\n\n\t\tt.Assert(timeTemp.Format(\"a A g G h H i s u .u\"), \"pm PM 3 15 03 15 04 05 000 .000\")\n\n\t\tt.Assert(timeTemp.Format(\"O P T\"), \"+0800 +08:00 CST\")\n\n\t\tt.Assert(timeTemp.Format(\"r\"), \"Wed, 11 Jan 06 15:04 CST\")\n\n\t\tt.Assert(timeTemp.Format(\"c\"), \"2006-01-11T15:04:05+08:00\")\n\n\t\t//补零\n\t\ttimeTemp1, err := gtime.StrToTime(\"2006-01-02 03:04:05\", \"Y-m-d H:i:s\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d h:i:s\"), \"2006-01-02 03:04:05\")\n\t\t//不补零\n\t\ttimeTemp2, err := gtime.StrToTime(\"2006-01-02 03:04:05\", \"Y-m-d H:i:s\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\tt.Assert(timeTemp2.Format(\"Y-n-j G:i:s\"), \"2006-1-2 3:04:05\")\n\n\t\tt.Assert(timeTemp2.Format(\"U\"), \"1136142245\")\n\n\t\t// 测试数字型的星期\n\t\ttimes := []map[string]string{\n\t\t\t{\"k\": \"2019-04-22\", \"f\": \"w\", \"r\": \"1\"},\n\t\t\t{\"k\": \"2019-04-23\", \"f\": \"w\", \"r\": \"2\"},\n\t\t\t{\"k\": \"2019-04-24\", \"f\": \"w\", \"r\": \"3\"},\n\t\t\t{\"k\": \"2019-04-25\", \"f\": \"w\", \"r\": \"4\"},\n\t\t\t{\"k\": \"2019-04-26\", \"f\": \"dw\", \"r\": \"265\"},\n\t\t\t{\"k\": \"2019-04-27\", \"f\": \"w\", \"r\": \"6\"},\n\t\t\t{\"k\": \"2019-03-10\", \"f\": \"w\", \"r\": \"0\"},\n\t\t\t{\"k\": \"2019-03-10\", \"f\": \"Y-m-d 星期:w\", \"r\": \"2019-03-10 星期:0\"},\n\t\t\t{\"k\": \"2019-04-25\", \"f\": \"N\", \"r\": \"4\"},\n\t\t\t{\"k\": \"2019-03-10\", \"f\": \"N\", \"r\": \"7\"},\n\t\t\t{\"k\": \"2019-03-01\", \"f\": \"S\", \"r\": \"st\"},\n\t\t\t{\"k\": \"2019-03-02\", \"f\": \"S\", \"r\": \"nd\"},\n\t\t\t{\"k\": \"2019-03-03\", \"f\": \"S\", \"r\": \"rd\"},\n\t\t\t{\"k\": \"2019-03-05\", \"f\": \"S\", \"r\": \"th\"},\n\n\t\t\t{\"k\": \"2019-01-01\", \"f\": \"第z天\", \"r\": \"第0天\"},\n\t\t\t{\"k\": \"2019-01-05\", \"f\": \"第z天\", \"r\": \"第4天\"},\n\t\t\t{\"k\": \"2020-05-05\", \"f\": \"第z天\", \"r\": \"第125天\"},\n\t\t\t{\"k\": \"2020-12-31\", \"f\": \"第z天\", \"r\": \"第365天\"}, //润年\n\t\t\t{\"k\": \"2020-02-12\", \"f\": \"第z天\", \"r\": \"第42天\"},  //润年\n\t\t\t{\"k\": \"2019-02-12\", \"f\": \"有t天\", \"r\": \"有28天\"},\n\t\t\t{\"k\": \"2020-02-12\", \"f\": \"20.2有t天\", \"r\": \"20.2有29天\"},\n\t\t\t{\"k\": \"2019-03-12\", \"f\": \"19.3有t天\", \"r\": \"19.3有31天\"},\n\t\t\t{\"k\": \"2019-11-12\", \"f\": \"19.11有t天\", \"r\": \"19.11有30天\"},\n\t\t\t{\"k\": \"2019-01-01\", \"f\": \"第W周\", \"r\": \"第1周\"},\n\t\t\t{\"k\": \"2017-01-01\", \"f\": \"第W周\", \"r\": \"第52周\"},         //星期7\n\t\t\t{\"k\": \"2002-01-01\", \"f\": \"第W周为星期2\", \"r\": \"第1周为星期2\"},  //星期2\n\t\t\t{\"k\": \"2016-01-01\", \"f\": \"第W周为星期5\", \"r\": \"第53周为星期5\"}, //星期5\n\t\t\t{\"k\": \"2014-01-01\", \"f\": \"第W周为星期3\", \"r\": \"第1周为星期3\"},  //星期3\n\t\t\t{\"k\": \"2015-01-01\", \"f\": \"第W周为星期4\", \"r\": \"第1周为星期4\"},  //星期4\n\t\t}\n\n\t\tfor _, v := range times {\n\t\t\tt1, err1 := gtime.StrToTime(v[\"k\"], \"Y-m-d\")\n\t\t\tt.Assert(err1, nil)\n\t\t\tt.Assert(t1.Format(v[\"f\"]), v[\"r\"])\n\t\t}\n\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ti *gtime.Time = nil\n\t\tt.Assert(ti.Format(\"Y-m-d h:i:s\"), \"\")\n\t\tt.Assert(ti.FormatNew(\"Y-m-d h:i:s\"), nil)\n\t\tt.Assert(ti.FormatTo(\"Y-m-d h:i:s\"), nil)\n\t\tt.Assert(ti.Layout(\"Y-m-d h:i:s\"), \"\")\n\t\tt.Assert(ti.LayoutNew(\"Y-m-d h:i:s\"), nil)\n\t\tt.Assert(ti.LayoutTo(\"Y-m-d h:i:s\"), nil)\n\t})\n}\n\nfunc Test_Format_ZeroString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp, err := gtime.StrToTime(\"0000-00-00 00:00:00\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(timeTemp.String(), \"\")\n\t})\n}\n\nfunc Test_FormatTo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.FormatTo(\"Y-m-01 00:00:01\"), timeTemp.Time.Format(\"2006-01\")+\"-01 00:00:01\")\n\t})\n}\n\nfunc Test_Layout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.Layout(\"2006-01-02 15:04:05\"), timeTemp.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n}\n\nfunc Test_LayoutTo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.LayoutTo(\"2006-01-02 00:00:00\"), timeTemp.Time.Format(\"2006-01-02 00:00:00\"))\n\t})\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\n// https://github.com/gogf/gf/issues/1681\nfunc Test_Issue1681(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gtime.New(\"2022-03-08T03:01:14-07:00\").Local().Time, gtime.New(\"2022-03-08T10:01:14Z\").Local().Time)\n\t\tt.Assert(gtime.New(\"2022-03-08T03:01:14-08:00\").Local().Time, gtime.New(\"2022-03-08T11:01:14Z\").Local().Time)\n\t\tt.Assert(gtime.New(\"2022-03-08T03:01:14-09:00\").Local().Time, gtime.New(\"2022-03-08T12:01:14Z\").Local().Time)\n\t\tt.Assert(gtime.New(\"2022-03-08T03:01:14+08:00\").Local().Time, gtime.New(\"2022-03-07T19:01:14Z\").Local().Time)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2803\nfunc Test_Issue2803(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnewTime := gtime.New(\"2023-07-26\").LayoutTo(\"2006-01\")\n\t\tt.Assert(newTime.Year(), 2023)\n\t\tt.Assert(newTime.Month(), 7)\n\t\tt.Assert(newTime.Day(), 1)\n\t\tt.Assert(newTime.Hour(), 0)\n\t\tt.Assert(newTime.Minute(), 0)\n\t\tt.Assert(newTime.Second(), 0)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3558\nfunc Test_Issue3558(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := \"1880-10-24T00:00:00+08:05\"\n\t\tgfTime := gtime.NewFromStr(timeStr)\n\t\tt.Assert(gfTime.Year(), 1880)\n\t\tt.Assert(gfTime.Month(), 10)\n\t\tt.Assert(gfTime.Day(), 24)\n\t\tt.Assert(gfTime.Hour(), 0)\n\t\tt.Assert(gfTime.Minute(), 0)\n\t\tt.Assert(gfTime.Second(), 0)\n\n\t\tstdTime, err := time.Parse(time.RFC3339, timeStr)\n\t\tt.AssertNil(err)\n\t\tstdTimeFormat := stdTime.Format(\"2006-01-02 15:04:05\")\n\t\tgfTimeFormat := gfTime.Format(\"Y-m-d H:i:s\")\n\t\tt.Assert(gfTimeFormat, stdTimeFormat)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := \"1880-10-24T00:00:00-08:05\"\n\t\tgfTime := gtime.NewFromStr(timeStr)\n\t\tt.Assert(gfTime.Year(), 1880)\n\t\tt.Assert(gfTime.Month(), 10)\n\t\tt.Assert(gfTime.Day(), 24)\n\t\tt.Assert(gfTime.Hour(), 0)\n\t\tt.Assert(gfTime.Minute(), 0)\n\t\tt.Assert(gfTime.Second(), 0)\n\t\tstdTime, err := time.Parse(time.RFC3339, timeStr)\n\t\tt.AssertNil(err)\n\t\tstdTimeFormat := stdTime.Format(\"2006-01-02 15:04:05\")\n\t\tgfTimeFormat := gfTime.Format(\"Y-m-d H:i:s\")\n\t\tt.Assert(gfTimeFormat, stdTimeFormat)\n\t})\n}\n\n// Test_Issue4307 https://github.com/gogf/gf/issues/4307\nfunc Test_Issue4307(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar timeNil *time.Time = nil\n\t\t// This should not panic.\n\t\tgfTime := gtime.New(timeNil)\n\t\tt.AssertNil(gfTime)\n\t})\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_TimestampStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(len(gtime.TimestampMilliStr()), 0)\n\t\tt.AssertGT(len(gtime.TimestampMicroStr()), 0)\n\t\tt.AssertGT(len(gtime.TimestampNanoStr()), 0)\n\t})\n}\n\nfunc Test_Nanosecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnanos := gtime.TimestampNano()\n\t\ttimeTemp := time.Unix(0, nanos)\n\t\tt.Assert(nanos, timeTemp.UnixNano())\n\t})\n}\n\nfunc Test_Microsecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmicros := gtime.TimestampMicro()\n\t\ttimeTemp := time.Unix(0, micros*1e3)\n\t\tt.Assert(micros, timeTemp.UnixNano()/1e3)\n\t})\n}\n\nfunc Test_Millisecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmillis := gtime.TimestampMilli()\n\t\ttimeTemp := time.Unix(0, millis*1e6)\n\t\tt.Assert(millis, timeTemp.UnixNano()/1e6)\n\t})\n}\n\nfunc Test_Second(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gtime.Timestamp()\n\t\ttimeTemp := time.Unix(s, 0)\n\t\tt.Assert(s, timeTemp.Unix())\n\t})\n}\n\nfunc Test_Date(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gtime.Date(), time.Now().Format(\"2006-01-02\"))\n\t})\n}\n\nfunc Test_Datetime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdatetime := gtime.Datetime()\n\t\ttimeTemp, err := gtime.StrToTime(datetime, \"Y-m-d H:i:s\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\tt.Assert(datetime, timeTemp.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp, err := gtime.StrToTime(\"\")\n\t\tt.AssertNil(err)\n\t\tt.AssertLT(timeTemp.Unix(), 0)\n\t\ttimeTemp, err = gtime.StrToTime(\"2006-01\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(timeTemp, nil)\n\t})\n}\n\nfunc Test_ISO8601(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tiso8601 := gtime.ISO8601()\n\t\tt.Assert(iso8601, gtime.Now().Format(\"c\"))\n\t})\n}\n\nfunc Test_RFC822(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trfc822 := gtime.RFC822()\n\t\tt.Assert(rfc822, gtime.Now().Format(\"r\"))\n\t})\n}\n\nfunc Test_StrToTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Correct datetime string.\n\t\tvar testDateTimes = []string{\n\t\t\t\"2006-01-02 15:04:05\",\n\t\t\t\"2006/01/02 15:04:05\",\n\t\t\t\"2006.01.02 15:04:05.000\",\n\t\t\t\"2006.01.02 - 15:04:05\",\n\t\t\t\"2006.01.02 15:04:05 +0800 CST\",\n\t\t\t\"2006-01-02T12:05:05+05:01\",\n\t\t\t\"2006-01-02T02:03:05-05:01\",\n\t\t\t\"2006-01-02T15:04:05\",\n\t\t\t\"02-jan-2006 15:04:05\",\n\t\t\t\"02/jan/2006 15:04:05\",\n\t\t\t\"02.jan.2006 15:04:05\",\n\t\t\t\"02.jan.2006:15:04:05\",\n\t\t}\n\n\t\tfor _, item := range testDateTimes {\n\t\t\ttimeTemp, err := gtime.StrToTime(item)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(timeTemp.Time.Local().Format(\"2006-01-02 15:04:05\"), \"2006-01-02 15:04:05\")\n\t\t}\n\n\t\t// Correct date string.\n\t\tvar testDates = []string{\n\t\t\t\"2006.01.02\",\n\t\t\t\"2006.01.02 00:00\",\n\t\t\t\"2006.01.02 00:00:00.000\",\n\t\t}\n\n\t\tfor _, item := range testDates {\n\t\t\ttimeTemp, err := gtime.StrToTime(item)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2006-01-02 00:00:00\")\n\t\t}\n\n\t\t// Correct time string.\n\t\tvar testTimes = g.MapStrStr{\n\t\t\t\"16:12:01\":     \"15:04:05\",\n\t\t\t\"16:12:01.789\": \"15:04:05.000\",\n\t\t}\n\n\t\tfor k, v := range testTimes {\n\t\t\ttime1, err := gtime.StrToTime(k)\n\t\t\tt.AssertNil(err)\n\t\t\ttime2, err := time.ParseInLocation(v, k, time.Local)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(time1.Time, time2)\n\t\t}\n\n\t\t// formatToStdLayout\n\t\tvar testDateFormats = []string{\n\t\t\t\"Y-m-d H:i:s\",\n\t\t\t\"\\\\T\\\\i\\\\m\\\\e Y-m-d H:i:s\",\n\t\t\t\"Y-m-d H:i:s\\\\\",\n\t\t\t\"Y-m-j G:i:s.u\",\n\t\t\t\"Y-m-j G:i:su\",\n\t\t}\n\n\t\tvar testDateFormatsResult = []string{\n\t\t\t\"2007-01-02 15:04:05\",\n\t\t\t\"Time 2007-01-02 15:04:05\",\n\t\t\t\"2007-01-02 15:04:05\",\n\t\t\t\"2007-01-02 15:04:05.000\",\n\t\t\t\"2007-01-02 15:04:05.000\",\n\t\t}\n\n\t\tfor index, item := range testDateFormats {\n\t\t\ttimeTemp, err := gtime.StrToTime(testDateFormatsResult[index], item)\n\t\t\tif err != nil {\n\t\t\t\tt.Error(\"test fail\")\n\t\t\t}\n\t\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05.000\"), \"2007-01-02 15:04:05.000\")\n\t\t}\n\n\t\t// 异常日期列表\n\t\tvar testDatesFail = []string{\n\t\t\t\"2006.01\",\n\t\t\t\"06..02\",\n\t\t}\n\n\t\tfor _, item := range testDatesFail {\n\t\t\t_, err := gtime.StrToTime(item)\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"test fail\")\n\t\t\t}\n\t\t}\n\n\t\t// test special time string\n\t\tvar testSpecialDateTimes = []string{\n\t\t\t\"2006-01-02 8:04:05\",\n\t\t\t\"2006-01-02 8:4:05\",\n\t\t\t\"2006-01-02 8:4:5\",\n\t\t\t\"2006-01-02 8:04:05.000\",\n\t\t\t\"2006/01/02 8:4:5\",\n\t\t\t\"2006.01.02 8:4:5.000\",\n\t\t\t\"2006.01.02 - 8:4:5\",\n\t\t\t\"2006.01.02 8:4:5 +0800 CST\",\n\t\t\t\"2006-01-02T5:5:5+05:01\",\n\t\t\t\"2006-01-01T19:3:5-05:01\",\n\t\t\t\"2006-01-02T8:4:5\",\n\t\t\t\"02-jan-2006 8:4:5\",\n\t\t\t\"02/jan/2006 8:4:5\",\n\t\t\t\"02.jan.2006 8:4:5\",\n\t\t\t\"02.jan.2006:8:4:5\",\n\t\t}\n\t\tfor _, item := range testSpecialDateTimes {\n\t\t\ttimeTemp, err := gtime.StrToTime(item)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(timeTemp.Time.Local().Format(\"2006-01-02 15:04:05\"), \"2006-01-02 08:04:05\")\n\t\t}\n\n\t\t// test error time string\n\t\tvar testErrorDateTimes = []string{\n\t\t\t\"2006-01-02 28:4:5\",\n\t\t\t\"2006-01-02 8:60:5\",\n\t\t\t\"2006-01-02 8:4:60\",\n\t\t\t\"28:20:20\",\n\t\t\t\"8:60:20\",\n\t\t\t\"8:20:60\",\n\t\t}\n\t\tfor _, item := range testErrorDateTimes {\n\t\t\t_, err := gtime.StrToTime(item)\n\t\t\tif err == nil {\n\t\t\t\tt.Error(\"test fail\")\n\t\t\t}\n\t\t}\n\n\t\t// test err\n\t\t_, err := gtime.StrToTime(\"2006-01-02 15:04:05\", \"aabbccdd\")\n\t\tif err == nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n}\n\nfunc Test_ConvertZone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 现行时间\n\t\tnowUTC := time.Now().UTC()\n\t\ttestZone := \"America/Los_Angeles\"\n\n\t\t// 转换为洛杉矶时间\n\t\tt1, err := gtime.ConvertZone(nowUTC.Format(\"2006-01-02 15:04:05\"), testZone, \"\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\n\t\t// 使用洛杉矶时区解析上面转换后的时间\n\t\tlaStr := t1.Time.Format(\"2006-01-02 15:04:05\")\n\t\tloc, err := time.LoadLocation(testZone)\n\t\tt2, err := time.ParseInLocation(\"2006-01-02 15:04:05\", laStr, loc)\n\n\t\t// 判断是否与现行时间匹配\n\t\tt.Assert(t2.UTC().Unix(), nowUTC.Unix())\n\n\t})\n\n\t// test err\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// 现行时间\n\t\tnowUTC := time.Now().UTC()\n\t\t// t.Log(nowUTC.Unix())\n\t\ttestZone := \"errZone\"\n\n\t\t// 错误时间输入\n\t\t_, err := gtime.ConvertZone(nowUTC.Format(\"06..02 15:04:05\"), testZone, \"\")\n\t\tif err == nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\t// 错误时区输入\n\t\t_, err = gtime.ConvertZone(nowUTC.Format(\"2006-01-02 15:04:05\"), testZone, \"\")\n\t\tif err == nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\t// 错误时区输入\n\t\t_, err = gtime.ConvertZone(nowUTC.Format(\"2006-01-02 15:04:05\"), testZone, testZone)\n\t\tif err == nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n}\n\nfunc Test_ParseDuration(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\td, err := gtime.ParseDuration(\"1d\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(d.String(), \"24h0m0s\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\td, err := gtime.ParseDuration(\"1d2h3m\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(d.String(), \"26h3m0s\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\td, err := gtime.ParseDuration(\"-1d2h3m\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(d.String(), \"-26h3m0s\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\td, err := gtime.ParseDuration(\"3m\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(d.String(), \"3m0s\")\n\t})\n\t// error\n\tgtest.C(t, func(t *gtest.T) {\n\t\td, err := gtime.ParseDuration(\"-1dd2h3m\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(d.String(), \"0s\")\n\t})\n}\n\nfunc Test_ParseTimeFromContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.ParseTimeFromContent(\"我是中文2006-01-02 15:04:05我也是中文\", \"Y-m-d H:i:s\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2006-01-02 15:04:05\")\n\n\t\ttimeTemp1 := gtime.ParseTimeFromContent(\"我是中文2006-01-02 15:04:05我也是中文\")\n\t\tt.Assert(timeTemp1.Time.Format(\"2006-01-02 15:04:05\"), \"2006-01-02 15:04:05\")\n\n\t\ttimeTemp2 := gtime.ParseTimeFromContent(\"我是中文02.jan.2006 15:04:05我也是中文\")\n\t\tt.Assert(timeTemp2.Time.Format(\"2006-01-02 15:04:05\"), \"2006-01-02 15:04:05\")\n\n\t\t// test err\n\t\ttimeTempErr := gtime.ParseTimeFromContent(\"我是中文\", \"Y-m-d H:i:s\")\n\t\tif timeTempErr != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeStr := \"2021-1-27 9:10:24\"\n\t\tt.Assert(gtime.ParseTimeFromContent(timeStr, \"Y-n-d g:i:s\").String(), \"2021-01-27 09:10:24\")\n\t})\n}\n\nfunc Test_FuncCost(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgtime.FuncCost(func() {\n\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "os/gtime/gtime_z_unit_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtime_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_New(t *testing.T) {\n\t// time.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeNow := time.Now()\n\t\ttimeTemp := gtime.New(timeNow)\n\t\tt.Assert(timeTemp.Time.UnixNano(), timeNow.UnixNano())\n\n\t\ttimeTemp1 := gtime.New()\n\t\tt.Assert(timeTemp1.Time, time.Time{})\n\t})\n\t// string\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeNow := gtime.Now()\n\t\ttimeTemp := gtime.New(timeNow.String())\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), timeNow.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeNow := gtime.Now()\n\t\ttimeTemp := gtime.New(timeNow.TimestampMicroStr())\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), timeNow.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n\t// int64\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeNow := gtime.Now()\n\t\ttimeTemp := gtime.New(timeNow.TimestampMicro())\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), timeNow.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n\t// short datetime.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.New(\"2021-2-9 08:01:21\")\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2021-02-09 08:01:21\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2021-02-09 08:01:21\")\n\n\t\ttimeTemp = gtime.New(\"2021-02-09 08:01:21\", []byte(\"Y-m-d H:i:s\"))\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2021-02-09 08:01:21\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2021-02-09 08:01:21\")\n\n\t\ttimeTemp = gtime.New([]byte(\"2021-02-09 08:01:21\"))\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2021-02-09 08:01:21\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2021-02-09 08:01:21\")\n\n\t\ttimeTemp = gtime.New([]byte(\"2021-02-09 08:01:21\"), \"Y-m-d H:i:s\")\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2021-02-09 08:01:21\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2021-02-09 08:01:21\")\n\n\t\ttimeTemp = gtime.New([]byte(\"2021-02-09 08:01:21\"), []byte(\"Y-m-d H:i:s\"))\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2021-02-09 08:01:21\")\n\t\tt.Assert(timeTemp.Time.Format(\"2006-01-02 15:04:05\"), \"2021-02-09 08:01:21\")\n\t})\n\t//\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gtime.New(gtime.Time{}), nil)\n\t\tt.Assert(gtime.New(&gtime.Time{}), nil)\n\t})\n\n\t// unconventional\n\tgtest.C(t, func(t *gtest.T) {\n\n\t\tvar testUnconventionalDates = []string{\n\t\t\t\"2006-01.02\",\n\t\t\t\"2006.01-02\",\n\t\t}\n\n\t\tfor _, item := range testUnconventionalDates {\n\t\t\ttimeTemp := gtime.New(item)\n\t\t\tt.Assert(timeTemp.TimestampMilli(), 0)\n\t\t\tt.Assert(timeTemp.TimestampMilliStr(), \"\")\n\t\t\tt.Assert(timeTemp.String(), \"\")\n\t\t}\n\t})\n}\n\nfunc Test_Nil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 *gtime.Time\n\t\tt.Assert(t1.String(), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 gtime.Time\n\t\tt.Assert(t1.String(), \"\")\n\t})\n}\n\nfunc Test_NewFromStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2006-01-02 15:04:05\")\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2006-01-02 15:04:05\")\n\n\t\ttimeTemp1 := gtime.NewFromStr(\"2006.0102\")\n\t\tif timeTemp1 != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n}\n\nfunc Test_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := gtime.NewFromStr(\"2006-01-02 15:04:05\")\n\t\tt.Assert(t1.String(), \"2006-01-02 15:04:05\")\n\t\tt.Assert(fmt.Sprintf(\"%s\", t1), \"2006-01-02 15:04:05\")\n\n\t\tt2 := *t1\n\t\tt.Assert(t2.String(), \"2006-01-02 15:04:05\")\n\t\tt.Assert(fmt.Sprintf(\"{%s}\", t2.String()), \"{2006-01-02 15:04:05}\")\n\t})\n}\n\nfunc Test_NewFromStrFormat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStrFormat(\"2006-01-02 15:04:05\", \"Y-m-d H:i:s\")\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2006-01-02 15:04:05\")\n\n\t\ttimeTemp1 := gtime.NewFromStrFormat(\"2006-01-02 15:04:05\", \"aabbcc\")\n\t\tif timeTemp1 != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := gtime.NewFromStrFormat(\"2019/2/1\", \"Y/n/j\")\n\t\tt.Assert(t1.Format(\"Y-m-d\"), \"2019-02-01\")\n\n\t\tt2 := gtime.NewFromStrFormat(\"2019/10/12\", \"Y/n/j\")\n\t\tt.Assert(t2.Format(\"Y-m-d\"), \"2019-10-12\")\n\t})\n}\n\nfunc Test_NewFromStrLayout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStrLayout(\"2006-01-02 15:04:05\", \"2006-01-02 15:04:05\")\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2006-01-02 15:04:05\")\n\n\t\ttimeTemp1 := gtime.NewFromStrLayout(\"2006-01-02 15:04:05\", \"aabbcc\")\n\t\tif timeTemp1 != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n}\n\nfunc Test_NewFromTimeStamp(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromTimeStamp(1554459846000)\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2019-04-05 18:24:06\")\n\t\ttimeTemp1 := gtime.NewFromTimeStamp(0)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"0001-01-01 00:00:00\")\n\t\ttimeTemp2 := gtime.NewFromTimeStamp(155445984)\n\t\tt.Assert(timeTemp2.Format(\"Y-m-d H:i:s\"), \"1974-12-05 11:26:24\")\n\t})\n}\n\nfunc Test_Time_Second(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.Second(), timeTemp.Time.Second())\n\t})\n}\n\nfunc Test_Time_IsZero(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar ti *gtime.Time = nil\n\t\tt.Assert(ti.IsZero(), true)\n\t})\n}\n\nfunc Test_Time_AddStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgt := gtime.New(\"2018-08-08 08:08:08\")\n\t\tgt1, err := gt.AddStr(\"10T\")\n\t\tt.Assert(gt1, nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Time_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 *gtime.Time = nil\n\t\tvar t2 = gtime.New()\n\t\tt.Assert(t1.Equal(t2), false)\n\t\tt.Assert(t1.Equal(t1), true)\n\t\tt.Assert(t2.Equal(t1), false)\n\t})\n}\n\nfunc Test_Time_After(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 *gtime.Time = nil\n\t\tvar t2 = gtime.New()\n\t\tt.Assert(t1.After(t2), false)\n\t\tt.Assert(t2.After(t1), true)\n\t})\n}\n\nfunc Test_Time_Sub(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 *gtime.Time = nil\n\t\tvar t2 = gtime.New()\n\t\tt.Assert(t1.Sub(t2), time.Duration(0))\n\t\tt.Assert(t2.Sub(t1), time.Duration(0))\n\t})\n}\n\nfunc Test_Time_Nanosecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.Nanosecond(), timeTemp.Time.Nanosecond())\n\t})\n}\n\nfunc Test_Time_Microsecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.Microsecond(), timeTemp.Time.Nanosecond()/1e3)\n\t})\n}\n\nfunc Test_Time_Millisecond(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.Millisecond(), timeTemp.Time.Nanosecond()/1e6)\n\t})\n}\n\nfunc Test_Time_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\tt.Assert(timeTemp.String(), timeTemp.Time.Format(\"2006-01-02 15:04:05\"))\n\t})\n}\n\nfunc Test_Time_ISO8601(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnow := gtime.Now()\n\t\tt.Assert(now.ISO8601(), now.Format(\"c\"))\n\t})\n}\n\nfunc Test_Time_RFC822(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tnow := gtime.Now()\n\t\tt.Assert(now.RFC822(), now.Format(\"r\"))\n\t})\n}\n\nfunc Test_Clone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Clone()\n\t\tt.Assert(timeTemp.Time.Unix(), timeTemp1.Time.Unix())\n\t})\n}\n\nfunc Test_ToTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Time\n\t\tt.Assert(timeTemp.Time.UnixNano(), timeTemp1.UnixNano())\n\t})\n}\n\nfunc Test_Add(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2006-01-02 15:04:05\")\n\t\ttimeTemp = timeTemp.Add(time.Second)\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2006-01-02 15:04:06\")\n\t})\n}\n\nfunc Test_ToZone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp, _ = timeTemp.ToZone(\"America/Los_Angeles\")\n\t\tt.Assert(timeTemp.Time.Location().String(), \"America/Los_Angeles\")\n\n\t\tloc, err := time.LoadLocation(\"Asia/Shanghai\")\n\t\tif err != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t\ttimeTemp = timeTemp.ToLocation(loc)\n\t\tt.Assert(timeTemp.Time.Location().String(), \"Asia/Shanghai\")\n\n\t\ttimeTemp1, _ := timeTemp.ToZone(\"errZone\")\n\t\tif timeTemp1 != nil {\n\t\t\tt.Error(\"test fail\")\n\t\t}\n\t})\n}\n\nfunc Test_AddDate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2006-01-02 15:04:05\")\n\t\ttimeTemp = timeTemp.AddDate(1, 2, 3)\n\t\tt.Assert(timeTemp.Format(\"Y-m-d H:i:s\"), \"2007-03-05 15:04:05\")\n\t})\n}\n\nfunc Test_UTC(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Time\n\t\ttimeTemp.UTC()\n\t\tt.Assert(timeTemp.UnixNano(), timeTemp1.UTC().UnixNano())\n\t})\n}\n\nfunc Test_Local(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Time\n\t\ttimeTemp.Local()\n\t\tt.Assert(timeTemp.UnixNano(), timeTemp1.Local().UnixNano())\n\t})\n}\n\nfunc Test_Round(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Time\n\t\ttimeTemp = timeTemp.Round(time.Hour)\n\t\tt.Assert(timeTemp.UnixNano(), timeTemp1.Round(time.Hour).UnixNano())\n\t})\n}\n\nfunc Test_Truncate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.Now()\n\t\ttimeTemp1 := timeTemp.Time\n\t\ttimeTemp = timeTemp.Truncate(time.Hour)\n\t\tt.Assert(timeTemp.UnixNano(), timeTemp1.Truncate(time.Hour).UnixNano())\n\t})\n}\n\nfunc Test_StartOfMinute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfMinute()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-12-12 18:24:00\")\n\t})\n}\n\nfunc Test_EndOfMinute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfMinute()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 18:24:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfMinute(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 18:24:59.999\")\n\t})\n}\n\nfunc Test_StartOfHour(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfHour()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-12-12 18:00:00\")\n\t})\n}\n\nfunc Test_EndOfHour(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfHour()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 18:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfHour(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 18:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfDay(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfDay()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-12-12 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfDay(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfDay()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfDay(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 23:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfWeek(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfWeek()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-12-06 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfWeek(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfWeek()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfWeek(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-12 23:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfMonth(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfMonth()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-12-01 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfMonth(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfMonth()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-12 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfMonth(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfQuarter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfQuarter()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-10-01 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfQuarter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfQuarter()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfQuarter(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfHalf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfHalf()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-07-01 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfHalf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfHalf()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfHalf(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.999\")\n\t})\n}\n\nfunc Test_StartOfYear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.StartOfYear()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s\"), \"2020-01-01 00:00:00\")\n\t})\n}\n\nfunc Test_EndOfYear(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfYear()\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.000\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimeTemp := gtime.NewFromStr(\"2020-12-06 18:24:06\")\n\t\ttimeTemp1 := timeTemp.EndOfYear(true)\n\t\tt.Assert(timeTemp1.Format(\"Y-m-d H:i:s.u\"), \"2020-12-31 23:59:59.999\")\n\t})\n}\n\nfunc Test_OnlyTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tobj := gtime.NewFromStr(\"18:24:06\")\n\t\tt.Assert(obj.String(), \"18:24:06\")\n\t})\n}\n\nfunc Test_DeepCopy(t *testing.T) {\n\ttype User struct {\n\t\tId          int\n\t\tCreatedTime *gtime.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tu1 := &User{\n\t\t\tId:          1,\n\t\t\tCreatedTime: gtime.New(\"2022-03-08T03:01:14+08:00\"),\n\t\t}\n\t\tu2 := gutil.Copy(u1).(*User)\n\t\tt.Assert(u1, u2)\n\t})\n\t// nil attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tu1 := &User{}\n\t\tu2 := gutil.Copy(u1).(*User)\n\t\tt.Assert(u1, u2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 *gtime.Time = nil\n\t\tt.Assert(t1.DeepCopy(), nil)\n\t})\n}\n\nfunc Test_UnmarshalJSON(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar t1 gtime.Time\n\t\tt.AssertNE(json.Unmarshal([]byte(\"{}\"), &t1), nil)\n\t})\n}\n"
  },
  {
    "path": "os/gtimer/gtimer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtimer implements timer for interval/delayed jobs running and management.\n//\n// This package is designed for management for millions of timing jobs. The differences\n// between gtimer and gcron are as follows:\n//  1. package gcron is implemented based on package gtimer.\n//  2. gtimer is designed for high performance and for millions of timing jobs.\n//  3. gcron supports configuration pattern grammar like linux crontab, which is more manually\n//     readable.\n//  4. gtimer's benchmark OP is measured in nanoseconds, and gcron's benchmark OP is measured\n//     in microseconds.\n//\n// ALSO VERY NOTE the common delay of the timer: https://github.com/golang/go/issues/14410\npackage gtimer\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n)\n\n// Timer is the timer manager, which uses ticks to calculate the timing interval.\ntype Timer struct {\n\tmu      sync.RWMutex\n\tqueue   *priorityQueue // queue is a priority queue based on heap structure.\n\tstatus  *gtype.Int     // status is the current timer status.\n\tticks   *gtype.Int64   // ticks is the proceeded interval number by the timer.\n\toptions TimerOptions   // timer options is used for timer configuration.\n}\n\n// TimerOptions is the configuration object for Timer.\ntype TimerOptions struct {\n\tInterval time.Duration // (optional) Interval is the underlying rolling interval tick of the timer.\n\tQuick    bool          // Quick is used for quick timer, which means the timer will not wait for the first interval to be elapsed.\n}\n\n// internalPanic is the custom panic for internal usage.\ntype internalPanic string\n\nconst (\n\tStatusReady                        = 0      // Job or Timer is ready for running.\n\tStatusRunning                      = 1      // Job or Timer is already running.\n\tStatusStopped                      = 2      // Job or Timer is stopped.\n\tStatusClosed                       = -1     // Job or Timer is closed and waiting to be deleted.\n\tpanicExit            internalPanic = \"exit\" // panicExit is used for custom job exit with panic.\n\tdefaultTimerInterval               = \"100\"  // defaultTimerInterval is the default timer interval in milliseconds.\n\t// commandEnvKeyForInterval is the key for command argument or environment configuring default interval duration for timer.\n\tcommandEnvKeyForInterval = \"gf.gtimer.interval\"\n)\n\nvar (\n\tdefaultInterval = getDefaultInterval()\n\tdefaultTimer    = New()\n)\n\nfunc getDefaultInterval() time.Duration {\n\tinterval := command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval)\n\tn, err := strconv.Atoi(interval)\n\tif err != nil {\n\t\tpanic(gerror.WrapCodef(\n\t\t\tgcode.CodeInvalidConfiguration, err, `error converting string \"%s\" to int number`,\n\t\t\tinterval,\n\t\t))\n\t}\n\treturn time.Duration(n) * time.Millisecond\n}\n\n// DefaultOptions creates and returns a default options object for Timer creation.\nfunc DefaultOptions() TimerOptions {\n\treturn TimerOptions{\n\t\tInterval: defaultInterval,\n\t}\n}\n\n// SetTimeout runs the job once after duration of `delay`.\n// It is like the one in javascript.\nfunc SetTimeout(ctx context.Context, delay time.Duration, job JobFunc) {\n\tAddOnce(ctx, delay, job)\n}\n\n// SetInterval runs the job every duration of `delay`.\n// It is like the one in javascript.\nfunc SetInterval(ctx context.Context, interval time.Duration, job JobFunc) {\n\tAdd(ctx, interval, job)\n}\n\n// Add adds a timing job to the default timer, which runs in interval of `interval`.\nfunc Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn defaultTimer.Add(ctx, interval, job)\n}\n\n// AddEntry adds a timing job to the default timer with detailed parameters.\n//\n// The parameter `interval` specifies the running interval of the job.\n//\n// The parameter `singleton` specifies whether the job running in singleton mode.\n// There's only one of the same job is allowed running when its a singleton mode job.\n//\n// The parameter `times` specifies limit for the job running times, which means the job\n// exits if its run times exceeds the `times`.\n//\n// The parameter `status` specifies the job status when it's firstly added to the timer.\nfunc AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {\n\treturn defaultTimer.AddEntry(ctx, interval, job, isSingleton, times, status)\n}\n\n// AddSingleton is a convenience function for add singleton mode job.\nfunc AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn defaultTimer.AddSingleton(ctx, interval, job)\n}\n\n// AddOnce is a convenience function for adding a job which only runs once and then exits.\nfunc AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn defaultTimer.AddOnce(ctx, interval, job)\n}\n\n// AddTimes is a convenience function for adding a job which is limited running times.\nfunc AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {\n\treturn defaultTimer.AddTimes(ctx, interval, times, job)\n}\n\n// DelayAdd adds a timing job after delay of `interval` duration.\n// Also see Add.\nfunc DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tdefaultTimer.DelayAdd(ctx, delay, interval, job)\n}\n\n// DelayAddEntry adds a timing job after delay of `interval` duration.\n// Also see AddEntry.\nfunc DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {\n\tdefaultTimer.DelayAddEntry(ctx, delay, interval, job, isSingleton, times, status)\n}\n\n// DelayAddSingleton adds a timing job after delay of `interval` duration.\n// Also see AddSingleton.\nfunc DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tdefaultTimer.DelayAddSingleton(ctx, delay, interval, job)\n}\n\n// DelayAddOnce adds a timing job after delay of `interval` duration.\n// Also see AddOnce.\nfunc DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tdefaultTimer.DelayAddOnce(ctx, delay, interval, job)\n}\n\n// DelayAddTimes adds a timing job after delay of `interval` duration.\n// Also see AddTimes.\nfunc DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {\n\tdefaultTimer.DelayAddTimes(ctx, delay, interval, times, job)\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_entry.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Entry is the timing job.\ntype Entry struct {\n\tjob         JobFunc         // The job function.\n\tctx         context.Context // The context for the job, for READ ONLY.\n\ttimer       *Timer          // Belonged timer.\n\tticks       int64           // The job runs every tick.\n\ttimes       *gtype.Int      // Limit running times.\n\tstatus      *gtype.Int      // Job status.\n\tisSingleton *gtype.Bool     // Singleton mode.\n\tnextTicks   *gtype.Int64    // Next run ticks of the job.\n\tinfinite    *gtype.Bool     // No times limit.\n}\n\n// JobFunc is the timing called job function in timer.\ntype JobFunc = func(ctx context.Context)\n\n// Status returns the status of the job.\nfunc (entry *Entry) Status() int {\n\treturn entry.status.Val()\n}\n\n// Run runs the timer job asynchronously.\nfunc (entry *Entry) Run() {\n\tif !entry.infinite.Val() {\n\t\tleftRunningTimes := entry.times.Add(-1)\n\t\t// It checks its running times exceeding.\n\t\tif leftRunningTimes < 0 {\n\t\t\tentry.status.Set(StatusClosed)\n\t\t\treturn\n\t\t}\n\t}\n\tgo entry.callJobFunc()\n}\n\n// callJobFunc executes the job function in entry.\nfunc (entry *Entry) callJobFunc() {\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif exception != panicExit {\n\t\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\t\tpanic(v)\n\t\t\t\t} else {\n\t\t\t\t\tpanic(gerror.NewCodef(gcode.CodeInternalPanic, \"exception recovered: %+v\", exception))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tentry.Close()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif entry.Status() == StatusRunning {\n\t\t\tentry.SetStatus(StatusReady)\n\t\t}\n\t}()\n\tentry.job(entry.ctx)\n}\n\n// doCheckAndRunByTicks checks the if job can run in given timer ticks,\n// it runs asynchronously if the given `currentTimerTicks` meets or else\n// it increments its ticks and waits for next running check.\nfunc (entry *Entry) doCheckAndRunByTicks(currentTimerTicks int64) {\n\t// Ticks check.\n\tif currentTimerTicks < entry.nextTicks.Val() {\n\t\treturn\n\t}\n\tentry.nextTicks.Set(currentTimerTicks + entry.ticks)\n\t// Perform job checking.\n\tswitch entry.status.Val() {\n\tcase StatusRunning:\n\t\tif entry.IsSingleton() {\n\t\t\treturn\n\t\t}\n\tcase StatusReady:\n\t\tif !entry.status.Cas(StatusReady, StatusRunning) {\n\t\t\treturn\n\t\t}\n\tcase StatusStopped:\n\t\treturn\n\tcase StatusClosed:\n\t\treturn\n\t}\n\t// Perform job running.\n\tentry.Run()\n}\n\n// SetStatus custom sets the status for the job.\nfunc (entry *Entry) SetStatus(status int) int {\n\treturn entry.status.Set(status)\n}\n\n// Start starts the job.\nfunc (entry *Entry) Start() {\n\tentry.status.Set(StatusReady)\n}\n\n// Stop stops the job.\nfunc (entry *Entry) Stop() {\n\tentry.status.Set(StatusStopped)\n}\n\n// Close closes the job, and then it will be removed from the timer.\nfunc (entry *Entry) Close() {\n\tentry.status.Set(StatusClosed)\n}\n\n// Reset resets the job, which resets its ticks for next running.\nfunc (entry *Entry) Reset() {\n\tentry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks)\n}\n\n// IsSingleton checks and returns whether the job in singleton mode.\nfunc (entry *Entry) IsSingleton() bool {\n\treturn entry.isSingleton.Val()\n}\n\n// SetSingleton sets the job singleton mode.\nfunc (entry *Entry) SetSingleton(enabled bool) {\n\tentry.isSingleton.Set(enabled)\n}\n\n// Job returns the job function of this job.\nfunc (entry *Entry) Job() JobFunc {\n\treturn entry.job\n}\n\n// Ctx returns the initialized context of this job.\nfunc (entry *Entry) Ctx() context.Context {\n\treturn entry.ctx\n}\n\n// SetTimes sets the limit running times for the job.\nfunc (entry *Entry) SetTimes(times int) {\n\tentry.times.Set(times)\n\tentry.infinite.Set(false)\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_exit.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\n// Exit is used in timing job internally, which exits and marks it closed from timer.\n// The timing job will be automatically removed from timer later. It uses \"panic-recover\"\n// mechanism internally implementing this feature, which is designed for simplification\n// and convenience.\nfunc Exit() {\n\tpanic(panicExit)\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_queue.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport (\n\t\"container/heap\"\n\t\"math\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n)\n\n// priorityQueue is an abstract data type similar to a regular queue or stack data structure in which\n// each element additionally has a \"priority\" associated with it. In a priority queue, an element with\n// high priority is served before an element with low priority.\n// priorityQueue is based on heap structure.\ntype priorityQueue struct {\n\tmu           sync.Mutex\n\theap         *priorityQueueHeap // the underlying queue items manager using heap.\n\tnextPriority *gtype.Int64       // nextPriority stores the next priority value of the heap, which is used to check if necessary to call the Pop of heap by Timer.\n}\n\n// priorityQueueHeap is a heap manager, of which the underlying `array` is an array implementing a heap structure.\ntype priorityQueueHeap struct {\n\tarray []priorityQueueItem\n}\n\n// priorityQueueItem stores the queue item which has a `priority` attribute to sort itself in heap.\ntype priorityQueueItem struct {\n\tvalue    any\n\tpriority int64\n}\n\n// newPriorityQueue creates and returns a priority queue.\nfunc newPriorityQueue() *priorityQueue {\n\tqueue := &priorityQueue{\n\t\theap:         &priorityQueueHeap{array: make([]priorityQueueItem, 0)},\n\t\tnextPriority: gtype.NewInt64(math.MaxInt64),\n\t}\n\theap.Init(queue.heap)\n\treturn queue\n}\n\n// NextPriority retrieves and returns the minimum and the most priority value of the queue.\nfunc (q *priorityQueue) NextPriority() int64 {\n\treturn q.nextPriority.Val()\n}\n\n// Push pushes a value to the queue.\n// The `priority` specifies the priority of the value.\n// The lesser the `priority` value the higher priority of the `value`.\nfunc (q *priorityQueue) Push(value any, priority int64) {\n\tq.mu.Lock()\n\tdefer q.mu.Unlock()\n\theap.Push(q.heap, priorityQueueItem{\n\t\tvalue:    value,\n\t\tpriority: priority,\n\t})\n\t// Update the minimum priority using atomic operation.\n\tnextPriority := q.nextPriority.Val()\n\tif priority >= nextPriority {\n\t\treturn\n\t}\n\tq.nextPriority.Set(priority)\n}\n\n// Pop retrieves, removes and returns the most high priority value from the queue.\nfunc (q *priorityQueue) Pop() any {\n\tq.mu.Lock()\n\tdefer q.mu.Unlock()\n\tif v := heap.Pop(q.heap); v != nil {\n\t\tvar nextPriority int64 = math.MaxInt64\n\t\tif len(q.heap.array) > 0 {\n\t\t\tnextPriority = q.heap.array[0].priority\n\t\t}\n\t\tq.nextPriority.Set(nextPriority)\n\t\treturn v.(priorityQueueItem).value\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_queue_heap.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\n// Len is used to implement the interface of sort.Interface.\nfunc (h *priorityQueueHeap) Len() int {\n\treturn len(h.array)\n}\n\n// Less is used to implement the interface of sort.Interface.\n// The least one is placed to the top of the heap.\nfunc (h *priorityQueueHeap) Less(i, j int) bool {\n\treturn h.array[i].priority < h.array[j].priority\n}\n\n// Swap is used to implement the interface of sort.Interface.\nfunc (h *priorityQueueHeap) Swap(i, j int) {\n\tif len(h.array) == 0 {\n\t\treturn\n\t}\n\th.array[i], h.array[j] = h.array[j], h.array[i]\n}\n\n// Push pushes an item to the heap.\nfunc (h *priorityQueueHeap) Push(x any) {\n\th.array = append(h.array, x.(priorityQueueItem))\n}\n\n// Pop retrieves, removes and returns the most high priority item from the heap.\nfunc (h *priorityQueueHeap) Pop() any {\n\tlength := len(h.array)\n\tif length == 0 {\n\t\treturn nil\n\t}\n\titem := h.array[length-1]\n\th.array = h.array[0 : length-1]\n\treturn item\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_timer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n)\n\n// New creates and returns a Timer.\nfunc New(options ...TimerOptions) *Timer {\n\tt := &Timer{\n\t\tqueue:  newPriorityQueue(),\n\t\tstatus: gtype.NewInt(StatusRunning),\n\t\tticks:  gtype.NewInt64(),\n\t}\n\tif len(options) > 0 {\n\t\tt.options = options[0]\n\t\tif t.options.Interval == 0 {\n\t\t\tt.options.Interval = defaultInterval\n\t\t}\n\t} else {\n\t\tt.options = DefaultOptions()\n\t}\n\tgo t.loop()\n\treturn t\n}\n\n// Add adds a timing job to the timer, which runs in interval of `interval`.\nfunc (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn t.createEntry(createEntryInput{\n\t\tCtx:         ctx,\n\t\tInterval:    interval,\n\t\tJob:         job,\n\t\tIsSingleton: false,\n\t\tTimes:       -1,\n\t\tStatus:      StatusReady,\n\t})\n}\n\n// AddEntry adds a timing job to the timer with detailed parameters.\n//\n// The parameter `interval` specifies the running interval of the job.\n//\n// The parameter `singleton` specifies whether the job running in singleton mode.\n// There's only one of the same job is allowed running when it's a singleton mode job.\n//\n// The parameter `times` specifies limit for the job running times, which means the job\n// exits if its run times exceeds the `times`.\n//\n// The parameter `status` specifies the job status when it's firstly added to the timer.\nfunc (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {\n\treturn t.createEntry(createEntryInput{\n\t\tCtx:         ctx,\n\t\tInterval:    interval,\n\t\tJob:         job,\n\t\tIsSingleton: isSingleton,\n\t\tTimes:       times,\n\t\tStatus:      status,\n\t})\n}\n\n// AddSingleton is a convenience function for add singleton mode job.\nfunc (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn t.createEntry(createEntryInput{\n\t\tCtx:         ctx,\n\t\tInterval:    interval,\n\t\tJob:         job,\n\t\tIsSingleton: true,\n\t\tTimes:       -1,\n\t\tStatus:      StatusReady,\n\t})\n}\n\n// AddOnce is a convenience function for adding a job which only runs once and then exits.\nfunc (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {\n\treturn t.createEntry(createEntryInput{\n\t\tCtx:         ctx,\n\t\tInterval:    interval,\n\t\tJob:         job,\n\t\tIsSingleton: true,\n\t\tTimes:       1,\n\t\tStatus:      StatusReady,\n\t})\n}\n\n// AddTimes is a convenience function for adding a job which is limited running times.\nfunc (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {\n\treturn t.createEntry(createEntryInput{\n\t\tCtx:         ctx,\n\t\tInterval:    interval,\n\t\tJob:         job,\n\t\tIsSingleton: true,\n\t\tTimes:       times,\n\t\tStatus:      StatusReady,\n\t})\n}\n\n// DelayAdd adds a timing job after delay of `delay` duration.\n// Also see Add.\nfunc (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tt.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tt.Add(ctx, interval, job)\n\t})\n}\n\n// DelayAddEntry adds a timing job after delay of `delay` duration.\n// Also see AddEntry.\nfunc (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {\n\tt.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tt.AddEntry(ctx, interval, job, isSingleton, times, status)\n\t})\n}\n\n// DelayAddSingleton adds a timing job after delay of `delay` duration.\n// Also see AddSingleton.\nfunc (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tt.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tt.AddSingleton(ctx, interval, job)\n\t})\n}\n\n// DelayAddOnce adds a timing job after delay of `delay` duration.\n// Also see AddOnce.\nfunc (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {\n\tt.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tt.AddOnce(ctx, interval, job)\n\t})\n}\n\n// DelayAddTimes adds a timing job after delay of `delay` duration.\n// Also see AddTimes.\nfunc (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {\n\tt.AddOnce(ctx, delay, func(ctx context.Context) {\n\t\tt.AddTimes(ctx, interval, times, job)\n\t})\n}\n\n// Start starts the timer.\nfunc (t *Timer) Start() {\n\tt.status.Set(StatusRunning)\n}\n\n// Stop stops the timer.\nfunc (t *Timer) Stop() {\n\tt.status.Set(StatusStopped)\n}\n\n// Close closes the timer.\nfunc (t *Timer) Close() {\n\tt.status.Set(StatusClosed)\n}\n\ntype createEntryInput struct {\n\tCtx         context.Context\n\tInterval    time.Duration\n\tJob         JobFunc\n\tIsSingleton bool\n\tTimes       int\n\tStatus      int\n}\n\n// createEntry creates and adds a timing job to the timer.\nfunc (t *Timer) createEntry(in createEntryInput) *Entry {\n\tvar (\n\t\tinfinite  = false\n\t\tnextTicks int64\n\t)\n\tif in.Times <= 0 {\n\t\tinfinite = true\n\t}\n\tvar (\n\t\tintervalTicksOfJob = int64(in.Interval / t.options.Interval)\n\t)\n\tif intervalTicksOfJob == 0 {\n\t\t// If the given interval is lesser than the one of the wheel,\n\t\t// then sets it to one tick, which means it will be run in one interval.\n\t\tintervalTicksOfJob = 1\n\t}\n\tif t.options.Quick {\n\t\t// If the quick mode is enabled, which means it will be run right now.\n\t\t// Don't need to wait for the first interval.\n\t\tnextTicks = t.ticks.Val()\n\t} else {\n\t\tnextTicks = t.ticks.Val() + intervalTicksOfJob\n\t}\n\tvar (\n\t\tentry = &Entry{\n\t\t\tjob:         in.Job,\n\t\t\tctx:         in.Ctx,\n\t\t\ttimer:       t,\n\t\t\tticks:       intervalTicksOfJob,\n\t\t\ttimes:       gtype.NewInt(in.Times),\n\t\t\tstatus:      gtype.NewInt(in.Status),\n\t\t\tisSingleton: gtype.NewBool(in.IsSingleton),\n\t\t\tnextTicks:   gtype.NewInt64(nextTicks),\n\t\t\tinfinite:    gtype.NewBool(infinite),\n\t\t}\n\t)\n\tt.queue.Push(entry, nextTicks)\n\treturn entry\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_timer_loop.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport \"time\"\n\n// loop starts the ticker using a standalone goroutine.\nfunc (t *Timer) loop() {\n\tvar (\n\t\tcurrentTimerTicks   int64\n\t\ttimerIntervalTicker = time.NewTicker(t.options.Interval)\n\t)\n\tdefer timerIntervalTicker.Stop()\n\tfor range timerIntervalTicker.C {\n\t\t// Check the timer status.\n\t\tswitch t.status.Val() {\n\t\tcase StatusRunning:\n\t\t\t// Timer proceeding.\n\t\t\tif currentTimerTicks = t.ticks.Add(1); currentTimerTicks >= t.queue.NextPriority() {\n\t\t\t\tt.proceed(currentTimerTicks)\n\t\t\t}\n\n\t\tcase StatusStopped:\n\t\t\t// Do nothing.\n\n\t\tcase StatusClosed:\n\t\t\t// Timer exits.\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// proceed function proceeds the timer job checking and running logic.\nfunc (t *Timer) proceed(currentTimerTicks int64) {\n\tvar value any\n\tfor {\n\t\tvalue = t.queue.Pop()\n\t\tif value == nil {\n\t\t\tbreak\n\t\t}\n\t\tentry := value.(*Entry)\n\t\t// It checks if it meets the ticks' requirement.\n\t\tif jobNextTicks := entry.nextTicks.Val(); currentTimerTicks < jobNextTicks {\n\t\t\t// It pushes the job back if current ticks does not meet its running ticks requirement.\n\t\t\tt.queue.Push(entry, entry.nextTicks.Val())\n\t\t\tbreak\n\t\t}\n\t\t// It checks the job running requirements and then does asynchronous running.\n\t\tentry.doCheckAndRunByTicks(currentTimerTicks)\n\t\t// Status check: push back or ignore it.\n\t\tif entry.Status() != StatusClosed {\n\t\t\t// It pushes the job back to queue for next running.\n\t\t\tt.queue.Push(entry, entry.nextTicks.Val())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar (\n\tctx   = context.TODO()\n\ttimer = New()\n)\n\nfunc Benchmark_Add(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\ttimer.Add(ctx, time.Hour, func(ctx context.Context) {\n\n\t\t})\n\t}\n}\n\nfunc Benchmark_PriorityQueue_Pop(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\ttimer.queue.Pop()\n\t}\n}\n\nfunc Benchmark_StartStop(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\ttimer.Start()\n\t\ttimer.Stop()\n\t}\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n)\n\nfunc ExampleAdd() {\n\tvar (\n\t\tctx      = context.Background()\n\t\tnow      = time.Now()\n\t\tinterval = 1400 * time.Millisecond\n\t)\n\tgtimer.Add(ctx, interval, func(ctx context.Context) {\n\t\tfmt.Println(time.Now(), time.Duration(time.Now().UnixNano()-now.UnixNano()))\n\t\tnow = time.Now()\n\t})\n\n\tselect {}\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_unit_entry_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Job Operations\n\npackage gtimer_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestJob_Start_Stop_Close(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\tjob := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tjob.Stop()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\tjob.Start()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\tjob.Close()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\n\t\tt.Assert(job.Status(), gtimer.StatusClosed)\n\t})\n}\n\nfunc TestJob_Singleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\tjob := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\tt.Assert(job.IsSingleton(), false)\n\t\tjob.SetSingleton(true)\n\t\tt.Assert(job.IsSingleton(), true)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestJob_SingletonQuick(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New(gtimer.TimerOptions{\n\t\t\tQuick: true,\n\t\t})\n\t\tarray := garray.New(true)\n\t\tjob := timer.Add(ctx, 5*time.Second, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\tt.Assert(job.IsSingleton(), false)\n\t\tjob.SetSingleton(true)\n\t\tt.Assert(job.IsSingleton(), true)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestJob_SetTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\tjob := timer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\tjob.SetTimes(2)\n\t\t//job.IsSingleton()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestJob_Run(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\tjob := timer.Add(ctx, 1000*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\tjob.Job()(ctx)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtimer\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestTimer_Proceed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\ttimer := New(TimerOptions{\n\t\t\tInterval: time.Hour,\n\t\t})\n\t\ttimer.Add(ctx, 10000*time.Hour, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttimer.proceed(10001)\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttimer.proceed(20001)\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\ttimer := New(TimerOptions{\n\t\t\tInterval: time.Millisecond * 100,\n\t\t})\n\t\ttimer.Add(ctx, 10000*time.Hour, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\tticks := int64((10000 * time.Hour) / (time.Millisecond * 100))\n\t\ttimer.proceed(ticks + 1)\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttimer.proceed(2*ticks + 1)\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestTimer_PriorityQueue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tqueue := newPriorityQueue()\n\t\tqueue.Push(1, 1)\n\t\tqueue.Push(4, 4)\n\t\tqueue.Push(5, 5)\n\t\tqueue.Push(2, 2)\n\t\tqueue.Push(3, 3)\n\t\tt.Assert(queue.Pop(), 1)\n\t\tt.Assert(queue.Pop(), 2)\n\t\tt.Assert(queue.Pop(), 3)\n\t\tt.Assert(queue.Pop(), 4)\n\t\tt.Assert(queue.Pop(), 5)\n\t})\n}\n\nfunc TestTimer_PriorityQueue_FirstOneInArrayIsTheLeast(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tsize  = 1000000\n\t\t\tarray = garray.NewIntArrayRange(0, size, 1)\n\t\t)\n\t\tarray.Shuffle()\n\t\tqueue := newPriorityQueue()\n\t\tarray.Iterator(func(k int, v int) bool {\n\t\t\tqueue.Push(v, int64(v))\n\t\t\treturn true\n\t\t})\n\t\tfor i := 0; i < size; i++ {\n\t\t\tt.Assert(queue.Pop(), i)\n\t\t\tt.Assert(queue.heap.array[0].priority, i+1)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package functions\n\npackage gtimer_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc TestSetTimeout(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.SetTimeout(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestSetInterval(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.SetInterval(ctx, 300*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 3)\n\t})\n}\n\nfunc TestAddEntry(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.AddEntry(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t}, false, 2, gtimer.StatusReady)\n\t\ttime.Sleep(1100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestAddSingleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.AddSingleton(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10000 * time.Millisecond)\n\t\t})\n\t\ttime.Sleep(1100 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestAddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.AddTimes(ctx, 200*time.Millisecond, 2, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestDelayAdd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.DelayAdd(ctx, 500*time.Millisecond, 500*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(600 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(600 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestDelayAddEntry(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.DelayAddEntry(ctx, 500*time.Millisecond, 500*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t}, false, 2, gtimer.StatusReady)\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(2000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestDelayAddSingleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.DelayAddSingleton(ctx, 500*time.Millisecond, 500*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10000 * time.Millisecond)\n\t\t})\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestDelayAddOnce(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.DelayAddOnce(ctx, 1000*time.Millisecond, 2000*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(2000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(2000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestDelayAddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tarray := garray.New(true)\n\t\tgtimer.DelayAddTimes(ctx, 500*time.Millisecond, 500*time.Millisecond, 2, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(1500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n"
  },
  {
    "path": "os/gtimer/gtimer_z_unit_timer_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Timer Operations\n\npackage gtimer_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/os/gtimer\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc TestTimer_Add_Close(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\t//fmt.Println(\"start\", time.Now())\n\t\ttimer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\t//fmt.Println(\"job1\", time.Now())\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttimer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\t//fmt.Println(\"job2\", time.Now())\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttimer.Add(ctx, 400*time.Millisecond, func(ctx context.Context) {\n\t\t\t//fmt.Println(\"job3\", time.Now())\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 5)\n\t\ttimer.Close()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tfixedLength := array.Len()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), fixedLength)\n\t})\n}\n\nfunc TestTimer_Start_Stop_Close(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.Add(ctx, 1000*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttimer.Stop()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t\ttimer.Start()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttimer.Close()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestJob_Reset(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\tjob := timer.AddSingleton(ctx, 500*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tjob.Reset()\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tjob.Reset()\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tjob.Reset()\n\t\ttime.Sleep(600 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_AddSingleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.AddSingleton(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_AddSingletonWithQuick(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New(gtimer.TimerOptions{\n\t\t\tInterval: 100 * time.Millisecond,\n\t\t\tQuick:    true,\n\t\t})\n\t\tarray := garray.New(true)\n\t\ttimer.AddSingleton(ctx, 5*time.Second, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_AddSingletonWithoutQuick(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New(gtimer.TimerOptions{\n\t\t\tInterval: 100 * time.Millisecond,\n\t\t\tQuick:    false,\n\t\t})\n\t\tarray := garray.New(true)\n\t\ttimer.AddSingleton(ctx, 5*time.Second, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t})\n}\n\nfunc TestTimer_AddOnce(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.AddOnce(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttimer.AddOnce(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t\ttimer.Close()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tfixedLength := array.Len()\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), fixedLength)\n\t})\n}\n\nfunc TestTimer_AddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.AddTimes(ctx, 200*time.Millisecond, 2, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestTimer_DelayAdd(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAdd(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_DelayAddJob(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAddEntry(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t}, false, 100, gtimer.StatusReady)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_DelayAddSingleton(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAddSingleton(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\ttime.Sleep(10 * time.Second)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_DelayAddOnce(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAddOnce(ctx, 200*time.Millisecond, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\n\t\ttime.Sleep(250 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_DelayAddTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAddTimes(ctx, 200*time.Millisecond, 500*time.Millisecond, 2, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\n\t\ttime.Sleep(600 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(600 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestTimer_AddLessThanInterval(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New(gtimer.TimerOptions{\n\t\t\tInterval: 100 * time.Millisecond,\n\t\t})\n\t\tarray := garray.New(true)\n\t\ttimer.Add(ctx, 20*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\n\t\ttime.Sleep(110 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\n\t\ttime.Sleep(110 * time.Millisecond)\n\t\tt.Assert(array.Len(), 2)\n\t})\n}\n\nfunc TestTimer_AddLeveledJob1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.DelayAdd(ctx, 1000*time.Millisecond, 1000*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t})\n\t\ttime.Sleep(1500 * time.Millisecond)\n\t\tt.Assert(array.Len(), 0)\n\t\ttime.Sleep(1300 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n\nfunc TestTimer_Exit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttimer := gtimer.New()\n\t\tarray := garray.New(true)\n\t\ttimer.Add(ctx, 200*time.Millisecond, func(ctx context.Context) {\n\t\t\tarray.Append(1)\n\t\t\tgtimer.Exit()\n\t\t})\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tt.Assert(array.Len(), 1)\n\t})\n}\n"
  },
  {
    "path": "os/gview/gview.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gview implements a template engine based on text/template.\n//\n// Reserved template variable names:\n// I18nLanguage: Assign this variable to define i18n language for each page.\npackage gview\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n)\n\n// View object for template engine.\ntype View struct {\n\tsearchPaths  *garray.StrArray                    // Searching array for path, NOT concurrent-safe for performance purpose.\n\tdata         map[string]any                      // Global template variables.\n\tfuncMap      map[string]any                      // Global template function map.\n\tfileCacheMap *gmap.KVMap[string, *fileCacheItem] // File cache map.\n\tconfig       Config                              // Extra configuration for the view.\n}\n\ntype (\n\tParams  = map[string]any // Params is type for template params.\n\tFuncMap = map[string]any // FuncMap is type for custom template functions.\n)\n\nconst (\n\tcommandEnvKeyForPath = \"gf.gview.path\"\n)\n\nvar (\n\t// Default view object.\n\tdefaultViewObj       *View\n\tfileCacheItemChecker = func(v *fileCacheItem) bool { return v == nil }\n)\n\n// checkAndInitDefaultView checks and initializes the default view object.\n// The default view object will be initialized just once.\nfunc checkAndInitDefaultView() {\n\tif defaultViewObj == nil {\n\t\tdefaultViewObj = New()\n\t}\n}\n\n// ParseContent parses the template content directly using the default view object\n// and returns the parsed content.\nfunc ParseContent(ctx context.Context, content string, params ...Params) (string, error) {\n\tcheckAndInitDefaultView()\n\treturn defaultViewObj.ParseContent(ctx, content, params...)\n}\n\n// New returns a new view object.\n// The parameter `path` specifies the template directory path to load template files.\nfunc New(path ...string) *View {\n\tvar (\n\t\tctx = context.TODO()\n\t)\n\tview := &View{\n\t\tsearchPaths:  garray.NewStrArray(),\n\t\tdata:         make(map[string]any),\n\t\tfuncMap:      make(map[string]any),\n\t\tfileCacheMap: gmap.NewKVMapWithChecker[string, *fileCacheItem](fileCacheItemChecker, true),\n\t\tconfig:       DefaultConfig(),\n\t}\n\tif len(path) > 0 && len(path[0]) > 0 {\n\t\tif err := view.SetPath(path[0]); err != nil {\n\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t}\n\t} else {\n\t\t// Customized dir path from env/cmd.\n\t\tif envPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); envPath != \"\" {\n\t\t\tif gfile.Exists(envPath) {\n\t\t\t\tif err := view.SetPath(envPath); err != nil {\n\t\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif errorPrint() {\n\t\t\t\t\tglog.Errorf(ctx, \"Template directory path does not exist: %s\", envPath)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Dir path of working dir.\n\t\t\tif pwdPath := gfile.Pwd(); pwdPath != \"\" {\n\t\t\t\tif err := view.SetPath(pwdPath); err != nil {\n\t\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Dir path of binary.\n\t\t\tif selfPath := gfile.SelfDir(); selfPath != \"\" && gfile.Exists(selfPath) {\n\t\t\t\tif err := view.AddPath(selfPath); err != nil {\n\t\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Dir path of main package.\n\t\t\tif mainPath := gfile.MainPkgPath(); mainPath != \"\" && gfile.Exists(mainPath) {\n\t\t\t\tif err := view.AddPath(mainPath); err != nil {\n\t\t\t\t\tintlog.Errorf(context.TODO(), `%+v`, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// set default delimiters.\n\tview.SetDelimiters(\"{{\", \"}}\")\n\t// default build-in functions.\n\tview.BindFuncMap(FuncMap{\n\t\t\"eq\":         view.buildInFuncEq,\n\t\t\"ne\":         view.buildInFuncNe,\n\t\t\"lt\":         view.buildInFuncLt,\n\t\t\"le\":         view.buildInFuncLe,\n\t\t\"gt\":         view.buildInFuncGt,\n\t\t\"ge\":         view.buildInFuncGe,\n\t\t\"text\":       view.buildInFuncText,\n\t\t\"html\":       view.buildInFuncHtmlEncode,\n\t\t\"htmlencode\": view.buildInFuncHtmlEncode,\n\t\t\"htmldecode\": view.buildInFuncHtmlDecode,\n\t\t\"encode\":     view.buildInFuncHtmlEncode,\n\t\t\"decode\":     view.buildInFuncHtmlDecode,\n\t\t\"url\":        view.buildInFuncUrlEncode,\n\t\t\"urlencode\":  view.buildInFuncUrlEncode,\n\t\t\"urldecode\":  view.buildInFuncUrlDecode,\n\t\t\"date\":       view.buildInFuncDate,\n\t\t\"substr\":     view.buildInFuncSubStr,\n\t\t\"strlimit\":   view.buildInFuncStrLimit,\n\t\t\"concat\":     view.buildInFuncConcat,\n\t\t\"replace\":    view.buildInFuncReplace,\n\t\t\"compare\":    view.buildInFuncCompare,\n\t\t\"hidestr\":    view.buildInFuncHideStr,\n\t\t\"highlight\":  view.buildInFuncHighlight,\n\t\t\"toupper\":    view.buildInFuncToUpper,\n\t\t\"tolower\":    view.buildInFuncToLower,\n\t\t\"nl2br\":      view.buildInFuncNl2Br,\n\t\t\"include\":    view.buildInFuncInclude,\n\t\t\"dump\":       view.buildInFuncDump,\n\t\t\"map\":        view.buildInFuncMap,\n\t\t\"maps\":       view.buildInFuncMaps,\n\t\t\"json\":       view.buildInFuncJson,\n\t\t\"xml\":        view.buildInFuncXml,\n\t\t\"ini\":        view.buildInFuncIni,\n\t\t\"yaml\":       view.buildInFuncYaml,\n\t\t\"yamli\":      view.buildInFuncYamlIndent,\n\t\t\"toml\":       view.buildInFuncToml,\n\t\t\"plus\":       view.buildInFuncPlus,\n\t\t\"minus\":      view.buildInFuncMinus,\n\t\t\"times\":      view.buildInFuncTimes,\n\t\t\"divide\":     view.buildInFuncDivide,\n\t})\n\treturn view\n}\n"
  },
  {
    "path": "os/gview/gview_buildin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\thtmltpl \"html/template\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghtml\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/encoding/gurl\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmode\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// buildInFuncDump implements build-in template function: dump\nfunc (view *View) buildInFuncDump(values ...any) string {\n\tbuffer := bytes.NewBuffer(nil)\n\tbuffer.WriteString(\"\\n\")\n\tbuffer.WriteString(\"<!--\\n\")\n\tif gmode.IsDevelop() {\n\t\tfor _, v := range values {\n\t\t\tgutil.DumpTo(buffer, v, gutil.DumpOption{})\n\t\t\tbuffer.WriteString(\"\\n\")\n\t\t}\n\t} else {\n\t\tbuffer.WriteString(\"dump feature is disabled as process is not running in develop mode\\n\")\n\t}\n\tbuffer.WriteString(\"-->\\n\")\n\treturn buffer.String()\n}\n\n// buildInFuncMap implements build-in template function: map\nfunc (view *View) buildInFuncMap(value ...any) map[string]any {\n\tif len(value) > 0 {\n\t\treturn gconv.Map(value[0])\n\t}\n\treturn map[string]any{}\n}\n\n// buildInFuncMaps implements build-in template function: maps\nfunc (view *View) buildInFuncMaps(value ...any) []map[string]any {\n\tif len(value) > 0 {\n\t\treturn gconv.Maps(value[0])\n\t}\n\treturn []map[string]any{}\n}\n\n// buildInFuncEq implements build-in template function: eq\nfunc (view *View) buildInFuncEq(value any, others ...any) bool {\n\ts := gconv.String(value)\n\tfor _, v := range others {\n\t\tif strings.Compare(s, gconv.String(v)) == 0 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// buildInFuncNe implements build-in template function: ne\nfunc (view *View) buildInFuncNe(value, other any) bool {\n\treturn strings.Compare(gconv.String(value), gconv.String(other)) != 0\n}\n\n// buildInFuncLt implements build-in template function: lt\nfunc (view *View) buildInFuncLt(value, other any) bool {\n\ts1 := gconv.String(value)\n\ts2 := gconv.String(other)\n\tif gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {\n\t\treturn gconv.Int64(value) < gconv.Int64(other)\n\t}\n\treturn strings.Compare(s1, s2) < 0\n}\n\n// buildInFuncLe implements build-in template function: le\nfunc (view *View) buildInFuncLe(value, other any) bool {\n\ts1 := gconv.String(value)\n\ts2 := gconv.String(other)\n\tif gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {\n\t\treturn gconv.Int64(value) <= gconv.Int64(other)\n\t}\n\treturn strings.Compare(s1, s2) <= 0\n}\n\n// buildInFuncGt implements build-in template function: gt\nfunc (view *View) buildInFuncGt(value, other any) bool {\n\ts1 := gconv.String(value)\n\ts2 := gconv.String(other)\n\tif gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {\n\t\treturn gconv.Int64(value) > gconv.Int64(other)\n\t}\n\treturn strings.Compare(s1, s2) > 0\n}\n\n// buildInFuncGe implements build-in template function: ge\nfunc (view *View) buildInFuncGe(value, other any) bool {\n\ts1 := gconv.String(value)\n\ts2 := gconv.String(other)\n\tif gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {\n\t\treturn gconv.Int64(value) >= gconv.Int64(other)\n\t}\n\treturn strings.Compare(s1, s2) >= 0\n}\n\n// buildInFuncInclude implements build-in template function: include\n// Note that configuration AutoEncode does not affect the output of this function.\nfunc (view *View) buildInFuncInclude(file any, data ...map[string]any) htmltpl.HTML {\n\tvar m map[string]any = nil\n\tif len(data) > 0 {\n\t\tm = data[0]\n\t}\n\tpath := gconv.String(file)\n\tif path == \"\" {\n\t\treturn \"\"\n\t}\n\t// It will search the file internally.\n\tcontent, err := view.Parse(context.TODO(), path, m)\n\tif err != nil {\n\t\treturn htmltpl.HTML(err.Error())\n\t}\n\treturn htmltpl.HTML(content)\n}\n\n// buildInFuncText implements build-in template function: text\nfunc (view *View) buildInFuncText(html any) string {\n\treturn ghtml.StripTags(gconv.String(html))\n}\n\n// buildInFuncHtmlEncode implements build-in template function: html\nfunc (view *View) buildInFuncHtmlEncode(html any) string {\n\treturn ghtml.Entities(gconv.String(html))\n}\n\n// buildInFuncHtmlDecode implements build-in template function: htmldecode\nfunc (view *View) buildInFuncHtmlDecode(html any) string {\n\treturn ghtml.EntitiesDecode(gconv.String(html))\n}\n\n// buildInFuncUrlEncode implements build-in template function: url\nfunc (view *View) buildInFuncUrlEncode(url any) string {\n\treturn gurl.Encode(gconv.String(url))\n}\n\n// buildInFuncUrlDecode implements build-in template function: urldecode\nfunc (view *View) buildInFuncUrlDecode(url any) string {\n\tif content, err := gurl.Decode(gconv.String(url)); err == nil {\n\t\treturn content\n\t} else {\n\t\treturn err.Error()\n\t}\n}\n\n// buildInFuncDate implements build-in template function: date\nfunc (view *View) buildInFuncDate(format any, timestamp ...any) string {\n\tt := int64(0)\n\tif len(timestamp) > 0 {\n\t\tt = gconv.Int64(timestamp[0])\n\t}\n\tif t == 0 {\n\t\tt = gtime.Timestamp()\n\t}\n\treturn gtime.NewFromTimeStamp(t).Format(gconv.String(format))\n}\n\n// buildInFuncCompare implements build-in template function: compare\nfunc (view *View) buildInFuncCompare(value1, value2 any) int {\n\treturn strings.Compare(gconv.String(value1), gconv.String(value2))\n}\n\n// buildInFuncSubStr implements build-in template function: substr\nfunc (view *View) buildInFuncSubStr(start, end, str any) string {\n\treturn gstr.SubStrRune(gconv.String(str), gconv.Int(start), gconv.Int(end))\n}\n\n// buildInFuncStrLimit implements build-in template function: strlimit\nfunc (view *View) buildInFuncStrLimit(length, suffix, str any) string {\n\treturn gstr.StrLimitRune(gconv.String(str), gconv.Int(length), gconv.String(suffix))\n}\n\n// buildInFuncConcat implements build-in template function: concat\nfunc (view *View) buildInFuncConcat(str ...any) string {\n\tvar s string\n\tfor _, v := range str {\n\t\ts += gconv.String(v)\n\t}\n\treturn s\n}\n\n// buildInFuncReplace implements build-in template function: replace\nfunc (view *View) buildInFuncReplace(search, replace, str any) string {\n\treturn gstr.Replace(gconv.String(str), gconv.String(search), gconv.String(replace), -1)\n}\n\n// buildInFuncHighlight implements build-in template function: highlight\nfunc (view *View) buildInFuncHighlight(key, color, str any) string {\n\treturn gstr.Replace(gconv.String(str), gconv.String(key), fmt.Sprintf(`<span style=\"color:%v;\">%v</span>`, color, key))\n}\n\n// buildInFuncHideStr implements build-in template function: hidestr\nfunc (view *View) buildInFuncHideStr(percent, hide, str any) string {\n\treturn gstr.HideStr(gconv.String(str), gconv.Int(percent), gconv.String(hide))\n}\n\n// buildInFuncToUpper implements build-in template function: toupper\nfunc (view *View) buildInFuncToUpper(str any) string {\n\treturn gstr.ToUpper(gconv.String(str))\n}\n\n// buildInFuncToLower implements build-in template function: toupper\nfunc (view *View) buildInFuncToLower(str any) string {\n\treturn gstr.ToLower(gconv.String(str))\n}\n\n// buildInFuncNl2Br implements build-in template function: nl2br\nfunc (view *View) buildInFuncNl2Br(str any) string {\n\treturn gstr.Nl2Br(gconv.String(str))\n}\n\n// buildInFuncJson implements build-in template function: json ,\n// which encodes and returns `value` as JSON string.\nfunc (view *View) buildInFuncJson(value any) (string, error) {\n\tb, err := gjson.Marshal(value)\n\treturn string(b), err\n}\n\n// buildInFuncXml implements build-in template function: xml ,\n// which encodes and returns `value` as XML string.\nfunc (view *View) buildInFuncXml(value any, rootTag ...string) (string, error) {\n\tb, err := gjson.New(value).ToXml(rootTag...)\n\treturn string(b), err\n}\n\n// buildInFuncIni implements build-in template function: ini ,\n// which encodes and returns `value` as XML string.\nfunc (view *View) buildInFuncIni(value any) (string, error) {\n\tb, err := gjson.New(value).ToIni()\n\treturn string(b), err\n}\n\n// buildInFuncYaml implements build-in template function: yaml ,\n// which encodes and returns `value` as YAML string.\nfunc (view *View) buildInFuncYaml(value any) (string, error) {\n\tb, err := gjson.New(value).ToYaml()\n\treturn string(b), err\n}\n\n// buildInFuncYamlIndent implements build-in template function: yamli ,\n// which encodes and returns `value` as YAML string with custom indent string.\nfunc (view *View) buildInFuncYamlIndent(value, indent any) (string, error) {\n\tb, err := gjson.New(value).ToYamlIndent(gconv.String(indent))\n\treturn string(b), err\n}\n\n// buildInFuncToml implements build-in template function: toml ,\n// which encodes and returns `value` as TOML string.\nfunc (view *View) buildInFuncToml(value any) (string, error) {\n\tb, err := gjson.New(value).ToToml()\n\treturn string(b), err\n}\n\n// buildInFuncPlus implements build-in template function: plus ,\n// which returns the result that pluses all `deltas` to `value`.\nfunc (view *View) buildInFuncPlus(value any, deltas ...any) string {\n\tresult := gconv.Float64(value)\n\tfor _, v := range deltas {\n\t\tresult += gconv.Float64(v)\n\t}\n\treturn gconv.String(result)\n}\n\n// buildInFuncMinus implements build-in template function: minus ,\n// which returns the result that subtracts all `deltas` from `value`.\nfunc (view *View) buildInFuncMinus(value any, deltas ...any) string {\n\tresult := gconv.Float64(value)\n\tfor _, v := range deltas {\n\t\tresult -= gconv.Float64(v)\n\t}\n\treturn gconv.String(result)\n}\n\n// buildInFuncTimes implements build-in template function: times ,\n// which returns the result that multiplies `value` by all of `values`.\nfunc (view *View) buildInFuncTimes(value any, values ...any) string {\n\tresult := gconv.Float64(value)\n\tfor _, v := range values {\n\t\tresult *= gconv.Float64(v)\n\t}\n\treturn gconv.String(result)\n}\n\n// buildInFuncDivide implements build-in template function: divide ,\n// which returns the result that divides `value` by all of `values`.\nfunc (view *View) buildInFuncDivide(value any, values ...any) string {\n\tresult := gconv.Float64(value)\n\tfor _, v := range values {\n\t\tvalue2Float64 := gconv.Float64(v)\n\t\tif value2Float64 == 0 {\n\t\t\t// Invalid `value2`.\n\t\t\treturn \"0\"\n\t\t}\n\t\tresult /= value2Float64\n\t}\n\treturn gconv.String(result)\n}\n"
  },
  {
    "path": "os/gview/gview_config.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gspath\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// Config is the configuration object for template engine.\ntype Config struct {\n\tPaths       []string       `json:\"paths\"`       // Searching array for path, NOT concurrent-safe for performance purpose.\n\tData        map[string]any `json:\"data\"`        // Global template variables including configuration.\n\tDefaultFile string         `json:\"defaultFile\"` // Default template file for parsing.\n\tDelimiters  []string       `json:\"delimiters\"`  // Custom template delimiters.\n\tAutoEncode  bool           `json:\"autoEncode\"`  // Automatically encodes and provides safe html output, which is good for avoiding XSS.\n\tI18nManager *gi18n.Manager `json:\"-\"`           // I18n manager for the view.\n}\n\nconst (\n\t// Default template file for parsing.\n\tdefaultParsingFile = \"index.html\"\n)\n\n// DefaultConfig creates and returns a configuration object with default configurations.\nfunc DefaultConfig() Config {\n\treturn Config{\n\t\tDefaultFile: defaultParsingFile,\n\t\tI18nManager: gi18n.Instance(),\n\t\tDelimiters:  make([]string, 2),\n\t}\n}\n\n// SetConfig sets the configuration for view.\nfunc (view *View) SetConfig(config Config) error {\n\tvar err error\n\tif len(config.Paths) > 0 {\n\t\tfor _, v := range config.Paths {\n\t\t\tif err = view.AddPath(v); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif len(config.Data) > 0 {\n\t\tview.Assigns(config.Data)\n\t}\n\tif config.DefaultFile != \"\" {\n\t\tview.SetDefaultFile(config.DefaultFile)\n\t}\n\tif len(config.Delimiters) > 1 {\n\t\tview.SetDelimiters(config.Delimiters[0], config.Delimiters[1])\n\t}\n\tview.config = config\n\t// Clear global template object cache.\n\t// It's just cache, do not hesitate clearing it.\n\ttemplates.Clear()\n\n\tintlog.Printf(context.TODO(), \"SetConfig: %+v\", view.config)\n\treturn nil\n}\n\n// SetConfigWithMap set configurations with map for the view.\nfunc (view *View) SetConfigWithMap(m map[string]any) error {\n\tif len(m) == 0 {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"configuration cannot be empty\")\n\t}\n\t// The m now is a shallow copy of m.\n\t// Any changes to m does not affect the original one.\n\t// A little tricky, isn't it?\n\tm = gutil.MapCopy(m)\n\t// Most common used configuration support for single view path.\n\t_, v1 := gutil.MapPossibleItemByKey(m, \"paths\")\n\t_, v2 := gutil.MapPossibleItemByKey(m, \"path\")\n\tif v1 == nil && v2 != nil {\n\t\tswitch v2 := v2.(type) {\n\t\tcase string:\n\t\t\tm[\"paths\"] = []string{v2}\n\t\tcase []string:\n\t\t\tm[\"paths\"] = v2\n\t\t}\n\t}\n\terr := gconv.Struct(m, &view.config)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn view.SetConfig(view.config)\n}\n\n// SetPath sets the template directory path for template file search.\n// The parameter `path` can be absolute or relative path, but absolute path is suggested.\nfunc (view *View) SetPath(path string) error {\n\tvar (\n\t\tctx      = context.TODO()\n\t\tisDir    = false\n\t\trealPath = \"\"\n\t)\n\tif file := gres.Get(path); file != nil {\n\t\trealPath = path\n\t\tisDir = file.FileInfo().IsDir()\n\t} else {\n\t\t// Absolute path.\n\t\trealPath = gfile.RealPath(path)\n\t\tif realPath == \"\" {\n\t\t\t// Relative path.\n\t\t\tview.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor _, v := range array {\n\t\t\t\t\tif path, _ := gspath.Search(v, path); path != \"\" {\n\t\t\t\t\t\trealPath = path\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tif realPath != \"\" {\n\t\t\tisDir = gfile.IsDir(realPath)\n\t\t}\n\t}\n\t// Path not exist.\n\tif realPath == \"\" {\n\t\terr := gerror.NewCodef(gcode.CodeInvalidParameter, `View.SetPath failed: path \"%s\" does not exist`, path)\n\t\tif errorPrint() {\n\t\t\tglog.Error(ctx, err)\n\t\t}\n\t\treturn err\n\t}\n\t// Should be a directory.\n\tif !isDir {\n\t\terr := gerror.NewCodef(gcode.CodeInvalidParameter, `View.SetPath failed: path \"%s\" should be directory type`, path)\n\t\tif errorPrint() {\n\t\t\tglog.Error(ctx, err)\n\t\t}\n\t\treturn err\n\t}\n\t// Repeated path adding check.\n\tif view.searchPaths.Search(realPath) != -1 {\n\t\treturn nil\n\t}\n\tview.searchPaths.Clear()\n\tview.searchPaths.Append(realPath)\n\tview.fileCacheMap.Clear()\n\treturn nil\n}\n\n// AddPath adds an absolute or relative path to the search paths.\nfunc (view *View) AddPath(path string) error {\n\tvar (\n\t\tctx      = context.TODO()\n\t\tisDir    = false\n\t\trealPath = \"\"\n\t)\n\tif file := gres.Get(path); file != nil {\n\t\trealPath = path\n\t\tisDir = file.FileInfo().IsDir()\n\t} else {\n\t\t// Absolute path.\n\t\tif realPath = gfile.RealPath(path); realPath == \"\" {\n\t\t\t// Relative path.\n\t\t\tview.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor _, v := range array {\n\t\t\t\t\tif searchedPath, _ := gspath.Search(v, path); searchedPath != \"\" {\n\t\t\t\t\t\trealPath = searchedPath\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tif realPath != \"\" {\n\t\t\tisDir = gfile.IsDir(realPath)\n\t\t}\n\t}\n\t// Path doesn't exist.\n\tif realPath == \"\" {\n\t\terr := gerror.NewCodef(gcode.CodeInvalidParameter, `View.AddPath failed: path \"%s\" does not exist`, path)\n\t\tif errorPrint() {\n\t\t\tglog.Error(ctx, err)\n\t\t}\n\t\treturn err\n\t}\n\t// realPath should be type of folder.\n\tif !isDir {\n\t\terr := gerror.NewCodef(gcode.CodeInvalidParameter, `View.AddPath failed: path \"%s\" should be directory type`, path)\n\t\tif errorPrint() {\n\t\t\tglog.Error(ctx, err)\n\t\t}\n\t\treturn err\n\t}\n\t// Repeated path adding check.\n\tif view.searchPaths.Search(realPath) != -1 {\n\t\treturn nil\n\t}\n\tview.searchPaths.Append(realPath)\n\tview.fileCacheMap.Clear()\n\treturn nil\n}\n\n// Assigns binds multiple global template variables to current view object.\n// Note that it's not concurrent-safe, which means it would panic\n// if it's called in multiple goroutines in runtime.\nfunc (view *View) Assigns(data Params) {\n\tfor k, v := range data {\n\t\tview.data[k] = v\n\t}\n}\n\n// Assign binds a global template variable to current view object.\n// Note that it's not concurrent-safe, which means it would panic\n// if it's called in multiple goroutines in runtime.\nfunc (view *View) Assign(key string, value any) {\n\tview.data[key] = value\n}\n\n// ClearAssigns trunk all global template variables assignments.\nfunc (view *View) ClearAssigns() {\n\tview.data = make(map[string]any)\n}\n\n// SetDefaultFile sets default template file for parsing.\nfunc (view *View) SetDefaultFile(file string) {\n\tview.config.DefaultFile = file\n}\n\n// GetDefaultFile returns default template file for parsing.\nfunc (view *View) GetDefaultFile() string {\n\treturn view.config.DefaultFile\n}\n\n// SetDelimiters sets customized delimiters for template parsing.\nfunc (view *View) SetDelimiters(left, right string) {\n\tview.config.Delimiters = []string{left, right}\n}\n\n// SetAutoEncode enables/disables automatically html encoding feature.\n// When AutoEncode feature is enables, view engine automatically encodes and provides safe html output,\n// which is good for avoid XSS.\nfunc (view *View) SetAutoEncode(enable bool) {\n\tview.config.AutoEncode = enable\n}\n\n// BindFunc registers customized global template function named `name`\n// with given function `function` to current view object.\n// The `name` is the function name which can be called in template content.\nfunc (view *View) BindFunc(name string, function any) {\n\tview.funcMap[name] = function\n\t// Clear global template object cache.\n\ttemplates.Clear()\n}\n\n// BindFuncMap registers customized global template functions by map to current view object.\n// The key of map is the template function name\n// and the value of map is the address of customized function.\nfunc (view *View) BindFuncMap(funcMap FuncMap) {\n\tfor k, v := range funcMap {\n\t\tview.funcMap[k] = v\n\t}\n\t// Clear global template object cache.\n\ttemplates.Clear()\n}\n\n// SetI18n binds i18n manager to current view engine.\nfunc (view *View) SetI18n(manager *gi18n.Manager) {\n\tview.config.I18nManager = manager\n}\n"
  },
  {
    "path": "os/gview/gview_error.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport (\n\t\"github.com/gogf/gf/v2/os/gcmd\"\n)\n\nconst (\n\t// commandEnvKeyForErrorPrint is used to specify the key controlling error printing to stdout.\n\t// This error is designed not to be returned by functions.\n\tcommandEnvKeyForErrorPrint = \"gf.gview.errorprint\"\n)\n\n// errorPrint checks whether printing error to stdout.\nfunc errorPrint() bool {\n\treturn gcmd.GetOptWithEnv(commandEnvKeyForErrorPrint, true).Bool()\n}\n"
  },
  {
    "path": "os/gview/gview_i18n.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\ti18nLanguageVariableName = \"I18nLanguage\"\n)\n\n// i18nTranslate translate the content with i18n feature.\nfunc (view *View) i18nTranslate(ctx context.Context, content string, variables Params) string {\n\tif view.config.I18nManager != nil {\n\t\t// Compatible with old version.\n\t\tif language, ok := variables[i18nLanguageVariableName]; ok {\n\t\t\tctx = gi18n.WithLanguage(ctx, gconv.String(language))\n\t\t}\n\t\treturn view.config.I18nManager.T(ctx, content)\n\t}\n\treturn content\n}\n\n// setI18nLanguageFromCtx retrieves language name from context and sets it to template variables map.\nfunc (view *View) setI18nLanguageFromCtx(ctx context.Context, variables map[string]any) {\n\tif _, ok := variables[i18nLanguageVariableName]; !ok {\n\t\tif language := gi18n.LanguageFromCtx(ctx); language != \"\" {\n\t\t\tvariables[i18nLanguageVariableName] = language\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "os/gview/gview_instance.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport \"github.com/gogf/gf/v2/container/gmap\"\n\nconst (\n\t// DefaultName is the default group name for instance usage.\n\tDefaultName = \"default\"\n)\n\nvar (\n\tchecker = func(v *View) bool { return v == nil }\n\t// Instances map.\n\tinstances = gmap.NewKVMapWithChecker[string, *View](checker, true)\n)\n\n// Instance returns an instance of View with default settings.\n// The parameter `name` is the name for the instance.\nfunc Instance(name ...string) *View {\n\tkey := DefaultName\n\tif len(name) > 0 && name[0] != \"\" {\n\t\tkey = name[0]\n\t}\n\treturn instances.GetOrSetFuncLock(key, func() *View {\n\t\treturn New()\n\t})\n}\n"
  },
  {
    "path": "os/gview/gview_parse.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\thtmltpl \"html/template\"\n\t\"strconv\"\n\t\"strings\"\n\ttexttpl \"text/template\"\n\n\t\"github.com/gogf/gf/v2\"\n\t\"github.com/gogf/gf/v2/container/gmap\"\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gfsnotify\"\n\t\"github.com/gogf/gf/v2/os/glog\"\n\t\"github.com/gogf/gf/v2/os/gmlock\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gspath\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nconst (\n\t// Template name for content parsing.\n\ttemplateNameForContentParsing = \"TemplateContent\"\n)\n\n// fileCacheItem is the cache item for the template file.\ntype fileCacheItem struct {\n\tpath    string\n\tfolder  string\n\tcontent string\n}\n\nvar (\n\t// Templates cache map for template folder.\n\t// Note that there's no expiring logic for this map.\n\ttemplates = gmap.NewStrAnyMap(true)\n\n\t// Try-folders for resource template file searching.\n\tresourceTryFolders = []string{\n\t\t\"template/\", \"template\", \"/template\", \"/template/\",\n\t\t\"resource/template/\", \"resource/template\", \"/resource/template\", \"/resource/template/\",\n\t}\n\n\t// Prefix array for trying searching in the local system.\n\tlocalSystemTryFolders = []string{\"\", \"template/\", \"resource/template\"}\n)\n\n// Parse parses given template file `file` with given template variables `params`\n// and returns the parsed template content.\nfunc (view *View) Parse(ctx context.Context, file string, params ...Params) (result string, err error) {\n\tvar usedParams Params\n\tif len(params) > 0 {\n\t\tusedParams = params[0]\n\t}\n\treturn view.ParseOption(ctx, Option{\n\t\tFile:    file,\n\t\tContent: \"\",\n\t\tOrphan:  false,\n\t\tParams:  usedParams,\n\t})\n}\n\n// ParseDefault parses the default template file with params.\nfunc (view *View) ParseDefault(ctx context.Context, params ...Params) (result string, err error) {\n\tvar usedParams Params\n\tif len(params) > 0 {\n\t\tusedParams = params[0]\n\t}\n\treturn view.ParseOption(ctx, Option{\n\t\tFile:    view.config.DefaultFile,\n\t\tContent: \"\",\n\t\tOrphan:  false,\n\t\tParams:  usedParams,\n\t})\n}\n\n// ParseContent parses given template content `content` with template variables `params`\n// and returns the parsed content in []byte.\nfunc (view *View) ParseContent(ctx context.Context, content string, params ...Params) (string, error) {\n\tvar usedParams Params\n\tif len(params) > 0 {\n\t\tusedParams = params[0]\n\t}\n\treturn view.ParseOption(ctx, Option{\n\t\tContent: content,\n\t\tOrphan:  false,\n\t\tParams:  usedParams,\n\t})\n}\n\n// Option for template parsing.\n//\n// Deprecated: use Options instead.\ntype Option = Options\n\n// Options for template parsing.\ntype Options struct {\n\tFile    string // Template file path in absolute or relative to searching paths.\n\tContent string // Template content, it ignores `File` if `Content` is given.\n\tOrphan  bool   // If true, the `File` is considered as a single file parsing without files recursively parsing from its folder.\n\tParams  Params // Template parameters map.\n}\n\n// ParseOption implements template parsing using Option.\n//\n// Deprecated: use ParseWithOptions instead.\nfunc (view *View) ParseOption(ctx context.Context, option Option) (result string, err error) {\n\treturn view.ParseWithOptions(ctx, option)\n}\n\n// ParseWithOptions implements template parsing using Option.\nfunc (view *View) ParseWithOptions(ctx context.Context, opts Options) (result string, err error) {\n\tif opts.Content != \"\" {\n\t\treturn view.doParseContent(ctx, opts.Content, opts.Params)\n\t}\n\tif opts.File == \"\" {\n\t\treturn \"\", gerror.New(`template file cannot be empty`)\n\t}\n\t// It caches the file, folder, and content to enhance performance.\n\tr := view.fileCacheMap.GetOrSetFuncLock(opts.File, func() *fileCacheItem {\n\t\tvar (\n\t\t\tpath     string\n\t\t\tfolder   string\n\t\t\tcontent  string\n\t\t\tresource *gres.File\n\t\t)\n\t\t// Searching the absolute file path for `file`.\n\t\tpath, folder, resource, err = view.searchFile(ctx, opts.File)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tif resource != nil {\n\t\t\tcontent = string(resource.Content())\n\t\t} else {\n\t\t\tcontent = gfile.GetContentsWithCache(path)\n\t\t}\n\t\t// Monitor template files changes using fsnotify asynchronously.\n\t\tif resource == nil {\n\t\t\tif _, err = gfsnotify.AddOnce(\n\t\t\t\t\"gview.Parse:\"+folder, folder, func(event *gfsnotify.Event) {\n\t\t\t\t\t// CLEAR THEM ALL.\n\t\t\t\t\tview.fileCacheMap.Clear()\n\t\t\t\t\ttemplates.Clear()\n\t\t\t\t\tgfsnotify.Exit()\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\tintlog.Errorf(ctx, `%+v`, err)\n\t\t\t}\n\t\t}\n\t\treturn &fileCacheItem{\n\t\t\tpath:    path,\n\t\t\tfolder:  folder,\n\t\t\tcontent: content,\n\t\t}\n\t})\n\tif r == nil {\n\t\treturn\n\t}\n\t// It's not necessary continuing parsing if template content is empty.\n\tif r.content == \"\" {\n\t\treturn \"\", nil\n\t}\n\t// If it's an Orphan option, it just parses the single file by ParseContent.\n\tif opts.Orphan {\n\t\treturn view.doParseContent(ctx, r.content, opts.Params)\n\t}\n\t// Get the template object instance for `folder`.\n\tvar tpl any\n\ttpl, err = view.getTemplate(r.path, r.folder, fmt.Sprintf(`*%s`, gfile.Ext(r.path)))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// Using memory lock to ensure concurrent safety for template parsing.\n\tgmlock.LockFunc(\"gview.Parse:\"+r.path, func() {\n\t\tif view.config.AutoEncode {\n\t\t\ttpl, err = tpl.(*htmltpl.Template).Parse(r.content)\n\t\t} else {\n\t\t\ttpl, err = tpl.(*texttpl.Template).Parse(r.content)\n\t\t}\n\t\tif err != nil && r.path != \"\" {\n\t\t\terr = gerror.Wrap(err, r.path)\n\t\t}\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn view.doParseContentWithStdTemplate(ctx, tpl, opts.Params)\n}\n\n// doParseContent parses given template content `content` with template variables `params`\n// and returns the parsed content in []byte.\nfunc (view *View) doParseContent(ctx context.Context, content string, params Params) (string, error) {\n\t// It's not necessary continuing parsing if template content is empty.\n\tif content == \"\" {\n\t\treturn \"\", nil\n\t}\n\tvar (\n\t\terr error\n\t\tkey = fmt.Sprintf(\"%s_%v_%v\", templateNameForContentParsing, view.config.Delimiters, view.config.AutoEncode)\n\t\ttpl = templates.GetOrSetFuncLock(key, func() any {\n\t\t\tif view.config.AutoEncode {\n\t\t\t\treturn htmltpl.New(templateNameForContentParsing).Delims(\n\t\t\t\t\tview.config.Delimiters[0],\n\t\t\t\t\tview.config.Delimiters[1],\n\t\t\t\t).Funcs(view.funcMap)\n\t\t\t}\n\t\t\treturn texttpl.New(templateNameForContentParsing).Delims(\n\t\t\t\tview.config.Delimiters[0],\n\t\t\t\tview.config.Delimiters[1],\n\t\t\t).Funcs(view.funcMap)\n\t\t})\n\t)\n\t// Using memory lock to ensure concurrent safety for content parsing.\n\thash := strconv.FormatUint(ghash.DJB64([]byte(content)), 10)\n\tgmlock.LockFunc(\"gview.ParseContent:\"+hash, func() {\n\t\tif view.config.AutoEncode {\n\t\t\ttpl, err = tpl.(*htmltpl.Template).Parse(content)\n\t\t} else {\n\t\t\ttpl, err = tpl.(*texttpl.Template).Parse(content)\n\t\t}\n\t})\n\tif err != nil {\n\t\terr = gerror.Wrapf(err, `template parsing failed`)\n\t\treturn \"\", err\n\t}\n\treturn view.doParseContentWithStdTemplate(ctx, tpl, params)\n}\n\nfunc (view *View) doParseContentWithStdTemplate(ctx context.Context, tpl any, params Params) (string, error) {\n\t// Note that the template variable assignment cannot change the value\n\t// of the existing `params` or view.data because both variables are pointers.\n\t// It needs to merge the values of the two maps into a new map.\n\tvariables := gutil.MapMergeCopy(params, view.getBuiltInParams())\n\tif len(view.data) > 0 {\n\t\tgutil.MapMerge(variables, view.data)\n\t}\n\tview.setI18nLanguageFromCtx(ctx, variables)\n\n\tbuffer := bytes.NewBuffer(nil)\n\tif view.config.AutoEncode {\n\t\tvar newTpl *htmltpl.Template\n\t\tnewTpl, err := tpl.(*htmltpl.Template).Clone()\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `template clone failed`)\n\t\t\treturn \"\", err\n\t\t}\n\t\tif err = newTpl.Execute(buffer, variables); err != nil {\n\t\t\terr = gerror.Wrapf(err, `template parsing failed`)\n\t\t\treturn \"\", err\n\t\t}\n\t} else {\n\t\tif err := tpl.(*texttpl.Template).Execute(buffer, variables); err != nil {\n\t\t\terr = gerror.Wrapf(err, `template parsing failed`)\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\t// TODO any graceful plan to replace \"<no value>\"?\n\tresult := gstr.Replace(buffer.String(), \"<no value>\", \"\")\n\tresult = view.i18nTranslate(ctx, result, variables)\n\treturn result, nil\n}\n\nfunc (view *View) getBuiltInParams() map[string]any {\n\treturn map[string]any{\n\t\t\"version\": gf.VERSION,\n\t}\n}\n\n// getTemplate returns the template object associated with given template file `path`.\n// It uses template cache to enhance performance, that is, it will return the same template object\n// with the same given `path`. It will also automatically refresh the template cache\n// if the template files under `path` changes (recursively).\nfunc (view *View) getTemplate(filePath, folderPath, pattern string) (tpl any, err error) {\n\tvar (\n\t\tmapKey  = fmt.Sprintf(\"%s_%v\", filePath, view.config.Delimiters)\n\t\tmapFunc = func() any {\n\t\t\ttplName := filePath\n\t\t\tif view.config.AutoEncode {\n\t\t\t\ttpl = htmltpl.New(tplName).Delims(\n\t\t\t\t\tview.config.Delimiters[0],\n\t\t\t\t\tview.config.Delimiters[1],\n\t\t\t\t).Funcs(view.funcMap)\n\t\t\t} else {\n\t\t\t\ttpl = texttpl.New(tplName).Delims(\n\t\t\t\t\tview.config.Delimiters[0],\n\t\t\t\t\tview.config.Delimiters[1],\n\t\t\t\t).Funcs(view.funcMap)\n\t\t\t}\n\t\t\t// Firstly, checking the resource manager.\n\t\t\tif !gres.IsEmpty() {\n\t\t\t\tif files := gres.ScanDirFile(folderPath, pattern, true); len(files) > 0 {\n\t\t\t\t\tif view.config.AutoEncode {\n\t\t\t\t\t\tvar t = tpl.(*htmltpl.Template)\n\t\t\t\t\t\tfor _, v := range files {\n\t\t\t\t\t\t\t_, err = t.New(v.FileInfo().Name()).Parse(string(v.Content()))\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\terr = view.formatTemplateObjectCreatingError(v.Name(), tplName, err)\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar t = tpl.(*texttpl.Template)\n\t\t\t\t\t\tfor _, v := range files {\n\t\t\t\t\t\t\t_, err = t.New(v.FileInfo().Name()).Parse(string(v.Content()))\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\terr = view.formatTemplateObjectCreatingError(v.Name(), tplName, err)\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn tpl\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Secondly, checking the file system,\n\t\t\t// and then automatically parsing all its sub-files recursively.\n\t\t\tvar files []string\n\t\t\tfiles, err = gfile.ScanDir(folderPath, pattern, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif view.config.AutoEncode {\n\t\t\t\tt := tpl.(*htmltpl.Template)\n\t\t\t\tfor _, file := range files {\n\t\t\t\t\tif _, err = t.Parse(gfile.GetContents(file)); err != nil {\n\t\t\t\t\t\terr = view.formatTemplateObjectCreatingError(file, tplName, err)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tt := tpl.(*texttpl.Template)\n\t\t\t\tfor _, file := range files {\n\t\t\t\t\tif _, err = t.Parse(gfile.GetContents(file)); err != nil {\n\t\t\t\t\t\terr = view.formatTemplateObjectCreatingError(file, tplName, err)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tpl\n\t\t}\n\t)\n\tresult := templates.GetOrSetFuncLock(mapKey, mapFunc)\n\tif result != nil {\n\t\treturn result, nil\n\t}\n\treturn\n}\n\n// formatTemplateObjectCreatingError formats the error that created from creating the template object.\nfunc (view *View) formatTemplateObjectCreatingError(filePath, tplName string, err error) error {\n\tif err != nil {\n\t\treturn gerror.NewSkip(1, gstr.Replace(err.Error(), tplName, filePath))\n\t}\n\treturn nil\n}\n\n// searchFile returns the absolute path of the `file` and its template folder path.\n// The returned `folder` is the template folder path, not the folder of the template file `path`.\nfunc (view *View) searchFile(ctx context.Context, file string) (path string, folder string, resource *gres.File, err error) {\n\tvar (\n\t\ttempPath    string\n\t\ttrimmedFile = strings.TrimLeft(file, `\\/`)\n\t)\n\t// Firstly checking the resource manager.\n\tif !gres.IsEmpty() {\n\t\t// Search folders.\n\t\tif path == \"\" {\n\t\t\tview.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tfor _, searchPath := range array {\n\t\t\t\t\ttempPath = strings.TrimRight(searchPath, `\\/`) + `/` + trimmedFile\n\t\t\t\t\tif tmpFile := gres.Get(tempPath); tmpFile != nil {\n\t\t\t\t\t\tpath = tmpFile.Name()\n\t\t\t\t\t\tfolder = searchPath\n\t\t\t\t\t\tresource = tmpFile\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tfor _, tryFolder := range resourceTryFolders {\n\t\t\t\t\t\ttempPath = strings.TrimRight(searchPath, `\\/`) + `/` + strings.TrimRight(tryFolder, `\\/`) + `/` + file\n\t\t\t\t\t\tif tmpFile := gres.Get(tempPath); tmpFile != nil {\n\t\t\t\t\t\t\tpath = tmpFile.Name()\n\t\t\t\t\t\t\tfolder = searchPath + tryFolder\n\t\t\t\t\t\t\tresource = tmpFile\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\t// Try folders.\n\t\tif path == \"\" {\n\t\t\tfor _, tryFolder := range resourceTryFolders {\n\t\t\t\ttempPath = strings.TrimRight(tryFolder, `\\/`) + `/` + trimmedFile\n\t\t\t\tif tmpFile := gres.Get(tempPath); tmpFile != nil {\n\t\t\t\t\tpath = tmpFile.Name()\n\t\t\t\t\tfolder = tryFolder\n\t\t\t\t\tresource = tmpFile\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Secondly, checking the file system.\n\tif path == \"\" {\n\t\t// Absolute path.\n\t\tpath = gfile.RealPath(file)\n\t\tif path != \"\" {\n\t\t\tfolder = gfile.Dir(path)\n\t\t\treturn\n\t\t}\n\t\t// In search paths.\n\t\tview.searchPaths.RLockFunc(func(array []string) {\n\t\t\tfor _, searchPath := range array {\n\t\t\t\tsearchPath = gstr.TrimRight(searchPath, `\\/`)\n\t\t\t\tfor _, tryFolder := range localSystemTryFolders {\n\t\t\t\t\trelativePath := gstr.TrimRight(\n\t\t\t\t\t\tgfile.Join(tryFolder, file),\n\t\t\t\t\t\t`\\/`,\n\t\t\t\t\t)\n\t\t\t\t\tif path, _ = gspath.Search(searchPath, relativePath); path != \"\" {\n\t\t\t\t\t\tfolder = gfile.Join(searchPath, tryFolder)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t// Error checking.\n\tif path == \"\" {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tif view.searchPaths.Len() > 0 {\n\t\t\tfmt.Fprintf(buffer, \"cannot find template file \\\"%s\\\" in following paths:\", file)\n\t\t\tview.searchPaths.RLockFunc(func(array []string) {\n\t\t\t\tindex := 1\n\t\t\t\tfor _, searchPath := range array {\n\t\t\t\t\tsearchPath = gstr.TrimRight(searchPath, `\\/`)\n\t\t\t\t\tfor _, tryFolder := range localSystemTryFolders {\n\t\t\t\t\t\tfmt.Fprintf(buffer,\n\t\t\t\t\t\t\t\"\\n%d. %s\",\n\t\t\t\t\t\t\tindex, gfile.Join(searchPath, tryFolder))\n\t\t\t\t\t\tindex++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer, \"cannot find template file \\\"%s\\\" with no path set/add\", file)\n\t\t}\n\t\tif errorPrint() {\n\t\t\tglog.Error(ctx, buffer.String())\n\t\t}\n\t\terr = gerror.NewCodef(gcode.CodeInvalidParameter, `template file \"%s\" not found`, file)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "os/gview/gview_z_unit_config_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Config(t *testing.T) {\n\t// show error print\n\tcommand.Init(\"-gf.gview.errorprint=true\")\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig := gview.Config{\n\t\t\tPaths: []string{gtest.DataPath(\"config\")},\n\t\t\tData: g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t\tDefaultFile: \"test.html\",\n\t\t\tDelimiters:  []string{\"${\", \"}\"},\n\t\t}\n\n\t\tview := gview.New()\n\t\terr := view.SetConfig(config)\n\t\tt.AssertNil(err)\n\n\t\tview.SetI18n(gi18n.New())\n\n\t\tstr := `hello ${.name},version:${.version}`\n\t\tview.Assigns(g.Map{\"version\": \"1.7.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello gf,version:1.7.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:gf\")\n\n\t\tt.Assert(view.GetDefaultFile(), \"test.html\")\n\t})\n\t// SetConfig path fail: notexist\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig := gview.Config{\n\t\t\tPaths: []string{\"notexist\", gtest.DataPath(\"config/test.html\")},\n\t\t\tData: g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t\tDefaultFile: \"test.html\",\n\t\t\tDelimiters:  []string{\"${\", \"}\"},\n\t\t}\n\n\t\tview := gview.New()\n\t\terr := view.SetConfig(config)\n\t\tt.AssertNE(err, nil)\n\t})\n\t// SetConfig path fail: set file path\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconfig := gview.Config{\n\t\t\tPaths: []string{gtest.DataPath(\"config/test.html\")},\n\t\t\tData: g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t\tDefaultFile: \"test.html\",\n\t\t\tDelimiters:  []string{\"${\", \"}\"},\n\t\t}\n\n\t\tview := gview.New()\n\t\terr := view.SetConfig(config)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ConfigWithMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tview := gview.New()\n\t\terr := view.SetConfigWithMap(g.Map{\n\t\t\t\"Paths\":       []string{gtest.DataPath(\"config\")},\n\t\t\t\"DefaultFile\": \"test.html\",\n\t\t\t\"Delimiters\":  []string{\"${\", \"}\"},\n\t\t\t\"Data\": g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello ${.name},version:${.version}`\n\t\tview.Assigns(g.Map{\"version\": \"1.7.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello gf,version:1.7.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:gf\")\n\t})\n\t// path as paths\n\tgtest.C(t, func(t *gtest.T) {\n\t\tview := gview.New()\n\t\terr := view.SetConfigWithMap(g.Map{\n\t\t\t\"Path\":        gtest.DataPath(\"config\"),\n\t\t\t\"DefaultFile\": \"test.html\",\n\t\t\t\"Delimiters\":  []string{\"${\", \"}\"},\n\t\t\t\"Data\": g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello ${.name},version:${.version}`\n\t\tview.Assigns(g.Map{\"version\": \"1.7.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello gf,version:1.7.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:gf\")\n\t})\n\t// path as paths\n\tgtest.C(t, func(t *gtest.T) {\n\t\tview := gview.New()\n\t\terr := view.SetConfigWithMap(g.Map{\n\t\t\t\"Path\":        []string{gtest.DataPath(\"config\")},\n\t\t\t\"DefaultFile\": \"test.html\",\n\t\t\t\"Delimiters\":  []string{\"${\", \"}\"},\n\t\t\t\"Data\": g.Map{\n\t\t\t\t\"name\": \"gf\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\n\t\tstr := `hello ${.name},version:${.version}`\n\t\tview.Assigns(g.Map{\"version\": \"1.7.0\"})\n\t\tresult, err := view.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"hello gf,version:1.7.0\")\n\n\t\tresult, err = view.ParseDefault(context.TODO())\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:gf\")\n\t})\n\t// map is nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\tview := gview.New()\n\t\terr := view.SetConfigWithMap(nil)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n"
  },
  {
    "path": "os/gview/gview_z_unit_feature_encode_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Encode_Parse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetPath(gtest.DataPath(\"tpl\"))\n\t\tv.SetAutoEncode(true)\n\t\tresult, err := v.Parse(context.TODO(), \"encode.tpl\", g.Map{\n\t\t\t\"title\": \"<b>my title</b>\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"<div>&lt;b&gt;my title&lt;/b&gt;</div>\")\n\t})\n}\n\nfunc Test_Encode_ParseContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\ttplContent := gfile.GetContents(gtest.DataPath(\"tpl\", \"encode.tpl\"))\n\t\tv.SetAutoEncode(true)\n\t\tresult, err := v.ParseContent(context.TODO(), tplContent, g.Map{\n\t\t\t\"title\": \"<b>my title</b>\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"<div>&lt;b&gt;my title&lt;/b&gt;</div>\")\n\t})\n}\n"
  },
  {
    "path": "os/gview/gview_z_unit_i18n_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_I18n(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `{{.name}} says \"{#hello}{#world}!\"`\n\t\texpect1 := `john says \"你好世界!\"`\n\t\texpect2 := `john says \"こんにちは世界!\"`\n\t\texpect3 := `john says \"{#hello}{#world}!\"`\n\n\t\tg.I18n().SetPath(gtest.DataPath(\"i18n\"))\n\n\t\tg.I18n().SetLanguage(\"zh-CN\")\n\t\tresult1, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result1, expect1)\n\n\t\tg.I18n().SetLanguage(\"ja\")\n\t\tresult2, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result2, expect2)\n\n\t\tg.I18n().SetLanguage(\"none\")\n\t\tresult3, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result3, expect3)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `{{.name}} says \"{#hello}{#world}!\"`\n\t\texpect1 := `john says \"你好世界!\"`\n\t\texpect2 := `john says \"こんにちは世界!\"`\n\t\texpect3 := `john says \"{#hello}{#world}!\"`\n\n\t\tg.I18n().SetPath(gdebug.CallerDirectory() + gfile.Separator + \"testdata\" + gfile.Separator + \"i18n\")\n\n\t\tresult1, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\":         \"john\",\n\t\t\t\"I18nLanguage\": \"zh-CN\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result1, expect1)\n\n\t\tresult2, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\":         \"john\",\n\t\t\t\"I18nLanguage\": \"ja\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result2, expect2)\n\n\t\tresult3, err := g.View().ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\":         \"john\",\n\t\t\t\"I18nLanguage\": \"none\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result3, expect3)\n\t})\n\t// gi18n manager is nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `{{.name}} says \"{#hello}{#world}!\"`\n\t\texpect1 := `john says \"{#hello}{#world}!\"`\n\n\t\tg.I18n().SetPath(gdebug.CallerDirectory() + gfile.Separator + \"testdata\" + gfile.Separator + \"i18n\")\n\n\t\tview := gview.New()\n\t\tview.SetI18n(nil)\n\t\tresult1, err := view.ParseContent(context.TODO(), content, g.Map{\n\t\t\t\"name\":         \"john\",\n\t\t\t\"I18nLanguage\": \"zh-CN\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result1, expect1)\n\t})\n\t// SetLanguage in context\n\tgtest.C(t, func(t *gtest.T) {\n\t\tcontent := `{{.name}} says \"{#hello}{#world}!\"`\n\t\texpect1 := `john says \"你好世界!\"`\n\t\tctx := gctx.New()\n\t\tg.I18n().SetPath(gdebug.CallerDirectory() + gfile.Separator + \"testdata\" + gfile.Separator + \"i18n\")\n\t\tctx = gi18n.WithLanguage(ctx, \"zh-CN\")\n\t\tt.Log(gi18n.LanguageFromCtx(ctx))\n\n\t\tview := gview.New()\n\n\t\tresult1, err := view.ParseContent(ctx, content, g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result1, expect1)\n\t})\n\n}\n"
  },
  {
    "path": "os/gview/gview_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gview_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/encoding/ghtml\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n\t\"github.com/gogf/gf/v2/os/gres\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/os/gview\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmode\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc init() {\n\tos.Setenv(\"GF_GVIEW_ERRORPRINT\", \"false\")\n}\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `hello {{.name}},version:{{.version}};hello {{GetName}},version:{{GetVersion}};{{.other}}`\n\t\tpwd := gfile.Pwd()\n\t\tview := gview.New()\n\t\tview.SetDelimiters(\"{{\", \"}}\")\n\t\tview.AddPath(pwd)\n\t\tview.SetPath(pwd)\n\t\tview.Assign(\"name\", \"gf\")\n\t\tview.Assigns(g.Map{\"version\": \"1.7.0\"})\n\t\tview.BindFunc(\"GetName\", func() string { return \"gf\" })\n\t\tview.BindFuncMap(gview.FuncMap{\"GetVersion\": func() string { return \"1.7.0\" }})\n\t\tresult, err := view.ParseContent(context.TODO(), str, g.Map{\"other\": \"that's all\"})\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, \"hello gf,version:1.7.0;hello gf,version:1.7.0;that's all\")\n\n\t\t// 测试api方法\n\t\tstr = `hello {{.name}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, g.Map{\"name\": \"gf\"})\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, \"hello gf\")\n\n\t\t// 测试instance方法\n\t\tresult, err = gview.Instance().ParseContent(context.TODO(), str, g.Map{\"name\": \"gf\"})\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, \"hello gf\")\n\t})\n}\n\nfunc Test_Func(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `{{eq 1 1}};{{eq 1 2}};{{eq \"A\" \"B\"}}`\n\t\tresult, err := gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `true;false;false`)\n\n\t\tstr = `{{ne 1 2}};{{ne 1 1}};{{ne \"A\" \"B\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `true;false;true`)\n\n\t\tstr = `{{lt 1 2}};{{lt 1 1}};{{lt 1 0}};{{lt \"A\" \"B\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `true;false;false;true`)\n\n\t\tstr = `{{le 1 2}};{{le 1 1}};{{le 1 0}};{{le \"A\" \"B\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `true;true;false;true`)\n\n\t\tstr = `{{gt 1 2}};{{gt 1 1}};{{gt 1 0}};{{gt \"A\" \"B\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `false;false;true;false`)\n\n\t\tstr = `{{ge 1 2}};{{ge 1 1}};{{ge 1 0}};{{ge \"A\" \"B\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `false;true;true;false`)\n\n\t\tstr = `{{\"<div>测试</div>\"|text}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `测试`)\n\n\t\tstr = `{{\"<div>测试</div>\"|html}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `&lt;div&gt;测试&lt;/div&gt;`)\n\n\t\tstr = `{{\"<div>测试</div>\"|htmlencode}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `&lt;div&gt;测试&lt;/div&gt;`)\n\n\t\tstr = `{{\"&lt;div&gt;测试&lt;/div&gt;\"|htmldecode}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `<div>测试</div>`)\n\n\t\tstr = `{{\"https://goframe.org\"|url}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `https%3A%2F%2Fgoframe.org`)\n\n\t\tstr = `{{\"https://goframe.org\"|urlencode}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `https%3A%2F%2Fgoframe.org`)\n\n\t\tstr = `{{\"https%3A%2F%2Fgoframe.org\"|urldecode}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `https://goframe.org`)\n\t\tstr = `{{\"https%3NA%2F%2Fgoframe.org\"|urldecode}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(gstr.Contains(result, \"invalid URL escape\"), true)\n\n\t\tstr = `{{1540822968 | date \"Y-m-d\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `2018-10-29`)\n\t\tstr = `{{date \"Y-m-d\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\n\t\tstr = `{{\"我是中国人\" | substr 2 -1}};{{\"我是中国人\" | substr 2  2}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `中国;中国`)\n\n\t\tstr = `{{\"我是中国人\" | strlimit 2  \"...\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `我是...`)\n\n\t\tstr = `{{\"I'm中国人\" | replace \"I'm\" \"我是\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `我是中国人`)\n\n\t\tstr = `{{compare \"A\" \"B\"}};{{compare \"1\" \"2\"}};{{compare 2 1}};{{compare 1 1}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `-1;-1;1;0`)\n\n\t\tstr = `{{\"热爱GF热爱生活\" | hidestr 20  \"*\"}};{{\"热爱GF热爱生活\" | hidestr 50  \"*\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `热爱GF*爱生活;热爱****生活`)\n\n\t\tstr = `{{\"热爱GF热爱生活\" | highlight \"GF\" \"red\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `热爱<span style=\"color:red;\">GF</span>热爱生活`)\n\n\t\tstr = `{{\"gf\" | toupper}};{{\"GF\" | tolower}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `GF;gf`)\n\n\t\tstr = `{{concat \"I\" \"Love\" \"GoFrame\"}}`\n\t\tresult, err = gview.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `ILoveGoFrame`)\n\t})\n\t// eq: multiple values.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `{{eq 1 2 1 3 4 5}}`\n\t\tresult, err := gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `true`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `{{eq 6 2 1 3 4 5}}`\n\t\tresult, err := gview.ParseContent(context.TODO(), str, nil)\n\t\tt.Assert(err != nil, false)\n\t\tt.Assert(result, `false`)\n\t})\n}\n\nfunc Test_FuncNl2Br(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `{{\"Go\\nFrame\" | nl2br}}`\n\t\tresult, err := gview.ParseContent(context.TODO(), str, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `Go<br>Frame`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"\"\n\t\tfor i := 0; i < 3000; i++ {\n\t\t\ts += \"Go\\nFrame\\n中文\"\n\t\t}\n\t\tstr := `{{.content | nl2br}}`\n\t\tresult, err := gview.ParseContent(context.TODO(), str, g.Map{\n\t\t\t\"content\": s,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, strings.Replace(s, \"\\n\", \"<br>\", -1))\n\t})\n}\n\nfunc Test_FuncInclude(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\theader = `<h1>HEADER</h1>`\n\t\t\tmain   = `<h1>hello gf</h1>`\n\t\t\tfooter = `<h1>FOOTER</h1>`\n\t\t\tlayout = `{{include \"header.html\" .}}\n{{include \"main.html\" .}}\n{{include \"footer.html\" .}}\n{{include \"footer_not_exist.html\" .}}\n{{include \"\" .}}`\n\t\t\ttemplatePath = gfile.Temp(guid.S())\n\t\t)\n\n\t\tgfile.Mkdir(templatePath)\n\t\tdefer gfile.Remove(templatePath)\n\n\t\tt.AssertNil(gfile.PutContents(gfile.Join(templatePath, `header.html`), header))\n\t\tt.AssertNil(gfile.PutContents(gfile.Join(templatePath, `main.html`), main))\n\t\tt.AssertNil(gfile.PutContents(gfile.Join(templatePath, `footer.html`), footer))\n\t\tt.AssertNil(gfile.PutContents(gfile.Join(templatePath, `layout.html`), layout))\n\n\t\tview := gview.New(templatePath)\n\t\tresult, err := view.Parse(context.TODO(), \"notfound.html\")\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(result, ``)\n\n\t\tresult, err = view.Parse(context.TODO(), \"layout.html\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `<h1>HEADER</h1>\n<h1>hello gf</h1>\n<h1>FOOTER</h1>\ntemplate file \"footer_not_exist.html\" not found\n`)\n\n\t\tt.AssertNil(gfile.PutContents(gfile.Join(templatePath, `notfound.html`), \"notfound\"))\n\t\tresult, err = view.Parse(context.TODO(), \"notfound.html\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `notfound`)\n\t})\n}\n\nfunc Test_SetPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tview := gview.Instance(\"addpath\")\n\t\terr := view.AddPath(\"tmp\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = view.AddPath(\"gview.go\")\n\t\tt.AssertNE(err, nil)\n\n\t\tos.Setenv(\"GF_GVIEW_PATH\", \"tmp\")\n\t\tview = gview.Instance(\"setpath\")\n\t\terr = view.SetPath(\"tmp\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = view.SetPath(\"gview.go\")\n\t\tt.AssertNE(err, nil)\n\n\t\tview = gview.New(gfile.Pwd())\n\t\terr = view.SetPath(\"tmp\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = view.SetPath(\"gview.go\")\n\t\tt.AssertNE(err, nil)\n\n\t\tos.Setenv(\"GF_GVIEW_PATH\", \"template\")\n\t\tgfile.Mkdir(gfile.Pwd() + gfile.Separator + \"template\")\n\t\tview = gview.New()\n\t})\n}\n\nfunc Test_ParseContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstr := `{{.name}}`\n\t\tview := gview.New()\n\t\tresult, err := view.ParseContent(context.TODO(), str, g.Map{\"name\": func() {}})\n\t\tt.Assert(err != nil, true)\n\t\tt.Assert(result, ``)\n\t})\n}\n\nfunc Test_HotReload(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdirPath := gfile.Join(\n\t\t\tgfile.Temp(),\n\t\t\t\"testdata\",\n\t\t\t\"template-\"+gconv.String(gtime.TimestampNano()),\n\t\t)\n\t\tdefer gfile.Remove(dirPath)\n\t\tfilePath := gfile.Join(dirPath, \"test.html\")\n\n\t\t// Initialize data.\n\t\terr := gfile.PutContents(filePath, \"test:{{.var}}\")\n\t\tt.AssertNil(err)\n\n\t\tview := gview.New(dirPath)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err := view.Parse(context.TODO(), \"test.html\", g.Map{\n\t\t\t\"var\": \"1\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `test:1`)\n\n\t\t// Update data.\n\t\terr = gfile.PutContents(filePath, \"test2:{{.var}}\")\n\t\tt.AssertNil(err)\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t\tresult, err = view.Parse(context.TODO(), \"test.html\", g.Map{\n\t\t\t\"var\": \"2\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, `test2:2`)\n\t})\n}\n\nfunc Test_XSS(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\ts := \"<br>\"\n\t\tr, err := v.ParseContent(context.TODO(), \"{{.v}}\", g.Map{\n\t\t\t\"v\": s,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, s)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetAutoEncode(true)\n\t\ts := \"<br>\"\n\t\tr, err := v.ParseContent(context.TODO(), \"{{.v}}\", g.Map{\n\t\t\t\"v\": s,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, ghtml.Entities(s))\n\t})\n\t// Tag \"if\".\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetAutoEncode(true)\n\t\ts := \"<br>\"\n\t\tr, err := v.ParseContent(context.TODO(), \"{{if eq 1 1}}{{.v}}{{end}}\", g.Map{\n\t\t\t\"v\": s,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, ghtml.Entities(s))\n\t})\n}\n\ntype TypeForBuildInFuncMap struct {\n\tName  string\n\tScore float32\n}\n\nfunc (t *TypeForBuildInFuncMap) Test() (*TypeForBuildInFuncMap, error) {\n\treturn &TypeForBuildInFuncMap{\"john\", 99.9}, nil\n}\n\nfunc Test_BuildInFuncMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", new(TypeForBuildInFuncMap))\n\t\tr, err := v.ParseContent(context.TODO(), \"{{range $k, $v := map .v.Test}} {{$k}}:{{$v}} {{end}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(r, \"Name:john\"), true)\n\t\tt.Assert(gstr.Contains(r, \"Score:99.9\"), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(context.TODO(), \"{{range $k, $v := map }} {{$k}}:{{$v}} {{end}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(gstr.Contains(r, \"Name:john\"), false)\n\t\tt.Assert(gstr.Contains(r, \"Score:99.9\"), false)\n\t})\n}\n\ntype TypeForBuildInFuncMaps struct {\n\tName  string\n\tScore float32\n}\n\nfunc (t *TypeForBuildInFuncMaps) Test() ([]*TypeForBuildInFuncMaps, error) {\n\treturn []*TypeForBuildInFuncMaps{\n\t\t{\"john\", 99.9},\n\t\t{\"smith\", 100},\n\t}, nil\n}\n\nfunc Test_BuildInFuncMaps(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", new(TypeForBuildInFuncMaps))\n\t\tr, err := v.ParseContent(context.TODO(), \"{{range $k, $v := maps .v.Test}} {{$k}}:{{$v.Name}} {{$v.Score}} {{end}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, ` 0:john 99.9  1:smith 100 `)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", new(TypeForBuildInFuncMaps))\n\t\tr, err := v.ParseContent(context.TODO(), \"{{range $k, $v := maps }} {{$k}}:{{$v.Name}} {{$v.Score}} {{end}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, ``)\n\t})\n}\n\nfunc Test_BuildInFuncDump(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"score\": 100,\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{dump .}}\")\n\t\tt.AssertNil(err)\n\t\tfmt.Println(r)\n\t\tt.Assert(gstr.Contains(r, `\"name\":  \"john\"`), true)\n\t\tt.Assert(gstr.Contains(r, `\"score\": 100`), true)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmode := gmode.Mode()\n\t\tgmode.SetTesting()\n\t\tdefer gmode.Set(mode)\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\":  \"john\",\n\t\t\t\"score\": 100,\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{dump .}}\")\n\t\tt.AssertNil(err)\n\t\tfmt.Println(r)\n\t\tt.Assert(gstr.Contains(r, `\"name\":  \"john\"`), false)\n\t\tt.Assert(gstr.Contains(r, `\"score\": 100`), false)\n\t})\n}\n\nfunc Test_BuildInFuncJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{json .v}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `{\"name\":\"john\"}`)\n\t})\n}\n\nfunc Test_BuildInFuncXml(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{xml .v}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `<name>john</name>`)\n\t})\n}\n\nfunc Test_BuildInFuncIni(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{ini .v}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `name=john\n`)\n\t})\n}\n\nfunc Test_BuildInFuncYaml(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{yaml .v}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `name: john\n`)\n\t})\n}\n\nfunc Test_BuildInFuncYamlIndent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), `{{yamli .v \"####\"}}`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `####name: john\n`)\n\t})\n}\n\nfunc Test_BuildInFuncToml(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.Assign(\"v\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tr, err := v.ParseContent(context.TODO(), \"{{toml .v}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `name = \"john\"\n`)\n\t})\n}\n\nfunc Test_BuildInFuncPlus(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{plus 1 2 3}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `6`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{1| plus 2}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `3`)\n\t})\n}\n\nfunc Test_BuildInFuncMinus(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{minus 1 2 3}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `-4`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{2 | minus 3}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `1`)\n\t})\n}\n\nfunc Test_BuildInFuncTimes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{times 1 2 3 4}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `24`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{2 | times 3}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `6`)\n\t})\n}\n\nfunc Test_BuildInFuncDivide(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{divide 8 2 2}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `2`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{2 | divide 4}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `2`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tr, err := v.ParseContent(gctx.New(), \"{{divide 8 0}}\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `0`)\n\t})\n}\n\nfunc Test_Issue1416(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\terr := v.SetPath(gtest.DataPath(\"issue1416\"))\n\t\tt.AssertNil(err)\n\t\tr, err := v.ParseOption(context.TODO(), gview.Option{\n\t\t\tFile:   \"gview.tpl\",\n\t\t\tOrphan: true,\n\t\t\tParams: map[string]any{\n\t\t\t\t\"hello\": \"world\",\n\t\t\t},\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(r, `test.tpl content, vars: world`)\n\t})\n}\n\n// template/gview_test.html\n// name:{{.name}}\nfunc init() {\n\tif err := gres.Add(\"H4sIAAAAAAAC/wrwZmYRYeBg4GBIFA0LY0ACEgycDCWpuQU5iSWp+ullmanl8SWpxSV6GSW5OaEhrAyM5o1fk095n/HdumrdNeaLW7c2MDAw/P8f4M3OoZ+9QESIgYGBj4GBAWYBA0MTmgUcSBaADSxt/JoM0o6sKMCbkUmEGeFCZKNBLoSBbY0gkqB7EcZhdw8ECDD8d0xEMg7JdaxsIAVMDEwMfQwMDAvAygEBAAD//0d6jptEAQAA\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n\n\tif err := gres.Add(\"H4sIAAAAAAAC/wrwZmYRYeBg4GBIFA0LY0ACEgycDCWpuQU5iSWp+ullmanl8SWpxSV6GSW5OaEhrAyM5o1fk095n/HdumrdNeaLW7c2MDAw/P8f4M3OoZ+9QESIgYGBj4GBAWYBA0MTmgUcSBaADSxt/JoM0o6sKMCbkUmEGeFCZKNBLoSBbY0gkqB7EcZhdw8ECDD8d0xEMg7JdaxsIAVMDEwMfQwMDAvAygEBAAD//0d6jptEAQAA\", \"assets/\"); err != nil {\n\t\tpanic(\"add binary content to resource manager failed: \" + err.Error())\n\t}\n}\n\nfunc Test_GviewInGres(t *testing.T) {\n\tgres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetPath(\"template\")\n\t\tresult, err := v.Parse(context.TODO(), \"gview_test.html\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:john\")\n\t})\n}\n\nfunc Test_GviewSearchFileInGres(t *testing.T) {\n\tgres.Dump()\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := gview.New()\n\t\tv.SetPath(\"assets/template\")\n\t\tresult, err := v.Parse(context.TODO(), \"gview_test.html\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(result, \"name:john\")\n\n\t\tv1 := gview.New(\"assets/template\")\n\t\tresult1, err1 := v1.Parse(context.TODO(), \"gview_test.html\", g.Map{\n\t\t\t\"name\": \"john\",\n\t\t})\n\t\tt.AssertNil(err1)\n\t\tt.Assert(result1, \"name:john\")\n\t})\n}\n"
  },
  {
    "path": "os/gview/testdata/config/test.html",
    "content": "name:${.name}"
  },
  {
    "path": "os/gview/testdata/i18n/en.toml",
    "content": "\nhello = \"Hello\"\nworld = \"World\""
  },
  {
    "path": "os/gview/testdata/i18n/ja.toml",
    "content": "\nhello = \"こんにちは\"\nworld = \"世界\""
  },
  {
    "path": "os/gview/testdata/i18n/ru.toml",
    "content": "\nhello = \"Привет\"\nworld = \"мир\""
  },
  {
    "path": "os/gview/testdata/i18n/zh-CN.toml",
    "content": "hello = \"你好\"\nworld = \"世界\""
  },
  {
    "path": "os/gview/testdata/i18n/zh-TW.toml",
    "content": "hello = \"你好\"\nworld = \"世界\""
  },
  {
    "path": "os/gview/testdata/issue1416/gview copy.tpl",
    "content": "test.tpl content, vars: {{ hello }}"
  },
  {
    "path": "os/gview/testdata/issue1416/gview.tpl",
    "content": "test.tpl content, vars: {{.hello}}"
  },
  {
    "path": "os/gview/testdata/tpl/encode.tpl",
    "content": "<div>{{.title}}</div>"
  },
  {
    "path": "sonar-project.properties",
    "content": "sonar.projectKey=gogf_gf\nsonar.organization=gogf\n\nsonar.sources=.\n\nsonar.sourceEncoding=UTF-8\n\nsonar.host.url=https://sonarcloud.io\n"
  },
  {
    "path": "test/gtest/gtest.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtest provides convenient test utilities for unit testing.\npackage gtest\n"
  },
  {
    "path": "test/gtest/gtest_t.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtest\n\nimport (\n\t\"testing\"\n)\n\n// T is the testing unit case management object.\ntype T struct {\n\t*testing.T\n}\n\n// Assert checks `value` and `expect` EQUAL.\nfunc (t *T) Assert(value, expect any) {\n\tAssert(value, expect)\n}\n\n// AssertEQ checks `value` and `expect` EQUAL, including their TYPES.\nfunc (t *T) AssertEQ(value, expect any) {\n\tAssertEQ(value, expect)\n}\n\n// AssertNE checks `value` and `expect` NOT EQUAL.\nfunc (t *T) AssertNE(value, expect any) {\n\tAssertNE(value, expect)\n}\n\n// AssertNQ checks `value` and `expect` NOT EQUAL, including their TYPES.\nfunc (t *T) AssertNQ(value, expect any) {\n\tAssertNQ(value, expect)\n}\n\n// AssertGT checks `value` is GREATER THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertGT,\n// others are invalid.\nfunc (t *T) AssertGT(value, expect any) {\n\tAssertGT(value, expect)\n}\n\n// AssertGE checks `value` is GREATER OR EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertGTE,\n// others are invalid.\nfunc (t *T) AssertGE(value, expect any) {\n\tAssertGE(value, expect)\n}\n\n// AssertLT checks `value` is LESS EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertLT,\n// others are invalid.\nfunc (t *T) AssertLT(value, expect any) {\n\tAssertLT(value, expect)\n}\n\n// AssertLE checks `value` is LESS OR EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertLTE,\n// others are invalid.\nfunc (t *T) AssertLE(value, expect any) {\n\tAssertLE(value, expect)\n}\n\n// AssertIN checks `value` is IN `expect`.\n// The `expect` should be a slice,\n// but the `value` can be a slice or a basic type variable.\nfunc (t *T) AssertIN(value, expect any) {\n\tAssertIN(value, expect)\n}\n\n// AssertNI checks `value` is NOT IN `expect`.\n// The `expect` should be a slice,\n// but the `value` can be a slice or a basic type variable.\nfunc (t *T) AssertNI(value, expect any) {\n\tAssertNI(value, expect)\n}\n\n// AssertNil asserts `value` is nil.\nfunc (t *T) AssertNil(value any) {\n\tAssertNil(value)\n}\n\n// Error panics with given `message`.\nfunc (t *T) Error(message ...any) {\n\tError(message...)\n}\n\n// Fatal prints `message` to stderr and exit the process.\nfunc (t *T) Fatal(message ...any) {\n\tFatal(message...)\n}\n"
  },
  {
    "path": "test/gtest/gtest_util.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtest\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tpathFilterKey = \"/test/gtest/gtest\"\n)\n\n// C creates a unit testing case.\n// The parameter `t` is the pointer to testing.T of stdlib (*testing.T).\n// The parameter `f` is the closure function for unit testing case.\nfunc C(t *testing.T, f func(t *T)) {\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\t_, _ = fmt.Fprintf(os.Stderr, \"%v\\n%s\", err, gdebug.StackWithFilter([]string{pathFilterKey}))\n\t\t\tt.Fail()\n\t\t}\n\t}()\n\tf(&T{t})\n}\n\n// Assert checks `value` and `expect` EQUAL.\nfunc Assert(value, expect any) {\n\trvExpect := reflect.ValueOf(expect)\n\tif empty.IsNil(value) {\n\t\tvalue = nil\n\t}\n\tif rvExpect.Kind() == reflect.Map {\n\t\tif err := compareMap(value, expect); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn\n\t}\n\tvar (\n\t\tstrValue  = gconv.String(value)\n\t\tstrExpect = gconv.String(expect)\n\t)\n\tif strValue != strExpect {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, strValue, strExpect))\n\t}\n}\n\n// AssertEQ checks `value` and `expect` EQUAL, including their TYPES.\nfunc AssertEQ(value, expect any) {\n\t// Value assert.\n\trvExpect := reflect.ValueOf(expect)\n\tif empty.IsNil(value) {\n\t\tvalue = nil\n\t}\n\tif rvExpect.Kind() == reflect.Map {\n\t\tif err := compareMap(value, expect); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn\n\t}\n\tstrValue := gconv.String(value)\n\tstrExpect := gconv.String(expect)\n\tif strValue != strExpect {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v == %v`, strValue, strExpect))\n\t}\n\t// Type assert.\n\tt1 := reflect.TypeOf(value)\n\tt2 := reflect.TypeOf(expect)\n\tif t1 != t2 {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT TYPE %v[%v] == %v[%v]`, strValue, t1, strExpect, t2))\n\t}\n}\n\n// AssertNE checks `value` and `expect` NOT EQUAL.\nfunc AssertNE(value, expect any) {\n\trvExpect := reflect.ValueOf(expect)\n\tif empty.IsNil(value) {\n\t\tvalue = nil\n\t}\n\tif rvExpect.Kind() == reflect.Map {\n\t\tif err := compareMap(value, expect); err == nil {\n\t\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, value, expect))\n\t\t}\n\t\treturn\n\t}\n\tvar (\n\t\tstrValue  = gconv.String(value)\n\t\tstrExpect = gconv.String(expect)\n\t)\n\tif strValue == strExpect {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, strValue, strExpect))\n\t}\n}\n\n// AssertNQ checks `value` and `expect` NOT EQUAL, including their TYPES.\nfunc AssertNQ(value, expect any) {\n\t// Type assert.\n\tt1 := reflect.TypeOf(value)\n\tt2 := reflect.TypeOf(expect)\n\tif t1 == t2 {\n\t\tpanic(\n\t\t\tfmt.Sprintf(\n\t\t\t\t`[ASSERT] EXPECT TYPE %v[%v] != %v[%v]`,\n\t\t\t\tgconv.String(value), t1, gconv.String(expect), t2,\n\t\t\t),\n\t\t)\n\t}\n\t// Value assert.\n\tAssertNE(value, expect)\n}\n\n// AssertGT checks `value` is GREATER THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertGT,\n// others are invalid.\nfunc AssertGT(value, expect any) {\n\tpassed := false\n\tswitch reflect.ValueOf(expect).Kind() {\n\tcase reflect.String:\n\t\tpassed = gconv.String(value) > gconv.String(expect)\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tpassed = gconv.Int(value) > gconv.Int(expect)\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tpassed = gconv.Uint(value) > gconv.Uint(expect)\n\n\tcase reflect.Float32, reflect.Float64:\n\t\tpassed = gconv.Float64(value) > gconv.Float64(expect)\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v > %v`, value, expect))\n\t}\n}\n\n// AssertGE checks `value` is GREATER OR EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertGTE,\n// others are invalid.\nfunc AssertGE(value, expect any) {\n\tpassed := false\n\tswitch reflect.ValueOf(expect).Kind() {\n\tcase reflect.String:\n\t\tpassed = gconv.String(value) >= gconv.String(expect)\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tpassed = gconv.Int64(value) >= gconv.Int64(expect)\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tpassed = gconv.Uint64(value) >= gconv.Uint64(expect)\n\n\tcase reflect.Float32, reflect.Float64:\n\t\tpassed = gconv.Float64(value) >= gconv.Float64(expect)\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(\n\t\t\t`[ASSERT] EXPECT %v(%v) >= %v(%v)`,\n\t\t\tvalue, reflect.ValueOf(value).Kind(),\n\t\t\texpect, reflect.ValueOf(expect).Kind(),\n\t\t))\n\t}\n}\n\n// AssertLT checks `value` is LESS EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertLT,\n// others are invalid.\nfunc AssertLT(value, expect any) {\n\tpassed := false\n\tswitch reflect.ValueOf(expect).Kind() {\n\tcase reflect.String:\n\t\tpassed = gconv.String(value) < gconv.String(expect)\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tpassed = gconv.Int(value) < gconv.Int(expect)\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tpassed = gconv.Uint(value) < gconv.Uint(expect)\n\n\tcase reflect.Float32, reflect.Float64:\n\t\tpassed = gconv.Float64(value) < gconv.Float64(expect)\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v < %v`, value, expect))\n\t}\n}\n\n// AssertLE checks `value` is LESS OR EQUAL THAN `expect`.\n// Notice that, only string, integer and float types can be compared by AssertLTE,\n// others are invalid.\nfunc AssertLE(value, expect any) {\n\tpassed := false\n\tswitch reflect.ValueOf(expect).Kind() {\n\tcase reflect.String:\n\t\tpassed = gconv.String(value) <= gconv.String(expect)\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tpassed = gconv.Int(value) <= gconv.Int(expect)\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tpassed = gconv.Uint(value) <= gconv.Uint(expect)\n\n\tcase reflect.Float32, reflect.Float64:\n\t\tpassed = gconv.Float64(value) <= gconv.Float64(expect)\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v <= %v`, value, expect))\n\t}\n}\n\n// AssertIN checks `value` is IN `expect`.\n// The `expect` should be a slice,\n// but the `value` can be a slice or a basic type variable.\n// TODO: gconv.Strings(0) is not [0]\nfunc AssertIN(value, expect any) {\n\tvar (\n\t\tpassed     = true\n\t\texpectKind = reflect.ValueOf(expect).Kind()\n\t)\n\tswitch expectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\texpectSlice := gconv.Strings(expect)\n\t\tfor _, v1 := range gconv.Strings(value) {\n\t\t\tresult := false\n\t\t\tfor _, v2 := range expectSlice {\n\t\t\t\tif v1 == v2 {\n\t\t\t\t\tresult = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !result {\n\t\t\t\tpassed = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\tcase reflect.String:\n\t\tvar (\n\t\t\tvalueStr  = gconv.String(value)\n\t\t\texpectStr = gconv.String(expect)\n\t\t)\n\t\tpassed = gstr.Contains(expectStr, valueStr)\n\tcase reflect.Map:\n\t\texpectMap := gconv.Map(expect)\n\t\tfor _, v1 := range gconv.Strings(value) {\n\t\t\tif _, exists := expectMap[v1]; !exists {\n\t\t\t\tpassed = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(`[ASSERT] INVALID EXPECT VALUE TYPE: %v`, expectKind))\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v IN %v`, value, expect))\n\t}\n}\n\n// AssertNI checks `value` is NOT IN `expect`.\n// The `expect` should be a slice,\n// but the `value` can be a slice or a basic type variable.\nfunc AssertNI(value, expect any) {\n\tvar (\n\t\tpassed     = true\n\t\texpectKind = reflect.ValueOf(expect).Kind()\n\t)\n\tswitch expectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tfor _, v1 := range gconv.Strings(value) {\n\t\t\tresult := true\n\t\t\tfor _, v2 := range gconv.Strings(expect) {\n\t\t\t\tif v1 == v2 {\n\t\t\t\t\tresult = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !result {\n\t\t\t\tpassed = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\tcase reflect.String:\n\t\tvar (\n\t\t\tvalueStr  = gconv.String(value)\n\t\t\texpectStr = gconv.String(expect)\n\t\t)\n\t\tpassed = !gstr.Contains(expectStr, valueStr)\n\tcase reflect.Map:\n\t\texpectMap := gconv.Map(expect)\n\t\tfor _, v1 := range gconv.Strings(value) {\n\t\t\tif _, exists := expectMap[v1]; exists {\n\t\t\t\tpassed = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(`[ASSERT] INVALID EXPECT VALUE TYPE: %v`, expectKind))\n\t}\n\tif !passed {\n\t\tpanic(fmt.Sprintf(`[ASSERT] EXPECT %v NOT IN %v`, value, expect))\n\t}\n}\n\n// Error panics with given `message`.\nfunc Error(message ...any) {\n\tpanic(fmt.Sprintf(\"[ERROR] %s\", fmt.Sprint(message...)))\n}\n\n// Fatal prints `message` to stderr and exit the process.\nfunc Fatal(message ...any) {\n\t_, _ = fmt.Fprintf(\n\t\tos.Stderr, \"[FATAL] %s\\n%s\", fmt.Sprint(message...),\n\t\tgdebug.StackWithFilter([]string{pathFilterKey}),\n\t)\n\tos.Exit(1)\n}\n\n// compareMap compares two maps, returns nil if they are equal, or else returns error.\nfunc compareMap(value, expect any) error {\n\tvar (\n\t\trvValue  = reflect.ValueOf(value)\n\t\trvExpect = reflect.ValueOf(expect)\n\t)\n\n\tif rvExpect.Kind() != reflect.Map {\n\t\treturn nil\n\t}\n\n\tif rvValue.Kind() != reflect.Map {\n\t\treturn fmt.Errorf(`[ASSERT] EXPECT VALUE TO BE A MAP, BUT GIVEN \"%s\"`, rvValue.Kind())\n\t}\n\n\tif rvExpect.Len() != rvValue.Len() {\n\t\treturn fmt.Errorf(`[ASSERT] EXPECT MAP LENGTH %d == %d`, rvValue.Len(), rvExpect.Len())\n\t}\n\n\t// Turn two interface maps to the same type for comparison.\n\t// Direct use of rvValue.MapIndex(key).Interface() will panic\n\t// when the key types are inconsistent.\n\tvar (\n\t\tmValue   = make(map[string]string)\n\t\tmExpect  = make(map[string]string)\n\t\tksValue  = rvValue.MapKeys()\n\t\tksExpect = rvExpect.MapKeys()\n\t)\n\n\tfor _, key := range ksValue {\n\t\tmValue[gconv.String(key.Interface())] = gconv.String(rvValue.MapIndex(key).Interface())\n\t}\n\n\tfor _, key := range ksExpect {\n\t\tmExpect[gconv.String(key.Interface())] = gconv.String(rvExpect.MapIndex(key).Interface())\n\t}\n\n\tfor k, v := range mExpect {\n\t\tif v != mValue[k] {\n\t\t\treturn fmt.Errorf(`[ASSERT] EXPECT VALUE map[\"%v\"]:%v == map[\"%v\"]:%v`+\n\t\t\t\t\"\\nGIVEN : %v\\nEXPECT: %v\", k, mValue[k], k, v, mValue, mExpect)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// AssertNil asserts `value` is nil.\nfunc AssertNil(value any) {\n\tif empty.IsNil(value) {\n\t\treturn\n\t}\n\tif err, ok := value.(error); ok {\n\t\tpanic(fmt.Sprintf(`%+v`, err))\n\t}\n\tAssert(value, nil)\n}\n\n// DataPath retrieves and returns the testdata path of current package,\n// which is used for unit testing cases only.\n// The optional parameter `names` specifies the sub-folders/sub-files,\n// which will be joined with current system separator and returned with the path.\nfunc DataPath(names ...string) string {\n\t_, path, _ := gdebug.CallerWithFilter([]string{pathFilterKey})\n\tpath = filepath.Join(filepath.Dir(path), \"testdata\")\n\tfor _, name := range names {\n\t\tpath = filepath.Join(path, name)\n\t}\n\treturn filepath.FromSlash(path)\n}\n\n// DataContent retrieves and returns the file content for specified testdata path of current package\nfunc DataContent(names ...string) string {\n\tpath := DataPath(names...)\n\tif path != \"\" {\n\t\tdata, err := os.ReadFile(path)\n\t\tif err == nil {\n\t\t\treturn string(data)\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "test/gtest/gtest_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtest_test\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nvar (\n\tmap1           = map[string]string{\"k1\": \"v1\"}\n\tmap1Expect     = map[string]string{\"k1\": \"v1\"}\n\tmap2           = map[string]string{\"k2\": \"v2\"}\n\tmapLong1       = map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"}\n\tmapLong1Expect = map[string]string{\"k2\": \"v2\", \"k1\": \"v1\"}\n)\n\nfunc TestC(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(1, 1)\n\t\tt.AssertNE(1, 0)\n\t\tt.AssertEQ(float32(123.456), float32(123.456))\n\t\tt.AssertEQ(float32(123.456), float32(123.456))\n\t\tt.Assert(map[string]string{\"1\": \"1\"}, map[string]string{\"1\": \"1\"})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 == 0\")\n\t\t\t}\n\t\t}()\n\t\tt.Assert(1, 0)\n\t})\n}\n\nfunc TestCase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(1, 1)\n\t\tt.AssertNE(1, 0)\n\t\tt.AssertEQ(float32(123.456), float32(123.456))\n\t\tt.AssertEQ(float32(123.456), float32(123.456))\n\t})\n}\n\nfunc TestAssert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tnilChan chan struct{}\n\t\t)\n\t\tt.Assert(1, 1)\n\t\tt.Assert(nilChan, nil)\n\t\tt.Assert(map1, map1Expect)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT VALUE map[\"k2\"]: == map[\"k2\"]:v2\nGIVEN : map[k1:v1]\nEXPECT: map[k2:v2]`)\n\t\t\t}\n\t\t}()\n\t\tt.Assert(map1, map2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT MAP LENGTH 2 == 1`)\n\t\t\t}\n\t\t}()\n\t\tt.Assert(mapLong1, map2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT VALUE TO BE A MAP, BUT GIVEN \"int\"`)\n\t\t\t}\n\t\t}()\n\t\tt.Assert(0, map1)\n\t})\n}\n\nfunc TestAssertEQ(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tnilChan chan struct{}\n\t\t)\n\t\tt.AssertEQ(nilChan, nil)\n\t\tt.AssertEQ(\"0\", \"0\")\n\t\tt.AssertEQ(float32(123.456), float32(123.456))\n\t\tt.AssertEQ(mapLong1, mapLong1Expect)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 == 0\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertEQ(1, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT TYPE 1[int] == 1[string]\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertEQ(1, \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT VALUE map[\"k2\"]: == map[\"k2\"]:v2\nGIVEN : map[k1:v1]\nEXPECT: map[k2:v2]`)\n\t\t\t}\n\t\t}()\n\t\tt.AssertEQ(map1, map2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT MAP LENGTH 2 == 1`)\n\t\t\t}\n\t\t}()\n\t\tt.AssertEQ(mapLong1, map2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT VALUE TO BE A MAP, BUT GIVEN \"int\"`)\n\t\t\t}\n\t\t}()\n\t\tt.AssertEQ(0, map1)\n\t})\n}\n\nfunc TestAssertNE(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tc = make(chan struct{}, 1)\n\t\t)\n\t\tt.AssertNE(nil, c)\n\t\tt.AssertNE(\"0\", \"1\")\n\t\tt.AssertNE(float32(123.456), float32(123.4567))\n\t\tt.AssertNE(map1, map2)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 != 1\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNE(1, 1)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, `[ASSERT] EXPECT map[k1:v1] != map[k1:v1]`)\n\t\t\t}\n\t\t}()\n\t\tt.AssertNE(map1, map1Expect)\n\t})\n}\n\nfunc TestAssertNQ(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNQ(1, \"0\")\n\t\tt.AssertNQ(float32(123.456), float64(123.4567))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 != 1\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNQ(1, \"1\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT TYPE 1[int] != 1[int]\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNQ(1, 1)\n\t})\n}\n\nfunc TestAssertGT(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGT(\"b\", \"a\")\n\t\tt.AssertGT(1, -1)\n\t\tt.AssertGT(uint(1), uint(0))\n\t\tt.AssertGT(float32(123.45678), float32(123.4567))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT -1 > 1\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertGT(-1, 1)\n\t})\n}\n\nfunc TestAssertGE(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertGE(\"b\", \"a\")\n\t\tt.AssertGE(\"a\", \"a\")\n\t\tt.AssertGE(1, -1)\n\t\tt.AssertGE(1, 1)\n\t\tt.AssertGE(uint(1), uint(0))\n\t\tt.AssertGE(uint(0), uint(0))\n\t\tt.AssertGE(float32(123.45678), float32(123.4567))\n\t\tt.AssertGE(float32(123.456), float32(123.456))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT -1(int) >= 1(int)\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertGE(-1, 1)\n\t})\n}\n\nfunc TestAssertLT(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertLT(\"a\", \"b\")\n\t\tt.AssertLT(-1, 1)\n\t\tt.AssertLT(uint(0), uint(1))\n\t\tt.AssertLT(float32(123.456), float32(123.4567))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 < -1\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertLT(1, -1)\n\t})\n}\n\nfunc TestAssertLE(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertLE(\"a\", \"b\")\n\t\tt.AssertLE(\"a\", \"a\")\n\t\tt.AssertLE(-1, 1)\n\t\tt.AssertLE(1, 1)\n\t\tt.AssertLE(uint(0), uint(1))\n\t\tt.AssertLE(uint(0), uint(0))\n\t\tt.AssertLE(float32(123.456), float32(123.4567))\n\t\tt.AssertLE(float32(123.456), float32(123.456))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 <= -1\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertLE(1, -1)\n\t})\n}\n\nfunc TestAssertIN(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertIN(\"a\", []string{\"a\", \"b\", \"c\"})\n\t\tt.AssertIN(1, []int{1, 2, 3})\n\t\tt.AssertIN(\"a\", \"abc\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] INVALID EXPECT VALUE TYPE: int\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertIN(0, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 4 IN [1 2 3]\")\n\t\t\t}\n\t\t}()\n\t\t// t.AssertIN(0, []int{0, 1, 2, 3})\n\t\t// t.AssertIN(0, []int{ 1, 2, 3})\n\t\tt.AssertIN(4, []int{1, 2, 3})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT d IN abc\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertIN(\"d\", \"abc\")\n\t})\n}\n\nfunc TestAssertIN_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertIN(\"k1\", map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"})\n\t\tt.AssertIN(1, map[int64]string{1: \"v1\", 2: \"v2\"})\n\t\tt.AssertIN([]string{\"k1\", \"k2\"}, map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"})\n\t})\n}\n\nfunc TestAssertNI_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNI(\"k3\", map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"})\n\t\tt.AssertNI(3, map[int64]string{1: \"v1\", 2: \"v2\"})\n\t\tt.AssertNI([]string{\"k3\", \"k4\"}, map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"})\n\t})\n}\n\nfunc TestAssertNI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertNI(\"d\", []string{\"a\", \"b\", \"c\"})\n\t\tt.AssertNI(4, []int{1, 2, 3})\n\t\tt.AssertNI(\"d\", \"abc\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] INVALID EXPECT VALUE TYPE: int\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNI(0, 0)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT 1 NOT IN [1 2 3]\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNI(1, []int{1, 2, 3})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ASSERT] EXPECT a NOT IN abc\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNI(\"a\", \"abc\")\n\t})\n}\n\nfunc TestAssertNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tnilChan chan struct{}\n\t\t)\n\t\tt.AssertNil(nilChan)\n\t\t_, err := strconv.ParseInt(\"123\", 10, 64)\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"error\")\n\t\t\t}\n\t\t}()\n\t\tt.AssertNil(errors.New(\"error\"))\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}()\n\t\tt.AssertNil(1)\n\t})\n}\n\nfunc TestAssertError(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tt.Assert(err, \"[ERROR] this is an error\")\n\t\t\t}\n\t\t}()\n\t\tt.Error(\"this is an error\")\n\t})\n}\n\nfunc TestDataPath(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(filepath.ToSlash(gtest.DataPath(\"testdata.txt\")), `testdata/testdata.txt`)\n\t})\n}\n\nfunc TestDataContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gtest.DataContent(\"testdata.txt\"), `hello`)\n\t\tt.Assert(gtest.DataContent(\"\"), \"\")\n\t})\n}\n"
  },
  {
    "path": "test/gtest/testdata/testdata.txt",
    "content": "hello"
  },
  {
    "path": "text/gregex/gregex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gregex provides high performance API for regular expression functionality.\npackage gregex\n\nimport (\n\t\"regexp\"\n)\n\n// Quote quotes `s` by replacing special chars in `s`\n// to match the rules of regular expression pattern.\n// And returns the copy.\n//\n// Eg: Quote(`[foo]`) returns `\\[foo\\]`.\nfunc Quote(s string) string {\n\treturn regexp.QuoteMeta(s)\n}\n\n// Validate checks whether given regular expression pattern `pattern` valid.\nfunc Validate(pattern string) error {\n\t_, err := getRegexp(pattern)\n\treturn err\n}\n\n// IsMatch checks whether given bytes `src` matches `pattern`.\nfunc IsMatch(pattern string, src []byte) bool {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.Match(src)\n\t}\n\treturn false\n}\n\n// IsMatchString checks whether given string `src` matches `pattern`.\nfunc IsMatchString(pattern string, src string) bool {\n\treturn IsMatch(pattern, []byte(src))\n}\n\n// Match return bytes slice that matched `pattern`.\nfunc Match(pattern string, src []byte) ([][]byte, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.FindSubmatch(src), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// MatchString return strings that matched `pattern`.\nfunc MatchString(pattern string, src string) ([]string, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.FindStringSubmatch(src), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// MatchAll return all bytes slices that matched `pattern`.\nfunc MatchAll(pattern string, src []byte) ([][][]byte, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.FindAllSubmatch(src, -1), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// MatchAllString return all strings that matched `pattern`.\nfunc MatchAllString(pattern string, src string) ([][]string, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.FindAllStringSubmatch(src, -1), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// Replace replaces all matched `pattern` in bytes `src` with bytes `replace`.\nfunc Replace(pattern string, replace, src []byte) ([]byte, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.ReplaceAll(src, replace), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// ReplaceString replace all matched `pattern` in string `src` with string `replace`.\nfunc ReplaceString(pattern, replace, src string) (string, error) {\n\tr, e := Replace(pattern, []byte(replace), []byte(src))\n\treturn string(r), e\n}\n\n// ReplaceFunc replace all matched `pattern` in bytes `src`\n// with custom replacement function `replaceFunc`.\nfunc ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte) ([]byte, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.ReplaceAllFunc(src, replaceFunc), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// ReplaceFuncMatch replace all matched `pattern` in bytes `src`\n// with custom replacement function `replaceFunc`.\n// The parameter `match` type for `replaceFunc` is [][]byte,\n// which is the result contains all sub-patterns of `pattern` using Match function.\nfunc ReplaceFuncMatch(pattern string, src []byte, replaceFunc func(match [][]byte) []byte) ([]byte, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.ReplaceAllFunc(src, func(bytes []byte) []byte {\n\t\t\tmatch, _ := Match(pattern, bytes)\n\t\t\treturn replaceFunc(match)\n\t\t}), nil\n\t} else {\n\t\treturn nil, err\n\t}\n}\n\n// ReplaceStringFunc replace all matched `pattern` in string `src`\n// with custom replacement function `replaceFunc`.\nfunc ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) string) (string, error) {\n\tbytes, err := ReplaceFunc(pattern, []byte(src), func(bytes []byte) []byte {\n\t\treturn []byte(replaceFunc(string(bytes)))\n\t})\n\treturn string(bytes), err\n}\n\n// ReplaceStringFuncMatch replace all matched `pattern` in string `src`\n// with custom replacement function `replaceFunc`.\n// The parameter `match` type for `replaceFunc` is []string,\n// which is the result contains all sub-patterns of `pattern` using MatchString function.\nfunc ReplaceStringFuncMatch(pattern string, src string, replaceFunc func(match []string) string) (string, error) {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn string(r.ReplaceAllFunc([]byte(src), func(bytes []byte) []byte {\n\t\t\tmatch, _ := MatchString(pattern, string(bytes))\n\t\t\treturn []byte(replaceFunc(match))\n\t\t})), nil\n\t} else {\n\t\treturn \"\", err\n\t}\n}\n\n// Split slices `src` into substrings separated by the expression and returns a slice of\n// the substrings between those expression matches.\nfunc Split(pattern string, src string) []string {\n\tif r, err := getRegexp(pattern); err == nil {\n\t\treturn r.Split(src, -1)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "text/gregex/gregex_cache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gregex\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\tregexMu = sync.RWMutex{}\n\n\t// Cache for regex object.\n\t// Note that:\n\t// 1. It uses sync.RWMutex ensuring the concurrent safety.\n\t// 2. There's no expiring logic for this map.\n\tregexMap = make(map[string]*regexp.Regexp)\n)\n\n// getRegexp returns *regexp.Regexp object with given `pattern`.\n// It uses cache to enhance the performance for compiling regular expression pattern,\n// which means, it will return the same *regexp.Regexp object with the same regular\n// expression pattern.\n//\n// It is concurrent-safe for multiple goroutines.\nfunc getRegexp(pattern string) (regex *regexp.Regexp, err error) {\n\t// Retrieve the regular expression object using reading lock.\n\tregexMu.RLock()\n\tregex = regexMap[pattern]\n\tregexMu.RUnlock()\n\tif regex != nil {\n\t\treturn\n\t}\n\t// If it does not exist in the cache,\n\t// it compiles the pattern and creates one.\n\tif regex, err = regexp.Compile(pattern); err != nil {\n\t\terr = gerror.Wrapf(err, `regexp.Compile failed for pattern \"%s\"`, pattern)\n\t\treturn\n\t}\n\t// Cache the result object using writing lock.\n\tregexMu.Lock()\n\tregexMap[pattern] = regex\n\tregexMu.Unlock()\n\treturn\n}\n"
  },
  {
    "path": "text/gregex/gregex_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gregex_test\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nvar pattern = `(\\w+).+\\-\\-\\s*(.+)`\n\nvar src = `GF is best! -- John`\n\nfunc Benchmark_GF_IsMatchString(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgregex.IsMatchString(pattern, src)\n\t}\n}\n\nfunc Benchmark_GF_MatchString(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgregex.MatchString(pattern, src)\n\t}\n}\n\nfunc Benchmark_Compile(b *testing.B) {\n\tvar wcdRegexp = regexp.MustCompile(pattern)\n\tfor i := 0; i < b.N; i++ {\n\t\twcdRegexp.MatchString(src)\n\t}\n}\n\nfunc Benchmark_Compile_Actual(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\twcdRegexp := regexp.MustCompile(pattern)\n\t\twcdRegexp.MatchString(src)\n\t}\n}\n"
  },
  {
    "path": "text/gregex/gregex_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\npackage gregex_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nfunc ExampleIsMatch() {\n\tpatternStr := `\\d+`\n\tg.Dump(gregex.IsMatch(patternStr, []byte(\"hello 2022! hello gf!\")))\n\tg.Dump(gregex.IsMatch(patternStr, nil))\n\tg.Dump(gregex.IsMatch(patternStr, []byte(\"hello gf!\")))\n\n\t// Output:\n\t// true\n\t// false\n\t// false\n}\n\nfunc ExampleIsMatchString() {\n\tpatternStr := `\\d+`\n\tg.Dump(gregex.IsMatchString(patternStr, \"hello 2022! hello gf!\"))\n\tg.Dump(gregex.IsMatchString(patternStr, \"hello gf!\"))\n\tg.Dump(gregex.IsMatchString(patternStr, \"\"))\n\n\t// Output:\n\t// true\n\t// false\n\t// false\n}\n\nfunc ExampleMatch() {\n\tpatternStr := `(\\w+)=(\\w+)`\n\tmatchStr := \"https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!\"\n\t// This method looks for the first match index\n\tresult, err := gregex.Match(patternStr, []byte(matchStr))\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     \"pageId=1114219\",\n\t//     \"pageId\",\n\t//     \"1114219\",\n\t// ]\n\t// <nil>\n}\n\nfunc ExampleMatchString() {\n\tpatternStr := `(\\w+)=(\\w+)`\n\tmatchStr := \"https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!\"\n\t// This method looks for the first match index\n\tresult, err := gregex.MatchString(patternStr, matchStr)\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     \"pageId=1114219\",\n\t//     \"pageId\",\n\t//     \"1114219\",\n\t// ]\n\t// <nil>\n}\n\nfunc ExampleMatchAll() {\n\tpatternStr := `(\\w+)=(\\w+)`\n\tmatchStr := \"https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!\"\n\tresult, err := gregex.MatchAll(patternStr, []byte(matchStr))\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t//  [\n\t//     [\n\t//         \"pageId=1114219\",\n\t//         \"pageId\",\n\t//         \"1114219\",\n\t//     ],\n\t//     [\n\t//         \"searchId=8QC5D1D2E\",\n\t//         \"searchId\",\n\t//         \"8QC5D1D2E\",\n\t//     ],\n\t// ]\n\t// <nil>\n}\n\nfunc ExampleMatchAllString() {\n\tpatternStr := `(\\w+)=(\\w+)`\n\tmatchStr := \"https://goframe.org/pages/viewpage.action?pageId=1114219&searchId=8QC5D1D2E!\"\n\tresult, err := gregex.MatchAllString(patternStr, matchStr)\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     [\n\t//         \"pageId=1114219\",\n\t//         \"pageId\",\n\t//         \"1114219\",\n\t//     ],\n\t//     [\n\t//         \"searchId=8QC5D1D2E\",\n\t//         \"searchId\",\n\t//         \"8QC5D1D2E\",\n\t//     ],\n\t// ]\n\t// <nil>\n}\n\nfunc ExampleQuote() {\n\tresult := gregex.Quote(`[1-9]\\d+`)\n\tfmt.Println(result)\n\n\t// Output:\n\t// \\[1-9\\]\\\\d\\+\n}\n\nfunc ExampleReplace() {\n\tvar (\n\t\tpatternStr  = `\\d+`\n\t\tstr         = \"hello gf 2020!\"\n\t\trepStr      = \"2021\"\n\t\tresult, err = gregex.Replace(patternStr, []byte(repStr), []byte(str))\n\t)\n\tg.Dump(err)\n\tg.Dump(result)\n\n\t// Output:\n\t// <nil>\n\t// \"hello gf 2021!\"\n}\n\nfunc ExampleReplaceFunc() {\n\t// In contrast to [ExampleReplaceFunc]\n\t// the result contains the `pattern' of all subpattern that use the matching function\n\tresult, err := gregex.ReplaceFuncMatch(`(\\d+)~(\\d+)`, []byte(\"hello gf 2018~2020!\"), func(match [][]byte) []byte {\n\t\tg.Dump(match)\n\t\tmatch[2] = []byte(\"2021\")\n\t\treturn bytes.Join(match[1:], []byte(\"~\"))\n\t})\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     \"2018~2020\",\n\t//     \"2018\",\n\t//     \"2020\",\n\t// ]\n\t// \"hello gf 2018~2021!\"\n\t// <nil>\n}\n\nfunc ExampleReplaceFuncMatch() {\n\tvar (\n\t\tpatternStr = `(\\d+)~(\\d+)`\n\t\tstr        = \"hello gf 2018~2020!\"\n\t)\n\t// In contrast to [ExampleReplaceFunc]\n\t// the result contains the `pattern' of all subpatterns that use the matching function\n\tresult, err := gregex.ReplaceFuncMatch(patternStr, []byte(str), func(match [][]byte) []byte {\n\t\tg.Dump(match)\n\t\tmatch[2] = []byte(\"2021\")\n\t\treturn bytes.Join(match[1:], []byte(\"-\"))\n\t})\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     \"2018~2020\",\n\t//     \"2018\",\n\t//     \"2020\",\n\t// ]\n\t// \"hello gf 2018-2021!\"\n\t// <nil>\n}\n\nfunc ExampleReplaceString() {\n\tpatternStr := `\\d+`\n\tstr := \"hello gf 2020!\"\n\treplaceStr := \"2021\"\n\tresult, err := gregex.ReplaceString(patternStr, replaceStr, str)\n\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// \"hello gf 2021!\"\n\t// <nil>\n}\n\nfunc ExampleReplaceStringFunc() {\n\treplaceStrMap := map[string]string{\n\t\t\"2020\": \"2021\",\n\t}\n\t// When the regular statement can match multiple results\n\t// func can be used to further control the value that needs to be modified\n\tresult, err := gregex.ReplaceStringFunc(`\\d+`, `hello gf 2018~2020!`, func(b string) string {\n\t\tg.Dump(b)\n\t\tif replaceStr, ok := replaceStrMap[b]; ok {\n\t\t\treturn replaceStr\n\t\t}\n\t\treturn b\n\t})\n\tg.Dump(result)\n\tg.Dump(err)\n\n\tresult, err = gregex.ReplaceStringFunc(`[a-z]*`, \"gf@goframe.org\", strings.ToUpper)\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// \"2018\"\n\t// \"2020\"\n\t// \"hello gf 2018~2021!\"\n\t// <nil>\n\t// \"GF@GOFRAME.ORG\"\n\t// <nil>\n}\n\nfunc ExampleReplaceStringFuncMatch() {\n\tvar (\n\t\tpatternStr = `([A-Z])\\w+`\n\t\tstr        = \"hello Golang 2018~2021!\"\n\t)\n\t// In contrast to [ExampleReplaceFunc]\n\t// the result contains the `pattern' of all subpatterns that use the matching function\n\tresult, err := gregex.ReplaceStringFuncMatch(patternStr, str, func(match []string) string {\n\t\tg.Dump(match)\n\t\tmatch[0] = \"Gf\"\n\t\treturn match[0]\n\t})\n\tg.Dump(result)\n\tg.Dump(err)\n\n\t// Output:\n\t// [\n\t//     \"Golang\",\n\t//     \"G\",\n\t// ]\n\t// \"hello Gf 2018~2021!\"\n\t// <nil>\n}\n\nfunc ExampleSplit() {\n\tpatternStr := `\\d+`\n\tstr := \"hello2020gf\"\n\tresult := gregex.Split(patternStr, str)\n\tg.Dump(result)\n\n\t// Output:\n\t// [\n\t//     \"hello\",\n\t//     \"gf\",\n\t// ]\n}\n\nfunc ExampleValidate() {\n\t// Valid match statement\n\tfmt.Println(gregex.Validate(`\\d+`))\n\t// Mismatched statement\n\tfmt.Println(gregex.Validate(`[a-9]\\d+`))\n\n\t// Output:\n\t// <nil>\n\t// regexp.Compile failed for pattern \"[a-9]\\d+\": error parsing regexp: invalid character class range: `a-9`\n}\n"
  },
  {
    "path": "text/gregex/gregex_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gregex_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\nvar (\n\tPatternErr = `([\\d+`\n)\n\nfunc Test_Quote(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := `[foo]` //`\\[foo\\]`\n\t\tt.Assert(gregex.Quote(s1), `\\[foo\\]`)\n\t})\n}\n\nfunc Test_Validate(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s1 = `(.+):(\\d+)`\n\t\tt.Assert(gregex.Validate(s1), nil)\n\t\ts1 = `((.+):(\\d+)`\n\t\tt.Assert(gregex.Validate(s1) == nil, false)\n\t})\n}\n\nfunc Test_IsMatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar pattern = `(.+):(\\d+)`\n\t\ts1 := []byte(`sfs:2323`)\n\t\tt.Assert(gregex.IsMatch(pattern, s1), true)\n\t\ts1 = []byte(`sfs2323`)\n\t\tt.Assert(gregex.IsMatch(pattern, s1), false)\n\t\ts1 = []byte(`sfs:`)\n\t\tt.Assert(gregex.IsMatch(pattern, s1), false)\n\t\t// error pattern\n\t\tt.Assert(gregex.IsMatch(PatternErr, s1), false)\n\t})\n}\n\nfunc Test_IsMatchString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar pattern = `(.+):(\\d+)`\n\t\ts1 := `sfs:2323`\n\t\tt.Assert(gregex.IsMatchString(pattern, s1), true)\n\t\ts1 = `sfs2323`\n\t\tt.Assert(gregex.IsMatchString(pattern, s1), false)\n\t\ts1 = `sfs:`\n\t\tt.Assert(gregex.IsMatchString(pattern, s1), false)\n\t\t// error pattern\n\t\tt.Assert(gregex.IsMatchString(PatternErr, s1), false)\n\t})\n}\n\nfunc Test_Match(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\tsubs, err := gregex.Match(re, []byte(s))\n\t\tt.AssertNil(err)\n\t\tif string(subs[0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[0], wantSubs)\n\t\t}\n\t\tif string(subs[1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[1], \"aab\")\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.Match(PatternErr, []byte(s))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_MatchString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\tsubs, err := gregex.MatchString(re, s)\n\t\tt.AssertNil(err)\n\t\tif string(subs[0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[0], wantSubs)\n\t\t}\n\t\tif string(subs[1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[1], \"aab\")\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.MatchString(PatternErr, s)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_MatchAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\ts = s + `其他的` + s\n\t\tsubs, err := gregex.MatchAll(re, []byte(s))\n\t\tt.AssertNil(err)\n\t\tif string(subs[0][0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[0][0], wantSubs)\n\t\t}\n\t\tif string(subs[0][1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[0][1], \"aab\")\n\t\t}\n\n\t\tif string(subs[1][0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[1][0], wantSubs)\n\t\t}\n\t\tif string(subs[1][1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[1][1], \"aab\")\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.MatchAll(PatternErr, []byte(s))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_MatchAllString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\tsubs, err := gregex.MatchAllString(re, s+`其他的`+s)\n\t\tt.AssertNil(err)\n\t\tif string(subs[0][0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[0][0], wantSubs)\n\t\t}\n\t\tif string(subs[0][1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[0][1], \"aab\")\n\t\t}\n\n\t\tif string(subs[1][0]) != wantSubs {\n\t\t\tt.Fatalf(\"regex:%s,Match(%q)[0] = %q; want %q\", re, s, subs[1][0], wantSubs)\n\t\t}\n\t\tif string(subs[1][1]) != \"aab\" {\n\t\t\tt.Fatalf(\"Match(%q)[1] = %q; want %q\", s, subs[1][1], \"aab\")\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.MatchAllString(PatternErr, s)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\treplace := \"12345\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\twanted := \"acbb\" + replace + \"dd\"\n\t\treplacedStr, err := gregex.Replace(re, []byte(replace), []byte(s))\n\t\tt.AssertNil(err)\n\t\tif string(replacedStr) != wanted {\n\t\t\tt.Fatalf(\"regex:%s,old:%s; want %q\", re, s, wanted)\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.Replace(PatternErr, []byte(replace), []byte(s))\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\treplace := \"12345\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\twanted := \"acbb\" + replace + \"dd\"\n\t\treplacedStr, err := gregex.ReplaceString(re, replace, s)\n\t\tt.AssertNil(err)\n\t\tif replacedStr != wanted {\n\t\t\tt.Fatalf(\"regex:%s,old:%s; want %q\", re, s, wanted)\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.ReplaceString(PatternErr, replace, s)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceFun(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\t//replace :=\"12345\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\twanted := \"acbb[x\" + wantSubs + \"y]dd\"\n\t\twanted = \"acbb\" + \"3个a\" + \"dd\"\n\t\treplacedStr, err := gregex.ReplaceFunc(re, []byte(s), func(s []byte) []byte {\n\t\t\tif strings.Contains(string(s), \"aaa\") {\n\t\t\t\treturn []byte(\"3个a\")\n\t\t\t}\n\t\t\treturn []byte(\"[x\" + string(s) + \"y]\")\n\t\t})\n\t\tt.AssertNil(err)\n\t\tif string(replacedStr) != wanted {\n\t\t\tt.Fatalf(\"regex:%s,old:%s; want %q\", re, s, wanted)\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.ReplaceFunc(PatternErr, []byte(s), func(s []byte) []byte {\n\t\t\treturn []byte(\"\")\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceFuncMatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := []byte(\"1234567890\")\n\t\tp := `(\\d{3})(\\d{3})(.+)`\n\t\ts0, e0 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {\n\t\t\treturn match[0]\n\t\t})\n\t\tt.Assert(e0, nil)\n\t\tt.Assert(s0, s)\n\t\ts1, e1 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {\n\t\t\treturn match[1]\n\t\t})\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(s1, []byte(\"123\"))\n\t\ts2, e2 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {\n\t\t\treturn match[2]\n\t\t})\n\t\tt.Assert(e2, nil)\n\t\tt.Assert(s2, []byte(\"456\"))\n\t\ts3, e3 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {\n\t\t\treturn match[3]\n\t\t})\n\t\tt.Assert(e3, nil)\n\t\tt.Assert(s3, []byte(\"7890\"))\n\t\t// error pattern\n\t\t_, err := gregex.ReplaceFuncMatch(PatternErr, s, func(match [][]byte) []byte {\n\t\t\treturn match[3]\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceStringFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\twantSubs := \"aaabb\"\n\t\t//replace :=\"12345\"\n\t\ts := \"acbb\" + wantSubs + \"dd\"\n\t\twanted := \"acbb[x\" + wantSubs + \"y]dd\"\n\t\twanted = \"acbb\" + \"3个a\" + \"dd\"\n\t\treplacedStr, err := gregex.ReplaceStringFunc(re, s, func(s string) string {\n\t\t\tif strings.Contains(s, \"aaa\") {\n\t\t\t\treturn \"3个a\"\n\t\t\t}\n\t\t\treturn \"[x\" + s + \"y]\"\n\t\t})\n\t\tt.AssertNil(err)\n\t\tif replacedStr != wanted {\n\t\t\tt.Fatalf(\"regex:%s,old:%s; want %q\", re, s, wanted)\n\t\t}\n\t\t// error pattern\n\t\t_, err = gregex.ReplaceStringFunc(PatternErr, s, func(s string) string {\n\t\t\treturn \"\"\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_ReplaceStringFuncMatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"1234567890\"\n\t\tp := `(\\d{3})(\\d{3})(.+)`\n\t\ts0, e0 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {\n\t\t\treturn match[0]\n\t\t})\n\t\tt.Assert(e0, nil)\n\t\tt.Assert(s0, s)\n\t\ts1, e1 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {\n\t\t\treturn match[1]\n\t\t})\n\t\tt.Assert(e1, nil)\n\t\tt.Assert(s1, \"123\")\n\t\ts2, e2 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {\n\t\t\treturn match[2]\n\t\t})\n\t\tt.Assert(e2, nil)\n\t\tt.Assert(s2, \"456\")\n\t\ts3, e3 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {\n\t\t\treturn match[3]\n\t\t})\n\t\tt.Assert(e3, nil)\n\t\tt.Assert(s3, \"7890\")\n\t\t// error pattern\n\t\t_, err := gregex.ReplaceStringFuncMatch(PatternErr, s, func(match []string) string {\n\t\t\treturn \"\"\n\t\t})\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Split(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\tmatched := \"aaabb\"\n\t\titem0 := \"acbb\"\n\t\titem1 := \"dd\"\n\t\ts := item0 + matched + item1\n\t\tt.Assert(gregex.IsMatchString(re, matched), true)\n\t\titems := gregex.Split(re, s) //split string with matched\n\t\tif items[0] != item0 {\n\t\t\tt.Fatalf(\"regex:%s,Split(%q) want %q\", re, s, item0)\n\t\t}\n\t\tif items[1] != item1 {\n\t\t\tt.Fatalf(\"regex:%s,Split(%q) want %q\", re, s, item0)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tre := \"a(a+b+)b\"\n\t\tnotmatched := \"aaxbb\"\n\t\titem0 := \"acbb\"\n\t\titem1 := \"dd\"\n\t\ts := item0 + notmatched + item1\n\t\tt.Assert(gregex.IsMatchString(re, notmatched), false)\n\t\titems := gregex.Split(re, s) //split string with notmatched then nosplitting\n\t\tif items[0] != s {\n\t\t\tt.Fatalf(\"regex:%s,Split(%q) want %q\", re, s, item0)\n\t\t}\n\t\t// error pattern\n\t\titems = gregex.Split(PatternErr, s)\n\t\tt.AssertEQ(items, nil)\n\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gstr provides functions for string handling.\npackage gstr\n\nconst (\n\t// NotFoundIndex is the position index for string not found in searching functions.\n\tNotFoundIndex = -1\n)\n\nconst (\n\tdefaultSuffixForStrLimit = \"...\"\n)\n"
  },
  {
    "path": "text/gstr/gstr_array.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\n// SearchArray searches string `s` in string slice `a` case-sensitively,\n// returns its index in `a`.\n// If `s` is not found in `a`, it returns -1.\nfunc SearchArray(a []string, s string) int {\n\tfor i, v := range a {\n\t\tif s == v {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn NotFoundIndex\n}\n\n// InArray checks whether string `s` in slice `a`.\nfunc InArray(a []string, s string) bool {\n\treturn SearchArray(a, s) != NotFoundIndex\n}\n\n// PrefixArray adds `prefix` string for each item of `array`.\n//\n// Example:\n// PrefixArray([\"a\",\"b\"], \"gf_\") -> [\"gf_a\", \"gf_b\"]\nfunc PrefixArray(array []string, prefix string) {\n\tfor k, v := range array {\n\t\tarray[k] = prefix + v\n\t}\n}\n"
  },
  {
    "path": "text/gstr/gstr_case.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n//\n//   | Function                          | Result             |\n//   |-----------------------------------|--------------------|\n//   | CaseSnake(s)                      | any_kind_of_string |\n//   | CaseSnakeScreaming(s)             | ANY_KIND_OF_STRING |\n//   | CaseSnakeFirstUpper(\"RGBCodeMd5\") | rgb_code_md5       |\n//   | CaseKebab(s)                      | any-kind-of-string |\n//   | CaseKebabScreaming(s)             | ANY-KIND-OF-STRING |\n//   | CaseDelimited(s, '.')             | any.kind.of.string |\n//   | CaseDelimitedScreaming(s, '.')    | ANY.KIND.OF.STRING |\n//   | CaseCamel(s)                      | AnyKindOfString    |\n//   | CaseCamelLower(s)                 | anyKindOfString    |\n\npackage gstr\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n)\n\n// CaseType is the type for Case.\ntype CaseType string\n\n// The case type constants.\nconst (\n\tCamel           CaseType = \"Camel\"\n\tCamelLower      CaseType = \"CamelLower\"\n\tSnake           CaseType = \"Snake\"\n\tSnakeFirstUpper CaseType = \"SnakeFirstUpper\"\n\tSnakeScreaming  CaseType = \"SnakeScreaming\"\n\tKebab           CaseType = \"Kebab\"\n\tKebabScreaming  CaseType = \"KebabScreaming\"\n\tLower           CaseType = \"Lower\"\n)\n\nvar (\n\tnumberSequence      = regexp.MustCompile(`([a-zA-Z]{0,1})(\\d+)([a-zA-Z]{0,1})`)\n\tfirstCamelCaseStart = regexp.MustCompile(`([A-Z]+)([A-Z]?[_a-z\\d]+)|$`)\n\tfirstCamelCaseEnd   = regexp.MustCompile(`([\\w\\W]*?)([_]?[A-Z]+)$`)\n)\n\n// CaseTypeMatch matches the case type from string.\nfunc CaseTypeMatch(caseStr string) CaseType {\n\tcaseTypes := []CaseType{\n\t\tCamel,\n\t\tCamelLower,\n\t\tSnake,\n\t\tSnakeFirstUpper,\n\t\tSnakeScreaming,\n\t\tKebab,\n\t\tKebabScreaming,\n\t\tLower,\n\t}\n\n\tfor _, caseType := range caseTypes {\n\t\tif Equal(caseStr, string(caseType)) {\n\t\t\treturn caseType\n\t\t}\n\t}\n\n\treturn CaseType(caseStr)\n}\n\n// CaseConvert converts a string to the specified naming convention.\n// Use CaseTypeMatch to match the case type from string.\nfunc CaseConvert(s string, caseType CaseType) string {\n\tif s == \"\" || caseType == \"\" {\n\t\treturn s\n\t}\n\n\tswitch caseType {\n\tcase Camel:\n\t\treturn CaseCamel(s)\n\n\tcase CamelLower:\n\t\treturn CaseCamelLower(s)\n\n\tcase Kebab:\n\t\treturn CaseKebab(s)\n\n\tcase KebabScreaming:\n\t\treturn CaseKebabScreaming(s)\n\n\tcase Snake:\n\t\treturn CaseSnake(s)\n\n\tcase SnakeFirstUpper:\n\t\treturn CaseSnakeFirstUpper(s)\n\n\tcase SnakeScreaming:\n\t\treturn CaseSnakeScreaming(s)\n\n\tcase Lower:\n\t\treturn ToLower(s)\n\n\tdefault:\n\t\treturn s\n\t}\n}\n\n// CaseCamel converts a string to CamelCase.\n//\n// Example:\n// CaseCamel(\"any_kind_of_string\") -> AnyKindOfString\n// CaseCamel(\"anyKindOfString\")    -> AnyKindOfString\nfunc CaseCamel(s string) string {\n\treturn toCamelInitCase(s, true)\n}\n\n// CaseCamelLower converts a string to lowerCamelCase.\n//\n// Example:\n// CaseCamelLower(\"any_kind_of_string\") -> anyKindOfString\n// CaseCamelLower(\"AnyKindOfString\")    -> anyKindOfString\nfunc CaseCamelLower(s string) string {\n\tif s == \"\" {\n\t\treturn s\n\t}\n\tif r := rune(s[0]); r >= 'A' && r <= 'Z' {\n\t\ts = strings.ToLower(string(r)) + s[1:]\n\t}\n\treturn toCamelInitCase(s, false)\n}\n\n// CaseSnake converts a string to snake_case.\n//\n// Example:\n// CaseSnake(\"AnyKindOfString\") -> any_kind_of_string\nfunc CaseSnake(s string) string {\n\treturn CaseDelimited(s, '_')\n}\n\n// CaseSnakeScreaming converts a string to SNAKE_CASE_SCREAMING.\n//\n// Example:\n// CaseSnakeScreaming(\"AnyKindOfString\") -> ANY_KIND_OF_STRING\nfunc CaseSnakeScreaming(s string) string {\n\treturn CaseDelimitedScreaming(s, '_', true)\n}\n\n// CaseSnakeFirstUpper converts a string like \"RGBCodeMd5\" to \"rgb_code_md5\".\n// TODO for efficiency should change regexp to traversing string in future.\n//\n// Example:\n// CaseSnakeFirstUpper(\"RGBCodeMd5\") -> rgb_code_md5\nfunc CaseSnakeFirstUpper(word string, underscore ...string) string {\n\treplace := \"_\"\n\tif len(underscore) > 0 {\n\t\treplace = underscore[0]\n\t}\n\n\tm := firstCamelCaseEnd.FindAllStringSubmatch(word, 1)\n\tif len(m) > 0 {\n\t\tword = m[0][1] + replace + TrimLeft(ToLower(m[0][2]), replace)\n\t}\n\n\tfor {\n\t\tm = firstCamelCaseStart.FindAllStringSubmatch(word, 1)\n\t\tif len(m) > 0 && m[0][1] != \"\" {\n\t\t\tw := strings.ToLower(m[0][1])\n\t\t\tw = w[:len(w)-1] + replace + string(w[len(w)-1])\n\n\t\t\tword = strings.Replace(word, m[0][1], w, 1)\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn TrimLeft(word, replace)\n}\n\n// CaseKebab converts a string to kebab-case.\n//\n// Example:\n// CaseKebab(\"AnyKindOfString\") -> any-kind-of-string\nfunc CaseKebab(s string) string {\n\treturn CaseDelimited(s, '-')\n}\n\n// CaseKebabScreaming converts a string to KEBAB-CASE-SCREAMING.\n//\n// Example:\n// CaseKebab(\"AnyKindOfString\") -> ANY-KIND-OF-STRING\nfunc CaseKebabScreaming(s string) string {\n\treturn CaseDelimitedScreaming(s, '-', true)\n}\n\n// CaseDelimited converts a string to snake.case.delimited.\n//\n// Example:\n// CaseDelimited(\"AnyKindOfString\", '.') -> any.kind.of.string\nfunc CaseDelimited(s string, del byte) string {\n\treturn CaseDelimitedScreaming(s, del, false)\n}\n\n// CaseDelimitedScreaming converts a string to DELIMITED.SCREAMING.CASE or delimited.screaming.case.\n//\n// Example:\n// CaseDelimitedScreaming(\"AnyKindOfString\", '.') -> ANY.KIND.OF.STRING\nfunc CaseDelimitedScreaming(s string, del uint8, screaming bool) string {\n\ts = addWordBoundariesToNumbers(s)\n\ts = strings.Trim(s, \" \")\n\tn := \"\"\n\tfor i, v := range s {\n\t\t// treat acronyms as words, eg for JSONData -> JSON is a whole word\n\t\tnextCaseIsChanged := false\n\t\tif i+1 < len(s) {\n\t\t\tnext := s[i+1]\n\t\t\tif (v >= 'A' && v <= 'Z' && next >= 'a' && next <= 'z') || (v >= 'a' && v <= 'z' && next >= 'A' && next <= 'Z') {\n\t\t\t\tnextCaseIsChanged = true\n\t\t\t}\n\t\t}\n\n\t\tif i > 0 && n[len(n)-1] != del && nextCaseIsChanged {\n\t\t\t// add underscore if next letter case type is changed\n\t\t\tif v >= 'A' && v <= 'Z' {\n\t\t\t\tn += string(del) + string(v)\n\t\t\t} else if v >= 'a' && v <= 'z' {\n\t\t\t\tn += string(v) + string(del)\n\t\t\t}\n\t\t} else if v == ' ' || v == '_' || v == '-' || v == '.' {\n\t\t\t// replace spaces/underscores with delimiters\n\t\t\tn += string(del)\n\t\t} else {\n\t\t\tn = n + string(v)\n\t\t}\n\t}\n\n\tif screaming {\n\t\tn = strings.ToUpper(n)\n\t} else {\n\t\tn = strings.ToLower(n)\n\t}\n\treturn n\n}\n\nfunc addWordBoundariesToNumbers(s string) string {\n\tr := numberSequence.ReplaceAllFunc([]byte(s), func(bytes []byte) []byte {\n\t\tvar result []byte\n\t\tmatch := numberSequence.FindSubmatch(bytes)\n\t\tif len(match[1]) > 0 {\n\t\t\tresult = append(result, match[1]...)\n\t\t\tresult = append(result, []byte(\" \")...)\n\t\t}\n\t\tresult = append(result, match[2]...)\n\t\tif len(match[3]) > 0 {\n\t\t\tresult = append(result, []byte(\" \")...)\n\t\t\tresult = append(result, match[3]...)\n\t\t}\n\t\treturn result\n\t})\n\treturn string(r)\n}\n\n// Converts a string to CamelCase\nfunc toCamelInitCase(s string, initCase bool) string {\n\ts = addWordBoundariesToNumbers(s)\n\ts = strings.Trim(s, \" \")\n\tn := \"\"\n\tcapNext := initCase\n\tfor _, v := range s {\n\t\tif v >= 'A' && v <= 'Z' {\n\t\t\tn += string(v)\n\t\t}\n\t\tif v >= '0' && v <= '9' {\n\t\t\tn += string(v)\n\t\t}\n\t\tif v >= 'a' && v <= 'z' {\n\t\t\tif capNext {\n\t\t\t\tn += strings.ToUpper(string(v))\n\t\t\t} else {\n\t\t\t\tn += string(v)\n\t\t\t}\n\t\t}\n\t\tif v == '_' || v == ' ' || v == '-' || v == '.' {\n\t\t\tcapNext = true\n\t\t} else {\n\t\t\tcapNext = false\n\t\t}\n\t}\n\treturn n\n}\n"
  },
  {
    "path": "text/gstr/gstr_compare.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// Compare returns an integer comparing two strings lexicographically.\n// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.\nfunc Compare(a, b string) int {\n\treturn strings.Compare(a, b)\n}\n\n// Equal reports whether `a` and `b`, interpreted as UTF-8 strings,\n// are equal under Unicode case-folding, case-insensitively.\nfunc Equal(a, b string) bool {\n\treturn strings.EqualFold(a, b)\n}\n"
  },
  {
    "path": "text/gstr/gstr_contain.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// Contains reports whether `substr` is within `str`, case-sensitively.\nfunc Contains(str, substr string) bool {\n\treturn strings.Contains(str, substr)\n}\n\n// ContainsI reports whether substr is within str, case-insensitively.\nfunc ContainsI(str, substr string) bool {\n\treturn PosI(str, substr) != -1\n}\n\n// ContainsAny reports whether any Unicode code points in `chars` are within `s`.\nfunc ContainsAny(s, chars string) bool {\n\treturn strings.ContainsAny(s, chars)\n}\n"
  },
  {
    "path": "text/gstr/gstr_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nvar (\n\t// octReg is the regular expression object for checks octal string.\n\toctReg = regexp.MustCompile(`\\\\[0-7]{3}`)\n)\n\n// Chr return the ascii string of a number(0-255).\n//\n// Example:\n// Chr(65) -> \"A\"\nfunc Chr(ascii int) string {\n\treturn string([]byte{byte(ascii % 256)})\n}\n\n// Ord converts the first byte of a string to a value between 0 and 255.\n//\n// Example:\n// Chr(\"A\") -> 65\nfunc Ord(char string) int {\n\treturn int(char[0])\n}\n\n// OctStr converts string container octal string to its original string,\n// for example, to Chinese string.\n//\n// Example:\n// OctStr(\"\\346\\200\\241\") -> 怡\nfunc OctStr(str string) string {\n\treturn octReg.ReplaceAllStringFunc(\n\t\tstr,\n\t\tfunc(s string) string {\n\t\t\ti, _ := strconv.ParseInt(s[1:], 8, 0)\n\t\t\treturn string([]byte{byte(i)})\n\t\t},\n\t)\n}\n\n// Reverse returns a string which is the reverse of `str`.\n//\n// Example:\n// Reverse(\"123456\") -> \"654321\"\nfunc Reverse(str string) string {\n\trunes := []rune(str)\n\tfor i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {\n\t\trunes[i], runes[j] = runes[j], runes[i]\n\t}\n\treturn string(runes)\n}\n\n// NumberFormat formats a number with grouped thousands.\n// Parameter `decimals`: Sets the number of decimal points.\n// Parameter `decPoint`: Sets the separator for the decimal point.\n// Parameter `thousandsSep`: Sets the thousands' separator.\n// See http://php.net/manual/en/function.number-format.php.\n//\n// Example:\n// NumberFormat(1234.56, 2, \".\", \"\")  -> 1234,56\n// NumberFormat(1234.56, 2, \",\", \" \") -> 1 234,56\nfunc NumberFormat(number float64, decimals int, decPoint, thousandsSep string) string {\n\tneg := false\n\tif number < 0 {\n\t\tnumber = -number\n\t\tneg = true\n\t}\n\t// Will round off\n\tstr := fmt.Sprintf(\"%.\"+strconv.Itoa(decimals)+\"F\", number)\n\tprefix, suffix := \"\", \"\"\n\tif decimals > 0 {\n\t\tprefix = str[:len(str)-(decimals+1)]\n\t\tsuffix = str[len(str)-decimals:]\n\t} else {\n\t\tprefix = str\n\t}\n\tsep := []byte(thousandsSep)\n\tn, l1, l2 := 0, len(prefix), len(sep)\n\t// thousands sep num\n\tc := (l1 - 1) / 3\n\ttmp := make([]byte, l2*c+l1)\n\tpos := len(tmp) - 1\n\tfor i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 {\n\t\tif l2 > 0 && n > 0 && n%3 == 0 {\n\t\t\tfor j := range sep {\n\t\t\t\ttmp[pos] = sep[l2-j-1]\n\t\t\t\tpos--\n\t\t\t}\n\t\t}\n\t\ttmp[pos] = prefix[i]\n\t}\n\ts := string(tmp)\n\tif decimals > 0 {\n\t\ts += decPoint + suffix\n\t}\n\tif neg {\n\t\ts = \"-\" + s\n\t}\n\n\treturn s\n}\n\n// Shuffle randomly shuffles a string.\n// It considers parameter `str` as unicode string.\n//\n// Example:\n// Shuffle(\"123456\") -> \"325164\"\n// Shuffle(\"123456\") -> \"231546\"\n// ...\nfunc Shuffle(str string) string {\n\trunes := []rune(str)\n\ts := make([]rune, len(runes))\n\tfor i, v := range grand.Perm(len(runes)) {\n\t\ts[i] = runes[v]\n\t}\n\treturn string(s)\n}\n\n// HideStr replaces part of the string `str` to `hide` by `percentage` from the `middle`.\n// It considers parameter `str` as unicode string.\nfunc HideStr(str string, percent int, hide string) string {\n\t// Handle email case\n\tvar suffix string\n\tif idx := strings.IndexByte(str, '@'); idx >= 0 {\n\t\tsuffix = str[idx:]\n\t\tstr = str[:idx]\n\t}\n\n\t// Early return for edge cases\n\tif str == \"\" || percent <= 0 {\n\t\treturn str + suffix\n\t}\n\tif percent >= 100 {\n\t\treturn strings.Repeat(hide, len([]rune(str))) + suffix\n\t}\n\n\trs := []rune(str)\n\tlength := len(rs)\n\tif length == 0 {\n\t\treturn str + suffix\n\t}\n\n\t// Calculate hideLen using the same logic as original (with floor)\n\thideLen := (length * percent) / 100\n\tif hideLen == 0 {\n\t\treturn str + suffix\n\t}\n\n\t// Calculate start position: mid - hideLen/2\n\t// This matches the original algorithm behavior\n\tmid := length / 2\n\tstart := max(mid-hideLen/2, 0)\n\n\tend := start + hideLen\n\tif end > length {\n\t\tend = length\n\t\tstart = max(length-hideLen, 0)\n\t}\n\n\t// Pre-calculate capacity to avoid reallocations\n\tvar builder strings.Builder\n\tbuilder.Grow(len(str) + len(hide)*hideLen + len(suffix))\n\n\t// Build result string efficiently\n\tbuilder.WriteString(string(rs[:start]))\n\tif hide != \"\" {\n\t\tbuilder.WriteString(strings.Repeat(hide, hideLen))\n\t}\n\tbuilder.WriteString(string(rs[end:]))\n\tbuilder.WriteString(suffix)\n\n\treturn builder.String()\n}\n\n// Nl2Br inserts HTML line breaks(`br`|<br />) before all newlines in a string:\n// \\n\\r, \\r\\n, \\r, \\n.\n// It considers parameter `str` as unicode string.\nfunc Nl2Br(str string, isXhtml ...bool) string {\n\tr, n, runes := '\\r', '\\n', []rune(str)\n\tvar br []byte\n\tif len(isXhtml) > 0 && isXhtml[0] {\n\t\tbr = []byte(\"<br />\")\n\t} else {\n\t\tbr = []byte(\"<br>\")\n\t}\n\tskip := false\n\tlength := len(runes)\n\tvar buf bytes.Buffer\n\tfor i, v := range runes {\n\t\tif skip {\n\t\t\tskip = false\n\t\t\tcontinue\n\t\t}\n\t\tswitch v {\n\t\tcase n, r:\n\t\t\tif (i+1 < length) && ((v == r && runes[i+1] == n) || (v == n && runes[i+1] == r)) {\n\t\t\t\tbuf.Write(br)\n\t\t\t\tskip = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbuf.Write(br)\n\t\tdefault:\n\t\t\tbuf.WriteRune(v)\n\t\t}\n\t}\n\treturn buf.String()\n}\n\n// WordWrap wraps a string to a given number of characters.\n// This function supports cut parameters of both english and chinese punctuations.\n// TODO: Enable custom cut parameter, see http://php.net/manual/en/function.wordwrap.php.\nfunc WordWrap(str string, width int, br string) string {\n\tif br == \"\" {\n\t\tbr = \"\\n\"\n\t}\n\tvar (\n\t\tcurrent           int\n\t\twordBuf, spaceBuf bytes.Buffer\n\t\tinit              = make([]byte, 0, len(str))\n\t\tbuf               = bytes.NewBuffer(init)\n\t)\n\tfor _, char := range str {\n\t\tswitch {\n\t\tcase char == '\\n':\n\t\t\tif wordBuf.Len() == 0 {\n\t\t\t\tif current+spaceBuf.Len() > width {\n\t\t\t\t\tcurrent = 0\n\t\t\t\t} else {\n\t\t\t\t\tcurrent += spaceBuf.Len()\n\t\t\t\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t\t\t}\n\t\t\t\tspaceBuf.Reset()\n\t\t\t} else {\n\t\t\t\tcurrent += spaceBuf.Len() + wordBuf.Len()\n\t\t\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t\t\tspaceBuf.Reset()\n\t\t\t\t_, _ = wordBuf.WriteTo(buf)\n\t\t\t\twordBuf.Reset()\n\t\t\t}\n\t\t\tbuf.WriteRune(char)\n\t\t\tcurrent = 0\n\n\t\tcase unicode.IsSpace(char):\n\t\t\tif spaceBuf.Len() == 0 || wordBuf.Len() > 0 {\n\t\t\t\tcurrent += spaceBuf.Len() + wordBuf.Len()\n\t\t\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t\t\tspaceBuf.Reset()\n\t\t\t\t_, _ = wordBuf.WriteTo(buf)\n\t\t\t\twordBuf.Reset()\n\t\t\t}\n\t\t\tspaceBuf.WriteRune(char)\n\n\t\tcase isPunctuation(char):\n\t\t\twordBuf.WriteRune(char)\n\t\t\tif spaceBuf.Len() == 0 || wordBuf.Len() > 0 {\n\t\t\t\tcurrent += spaceBuf.Len() + wordBuf.Len()\n\t\t\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t\t\tspaceBuf.Reset()\n\t\t\t\t_, _ = wordBuf.WriteTo(buf)\n\t\t\t\twordBuf.Reset()\n\t\t\t}\n\n\t\tdefault:\n\t\t\twordBuf.WriteRune(char)\n\t\t\tif current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width {\n\t\t\t\tbuf.WriteString(br)\n\t\t\t\tcurrent = 0\n\t\t\t\tspaceBuf.Reset()\n\t\t\t}\n\t\t}\n\t}\n\n\tif wordBuf.Len() == 0 {\n\t\tif current+spaceBuf.Len() <= width {\n\t\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t}\n\t} else {\n\t\t_, _ = spaceBuf.WriteTo(buf)\n\t\t_, _ = wordBuf.WriteTo(buf)\n\t}\n\treturn buf.String()\n}\n\nfunc isPunctuation(char int32) bool {\n\tswitch char {\n\t// English Punctuations.\n\tcase ';', '.', ',', ':', '~':\n\t\treturn true\n\t// Chinese Punctuations.\n\tcase '；', '，', '。', '：', '？', '！', '…', '、':\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "text/gstr/gstr_count.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"unicode\"\n)\n\n// Count counts the number of `substr` appears in `s`.\n// It returns 0 if no `substr` found in `s`.\nfunc Count(s, substr string) int {\n\treturn strings.Count(s, substr)\n}\n\n// CountI counts the number of `substr` appears in `s`, case-insensitively.\n// It returns 0 if no `substr` found in `s`.\nfunc CountI(s, substr string) int {\n\treturn strings.Count(ToLower(s), ToLower(substr))\n}\n\n// CountWords returns information about words' count used in a string.\n// It considers parameter `str` as unicode string.\nfunc CountWords(str string) map[string]int {\n\tm := make(map[string]int)\n\tbuffer := bytes.NewBuffer(nil)\n\tfor _, r := range str {\n\t\tif unicode.IsSpace(r) {\n\t\t\tif buffer.Len() > 0 {\n\t\t\t\tm[buffer.String()]++\n\t\t\t\tbuffer.Reset()\n\t\t\t}\n\t\t} else {\n\t\t\tbuffer.WriteRune(r)\n\t\t}\n\t}\n\tif buffer.Len() > 0 {\n\t\tm[buffer.String()]++\n\t}\n\treturn m\n}\n\n// CountChars returns information about chars' count used in a string.\n// It considers parameter `str` as Unicode string.\nfunc CountChars(str string, noSpace ...bool) map[string]int {\n\tm := make(map[string]int)\n\tcountSpace := len(noSpace) == 0 || !noSpace[0]\n\tfor _, r := range str {\n\t\tif !countSpace && unicode.IsSpace(r) {\n\t\t\tcontinue\n\t\t}\n\t\tm[string(r)]++\n\t}\n\treturn m\n}\n"
  },
  {
    "path": "text/gstr/gstr_create.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// Repeat returns a new string consisting of multiplier copies of the string input.\n//\n// Example:\n// Repeat(\"a\", 3) -> \"aaa\"\nfunc Repeat(input string, multiplier int) string {\n\treturn strings.Repeat(input, multiplier)\n}\n"
  },
  {
    "path": "text/gstr/gstr_domain.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// IsSubDomain checks whether `subDomain` is sub-domain of mainDomain.\n// It supports '*' in `mainDomain`.\nfunc IsSubDomain(subDomain string, mainDomain string) bool {\n\tif p := strings.IndexByte(subDomain, ':'); p != -1 {\n\t\tsubDomain = subDomain[0:p]\n\t}\n\tif p := strings.IndexByte(mainDomain, ':'); p != -1 {\n\t\tmainDomain = mainDomain[0:p]\n\t}\n\tvar (\n\t\tsubArray   = strings.Split(subDomain, \".\")\n\t\tmainArray  = strings.Split(mainDomain, \".\")\n\t\tsubLength  = len(subArray)\n\t\tmainLength = len(mainArray)\n\t)\n\t// Eg:\n\t// \"goframe.org\" is not sub-domain of \"s.goframe.org\".\n\tif mainLength > subLength {\n\t\tfor i := range mainArray[0 : mainLength-subLength] {\n\t\t\tif mainArray[i] != \"*\" {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\t// Eg:\n\t// \"s.s.goframe.org\" is not sub-domain of \"*.goframe.org\"\n\t// but\n\t// \"s.s.goframe.org\" is sub-domain of \"goframe.org\"\n\tif mainLength > 2 && subLength > mainLength {\n\t\treturn false\n\t}\n\tminLength := subLength\n\tif mainLength < minLength {\n\t\tminLength = mainLength\n\t}\n\tfor i := minLength; i > 0; i-- {\n\t\tif mainArray[mainLength-i] == \"*\" {\n\t\t\tcontinue\n\t\t}\n\t\tif mainArray[mainLength-i] != subArray[subLength-i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "text/gstr/gstr_is.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"github.com/gogf/gf/v2/internal/utils\"\n\n// IsNumeric tests whether the given string s is numeric.\nfunc IsNumeric(s string) bool {\n\treturn utils.IsNumeric(s)\n}\n"
  },
  {
    "path": "text/gstr/gstr_length.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"unicode/utf8\"\n\n// LenRune returns string length of unicode.\nfunc LenRune(str string) int {\n\treturn utf8.RuneCountInString(str)\n}\n"
  },
  {
    "path": "text/gstr/gstr_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\n// List2 Split the `str` with `delimiter` and returns the result as two parts string.\nfunc List2(str, delimiter string) (part1, part2 string) {\n\treturn doList2(delimiter, Split(str, delimiter))\n}\n\n// ListAndTrim2 SplitAndTrim the `str` with `delimiter` and returns the result as two parts string.\nfunc ListAndTrim2(str, delimiter string) (part1, part2 string) {\n\treturn doList2(delimiter, SplitAndTrim(str, delimiter))\n}\n\nfunc doList2(delimiter string, array []string) (part1, part2 string) {\n\tswitch len(array) {\n\tcase 0:\n\t\treturn \"\", \"\"\n\tcase 1:\n\t\treturn array[0], \"\"\n\tcase 2:\n\t\treturn array[0], array[1]\n\tdefault:\n\t\treturn array[0], Join(array[1:], delimiter)\n\t}\n}\n\n// List3 Split the `str` with `delimiter` and returns the result as three parts string.\nfunc List3(str, delimiter string) (part1, part2, part3 string) {\n\treturn doList3(delimiter, Split(str, delimiter))\n}\n\n// ListAndTrim3 SplitAndTrim the `str` with `delimiter` and returns the result as three parts string.\nfunc ListAndTrim3(str, delimiter string) (part1, part2, part3 string) {\n\treturn doList3(delimiter, SplitAndTrim(str, delimiter))\n}\n\nfunc doList3(delimiter string, array []string) (part1, part2, part3 string) {\n\tswitch len(array) {\n\tcase 0:\n\t\treturn \"\", \"\", \"\"\n\tcase 1:\n\t\treturn array[0], \"\", \"\"\n\tcase 2:\n\t\treturn array[0], array[1], \"\"\n\tcase 3:\n\t\treturn array[0], array[1], array[2]\n\tdefault:\n\t\treturn array[0], array[1], Join(array[2:], delimiter)\n\t}\n}\n"
  },
  {
    "path": "text/gstr/gstr_parse.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Parse parses the string into map[string]any.\n//\n// v1=m&v2=n           -> map[v1:m v2:n]\n// v[a]=m&v[b]=n       -> map[v:map[a:m b:n]]\n// v[a][a]=m&v[a][b]=n -> map[v:map[a:map[a:m b:n]]]\n// v[]=m&v[]=n         -> map[v:[m n]]\n// v[a][]=m&v[a][]=n   -> map[v:map[a:[m n]]]\n// v[][]=m&v[][]=n     -> map[v:[map[]]] // Currently does not support nested slice.\n// v=m&v[a]=n          -> error\n// a .[[b=c            -> map[a___[b:c]\nfunc Parse(s string) (result map[string]any, err error) {\n\tif s == \"\" {\n\t\treturn nil, nil\n\t}\n\tresult = make(map[string]any)\n\tparts := strings.Split(s, \"&\")\n\tfor _, part := range parts {\n\t\tpos := strings.Index(part, \"=\")\n\t\tif pos <= 0 {\n\t\t\tcontinue\n\t\t}\n\t\tkey, err := url.QueryUnescape(part[:pos])\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `url.QueryUnescape failed for string \"%s\"`, part[:pos])\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor len(key) > 0 && key[0] == ' ' {\n\t\t\tkey = key[1:]\n\t\t}\n\n\t\tif key == \"\" || key[0] == '[' {\n\t\t\tcontinue\n\t\t}\n\t\tvalue, err := url.QueryUnescape(part[pos+1:])\n\t\tif err != nil {\n\t\t\terr = gerror.Wrapf(err, `url.QueryUnescape failed for string \"%s\"`, part[pos+1:])\n\t\t\treturn nil, err\n\t\t}\n\t\t// split into multiple keys\n\t\tvar keys []string\n\t\tleft := 0\n\t\tfor i, k := range key {\n\t\t\tif k == '[' && left == 0 {\n\t\t\t\tleft = i\n\t\t\t} else if k == ']' {\n\t\t\t\tif left > 0 {\n\t\t\t\t\tif len(keys) == 0 {\n\t\t\t\t\t\tkeys = append(keys, key[:left])\n\t\t\t\t\t}\n\t\t\t\t\tkeys = append(keys, key[left+1:i])\n\t\t\t\t\tleft = 0\n\t\t\t\t\tif i+1 < len(key) && key[i+1] != '[' {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(keys) == 0 {\n\t\t\tkeys = append(keys, key)\n\t\t}\n\t\t// first key\n\t\tfirst := \"\"\n\t\tfor i, chr := range keys[0] {\n\t\t\tif chr == ' ' || chr == '.' || chr == '[' {\n\t\t\t\tfirst += \"_\"\n\t\t\t} else {\n\t\t\t\tfirst += string(chr)\n\t\t\t}\n\t\t\tif chr == '[' {\n\t\t\t\tfirst += keys[0][i+1:]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tkeys[0] = first\n\n\t\t// build nested map\n\t\tif err = build(result, keys, value); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn result, nil\n}\n\n// build nested map.\nfunc build(result map[string]any, keys []string, value any) error {\n\tvar (\n\t\tlength = len(keys)\n\t\tkey    = strings.Trim(keys[0], \"'\\\"\")\n\t)\n\tif length == 1 {\n\t\tresult[key] = value\n\t\treturn nil\n\t}\n\n\t// The end is slice. like f[], f[a][]\n\tif keys[1] == \"\" && length == 2 {\n\t\t// TODO nested slice\n\t\tif key == \"\" {\n\t\t\treturn nil\n\t\t}\n\t\tval, ok := result[key]\n\t\tif !ok {\n\t\t\tresult[key] = []any{value}\n\t\t\treturn nil\n\t\t}\n\t\tchildren, ok := val.([]any)\n\t\tif !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\"expected type '[]any' for key '%s', but got '%T'\",\n\t\t\t\tkey, val,\n\t\t\t)\n\t\t}\n\t\tresult[key] = append(children, value)\n\t\treturn nil\n\t}\n\t// The end is slice + map. like v[][a]\n\tif keys[1] == \"\" && length > 2 && keys[2] != \"\" {\n\t\tval, ok := result[key]\n\t\tif !ok {\n\t\t\tresult[key] = []any{}\n\t\t\tval = result[key]\n\t\t}\n\t\tchildren, ok := val.([]any)\n\t\tif !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\"expected type '[]any' for key '%s', but got '%T'\",\n\t\t\t\tkey, val,\n\t\t\t)\n\t\t}\n\t\tif l := len(children); l > 0 {\n\t\t\tif child, ok := children[l-1].(map[string]any); ok {\n\t\t\t\tif _, ok := child[keys[2]]; !ok {\n\t\t\t\t\t_ = build(child, keys[2:], value)\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tchild := map[string]any{}\n\t\t_ = build(child, keys[2:], value)\n\t\tresult[key] = append(children, child)\n\t\treturn nil\n\t}\n\n\t// map, like v[a], v[a][b]\n\tval, ok := result[key]\n\tif !ok {\n\t\tresult[key] = map[string]any{}\n\t\tval = result[key]\n\t}\n\tchildren, ok := val.(map[string]any)\n\tif !ok {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"expected type 'map[string]any' for key '%s', but got '%T'\",\n\t\t\tkey, val,\n\t\t)\n\t}\n\tif err := build(children, keys[1:], value); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "text/gstr/gstr_pos.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// Pos returns the position of the first occurrence of `needle`\n// in `haystack` from `startOffset`, case-sensitively.\n// It returns -1, if not found.\nfunc Pos(haystack, needle string, startOffset ...int) int {\n\tlength := len(haystack)\n\toffset := 0\n\tif len(startOffset) > 0 {\n\t\toffset = startOffset[0]\n\t}\n\tif length == 0 || offset > length || -offset > length {\n\t\treturn -1\n\t}\n\tif offset < 0 {\n\t\toffset += length\n\t}\n\tpos := strings.Index(haystack[offset:], needle)\n\tif pos == NotFoundIndex {\n\t\treturn NotFoundIndex\n\t}\n\treturn pos + offset\n}\n\n// PosRune acts like function Pos but considers `haystack` and `needle` as unicode string.\nfunc PosRune(haystack, needle string, startOffset ...int) int {\n\tpos := Pos(haystack, needle, startOffset...)\n\tif pos < 3 {\n\t\treturn pos\n\t}\n\treturn len([]rune(haystack[:pos]))\n}\n\n// PosI returns the position of the first occurrence of `needle`\n// in `haystack` from `startOffset`, case-insensitively.\n// It returns -1, if not found.\nfunc PosI(haystack, needle string, startOffset ...int) int {\n\tlength := len(haystack)\n\toffset := 0\n\tif len(startOffset) > 0 {\n\t\toffset = startOffset[0]\n\t}\n\tif length == 0 || offset > length || -offset > length {\n\t\treturn -1\n\t}\n\n\tif offset < 0 {\n\t\toffset += length\n\t}\n\tpos := strings.Index(strings.ToLower(haystack[offset:]), strings.ToLower(needle))\n\tif pos == -1 {\n\t\treturn -1\n\t}\n\treturn pos + offset\n}\n\n// PosIRune acts like function PosI but considers `haystack` and `needle` as unicode string.\nfunc PosIRune(haystack, needle string, startOffset ...int) int {\n\tpos := PosI(haystack, needle, startOffset...)\n\tif pos < 3 {\n\t\treturn pos\n\t}\n\treturn len([]rune(haystack[:pos]))\n}\n\n// PosR returns the position of the last occurrence of `needle`\n// in `haystack` from `startOffset`, case-sensitively.\n// It returns -1, if not found.\nfunc PosR(haystack, needle string, startOffset ...int) int {\n\toffset := 0\n\tif len(startOffset) > 0 {\n\t\toffset = startOffset[0]\n\t}\n\tpos, length := 0, len(haystack)\n\tif length == 0 || offset > length || -offset > length {\n\t\treturn -1\n\t}\n\n\tif offset < 0 {\n\t\thaystack = haystack[:offset+length+1]\n\t} else {\n\t\thaystack = haystack[offset:]\n\t}\n\tpos = strings.LastIndex(haystack, needle)\n\tif offset > 0 && pos != -1 {\n\t\tpos += offset\n\t}\n\treturn pos\n}\n\n// PosRRune acts like function PosR but considers `haystack` and `needle` as unicode string.\nfunc PosRRune(haystack, needle string, startOffset ...int) int {\n\tpos := PosR(haystack, needle, startOffset...)\n\tif pos < 3 {\n\t\treturn pos\n\t}\n\treturn len([]rune(haystack[:pos]))\n}\n\n// PosRI returns the position of the last occurrence of `needle`\n// in `haystack` from `startOffset`, case-insensitively.\n// It returns -1, if not found.\nfunc PosRI(haystack, needle string, startOffset ...int) int {\n\toffset := 0\n\tif len(startOffset) > 0 {\n\t\toffset = startOffset[0]\n\t}\n\tpos, length := 0, len(haystack)\n\tif length == 0 || offset > length || -offset > length {\n\t\treturn -1\n\t}\n\n\tif offset < 0 {\n\t\thaystack = haystack[:offset+length+1]\n\t} else {\n\t\thaystack = haystack[offset:]\n\t}\n\tpos = strings.LastIndex(strings.ToLower(haystack), strings.ToLower(needle))\n\tif offset > 0 && pos != -1 {\n\t\tpos += offset\n\t}\n\treturn pos\n}\n\n// PosRIRune acts like function PosRI but considers `haystack` and `needle` as unicode string.\nfunc PosRIRune(haystack, needle string, startOffset ...int) int {\n\tpos := PosRI(haystack, needle, startOffset...)\n\tif pos < 3 {\n\t\treturn pos\n\t}\n\treturn len([]rune(haystack[:pos]))\n}\n"
  },
  {
    "path": "text/gstr/gstr_replace.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// Replace returns a copy of the string `origin`\n// in which string `search` replaced by `replace` case-sensitively.\nfunc Replace(origin, search, replace string, count ...int) string {\n\tn := -1\n\tif len(count) > 0 {\n\t\tn = count[0]\n\t}\n\treturn strings.Replace(origin, search, replace, n)\n}\n\n// ReplaceI returns a copy of the string `origin`\n// in which string `search` replaced by `replace` case-insensitively.\nfunc ReplaceI(origin, search, replace string, count ...int) string {\n\tn := -1\n\tif len(count) > 0 {\n\t\tn = count[0]\n\t}\n\tif n == 0 {\n\t\treturn origin\n\t}\n\tvar (\n\t\tsearchLength  = len(search)\n\t\treplaceLength = len(replace)\n\t\tsearchLower   = strings.ToLower(search)\n\t\toriginLower   string\n\t\tpos           int\n\t)\n\tfor {\n\t\toriginLower = strings.ToLower(origin)\n\t\tif pos = Pos(originLower, searchLower, pos); pos != -1 {\n\t\t\torigin = origin[:pos] + replace + origin[pos+searchLength:]\n\t\t\tpos += replaceLength\n\t\t\tif n--; n == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn origin\n}\n\n// ReplaceByArray returns a copy of `origin`,\n// which is replaced by a slice in order, case-sensitively.\nfunc ReplaceByArray(origin string, array []string) string {\n\tfor i := 0; i < len(array); i += 2 {\n\t\tif i+1 >= len(array) {\n\t\t\tbreak\n\t\t}\n\t\torigin = Replace(origin, array[i], array[i+1])\n\t}\n\treturn origin\n}\n\n// ReplaceIByArray returns a copy of `origin`,\n// which is replaced by a slice in order, case-insensitively.\nfunc ReplaceIByArray(origin string, array []string) string {\n\tfor i := 0; i < len(array); i += 2 {\n\t\tif i+1 >= len(array) {\n\t\t\tbreak\n\t\t}\n\t\torigin = ReplaceI(origin, array[i], array[i+1])\n\t}\n\treturn origin\n}\n\n// ReplaceByMap returns a copy of `origin`,\n// which is replaced by a map in unordered way, case-sensitively.\nfunc ReplaceByMap(origin string, replaces map[string]string) string {\n\treturn utils.ReplaceByMap(origin, replaces)\n}\n\n// ReplaceIByMap returns a copy of `origin`,\n// which is replaced by a map in unordered way, case-insensitively.\nfunc ReplaceIByMap(origin string, replaces map[string]string) string {\n\tfor k, v := range replaces {\n\t\torigin = ReplaceI(origin, k, v)\n\t}\n\treturn origin\n}\n\n// ReplaceFunc returns a copy of the string `origin` in which each non-overlapping substring\n// that matches the given search string is replaced by the result of function `f` applied to that substring.\n// The function `f` is called with each matching substring as its argument and must return a string to be used\n// as the replacement value.\nfunc ReplaceFunc(origin string, search string, f func(string) string) string {\n\tif search == \"\" {\n\t\treturn origin\n\t}\n\tvar (\n\t\tsearchLen = len(search)\n\t\toriginLen = len(origin)\n\t)\n\t// If search string is longer than origin string, no match is possible\n\tif searchLen > originLen {\n\t\treturn origin\n\t}\n\tvar (\n\t\tresult     strings.Builder\n\t\tlastMatch  int\n\t\tcurrentPos int\n\t)\n\t// Pre-allocate the builder capacity to avoid reallocations\n\tresult.Grow(originLen)\n\n\tfor currentPos < originLen {\n\t\tpos := Pos(origin[currentPos:], search)\n\t\tif pos == -1 {\n\t\t\tbreak\n\t\t}\n\t\tpos += currentPos\n\t\t// Append unmatched portion\n\t\tresult.WriteString(origin[lastMatch:pos])\n\t\t// Apply replacement function and append result\n\t\tmatch := origin[pos : pos+searchLen]\n\t\tresult.WriteString(f(match))\n\t\t// Update positions\n\t\tlastMatch = pos + searchLen\n\t\tcurrentPos = lastMatch\n\t}\n\t// Append remaining unmatched portion\n\tif lastMatch < originLen {\n\t\tresult.WriteString(origin[lastMatch:])\n\t}\n\treturn result.String()\n}\n\n// ReplaceIFunc returns a copy of the string `origin` in which each non-overlapping substring\n// that matches the given search string is replaced by the result of function `f` applied to that substring.\n// The match is done case-insensitively.\n// The function `f` is called with each matching substring as its argument and must return a string to be used\n// as the replacement value.\nfunc ReplaceIFunc(origin string, search string, f func(string) string) string {\n\tif search == \"\" {\n\t\treturn origin\n\t}\n\tvar (\n\t\tsearchLen = len(search)\n\t\toriginLen = len(origin)\n\t)\n\t// If search string is longer than origin string, no match is possible\n\tif searchLen > originLen {\n\t\treturn origin\n\t}\n\tvar (\n\t\tresult     strings.Builder\n\t\tlastMatch  int\n\t\tcurrentPos int\n\t)\n\t// Pre-allocate the builder capacity to avoid reallocations\n\tresult.Grow(originLen)\n\n\tfor currentPos < originLen {\n\t\tpos := PosI(origin[currentPos:], search)\n\t\tif pos == -1 {\n\t\t\tbreak\n\t\t}\n\t\tpos += currentPos\n\t\t// Append unmatched portion\n\t\tresult.WriteString(origin[lastMatch:pos])\n\t\t// Apply replacement function and append result\n\t\tmatch := origin[pos : pos+searchLen]\n\t\tresult.WriteString(f(match))\n\t\t// Update positions\n\t\tlastMatch = pos + searchLen\n\t\tcurrentPos = lastMatch\n\t}\n\t// Append remaining unmatched portion\n\tif lastMatch < originLen {\n\t\tresult.WriteString(origin[lastMatch:])\n\t}\n\treturn result.String()\n}\n"
  },
  {
    "path": "text/gstr/gstr_similar.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\n// Levenshtein calculates Levenshtein distance between two strings.\n// costIns: Defines the cost of insertion.\n// costRep: Defines the cost of replacement.\n// costDel: Defines the cost of deletion.\n// See http://php.net/manual/en/function.levenshtein.php.\nfunc Levenshtein(str1, str2 string, costIns, costRep, costDel int) int {\n\tvar maxLen = 255\n\tl1 := len(str1)\n\tl2 := len(str2)\n\tif l1 == 0 {\n\t\treturn l2 * costIns\n\t}\n\tif l2 == 0 {\n\t\treturn l1 * costDel\n\t}\n\tif l1 > maxLen || l2 > maxLen {\n\t\treturn -1\n\t}\n\n\tp1 := make([]int, l2+1)\n\tp2 := make([]int, l2+1)\n\tvar c0, c1, c2 int\n\tvar i1, i2 int\n\tfor i2 := 0; i2 <= l2; i2++ {\n\t\tp1[i2] = i2 * costIns\n\t}\n\tfor i1 = 0; i1 < l1; i1++ {\n\t\tp2[0] = p1[0] + costDel\n\t\tfor i2 = 0; i2 < l2; i2++ {\n\t\t\tif str1[i1] == str2[i2] {\n\t\t\t\tc0 = p1[i2]\n\t\t\t} else {\n\t\t\t\tc0 = p1[i2] + costRep\n\t\t\t}\n\t\t\tc1 = p1[i2+1] + costDel\n\t\t\tif c1 < c0 {\n\t\t\t\tc0 = c1\n\t\t\t}\n\t\t\tc2 = p2[i2] + costIns\n\t\t\tif c2 < c0 {\n\t\t\t\tc0 = c2\n\t\t\t}\n\t\t\tp2[i2+1] = c0\n\t\t}\n\t\tp1, p2 = p2, p1\n\t}\n\tc0 = p1[l2]\n\n\treturn c0\n}\n\n// SimilarText calculates the similarity between two strings.\n// See http://php.net/manual/en/function.similar-text.php.\nfunc SimilarText(first, second string, percent *float64) int {\n\tvar similarText func(string, string, int, int) int\n\tsimilarText = func(str1, str2 string, len1, len2 int) int {\n\t\tvar sum, max int\n\t\tpos1, pos2 := 0, 0\n\n\t\t// Find the longest segment of the same section in two strings\n\t\tfor i := 0; i < len1; i++ {\n\t\t\tfor j := 0; j < len2; j++ {\n\t\t\t\tfor l := 0; (i+l < len1) && (j+l < len2) && (str1[i+l] == str2[j+l]); l++ {\n\t\t\t\t\tif l+1 > max {\n\t\t\t\t\t\tmax = l + 1\n\t\t\t\t\t\tpos1 = i\n\t\t\t\t\t\tpos2 = j\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif sum = max; sum > 0 {\n\t\t\tif pos1 > 0 && pos2 > 0 {\n\t\t\t\tsum += similarText(str1, str2, pos1, pos2)\n\t\t\t}\n\t\t\tif (pos1+max < len1) && (pos2+max < len2) {\n\t\t\t\ts1 := []byte(str1)\n\t\t\t\ts2 := []byte(str2)\n\t\t\t\tsum += similarText(string(s1[pos1+max:]), string(s2[pos2+max:]), len1-pos1-max, len2-pos2-max)\n\t\t\t}\n\t\t}\n\n\t\treturn sum\n\t}\n\n\tl1, l2 := len(first), len(second)\n\tif l1+l2 == 0 {\n\t\treturn 0\n\t}\n\tsim := similarText(first, second, l1, l2)\n\tif percent != nil {\n\t\t*percent = float64(sim*200) / float64(l1+l2)\n\t}\n\treturn sim\n}\n\n// Soundex calculates the soundex key of a string.\n// See http://php.net/manual/en/function.soundex.php.\nfunc Soundex(str string) string {\n\tif str == \"\" {\n\t\tpanic(\"str: cannot be an empty string\")\n\t}\n\ttable := [26]rune{\n\t\t'0', '1', '2', '3', // A, B, C, D\n\t\t'0', '1', '2', // E, F, G\n\t\t'0',                          // H\n\t\t'0', '2', '2', '4', '5', '5', // I, J, K, L, M, N\n\t\t'0', '1', '2', '6', '2', '3', // O, P, Q, R, S, T\n\t\t'0', '1', // U, V\n\t\t'0', '2', // W, X\n\t\t'0', '2', // Y, Z\n\t}\n\tlast, code, small := -1, 0, 0\n\tsd := make([]rune, 4)\n\t// build soundex string\n\tfor i := 0; i < len(str) && small < 4; i++ {\n\t\t// ToUpper\n\t\tchar := str[i]\n\t\tif char < '\\u007F' && 'a' <= char && char <= 'z' {\n\t\t\tcode = int(char - 'a' + 'A')\n\t\t} else {\n\t\t\tcode = int(char)\n\t\t}\n\t\tif code >= 'A' && code <= 'Z' {\n\t\t\tif small == 0 {\n\t\t\t\tsd[small] = rune(code)\n\t\t\t\tsmall++\n\t\t\t\tlast = int(table[code-'A'])\n\t\t\t} else {\n\t\t\t\tcode = int(table[code-'A'])\n\t\t\t\tif code != last {\n\t\t\t\t\tif code != 0 {\n\t\t\t\t\t\tsd[small] = rune(code)\n\t\t\t\t\t\tsmall++\n\t\t\t\t\t}\n\t\t\t\t\tlast = code\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// pad with \"0\"\n\tfor ; small < 4; small++ {\n\t\tsd[small] = '0'\n\t}\n\treturn string(sd)\n}\n"
  },
  {
    "path": "text/gstr/gstr_slashes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// AddSlashes quotes with slashes `\\` for chars: '\"\\.\nfunc AddSlashes(str string) string {\n\tvar buf bytes.Buffer\n\tfor _, char := range str {\n\t\tswitch char {\n\t\tcase '\\'', '\"', '\\\\':\n\t\t\tbuf.WriteRune('\\\\')\n\t\t}\n\t\tbuf.WriteRune(char)\n\t}\n\treturn buf.String()\n}\n\n// StripSlashes un-quotes a quoted string by AddSlashes.\nfunc StripSlashes(str string) string {\n\treturn utils.StripSlashes(str)\n}\n\n// QuoteMeta returns a version of `str` with a backslash character (`\\`).\n// If custom chars `chars` not given, it uses default chars: .\\+*?[^]($)\nfunc QuoteMeta(str string, chars ...string) string {\n\tvar buf bytes.Buffer\n\tfor _, char := range str {\n\t\tif len(chars) > 0 {\n\t\t\tfor _, c := range chars[0] {\n\t\t\t\tif c == char {\n\t\t\t\t\tbuf.WriteRune('\\\\')\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tswitch char {\n\t\t\tcase '.', '+', '\\\\', '(', '$', ')', '[', '^', ']', '*', '?':\n\t\t\t\tbuf.WriteRune('\\\\')\n\t\t\t}\n\t\t}\n\t\tbuf.WriteRune(char)\n\t}\n\treturn buf.String()\n}\n"
  },
  {
    "path": "text/gstr/gstr_split_join.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Split splits string `str` by a string `delimiter`, to an array.\nfunc Split(str, delimiter string) []string {\n\treturn strings.Split(str, delimiter)\n}\n\n// SplitAndTrim splits string `str` by a string `delimiter` to an array,\n// and calls Trim to every element of this array. It ignores the elements\n// which are empty after Trim.\nfunc SplitAndTrim(str, delimiter string, characterMask ...string) []string {\n\treturn utils.SplitAndTrim(str, delimiter, characterMask...)\n}\n\n// Join concatenates the elements of `array` to create a single string. The separator string\n// `sep` is placed between elements in the resulting string.\nfunc Join(array []string, sep string) string {\n\treturn strings.Join(array, sep)\n}\n\n// JoinAny concatenates the elements of `array` to create a single string. The separator string\n// `sep` is placed between elements in the resulting string.\n//\n// The parameter `array` can be any type of slice, which be converted to string array.\nfunc JoinAny(array any, sep string) string {\n\treturn strings.Join(gconv.Strings(array), sep)\n}\n\n// Explode splits string `str` by a string `delimiter`, to an array.\n// See http://php.net/manual/en/function.explode.php.\nfunc Explode(delimiter, str string) []string {\n\treturn Split(str, delimiter)\n}\n\n// Implode joins array elements `pieces` with a string `glue`.\n// http://php.net/manual/en/function.implode.php\nfunc Implode(glue string, pieces []string) string {\n\treturn strings.Join(pieces, glue)\n}\n\n// ChunkSplit splits a string into smaller chunks.\n// Can be used to split a string into smaller chunks which is useful for\n// e.g. converting BASE64 string output to match RFC 2045 semantics.\n// It inserts end every chunkLen characters.\n// It considers parameter `body` and `end` as unicode string.\nfunc ChunkSplit(body string, chunkLen int, end string) string {\n\tif end == \"\" {\n\t\tend = \"\\r\\n\"\n\t}\n\trunes, endRunes := []rune(body), []rune(end)\n\tl := len(runes)\n\tif l <= 1 || l < chunkLen {\n\t\treturn body + end\n\t}\n\tns := make([]rune, 0, len(runes)+len(endRunes))\n\tfor i := 0; i < l; i += chunkLen {\n\t\tif i+chunkLen > l {\n\t\t\tns = append(ns, runes[i:]...)\n\t\t} else {\n\t\t\tns = append(ns, runes[i:i+chunkLen]...)\n\t\t}\n\t\tns = append(ns, endRunes...)\n\t}\n\treturn string(ns)\n}\n\n// Fields returns the words used in a string as slice.\nfunc Fields(str string) []string {\n\treturn strings.Fields(str)\n}\n"
  },
  {
    "path": "text/gstr/gstr_sub.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport \"strings\"\n\n// Str returns part of `haystack` string starting from and including\n// the first occurrence of `needle` to the end of `haystack`.\n//\n// This function performs exactly as function SubStr, but to implement the same function\n// as PHP: http://php.net/manual/en/function.strstr.php.\n//\n// Example:\n// Str(\"av.mp4\", \".\") -> \".mp4\"\nfunc Str(haystack string, needle string) string {\n\tif needle == \"\" {\n\t\treturn \"\"\n\t}\n\tpos := strings.Index(haystack, needle)\n\tif pos == NotFoundIndex {\n\t\treturn \"\"\n\t}\n\treturn haystack[pos+len([]byte(needle))-1:]\n}\n\n// StrEx returns part of `haystack` string starting from and excluding\n// the first occurrence of `needle` to the end of `haystack`.\n//\n// This function performs exactly as function SubStrEx, but to implement the same function\n// as PHP: http://php.net/manual/en/function.strstr.php.\n//\n// Example:\n// StrEx(\"av.mp4\", \".\") -> \"mp4\"\nfunc StrEx(haystack string, needle string) string {\n\tif s := Str(haystack, needle); s != \"\" {\n\t\treturn s[1:]\n\t}\n\treturn \"\"\n}\n\n// StrTill returns part of `haystack` string ending to and including\n// the first occurrence of `needle` from the start of `haystack`.\n//\n// Example:\n// StrTill(\"av.mp4\", \".\") -> \"av.\"\nfunc StrTill(haystack string, needle string) string {\n\tpos := strings.Index(haystack, needle)\n\tif pos == NotFoundIndex || pos == 0 {\n\t\treturn \"\"\n\t}\n\treturn haystack[:pos+1]\n}\n\n// StrTillEx returns part of `haystack` string ending to and excluding\n// the first occurrence of `needle` from the start of `haystack`.\n//\n// Example:\n// StrTillEx(\"av.mp4\", \".\") -> \"av\"\nfunc StrTillEx(haystack string, needle string) string {\n\tpos := strings.Index(haystack, needle)\n\tif pos == NotFoundIndex || pos == 0 {\n\t\treturn \"\"\n\t}\n\treturn haystack[:pos]\n}\n\n// SubStr returns a portion of string `str` specified by the `start` and `length` parameters.\n// The parameter `length` is optional, it uses the length of `str` in default.\n//\n// Example:\n// SubStr(\"123456\", 1, 2) -> \"23\"\nfunc SubStr(str string, start int, length ...int) (substr string) {\n\tstrLength := len(str)\n\tif start < 0 {\n\t\tif -start > strLength {\n\t\t\tstart = 0\n\t\t} else {\n\t\t\tstart = strLength + start\n\t\t}\n\t} else if start > strLength {\n\t\treturn \"\"\n\t}\n\trealLength := 0\n\tif len(length) > 0 {\n\t\trealLength = length[0]\n\t\tif realLength < 0 {\n\t\t\tif -realLength > strLength-start {\n\t\t\t\trealLength = 0\n\t\t\t} else {\n\t\t\t\trealLength = strLength - start + realLength\n\t\t\t}\n\t\t} else if realLength > strLength-start {\n\t\t\trealLength = strLength - start\n\t\t}\n\t} else {\n\t\trealLength = strLength - start\n\t}\n\n\tif realLength == strLength {\n\t\treturn str\n\t} else {\n\t\tend := start + realLength\n\t\treturn str[start:end]\n\t}\n}\n\n// SubStrRune returns a portion of string `str` specified by the `start` and `length` parameters.\n// SubStrRune considers parameter `str` as unicode string.\n// The parameter `length` is optional, it uses the length of `str` in default.\n//\n// Example:\n// SubStrRune(\"一起学习吧！\", 2, 2) -> \"学习\"\nfunc SubStrRune(str string, start int, length ...int) (substr string) {\n\t// Converting to []rune to support unicode.\n\tvar (\n\t\trunes       = []rune(str)\n\t\trunesLength = len(runes)\n\t)\n\n\tstrLength := runesLength\n\tif start < 0 {\n\t\tif -start > strLength {\n\t\t\tstart = 0\n\t\t} else {\n\t\t\tstart = strLength + start\n\t\t}\n\t} else if start > strLength {\n\t\treturn \"\"\n\t}\n\trealLength := 0\n\tif len(length) > 0 {\n\t\trealLength = length[0]\n\t\tif realLength < 0 {\n\t\t\tif -realLength > strLength-start {\n\t\t\t\trealLength = 0\n\t\t\t} else {\n\t\t\t\trealLength = strLength - start + realLength\n\t\t\t}\n\t\t} else if realLength > strLength-start {\n\t\t\trealLength = strLength - start\n\t\t}\n\t} else {\n\t\trealLength = strLength - start\n\t}\n\tend := start + realLength\n\tif end > runesLength {\n\t\tend = runesLength\n\t}\n\treturn string(runes[start:end])\n}\n\n// StrLimit returns a portion of string `str` specified by `length` parameters, if the length\n// of `str` is greater than `length`, then the `suffix` will be appended to the result string.\n//\n// Example:\n// StrLimit(\"123456\", 3)      -> \"123...\"\n// StrLimit(\"123456\", 3, \"~\") -> \"123~\"\nfunc StrLimit(str string, length int, suffix ...string) string {\n\tif len(str) < length {\n\t\treturn str\n\t}\n\tsuffixStr := defaultSuffixForStrLimit\n\tif len(suffix) > 0 {\n\t\tsuffixStr = suffix[0]\n\t}\n\treturn str[0:length] + suffixStr\n}\n\n// StrLimitRune returns a portion of string `str` specified by `length` parameters, if the length\n// of `str` is greater than `length`, then the `suffix` will be appended to the result string.\n// StrLimitRune considers parameter `str` as unicode string.\n//\n// Example:\n// StrLimitRune(\"一起学习吧！\", 2)      -> \"一起...\"\n// StrLimitRune(\"一起学习吧！\", 2, \"~\") -> \"一起~\"\nfunc StrLimitRune(str string, length int, suffix ...string) string {\n\trunes := []rune(str)\n\tif len(runes) < length {\n\t\treturn str\n\t}\n\tsuffixStr := defaultSuffixForStrLimit\n\tif len(suffix) > 0 {\n\t\tsuffixStr = suffix[0]\n\t}\n\treturn string(runes[0:length]) + suffixStr\n}\n\n// SubStrFrom returns a portion of string `str` starting from first occurrence of and including `need`\n// to the end of `str`.\n//\n// Example:\n// SubStrFrom(\"av.mp4\", \".\") -> \".mp4\"\nfunc SubStrFrom(str string, need string) (substr string) {\n\tpos := Pos(str, need)\n\tif pos < 0 {\n\t\treturn \"\"\n\t}\n\treturn str[pos:]\n}\n\n// SubStrFromEx returns a portion of string `str` starting from first occurrence of and excluding `need`\n// to the end of `str`.\n//\n// Example:\n// SubStrFromEx(\"av.mp4\", \".\") -> \"mp4\"\nfunc SubStrFromEx(str string, need string) (substr string) {\n\tpos := Pos(str, need)\n\tif pos < 0 {\n\t\treturn \"\"\n\t}\n\treturn str[pos+len(need):]\n}\n\n// SubStrFromR returns a portion of string `str` starting from last occurrence of and including `need`\n// to the end of `str`.\n//\n// Example:\n// SubStrFromR(\"/dev/vda\", \"/\") -> \"/vda\"\nfunc SubStrFromR(str string, need string) (substr string) {\n\tpos := PosR(str, need)\n\tif pos < 0 {\n\t\treturn \"\"\n\t}\n\treturn str[pos:]\n}\n\n// SubStrFromREx returns a portion of string `str` starting from last occurrence of and excluding `need`\n// to the end of `str`.\n//\n// Example:\n// SubStrFromREx(\"/dev/vda\", \"/\") -> \"vda\"\nfunc SubStrFromREx(str string, need string) (substr string) {\n\tpos := PosR(str, need)\n\tif pos < 0 {\n\t\treturn \"\"\n\t}\n\treturn str[pos+len(need):]\n}\n"
  },
  {
    "path": "text/gstr/gstr_trim.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// Trim strips whitespace (or other characters) from the beginning and end of a string.\n// The optional parameter `characterMask` specifies the additional stripped characters.\nfunc Trim(str string, characterMask ...string) string {\n\treturn utils.Trim(str, characterMask...)\n}\n\n// TrimStr strips all the given `cut` string from the beginning and end of a string.\n// Note that it does not strip the whitespaces of its beginning or end.\nfunc TrimStr(str string, cut string, count ...int) string {\n\treturn TrimLeftStr(TrimRightStr(str, cut, count...), cut, count...)\n}\n\n// TrimLeft strips whitespace (or other characters) from the beginning of a string.\nfunc TrimLeft(str string, characterMask ...string) string {\n\ttrimChars := utils.DefaultTrimChars\n\tif len(characterMask) > 0 {\n\t\ttrimChars += characterMask[0]\n\t}\n\treturn strings.TrimLeft(str, trimChars)\n}\n\n// TrimLeftStr strips all the given `cut` string from the beginning of a string.\n// Note that it does not strip the whitespaces of its beginning.\nfunc TrimLeftStr(str string, cut string, count ...int) string {\n\tvar (\n\t\tlenCut   = len(cut)\n\t\tcutCount = 0\n\t)\n\tfor len(str) >= lenCut && str[0:lenCut] == cut {\n\t\tstr = str[lenCut:]\n\t\tcutCount++\n\t\tif len(count) > 0 && count[0] != -1 && cutCount >= count[0] {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn str\n}\n\n// TrimRight strips whitespace (or other characters) from the end of a string.\nfunc TrimRight(str string, characterMask ...string) string {\n\ttrimChars := utils.DefaultTrimChars\n\tif len(characterMask) > 0 {\n\t\ttrimChars += characterMask[0]\n\t}\n\treturn strings.TrimRight(str, trimChars)\n}\n\n// TrimRightStr strips all the given `cut` string from the end of a string.\n// Note that it does not strip the whitespaces of its end.\nfunc TrimRightStr(str string, cut string, count ...int) string {\n\tvar (\n\t\tlenStr   = len(str)\n\t\tlenCut   = len(cut)\n\t\tcutCount = 0\n\t)\n\tfor lenStr >= lenCut && str[lenStr-lenCut:lenStr] == cut {\n\t\tlenStr = lenStr - lenCut\n\t\tstr = str[:lenStr]\n\t\tcutCount++\n\t\tif len(count) > 0 && count[0] != -1 && cutCount >= count[0] {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn str\n}\n\n// TrimAll trims all characters in string `str`.\nfunc TrimAll(str string, characterMask ...string) string {\n\ttrimChars := utils.DefaultTrimChars\n\tif len(characterMask) > 0 {\n\t\ttrimChars += characterMask[0]\n\t}\n\tvar (\n\t\tfiltered bool\n\t\tslice    = make([]rune, 0, len(str))\n\t)\n\tfor _, char := range str {\n\t\tfiltered = false\n\t\tfor _, trimChar := range trimChars {\n\t\t\tif char == trimChar {\n\t\t\t\tfiltered = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !filtered {\n\t\t\tslice = append(slice, char)\n\t\t}\n\t}\n\treturn string(slice)\n}\n\n// HasPrefix tests whether the string s begins with prefix.\nfunc HasPrefix(s, prefix string) bool {\n\treturn strings.HasPrefix(s, prefix)\n}\n\n// HasSuffix tests whether the string s ends with suffix.\nfunc HasSuffix(s, suffix string) bool {\n\treturn strings.HasSuffix(s, suffix)\n}\n"
  },
  {
    "path": "text/gstr/gstr_upper_lower.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"strings\"\n\n\t\"golang.org/x/text/cases\"\n\t\"golang.org/x/text/language\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.\nfunc ToLower(s string) string {\n\treturn strings.ToLower(s)\n}\n\n// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.\nfunc ToUpper(s string) string {\n\treturn strings.ToUpper(s)\n}\n\n// UcFirst returns a copy of the string s with the first letter mapped to its upper case.\nfunc UcFirst(s string) string {\n\treturn utils.UcFirst(s)\n}\n\n// LcFirst returns a copy of the string s with the first letter mapped to its lower case.\nfunc LcFirst(s string) string {\n\tif len(s) == 0 {\n\t\treturn s\n\t}\n\tif IsLetterUpper(s[0]) {\n\t\treturn string(s[0]+32) + s[1:]\n\t}\n\treturn s\n}\n\n// UcWords uppercase the first character of each word in a string.\nfunc UcWords(str string) string {\n\treturn cases.Title(language.Und).String(str)\n}\n\n// IsLetterLower tests whether the given byte b is in lower case.\nfunc IsLetterLower(b byte) bool {\n\treturn utils.IsLetterLower(b)\n}\n\n// IsLetterUpper tests whether the given byte b is in upper case.\nfunc IsLetterUpper(b byte) bool {\n\treturn utils.IsLetterUpper(b)\n}\n"
  },
  {
    "path": "text/gstr/gstr_version.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// IsGNUVersion checks and returns whether given `version` is valid GNU version string.\nfunc IsGNUVersion(version string) bool {\n\tif version != \"\" && (version[0] == 'v' || version[0] == 'V') {\n\t\tversion = version[1:]\n\t}\n\tif version == \"\" {\n\t\treturn false\n\t}\n\tvar array = strings.Split(version, \".\")\n\tif len(array) > 3 {\n\t\treturn false\n\t}\n\tfor _, v := range array {\n\t\tif v == \"\" {\n\t\t\treturn false\n\t\t}\n\t\tif !IsNumeric(v) {\n\t\t\treturn false\n\t\t}\n\t\tif v[0] == '-' || v[0] == '+' {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// CompareVersion compares `a` and `b` as standard GNU version.\n//\n// It returns  1 if `a` > `b`.\n//\n// It returns -1 if `a` < `b`.\n//\n// It returns  0 if `a` = `b`.\n//\n// GNU standard version is like:\n// v1.0\n// 1\n// 1.0.0\n// v1.0.1\n// v2.10.8\n// 10.2.0\n// etc.\nfunc CompareVersion(a, b string) int {\n\tif a != \"\" && a[0] == 'v' {\n\t\ta = a[1:]\n\t}\n\tif b != \"\" && b[0] == 'v' {\n\t\tb = b[1:]\n\t}\n\tvar (\n\t\tarray1 = strings.Split(a, \".\")\n\t\tarray2 = strings.Split(b, \".\")\n\t\tdiff   int\n\t)\n\tdiff = len(array2) - len(array1)\n\tfor i := 0; i < diff; i++ {\n\t\tarray1 = append(array1, \"0\")\n\t}\n\tdiff = len(array1) - len(array2)\n\tfor i := 0; i < diff; i++ {\n\t\tarray2 = append(array2, \"0\")\n\t}\n\tv1 := 0\n\tv2 := 0\n\tfor i := 0; i < len(array1); i++ {\n\t\tv1 = gconv.Int(array1[i])\n\t\tv2 = gconv.Int(array2[i])\n\t\tif v1 > v2 {\n\t\t\treturn 1\n\t\t}\n\t\tif v1 < v2 {\n\t\t\treturn -1\n\t\t}\n\t}\n\treturn 0\n}\n\n// CompareVersionGo compares `a` and `b` as standard Golang version.\n//\n// It returns  1 if `a` > `b`.\n//\n// It returns -1 if `a` < `b`.\n//\n// It returns  0 if `a` = `b`.\n//\n// Golang standard version is like:\n// 1.0.0\n// v1.0.1\n// v2.10.8\n// 10.2.0\n// v0.0.0-20190626092158-b2ccc519800e\n// v1.12.2-0.20200413154443-b17e3a6804fa\n// v4.20.0+incompatible\n// etc.\n//\n// Docs: https://go.dev/doc/modules/version-numbers\nfunc CompareVersionGo(a, b string) int {\n\ta = Trim(a)\n\tb = Trim(b)\n\tif a != \"\" && a[0] == 'v' {\n\t\ta = a[1:]\n\t}\n\tif b != \"\" && b[0] == 'v' {\n\t\tb = b[1:]\n\t}\n\tvar (\n\t\trawA = a\n\t\trawB = b\n\t)\n\tif Count(a, \"-\") > 1 {\n\t\tif i := PosR(a, \"-\"); i > 0 {\n\t\t\ta = a[:i]\n\t\t}\n\t}\n\tif Count(b, \"-\") > 1 {\n\t\tif i := PosR(b, \"-\"); i > 0 {\n\t\t\tb = b[:i]\n\t\t}\n\t}\n\tif i := Pos(a, \"+\"); i > 0 {\n\t\ta = a[:i]\n\t}\n\tif i := Pos(b, \"+\"); i > 0 {\n\t\tb = b[:i]\n\t}\n\ta = Replace(a, \"-\", \".\")\n\tb = Replace(b, \"-\", \".\")\n\tvar (\n\t\tarray1 = strings.Split(a, \".\")\n\t\tarray2 = strings.Split(b, \".\")\n\t\tdiff   = len(array1) - len(array2)\n\t)\n\n\tfor i := diff; i < 0; i++ {\n\t\tarray1 = append(array1, \"0\")\n\t}\n\tfor i := 0; i < diff; i++ {\n\t\tarray2 = append(array2, \"0\")\n\t}\n\n\t// check Major.Minor.Patch first\n\tv1, v2 := 0, 0\n\tfor i := 0; i < len(array1); i++ {\n\t\tv1, v2 = gconv.Int(array1[i]), gconv.Int(array2[i])\n\t\t// Specially in Golang:\n\t\t// \"v1.12.2-0.20200413154443-b17e3a6804fa\" < \"v1.12.2\"\n\t\t// \"v1.12.3-0.20200413154443-b17e3a6804fa\" > \"v1.12.2\"\n\t\tif i == 4 && v1 != v2 && (v1 == 0 || v2 == 0) {\n\t\t\tif v1 > v2 {\n\t\t\t\treturn -1\n\t\t\t} else {\n\t\t\t\treturn 1\n\t\t\t}\n\t\t}\n\n\t\tif v1 > v2 {\n\t\t\treturn 1\n\t\t}\n\t\tif v1 < v2 {\n\t\t\treturn -1\n\t\t}\n\t}\n\n\t// Specially in Golang:\n\t// \"v4.20.1+incompatible\" < \"v4.20.1\"\n\tinA, inB := Contains(rawA, \"+incompatible\"), Contains(rawB, \"+incompatible\")\n\tif inA && !inB {\n\t\treturn -1\n\t}\n\tif !inA && inB {\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr_test\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc ExampleCount() {\n\tvar (\n\t\tstr     = `goframe is very, very easy to use`\n\t\tsubstr1 = \"goframe\"\n\t\tsubstr2 = \"very\"\n\t\tresult1 = gstr.Count(str, substr1)\n\t\tresult2 = gstr.Count(str, substr2)\n\t)\n\tfmt.Println(result1)\n\tfmt.Println(result2)\n\n\t// Output:\n\t// 1\n\t// 2\n}\n\nfunc ExampleCountI() {\n\tvar (\n\t\tstr     = `goframe is very, very easy to use`\n\t\tsubstr1 = \"GOFRAME\"\n\t\tsubstr2 = \"VERY\"\n\t\tresult1 = gstr.CountI(str, substr1)\n\t\tresult2 = gstr.CountI(str, substr2)\n\t)\n\tfmt.Println(result1)\n\tfmt.Println(result2)\n\n\t// Output:\n\t// 1\n\t// 2\n}\n\nfunc ExampleToLower() {\n\tvar (\n\t\ts      = `GOFRAME`\n\t\tresult = gstr.ToLower(s)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe\n}\n\nfunc ExampleToUpper() {\n\tvar (\n\t\ts      = `goframe`\n\t\tresult = gstr.ToUpper(s)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// GOFRAME\n}\n\nfunc ExampleUcFirst() {\n\tvar (\n\t\ts      = `hello`\n\t\tresult = gstr.UcFirst(s)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello\n}\n\nfunc ExampleLcFirst() {\n\tvar (\n\t\tstr    = `Goframe`\n\t\tresult = gstr.LcFirst(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe\n}\n\nfunc ExampleUcWords() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.UcWords(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello World\n}\n\nfunc ExampleIsLetterLower() {\n\tfmt.Println(gstr.IsLetterLower('a'))\n\tfmt.Println(gstr.IsLetterLower('A'))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIsLetterUpper() {\n\tfmt.Println(gstr.IsLetterUpper('A'))\n\tfmt.Println(gstr.IsLetterUpper('a'))\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleIsNumeric() {\n\tfmt.Println(gstr.IsNumeric(\"88\"))\n\tfmt.Println(gstr.IsNumeric(\"3.1415926\"))\n\tfmt.Println(gstr.IsNumeric(\"abc\"))\n\t// Output:\n\t// true\n\t// true\n\t// false\n}\n\nfunc ExampleReverse() {\n\tvar (\n\t\tstr    = `123456`\n\t\tresult = gstr.Reverse(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 654321\n}\n\nfunc ExampleNumberFormat() {\n\tvar (\n\t\tnumber       float64 = 123456\n\t\tdecimals             = 2\n\t\tdecPoint             = \".\"\n\t\tthousandsSep         = \",\"\n\t\tresult               = gstr.NumberFormat(number, decimals, decPoint, thousandsSep)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 123,456.00\n}\n\nfunc ExampleChunkSplit() {\n\tvar (\n\t\tbody     = `1234567890`\n\t\tchunkLen = 2\n\t\tend      = \"#\"\n\t\tresult   = gstr.ChunkSplit(body, chunkLen, end)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 12#34#56#78#90#\n}\n\nfunc ExampleCompare() {\n\tfmt.Println(gstr.Compare(\"c\", \"c\"))\n\tfmt.Println(gstr.Compare(\"a\", \"b\"))\n\tfmt.Println(gstr.Compare(\"c\", \"b\"))\n\n\t// Output:\n\t// 0\n\t// -1\n\t// 1\n}\n\nfunc ExampleEqual() {\n\tfmt.Println(gstr.Equal(`A`, `a`))\n\tfmt.Println(gstr.Equal(`A`, `A`))\n\tfmt.Println(gstr.Equal(`A`, `B`))\n\n\t// Output:\n\t// true\n\t// true\n\t// false\n}\n\nfunc ExampleFields() {\n\tvar (\n\t\tstr    = `Hello World`\n\t\tresult = gstr.Fields(str)\n\t)\n\tfmt.Printf(`%#v`, result)\n\n\t// Output:\n\t// []string{\"Hello\", \"World\"}\n}\n\nfunc ExampleHasPrefix() {\n\tvar (\n\t\ts      = `Hello World`\n\t\tprefix = \"Hello\"\n\t\tresult = gstr.HasPrefix(s, prefix)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleHasSuffix() {\n\tvar (\n\t\ts      = `my best love is goframe`\n\t\tprefix = \"goframe\"\n\t\tresult = gstr.HasSuffix(s, prefix)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// true\n}\n\nfunc ExampleCountWords() {\n\tvar (\n\t\tstr    = `goframe is very, very easy to use!`\n\t\tresult = gstr.CountWords(str)\n\t)\n\tfmt.Printf(`%#v`, result)\n\n\t// Output:\n\t// map[string]int{\"easy\":1, \"goframe\":1, \"is\":1, \"to\":1, \"use!\":1, \"very\":1, \"very,\":1}\n}\n\nfunc ExampleCountChars() {\n\tvar (\n\t\tstr    = `goframe`\n\t\tresult = gstr.CountChars(str)\n\t)\n\tfmt.Println(result)\n\n\t// May Output:\n\t// map[a:1 e:1 f:1 g:1 m:1 o:1 r:1]\n}\n\nfunc ExampleWordWrap() {\n\t{\n\t\tvar (\n\t\t\tstr    = `A very long woooooooooooooooooord. and something`\n\t\t\twidth  = 8\n\t\t\tbr     = \"\\n\"\n\t\t\tresult = gstr.WordWrap(str, width, br)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr    = `The quick brown fox jumped over the lazy dog.`\n\t\t\twidth  = 20\n\t\t\tbr     = \"<br />\\n\"\n\t\t\tresult = gstr.WordWrap(str, width, br)\n\t\t)\n\t\tfmt.Printf(\"%v\", result)\n\t}\n\n\t// Output:\n\t// A very\n\t// long\n\t// woooooooooooooooooord.\n\t// and\n\t// something\n\t// The quick brown fox<br />\n\t// jumped over the lazy<br />\n\t// dog.\n}\n\nfunc ExampleLenRune() {\n\tvar (\n\t\tstr    = `GoFrame框架`\n\t\tresult = gstr.LenRune(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 9\n}\n\nfunc ExampleRepeat() {\n\tvar (\n\t\tinput      = `goframe `\n\t\tmultiplier = 3\n\t\tresult     = gstr.Repeat(input, multiplier)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe goframe goframe\n}\n\nfunc ExampleShuffle() {\n\tvar (\n\t\tstr    = `123456`\n\t\tresult = gstr.Shuffle(str)\n\t)\n\tfmt.Println(result)\n\n\t// May Output:\n\t// 563214\n}\n\nfunc ExampleSplit() {\n\tvar (\n\t\tstr       = `a|b|c|d`\n\t\tdelimiter = `|`\n\t\tresult    = gstr.Split(str, delimiter)\n\t)\n\tfmt.Printf(`%#v`, result)\n\n\t// Output:\n\t// []string{\"a\", \"b\", \"c\", \"d\"}\n}\n\nfunc ExampleSplitAndTrim() {\n\tvar (\n\t\tstr       = `a|b|||||c|d`\n\t\tdelimiter = `|`\n\t\tresult    = gstr.SplitAndTrim(str, delimiter)\n\t)\n\tfmt.Printf(`%#v`, result)\n\n\t// Output:\n\t// []string{\"a\", \"b\", \"c\", \"d\"}\n}\n\nfunc ExampleJoin() {\n\tvar (\n\t\tarray  = []string{\"goframe\", \"is\", \"very\", \"easy\", \"to\", \"use\"}\n\t\tsep    = ` `\n\t\tresult = gstr.Join(array, sep)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very easy to use\n}\n\nfunc ExampleJoinAny() {\n\tvar (\n\t\tsep    = `,`\n\t\tarr2   = []int{99, 73, 85, 66}\n\t\tresult = gstr.JoinAny(arr2, sep)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 99,73,85,66\n}\n\nfunc ExampleExplode() {\n\tvar (\n\t\tstr       = `Hello World`\n\t\tdelimiter = \" \"\n\t\tresult    = gstr.Explode(delimiter, str)\n\t)\n\tfmt.Printf(`%#v`, result)\n\n\t// Output:\n\t// []string{\"Hello\", \"World\"}\n}\n\nfunc ExampleImplode() {\n\tvar (\n\t\tpieces = []string{\"goframe\", \"is\", \"very\", \"easy\", \"to\", \"use\"}\n\t\tglue   = \" \"\n\t\tresult = gstr.Implode(glue, pieces)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very easy to use\n}\n\nfunc ExampleChr() {\n\tvar (\n\t\tascii  = 65 // A\n\t\tresult = gstr.Chr(ascii)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// A\n}\n\n// '103' is the 'g' in ASCII\nfunc ExampleOrd() {\n\tvar (\n\t\tstr    = `goframe`\n\t\tresult = gstr.Ord(str)\n\t)\n\n\tfmt.Println(result)\n\n\t// Output:\n\t// 103\n}\n\nfunc ExampleHideStr() {\n\tvar (\n\t\tstr     = `13800138000`\n\t\tpercent = 40\n\t\thide    = `*`\n\t\tresult  = gstr.HideStr(str, percent, hide)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 138****8000\n}\n\nfunc ExampleNl2Br() {\n\tvar (\n\t\tstr = `goframe\nis\nvery\neasy\nto\nuse`\n\t\tresult = gstr.Nl2Br(str)\n\t)\n\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe<br>is<br>very<br>easy<br>to<br>use\n}\n\nfunc ExampleAddSlashes() {\n\tvar (\n\t\tstr    = `'aa'\"bb\"cc\\r\\n\\d\\t`\n\t\tresult = gstr.AddSlashes(str)\n\t)\n\n\tfmt.Println(result)\n\n\t// Output:\n\t// \\'aa\\'\\\"bb\\\"cc\\\\r\\\\n\\\\d\\\\t\n}\n\nfunc ExampleStripSlashes() {\n\tvar (\n\t\tstr    = `C:\\\\windows\\\\GoFrame\\\\test`\n\t\tresult = gstr.StripSlashes(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// C:\\windows\\GoFrame\\test\n}\n\nfunc ExampleQuoteMeta() {\n\t{\n\t\tvar (\n\t\t\tstr    = `.\\+?[^]()`\n\t\t\tresult = gstr.QuoteMeta(str)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr    = `https://goframe.org/pages/viewpage.action?pageId=1114327`\n\t\t\tresult = gstr.QuoteMeta(str)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// \\.\\\\\\+\\?\\[\\^\\]\\(\\)\n\t// https://goframe\\.org/pages/viewpage\\.action\\?pageId=1114327\n\n}\n\n// array\nfunc ExampleSearchArray() {\n\tvar (\n\t\tarray  = []string{\"goframe\", \"is\", \"very\", \"nice\"}\n\t\tstr    = `goframe`\n\t\tresult = gstr.SearchArray(array, str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 0\n}\n\nfunc ExampleInArray() {\n\tvar (\n\t\ta      = []string{\"goframe\", \"is\", \"very\", \"easy\", \"to\", \"use\"}\n\t\ts      = \"goframe\"\n\t\tresult = gstr.InArray(a, s)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// true\n}\n\nfunc ExamplePrefixArray() {\n\tvar (\n\t\tstrArray = []string{\"tom\", \"lily\", \"john\"}\n\t)\n\n\tgstr.PrefixArray(strArray, \"classA_\")\n\n\tfmt.Println(strArray)\n\n\t// Output:\n\t// [classA_tom classA_lily classA_john]\n}\n\n// case\nfunc ExampleCaseCamel() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseCamel(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// HelloWorld\n}\n\nfunc ExampleCaseCamelLower() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseCamelLower(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// helloWorld\n}\n\nfunc ExampleCaseSnake() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseSnake(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// hello_world\n}\n\nfunc ExampleCaseSnakeScreaming() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseSnakeScreaming(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// HELLO_WORLD\n}\n\nfunc ExampleCaseSnakeFirstUpper() {\n\tvar (\n\t\tstr    = `RGBCodeMd5`\n\t\tresult = gstr.CaseSnakeFirstUpper(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// rgb_code_md5\n}\n\nfunc ExampleCaseKebab() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseKebab(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// hello-world\n}\n\nfunc ExampleCaseKebabScreaming() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tresult = gstr.CaseKebabScreaming(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// HELLO-WORLD\n}\n\nfunc ExampleCaseDelimited() {\n\tvar (\n\t\tstr    = `hello world`\n\t\tdel    = byte('-')\n\t\tresult = gstr.CaseDelimited(str, del)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// hello-world\n}\n\nfunc ExampleCaseDelimitedScreaming() {\n\t{\n\t\tvar (\n\t\t\tstr    = `hello world`\n\t\t\tdel    = byte('-')\n\t\t\tresult = gstr.CaseDelimitedScreaming(str, del, true)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr    = `hello world`\n\t\t\tdel    = byte('-')\n\t\t\tresult = gstr.CaseDelimitedScreaming(str, del, false)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// HELLO-WORLD\n\t// hello-world\n}\n\n// contain\nfunc ExampleContains() {\n\t{\n\t\tvar (\n\t\t\tstr    = `Hello World`\n\t\t\tsubstr = `Hello`\n\t\t\tresult = gstr.Contains(str, substr)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr    = `Hello World`\n\t\t\tsubstr = `hello`\n\t\t\tresult = gstr.Contains(str, substr)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// true\n\t// false\n}\n\nfunc ExampleContainsI() {\n\tvar (\n\t\tstr     = `Hello World`\n\t\tsubstr  = \"hello\"\n\t\tresult1 = gstr.Contains(str, substr)\n\t\tresult2 = gstr.ContainsI(str, substr)\n\t)\n\tfmt.Println(result1)\n\tfmt.Println(result2)\n\n\t// Output:\n\t// false\n\t// true\n}\n\nfunc ExampleContainsAny() {\n\t{\n\t\tvar (\n\t\t\ts      = `goframe`\n\t\t\tchars  = \"g\"\n\t\t\tresult = gstr.ContainsAny(s, chars)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\ts      = `goframe`\n\t\t\tchars  = \"G\"\n\t\t\tresult = gstr.ContainsAny(s, chars)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// true\n\t// false\n}\n\n// convert\nfunc ExampleOctStr() {\n\tvar (\n\t\tstr    = `\\346\\200\\241`\n\t\tresult = gstr.OctStr(str)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 怡\n}\n\n// domain\nfunc ExampleIsSubDomain() {\n\tvar (\n\t\tsubDomain  = `s.goframe.org`\n\t\tmainDomain = `goframe.org`\n\t\tresult     = gstr.IsSubDomain(subDomain, mainDomain)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// true\n}\n\n// levenshtein\nfunc ExampleLevenshtein() {\n\tvar (\n\t\tstr1    = \"Hello World\"\n\t\tstr2    = \"hallo World\"\n\t\tcostIns = 1\n\t\tcostRep = 1\n\t\tcostDel = 1\n\t\tresult  = gstr.Levenshtein(str1, str2, costIns, costRep, costDel)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 2\n}\n\n// parse\nfunc ExampleParse() {\n\t{\n\t\tvar (\n\t\t\tstr       = `v1=m&v2=n`\n\t\t\tresult, _ = gstr.Parse(str)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr       = `v[a][a]=m&v[a][b]=n`\n\t\t\tresult, _ = gstr.Parse(str)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\t// The form of nested Slice is not yet supported.\n\t\tvar str = `v[][]=m&v[][]=n`\n\t\tresult, err := gstr.Parse(str)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\t// This will produce an error.\n\t\tvar str = `v=m&v[a]=n`\n\t\tresult, err := gstr.Parse(str)\n\t\tif err != nil {\n\t\t\tprintln(err)\n\t\t}\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\tstr       = `a .[[b=c`\n\t\t\tresult, _ = gstr.Parse(str)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// May Output:\n\t// map[v1:m v2:n]\n\t// map[v:map[a:map[a:m b:n]]]\n\t// map[v:map[]]\n\t// Error: expected type 'map[string]any' for key 'v', but got 'string'\n\t// map[]\n\t// map[a___[b:c]\n}\n\n// pos\nfunc ExamplePos() {\n\tvar (\n\t\thaystack = `Hello World`\n\t\tneedle   = `World`\n\t\tresult   = gstr.Pos(haystack, needle)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 6\n}\n\nfunc ExamplePosRune() {\n\tvar (\n\t\thaystack = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架`\n\t\tneedle   = `Go`\n\t\tposI     = gstr.PosRune(haystack, needle)\n\t\tposR     = gstr.PosRRune(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 0\n\t// 22\n}\n\nfunc ExamplePosI() {\n\tvar (\n\t\thaystack = `goframe is very, very easy to use`\n\t\tneedle   = `very`\n\t\tposI     = gstr.PosI(haystack, needle)\n\t\tposR     = gstr.PosR(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 11\n\t// 17\n}\n\nfunc ExamplePosIRune() {\n\t{\n\t\tvar (\n\t\t\thaystack    = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架`\n\t\t\tneedle      = `高性能`\n\t\t\tstartOffset = 10\n\t\t\tresult      = gstr.PosIRune(haystack, needle, startOffset)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\thaystack    = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架`\n\t\t\tneedle      = `高性能`\n\t\t\tstartOffset = 30\n\t\t\tresult      = gstr.PosIRune(haystack, needle, startOffset)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// 14\n\t// -1\n}\n\nfunc ExamplePosR() {\n\tvar (\n\t\thaystack = `goframe is very, very easy to use`\n\t\tneedle   = `very`\n\t\tposI     = gstr.PosI(haystack, needle)\n\t\tposR     = gstr.PosR(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 11\n\t// 17\n}\n\nfunc ExamplePosRRune() {\n\tvar (\n\t\thaystack = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架`\n\t\tneedle   = `Go`\n\t\tposI     = gstr.PosIRune(haystack, needle)\n\t\tposR     = gstr.PosRRune(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 0\n\t// 22\n}\n\nfunc ExamplePosRI() {\n\tvar (\n\t\thaystack = `goframe is very, very easy to use`\n\t\tneedle   = `VERY`\n\t\tposI     = gstr.PosI(haystack, needle)\n\t\tposR     = gstr.PosRI(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 11\n\t// 17\n}\n\nfunc ExamplePosRIRune() {\n\tvar (\n\t\thaystack = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架`\n\t\tneedle   = `GO`\n\t\tposI     = gstr.PosIRune(haystack, needle)\n\t\tposR     = gstr.PosRIRune(haystack, needle)\n\t)\n\tfmt.Println(posI)\n\tfmt.Println(posR)\n\n\t// Output:\n\t// 0\n\t// 22\n}\n\n// replace\nfunc ExampleReplace() {\n\tvar (\n\t\torigin  = `golang is very nice!`\n\t\tsearch  = `golang`\n\t\treplace = `goframe`\n\t\tresult  = gstr.Replace(origin, search, replace)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very nice!\n}\n\nfunc ExampleReplaceI() {\n\tvar (\n\t\torigin  = `golang is very nice!`\n\t\tsearch  = `GOLANG`\n\t\treplace = `goframe`\n\t\tresult  = gstr.ReplaceI(origin, search, replace)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very nice!\n}\n\nfunc ExampleReplaceByArray() {\n\t{\n\t\tvar (\n\t\t\torigin = `golang is very nice`\n\t\t\tarray  = []string{\"lang\", \"frame\"}\n\t\t\tresult = gstr.ReplaceByArray(origin, array)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\torigin = `golang is very good`\n\t\t\tarray  = []string{\"golang\", \"goframe\", \"good\", \"nice\"}\n\t\t\tresult = gstr.ReplaceByArray(origin, array)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// goframe is very nice\n\t// goframe is very nice\n}\n\nfunc ExampleReplaceIByArray() {\n\tvar (\n\t\torigin = `golang is very Good`\n\t\tarray  = []string{\"Golang\", \"goframe\", \"GOOD\", \"nice\"}\n\t\tresult = gstr.ReplaceIByArray(origin, array)\n\t)\n\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very nice\n}\n\nfunc ExampleReplaceByMap() {\n\t{\n\t\tvar (\n\t\t\torigin   = `golang is very nice`\n\t\t\treplaces = map[string]string{\n\t\t\t\t\"lang\": \"frame\",\n\t\t\t}\n\t\t\tresult = gstr.ReplaceByMap(origin, replaces)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\t{\n\t\tvar (\n\t\t\torigin   = `golang is very good`\n\t\t\treplaces = map[string]string{\n\t\t\t\t\"golang\": \"goframe\",\n\t\t\t\t\"good\":   \"nice\",\n\t\t\t}\n\t\t\tresult = gstr.ReplaceByMap(origin, replaces)\n\t\t)\n\t\tfmt.Println(result)\n\t}\n\n\t// Output:\n\t// goframe is very nice\n\t// goframe is very nice\n}\n\nfunc ExampleReplaceIByMap() {\n\tvar (\n\t\torigin   = `golang is very nice`\n\t\treplaces = map[string]string{\n\t\t\t\"Lang\": \"frame\",\n\t\t}\n\t\tresult = gstr.ReplaceIByMap(origin, replaces)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// goframe is very nice\n}\n\nfunc ExampleReplaceFunc() {\n\tstr := \"hello gf 2018~2020!\"\n\t// Replace \"gf\" with a custom function that returns \"GoFrame\"\n\tresult := gstr.ReplaceFunc(str, \"gf\", func(s string) string {\n\t\treturn \"GoFrame\"\n\t})\n\tfmt.Println(result)\n\n\t// Replace numbers with their doubled values\n\tresult = gstr.ReplaceFunc(\"1 2 3\", \"2\", func(s string) string {\n\t\tn, _ := strconv.Atoi(s)\n\t\treturn strconv.Itoa(n * 2)\n\t})\n\tfmt.Println(result)\n\n\t// Output:\n\t// hello GoFrame 2018~2020!\n\t// 1 4 3\n}\n\nfunc ExampleReplaceIFunc() {\n\tstr := \"Hello GF, hello gf, HELLO Gf!\"\n\t// Replace any case variation of \"gf\" with \"GoFrame\"\n\tresult := gstr.ReplaceIFunc(str, \"gf\", func(s string) string {\n\t\treturn \"GoFrame\"\n\t})\n\tfmt.Println(result)\n\n\t// Preserve the original case of each match\n\tresult = gstr.ReplaceIFunc(str, \"gf\", func(s string) string {\n\t\tif s == strings.ToUpper(s) {\n\t\t\treturn \"GOFRAME\"\n\t\t}\n\t\tif s == strings.ToLower(s) {\n\t\t\treturn \"goframe\"\n\t\t}\n\t\treturn \"GoFrame\"\n\t})\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello GoFrame, hello GoFrame, HELLO GoFrame!\n\t// Hello GOFRAME, hello goframe, HELLO GoFrame!\n}\n\n// similartext\nfunc ExampleSimilarText() {\n\tvar (\n\t\tfirst   = `AaBbCcDd`\n\t\tsecond  = `ad`\n\t\tpercent = 0.80\n\t\tresult  = gstr.SimilarText(first, second, &percent)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 2\n}\n\n// soundex\nfunc ExampleSoundex() {\n\tvar (\n\t\tstr1    = `Hello`\n\t\tstr2    = `Hallo`\n\t\tresult1 = gstr.Soundex(str1)\n\t\tresult2 = gstr.Soundex(str2)\n\t)\n\tfmt.Println(result1, result2)\n\n\t// Output:\n\t// H400 H400\n}\n\n// str\nfunc ExampleStr() {\n\tvar (\n\t\thaystack = `xxx.jpg`\n\t\tneedle   = `.`\n\t\tresult   = gstr.Str(haystack, needle)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// .jpg\n}\n\nfunc ExampleStrEx() {\n\tvar (\n\t\thaystack = `https://goframe.org/index.html?a=1&b=2`\n\t\tneedle   = `?`\n\t\tresult   = gstr.StrEx(haystack, needle)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// a=1&b=2\n}\n\nfunc ExampleStrTill() {\n\tvar (\n\t\thaystack = `https://goframe.org/index.html?test=123456`\n\t\tneedle   = `?`\n\t\tresult   = gstr.StrTill(haystack, needle)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// https://goframe.org/index.html?\n}\n\nfunc ExampleStrTillEx() {\n\tvar (\n\t\thaystack = `https://goframe.org/index.html?test=123456`\n\t\tneedle   = `?`\n\t\tresult   = gstr.StrTillEx(haystack, needle)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// https://goframe.org/index.html\n}\n\n// substr\nfunc ExampleSubStr() {\n\tvar (\n\t\tstr    = `1234567890`\n\t\tstart  = 0\n\t\tlength = 4\n\t\tsubStr = gstr.SubStr(str, start, length)\n\t)\n\tfmt.Println(subStr)\n\n\t// Output:\n\t// 1234\n}\n\nfunc ExampleSubStrRune() {\n\tvar (\n\t\tstr    = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架。`\n\t\tstart  = 14\n\t\tlength = 3\n\t\tsubStr = gstr.SubStrRune(str, start, length)\n\t)\n\tfmt.Println(subStr)\n\n\t// Output:\n\t// 高性能\n}\n\nfunc ExampleStrLimit() {\n\tvar (\n\t\tstr    = `123456789`\n\t\tlength = 3\n\t\tsuffix = `...`\n\t\tresult = gstr.StrLimit(str, length, suffix)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// 123...\n}\n\nfunc ExampleStrLimitRune() {\n\tvar (\n\t\tstr    = `GoFrame是一款模块化、高性能、企业级的Go基础开发框架。`\n\t\tlength = 17\n\t\tsuffix = \"...\"\n\t\tresult = gstr.StrLimitRune(str, length, suffix)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// GoFrame是一款模块化、高性能...\n}\n\nfunc ExampleSubStrFrom() {\n\tvar (\n\t\tstr  = \"我爱GoFrameGood\"\n\t\tneed = `爱`\n\t)\n\n\tfmt.Println(gstr.SubStrFrom(str, need))\n\n\t// Output:\n\t// 爱GoFrameGood\n}\n\nfunc ExampleSubStrFromEx() {\n\tvar (\n\t\tstr  = \"我爱GoFrameGood\"\n\t\tneed = `爱`\n\t)\n\n\tfmt.Println(gstr.SubStrFromEx(str, need))\n\n\t// Output:\n\t// GoFrameGood\n}\n\nfunc ExampleSubStrFromR() {\n\tvar (\n\t\tstr  = \"我爱GoFrameGood\"\n\t\tneed = `Go`\n\t)\n\n\tfmt.Println(gstr.SubStrFromR(str, need))\n\n\t// Output:\n\t// Good\n}\n\nfunc ExampleSubStrFromREx() {\n\tvar (\n\t\tstr  = \"我爱GoFrameGood\"\n\t\tneed = `Go`\n\t)\n\n\tfmt.Println(gstr.SubStrFromREx(str, need))\n\n\t// Output:\n\t// od\n}\n\n// trim\nfunc ExampleTrim() {\n\tvar (\n\t\tstr           = `*Hello World*`\n\t\tcharacterMask = \"*\"\n\t\tresult        = gstr.Trim(str, characterMask)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello World\n}\n\nfunc ExampleTrimStr() {\n\tvar (\n\t\tstr    = `Hello World`\n\t\tcut    = \"World\"\n\t\tcount  = -1\n\t\tresult = gstr.TrimStr(str, cut, count)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello\n}\n\nfunc ExampleTrimLeft() {\n\tvar (\n\t\tstr           = `*Hello World*`\n\t\tcharacterMask = \"*\"\n\t\tresult        = gstr.TrimLeft(str, characterMask)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello World*\n}\n\nfunc ExampleTrimLeftStr() {\n\tvar (\n\t\tstr    = `**Hello World**`\n\t\tcut    = \"*\"\n\t\tcount  = 1\n\t\tresult = gstr.TrimLeftStr(str, cut, count)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// *Hello World**\n}\n\nfunc ExampleTrimRight() {\n\tvar (\n\t\tstr           = `**Hello World**`\n\t\tcharacterMask = \"*def\" // []byte{\"*\", \"d\", \"e\", \"f\"}\n\t\tresult        = gstr.TrimRight(str, characterMask)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// **Hello Worl\n}\n\nfunc ExampleTrimRightStr() {\n\tvar (\n\t\tstr    = `Hello World!`\n\t\tcut    = \"!\"\n\t\tcount  = -1\n\t\tresult = gstr.TrimRightStr(str, cut, count)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// Hello World\n}\n\nfunc ExampleTrimAll() {\n\tvar (\n\t\tstr           = `*Hello World*`\n\t\tcharacterMask = \"*\"\n\t\tresult        = gstr.TrimAll(str, characterMask)\n\t)\n\tfmt.Println(result)\n\n\t// Output:\n\t// HelloWorld\n}\n\n// version\nfunc ExampleCompareVersion() {\n\tfmt.Println(gstr.CompareVersion(\"v2.11.9\", \"v2.10.8\"))\n\tfmt.Println(gstr.CompareVersion(\"1.10.8\", \"1.19.7\"))\n\tfmt.Println(gstr.CompareVersion(\"2.8.beta\", \"2.8\"))\n\n\t// Output:\n\t// 1\n\t// -1\n\t// 0\n}\n\nfunc ExampleCompareVersionGo() {\n\tfmt.Println(gstr.CompareVersionGo(\"v2.11.9\", \"v2.10.8\"))\n\tfmt.Println(gstr.CompareVersionGo(\"v4.20.1\", \"v4.20.1+incompatible\"))\n\tfmt.Println(gstr.CompareVersionGo(\n\t\t\"v0.0.2-20180626092158-b2ccc119800e\",\n\t\t\"v1.0.1-20190626092158-b2ccc519800e\",\n\t))\n\n\t// Output:\n\t// 1\n\t// 1\n\t// -1\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_array_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_SearchArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := g.SliceStr{\"a\", \"b\", \"c\"}\n\t\tt.AssertEQ(gstr.SearchArray(a, \"a\"), 0)\n\t\tt.AssertEQ(gstr.SearchArray(a, \"b\"), 1)\n\t\tt.AssertEQ(gstr.SearchArray(a, \"c\"), 2)\n\t\tt.AssertEQ(gstr.SearchArray(a, \"d\"), -1)\n\t})\n}\n\nfunc Test_InArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := g.SliceStr{\"a\", \"b\", \"c\"}\n\t\tt.AssertEQ(gstr.InArray(a, \"a\"), true)\n\t\tt.AssertEQ(gstr.InArray(a, \"b\"), true)\n\t\tt.AssertEQ(gstr.InArray(a, \"c\"), true)\n\t\tt.AssertEQ(gstr.InArray(a, \"d\"), false)\n\t})\n}\n\nfunc Test_PrefixArray(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := g.SliceStr{\"a\", \"b\", \"c\"}\n\t\tgstr.PrefixArray(a, \"1-\")\n\t\tt.AssertEQ(a, g.SliceStr{\"1-a\", \"1-b\", \"1-c\"})\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_case_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_CaseCamel(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"test_case\", \"TestCase\"},\n\t\t{\"test\", \"Test\"},\n\t\t{\"TestCase\", \"TestCase\"},\n\t\t{\"testCase\", \"TestCase\"},\n\t\t{\" test  case \", \"TestCase\"},\n\t\t{\"userLogin_log.bak\", \"UserLoginLogBak\"},\n\t\t{\"\", \"\"},\n\t\t{\"many_many_words\", \"ManyManyWords\"},\n\t\t{\"AnyKind of_string\", \"AnyKindOfString\"},\n\t\t{\"odd-fix\", \"OddFix\"},\n\t\t{\"numbers2And55with000\", \"Numbers2And55With000\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseCamel(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseCamelLower(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"foo-bar\", \"fooBar\"},\n\t\t{\"TestCase\", \"testCase\"},\n\t\t{\"\", \"\"},\n\t\t{\"AnyKind of_string\", \"anyKindOfString\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseCamelLower(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseSnake(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"test_case\"},\n\t\t{\"TestCase\", \"test_case\"},\n\t\t{\"Test Case\", \"test_case\"},\n\t\t{\" Test Case\", \"test_case\"},\n\t\t{\"Test Case \", \"test_case\"},\n\t\t{\" Test Case \", \"test_case\"},\n\t\t{\"test\", \"test\"},\n\t\t{\"test_case\", \"test_case\"},\n\t\t{\"Test\", \"test\"},\n\t\t{\"\", \"\"},\n\t\t{\"ManyManyWords\", \"many_many_words\"},\n\t\t{\"manyManyWords\", \"many_many_words\"},\n\t\t{\"AnyKind of_string\", \"any_kind_of_string\"},\n\t\t{\"numbers2and55with000\", \"numbers_2_and_55_with_000\"},\n\t\t{\"JSONData\", \"json_data\"},\n\t\t{\"userID\", \"user_id\"},\n\t\t{\"AAAbbb\", \"aa_abbb\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseSnake(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + in + \"'('\" + result + \"' != '\" + out + \"')\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseDelimited(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"test@case\"},\n\t\t{\"TestCase\", \"test@case\"},\n\t\t{\"Test Case\", \"test@case\"},\n\t\t{\" Test Case\", \"test@case\"},\n\t\t{\"Test Case \", \"test@case\"},\n\t\t{\" Test Case \", \"test@case\"},\n\t\t{\"test\", \"test\"},\n\t\t{\"test_case\", \"test@case\"},\n\t\t{\"Test\", \"test\"},\n\t\t{\"\", \"\"},\n\t\t{\"ManyManyWords\", \"many@many@words\"},\n\t\t{\"manyManyWords\", \"many@many@words\"},\n\t\t{\"AnyKind of_string\", \"any@kind@of@string\"},\n\t\t{\"numbers2and55with000\", \"numbers@2@and@55@with@000\"},\n\t\t{\"JSONData\", \"json@data\"},\n\t\t{\"userID\", \"user@id\"},\n\t\t{\"AAAbbb\", \"aa@abbb\"},\n\t\t{\"test-case\", \"test@case\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseDelimited(in, '@')\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + in + \"' ('\" + result + \"' != '\" + out + \"')\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseSnakeScreaming(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"TEST_CASE\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseSnakeScreaming(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseKebab(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"test-case\"},\n\t\t{\"optimization1.0.0\", \"optimization-1-0-0\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseKebab(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseKebabScreaming(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"TEST-CASE\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseKebabScreaming(in)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseDelimitedScreaming(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"testCase\", \"TEST.CASE\"},\n\t}\n\tfor _, i := range cases {\n\t\tin := i[0]\n\t\tout := i[1]\n\t\tresult := gstr.CaseDelimitedScreaming(in, '.', true)\n\t\tif result != out {\n\t\t\tt.Error(\"'\" + result + \"' != '\" + out + \"'\")\n\t\t}\n\t}\n}\n\nfunc Test_CaseSnakeFirstUpper(t *testing.T) {\n\tcases := [][]string{\n\t\t{\"RGBCodeMd5\", \"rgb_code_md5\"},\n\t\t{\"testCase\", \"test_case\"},\n\t\t{\"Md5\", \"md5\"},\n\t\t{\"userID\", \"user_id\"},\n\t\t{\"RGB\", \"rgb\"},\n\t\t{\"RGBCode\", \"rgb_code\"},\n\t\t{\"_ID\", \"id\"},\n\t\t{\"User_ID\", \"user_id\"},\n\t\t{\"user_id\", \"user_id\"},\n\t\t{\"md5\", \"md5\"},\n\t\t{\"Numbers2And55With000\", \"numbers2_and55_with000\"},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, item := range cases {\n\t\t\tt.Assert(gstr.CaseSnakeFirstUpper(item[0]), item[1])\n\t\t}\n\n\t\tt.Assert(gstr.CaseSnakeFirstUpper(\"RGBCodeMd5\", \".\"), \"rgb.code.md5\")\n\t})\n\n}\nfunc Test_CaseTypeMatch(t *testing.T) {\n\tcaseTypes := []gstr.CaseType{\n\t\tgstr.Camel,\n\t\tgstr.CamelLower,\n\t\tgstr.Snake,\n\t\tgstr.SnakeFirstUpper,\n\t\tgstr.SnakeScreaming,\n\t\tgstr.Kebab,\n\t\tgstr.KebabScreaming,\n\t\tgstr.Lower,\n\t\t\"test\", // invalid case type\n\t}\n\ttestCaseTypes := []string{\n\t\t\"camel\",\n\t\t\"camelLower\",\n\t\t\"snake\",\n\t\t\"snakeFirstUpper\",\n\t\t\"snakeScreaming\",\n\t\t\"kebab\",\n\t\t\"kebabScreaming\",\n\t\t\"lower\",\n\t\t\"test\",\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < len(caseTypes); i++ {\n\t\t\tt.Assert(gstr.CaseTypeMatch(testCaseTypes[i]), caseTypes[i])\n\t\t}\n\t})\n}\n\nfunc Test_CaseConvert(t *testing.T) {\n\tcaseTypes := []gstr.CaseType{\n\t\tgstr.Camel,\n\t\tgstr.CamelLower,\n\t\tgstr.Snake,\n\t\tgstr.SnakeFirstUpper,\n\t\tgstr.SnakeScreaming,\n\t\tgstr.Kebab,\n\t\tgstr.KebabScreaming,\n\t\tgstr.Lower,\n\t\t\"test\", // invalid case type\n\t\t\"\",     // invalid case type\n\t}\n\ttestCaseTypes := []string{\n\t\t\"AnyKindOfString\",    // Camel\n\t\t\"anyKindOfString\",    // CamelLower\n\t\t\"any_kind_of_string\", // Snake\n\t\t\"any_kind_of_string\", // SnakeFirstUpper\n\t\t\"ANY_KIND_OF_STRING\", // SnakeScreaming\n\t\t\"any-kind-of-string\", // Kebab\n\t\t\"ANY-KIND-OF-STRING\", // KebabScreaming\n\t\t\"any_kind_of_string\", // Lower\n\t\t\"any_kind_of_string\", // invalid case type\n\t\t\"any_kind_of_string\", // invalid case type\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < len(caseTypes); i++ {\n\t\t\tt.Assert(gstr.CaseConvert(\"any_kind_of_string\", caseTypes[i]), testCaseTypes[i])\n\t\t\tt.Logf(\"test case: %s success\", caseTypes[i])\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_convert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_OctStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.OctStr(`\\346\\200\\241`), \"怡\")\n\t})\n}\n\nfunc Test_WordWrap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.WordWrap(\"12 34\", 2, \"<br>\"), \"12<br>34\")\n\t\tt.Assert(gstr.WordWrap(\"12 34\", 2, \"\\n\"), \"12\\n34\")\n\t\tt.Assert(gstr.WordWrap(\"我爱 GF\", 2, \"\\n\"), \"我爱\\nGF\")\n\t\tt.Assert(gstr.WordWrap(\"A very long woooooooooooooooooord. and something\", 7, \"<br>\"),\n\t\t\t\"A very<br>long<br>woooooooooooooooooord.<br>and<br>something\")\n\t})\n\t// Chinese Punctuations.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tbr      = \"                       \"\n\t\t\tcontent = \"    DelRouteKeyIPv6    删除VPC内的服务的Route信息;和DelRouteIPv6接口相比，这个接口可以删除满足条件的多条RS\\n\"\n\t\t\tlength  = 120\n\t\t)\n\t\twrappedContent := gstr.WordWrap(content, length, \"\\n\"+br)\n\t\tt.Assert(wrappedContent, `    DelRouteKeyIPv6    删除VPC内的服务的Route信息;和DelRouteIPv6接口相比，\n                       这个接口可以删除满足条件的多条RS\n`)\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_domain_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_IsSubDomain(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"goframe.org\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org:8080\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.johng.cn\", main), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"*.goframe.org\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org:80\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.johng.cn\", main), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"*.*.goframe.org\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org:8000\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.s.goframe.org\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.johng.cn\", main), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"*.*.goframe.org:8080\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org:8000\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.s.goframe.org\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.johng.cn\", main), false)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"*.*.goframe.org:8080\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.goframe.org:8000\", main), true)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.s.goframe.org\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.johng.cn\", main), false)\n\t\tt.Assert(gstr.IsSubDomain(\"s.s.johng.cn\", main), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmain := \"s.goframe.org\"\n\t\tt.Assert(gstr.IsSubDomain(\"goframe.org\", main), false)\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_List2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.List2(\"1:2\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.List2(\"1:\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.List2(\"1\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.List2(\"\", \":\")\n\t\tt.Assert(p1, \"\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.List2(\"1:2:3\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2:3\")\n\t})\n}\n\nfunc Test_ListAndTrim2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.ListAndTrim2(\"1::2\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.ListAndTrim2(\"1::\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.ListAndTrim2(\"1:\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.ListAndTrim2(\"\", \":\")\n\t\tt.Assert(p1, \"\")\n\t\tt.Assert(p2, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2 := gstr.ListAndTrim2(\"1::2::3\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2:3\")\n\t})\n}\n\nfunc Test_List3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1:2:3\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1:2:\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1:2\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1:\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"\", \":\")\n\t\tt.Assert(p1, \"\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.List3(\"1:2:3:4\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"3:4\")\n\t})\n}\n\nfunc Test_ListAndTrim3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"1::2:3\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"1::2:\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"1::2\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"2\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"1::\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"1::\", \":\")\n\t\tt.Assert(p1, \"1\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tp1, p2, p3 := gstr.ListAndTrim3(\"\", \":\")\n\t\tt.Assert(p1, \"\")\n\t\tt.Assert(p2, \"\")\n\t\tt.Assert(p3, \"\")\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_parse_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Parse(t *testing.T) {\n\t// cover test\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// empty\n\t\tm, err := gstr.Parse(\"\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, nil)\n\t\t// invalid\n\t\tm, err = gstr.Parse(\"a&b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, make(map[string]any))\n\t\t// special key\n\t\tm, err = gstr.Parse(\" =1& b=2&   c =3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, map[string]any{\"b\": \"2\", \"c_\": \"3\"})\n\t\tm, err = gstr.Parse(\"c[=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, map[string]any{\"c_\": \"3\"})\n\t\tm, err = gstr.Parse(\"v[a][a]a=m\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"v\": g.Map{\n\t\t\t\t\"a\": g.Map{\n\t\t\t\t\t\"a\": \"m\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\t// v[][a]=m&v[][b]=b => map[\"v\"]:[{\"a\":\"m\",\"b\":\"b\"}]\n\t\tm, err = gstr.Parse(\"v[][a]=m&v[][b]=b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"v\": g.Slice{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"a\": \"m\",\n\t\t\t\t\t\"b\": \"b\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\t// v[][a]=m&v[][a]=b => map[\"v\"]:[{\"a\":\"m\"},{\"a\":\"b\"}]\n\t\tm, err = gstr.Parse(\"v[][a]=m&v[][a]=b\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"v\": g.Slice{\n\t\t\t\tg.Map{\n\t\t\t\t\t\"a\": \"m\",\n\t\t\t\t},\n\t\t\t\tg.Map{\n\t\t\t\t\t\"a\": \"b\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\t// error\n\t\tm, err = gstr.Parse(\"v=111&v[]=m&v[]=a&v[]=b\")\n\t\tt.Log(err)\n\t\tt.AssertNE(err, nil)\n\t\tm, err = gstr.Parse(\"v=111&v[a]=m&v[a]=a\")\n\t\tt.Log(err)\n\t\tt.AssertNE(err, nil)\n\t\t_, err = gstr.Parse(\"%Q=%Q&b\")\n\t\tt.Log(err)\n\t\tt.AssertNE(err, nil)\n\t\t_, err = gstr.Parse(\"a=%Q&b\")\n\t\tt.Log(err)\n\t\tt.AssertNE(err, nil)\n\t\t_, err = gstr.Parse(\"v[a][a]=m&v[][a]=b\")\n\t\tt.Log(err)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\t// url\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"goframe.org/index?name=john&score=100\"\n\t\tu, err := url.Parse(s)\n\t\tt.AssertNil(err)\n\t\tm, err := gstr.Parse(u.RawQuery)\n\t\tt.AssertNil(err)\n\t\tt.Assert(m[\"name\"], \"john\")\n\t\tt.Assert(m[\"score\"], \"100\")\n\n\t\t// name overwrite\n\t\tm, err = gstr.Parse(\"a=1&a=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"a\": 2,\n\t\t})\n\t\t// slice\n\t\tm, err = gstr.Parse(\"a[]=1&a[]=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"a\": g.Slice{\"1\", \"2\"},\n\t\t})\n\t\t// map\n\t\tm, err = gstr.Parse(\"a=1&b=2&c=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"a\": \"1\",\n\t\t\t\"b\": \"2\",\n\t\t\t\"c\": \"3\",\n\t\t})\n\t\tm, err = gstr.Parse(\"a=1&a=2&c=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"a\": \"2\",\n\t\t\t\"c\": \"3\",\n\t\t})\n\t\t// map\n\t\tm, err = gstr.Parse(\"m[a]=1&m[b]=2&m[c]=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"a\": \"1\",\n\t\t\t\t\"b\": \"2\",\n\t\t\t\t\"c\": \"3\",\n\t\t\t},\n\t\t})\n\t\tm, err = gstr.Parse(\"m[a]=1&m[a]=2&m[b]=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"a\": \"2\",\n\t\t\t\t\"b\": \"3\",\n\t\t\t},\n\t\t})\n\t\t// map - slice\n\t\tm, err = gstr.Parse(\"m[a][]=1&m[a][]=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"a\": g.Slice{\"1\", \"2\"},\n\t\t\t},\n\t\t})\n\t\tm, err = gstr.Parse(\"m[a][b][]=1&m[a][b][]=2\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"a\": g.Map{\n\t\t\t\t\t\"b\": g.Slice{\"1\", \"2\"},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\t// map - complicated\n\t\tm, err = gstr.Parse(\"m[a1][b1][c1][d1]=1&m[a2][b2]=2&m[a3][b3][c3]=3\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"m\": g.Map{\n\t\t\t\t\"a1\": g.Map{\n\t\t\t\t\t\"b1\": g.Map{\n\t\t\t\t\t\t\"c1\": g.Map{\n\t\t\t\t\t\t\t\"d1\": \"1\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"a2\": g.Map{\n\t\t\t\t\t\"b2\": \"2\",\n\t\t\t\t},\n\t\t\t\t\"a3\": g.Map{\n\t\t\t\t\t\"b3\": g.Map{\n\t\t\t\t\t\t\"c3\": \"3\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_pos_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Pos(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\tt.Assert(gstr.Pos(s1, \"ab\"), 0)\n\t\tt.Assert(gstr.Pos(s1, \"ab\", 2), 7)\n\t\tt.Assert(gstr.Pos(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.Pos(s1, \"e\", -4), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.Pos(s1, \"爱\"), 3)\n\t\tt.Assert(gstr.Pos(s1, \"C\"), 6)\n\t\tt.Assert(gstr.Pos(s1, \"China\"), 6)\n\t})\n}\n\nfunc Test_PosRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\tt.Assert(gstr.PosRune(s1, \"ab\"), 0)\n\t\tt.Assert(gstr.PosRune(s1, \"ab\", 2), 7)\n\t\tt.Assert(gstr.PosRune(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosRune(s1, \"e\", -4), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosRune(s1, \"爱\"), 1)\n\t\tt.Assert(gstr.PosRune(s1, \"C\"), 2)\n\t\tt.Assert(gstr.PosRune(s1, \"China\"), 2)\n\t})\n}\n\nfunc Test_PosI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\tt.Assert(gstr.PosI(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosI(s1, \"ab\"), 0)\n\t\tt.Assert(gstr.PosI(s1, \"ef\", 2), 4)\n\t\tt.Assert(gstr.PosI(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosI(s1, \"E\", -4), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosI(s1, \"爱\"), 3)\n\t\tt.Assert(gstr.PosI(s1, \"c\"), 6)\n\t\tt.Assert(gstr.PosI(s1, \"china\"), 6)\n\t})\n}\n\nfunc Test_PosIRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\tt.Assert(gstr.PosIRune(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosIRune(s1, \"ab\"), 0)\n\t\tt.Assert(gstr.PosIRune(s1, \"ef\", 2), 4)\n\t\tt.Assert(gstr.PosIRune(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosIRune(s1, \"E\", -4), 11)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosIRune(s1, \"爱\"), 1)\n\t\tt.Assert(gstr.PosIRune(s1, \"c\"), 2)\n\t\tt.Assert(gstr.PosIRune(s1, \"china\"), 2)\n\t})\n}\n\nfunc Test_PosR(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\ts2 := \"abcdEFGz1cdeab\"\n\t\tt.Assert(gstr.PosR(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosR(s1, \"ab\"), 7)\n\t\tt.Assert(gstr.PosR(s2, \"ab\", -2), 0)\n\t\tt.Assert(gstr.PosR(s1, \"ef\"), 11)\n\t\tt.Assert(gstr.PosR(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosR(s1, \"e\", -4), -1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosR(s1, \"爱\"), 3)\n\t\tt.Assert(gstr.PosR(s1, \"C\"), 6)\n\t\tt.Assert(gstr.PosR(s1, \"China\"), 6)\n\t})\n}\n\nfunc Test_PosRRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\ts2 := \"abcdEFGz1cdeab\"\n\t\tt.Assert(gstr.PosRRune(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosRRune(s1, \"ab\"), 7)\n\t\tt.Assert(gstr.PosRRune(s2, \"ab\", -2), 0)\n\t\tt.Assert(gstr.PosRRune(s1, \"ef\"), 11)\n\t\tt.Assert(gstr.PosRRune(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosRRune(s1, \"e\", -4), -1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosRRune(s1, \"爱\"), 1)\n\t\tt.Assert(gstr.PosRRune(s1, \"C\"), 2)\n\t\tt.Assert(gstr.PosRRune(s1, \"China\"), 2)\n\t})\n}\n\nfunc Test_PosRI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\ts2 := \"abcdEFGz1cdeab\"\n\t\tt.Assert(gstr.PosRI(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosRI(s1, \"AB\"), 7)\n\t\tt.Assert(gstr.PosRI(s2, \"AB\", -2), 0)\n\t\tt.Assert(gstr.PosRI(s1, \"EF\"), 11)\n\t\tt.Assert(gstr.PosRI(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosRI(s1, \"e\", -5), 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosRI(s1, \"爱\"), 3)\n\t\tt.Assert(gstr.PosRI(s1, \"C\"), 19)\n\t\tt.Assert(gstr.PosRI(s1, \"China\"), 6)\n\t})\n}\n\nfunc Test_PosRIRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFGabcdefg\"\n\t\ts2 := \"abcdEFGz1cdeab\"\n\t\tt.Assert(gstr.PosRIRune(s1, \"zz\"), -1)\n\t\tt.Assert(gstr.PosRIRune(s1, \"AB\"), 7)\n\t\tt.Assert(gstr.PosRIRune(s2, \"AB\", -2), 0)\n\t\tt.Assert(gstr.PosRIRune(s1, \"EF\"), 11)\n\t\tt.Assert(gstr.PosRIRune(s1, \"abd\", 0), -1)\n\t\tt.Assert(gstr.PosRIRune(s1, \"e\", -5), 4)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱China very much\"\n\t\tt.Assert(gstr.PosRIRune(s1, \"爱\"), 1)\n\t\tt.Assert(gstr.PosRIRune(s1, \"C\"), 15)\n\t\tt.Assert(gstr.PosRIRune(s1, \"China\"), 2)\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_replace_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Replace(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFG乱入的中文abcdefg\"\n\t\tt.Assert(gstr.Replace(s1, \"ab\", \"AB\"), \"ABcdEFG乱入的中文ABcdefg\")\n\t\tt.Assert(gstr.Replace(s1, \"EF\", \"ef\"), \"abcdefG乱入的中文abcdefg\")\n\t\tt.Assert(gstr.Replace(s1, \"MN\", \"mn\"), s1)\n\n\t\tt.Assert(gstr.ReplaceByArray(s1, g.ArrayStr{\n\t\t\t\"a\", \"A\",\n\t\t\t\"A\", \"-\",\n\t\t\t\"a\",\n\t\t}), \"-bcdEFG乱入的中文-bcdefg\")\n\n\t\tt.Assert(gstr.ReplaceByMap(s1, g.MapStrStr{\n\t\t\t\"a\": \"A\",\n\t\t\t\"G\": \"g\",\n\t\t}), \"AbcdEFg乱入的中文Abcdefg\")\n\t})\n}\n\nfunc Test_ReplaceI_1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcd乱入的中文ABCD\"\n\t\ts2 := \"a\"\n\t\tt.Assert(gstr.ReplaceI(s1, \"ab\", \"aa\"), \"aacd乱入的中文aaCD\")\n\t\tt.Assert(gstr.ReplaceI(s1, \"ab\", \"aa\", 0), \"abcd乱入的中文ABCD\")\n\t\tt.Assert(gstr.ReplaceI(s1, \"ab\", \"aa\", 1), \"aacd乱入的中文ABCD\")\n\n\t\tt.Assert(gstr.ReplaceI(s1, \"abcd\", \"-\"), \"-乱入的中文-\")\n\t\tt.Assert(gstr.ReplaceI(s1, \"abcd\", \"-\", 1), \"-乱入的中文ABCD\")\n\n\t\tt.Assert(gstr.ReplaceI(s1, \"abcd乱入的\", \"\"), \"中文ABCD\")\n\t\tt.Assert(gstr.ReplaceI(s1, \"ABCD乱入的\", \"\"), \"中文ABCD\")\n\n\t\tt.Assert(gstr.ReplaceI(s2, \"A\", \"-\"), \"-\")\n\t\tt.Assert(gstr.ReplaceI(s2, \"a\", \"-\"), \"-\")\n\n\t\tt.Assert(gstr.ReplaceIByArray(s1, g.ArrayStr{\n\t\t\t\"abcd乱入的\", \"-\",\n\t\t\t\"-\", \"=\",\n\t\t\t\"a\",\n\t\t}), \"=中文ABCD\")\n\n\t\tt.Assert(gstr.ReplaceIByMap(s1, g.MapStrStr{\n\t\t\t\"ab\": \"-\",\n\t\t\t\"CD\": \"=\",\n\t\t}), \"-=乱入的中文-=\")\n\t})\n}\n\nfunc Test_ReplaceI_2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"-a-\"), `-a--a--a-`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaa\", \"AA\", \"-\"), `--`)\n\t\tt.Assert(gstr.ReplaceI(\"a a a\", \"A\", \"b\"), `b b b`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"aa\", \"a\"), `aaa`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"AA\", \"A\"), `AAA`)\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"AA\"), `AAAAAA`)\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"AA\"), `AAAAAA`)\n\t\tt.Assert(gstr.ReplaceI(\"a duration\", \"duration\", \"recordduration\"), `a recordduration`)\n\t})\n\t// With count parameter.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"aa\", \"a\", 2), `aaaa`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"AA\", \"A\", 1), `Aaaaa`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"AA\", \"A\", 3), `AAA`)\n\t\tt.Assert(gstr.ReplaceI(\"aaaaaa\", \"AA\", \"A\", 4), `AAA`)\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"AA\", 2), `AAAAa`)\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"AA\", 3), `AAAAAA`)\n\t\tt.Assert(gstr.ReplaceI(\"aaa\", \"A\", \"AA\", 4), `AAAAAA`)\n\t})\n}\n\nfunc Test_ReplaceIFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\torigin = \"hello GF 2018~2020!\"\n\t\t\tsearch = \"gf\"\n\t\t)\n\t\t// Simple replacement\n\t\tresult := gstr.ReplaceIFunc(origin, search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"hello GoFrame 2018~2020!\")\n\n\t\t// Replace with original string\n\t\tresult = gstr.ReplaceIFunc(origin, search, func(s string) string {\n\t\t\treturn s\n\t\t})\n\t\tt.Assert(result, origin)\n\n\t\t// Replace with empty string\n\t\tresult = gstr.ReplaceIFunc(origin, search, func(s string) string {\n\t\t\treturn \"\"\n\t\t})\n\t\tt.Assert(result, \"hello  2018~2020!\")\n\n\t\t// Replace multiple occurrences with different cases\n\t\torigin = \"GF is best, gf is nice, Gf is excellent\"\n\t\tresult = gstr.ReplaceIFunc(origin, search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"GoFrame is best, GoFrame is nice, GoFrame is excellent\")\n\n\t\t// Empty search string\n\t\tresult = gstr.ReplaceIFunc(origin, \"\", func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, origin)\n\n\t\t// Empty origin string\n\t\tresult = gstr.ReplaceIFunc(\"\", search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"\")\n\n\t\t// Replace with longer string\n\t\tresult = gstr.ReplaceIFunc(\"GF\", search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"GoFrame\")\n\n\t\t// Replace with shorter string\n\t\tresult = gstr.ReplaceIFunc(\"GF\", search, func(s string) string {\n\t\t\treturn \"g\"\n\t\t})\n\t\tt.Assert(result, \"g\")\n\n\t\t// Replace with mixed case patterns\n\t\torigin = \"gf GF Gf gF\"\n\t\tresult = gstr.ReplaceIFunc(origin, search, func(s string) string {\n\t\t\treturn strings.ToUpper(s)\n\t\t})\n\t\tt.Assert(result, \"GF GF GF GF\")\n\t})\n}\n\nfunc Test_ReplaceFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\torigin = \"hello gf 2018~2020!\"\n\t\t\tsearch = \"gf\"\n\t\t)\n\t\t// Simple replacement\n\t\tresult := gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"hello GoFrame 2018~2020!\")\n\n\t\t// Replace with original string\n\t\tresult = gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn s\n\t\t})\n\t\tt.Assert(result, origin)\n\n\t\t// Replace with empty string\n\t\tresult = gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn \"\"\n\t\t})\n\t\tt.Assert(result, \"hello  2018~2020!\")\n\n\t\t// Replace multiple occurrences\n\t\torigin = \"gf is best, gf is nice\"\n\t\tresult = gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"GoFrame is best, GoFrame is nice\")\n\n\t\t// Empty search string\n\t\tresult = gstr.ReplaceFunc(origin, \"\", func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, origin)\n\n\t\t// Empty origin string\n\t\tresult = gstr.ReplaceFunc(\"\", search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"\")\n\n\t\t// Case sensitive\n\t\torigin = \"GF is best, gf is nice\"\n\t\tresult = gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"GF is best, GoFrame is nice\")\n\n\t\t// Replace with longer string\n\t\tresult = gstr.ReplaceFunc(\"gf\", search, func(s string) string {\n\t\t\treturn \"GoFrame\"\n\t\t})\n\t\tt.Assert(result, \"GoFrame\")\n\n\t\t// Replace with shorter string\n\t\tresult = gstr.ReplaceFunc(\"gf\", search, func(s string) string {\n\t\t\treturn \"g\"\n\t\t})\n\t\tt.Assert(result, \"g\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\torigin  = \"gggg\"\n\t\t\tsearch  = \"g\"\n\t\t\treplace = \"gg\"\n\t\t)\n\t\t// Simple replacement\n\t\tresult := gstr.ReplaceFunc(origin, search, func(s string) string {\n\t\t\treturn replace\n\t\t})\n\t\tt.Assert(result, \"gggggggg\")\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_ToLower(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFG乱入的中文abcdefg\"\n\t\te1 := \"abcdefg乱入的中文abcdefg\"\n\t\tt.Assert(gstr.ToLower(s1), e1)\n\t})\n}\n\nfunc Test_ToUpper(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFG乱入的中文abcdefg\"\n\t\te1 := \"ABCDEFG乱入的中文ABCDEFG\"\n\t\tt.Assert(gstr.ToUpper(s1), e1)\n\t})\n}\n\nfunc Test_UcFirst(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"abcdEFG乱入的中文abcdefg\"\n\t\te1 := \"AbcdEFG乱入的中文abcdefg\"\n\t\tt.Assert(gstr.UcFirst(\"\"), \"\")\n\t\tt.Assert(gstr.UcFirst(s1), e1)\n\t\tt.Assert(gstr.UcFirst(e1), e1)\n\t})\n}\n\nfunc Test_LcFirst(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"AbcdEFG乱入的中文abcdefg\"\n\t\te1 := \"abcdEFG乱入的中文abcdefg\"\n\t\tt.Assert(gstr.LcFirst(\"\"), \"\")\n\t\tt.Assert(gstr.LcFirst(s1), e1)\n\t\tt.Assert(gstr.LcFirst(e1), e1)\n\t})\n}\n\nfunc Test_UcWords(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts1 := \"我爱GF: i love go frame\"\n\t\te1 := \"我爱Gf: I Love Go Frame\"\n\t\tt.Assert(gstr.UcWords(s1), e1)\n\t})\n}\n\nfunc Test_IsLetterLower(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.IsLetterLower('a'), true)\n\t\tt.Assert(gstr.IsLetterLower('A'), false)\n\t\tt.Assert(gstr.IsLetterLower('1'), false)\n\t})\n}\n\nfunc Test_IsLetterUpper(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.IsLetterUpper('a'), false)\n\t\tt.Assert(gstr.IsLetterUpper('A'), true)\n\t\tt.Assert(gstr.IsLetterUpper('1'), false)\n\t})\n}\n\nfunc Test_IsNumeric(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.IsNumeric(\"1a我\"), false)\n\t\tt.Assert(gstr.IsNumeric(\"0123\"), true)\n\t\tt.Assert(gstr.IsNumeric(\"我是中国人\"), false)\n\t\tt.Assert(gstr.IsNumeric(\"1.2.3.4\"), false)\n\t})\n}\n\nfunc Test_SubStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStr(\"我爱GoFrame\", 0), \"我爱GoFrame\")\n\t\tt.Assert(gstr.SubStr(\"我爱GoFrame\", 6), \"GoFrame\")\n\t\tt.Assert(gstr.SubStr(\"我爱GoFrame\", 6, 2), \"Go\")\n\t\tt.Assert(gstr.SubStr(\"我爱GoFrame\", -1, 30), \"e\")\n\t\tt.Assert(gstr.SubStr(\"我爱GoFrame\", 30, 30), \"\")\n\t\tt.Assert(gstr.SubStr(\"abcdef\", 0, -1), \"abcde\")\n\t\tt.Assert(gstr.SubStr(\"abcdef\", 2, -1), \"cde\")\n\t\tt.Assert(gstr.SubStr(\"abcdef\", 4, -4), \"\")\n\t\tt.Assert(gstr.SubStr(\"abcdef\", -3, -1), \"de\")\n\t})\n}\n\nfunc Test_SubStrRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", 0), \"我爱GoFrame\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", 2), \"GoFrame\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", 2, 2), \"Go\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", -1, 30), \"e\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", 30, 30), \"\")\n\t\tt.Assert(gstr.SubStrRune(\"abcdef\", 0, -1), \"abcde\")\n\t\tt.Assert(gstr.SubStrRune(\"abcdef\", 2, -1), \"cde\")\n\t\tt.Assert(gstr.SubStrRune(\"abcdef\", 4, -4), \"\")\n\t\tt.Assert(gstr.SubStrRune(\"abcdef\", -3, -1), \"de\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame呵呵\", -3, 100), \"e呵呵\")\n\t\tt.Assert(gstr.SubStrRune(\"abcdef哈哈\", -3, -1), \"f哈\")\n\t\tt.Assert(gstr.SubStrRune(\"ab我爱GoFramecdef哈哈\", -3, -1), \"f哈\")\n\t\tt.Assert(gstr.SubStrRune(\"我爱GoFrame\", 0, 3), \"我爱G\")\n\t})\n}\n\nfunc Test_StrLimit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StrLimit(\"我爱GoFrame\", 6), \"我爱...\")\n\t\tt.Assert(gstr.StrLimit(\"我爱GoFrame\", 6, \"\"), \"我爱\")\n\t\tt.Assert(gstr.StrLimit(\"我爱GoFrame\", 6, \"**\"), \"我爱**\")\n\t\tt.Assert(gstr.StrLimit(\"我爱GoFrame\", 8, \"\"), \"我爱Go\")\n\t\tt.Assert(gstr.StrLimit(\"*\", 4, \"\"), \"*\")\n\t})\n}\n\nfunc Test_StrLimitRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StrLimitRune(\"我爱GoFrame\", 2), \"我爱...\")\n\t\tt.Assert(gstr.StrLimitRune(\"我爱GoFrame\", 2, \"\"), \"我爱\")\n\t\tt.Assert(gstr.StrLimitRune(\"我爱GoFrame\", 2, \"**\"), \"我爱**\")\n\t\tt.Assert(gstr.StrLimitRune(\"我爱GoFrame\", 4, \"\"), \"我爱Go\")\n\t\tt.Assert(gstr.StrLimitRune(\"*\", 4, \"\"), \"*\")\n\t})\n}\n\nfunc Test_HasPrefix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.HasPrefix(\"我爱GoFrame\", \"我爱\"), true)\n\t\tt.Assert(gstr.HasPrefix(\"en我爱GoFrame\", \"我爱\"), false)\n\t\tt.Assert(gstr.HasPrefix(\"en我爱GoFrame\", \"en\"), true)\n\t})\n}\n\nfunc Test_HasSuffix(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.HasSuffix(\"我爱GoFrame\", \"GoFrame\"), true)\n\t\tt.Assert(gstr.HasSuffix(\"en我爱GoFrame\", \"a\"), false)\n\t\tt.Assert(gstr.HasSuffix(\"GoFrame很棒\", \"棒\"), true)\n\t})\n}\n\nfunc Test_Reverse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Reverse(\"我爱123\"), \"321爱我\")\n\t})\n}\n\nfunc Test_NumberFormat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.NumberFormat(1234567.8910, 2, \".\", \",\"), \"1,234,567.89\")\n\t\tt.Assert(gstr.NumberFormat(1234567.8910, 2, \"#\", \"/\"), \"1/234/567#89\")\n\t\tt.Assert(gstr.NumberFormat(-1234567.8910, 2, \"#\", \"/\"), \"-1/234/567#89\")\n\t})\n}\n\nfunc Test_ChunkSplit(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.ChunkSplit(\"1234\", 1, \"#\"), \"1#2#3#4#\")\n\t\tt.Assert(gstr.ChunkSplit(\"我爱123\", 1, \"#\"), \"我#爱#1#2#3#\")\n\t\tt.Assert(gstr.ChunkSplit(\"1234\", 1, \"\"), \"1\\r\\n2\\r\\n3\\r\\n4\\r\\n\")\n\t})\n}\n\nfunc Test_SplitAndTrim(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := `\n\n010\n\n020\n\n`\n\t\ta := gstr.SplitAndTrim(s, \"\\n\", \"0\")\n\t\tt.Assert(len(a), 2)\n\t\tt.Assert(a[0], \"1\")\n\t\tt.Assert(a[1], \"2\")\n\t})\n}\n\nfunc Test_Fields(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Fields(\"我爱 Go Frame\"), []string{\n\t\t\t\"我爱\", \"Go\", \"Frame\",\n\t\t})\n\t})\n}\n\nfunc Test_CountWords(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.CountWords(\"我爱 Go Go Go\"), map[string]int{\n\t\t\t\"Go\": 3,\n\t\t\t\"我爱\": 1,\n\t\t})\n\t})\n}\n\nfunc Test_CountChars(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.CountChars(\"我爱 Go Go Go\"), map[string]int{\n\t\t\t\" \": 3,\n\t\t\t\"G\": 3,\n\t\t\t\"o\": 3,\n\t\t\t\"我\": 1,\n\t\t\t\"爱\": 1,\n\t\t})\n\t\tt.Assert(gstr.CountChars(\"我爱 Go Go Go\", true), map[string]int{\n\t\t\t\"G\": 3,\n\t\t\t\"o\": 3,\n\t\t\t\"我\": 1,\n\t\t\t\"爱\": 1,\n\t\t})\n\t})\n}\n\nfunc Test_LenRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.LenRune(\"1234\"), 4)\n\t\tt.Assert(gstr.LenRune(\"我爱GoFrame\"), 9)\n\t})\n}\n\nfunc Test_Repeat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Repeat(\"go\", 3), \"gogogo\")\n\t\tt.Assert(gstr.Repeat(\"好的\", 3), \"好的好的好的\")\n\t})\n}\n\nfunc Test_Str(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Str(\"name@example.com\", \"@\"), \"@example.com\")\n\t\tt.Assert(gstr.Str(\"name@example.com\", \"\"), \"\")\n\t\tt.Assert(gstr.Str(\"name@example.com\", \"z\"), \"\")\n\t})\n}\n\nfunc Test_StrEx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StrEx(\"name@example.com\", \"@\"), \"example.com\")\n\t\tt.Assert(gstr.StrEx(\"name@example.com\", \"\"), \"\")\n\t\tt.Assert(gstr.StrEx(\"name@example.com\", \"z\"), \"\")\n\t})\n}\n\nfunc Test_StrTill(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StrTill(\"name@example.com\", \"@\"), \"name@\")\n\t\tt.Assert(gstr.StrTill(\"name@example.com\", \"\"), \"\")\n\t\tt.Assert(gstr.StrTill(\"name@example.com\", \"z\"), \"\")\n\t})\n}\n\nfunc Test_StrTillEx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StrTillEx(\"name@example.com\", \"@\"), \"name\")\n\t\tt.Assert(gstr.StrTillEx(\"name@example.com\", \"\"), \"\")\n\t\tt.Assert(gstr.StrTillEx(\"name@example.com\", \"z\"), \"\")\n\t})\n}\n\nfunc Test_Shuffle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(gstr.Shuffle(\"123456\")), 6)\n\t})\n}\n\nfunc Test_Split(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Split(\"1.2\", \".\"), []string{\"1\", \"2\"})\n\t\tt.Assert(gstr.Split(\"我爱 - GoFrame\", \" - \"), []string{\"我爱\", \"GoFrame\"})\n\t})\n}\n\nfunc Test_Join(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Join([]string{\"我爱\", \"GoFrame\"}, \" - \"), \"我爱 - GoFrame\")\n\t})\n}\n\nfunc Test_Explode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Explode(\" - \", \"我爱 - GoFrame\"), []string{\"我爱\", \"GoFrame\"})\n\t})\n}\n\nfunc Test_Implode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Implode(\" - \", []string{\"我爱\", \"GoFrame\"}), \"我爱 - GoFrame\")\n\t})\n}\n\nfunc Test_Chr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Chr(65), \"A\")\n\t})\n}\n\nfunc Test_Ord(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Ord(\"A\"), 65)\n\t})\n}\n\nfunc Test_HideStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.HideStr(\"15928008611\", 40, \"*\"), \"159****8611\")\n\t\tt.Assert(gstr.HideStr(\"john@kohg.cn\", 40, \"*\"), \"jo*n@kohg.cn\")\n\t\tt.Assert(gstr.HideStr(\"张三\", 50, \"*\"), \"张*\")\n\t\tt.Assert(gstr.HideStr(\"张小三\", 50, \"*\"), \"张*三\")\n\t\tt.Assert(gstr.HideStr(\"欧阳小三\", 50, \"*\"), \"欧**三\")\n\n\t\t// 边界与特殊用例扩展\n\t\t// 1) 空字符串与非正百分比\n\t\tt.Assert(gstr.HideStr(\"\", 50, \"*\"), \"\")\n\t\tt.Assert(gstr.HideStr(\"abcdef\", 0, \"*\"), \"abcdef\")\n\t\tt.Assert(gstr.HideStr(\"abcdef\", -1, \"*\"), \"abcdef\")\n\n\t\t// 2) 百分比为100（完全隐藏），邮箱仅隐藏本地部分\n\t\tt.Assert(gstr.HideStr(\"abcdef\", 100, \"*\"), \"******\")\n\t\tt.Assert(gstr.HideStr(\"user@example.com\", 100, \"*\"), \"****@example.com\")\n\n\t\t// 3) 极短字符串\n\t\tt.Assert(gstr.HideStr(\"a\", 100, \"*\"), \"*\")\n\t\tt.Assert(gstr.HideStr(\"ab\", 50, \"*\"), \"a*\")\n\t\t// 百分比太小时（四舍五入前为0），应保持不变\n\t\tt.Assert(gstr.HideStr(\"ab\", 10, \"*\"), \"ab\")\n\n\t\t// 4) 隐藏字符为空：相当于删除中间片段\n\t\tt.Assert(gstr.HideStr(\"abcdef\", 50, \"\"), \"abf\")\n\t\tt.Assert(gstr.HideStr(\"john@kohg.cn\", 50, \"\"), \"jn@kohg.cn\")\n\n\t\t// 5) 多字符隐藏串\n\t\tt.Assert(gstr.HideStr(\"abcde\", 40, \"##\"), \"a####de\")\n\n\t\t// 6) Unicode/emoji\n\t\tt.Assert(gstr.HideStr(\"你好🙂世界\", 40, \"*\"), \"你**世界\")\n\n\t\t// 7) 多个@的字符串，按第一个@处理\n\t\tt.Assert(gstr.HideStr(\"a@b@c\", 100, \"*\"), \"*@b@c\")\n\t})\n}\n\nfunc Test_Nl2Br(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Nl2Br(\"1\\n2\"), \"1<br>2\")\n\t\tt.Assert(gstr.Nl2Br(\"1\\r\\n2\"), \"1<br>2\")\n\t\tt.Assert(gstr.Nl2Br(\"1\\r\\n2\", true), \"1<br />2\")\n\t})\n}\n\nfunc Test_AddSlashes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.AddSlashes(`1'2\"3\\`), `1\\'2\\\"3\\\\`)\n\t})\n}\n\nfunc Test_StripSlashes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.StripSlashes(`1\\'2\\\"3\\\\`), `1'2\"3\\`)\n\t})\n}\n\nfunc Test_QuoteMeta(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.QuoteMeta(`.\\+*?[^]($)`), `\\.\\\\\\+\\*\\?\\[\\^\\]\\(\\$\\)`)\n\t\tt.Assert(gstr.QuoteMeta(`.\\+*中国?[^]($)`), `\\.\\\\\\+\\*中国\\?\\[\\^\\]\\(\\$\\)`)\n\t\tt.Assert(gstr.QuoteMeta(`.''`, `'`), `.\\'\\'`)\n\t\tt.Assert(gstr.QuoteMeta(`中国.''`, `'`), `中国.\\'\\'`)\n\t})\n}\n\nfunc Test_Count(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"abcdaAD\"\n\t\tt.Assert(gstr.Count(s, \"0\"), 0)\n\t\tt.Assert(gstr.Count(s, \"a\"), 2)\n\t\tt.Assert(gstr.Count(s, \"b\"), 1)\n\t\tt.Assert(gstr.Count(s, \"d\"), 1)\n\t})\n}\n\nfunc Test_CountI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"abcdaAD\"\n\t\tt.Assert(gstr.CountI(s, \"0\"), 0)\n\t\tt.Assert(gstr.CountI(s, \"a\"), 3)\n\t\tt.Assert(gstr.CountI(s, \"b\"), 1)\n\t\tt.Assert(gstr.CountI(s, \"d\"), 2)\n\t})\n}\n\nfunc Test_Compare(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Compare(\"a\", \"b\"), -1)\n\t\tt.Assert(gstr.Compare(\"a\", \"a\"), 0)\n\t\tt.Assert(gstr.Compare(\"b\", \"a\"), 1)\n\t})\n}\n\nfunc Test_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Equal(\"a\", \"A\"), true)\n\t\tt.Assert(gstr.Equal(\"a\", \"a\"), true)\n\t\tt.Assert(gstr.Equal(\"b\", \"a\"), false)\n\t})\n}\n\nfunc Test_Contains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Contains(\"abc\", \"a\"), true)\n\t\tt.Assert(gstr.Contains(\"abc\", \"A\"), false)\n\t\tt.Assert(gstr.Contains(\"abc\", \"ab\"), true)\n\t\tt.Assert(gstr.Contains(\"abc\", \"abc\"), true)\n\t})\n}\n\nfunc Test_ContainsI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"a\"), true)\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"A\"), true)\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"Ab\"), true)\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"ABC\"), true)\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"ABCD\"), false)\n\t\tt.Assert(gstr.ContainsI(\"abc\", \"D\"), false)\n\t})\n}\n\nfunc Test_ContainsAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.ContainsAny(\"abc\", \"a\"), true)\n\t\tt.Assert(gstr.ContainsAny(\"abc\", \"cd\"), true)\n\t\tt.Assert(gstr.ContainsAny(\"abc\", \"de\"), false)\n\t\tt.Assert(gstr.ContainsAny(\"abc\", \"A\"), false)\n\t})\n}\n\nfunc Test_SubStrFrom(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStrFrom(\"我爱GoFrameGood\", `G`), \"GoFrameGood\")\n\t\tt.Assert(gstr.SubStrFrom(\"我爱GoFrameGood\", `GG`), \"\")\n\t\tt.Assert(gstr.SubStrFrom(\"我爱GoFrameGood\", `我`), \"我爱GoFrameGood\")\n\t\tt.Assert(gstr.SubStrFrom(\"我爱GoFrameGood\", `Frame`), \"FrameGood\")\n\t})\n}\n\nfunc Test_SubStrFromEx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStrFromEx(\"我爱GoFrameGood\", `Go`), \"FrameGood\")\n\t\tt.Assert(gstr.SubStrFromEx(\"我爱GoFrameGood\", `GG`), \"\")\n\t\tt.Assert(gstr.SubStrFromEx(\"我爱GoFrameGood\", `我`), \"爱GoFrameGood\")\n\t\tt.Assert(gstr.SubStrFromEx(\"我爱GoFrameGood\", `Frame`), `Good`)\n\t})\n}\n\nfunc Test_SubStrFromR(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStrFromR(\"我爱GoFrameGood\", `G`), \"Good\")\n\t\tt.Assert(gstr.SubStrFromR(\"我爱GoFrameGood\", `GG`), \"\")\n\t\tt.Assert(gstr.SubStrFromR(\"我爱GoFrameGood\", `我`), \"我爱GoFrameGood\")\n\t\tt.Assert(gstr.SubStrFromR(\"我爱GoFrameGood\", `Frame`), \"FrameGood\")\n\t})\n}\n\nfunc Test_SubStrFromREx(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.SubStrFromREx(\"我爱GoFrameGood\", `G`), \"ood\")\n\t\tt.Assert(gstr.SubStrFromREx(\"我爱GoFrameGood\", `GG`), \"\")\n\t\tt.Assert(gstr.SubStrFromREx(\"我爱GoFrameGood\", `我`), \"爱GoFrameGood\")\n\t\tt.Assert(gstr.SubStrFromREx(\"我爱GoFrameGood\", `Frame`), `Good`)\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_trim_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_Trim(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.Trim(\" 123456\\n \"), \"123456\")\n\t\tt.Assert(gstr.Trim(\"#123456#;\", \"#;\"), \"123456\")\n\t})\n}\n\nfunc Test_TrimStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimStr(\"gogo我爱gogo\", \"go\"), \"我爱\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimStr(\"gogo我爱gogo\", \"go\", 1), \"go我爱go\")\n\t\tt.Assert(gstr.TrimStr(\"gogo我爱gogo\", \"go\", 2), \"我爱\")\n\t\tt.Assert(gstr.TrimStr(\"gogo我爱gogo\", \"go\", -1), \"我爱\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimStr(\"啊我爱中国人啊\", \"啊\"), \"我爱中国人\")\n\t})\n}\n\nfunc Test_TrimRight(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimRight(\" 123456\\n \"), \" 123456\")\n\t\tt.Assert(gstr.TrimRight(\"#123456#;\", \"#;\"), \"#123456\")\n\t})\n}\n\nfunc Test_TrimRightStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimRightStr(\"gogo我爱gogo\", \"go\"), \"gogo我爱\")\n\t\tt.Assert(gstr.TrimRightStr(\"gogo我爱gogo\", \"go我爱gogo\"), \"go\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimRightStr(\"gogo我爱gogo\", \"go\", 1), \"gogo我爱go\")\n\t\tt.Assert(gstr.TrimRightStr(\"gogo我爱gogo\", \"go\", 2), \"gogo我爱\")\n\t\tt.Assert(gstr.TrimRightStr(\"gogo我爱gogo\", \"go\", -1), \"gogo我爱\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimRightStr(\"我爱中国人\", \"人\"), \"我爱中国\")\n\t\tt.Assert(gstr.TrimRightStr(\"我爱中国人\", \"爱中国人\"), \"我\")\n\t})\n}\n\nfunc Test_TrimLeft(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimLeft(\" \\r123456\\n \"), \"123456\\n \")\n\t\tt.Assert(gstr.TrimLeft(\"#;123456#;\", \"#;\"), \"123456#;\")\n\t})\n}\n\nfunc Test_TrimLeftStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimLeftStr(\"gogo我爱gogo\", \"go\"), \"我爱gogo\")\n\t\tt.Assert(gstr.TrimLeftStr(\"gogo我爱gogo\", \"gogo我爱go\"), \"go\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimLeftStr(\"gogo我爱gogo\", \"go\", 1), \"go我爱gogo\")\n\t\tt.Assert(gstr.TrimLeftStr(\"gogo我爱gogo\", \"go\", 2), \"我爱gogo\")\n\t\tt.Assert(gstr.TrimLeftStr(\"gogo我爱gogo\", \"go\", -1), \"我爱gogo\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimLeftStr(\"我爱中国人\", \"我爱\"), \"中国人\")\n\t\tt.Assert(gstr.TrimLeftStr(\"我爱中国人\", \"我爱中国\"), \"人\")\n\t})\n}\n\nfunc Test_TrimAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimAll(\"gogo我go\\n爱gogo\\n\", \"go\"), \"我爱\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimAll(\"gogo\\n我go爱gogo\", \"go\"), \"我爱\")\n\t\tt.Assert(gstr.TrimAll(\"gogo\\n我go爱gogo\\n\", \"go\"), \"我爱\")\n\t\tt.Assert(gstr.TrimAll(\"gogo\\n我go\\n爱gogo\", \"go\"), \"我爱\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gstr.TrimAll(\"啊我爱\\n啊中国\\n人啊\", \"啊\"), \"我爱中国人\")\n\t})\n}\n"
  },
  {
    "path": "text/gstr/gstr_z_unit_version_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gstr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc Test_IsGNUVersion(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v0\"), true)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v0.\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1\"), true)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1.0\"), true)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1.\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1.0.0\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v0.0.0\"), true)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1.-1\"), false)\n\t\tt.AssertEQ(gstr.IsGNUVersion(\"v1.1.+1\"), false)\n\t})\n}\n\nfunc Test_CompareVersion(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gstr.CompareVersion(\"1\", \"\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"\", \"\"), 0)\n\t\tt.AssertEQ(gstr.CompareVersion(\"\", \"v0.1\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"1\", \"v0.99\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"v1.0\", \"v0.99\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"v1.0.1\", \"v1.1.0\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"1.0.1\", \"v1.1.0\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"1.0.0\", \"v0.1.0\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersion(\"1.0.0\", \"v1.0.0\"), 0)\n\t})\n}\n\nfunc Test_CompareVersionGo(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"1\", \"\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"\", \"\"), 0)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"\", \"v0.1\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.0.1\", \"v1.1.0\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"1.0.1\", \"v1.1.0\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"1.0.0\", \"v0.1.0\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"1.0.0\", \"v1.0.0\"), 0)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"1.0.0\", \"v1.0\"), 0)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v0.0.0-20190626092158-b2ccc519800e\", \"0.0.0-20190626092158\"), 0)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v0.0.0-20190626092159-b2ccc519800e\", \"0.0.0-20190626092158\"), 1)\n\n\t\t// Specially in Golang:\n\t\t// \"v1.12.2-0.20200413154443-b17e3a6804fa\" < \"v1.12.2\"\n\t\t// \"v1.12.3-0.20200413154443-b17e3a6804fa\" > \"v1.12.2\"\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.2-0.20200413154443-b17e3a6804fa\", \"v1.12.2\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.2\", \"v1.12.2-0.20200413154443-b17e3a6804fa\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.3-0.20200413154443-b17e3a6804fa\", \"v1.12.2\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.2\", \"v1.12.3-0.20200413154443-b17e3a6804fa\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.2-0.20200413154443-b17e3a6804fa\", \"v0.0.0-20190626092158-b2ccc519800e\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v1.12.2-0.20200413154443-b17e3a6804fa\", \"v1.12.2-0.20200413154444-b2ccc519800e\"), -1)\n\n\t\t// Specially in Golang:\n\t\t// \"v4.20.1+incompatible\" < \"v4.20.1\"\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v4.20.0+incompatible\", \"4.20.0\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"4.20.0\", \"v4.20.0+incompatible\"), 1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v4.20.0+incompatible\", \"4.20.1\"), -1)\n\t\tt.AssertEQ(gstr.CompareVersionGo(\"v4.20.0+incompatible\", \"v4.20.0+incompatible\"), 0)\n\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gconv implements powerful and convenient converting functionality for any types of variables.\n//\n// This package should keep much fewer dependencies with other packages.\npackage gconv\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/converter\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/structcache\"\n)\n\n// Converter is the manager for type converting.\ntype Converter interface {\n\tConverterForConvert\n\tConverterForRegister\n\tConverterForInt\n\tConverterForUint\n\tConverterForTime\n\tConverterForFloat\n\tConverterForMap\n\tConverterForSlice\n\tConverterForStruct\n\tConverterForBasic\n}\n\n// ConverterForBasic is the basic converting interface.\ntype ConverterForBasic interface {\n\tScan(srcValue, dstPointer any, option ...ScanOption) (err error)\n\tString(anyInput any) (string, error)\n\tBool(anyInput any) (bool, error)\n\tRune(anyInput any) (rune, error)\n}\n\n// ConverterForTime is the converting interface for time.\ntype ConverterForTime interface {\n\tTime(v any, format ...string) (time.Time, error)\n\tDuration(v any) (time.Duration, error)\n\tGTime(v any, format ...string) (*gtime.Time, error)\n}\n\n// ConverterForInt is the converting interface for integer.\ntype ConverterForInt interface {\n\tInt(v any) (int, error)\n\tInt8(v any) (int8, error)\n\tInt16(v any) (int16, error)\n\tInt32(v any) (int32, error)\n\tInt64(v any) (int64, error)\n}\n\n// ConverterForUint is the converting interface for unsigned integer.\ntype ConverterForUint interface {\n\tUint(v any) (uint, error)\n\tUint8(v any) (uint8, error)\n\tUint16(v any) (uint16, error)\n\tUint32(v any) (uint32, error)\n\tUint64(v any) (uint64, error)\n}\n\n// ConverterForFloat is the converting interface for float.\ntype ConverterForFloat interface {\n\tFloat32(v any) (float32, error)\n\tFloat64(v any) (float64, error)\n}\n\n// ConverterForMap is the converting interface for map.\ntype ConverterForMap interface {\n\tMap(v any, option ...MapOption) (map[string]any, error)\n\tMapStrStr(v any, option ...MapOption) (map[string]string, error)\n}\n\n// ConverterForSlice is the converting interface for slice.\ntype ConverterForSlice interface {\n\tBytes(v any) ([]byte, error)\n\tRunes(v any) ([]rune, error)\n\tSliceAny(v any, option ...SliceOption) ([]any, error)\n\tSliceFloat32(v any, option ...SliceOption) ([]float32, error)\n\tSliceFloat64(v any, option ...SliceOption) ([]float64, error)\n\tSliceInt(v any, option ...SliceOption) ([]int, error)\n\tSliceInt32(v any, option ...SliceOption) ([]int32, error)\n\tSliceInt64(v any, option ...SliceOption) ([]int64, error)\n\tSliceUint(v any, option ...SliceOption) ([]uint, error)\n\tSliceUint32(v any, option ...SliceOption) ([]uint32, error)\n\tSliceUint64(v any, option ...SliceOption) ([]uint64, error)\n\tSliceStr(v any, option ...SliceOption) ([]string, error)\n\tSliceMap(v any, option ...SliceMapOption) ([]map[string]any, error)\n}\n\n// ConverterForStruct is the converting interface for struct.\ntype ConverterForStruct interface {\n\tStruct(params, pointer any, option ...StructOption) (err error)\n\tStructs(params, pointer any, option ...StructsOption) (err error)\n}\n\n// ConverterForConvert is the converting interface for custom converting.\ntype ConverterForConvert interface {\n\tConvertWithRefer(fromValue, referValue any, option ...ConvertOption) (any, error)\n\tConvertWithTypeName(fromValue any, toTypeName string, option ...ConvertOption) (any, error)\n}\n\n// ConverterForRegister is the converting interface for custom converter registration.\ntype ConverterForRegister interface {\n\tRegisterTypeConverterFunc(f any) error\n\tRegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type)\n}\n\ntype (\n\t// AnyConvertFunc is the function type for converting any to specified type.\n\tAnyConvertFunc = structcache.AnyConvertFunc\n\n\t// MapOption specifies the option for map converting.\n\tMapOption = converter.MapOption\n\n\t// SliceOption is the option for Slice type converting.\n\tSliceOption = converter.SliceOption\n\n\t// SliceMapOption is the option for SliceMap function.\n\tSliceMapOption = converter.SliceMapOption\n\n\t// ScanOption is the option for the Scan function.\n\tScanOption = converter.ScanOption\n\n\t// StructOption is the option for Struct converting.\n\tStructOption = converter.StructOption\n\n\t// StructsOption is the option for Structs function.\n\tStructsOption = converter.StructsOption\n\n\t// ConvertOption is the option for converting.\n\tConvertOption = converter.ConvertOption\n)\n\n// IUnmarshalValue is the interface for custom defined types customizing value assignment.\n// Note that only pointer can implement interface IUnmarshalValue.\ntype IUnmarshalValue = localinterface.IUnmarshalValue\n\nvar (\n\t// defaultConverter is the default management object converting.\n\tdefaultConverter = converter.NewConverter()\n)\n\n// NewConverter creates and returns management object for type converting.\nfunc NewConverter() Converter {\n\treturn converter.NewConverter()\n}\n\n// RegisterConverter registers custom converter.\n//\n// Deprecated: use RegisterTypeConverterFunc instead for clear\nfunc RegisterConverter(fn any) (err error) {\n\treturn RegisterTypeConverterFunc(fn)\n}\n\n// RegisterTypeConverterFunc registers custom converter.\nfunc RegisterTypeConverterFunc(fn any) (err error) {\n\treturn defaultConverter.RegisterTypeConverterFunc(fn)\n}\n\n// RegisterAnyConverterFunc registers custom type converting function for specified type.\nfunc RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) {\n\tdefaultConverter.RegisterAnyConverterFunc(f, types...)\n}\n"
  },
  {
    "path": "util/gconv/gconv_basic.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Byte converts `any` to byte.\nfunc Byte(anyInput any) byte {\n\tv, _ := defaultConverter.Uint8(anyInput)\n\treturn v\n}\n\n// Bytes converts `any` to []byte.\nfunc Bytes(anyInput any) []byte {\n\tv, _ := defaultConverter.Bytes(anyInput)\n\treturn v\n}\n\n// Rune converts `any` to rune.\nfunc Rune(anyInput any) rune {\n\tv, _ := defaultConverter.Rune(anyInput)\n\treturn v\n}\n\n// Runes converts `any` to []rune.\nfunc Runes(anyInput any) []rune {\n\tv, _ := defaultConverter.Runes(anyInput)\n\treturn v\n}\n\n// String converts `any` to string.\n// It's most commonly used converting function.\nfunc String(anyInput any) string {\n\tv, _ := defaultConverter.String(anyInput)\n\treturn v\n}\n\n// Bool converts `any` to bool.\n// It returns false if `any` is: false, \"\", 0, \"false\", \"off\", \"no\", empty slice/map.\nfunc Bool(anyInput any) bool {\n\tv, _ := defaultConverter.Bool(anyInput)\n\treturn v\n}\n"
  },
  {
    "path": "util/gconv/gconv_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.\n//\n// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.\n// It supports common basic types conversion as its conversion based on type name string.\nfunc Convert(fromValue any, toTypeName string, extraParams ...any) any {\n\tresult, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, ConvertOption{\n\t\tExtraParams:  extraParams,\n\t\tSliceOption:  SliceOption{ContinueOnError: true},\n\t\tMapOption:    MapOption{ContinueOnError: true},\n\t\tStructOption: StructOption{ContinueOnError: true},\n\t})\n\treturn result\n}\n\n// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.\n//\n// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.\n// It supports common basic types conversion as its conversion based on type name string.\nfunc ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any {\n\tresult, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, ConvertOption{\n\t\tExtraParams:  extraParams,\n\t\tSliceOption:  SliceOption{ContinueOnError: true},\n\t\tMapOption:    MapOption{ContinueOnError: true},\n\t\tStructOption: StructOption{ContinueOnError: true},\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_float.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Float32 converts `any` to float32.\nfunc Float32(anyInput any) float32 {\n\tv, _ := defaultConverter.Float32(anyInput)\n\treturn v\n}\n\n// Float64 converts `any` to float64.\nfunc Float64(anyInput any) float64 {\n\tv, _ := defaultConverter.Float64(anyInput)\n\treturn v\n}\n"
  },
  {
    "path": "util/gconv/gconv_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Int converts `any` to int.\nfunc Int(anyInput any) int {\n\tv, _ := defaultConverter.Int(anyInput)\n\treturn v\n}\n\n// Int8 converts `any` to int8.\nfunc Int8(anyInput any) int8 {\n\tv, _ := defaultConverter.Int8(anyInput)\n\treturn v\n}\n\n// Int16 converts `any` to int16.\nfunc Int16(anyInput any) int16 {\n\tv, _ := defaultConverter.Int16(anyInput)\n\treturn v\n}\n\n// Int32 converts `any` to int32.\nfunc Int32(anyInput any) int32 {\n\tv, _ := defaultConverter.Int32(anyInput)\n\treturn v\n}\n\n// Int64 converts `any` to int64.\nfunc Int64(anyInput any) int64 {\n\tv, _ := defaultConverter.Int64(anyInput)\n\treturn v\n}\n"
  },
  {
    "path": "util/gconv/gconv_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Map converts any variable `value` to map[string]any. If the parameter `value` is not a\n// map/struct/*struct type, then the conversion will fail and returns nil.\n//\n// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority\n// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of:\n// gconv, json, field name.\nfunc Map(value any, option ...MapOption) map[string]any {\n\tresult, _ := defaultConverter.Map(value, getUsedMapOption(option...))\n\treturn result\n}\n\n// MapDeep does Map function recursively, which means if the attribute of `value`\n// is also a struct/*struct, calls Map function on this attribute converting it to\n// a map[string]any type variable.\n//\n// Deprecated: used Map instead.\nfunc MapDeep(value any, tags ...string) map[string]any {\n\tresult, _ := defaultConverter.Map(value, MapOption{\n\t\tDeep:            true,\n\t\tOmitEmpty:       false,\n\t\tTags:            tags,\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// MapStrStr converts `value` to map[string]string.\n// Note that there might be data copy for this map type converting.\nfunc MapStrStr(value any, option ...MapOption) map[string]string {\n\tresult, _ := defaultConverter.MapStrStr(value, getUsedMapOption(option...))\n\treturn result\n}\n\n// MapStrStrDeep converts `value` to map[string]string recursively.\n// Note that there might be data copy for this map type converting.\n//\n// Deprecated: used MapStrStr instead.\nfunc MapStrStrDeep(value any, tags ...string) map[string]string {\n\tif r, ok := value.(map[string]string); ok {\n\t\treturn r\n\t}\n\tm := MapDeep(value, tags...)\n\tif len(m) > 0 {\n\t\tvMap := make(map[string]string, len(m))\n\t\tfor k, v := range m {\n\t\t\tvMap[k] = String(v)\n\t\t}\n\t\treturn vMap\n\t}\n\treturn nil\n}\n\nfunc getUsedMapOption(option ...MapOption) MapOption {\n\tvar usedOption = MapOption{\n\t\tContinueOnError: true,\n\t}\n\tif len(option) > 0 {\n\t\tusedOption = option[0]\n\t}\n\treturn usedOption\n}\n"
  },
  {
    "path": "util/gconv/gconv_maps.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/converter\"\n)\n\n// SliceMap is alias of Maps.\nfunc SliceMap(anyInput any, option ...MapOption) []map[string]any {\n\treturn Maps(anyInput, option...)\n}\n\n// SliceMapDeep is alias of MapsDeep.\n//\n// Deprecated: used SliceMap instead.\nfunc SliceMapDeep(anyInput any) []map[string]any {\n\treturn MapsDeep(anyInput)\n}\n\n// Maps converts `value` to []map[string]any.\n// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.\nfunc Maps(value any, option ...MapOption) []map[string]any {\n\tmapOption := MapOption{\n\t\tContinueOnError: true,\n\t}\n\tif len(option) > 0 {\n\t\tmapOption = option[0]\n\t}\n\tresult, _ := defaultConverter.SliceMap(value, SliceMapOption{\n\t\tMapOption: mapOption,\n\t\tSliceOption: converter.SliceOption{\n\t\t\tContinueOnError: true,\n\t\t},\n\t})\n\treturn result\n}\n\n// MapsDeep converts `value` to []map[string]any recursively.\n//\n// TODO completely implement the recursive converting for all types.\n//\n// Deprecated: used Maps instead.\nfunc MapsDeep(value any, tags ...string) []map[string]any {\n\tif value == nil {\n\t\treturn nil\n\t}\n\tswitch r := value.(type) {\n\tcase string:\n\t\tlist := make([]map[string]any, 0)\n\t\tif len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {\n\t\t\tif err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn list\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\n\tcase []byte:\n\t\tlist := make([]map[string]any, 0)\n\t\tif len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {\n\t\t\tif err := json.UnmarshalUseNumber(r, &list); err != nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn list\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\n\tcase []map[string]any:\n\t\tlist := make([]map[string]any, len(r))\n\t\tfor k, v := range r {\n\t\t\tlist[k] = MapDeep(v, tags...)\n\t\t}\n\t\treturn list\n\n\tdefault:\n\t\tarray := Interfaces(value)\n\t\tif len(array) == 0 {\n\t\t\treturn nil\n\t\t}\n\t\tlist := make([]map[string]any, len(array))\n\t\tfor k, v := range array {\n\t\t\tlist[k] = MapDeep(v, tags...)\n\t\t}\n\t\treturn list\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_maptomap.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// MapToMap converts any map type variable `params` to another map type variable `pointer`\n// using reflect.\n// See doMapToMap.\nfunc MapToMap(params any, pointer any, mapping ...map[string]string) error {\n\treturn Scan(params, pointer, mapping...)\n}\n"
  },
  {
    "path": "util/gconv/gconv_maptomaps.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`.\n// See doMapToMaps.\nfunc MapToMaps(params any, pointer any, mapping ...map[string]string) error {\n\treturn Scan(params, pointer, mapping...)\n}\n"
  },
  {
    "path": "util/gconv/gconv_ptr.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// PtrAny creates and returns an any pointer variable to this value.\nfunc PtrAny(anyInput any) *any {\n\treturn &anyInput\n}\n\n// PtrString creates and returns a string pointer variable to this value.\nfunc PtrString(anyInput any) *string {\n\tv := String(anyInput)\n\treturn &v\n}\n\n// PtrBool creates and returns a bool pointer variable to this value.\nfunc PtrBool(anyInput any) *bool {\n\tv := Bool(anyInput)\n\treturn &v\n}\n\n// PtrInt creates and returns an int pointer variable to this value.\nfunc PtrInt(anyInput any) *int {\n\tv := Int(anyInput)\n\treturn &v\n}\n\n// PtrInt8 creates and returns an int8 pointer variable to this value.\nfunc PtrInt8(anyInput any) *int8 {\n\tv := Int8(anyInput)\n\treturn &v\n}\n\n// PtrInt16 creates and returns an int16 pointer variable to this value.\nfunc PtrInt16(anyInput any) *int16 {\n\tv := Int16(anyInput)\n\treturn &v\n}\n\n// PtrInt32 creates and returns an int32 pointer variable to this value.\nfunc PtrInt32(anyInput any) *int32 {\n\tv := Int32(anyInput)\n\treturn &v\n}\n\n// PtrInt64 creates and returns an int64 pointer variable to this value.\nfunc PtrInt64(anyInput any) *int64 {\n\tv := Int64(anyInput)\n\treturn &v\n}\n\n// PtrUint creates and returns an uint pointer variable to this value.\nfunc PtrUint(anyInput any) *uint {\n\tv := Uint(anyInput)\n\treturn &v\n}\n\n// PtrUint8 creates and returns an uint8 pointer variable to this value.\nfunc PtrUint8(anyInput any) *uint8 {\n\tv := Uint8(anyInput)\n\treturn &v\n}\n\n// PtrUint16 creates and returns an uint16 pointer variable to this value.\nfunc PtrUint16(anyInput any) *uint16 {\n\tv := Uint16(anyInput)\n\treturn &v\n}\n\n// PtrUint32 creates and returns an uint32 pointer variable to this value.\nfunc PtrUint32(anyInput any) *uint32 {\n\tv := Uint32(anyInput)\n\treturn &v\n}\n\n// PtrUint64 creates and returns an uint64 pointer variable to this value.\nfunc PtrUint64(anyInput any) *uint64 {\n\tv := Uint64(anyInput)\n\treturn &v\n}\n\n// PtrFloat32 creates and returns a float32 pointer variable to this value.\nfunc PtrFloat32(anyInput any) *float32 {\n\tv := Float32(anyInput)\n\treturn &v\n}\n\n// PtrFloat64 creates and returns a float64 pointer variable to this value.\nfunc PtrFloat64(anyInput any) *float64 {\n\tv := Float64(anyInput)\n\treturn &v\n}\n"
  },
  {
    "path": "util/gconv/gconv_scan.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.\n// It supports various types of parameter conversions, including:\n// 1. Basic types (int, string, float, etc.)\n// 2. Pointer types\n// 3. Slice types\n// 4. Map types\n// 5. Struct types\n//\n// The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys.\n// TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`.\nfunc Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {\n\toption := ScanOption{\n\t\tContinueOnError: true,\n\t}\n\tif len(paramKeyToAttrMap) > 0 {\n\t\toption.ParamKeyToAttrMap = paramKeyToAttrMap[0]\n\t}\n\treturn defaultConverter.Scan(srcValue, dstPointer, option)\n}\n\n// ScanWithOptions automatically checks the type of `dstPointer` and converts `srcValue` to `dstPointer`.\n// It is the same as Scan function, but accepts one or more ScanOption values for additional conversion control.\n//\n// When using ScanWithOptions, the term \"omit\" means that the assignment from the source to the destination\n// is skipped, so the existing value in the destination field is preserved.\n//\n//   - option.OmitEmpty, when set to true, skips assignment of empty source values (for example: empty strings,\n//     zero numeric values, zero time values, empty slices or maps), preserving any existing non-empty values\n//     in the destination.\n//\n//   - option.OmitNil, when set to true, skips assignment of nil source values, preserving the existing values\n//     in the destination when the source contains nil.\n//\n// Example:\n//\n//\ttype User struct {\n//\t    Name  string\n//\t    Email string\n//\t}\n//\n//\tdst := &User{Name: \"Alice\", Email: \"alice@example.com\"}\n//\tsrc := map[string]any{\n//\t    \"Name\":  \"\",\n//\t    \"Email\": nil,\n//\t}\n//\n//\t// With OmitEmpty and OmitNil, empty and nil values in src will not overwrite dst.\n//\terr := ScanWithOptions(src, dst, ScanOption{OmitEmpty: true, OmitNil: true})\nfunc ScanWithOptions(srcValue any, dstPointer any, option ...ScanOption) (err error) {\n\treturn defaultConverter.Scan(srcValue, dstPointer, option...)\n}\n"
  },
  {
    "path": "util/gconv/gconv_scan_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n)\n\n// ScanList converts `structSlice` to struct slice which contains other complex struct attributes.\n// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.\n//\n// Usage example 1: Normal attribute struct relation:\n//\n//\ttype EntityUser struct {\n//\t    Uid  int\n//\t    Name string\n//\t}\n//\n//\ttype EntityUserDetail struct {\n//\t    Uid     int\n//\t    Address string\n//\t}\n//\n//\ttype EntityUserScores struct {\n//\t    Id     int\n//\t    Uid    int\n//\t    Score  int\n//\t    Course string\n//\t}\n//\n//\ttype Entity struct {\n//\t    User       *EntityUser\n//\t    UserDetail *EntityUserDetail\n//\t    UserScores []*EntityUserScores\n//\t}\n//\n// var users []*Entity\n// var userRecords   = EntityUser{Uid: 1, Name:\"john\"}\n// var detailRecords = EntityUser{Uid: 1, Address: \"chengdu\"}\n// var scoresRecords = EntityUser{Id: 1, Uid: 1, Score: 100, Course: \"math\"}\n// ScanList(userRecords, &users, \"User\")\n// ScanList(userRecords, &users, \"User\", \"uid\")\n// ScanList(detailRecords, &users, \"UserDetail\", \"User\", \"uid:Uid\")\n// ScanList(scoresRecords, &users, \"UserScores\", \"User\", \"uid:Uid\")\n// ScanList(scoresRecords, &users, \"UserScores\", \"User\", \"uid\")\n//\n// Usage example 2: Embedded attribute struct relation:\n//\n//\ttype EntityUser struct {\n//\t\t   Uid  int\n//\t\t   Name string\n//\t}\n//\n//\ttype EntityUserDetail struct {\n//\t\t   Uid     int\n//\t\t   Address string\n//\t}\n//\n//\ttype EntityUserScores struct {\n//\t\t   Id    int\n//\t\t   Uid   int\n//\t\t   Score int\n//\t}\n//\n//\ttype Entity struct {\n//\t\t   EntityUser\n//\t\t   UserDetail EntityUserDetail\n//\t\t   UserScores []EntityUserScores\n//\t}\n//\n// var userRecords   = EntityUser{Uid: 1, Name:\"john\"}\n// var detailRecords = EntityUser{Uid: 1, Address: \"chengdu\"}\n// var scoresRecords = EntityUser{Id: 1, Uid: 1, Score: 100, Course: \"math\"}\n// ScanList(userRecords, &users)\n// ScanList(detailRecords, &users, \"UserDetail\", \"uid\")\n// ScanList(scoresRecords, &users, \"UserScores\", \"uid\")\n//\n// The parameters \"User/UserDetail/UserScores\" in the example codes specify the target attribute struct\n// that current result will be bound to.\n//\n// The \"uid\" in the example codes is the table field name of the result, and the \"Uid\" is the relational\n// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute\n// name \"Uid\" of \"User\" of entity \"Entity\". It automatically calculates the HasOne/HasMany relationship with\n// given `relation` parameter.\n//\n// See the example or unit testing cases for clear understanding for this function.\nfunc ScanList(\n\tstructSlice any, structSlicePointer any, bindToAttrName string, relationAttrNameAndFields ...string,\n) (err error) {\n\tvar (\n\t\trelationAttrName string\n\t\trelationFields   string\n\t)\n\tswitch len(relationAttrNameAndFields) {\n\tcase 2:\n\t\trelationAttrName = relationAttrNameAndFields[0]\n\t\trelationFields = relationAttrNameAndFields[1]\n\tcase 1:\n\t\trelationFields = relationAttrNameAndFields[0]\n\t}\n\treturn doScanList(structSlice, structSlicePointer, bindToAttrName, relationAttrName, relationFields)\n}\n\n// doScanList converts `structSlice` to struct slice which contains other complex struct attributes recursively.\n// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.\nfunc doScanList(\n\tstructSlice any, structSlicePointer any, bindToAttrName, relationAttrName, relationFields string,\n) (err error) {\n\tvar (\n\t\tmaps    = Maps(structSlice)\n\t\tlenMaps = len(maps)\n\t)\n\tif lenMaps == 0 {\n\t\treturn nil\n\t}\n\t// Necessary checks for parameters.\n\tif bindToAttrName == \"\" {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)\n\t}\n\n\tif relationAttrName == \".\" {\n\t\trelationAttrName = \"\"\n\t}\n\n\tvar (\n\t\treflectValue = reflect.ValueOf(structSlicePointer)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tif reflectKind == reflect.Interface {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tif reflectKind != reflect.Pointer {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v\",\n\t\t\treflectKind,\n\t\t)\n\t}\n\treflectValue = reflectValue.Elem()\n\treflectKind = reflectValue.Kind()\n\tif reflectKind != reflect.Slice && reflectKind != reflect.Array {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v\",\n\t\t\treflectKind,\n\t\t)\n\t}\n\tvar (\n\t\tarrayValue    reflect.Value // Like: []*Entity\n\t\tarrayItemType reflect.Type  // Like: *Entity\n\t\treflectType   = reflect.TypeOf(structSlicePointer)\n\t)\n\tif reflectValue.Len() > 0 {\n\t\tarrayValue = reflectValue\n\t} else {\n\t\tarrayValue = reflect.MakeSlice(reflectType.Elem(), lenMaps, lenMaps)\n\t}\n\n\t// Slice element item.\n\tarrayItemType = arrayValue.Index(0).Type()\n\n\t// Relation variables.\n\tvar (\n\t\trelationDataMap         map[string]any\n\t\trelationFromFieldName   string // Eg: relationKV: id:uid  -> id\n\t\trelationBindToFieldName string // Eg: relationKV: id:uid  -> uid\n\t)\n\tif len(relationFields) > 0 {\n\t\t// The relation key string of table field name and attribute name\n\t\t// can be joined with char '=' or ':'.\n\t\tarray := utils.SplitAndTrim(relationFields, \"=\")\n\t\tif len(array) == 1 {\n\t\t\t// Compatible with old splitting char ':'.\n\t\t\tarray = utils.SplitAndTrim(relationFields, \":\")\n\t\t}\n\t\tif len(array) == 1 {\n\t\t\t// The relation names are the same.\n\t\t\tarray = []string{relationFields, relationFields}\n\t\t}\n\t\tif len(array) == 2 {\n\t\t\t// Defined table field to relation attribute name.\n\t\t\t// Like:\n\t\t\t// uid:Uid\n\t\t\t// uid:UserId\n\t\t\trelationFromFieldName = array[0]\n\t\t\trelationBindToFieldName = array[1]\n\t\t\tif key, _ := utils.MapPossibleItemByKey(maps[0], relationFromFieldName); key == \"\" {\n\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`cannot find possible related table field name \"%s\" from given relation fields \"%s\"`,\n\t\t\t\t\trelationFromFieldName,\n\t\t\t\t\trelationFields,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\trelationFromFieldName = key\n\t\t\t}\n\t\t} else {\n\t\t\treturn gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`parameter relationKV should be format of \"ResultFieldName:BindToAttrName\"`,\n\t\t\t)\n\t\t}\n\t\tif relationFromFieldName != \"\" {\n\t\t\t// Note that the value might be type of slice.\n\t\t\trelationDataMap = utils.ListToMapByKey(maps, relationFromFieldName)\n\t\t}\n\t\tif len(relationDataMap) == 0 {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot find the relation data map, maybe invalid relation fields given \"%v\"`,\n\t\t\t\trelationFields,\n\t\t\t)\n\t\t}\n\t}\n\t// Bind to target attribute.\n\tvar (\n\t\tok              bool\n\t\tbindToAttrValue reflect.Value\n\t\tbindToAttrKind  reflect.Kind\n\t\tbindToAttrType  reflect.Type\n\t\tbindToAttrField reflect.StructField\n\t)\n\tif arrayItemType.Kind() == reflect.Pointer {\n\t\tif bindToAttrField, ok = arrayItemType.Elem().FieldByName(bindToAttrName); !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid parameter bindToAttrName: cannot find attribute with name \"%s\" from slice element`,\n\t\t\t\tbindToAttrName,\n\t\t\t)\n\t\t}\n\t} else {\n\t\tif bindToAttrField, ok = arrayItemType.FieldByName(bindToAttrName); !ok {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid parameter bindToAttrName: cannot find attribute with name \"%s\" from slice element`,\n\t\t\t\tbindToAttrName,\n\t\t\t)\n\t\t}\n\t}\n\tbindToAttrType = bindToAttrField.Type\n\tbindToAttrKind = bindToAttrType.Kind()\n\n\t// Bind to relation conditions.\n\tvar (\n\t\trelationFromAttrValue          reflect.Value\n\t\trelationFromAttrField          reflect.Value\n\t\trelationBindToFieldNameChecked bool\n\t)\n\tfor i := 0; i < arrayValue.Len(); i++ {\n\t\tarrayElemValue := arrayValue.Index(i)\n\t\t// The FieldByName should be called on non-pointer reflect.Value.\n\t\tif arrayElemValue.Kind() == reflect.Pointer {\n\t\t\t// Like: []*Entity\n\t\t\tarrayElemValue = arrayElemValue.Elem()\n\t\t\tif !arrayElemValue.IsValid() {\n\t\t\t\t// The element is nil, then create one and set it to the slice.\n\t\t\t\t// The \"reflect.New(itemType.Elem())\" creates a new element and returns the address of it.\n\t\t\t\t// For example:\n\t\t\t\t// reflect.New(itemType.Elem())        => *Entity\n\t\t\t\t// reflect.New(itemType.Elem()).Elem() => Entity\n\t\t\t\tarrayElemValue = reflect.New(arrayItemType.Elem()).Elem()\n\t\t\t\tarrayValue.Index(i).Set(arrayElemValue.Addr())\n\t\t\t}\n\t\t\t// } else {\n\t\t\t// Like: []Entity\n\t\t}\n\t\tbindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)\n\t\tif relationAttrName != \"\" {\n\t\t\t// Attribute value of current slice element.\n\t\t\trelationFromAttrValue = arrayElemValue.FieldByName(relationAttrName)\n\t\t\tif relationFromAttrValue.Kind() == reflect.Pointer {\n\t\t\t\trelationFromAttrValue = relationFromAttrValue.Elem()\n\t\t\t}\n\t\t} else {\n\t\t\t// Current slice element.\n\t\t\trelationFromAttrValue = arrayElemValue\n\t\t}\n\t\tif len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, relationFields)\n\t\t}\n\t\t// Check and find possible bind to attribute name.\n\t\tif relationFields != \"\" && !relationBindToFieldNameChecked {\n\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\tif !relationFromAttrField.IsValid() {\n\t\t\t\tvar (\n\t\t\t\t\tfieldMap, _ = gstructs.FieldMap(gstructs.FieldMapInput{\n\t\t\t\t\t\tPointer:         relationFromAttrValue,\n\t\t\t\t\t\tRecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\tif key, _ := utils.MapPossibleItemByKey(Map(fieldMap), relationBindToFieldName); key == \"\" {\n\t\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t\t`cannot find possible related attribute name \"%s\" from given relation fields \"%s\"`,\n\t\t\t\t\t\trelationBindToFieldName,\n\t\t\t\t\t\trelationFields,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\trelationBindToFieldName = key\n\t\t\t\t}\n\t\t\t}\n\t\t\trelationBindToFieldNameChecked = true\n\t\t}\n\t\tswitch bindToAttrKind {\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\t// results := make(Result, 0)\n\t\t\t\t\tresults := make([]any, 0)\n\t\t\t\t\tfor _, v := range SliceAny(relationDataMap[String(relationFromAttrField.Interface())]) {\n\t\t\t\t\t\titem := v\n\t\t\t\t\t\tresults = append(results, item)\n\t\t\t\t\t}\n\t\t\t\t\tif err = Structs(results, bindToAttrValue.Addr()); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, relationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\t`relationKey should not be empty as field \"%s\" is slice`,\n\t\t\t\t\tbindToAttrName,\n\t\t\t\t)\n\t\t\t}\n\n\t\tcase reflect.Pointer:\n\t\t\tvar element reflect.Value\n\t\t\tif bindToAttrValue.IsNil() {\n\t\t\t\telement = reflect.New(bindToAttrType.Elem()).Elem()\n\t\t\t} else {\n\t\t\t\telement = bindToAttrValue.Elem()\n\t\t\t}\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\tv := relationDataMap[String(relationFromAttrField.Interface())]\n\t\t\t\t\tif v == nil {\n\t\t\t\t\t\t// There's no relational data.\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif utils.IsSlice(v) {\n\t\t\t\t\t\tif err = Struct(SliceAny(v)[0], element); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err = Struct(v, element); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, relationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif i >= len(maps) {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tv := maps[i]\n\t\t\t\tif v == nil {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err = Struct(v, element); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tbindToAttrValue.Set(element.Addr())\n\n\t\tcase reflect.Struct:\n\t\t\tif len(relationDataMap) > 0 {\n\t\t\t\trelationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)\n\t\t\t\tif relationFromAttrField.IsValid() {\n\t\t\t\t\trelationDataItem := relationDataMap[String(relationFromAttrField.Interface())]\n\t\t\t\t\tif relationDataItem == nil {\n\t\t\t\t\t\t// There's no relational data.\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif utils.IsSlice(relationDataItem) {\n\t\t\t\t\t\tif err = Struct(SliceAny(relationDataItem)[0], bindToAttrValue); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err = Struct(relationDataItem, bindToAttrValue); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Maybe the attribute does not exist yet.\n\t\t\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: \"%v\"`, relationFields)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif i >= len(maps) {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trelationDataItem := maps[i]\n\t\t\t\tif relationDataItem == nil {\n\t\t\t\t\t// There's no relational data.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err = Struct(relationDataItem, bindToAttrValue); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\treturn gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())\n\t\t}\n\t}\n\treflect.ValueOf(structSlicePointer).Elem().Set(arrayValue)\n\treturn nil\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_any.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceAny is alias of Interfaces.\nfunc SliceAny(anyInput any) []any {\n\treturn Interfaces(anyInput)\n}\n\n// Interfaces converts `any` to []any.\nfunc Interfaces(anyInput any) []any {\n\tresult, _ := defaultConverter.SliceAny(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_bool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceBool is alias of Bools.\nfunc SliceBool(anyInput any) []bool {\n\treturn Bools(anyInput)\n}\n\n// Bools converts `any` to []bool.\nfunc Bools(anyInput any) []bool {\n\tresult, _ := defaultConverter.SliceBool(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_float.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceFloat is alias of Floats.\nfunc SliceFloat(anyInput any) []float64 {\n\treturn Floats(anyInput)\n}\n\n// SliceFloat32 is alias of Float32s.\nfunc SliceFloat32(anyInput any) []float32 {\n\treturn Float32s(anyInput)\n}\n\n// SliceFloat64 is alias of Float64s.\nfunc SliceFloat64(anyInput any) []float64 {\n\treturn Floats(anyInput)\n}\n\n// Floats converts `any` to []float64.\nfunc Floats(anyInput any) []float64 {\n\treturn Float64s(anyInput)\n}\n\n// Float32s converts `any` to []float32.\nfunc Float32s(anyInput any) []float32 {\n\tresult, _ := defaultConverter.SliceFloat32(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// Float64s converts `any` to []float64.\nfunc Float64s(anyInput any) []float64 {\n\tresult, _ := defaultConverter.SliceFloat64(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceInt is alias of Ints.\nfunc SliceInt(anyInput any) []int {\n\treturn Ints(anyInput)\n}\n\n// SliceInt32 is alias of Int32s.\nfunc SliceInt32(anyInput any) []int32 {\n\treturn Int32s(anyInput)\n}\n\n// SliceInt64 is alias of Int64s.\nfunc SliceInt64(anyInput any) []int64 {\n\treturn Int64s(anyInput)\n}\n\n// Ints converts `any` to []int.\nfunc Ints(anyInput any) []int {\n\tresult, _ := defaultConverter.SliceInt(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// Int32s converts `any` to []int32.\nfunc Int32s(anyInput any) []int32 {\n\tresult, _ := defaultConverter.SliceInt32(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// Int64s converts `any` to []int64.\nfunc Int64s(anyInput any) []int64 {\n\tresult, _ := defaultConverter.SliceInt64(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_str.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceStr is alias of Strings.\nfunc SliceStr(anyInput any) []string {\n\treturn Strings(anyInput)\n}\n\n// Strings converts `any` to []string.\nfunc Strings(anyInput any) []string {\n\tresult, _ := defaultConverter.SliceStr(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_slice_uint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// SliceUint is alias of Uints.\nfunc SliceUint(anyInput any) []uint {\n\treturn Uints(anyInput)\n}\n\n// SliceUint32 is alias of Uint32s.\nfunc SliceUint32(anyInput any) []uint32 {\n\treturn Uint32s(anyInput)\n}\n\n// SliceUint64 is alias of Uint64s.\nfunc SliceUint64(anyInput any) []uint64 {\n\treturn Uint64s(anyInput)\n}\n\n// Uints converts `any` to []uint.\nfunc Uints(anyInput any) []uint {\n\tresult, _ := defaultConverter.SliceUint(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// Uint32s converts `any` to []uint32.\nfunc Uint32s(anyInput any) []uint32 {\n\tresult, _ := defaultConverter.SliceUint32(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n\n// Uint64s converts `any` to []uint64.\nfunc Uint64s(anyInput any) []uint64 {\n\tresult, _ := defaultConverter.SliceUint64(anyInput, SliceOption{\n\t\tContinueOnError: true,\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "util/gconv/gconv_struct.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Struct maps the params key-value pairs to the corresponding struct object's attributes.\n// The third parameter `mapping` is unnecessary, indicating the mapping rules between the\n// custom key name and the attribute name(case-sensitive).\n//\n// Note:\n//  1. The `params` can be any type of map/struct, usually a map.\n//  2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object\n//     or struct pointer.\n//  3. Only the public attributes of struct object can be mapped.\n//  4. If `params` is a map, the key of the map `params` can be lowercase.\n//     It will automatically convert the first letter of the key to uppercase\n//     in mapping procedure to do the matching.\n//     It ignores the map key, if it does not match.\nfunc Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) {\n\treturn Scan(params, pointer, paramKeyToAttrMap...)\n}\n\n// StructTag acts as Struct but also with support for priority tag feature, which retrieves the\n// specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping.\n// The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','.\nfunc StructTag(params any, pointer any, priorityTag string) (err error) {\n\toption := StructOption{\n\t\tPriorityTag:     priorityTag,\n\t\tContinueOnError: true,\n\t}\n\treturn defaultConverter.Struct(params, pointer, option)\n}\n"
  },
  {
    "path": "util/gconv/gconv_structs.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\nimport \"github.com/gogf/gf/v2/util/gconv/internal/converter\"\n\n// Structs converts any slice to given struct slice.\n// Also see Scan, Struct.\nfunc Structs(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) {\n\treturn Scan(params, pointer, paramKeyToAttrMap...)\n}\n\n// SliceStruct is alias of Structs.\nfunc SliceStruct(params any, pointer any, mapping ...map[string]string) (err error) {\n\treturn Structs(params, pointer, mapping...)\n}\n\n// StructsTag acts as Structs but also with support for priority tag feature, which retrieves the\n// specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping.\n// The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','.\nfunc StructsTag(params any, pointer any, priorityTag string) (err error) {\n\treturn defaultConverter.Structs(params, pointer, StructsOption{\n\t\tSliceOption: converter.SliceOption{\n\t\t\tContinueOnError: true,\n\t\t},\n\t\tStructOption: converter.StructOption{\n\t\t\tPriorityTag:     priorityTag,\n\t\t\tContinueOnError: true,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// Time converts `any` to time.Time.\nfunc Time(anyInput any, format ...string) time.Time {\n\tt, _ := defaultConverter.Time(anyInput, format...)\n\treturn t\n}\n\n// Duration converts `any` to time.Duration.\n// If `any` is string, then it uses time.ParseDuration to convert it.\n// If `any` is numeric, then it converts `any` as nanoseconds.\nfunc Duration(anyInput any) time.Duration {\n\td, _ := defaultConverter.Duration(anyInput)\n\treturn d\n}\n\n// GTime converts `any` to *gtime.Time.\n// The parameter `format` can be used to specify the format of `any`.\n// It returns the converted value that matched the first format of the formats slice.\n// If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric,\n// or using gtime.StrToTime if `any` is string.\nfunc GTime(anyInput any, format ...string) *gtime.Time {\n\tt, _ := defaultConverter.GTime(anyInput, format...)\n\treturn t\n}\n"
  },
  {
    "path": "util/gconv/gconv_uint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\n// Uint converts `any` to uint.\nfunc Uint(anyInput any) uint {\n\tv, _ := defaultConverter.Uint(anyInput)\n\treturn v\n}\n\n// Uint8 converts `any` to uint8.\nfunc Uint8(anyInput any) uint8 {\n\tv, _ := defaultConverter.Uint8(anyInput)\n\treturn v\n}\n\n// Uint16 converts `any` to uint16.\nfunc Uint16(anyInput any) uint16 {\n\tv, _ := defaultConverter.Uint16(anyInput)\n\treturn v\n}\n\n// Uint32 converts `any` to uint32.\nfunc Uint32(anyInput any) uint32 {\n\tv, _ := defaultConverter.Uint32(anyInput)\n\treturn v\n}\n\n// Uint64 converts `any` to uint64.\nfunc Uint64(anyInput any) uint64 {\n\tv, _ := defaultConverter.Uint64(anyInput)\n\treturn v\n}\n"
  },
  {
    "path": "util/gconv/gconv_unsafe.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv\n\nimport \"unsafe\"\n\n// UnsafeStrToBytes converts string to []byte without memory copy.\n// Note that, if you completely sure you will never use `s` variable in the feature,\n// you can use this unsafe function to implement type conversion in high performance.\nfunc UnsafeStrToBytes(s string) []byte {\n\treturn unsafe.Slice(unsafe.StringData(s), len(s))\n}\n\n// UnsafeBytesToStr converts []byte to string without memory copy.\n// Note that, if you completely sure you will never use `b` variable in the feature,\n// you can use this unsafe function to implement type conversion in high performance.\nfunc UnsafeBytesToStr(b []byte) string {\n\treturn unsafe.String(unsafe.SliceData(b), len(b))\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_bytes_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench \"Benchmark_Bytes_To_*\" -benchmem\n\npackage gconv\n\nimport (\n\t\"testing\"\n\t\"unsafe\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n)\n\nvar valueBytes = gbinary.Encode(123456789)\n\nfunc Benchmark_Bytes_To_String_Normal(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = string(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_String_Unsafe(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = *(*string)(unsafe.Pointer(&valueBytes))\n\t}\n}\n\nfunc Benchmark_Bytes_To_String(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tString(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Int8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt8(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Int16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt16(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Int32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt32(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Int64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Uint(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Uint8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint8(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Uint16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint16(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Uint32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint32(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Uint64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint64(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Float32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat32(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Float64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat64(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Time(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tTime(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_TimeDuration(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDuration(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Bytes(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBytes(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Strings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStrings(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Ints(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInts(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Floats(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloats(valueBytes)\n\t}\n}\n\nfunc Benchmark_Bytes_To_Interfaces(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInterfaces(valueBytes)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_float_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gconv\n\nimport (\n\t\"testing\"\n)\n\nvar valueFloat = float64(1.23456789)\n\nfunc Benchmark_Float_To_String(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tString(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Int8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt8(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Int16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt16(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Int32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt32(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Int64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Uint(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Uint8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint8(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Uint16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint16(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Uint32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint32(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Uint64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint64(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Float32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat32(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Float64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat64(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Time(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tTime(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_TimeDuration(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDuration(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Bytes(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBytes(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Strings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStrings(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Ints(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInts(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Floats(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloats(valueFloat)\n\t}\n}\n\nfunc Benchmark_Float_To_Interfaces(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInterfaces(valueFloat)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gconv\n\nimport (\n\t\"testing\"\n)\n\nvar valueInt = 123456789\n\nfunc Benchmark_Int_To_String(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tString(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Int8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt8(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Int16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt16(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Int32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt32(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Int64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Uint(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Uint8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint8(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Uint16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint16(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Uint32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint32(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Uint64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint64(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Float32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat32(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Float64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat64(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Time(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tTime(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_TimeDuration(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDuration(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Bytes(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBytes(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Strings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStrings(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Ints(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInts(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Floats(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloats(valueInt)\n\t}\n}\n\nfunc Benchmark_Int_To_Interfaces(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInterfaces(valueInt)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_reflect_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gconv_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\ntype testStruct struct {\n\tId   int\n\tName string\n}\n\nvar ptr = []*testStruct{\n\t{\n\t\tId:   1,\n\t\tName: \"test1\",\n\t},\n\t{\n\t\tId:   2,\n\t\tName: \"test2\",\n\t},\n}\n\nfunc init() {\n\tfor i := 1; i <= 1000; i++ {\n\t\tptr = append(ptr, &testStruct{\n\t\t\tId:   1,\n\t\t\tName: \"test1\",\n\t\t})\n\t}\n}\n\nfunc Benchmark_Reflect_ValueOf(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treflect.ValueOf(ptr)\n\t}\n}\n\nfunc Benchmark_Reflect_ValueOf_Kind(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treflect.ValueOf(ptr).Kind()\n\t}\n}\n\nfunc Benchmark_Reflect_ValueOf_Interface(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treflect.ValueOf(ptr).Interface()\n\t}\n}\n\nfunc Benchmark_Reflect_ValueOf_Len(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\treflect.ValueOf(ptr).Len()\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_str_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gconv\n\nimport (\n\t\"testing\"\n)\n\nvar valueStr = \"123456789\"\n\nfunc Benchmark_Str_To_String(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tString(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Int8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt8(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Int16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt16(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Int32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt32(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Int64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInt(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Uint(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Uint8(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint8(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Uint16(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint16(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Uint32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint32(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Uint64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUint64(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Float32(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat32(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Float64(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloat64(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Time(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tTime(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_TimeDuration(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDuration(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Bytes(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBytes(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Strings(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStrings(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Ints(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInts(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Floats(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFloats(valueStr)\n\t}\n}\n\nfunc Benchmark_Str_To_Interfaces(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tInterfaces(valueStr)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_bench_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gconv\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\ntype structType struct {\n\tName  string\n\tScore int\n\tAge   int\n\tID    int\n}\n\ntype structType8 struct {\n\tName        string  `json:\"name\"   `\n\tCategoryId  string  `json:\"category-Id\" `\n\tPrice       float64 `json:\"price\"    `\n\tCode        string  `json:\"code\"       `\n\tImage       string  `json:\"image\"   `\n\tDescription string  `json:\"description\" `\n\tStatus      int     `json:\"status\"   `\n\tIdType      int     `json:\"id-type\"`\n\tScore       int\n\tAge         int\n\tID          int\n}\n\nvar (\n\tstructMap = map[string]any{\n\t\t\"name\":  \"gf\",\n\t\t\"score\": 100,\n\t\t\"Age\":   98,\n\t\t\"ID\":    199,\n\t}\n\n\tstructMapFields8 = map[string]any{\n\t\t\"name\":  \"gf\",\n\t\t\"score\": 100,\n\t\t\"Age\":   98,\n\t\t\"ID\":    199,\n\n\t\t\"category-Id\": \"1\",\n\t\t\"price\":       198.09,\n\t\t\"code\":        \"1\",\n\t\t\"image\":       \"https://goframe.org\",\n\t\t\"description\": \"This is the data for testing eight fields\",\n\t\t\"status\":      1,\n\t\t\"id-type\":     2,\n\t}\n\n\tstructObj = structType{\n\t\tName:  \"john\",\n\t\tScore: 60,\n\t\tAge:   98,\n\t\tID:    199,\n\t}\n\tstructPointer = &structType{\n\t\tName:  \"john\",\n\t\tScore: 60,\n\t}\n\tstructPointer8   = &structType8{}\n\tstructPointerNil *structType\n\n\t// struct slice\n\tstructSliceNil []structType\n\tstructSlice    = []structType{\n\t\t{Name: \"john\", Score: 60},\n\t\t{Name: \"smith\", Score: 100},\n\t}\n\t// struct pointer slice\n\tstructPointerSliceNil []*structType\n\tstructPointerSlice    = []*structType{\n\t\t{Name: \"john\", Score: 60},\n\t\t{Name: \"smith\", Score: 100},\n\t}\n)\n\nfunc Benchmark_Struct_Basic(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStruct(structMap, structPointer)\n\t}\n}\n\nfunc Benchmark_doStruct_Fields8_Basic_MapToStruct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tdefaultConverter.Struct(structMapFields8, structPointer8, StructOption{})\n\t}\n}\n\n// *struct -> **struct\nfunc Benchmark_Reflect_PPStruct_PStruct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tv1 := reflect.ValueOf(&structPointerNil)\n\t\tv2 := reflect.ValueOf(structPointer)\n\t\t//if v1.Kind() == reflect.Pointer {\n\t\t//\tif elem := v1.Elem(); elem.Type() == v2.Type() {\n\t\t//\t\telem.Set(v2)\n\t\t//\t}\n\t\t//}\n\t\tv1.Elem().Set(v2)\n\t}\n}\n\nfunc Benchmark_Struct_PPStruct_PStruct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStruct(structPointer, &structPointerNil)\n\t}\n}\n\n// struct -> *struct\nfunc Benchmark_Reflect_PStruct_Struct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tv1 := reflect.ValueOf(structPointer)\n\t\tv2 := reflect.ValueOf(structObj)\n\t\t//if v1.Kind() == reflect.Pointer {\n\t\t//\tif elem := v1.Elem(); elem.Type() == v2.Type() {\n\t\t//\t\telem.Set(v2)\n\t\t//\t}\n\t\t//}\n\t\tv1.Elem().Set(v2)\n\t}\n}\n\nfunc Benchmark_Struct_PStruct_Struct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStruct(structObj, structPointer)\n\t}\n}\n\n// []struct -> *[]struct\nfunc Benchmark_Reflect_PStructs_Structs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tv1 := reflect.ValueOf(&structSliceNil)\n\t\tv2 := reflect.ValueOf(structSlice)\n\t\t//if v1.Kind() == reflect.Pointer {\n\t\t//\tif elem := v1.Elem(); elem.Type() == v2.Type() {\n\t\t//\t\telem.Set(v2)\n\t\t//\t}\n\t\t//}\n\t\tv1.Elem().Set(v2)\n\t}\n}\n\nfunc Benchmark_Structs_PStructs_Structs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStructs(structSlice, &structSliceNil)\n\t}\n}\n\n// []*struct -> *[]*struct\nfunc Benchmark_Reflect_PPStructs_PStructs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tv1 := reflect.ValueOf(&structPointerSliceNil)\n\t\tv2 := reflect.ValueOf(structPointerSlice)\n\t\t//if v1.Kind() == reflect.Pointer {\n\t\t//\tif elem := v1.Elem(); elem.Type() == v2.Type() {\n\t\t//\t\telem.Set(v2)\n\t\t//\t}\n\t\t//}\n\t\tv1.Elem().Set(v2)\n\t}\n}\n\nfunc Benchmark_Structs_PPStructs_PStructs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tStructs(structPointerSlice, &structPointerSliceNil)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_bool_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\tboolTestTrueValue  = true\n\tboolTestFalseValue = false\n)\n\nvar boolTests = []struct {\n\tvalue  any\n\texpect bool\n}{\n\t{true, true},\n\t{false, false},\n\n\t{0, false},\n\t{1, true},\n\n\t{[]byte(\"\"), false},\n\n\t{\"\", false},\n\t{\"0\", false},\n\t{\"1\", true},\n\t{\"123.456\", true},\n\t{\"true\", true},\n\t{\"false\", false},\n\t{\"on\", true},\n\t{\"off\", false},\n\n\t{complex(1, 2), true},\n\t{complex(123.456, 789.123), true},\n\n\t{[3]int{1, 2, 3}, true},\n\t{[]int{1, 2, 3}, true},\n\n\t{map[int]int{1: 1}, true},\n\t{map[string]string{\"Earth\": \"印度洋\"}, true},\n\n\t{struct{}{}, true},\n\t{&struct{}{}, true},\n\t{nil, false},\n\t{(*bool)(nil), false},\n\n\t{&boolTestTrueValue, true},\n\t{&boolTestFalseValue, false},\n\n\t{myBool(true), true},\n\t{myBool(false), false},\n\t{(*myBool)(&boolTestTrueValue), true},\n\t{(*myBool)(&boolTestFalseValue), false},\n\n\t{(*myBool)(nil), false},\n}\n\nfunc TestBool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range boolTests {\n\t\t\tt.AssertEQ(gconv.Bool(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestBools(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Bools(nil), nil)\n\t\tt.AssertEQ(gconv.Bools([]bool{true, false}), []bool{true, false})\n\t\tt.AssertEQ(gconv.Bools([]int{1, 0, 2}), []bool{true, false, true})\n\t\tt.AssertEQ(gconv.Bools([]string{\"true\", \"false\", \"1\", \"0\"}), []bool{true, false, true, false})\n\t\tt.AssertEQ(gconv.Bools([]string{\"t\", \"f\", \"T\", \"F\"}), []bool{true, false, true, false})\n\t\tt.AssertEQ(gconv.Bools([]string{\"True\", \"False\", \"TRUE\", \"FALSE\"}), []bool{true, false, true, false})\n\t\tt.AssertEQ(gconv.Bools([]string{\"yes\", \"no\", \"YES\", \"NO\"}), []bool{true, false, true, false})\n\t\tt.AssertEQ(gconv.Bools([]string{\"on\", \"off\", \"ON\", \"OFF\"}), []bool{true, false, true, false})\n\t\tt.AssertEQ(gconv.Bools([]any{true, 0, \"false\", 1}), []bool{true, false, false, true})\n\t\tt.AssertEQ(gconv.Bools(`[true, false, true]`), []bool{true, false, true})\n\t\tt.AssertEQ(gconv.Bools(\"\"), []bool{})\n\t\tt.AssertEQ(gconv.Bools(\"true\"), []bool{true})\n\t})\n}\n\nfunc TestSliceBool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.SliceBool([]bool{true, false}), []bool{true, false})\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_byte_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar byteTests = []struct {\n\tvalue   any\n\texpect  byte\n\texpects []byte\n}{\n\t{true, 1, []byte{1}},\n\t{false, 0, []byte{0}},\n\n\t{int(0), 0, []byte{0}},\n\t{int(123), 123, []byte{123}},\n\t{int8(123), 123, []byte{123}},\n\t{int16(123), 123, []byte{123, 0}},\n\t{int32(123123123), 179, []byte{179, 181, 86, 7}},\n\t{int64(123123123123123123), 179, []byte{179, 243, 99, 1, 212, 107, 181, 1}},\n\n\t{uint(0), 0, []byte{0}},\n\t{uint(123), 123, []byte{123}},\n\t{uint8(123), 123, []byte{123}},\n\t{uint16(123), 123, []byte{123, 0}},\n\t{uint32(123123123), 179, []byte{179, 181, 86, 7}},\n\t{uint64(123123123123123123), 179, []byte{179, 243, 99, 1, 212, 107, 181, 1}},\n\n\t{uintptr(0), 0, []byte{48}},\n\t{uintptr(123), 123, []byte{49, 50, 51}},\n\n\t{rune(0), 0, []byte{0, 0, 0, 0}},\n\t{rune(49), 49, []byte{49, 0, 0, 0}},\n\n\t{float32(123), 123, []byte{0, 0, 246, 66}},\n\t{float64(123.456), 123, []byte{119, 190, 159, 26, 47, 221, 94, 64}},\n\n\t{[]byte(\"\"), 0, []byte(\"\")},\n\n\t{\"Uranus\", 0, []byte(\"Uranus\")},\n\n\t{complex(1, 2), 0,\n\t\t[]byte{0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 64}},\n\n\t{[3]int{1, 2, 3}, 0, []byte{1, 2, 3}},\n\t{[]int{1, 2, 3}, 0, []byte{1, 2, 3}},\n\n\t{map[int]int{1: 1}, 0, []byte(`{\"1\":1}`)},\n\t{map[string]string{\"Earth\": \"印度洋\"}, 0, []byte(`{\"Earth\":\"印度洋\"}`)},\n\n\t{gvar.New(123), 123, []byte{123}},\n\t{gvar.New(123.456), 123, []byte{119, 190, 159, 26, 47, 221, 94, 64}},\n}\n\nfunc TestByte(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range byteTests {\n\t\t\tt.AssertEQ(gconv.Byte(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestBytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range byteTests {\n\t\t\tt.AssertEQ(gconv.Bytes(test.value), test.expects)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Bytes(nil), nil)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_convert_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestConvert(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Convert(true, \"bool\"), true)\n\t\tt.AssertEQ(gconv.Convert(false, \"bool\"), false)\n\n\t\tt.Assert(gconv.Convert(int(0), \"int\"), int(0))\n\t\tt.Assert(gconv.Convert(int8(0), \"int8\"), int8(0))\n\t\tt.Assert(gconv.Convert(int16(0), \"int16\"), int16(0))\n\t\tt.Assert(gconv.Convert(int32(0), \"int32\"), int32(0))\n\t\tt.Assert(gconv.Convert(int64(1), \"int64\"), int64(1))\n\n\t\tt.Assert(gconv.Convert(uint(0), \"uint\"), uint(0))\n\t\tt.Assert(gconv.Convert(uint8(0), \"uint8\"), uint8(0))\n\t\tt.Assert(gconv.Convert(uint16(0), \"uint16\"), uint16(0))\n\t\tt.Assert(gconv.Convert(uint32(0), \"uint32\"), uint32(0))\n\t\tt.Assert(gconv.Convert(uint64(0), \"uint64\"), uint64(0))\n\n\t\tt.Assert(gconv.Convert(float32(0), \"float32\"), float32(0))\n\t\tt.Assert(gconv.Convert(float64(0), \"float64\"), float64(0))\n\n\t\tt.AssertEQ(gconv.Convert([]int{1, 2}, \"[]int\"), []int{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]int8{1, 2}, \"[]int8}\"), []int8{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]int16{1, 2}, \"[]int16\"), []int16{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]int32{1, 2}, \"[]int32\"), []int32{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]int64{1, 2}, \"[]int64\"), []int64{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]uint{1, 2}, \"[]uint\"), []uint{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]uint8{1, 2}, \"[]uint8}\"), []uint8{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]uint16{1, 2}, \"[]uint16\"), []uint16{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]uint32{1, 2}, \"[]uint32\"), []uint32{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]uint64{1, 2}, \"[]uint64\"), []uint64{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]float32{1, 2}, \"[]float32\"), []float32{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]float64{1, 2}, \"[]float64\"), []float64{1, 2})\n\t\tt.AssertEQ(gconv.Convert([]string{\"1\", \"2\"}, \"[]string\"), []string{\"1\", \"2\"})\n\t\tt.AssertEQ(gconv.Convert([]byte{}, \"[]byte\"), []uint8{})\n\n\t\tvar anyTest any = nil\n\t\tt.AssertEQ(gconv.Convert(anyTest, \"string\"), \"\")\n\t\tt.AssertEQ(gconv.Convert(\"1\", \"string\"), \"1\")\n\n\t\tt.AssertEQ(gconv.Convert(\"1989-01-02\", \"Time\", \"Y-m-d\"),\n\t\t\tgconv.Time(\"1989-01-02\", \"Y-m-d\"))\n\n\t\tt.AssertEQ(gconv.Convert(1989, \"Time\"),\n\t\t\tgconv.Time(\"1970-01-01 08:33:09 +0800 CST\"))\n\t\tt.AssertEQ(gconv.Convert(1989, \"gtime.Time\"),\n\t\t\t*gconv.GTime(\"1970-01-01 08:33:09 +0800 CST\"))\n\t\tt.AssertEQ(gconv.Convert(1989, \"*gtime.Time\"),\n\t\t\tgconv.GTime(1989))\n\t\tt.AssertEQ(gconv.Convert(1989, \"Duration\"),\n\t\t\ttime.Duration(int64(1989)))\n\t\tt.AssertEQ(gconv.Convert(\"1989\", \"Duration\"),\n\t\t\ttime.Duration(int64(1989)))\n\t\tt.AssertEQ(gconv.Convert(\"1989\", \"\"),\n\t\t\t\"1989\")\n\n\t\t// TODO gconv.Convert(gtime.Now(), \"gtime.Time\", 1) = {{0001-01-01 00:00:00 +0000 UTC}}\n\t\tt.AssertEQ(gconv.Convert(gtime.Now(), \"gtime.Time\", 1), *gtime.New())\n\t\tt.AssertEQ(gconv.Convert(gtime.Now(), \"*gtime.Time\", 1), gtime.New())\n\t\tt.AssertEQ(gconv.Convert(gtime.Now(), \"GTime\", 1), *gtime.New())\n\n\t\tvar boolValue bool = true\n\t\tt.Assert(gconv.Convert(boolValue, \"*bool\"), true)\n\t\tt.Assert(gconv.Convert(&boolValue, \"*bool\"), true)\n\n\t\tvar intNum int = 1\n\t\tt.Assert(gconv.Convert(intNum, \"*int\"), int(1))\n\t\tt.Assert(gconv.Convert(&intNum, \"*int\"), int(1))\n\t\tvar int8Num int8 = 1\n\t\tt.Assert(gconv.Convert(int8Num, \"*int8\"), int(1))\n\t\tt.Assert(gconv.Convert(&int8Num, \"*int8\"), int(1))\n\t\tvar int16Num int16 = 1\n\t\tt.Assert(gconv.Convert(int16Num, \"*int16\"), int(1))\n\t\tt.Assert(gconv.Convert(&int16Num, \"*int16\"), int(1))\n\t\tvar int32Num int32 = 1\n\t\tt.Assert(gconv.Convert(int32Num, \"*int32\"), int(1))\n\t\tt.Assert(gconv.Convert(&int32Num, \"*int32\"), int(1))\n\t\tvar int64Num int64 = 1\n\t\tt.Assert(gconv.Convert(int64Num, \"*int64\"), int(1))\n\t\tt.Assert(gconv.Convert(&int64Num, \"*int64\"), int(1))\n\n\t\tvar uintNum uint = 1\n\t\tt.Assert(gconv.Convert(&uintNum, \"*uint\"), int(1))\n\t\tvar uint8Num uint8 = 1\n\t\tt.Assert(gconv.Convert(uint8Num, \"*uint8\"), int(1))\n\t\tt.Assert(gconv.Convert(&uint8Num, \"*uint8\"), int(1))\n\t\tvar uint16Num uint16 = 1\n\t\tt.Assert(gconv.Convert(uint16Num, \"*uint16\"), int(1))\n\t\tt.Assert(gconv.Convert(&uint16Num, \"*uint16\"), int(1))\n\t\tvar uint32Num uint32 = 1\n\t\tt.Assert(gconv.Convert(uint32Num, \"*uint32\"), int(1))\n\t\tt.Assert(gconv.Convert(&uint32Num, \"*uint32\"), int(1))\n\t\tvar uint64Num uint64 = 1\n\t\tt.Assert(gconv.Convert(uint64Num, \"*uint64\"), int(1))\n\t\tt.Assert(gconv.Convert(&uint64Num, \"*uint64\"), int(1))\n\n\t\tvar float32Num float32 = 1.1\n\t\tt.Assert(gconv.Convert(float32Num, \"*float32\"), float32(1.1))\n\t\tt.Assert(gconv.Convert(&float32Num, \"*float32\"), float32(1.1))\n\n\t\tvar float64Num float64 = 1.1\n\t\tt.Assert(gconv.Convert(float64Num, \"*float64\"), float64(1.1))\n\t\tt.Assert(gconv.Convert(&float64Num, \"*float64\"), float64(1.1))\n\n\t\tvar stringValue string = \"1\"\n\t\tt.Assert(gconv.Convert(stringValue, \"*string\"), \"1\")\n\t\tt.Assert(gconv.Convert(&stringValue, \"*string\"), \"1\")\n\n\t\tvar durationValue time.Duration = 1989\n\t\tvar expectDurationValue = time.Duration(int64(1989))\n\t\tt.AssertEQ(gconv.Convert(&durationValue, \"*time.Duration\"),\n\t\t\t&expectDurationValue)\n\t\tt.AssertEQ(gconv.Convert(durationValue, \"*time.Duration\"),\n\t\t\t&expectDurationValue)\n\n\t\tvar mapStrInt = map[string]int{\"k1\": 1}\n\t\tvar mapStrStr = map[string]string{\"k1\": \"1\"}\n\t\tvar mapStrAny = map[string]any{\"k1\": 1}\n\t\tt.AssertEQ(gconv.Convert(mapStrInt, \"map[string]string\"), mapStrStr)\n\t\tt.AssertEQ(gconv.Convert(mapStrInt, \"map[string]any\"), mapStrAny)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_converter_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype converterStructInTest struct {\n\tName string\n}\n\ntype converterStructOutTest struct {\n\tPlace string\n}\n\nfunc TestRegisterConverter(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := gconv.RegisterConverter(\n\t\t\tfunc(in converterStructInTest) (*converterStructOutTest, error) {\n\t\t\t\treturn &converterStructOutTest{\n\t\t\t\t\tPlace: in.Name,\n\t\t\t\t}, nil\n\t\t\t},\n\t\t)\n\t\tt.AssertNil(err)\n\t})\n\n\t// Test failure cases.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar err error\n\t\terr = gconv.RegisterConverter(123)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.RegisterConverter(func() {})\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.RegisterConverter(\n\t\t\tfunc(in *converterStructInTest) (*converterStructOutTest, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.RegisterConverter(\n\t\t\tfunc(in converterStructInTest) (converterStructOutTest, error) {\n\t\t\t\treturn converterStructOutTest{}, nil\n\t\t\t},\n\t\t)\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.RegisterConverter(\n\t\t\tfunc(in converterStructInTest) (*converterStructOutTest, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tconverterStructIn  = converterStructInTest{\"小行星带\"}\n\t\t\tconverterStructOut converterStructOutTest\n\t\t)\n\t\terr := gconv.Scan(converterStructIn, &converterStructOut)\n\t\tt.AssertNil(err)\n\t\tt.Assert(converterStructOut.Place, converterStructIn.Name)\n\t})\n}\n\nfunc TestConvertWithRefer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.ConvertWithRefer(\"1\", 100), 1)\n\t\tt.AssertEQ(gconv.ConvertWithRefer(\"1.01\", 1.111), 1.01)\n\t\tt.AssertEQ(gconv.ConvertWithRefer(\"1.01\", \"1.111\"), \"1.01\")\n\t\tt.AssertEQ(gconv.ConvertWithRefer(\"1.01\", false), true)\n\t\tt.AssertNE(gconv.ConvertWithRefer(\"1.01\", false), false)\n\t})\n}\n\nfunc testAnyToMyInt(from any, to reflect.Value) error {\n\tswitch x := from.(type) {\n\tcase int:\n\t\tto.SetInt(123456)\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported type %T(%v)\", x, x)\n\t}\n\treturn nil\n}\n\nfunc testAnyToSqlNullType(_ any, to reflect.Value) error {\n\tif to.Kind() != reflect.Pointer {\n\t\tto = to.Addr()\n\t}\n\treturn to.Interface().(sql.Scanner).Scan(123456)\n}\n\nfunc TestNewConverter(t *testing.T) {\n\ttype Dst[T any] struct {\n\t\tA T\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconv := gconv.NewConverter()\n\t\tconv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((*myInt)(nil)))\n\t\tvar dst Dst[myInt]\n\t\terr := conv.Struct(map[string]any{\n\t\t\t\"a\": 1200,\n\t\t}, &dst, gconv.StructOption{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(dst, Dst[myInt]{\n\t\t\tA: 123456,\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconv := gconv.NewConverter()\n\t\tconv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((myInt)(0)))\n\t\tvar dst Dst[*myInt]\n\t\terr := conv.Struct(map[string]any{\n\t\t\t\"a\": 1200,\n\t\t}, &dst, gconv.StructOption{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(*dst.A, 123456)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconv := gconv.NewConverter()\n\t\tconv.RegisterAnyConverterFunc(testAnyToSqlNullType, reflect.TypeOf((*sql.Scanner)(nil)))\n\t\ttype sqlNullDst struct {\n\t\t\tA sql.Null[int]\n\t\t\tB sql.Null[float32]\n\t\t\tC sql.NullInt64\n\t\t\tD sql.NullString\n\n\t\t\tE *sql.Null[int]\n\t\t\tF *sql.Null[float32]\n\t\t\tG *sql.NullInt64\n\t\t\tH *sql.NullString\n\t\t}\n\t\tvar dst sqlNullDst\n\t\terr := conv.Struct(map[string]any{\n\t\t\t\"a\": 12,\n\t\t\t\"b\": 34,\n\t\t\t\"c\": 56,\n\t\t\t\"d\": \"sqlNullString\",\n\t\t\t\"e\": 12,\n\t\t\t\"f\": 34,\n\t\t\t\"g\": 56,\n\t\t\t\"h\": \"sqlNullString\",\n\t\t}, &dst, gconv.StructOption{})\n\t\tt.AssertNil(err)\n\t\tt.Assert(dst, sqlNullDst{\n\t\t\tA: sql.Null[int]{V: 123456, Valid: true},\n\t\t\tB: sql.Null[float32]{V: 123456, Valid: true},\n\t\t\tC: sql.NullInt64{Int64: 123456, Valid: true},\n\t\t\tD: sql.NullString{String: \"123456\", Valid: true},\n\n\t\t\tE: &sql.Null[int]{V: 123456, Valid: true},\n\t\t\tF: &sql.Null[float32]{V: 123456, Valid: true},\n\t\t\tG: &sql.NullInt64{Int64: 123456, Valid: true},\n\t\t\tH: &sql.NullString{String: \"123456\", Valid: true},\n\t\t})\n\t})\n}\n\ntype UserInput struct {\n\tName     string\n\tAge      int\n\tIsActive bool\n}\n\ntype UserModel struct {\n\tID       int\n\tFullName string\n\tAge      int\n\tStatus   int\n}\n\nfunc userInput2Model(in any, out reflect.Value) error {\n\tif out.Type() == reflect.TypeOf(&UserModel{}) {\n\t\tif input, ok := in.(UserInput); ok {\n\t\t\tmodel := UserModel{\n\t\t\t\tID:       1,\n\t\t\t\tFullName: input.Name,\n\t\t\t\tAge:      input.Age,\n\t\t\t\tStatus:   0,\n\t\t\t}\n\t\t\tif input.IsActive {\n\t\t\t\tmodel.Status = 1\n\t\t\t}\n\t\t\tout.Elem().Set(reflect.ValueOf(model))\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"unsupported type %T to UserModel\", in)\n\t}\n\treturn fmt.Errorf(\"unsupported type %s\", out.Type())\n}\n\nfunc TestConverter_RegisterAnyConverterFunc(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconverter := gconv.NewConverter()\n\t\tconverter.RegisterAnyConverterFunc(userInput2Model, reflect.TypeOf(UserModel{}))\n\t\tvar (\n\t\t\tmodel UserModel\n\t\t\tinput = UserInput{Name: \"sam\", Age: 30, IsActive: true}\n\t\t)\n\t\terr := converter.Scan(input, &model)\n\t\tt.AssertNil(err)\n\t\tt.Assert(model, UserModel{\n\t\t\tID:       1,\n\t\t\tFullName: \"sam\",\n\t\t\tAge:      30,\n\t\t\tStatus:   1,\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconverter := gconv.NewConverter()\n\t\tconverter.RegisterAnyConverterFunc(userInput2Model, reflect.TypeOf(&UserModel{}))\n\t\tvar (\n\t\t\tmodel UserModel\n\t\t\tinput = UserInput{Name: \"sam\", Age: 30, IsActive: true}\n\t\t)\n\t\terr := converter.Scan(input, &model)\n\t\tt.AssertNil(err)\n\t\tt.Assert(model, UserModel{\n\t\t\tID:       1,\n\t\t\tFullName: \"sam\",\n\t\t\tAge:      30,\n\t\t\tStatus:   1,\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_custom_base_type_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\ntype (\n\tmyInt   int\n\tmyInt8  int8\n\tmyInt16 int16\n\tmyInt32 int32\n\tmyInt64 int64\n\n\tmyUint   uint\n\tmyUint8  uint8\n\tmyUint16 uint16\n\tmyUint32 uint32\n\tmyUint64 uint64\n\n\tmyFloat32 float32\n\tmyFloat64 float64\n\n\tmyBool bool\n\n\tmyString string\n)\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_float_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\t// Please Note:\n\t// When the type is float32 or a custom type defined based on float32,\n\t// switching to float64 may result in a few extra decimal places.\n\tfloat32TestValue = float32(123)\n\tfloat64TestValue = float64(123.456)\n)\n\nvar floatTests = []struct {\n\tvalue    any\n\texpect32 float32\n\texpect64 float64\n}{\n\t{true, 1, 1},\n\t{false, 0, 0},\n\n\t{int(0), 0, 0},\n\t{int(123), 123, 123},\n\t{int8(123), 123, 123},\n\t{int16(123), 123, 123},\n\t{int32(123), 123, 123},\n\t{int64(123), 123, 123},\n\n\t{uint(0), 0, 0},\n\t{uint(123), 123, 123},\n\t{uint8(123), 123, 123},\n\t{uint16(123), 123, 123},\n\t{uint32(123), 123, 123},\n\t{uint64(123), 123, 123},\n\n\t{uintptr(0), 0, 0},\n\t{uintptr(123), 123, 123},\n\n\t{rune(0), 0, 0},\n\t{rune(49), 49, 49},\n\n\t{float32(123), 123, 123},\n\t{float64(123.456), 123.456, 123.456},\n\n\t{[]byte(\"\"), 0, 0},\n\n\t{\"0\", 0, 0},\n\t{\"\", 0, 0},\n\t{\"1\", 1, 1},\n\t{\"123.456\", 123.456, 123.456},\n\t{\"true\", 0, 0},\n\t{\"false\", 0, 0},\n\t{\"on\", 0, 0},\n\t{\"off\", 0, 0},\n\t{\"NaN\", float32(math.NaN()), math.NaN()},\n\n\t{complex(1, 2), 0, 0},\n\t{complex(123.456, 789.123), 0, 0},\n\n\t{[3]int{1, 2, 3}, 0, 0},\n\t{[]int{1, 2, 3}, 0, 0},\n\n\t{map[int]int{1: 1}, 0, 0},\n\t{map[string]string{\"Earth\": \"太平洋\"}, 0, 0},\n\n\t{struct{}{}, 0, 0},\n\t{nil, 0, 0},\n\t{(*float32)(nil), 0, 0},\n\t{(*float64)(nil), 0, 0},\n\n\t{gvar.New(123), 123, 123},\n\t{gvar.New(123.456), 123.456, 123.456},\n\n\t{&float32TestValue, 123, 123},\n\t{&float64TestValue, 123.456, 123.456},\n\n\t{myFloat32(123), 123, 123},\n\t{myFloat64(123.456), 123.456, 123.456},\n\n\t{(*myFloat32)(&float32TestValue), 123, 123},\n\t{(*myFloat64)(&float64TestValue), 123.456, 123.456},\n\n\t{(*myFloat32)(nil), 0, 0},\n\t{(*myFloat64)(nil), 0, 0},\n}\n\nfunc TestFloat32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range floatTests {\n\t\t\tt.AssertEQ(gconv.Float32(test.value), test.expect32)\n\t\t}\n\t})\n}\n\nfunc TestFloat64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range floatTests {\n\t\t\tt.AssertEQ(gconv.Float64(test.value), test.expect64)\n\t\t}\n\t})\n}\n\nfunc TestFloat32s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range floatTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Float32s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tfloat32s  = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []float32{\n\t\t\t\t\ttest.expect32, test.expect32,\n\t\t\t\t}\n\t\t\t)\n\t\t\tfloat32s = reflect.Append(float32s, reflect.ValueOf(test.value))\n\t\t\tfloat32s = reflect.Append(float32s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Float32s(float32s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceFloat32(float32s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Float32s(\"\"), []float32{})\n\t\tt.AssertEQ(gconv.Float32s(\"123\"), []float32{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Float32s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]float32{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Float32s([]any{1, 2, 3}), []float32{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Float32s(\n\t\t\tgvar.New([]float32{1, 2, 3}),\n\t\t), []float32{1, 2, 3})\n\t})\n}\n\nfunc TestFloat64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range floatTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Float64s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tfloat64s  = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []float64{\n\t\t\t\t\ttest.expect64, test.expect64,\n\t\t\t\t}\n\t\t\t)\n\t\t\tfloat64s = reflect.Append(float64s, reflect.ValueOf(test.value))\n\t\t\tfloat64s = reflect.Append(float64s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Float64s(float64s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceFloat64(float64s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Float64s(\"\"), []float64{})\n\t\tt.AssertEQ(gconv.Float64s(\"123\"), []float64{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Float64s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]float64{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Float64s([]any{1, 2, 3}), []float64{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Float64s(\n\t\t\tgvar.New([]float64{1, 2, 3}),\n\t\t), []float64{1, 2, 3})\n\t})\n}\n\n// gconv.Floats uses gconv.Float64s.\nfunc TestFloats(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range floatTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Floats(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tfloat64s  = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []float64{\n\t\t\t\t\ttest.expect64, test.expect64,\n\t\t\t\t}\n\t\t\t)\n\t\t\tfloat64s = reflect.Append(float64s, reflect.ValueOf(test.value))\n\t\t\tfloat64s = reflect.Append(float64s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Floats(float64s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceFloat(float64s.Interface()), expects)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_int_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\tintTestValue   = 123\n\tint8TestValue  = int8(123)\n\tint16TestValue = int16(123)\n\tint32TestValue = int32(123)\n\tint64TestValue = int64(123)\n)\n\nvar intTests = []struct {\n\tvalue    any\n\texpect   int\n\texpect8  int8\n\texpect16 int16\n\texpect32 int32\n\texpect64 int64\n}{\n\t{true, 1, 1, 1, 1, 1},\n\t{false, 0, 0, 0, 0, 0},\n\n\t{int(0), 0, 0, 0, 0, 0},\n\t{int(123), 123, 123, 123, 123, 123},\n\t{int8(123), 123, 123, 123, 123, 123},\n\t{int16(123), 123, 123, 123, 123, 123},\n\t{int32(123), 123, 123, 123, 123, 123},\n\t{int64(123), 123, 123, 123, 123, 123},\n\n\t{uint(0), 0, 0, 0, 0, 0},\n\t{uint(123), 123, 123, 123, 123, 123},\n\t{uint8(123), 123, 123, 123, 123, 123},\n\t{uint16(123), 123, 123, 123, 123, 123},\n\t{uint32(123), 123, 123, 123, 123, 123},\n\t{uint64(123), 123, 123, 123, 123, 123},\n\n\t{uintptr(0), 0, 0, 0, 0, 0},\n\t{uintptr(123), 123, 123, 123, 123, 123},\n\n\t{rune(0), 0, 0, 0, 0, 0},\n\t{rune(49), 49, 49, 49, 49, 49},\n\n\t{float32(123), 123, 123, 123, 123, 123},\n\t{float64(123.456), 123, 123, 123, 123, 123},\n\n\t{[]byte(\"\"), 0, 0, 0, 0, 0},\n\n\t{\"\", 0, 0, 0, 0, 0},\n\t{\"0\", 0, 0, 0, 0, 0},\n\t{\"1\", 1, 1, 1, 1, 1},\n\t{\"+1\", 1, 1, 1, 1, 1},\n\t{\"-1\", -1, -1, -1, -1, -1},\n\t{\"0xA\", 10, 10, 10, 10, 10},\n\t{\"-0xA\", -10, -10, -10, -10, -10},\n\t{\"0XA\", 10, 10, 10, 10, 10},\n\t{\"-0XA\", -10, -10, -10, -10, -10},\n\t{\"123.456\", 123, 123, 123, 123, 123},\n\t{\"-123.456\", -123, -123, -123, -123, -123},\n\t{\"true\", 0, 0, 0, 0, 0},\n\t{\"false\", 0, 0, 0, 0, 0},\n\t{\"on\", 0, 0, 0, 0, 0},\n\t{\"off\", 0, 0, 0, 0, 0},\n\t{\"NaN\", 0, 0, 0, 0, 0},\n\n\t{complex(1, 2), 0, 0, 0, 0, 0},\n\t{complex(123.456, 789.123), 0, 0, 0, 0, 0},\n\n\t{[3]int{1, 2, 3}, 0, 0, 0, 0, 0},\n\t{[]int{1, 2, 3}, 0, 0, 0, 0, 0},\n\n\t{map[int]int{1: 1}, 0, 0, 0, 0, 0},\n\t{map[string]string{\"Earth\": \"大西洋\"}, 0, 0, 0, 0, 0},\n\n\t{struct{}{}, 0, 0, 0, 0, 0},\n\t{nil, 0, 0, 0, 0, 0},\n\n\t{(*int)(nil), 0, 0, 0, 0, 0},\n\t{(*int8)(nil), 0, 0, 0, 0, 0},\n\t{(*int16)(nil), 0, 0, 0, 0, 0},\n\t{(*int32)(nil), 0, 0, 0, 0, 0},\n\t{(*int64)(nil), 0, 0, 0, 0, 0},\n\n\t{gvar.New(123), 123, 123, 123, 123, 123},\n\t{gvar.New(123.456), 123, 123, 123, 123, 123},\n\n\t{&intTestValue, 123, 123, 123, 123, 123},\n\t{&int8TestValue, 123, 123, 123, 123, 123},\n\t{&int16TestValue, 123, 123, 123, 123, 123},\n\t{&int32TestValue, 123, 123, 123, 123, 123},\n\t{&int64TestValue, 123, 123, 123, 123, 123},\n\n\t{(myInt)(intTestValue), 123, 123, 123, 123, 123},\n\t{(myInt8)(int8TestValue), 123, 123, 123, 123, 123},\n\t{(myInt16)(int16TestValue), 123, 123, 123, 123, 123},\n\t{(myInt32)(int32TestValue), 123, 123, 123, 123, 123},\n\t{(myInt64)(int64TestValue), 123, 123, 123, 123, 123},\n\n\t{(*myInt)(&intTestValue), 123, 123, 123, 123, 123},\n\t{(*myInt8)(&int8TestValue), 123, 123, 123, 123, 123},\n\t{(*myInt16)(&int16TestValue), 123, 123, 123, 123, 123},\n\t{(*myInt32)(&int32TestValue), 123, 123, 123, 123, 123},\n\t{(*myInt64)(&int64TestValue), 123, 123, 123, 123, 123},\n\n\t{(*myInt)(nil), 0, 0, 0, 0, 0},\n\t{(*myInt8)(nil), 0, 0, 0, 0, 0},\n\t{(*myInt16)(nil), 0, 0, 0, 0, 0},\n\t{(*myInt32)(nil), 0, 0, 0, 0, 0},\n\t{(*myInt64)(nil), 0, 0, 0, 0, 0},\n}\n\nfunc TestInt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tt.AssertEQ(gconv.Int(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestInt8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tt.AssertEQ(gconv.Int8(test.value), test.expect8)\n\t\t}\n\t})\n}\n\nfunc TestInt16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tt.AssertEQ(gconv.Int16(test.value), test.expect16)\n\t\t}\n\t})\n}\n\nfunc TestInt32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tt.AssertEQ(gconv.Int32(test.value), test.expect32)\n\t\t}\n\t})\n}\n\nfunc TestInt64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tt.AssertEQ(gconv.Int64(test.value), test.expect64)\n\t\t}\n\t})\n}\n\nfunc TestInts(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Ints(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tints      = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []int{\n\t\t\t\t\ttest.expect, test.expect,\n\t\t\t\t}\n\t\t\t)\n\t\t\tints = reflect.Append(ints, reflect.ValueOf(test.value))\n\t\t\tints = reflect.Append(ints, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Ints(ints.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceInt(ints.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Ints(\"\"), []int{})\n\t\tt.AssertEQ(gconv.Ints(\"123\"), []int{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Ints([]uint8(`{\"Name\":\"Earth\"}`)),\n\t\t\t[]int{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Ints([]any{1, 2, 3}), []int{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Ints(\n\t\t\tgvar.New([]int{1, 2, 3}),\n\t\t), []int{1, 2, 3})\n\n\t\t// array\n\t\tt.AssertEQ(gconv.Ints(\"[1, 2]\"), []int{1, 2})\n\t})\n}\n\nfunc TestInt32s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Int32s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tint32s    = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []int32{\n\t\t\t\t\ttest.expect32, test.expect32,\n\t\t\t\t}\n\t\t\t)\n\t\t\tint32s = reflect.Append(int32s, reflect.ValueOf(test.value))\n\t\t\tint32s = reflect.Append(int32s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Int32s(int32s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceInt32(int32s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Int32s(\"\"), []int32{})\n\t\tt.AssertEQ(gconv.Int32s(\"123\"), []int32{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Int32s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]int32{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Int32s([]any{1, 2, 3}), []int32{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Int32s(\n\t\t\tgvar.New([]int32{1, 2, 3}),\n\t\t), []int32{1, 2, 3})\n\t})\n}\n\nfunc TestInt64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range intTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Int64s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tint64s    = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []int64{\n\t\t\t\t\ttest.expect64, test.expect64,\n\t\t\t\t}\n\t\t\t)\n\t\t\tint64s = reflect.Append(int64s, reflect.ValueOf(test.value))\n\t\t\tint64s = reflect.Append(int64s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Int64s(int64s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceInt64(int64s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Int64s(\"\"), []int64{})\n\t\tt.AssertEQ(gconv.Int64s(\"123\"), []int64{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Int64s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]int64{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Int64s([]any{1, 2, 3}), []int64{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Int64s(\n\t\t\tgvar.New([]int64{1, 2, 3}),\n\t\t), []int64{1, 2, 3})\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_interfaces_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar interfacesTests = []struct {\n\tvalue  any\n\texpect []any\n}{\n\t{[]bool{true, false}, []any{true, false}},\n\n\t{[]int{0, 1, 2}, []any{0, 1, 2}},\n\t{[]int8{0, 1, 2}, []any{0, 1, 2}},\n\t{[]int16{0, 1, 2}, []any{0, 1, 2}},\n\t{[]int32{0, 1, 2}, []any{0, 1, 2}},\n\t{[]int64{0, 1, 2}, []any{0, 1, 2}},\n\n\t{[]uint{0, 1, 2}, []any{0, 1, 2}},\n\t{[]uint8{0, 1, 2}, []any{0, 1, 2}},\n\t{[]uint16{0, 1, 2}, []any{0, 1, 2}},\n\t{[]uint32{0, 1, 2}, []any{0, 1, 2}},\n\t{[]uint64{0, 1, 2}, []any{0, 1, 2}},\n\n\t{[]uintptr{0, 1, 2}, []any{0, 1, 2}},\n\t{[]rune{0, 1, 2}, []any{0, 1, 2}},\n\n\t{[]float32{0, 1, 2}, []any{0, 1, 2}},\n\t{[]float64{0, 1, 2}, []any{0, 1, 2}},\n\n\t{[][]byte{[]byte(\"0\"), []byte(\"1\"), []byte(\"2\")},\n\t\t[]any{[]byte(\"0\"), []byte(\"1\"), []byte(\"2\")}},\n\t{[]string{\"0\", \"1\", \"2\"}, []any{\"0\", \"1\", \"2\"}},\n\n\t{[]complex64{0, 1, 2}, []any{0 + 0i, 1 + 0i, 2 + 0i}},\n\t{[]complex128{0, 1, 2}, []any{0 + 0i, 1 + 0i, 2 + 0i}},\n\n\t{[]any{0, 1, 2}, []any{0, 1, 2}},\n\t{nil, nil},\n}\n\nfunc TestInterfaces(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range interfacesTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Interfaces(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tt.AssertEQ(gconv.Interfaces(test.value), test.expect)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// https://github.com/gogf/gf/issues/1227\nfunc Test_Issue1227(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype StructFromIssue1227 struct {\n\t\t\tName string `json:\"n1\"`\n\t\t}\n\t\ttests := []struct {\n\t\t\tname   string\n\t\t\torigin any\n\t\t\twant   string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:   \"Case1\",\n\t\t\t\torigin: `{\"n1\":\"n1\"}`,\n\t\t\t\twant:   \"n1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case2\",\n\t\t\t\torigin: `{\"name\":\"name\"}`,\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case3\",\n\t\t\t\torigin: `{\"NaMe\":\"NaMe\"}`,\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case4\",\n\t\t\t\torigin: g.Map{\"n1\": \"n1\"},\n\t\t\t\twant:   \"n1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case5\",\n\t\t\t\torigin: g.Map{\"NaMe\": \"n1\"},\n\t\t\t\twant:   \"n1\",\n\t\t\t},\n\t\t}\n\t\tfor _, tt := range tests {\n\t\t\tp := StructFromIssue1227{}\n\t\t\tif err := gconv.Struct(tt.origin, &p); err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t}\n\t\t\tt.Assert(p.Name, tt.want)\n\t\t}\n\t})\n\n\t// Chinese key.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype StructFromIssue1227 struct {\n\t\t\tName string `json:\"中文Key\"`\n\t\t}\n\t\ttests := []struct {\n\t\t\tname   string\n\t\t\torigin any\n\t\t\twant   string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:   \"Case1\",\n\t\t\t\torigin: `{\"中文Key\":\"n1\"}`,\n\t\t\t\twant:   \"n1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case2\",\n\t\t\t\torigin: `{\"Key\":\"name\"}`,\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case3\",\n\t\t\t\torigin: `{\"NaMe\":\"NaMe\"}`,\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case4\",\n\t\t\t\torigin: g.Map{\"中文Key\": \"n1\"},\n\t\t\t\twant:   \"n1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case5\",\n\t\t\t\torigin: g.Map{\"中文KEY\": \"n1\"},\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:   \"Case5\",\n\t\t\t\torigin: g.Map{\"KEY\": \"n1\"},\n\t\t\t\twant:   \"\",\n\t\t\t},\n\t\t}\n\t\tfor _, tt := range tests {\n\t\t\tp := StructFromIssue1227{}\n\t\t\tif err := gconv.Struct(tt.origin, &p); err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t}\n\t\t\t//t.Log(tt)\n\t\t\tt.Assert(p.Name, tt.want)\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1607\ntype issue1607Float64 float64\n\nfunc (f *issue1607Float64) UnmarshalValue(value any) error {\n\tif v, ok := value.(*big.Rat); ok {\n\t\tf64, _ := v.Float64()\n\t\t*f = issue1607Float64(f64)\n\t}\n\treturn nil\n}\n\nfunc Test_Issue1607(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Demo struct {\n\t\t\tB issue1607Float64\n\t\t}\n\t\trat := &big.Rat{}\n\t\trat.SetFloat64(1.5)\n\n\t\tvar demos = make([]Demo, 1)\n\t\terr := gconv.Scan([]map[string]any{\n\t\t\t{\"A\": 1, \"B\": rat},\n\t\t}, &demos)\n\t\tt.AssertNil(err)\n\t\tt.Assert(demos[0].B, 1.5)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1946\nfunc Test_Issue1946(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tinit *gtype.Bool\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tB *B\n\t\t}\n\t\ta := &A{\n\t\t\tB: &B{\n\t\t\t\tinit: gtype.NewBool(true),\n\t\t\t},\n\t\t}\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"B\": g.Map{\n\t\t\t\t\"Name\": \"init\",\n\t\t\t},\n\t\t}, a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.B.Name, \"init\")\n\t\tt.Assert(a.B.init.Val(), true)\n\t})\n\t// It cannot change private attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tinit *gtype.Bool\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tB *B\n\t\t}\n\t\ta := &A{\n\t\t\tB: &B{\n\t\t\t\tinit: gtype.NewBool(true),\n\t\t\t},\n\t\t}\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"B\": g.Map{\n\t\t\t\t\"init\": 0,\n\t\t\t\t\"Name\": \"init\",\n\t\t\t},\n\t\t}, a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.B.Name, \"init\")\n\t\tt.Assert(a.B.init.Val(), true)\n\t})\n\t// It can change public attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype B struct {\n\t\t\tInit *gtype.Bool\n\t\t\tName string\n\t\t}\n\t\ttype A struct {\n\t\t\tB *B\n\t\t}\n\t\ta := &A{\n\t\t\tB: &B{\n\t\t\t\tInit: gtype.NewBool(),\n\t\t\t},\n\t\t}\n\t\terr := gconv.Struct(g.Map{\n\t\t\t\"B\": g.Map{\n\t\t\t\t\"Init\": 1,\n\t\t\t\t\"Name\": \"init\",\n\t\t\t},\n\t\t}, a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.B.Name, \"init\")\n\t\tt.Assert(a.B.Init.Val(), true)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2381\nfunc Test_Issue2381(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Inherit struct {\n\t\t\tId        int64       `json:\"id\"          description:\"Id\"`\n\t\t\tFlag      *gjson.Json `json:\"flag\"        description:\"标签\"`\n\t\t\tTitle     string      `json:\"title\"       description:\"标题\"`\n\t\t\tCreatedAt *gtime.Time `json:\"createdAt\"   description:\"创建时间\"`\n\t\t}\n\t\ttype Test1 struct {\n\t\t\tInherit\n\t\t}\n\t\ttype Test2 struct {\n\t\t\tInherit\n\t\t}\n\t\tvar (\n\t\t\ta1 Test1\n\t\t\ta2 Test2\n\t\t)\n\n\t\ta1 = Test1{\n\t\t\tInherit{\n\t\t\t\tId:        2,\n\t\t\t\tFlag:      gjson.New(\"[1, 2]\"),\n\t\t\t\tTitle:     \"测试\",\n\t\t\t\tCreatedAt: gtime.Now(),\n\t\t\t},\n\t\t}\n\t\terr := gconv.Scan(a1, &a2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a1.Id, a2.Id)\n\t\tt.Assert(a1.Title, a2.Title)\n\t\tt.Assert(a1.CreatedAt, a2.CreatedAt)\n\t\tt.Assert(a1.Flag.String(), a2.Flag.String())\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2391\nfunc Test_Issue2391(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Inherit struct {\n\t\t\tIds   []int\n\t\t\tIds2  []int64\n\t\t\tFlag  *gjson.Json\n\t\t\tTitle string\n\t\t}\n\n\t\ttype Test1 struct {\n\t\t\tInherit\n\t\t}\n\t\ttype Test2 struct {\n\t\t\tInherit\n\t\t}\n\n\t\tvar (\n\t\t\ta1 Test1\n\t\t\ta2 Test2\n\t\t)\n\n\t\ta1 = Test1{\n\t\t\tInherit{\n\t\t\t\tIds:   []int{1, 2, 3},\n\t\t\t\tIds2:  []int64{4, 5, 6},\n\t\t\t\tFlag:  gjson.New(\"[\\\"1\\\", \\\"2\\\"]\"),\n\t\t\t\tTitle: \"测试\",\n\t\t\t},\n\t\t}\n\n\t\terr := gconv.Scan(a1, &a2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(a1.Ids, a2.Ids)\n\t\tt.Assert(a1.Ids2, a2.Ids2)\n\t\tt.Assert(a1.Title, a2.Title)\n\t\tt.Assert(a1.Flag.String(), a2.Flag.String())\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2395\nfunc Test_Issue2395(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Test struct {\n\t\t\tNum int\n\t\t}\n\t\tvar ()\n\t\tobj := Test{Num: 0}\n\t\tt.Assert(gconv.Interfaces(obj), []any{obj})\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2371\nfunc Test_Issue2371(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\ts = struct {\n\t\t\t\tTime time.Time `json:\"time\"`\n\t\t\t}{}\n\t\t\tjsonMap = map[string]any{\"time\": \"2022-12-15 16:11:34\"}\n\t\t)\n\n\t\terr := gconv.Struct(jsonMap, &s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.Time.UTC(), `2022-12-15 08:11:34 +0000 UTC`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2901\nfunc Test_Issue2901(t *testing.T) {\n\ttype GameApp2 struct {\n\t\tForceUpdateTime *time.Time\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := map[string]any{\n\t\t\t\"FORCE_UPDATE_TIME\": time.Now(),\n\t\t}\n\t\tm := GameApp2{}\n\t\terr := gconv.Scan(src, &m)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3006\nfunc Test_Issue3006(t *testing.T) {\n\ttype tFF struct {\n\t\tVal1 json.RawMessage            `json:\"val1\"`\n\t\tVal2 []json.RawMessage          `json:\"val2\"`\n\t\tVal3 map[string]json.RawMessage `json:\"val3\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tff := &tFF{}\n\t\tvar tmp = map[string]any{\n\t\t\t\"val1\": map[string]any{\"hello\": \"world\"},\n\t\t\t\"val2\": []any{map[string]string{\"hello\": \"world\"}},\n\t\t\t\"val3\": map[string]map[string]string{\"val3\": {\"hello\": \"world\"}},\n\t\t}\n\n\t\terr := gconv.Struct(tmp, ff)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(ff, nil)\n\t\tt.Assert(ff.Val1, []byte(`{\"hello\":\"world\"}`))\n\t\tt.AssertEQ(len(ff.Val2), 1)\n\t\tt.Assert(ff.Val2[0], []byte(`{\"hello\":\"world\"}`))\n\t\tt.AssertEQ(len(ff.Val3), 1)\n\t\tt.Assert(ff.Val3[\"val3\"], []byte(`{\"hello\":\"world\"}`))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3731\nfunc Test_Issue3731(t *testing.T) {\n\ttype Data struct {\n\t\tDoc map[string]any `json:\"doc\"`\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdataMap := map[string]any{\n\t\t\t\"doc\": map[string]any{\n\t\t\t\t\"craft\": nil,\n\t\t\t},\n\t\t}\n\n\t\tvar args Data\n\t\terr := gconv.Struct(dataMap, &args)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(\"<nil>\", fmt.Sprintf(\"%T\", args.Doc[\"craft\"]))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3764\nfunc Test_Issue3764(t *testing.T) {\n\ttype T struct {\n\t\tTrue     bool  `json:\"true\"`\n\t\tFalse    bool  `json:\"false\"`\n\t\tTruePtr  *bool `json:\"true_ptr\"`\n\t\tFalsePtr *bool `json:\"false_ptr\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttrueValue := true\n\t\tfalseValue := false\n\t\tm := g.Map{\n\t\t\t\"true\":      trueValue,\n\t\t\t\"false\":     falseValue,\n\t\t\t\"true_ptr\":  &trueValue,\n\t\t\t\"false_ptr\": &falseValue,\n\t\t}\n\t\ttt := &T{}\n\t\terr := gconv.Struct(m, &tt)\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(tt.True, true)\n\t\tt.AssertEQ(tt.False, false)\n\t\tt.AssertEQ(*tt.TruePtr, trueValue)\n\t\tt.AssertEQ(*tt.FalsePtr, falseValue)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3789\nfunc Test_Issue3789(t *testing.T) {\n\ttype ItemSecondThird struct {\n\t\tSecondID uint64 `json:\"secondId,string\"`\n\t\tThirdID  uint64 `json:\"thirdId,string\"`\n\t}\n\ttype ItemFirst struct {\n\t\tID uint64 `json:\"id,string\"`\n\t\tItemSecondThird\n\t}\n\ttype ItemInput struct {\n\t\tItemFirst\n\t}\n\ttype HelloReq struct {\n\t\tg.Meta `path:\"/hello\" method:\"GET\"`\n\t\tItemInput\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := map[string]any{\n\t\t\t\"id\":       1,\n\t\t\t\"secondId\": 2,\n\t\t\t\"thirdId\":  3,\n\t\t}\n\t\tvar dest HelloReq\n\t\terr := gconv.Scan(m, &dest)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dest.ID, uint64(1))\n\t\tt.Assert(dest.SecondID, uint64(2))\n\t\tt.Assert(dest.ThirdID, uint64(3))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3797\nfunc Test_Issue3797(t *testing.T) {\n\ttype Option struct {\n\t\tF1 int\n\t\tF2 string\n\t}\n\ttype Rule struct {\n\t\tID   int64     `json:\"id\"`\n\t\tRule []*Option `json:\"rule\"`\n\t}\n\ttype Res1 struct {\n\t\tg.Meta\n\t\tRule\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar r = &Rule{\n\t\t\tID: 100,\n\t\t}\n\t\tvar res = &Res1{}\n\t\tfor i := 0; i < 10000; i++ {\n\t\t\terr := gconv.Scan(r, res)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(res.ID, 100)\n\t\t\tt.AssertEQ(res.Rule.Rule, nil)\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3800\nfunc Test_Issue3800(t *testing.T) {\n\t// might be random assignment in converting,\n\t// it here so runs multiple times to reproduce the issue.\n\tfor i := 0; i < 1000; i++ {\n\t\tdoTestIssue3800(t)\n\t}\n}\n\nfunc doTestIssue3800(t *testing.T) {\n\ttype NullID string\n\n\ttype StructA struct {\n\t\tSuperior    string `json:\"superior\"`\n\t\tUpdatedTick int    `json:\"updated_tick\"`\n\t}\n\ttype StructB struct {\n\t\tSuperior    *NullID `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t}\n\n\ttype StructC struct {\n\t\tSuperior    string `json:\"superior\"`\n\t\tUpdatedTick int    `json:\"updated_tick\"`\n\t}\n\ttype StructD struct {\n\t\tStructC\n\t\tSuperior    *NullID `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t}\n\n\ttype StructE struct {\n\t\tSuperior    string `json:\"superior\"`\n\t\tUpdatedTick int    `json:\"updated_tick\"`\n\t}\n\ttype StructF struct {\n\t\tSuperior    *NullID `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t\tStructE\n\t}\n\n\ttype StructG struct {\n\t\tSuperior    string `json:\"superior\"`\n\t\tUpdatedTick int    `json:\"updated_tick\"`\n\t}\n\ttype StructH struct {\n\t\tSuperior    *string `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t\tStructG\n\t}\n\n\ttype StructI struct {\n\t\tMaster struct {\n\t\t\tSuperior    *NullID `json:\"superior\"`\n\t\t\tUpdatedTick int     `json:\"updated_tick\"`\n\t\t} `json:\"master\"`\n\t}\n\ttype StructJ struct {\n\t\tStructA\n\t\tSuperior    *NullID `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t}\n\n\ttype StructK struct {\n\t\tMaster struct {\n\t\t\tSuperior    *NullID `json:\"superior\"`\n\t\t\tUpdatedTick int     `json:\"updated_tick\"`\n\t\t} `json:\"master\"`\n\t}\n\ttype StructL struct {\n\t\tSuperior    *NullID `json:\"superior\"`\n\t\tUpdatedTick *int    `json:\"updated_tick\"`\n\t\tStructA\n\t}\n\n\t// case 0\n\t// NullID should not be initialized.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructA := g.Map{\n\t\t\t\"UpdatedTick\": 10,\n\t\t}\n\t\tstructB := StructB{}\n\t\terr := gconv.Scan(structA, &structB)\n\t\tt.AssertNil(err)\n\t\tt.AssertNil(structB.Superior)\n\t\tt.Assert(*structB.UpdatedTick, structA[\"UpdatedTick\"])\n\t})\n\n\t// case 1\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructA := StructA{\n\t\t\tSuperior:    \"superior100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructB := StructB{}\n\t\terr := gconv.Scan(structA, &structB)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structB.Superior, structA.Superior)\n\t})\n\n\t// case 2\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructA1 := StructA{\n\t\t\tSuperior:    \"100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructB1 := StructB{}\n\t\terr := gconv.Scan(structA1, &structB1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structB1.Superior, structA1.Superior)\n\t\tt.Assert(*structB1.UpdatedTick, structA1.UpdatedTick)\n\t})\n\n\t// case 3\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructC := StructC{\n\t\t\tSuperior:    \"superior100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructD := StructD{}\n\t\terr := gconv.Scan(structC, &structD)\n\t\tt.AssertNil(err)\n\t\tt.Assert(structD.StructC.Superior, structC.Superior)\n\t\tt.Assert(*structD.Superior, structC.Superior)\n\t\tt.Assert(*structD.UpdatedTick, structC.UpdatedTick)\n\t})\n\n\t// case 4\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructC1 := StructC{\n\t\t\tSuperior:    \"100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructD1 := StructD{}\n\t\terr := gconv.Scan(structC1, &structD1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(structD1.StructC.Superior, structC1.Superior)\n\t\tt.Assert(structD1.StructC.UpdatedTick, structC1.UpdatedTick)\n\t\tt.Assert(*structD1.Superior, structC1.Superior)\n\t\tt.Assert(*structD1.UpdatedTick, structC1.UpdatedTick)\n\t})\n\n\t// case 5\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructE := StructE{\n\t\t\tSuperior:    \"superior100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructF := StructF{}\n\t\terr := gconv.Scan(structE, &structF)\n\t\tt.AssertNil(err)\n\t\tt.Assert(structF.StructE.Superior, structE.Superior)\n\t\tt.Assert(structF.StructE.UpdatedTick, structE.UpdatedTick)\n\t\tt.Assert(*structF.Superior, structE.Superior)\n\t\tt.Assert(*structF.UpdatedTick, structE.UpdatedTick)\n\t})\n\n\t// case 6\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructE1 := StructE{\n\t\t\tSuperior:    \"100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructF1 := StructF{}\n\t\terr := gconv.Scan(structE1, &structF1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structF1.Superior, structE1.Superior)\n\t\tt.Assert(*structF1.UpdatedTick, structE1.UpdatedTick)\n\t\tt.Assert(structF1.StructE.Superior, structE1.Superior)\n\t\tt.Assert(structF1.StructE.UpdatedTick, structE1.UpdatedTick)\n\t})\n\n\t// case 7\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructG := StructG{\n\t\t\tSuperior:    \"superior100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructH := StructH{}\n\t\terr := gconv.Scan(structG, &structH)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structH.Superior, structG.Superior)\n\t\tt.Assert(*structH.UpdatedTick, structG.UpdatedTick)\n\t\tt.Assert(structH.StructG.Superior, structG.Superior)\n\t\tt.Assert(structH.StructG.UpdatedTick, structG.UpdatedTick)\n\t})\n\n\t// case 8\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructG1 := StructG{\n\t\t\tSuperior:    \"100\",\n\t\t\tUpdatedTick: 20,\n\t\t}\n\t\tstructH1 := StructH{}\n\t\terr := gconv.Scan(structG1, &structH1)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structH1.Superior, structG1.Superior)\n\t\tt.Assert(*structH1.UpdatedTick, structG1.UpdatedTick)\n\t\tt.Assert(structH1.StructG.Superior, structG1.Superior)\n\t\tt.Assert(structH1.StructG.UpdatedTick, structG1.UpdatedTick)\n\t})\n\n\t// case 9\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructI := StructI{}\n\t\txxx := NullID(\"superior100\")\n\t\tstructI.Master.Superior = &xxx\n\t\tstructI.Master.UpdatedTick = 30\n\t\tstructJ := StructJ{}\n\t\terr := gconv.Scan(structI.Master, &structJ)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structJ.Superior, structI.Master.Superior)\n\t\tt.Assert(*structJ.UpdatedTick, structI.Master.UpdatedTick)\n\t\tt.Assert(structJ.StructA.Superior, structI.Master.Superior)\n\t\tt.Assert(structJ.StructA.UpdatedTick, structI.Master.UpdatedTick)\n\t})\n\n\t// case 10\n\tgtest.C(t, func(t *gtest.T) {\n\t\tstructK := StructK{}\n\t\tyyy := NullID(\"superior100\")\n\t\tstructK.Master.Superior = &yyy\n\t\tstructK.Master.UpdatedTick = 40\n\t\tstructL := StructL{}\n\t\terr := gconv.Scan(structK.Master, &structL)\n\t\tt.AssertNil(err)\n\t\tt.Assert(*structL.Superior, structK.Master.Superior)\n\t\tt.Assert(*structL.UpdatedTick, structK.Master.UpdatedTick)\n\t\tt.Assert(structL.StructA.Superior, structK.Master.Superior)\n\t\tt.Assert(structL.StructA.UpdatedTick, structK.Master.UpdatedTick)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3821\nfunc Test_Issue3821(t *testing.T) {\n\t// Scan\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar record = map[string]any{\n\t\t\t`user_id`:   1,\n\t\t\t`user_name`: \"teemo\",\n\t\t}\n\n\t\ttype DoubleInnerUser struct {\n\t\t\tUserId int64 `orm:\"user_id\"`\n\t\t}\n\n\t\ttype InnerUser struct {\n\t\t\tUserId     int32   `orm:\"user_id\"`\n\t\t\tUserIdBool bool    `orm:\"user_id\"`\n\t\t\tUsername   *string `orm:\"user_name\"`\n\t\t\tUsername2  *string `orm:\"user_name\"`\n\t\t\tUsername3  string  `orm:\"username\"`\n\t\t\t*DoubleInnerUser\n\t\t}\n\n\t\ttype User struct {\n\t\t\tInnerUser\n\t\t\tUserId     int        `orm:\"user_id\"`\n\t\t\tUserIdBool gtype.Bool `orm:\"user_id\"`\n\t\t\tUsername   string     `orm:\"user_name\"`\n\t\t\tUsername2  string     `orm:\"user_name\"`\n\t\t\tUsername3  *string    `orm:\"user_name\"`\n\t\t\tUsername4  string     `orm:\"username\"` // empty string\n\t\t}\n\t\tvar user = &User{}\n\t\terr := gconv.StructTag(record, user, \"orm\")\n\n\t\tt.AssertNil(err)\n\t\tt.AssertEQ(user.UserId, 1)\n\t\tt.AssertEQ(user.UserIdBool.Val(), true)\n\t\tt.AssertEQ(user.Username, \"teemo\")\n\t\tt.AssertEQ(user.Username2, \"teemo\")\n\t\tt.AssertEQ(*user.Username3, \"teemo\")\n\t\tt.AssertEQ(user.Username4, \"\")\n\t\tt.AssertEQ(user.InnerUser.UserId, int32(1))\n\t\tt.AssertEQ(user.InnerUser.UserIdBool, true)\n\t\tt.AssertEQ(*user.InnerUser.Username, \"teemo\")\n\t\tt.AssertEQ(*user.InnerUser.Username2, \"teemo\")\n\t\tt.AssertEQ(user.InnerUser.Username3, \"\")\n\t\tt.AssertEQ(user.DoubleInnerUser.UserId, int64(1))\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3868\nfunc Test_Issue3868(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Config struct {\n\t\t\tEnable   bool\n\t\t\tSpec     string\n\t\t\tPoolSize int\n\t\t}\n\t\tdata := gjson.New(`[{\"enable\":false,\"spec\":\"a\"},{\"enable\":true,\"poolSize\":1}]`)\n\t\tfor i := 0; i < 1000; i++ {\n\t\t\tvar configs []*Config\n\t\t\terr := gconv.Structs(data, &configs)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(configs), 2)\n\t\t\tt.Assert(configs[0], &Config{\n\t\t\t\tEnable: false,\n\t\t\t\tSpec:   \"a\",\n\t\t\t})\n\t\t\tt.Assert(configs[1], &Config{\n\t\t\t\tEnable:   true,\n\t\t\t\tPoolSize: 1,\n\t\t\t})\n\t\t}\n\t})\n}\n\n// https://github.com/gogf/gf/issues/3903\nfunc Test_Issue3903(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype TestA struct {\n\t\t\tUserId int `json:\"UserId\"   orm:\"user_id\"   `\n\t\t}\n\t\ttype TestB struct {\n\t\t\tTestA\n\t\t\tUserId int `json:\"NewUserId\"  description:\"\"`\n\t\t}\n\t\tvar input = map[string]any{\n\t\t\t\"user_id\": gvar.New(100, true),\n\t\t}\n\t\tvar a TestB\n\t\terr := gconv.StructTag(input, &a, \"orm\")\n\t\tt.AssertNil(err)\n\t\tt.Assert(a.TestA.UserId, 100)\n\t\tt.Assert(a.UserId, 100)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4218\nfunc Test_Issue4218(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype SysMenuVo struct {\n\t\t\tMenuId   int64        `json:\"menuId\"     orm:\"menu_id\"`\n\t\t\tMenuName string       `json:\"menuName\"   orm:\"menu_name\"`\n\t\t\tChildren []*SysMenuVo `json:\"children\"   orm:\"children\"`\n\t\t\tParentId int64        `json:\"parentId\"   orm:\"parent_id\"`\n\t\t}\n\t\tmenus := []*SysMenuVo{\n\t\t\t{\n\t\t\t\tMenuId:   1,\n\t\t\t\tMenuName: \"系统管理\",\n\t\t\t\tParentId: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\tMenuId:   2,\n\t\t\t\tMenuName: \"字典查询\",\n\t\t\t\tParentId: 1,\n\t\t\t},\n\t\t}\n\t\tvar parent *SysMenuVo\n\t\terr := gconv.Scan(menus[0], &parent)\n\t\tt.AssertNil(err)\n\t\tt.Assert(parent.MenuId, 1)\n\t\tt.Assert(parent.ParentId, 0)\n\n\t\tparent.Children = append(parent.Children, menus[1])\n\n\t\tt.Assert(len(menus[0].Children), 1)\n\t\tt.Assert(menus[0].Children[0].MenuId, 2)\n\t\tt.Assert(menus[0].Children[0].ParentId, 1)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4542\nfunc Test_Issue4542(t *testing.T) {\n\t// Test case 1: Nested map conversion - map[string]any to map[string]map[string]float64\n\t// This is the original bug report scenario\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ExchangeRate map[string]map[string]float64\n\n\t\t// Source data from JSON unmarshalling (nested map[string]any)\n\t\tsource := map[string]any{\n\t\t\t\"USD\": map[string]any{\n\t\t\t\t\"CNY\": 7.0,\n\t\t\t\t\"EUR\": 0.85,\n\t\t\t},\n\t\t\t\"EUR\": map[string]any{\n\t\t\t\t\"CNY\": 8.2,\n\t\t\t\t\"USD\": 1.18,\n\t\t\t},\n\t\t}\n\n\t\tvar exchangeRate ExchangeRate\n\t\terr := gconv.Scan(source, &exchangeRate)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(exchangeRate), 2)\n\t\tt.Assert(len(exchangeRate[\"USD\"]), 2)\n\t\tt.Assert(exchangeRate[\"USD\"][\"CNY\"], 7.0)\n\t\tt.Assert(exchangeRate[\"USD\"][\"EUR\"], 0.85)\n\t\tt.Assert(exchangeRate[\"EUR\"][\"CNY\"], 8.2)\n\t\tt.Assert(exchangeRate[\"EUR\"][\"USD\"], 1.18)\n\t})\n\n\t// Test case 2: Deeply nested map conversion (3 levels)\n\t// Verifies recursion terminates correctly at base types\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype DeepMap map[string]map[string]map[string]int\n\n\t\tsource := map[string]any{\n\t\t\t\"level1\": map[string]any{\n\t\t\t\t\"level2\": map[string]any{\n\t\t\t\t\t\"level3\": 100,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tvar deepMap DeepMap\n\t\terr := gconv.Scan(source, &deepMap)\n\t\tt.AssertNil(err)\n\t\tt.Assert(deepMap[\"level1\"][\"level2\"][\"level3\"], 100)\n\t})\n\n\t// Test case 3: Map with different key types\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsource := map[string]any{\n\t\t\t\"1\": map[string]any{\n\t\t\t\t\"value\": 100,\n\t\t\t},\n\t\t\t\"2\": map[string]any{\n\t\t\t\t\"value\": 200,\n\t\t\t},\n\t\t}\n\n\t\tvar result map[int]map[string]int\n\t\terr := gconv.Scan(source, &result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[1][\"value\"], 100)\n\t\tt.Assert(result[2][\"value\"], 200)\n\t})\n\n\t// Test case 4: Empty nested map - verifies recursion terminates on empty map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsource := map[string]any{\n\t\t\t\"USD\": map[string]any{},\n\t\t}\n\n\t\tvar result map[string]map[string]float64\n\t\terr := gconv.Scan(source, &result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(result), 1)\n\t\tt.Assert(len(result[\"USD\"]), 0)\n\t})\n\n\t// Test case 5: Mixed struct and map in nested structure\n\t// Verifies struct conversion still works (no regression)\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Config struct {\n\t\t\tName  string\n\t\t\tValue int\n\t\t}\n\n\t\tsource := map[string]any{\n\t\t\t\"config1\": map[string]any{\n\t\t\t\t\"Name\":  \"test1\",\n\t\t\t\t\"Value\": 100,\n\t\t\t},\n\t\t\t\"config2\": map[string]any{\n\t\t\t\t\"Name\":  \"test2\",\n\t\t\t\t\"Value\": 200,\n\t\t\t},\n\t\t}\n\n\t\t// Map value is struct - should still work\n\t\tvar result map[string]Config\n\t\terr := gconv.Scan(source, &result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"config1\"].Name, \"test1\")\n\t\tt.Assert(result[\"config1\"].Value, 100)\n\t\tt.Assert(result[\"config2\"].Name, \"test2\")\n\t\tt.Assert(result[\"config2\"].Value, 200)\n\t})\n\n\t// Test case 6: Very deep nesting (5 levels) - stress test for recursion\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsource := map[string]any{\n\t\t\t\"l1\": map[string]any{\n\t\t\t\t\"l2\": map[string]any{\n\t\t\t\t\t\"l3\": map[string]any{\n\t\t\t\t\t\t\"l4\": map[string]any{\n\t\t\t\t\t\t\t\"l5\": \"deep_value\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tvar result map[string]map[string]map[string]map[string]map[string]string\n\t\terr := gconv.Scan(source, &result)\n\t\tt.AssertNil(err)\n\t\tt.Assert(result[\"l1\"][\"l2\"][\"l3\"][\"l4\"][\"l5\"], \"deep_value\")\n\t})\n\n\t// Test case 7: Source value is not a map (should be converted first)\n\t// Verifies no infinite recursion when source doesn't match expected structure\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsource := map[string]any{\n\t\t\t\"key\": \"not_a_map\",\n\t\t}\n\n\t\tvar result map[string]map[string]string\n\t\terr := gconv.Scan(source, &result)\n\t\t// This should not cause infinite recursion, but conversion may fail or return empty\n\t\t// The key point is it should not hang\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype SubMapTest struct {\n\tName string\n}\n\nvar mapTests = []struct {\n\tvalue  any\n\texpect any\n}{\n\t{map[string]int{\"k1\": 1}, map[string]any{\"k1\": 1}},\n\t{map[string]uint{\"k1\": 1}, map[string]any{\"k1\": 1}},\n\t{map[string]string{\"k1\": \"v1\"}, map[string]any{\"k1\": \"v1\"}},\n\t{map[string]float32{\"k1\": 1.1}, map[string]any{\"k1\": 1.1}},\n\t{map[string]float64{\"k1\": 1.1}, map[string]any{\"k1\": 1.1}},\n\t{map[string]bool{\"k1\": true}, map[string]any{\"k1\": true}},\n\t{map[string]any{\"k1\": \"v1\"}, map[string]any{\"k1\": \"v1\"}},\n\n\t{map[any]int{\"k1\": 1}, map[string]any{\"k1\": 1}},\n\t{map[any]uint{\"k1\": 1}, map[string]any{\"k1\": 1}},\n\t{map[any]string{\"k1\": \"v1\"}, map[string]any{\"k1\": \"v1\"}},\n\t{map[any]float32{\"k1\": 1.1}, map[string]any{\"k1\": 1.1}},\n\t{map[any]float64{\"k1\": 1.1}, map[string]any{\"k1\": 1.1}},\n\t{map[any]bool{\"k1\": true}, map[string]any{\"k1\": true}},\n\t{map[any]any{\"k1\": \"v1\"}, map[string]any{\"k1\": \"v1\"}},\n\n\t{map[int]int{1: 1}, map[string]any{\"1\": 1}},\n\t{map[int]string{1: \"v1\"}, map[string]any{\"1\": \"v1\"}},\n\t{map[uint]int{1: 1}, map[string]any{\"1\": 1}},\n\t{map[uint]string{1: \"v1\"}, map[string]any{\"1\": \"v1\"}},\n\n\t{[]int{1, 2, 3}, map[string]any{\"1\": 2, \"3\": nil}},\n\t{[]int{1, 2, 3, 4}, map[string]any{\"1\": 2, \"3\": 4}},\n\n\t{`{\"earth\": \"亚马逊雨林\"}`,\n\t\tmap[string]any{\"earth\": \"亚马逊雨林\"}},\n\t{[]byte(`{\"earth\": \"撒哈拉沙漠\"}`),\n\t\tmap[string]any{\"earth\": \"撒哈拉沙漠\"}},\n\t{`{Earth}`, nil},\n\n\t{\"\", nil},\n\t{[]byte(\"\"), nil},\n\t{`\"{earth亚马逊雨林}`, nil},\n\t{[]byte(`{earth撒哈拉沙漠}`), nil},\n\t{[]byte(`{Earth}`), nil},\n\n\t{nil, nil},\n\n\t{&struct {\n\t\tEarth string\n\t}{\n\t\tEarth: \"大峡谷\",\n\t}, map[string]any{\"Earth\": \"大峡谷\"}},\n\n\t{struct {\n\t\tEarth string\n\t}{\n\t\tEarth: \"马里亚纳海沟\",\n\t}, map[string]any{\"Earth\": \"马里亚纳海沟\"}},\n\n\t{struct {\n\t\tEarth string\n\t\tmars  string\n\t}{\n\t\tEarth: \"大堡礁\",\n\t\tmars:  \"奥林帕斯山\",\n\t}, map[string]any{\"Earth\": \"大堡礁\"}},\n\n\t{struct {\n\t\tEarth string\n\t\tSubMapTest\n\t}{\n\t\tEarth: \"中国\",\n\t\tSubMapTest: SubMapTest{\n\t\t\tName: \"长江\",\n\t\t},\n\t}, map[string]any{\"Earth\": \"中国\", \"Name\": \"长江\"}},\n\n\t{struct {\n\t\tEarth string\n\t\tChina SubMapTest\n\t}{\n\t\tEarth: \"中国\",\n\t\tChina: SubMapTest{\n\t\t\tName: \"黄河\",\n\t\t},\n\t}, map[string]any{\"Earth\": \"中国\", \"China\": map[string]any{\"Name\": \"黄河\"}}},\n\n\t{struct {\n\t\tEarth      string\n\t\tSubMapTest `json:\"sub_map_test\"`\n\t}{\n\t\tEarth: \"中国\",\n\t\tSubMapTest: SubMapTest{\n\t\t\tName: \"淮河\",\n\t\t},\n\t}, map[string]any{\"Earth\": \"中国\", \"sub_map_test\": map[string]any{\"Name\": \"淮河\"}}},\n\n\t{struct {\n\t\tEarth string\n\t\tChina SubMapTest `gconv:\"中国\"`\n\t}{\n\t\tEarth: \"中国\",\n\t\tChina: SubMapTest{\n\t\t\tName: \"黄河\",\n\t\t},\n\t}, map[string]any{\"Earth\": \"中国\", \"中国\": map[string]any{\"Name\": \"黄河\"}}},\n\n\t{struct {\n\t\tChina         string `c:\"中国\"`\n\t\tAmerica       string `c:\"-\"`\n\t\tUnitedKingdom string `c:\"UK,omitempty\"`\n\t}{\n\t\tChina:         \"长城\",\n\t\tAmerica:       \"Statue of Liberty\",\n\t\tUnitedKingdom: \"\",\n\t}, map[string]any{\"中国\": \"长城\", \"UK\": \"\"}},\n\n\t{struct {\n\t\tChina         string `gconv:\"中国\"`\n\t\tAmerica       string `gconv:\"-\"`\n\t\tUnitedKingdom string `c:\"UK,omitempty\"`\n\t}{\n\t\tChina:         \"故宫\",\n\t\tAmerica:       \"White House\",\n\t\tUnitedKingdom: \"\",\n\t}, map[string]any{\"中国\": \"故宫\", \"UK\": \"\"}},\n\n\t{struct {\n\t\tChina         string `json:\"中国\"`\n\t\tAmerica       string `json:\"-\"`\n\t\tUnitedKingdom string `json:\"UK,omitempty\"`\n\t}{\n\t\tChina:         \"东方明珠\",\n\t\tAmerica:       \"Empire State Building\",\n\t\tUnitedKingdom: \"\",\n\t}, map[string]any{\"中国\": \"东方明珠\", \"UK\": \"\"}},\n\n\t{struct {\n\t\tChina   any    `json:\",omitempty\"`\n\t\tAmerica string `json:\",omitempty\"`\n\t}{\n\t\tChina:   \"黄山\",\n\t\tAmerica: \"\",\n\t}, map[string]any{\"China\": \"黄山\", \"America\": \"\"}},\n}\n\nfunc TestMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range mapTests {\n\t\t\tt.Assert(gconv.Map(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestMaps(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range mapTests {\n\t\t\tvar (\n\t\t\t\tmaps    any\n\t\t\t\texpects any\n\t\t\t)\n\n\t\t\tif v, ok := test.value.(string); ok {\n\t\t\t\tmaps = fmt.Sprintf(`[%s,%s]`, v, v)\n\t\t\t} else if v, ok := test.value.([]byte); ok {\n\t\t\t\tmaps = []byte(fmt.Sprintf(`[%s,%s]`, v, v))\n\t\t\t} else if test.value == nil {\n\t\t\t\tmaps = nil\n\t\t\t} else {\n\t\t\t\tmaps = []any{\n\t\t\t\t\ttest.value,\n\t\t\t\t\ttest.value,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif test.expect == nil {\n\t\t\t\texpects = test.expect\n\t\t\t} else {\n\t\t\t\texpects = []any{\n\t\t\t\t\ttest.expect,\n\t\t\t\t\ttest.expect,\n\t\t\t\t}\n\t\t\t}\n\t\t\tt.Assert(gconv.Maps(maps), expects)\n\n\t\t\t// The following is the same as gconv.Maps.\n\t\t\tt.Assert(gconv.MapsDeep(maps), expects)\n\t\t\tt.Assert(gconv.SliceMap(maps), expects)\n\t\t\tt.Assert(gconv.SliceMapDeep(maps), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tmapStrAny := []map[string]any{\n\t\t\t{\"earth\": \"亚马逊雨林\"},\n\t\t\t{\"mars\": \"奥林帕斯山\"},\n\t\t}\n\t\tt.Assert(gconv.Maps(mapStrAny), mapStrAny)\n\n\t\tmapEmpty := []map[string]string{}\n\t\tt.AssertNil(gconv.Maps(mapEmpty))\n\n\t\tt.Assert(gconv.Maps(`test`), nil)\n\t\tt.Assert(gconv.Maps([]byte(`test`)), nil)\n\t})\n}\n\nfunc TestMapsDeepExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype s struct {\n\t\t\tEarth g.Map `c:\"earth_map\"`\n\t\t}\n\n\t\tt.Assert(gconv.MapDeep(&s{\n\t\t\tEarth: g.Map{\n\t\t\t\t\"sea_num\": 4,\n\t\t\t\t\"one_sea\": g.Map{\n\t\t\t\t\t\"sea_name\": \"太平洋\",\n\t\t\t\t},\n\t\t\t\t\"map_sat\": g.MapAnyAny{\n\t\t\t\t\t1:         \"Arctic\",\n\t\t\t\t\t\"Pacific\": 2,\n\t\t\t\t\t\"Indian\":  \"印度洋\",\n\t\t\t\t},\n\t\t\t},\n\t\t}), g.Map{\n\t\t\t\"earth_map\": g.Map{\n\t\t\t\t\"sea_num\": 4,\n\t\t\t\t\"one_sea\": g.Map{\n\t\t\t\t\t\"sea_name\": \"太平洋\",\n\t\t\t\t},\n\t\t\t\t\"map_sat\": g.Map{\n\t\t\t\t\t\"1\":       \"Arctic\",\n\t\t\t\t\t\"Pacific\": 2,\n\t\t\t\t\t\"Indian\":  \"印度洋\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gconv.MapsDeep(`test`), nil)\n\t\tt.Assert(gconv.MapsDeep([]byte(`test`)), nil)\n\t})\n}\n\nfunc TestMapStrStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range mapTests {\n\t\t\tvar expect map[string]any\n\t\t\tif v, ok := test.expect.(map[string]any); ok {\n\t\t\t\texpect = v\n\t\t\t}\n\t\t\tfor k, v := range expect {\n\t\t\t\texpect[k] = gconv.String(v)\n\t\t\t}\n\t\t\tt.Assert(gconv.MapStrStr(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestMapStrStrDeepExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gconv.MapStrStrDeep(map[string]string{\"mars\": \"Syrtis\"}), map[string]string{\"mars\": \"Syrtis\"})\n\t\tt.Assert(gconv.MapStrStrDeep(`{}`), nil)\n\t})\n}\n\nfunc TestMapWithMapOption(t *testing.T) {\n\t// Test for option: Deep.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar testMapDeep = struct {\n\t\t\tEarth      string\n\t\t\tSubMapTest SubMapTest\n\t\t}{\n\t\t\tEarth: \"中国\",\n\t\t\tSubMapTest: SubMapTest{\n\t\t\t\tName: \"黄山\",\n\t\t\t},\n\t\t}\n\t\tvar (\n\t\t\tdt  = gconv.Map(testMapDeep, gconv.MapOption{Deep: true})\n\t\t\tdf  = gconv.Map(testMapDeep, gconv.MapOption{Deep: false})\n\t\t\tdtk = reflect.TypeOf(dt[\"SubMapTest\"]).Kind()\n\t\t\tdfk = reflect.TypeOf(df[\"SubMapTest\"]).Kind()\n\t\t)\n\t\tt.AssertNE(dtk, dfk)\n\t})\n\n\t// Test for option: OmitEmpty.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar testMapOmitEmpty = struct {\n\t\t\tEarth   string\n\t\t\tVenus   int    `gconv:\",omitempty\"`\n\t\t\tMars    string `c:\",omitempty\"`\n\t\t\tMercury any    `json:\",omitempty\"`\n\t\t}{\n\t\t\tEarth:   \"死海\",\n\t\t\tVenus:   0,\n\t\t\tMars:    \"\",\n\t\t\tMercury: nil,\n\t\t}\n\t\tr := gconv.Map(testMapOmitEmpty, gconv.MapOption{OmitEmpty: true})\n\t\tt.Assert(r, map[string]any{\"Earth\": \"死海\"})\n\t})\n\n\t// Test for option: Tags.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar testMapOmitEmpty = struct {\n\t\t\tEarth string `gconv:\"errEarth\" chinese:\"地球\" french:\"Terre\"`\n\t\t}{\n\t\t\tEarth: \"尼莫点\",\n\t\t}\n\t\tc := gconv.Map(testMapOmitEmpty, gconv.MapOption{Tags: []string{\"chinese\", \"french\"}})\n\t\tt.Assert(c, map[string]any{\"地球\": \"尼莫点\"})\n\n\t\tf := gconv.Map(testMapOmitEmpty, gconv.MapOption{Tags: []string{\"french\", \"chinese\"}})\n\t\tt.Assert(f, map[string]any{\"Terre\": \"尼莫点\"})\n\t})\n}\n\nfunc TestMapToMapExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\tvalue  = map[string]string{\"k1\": \"v1\"}\n\t\t\texpect = make(map[string]any)\n\t\t)\n\t\terr = gconv.MapToMap(value, &expect)\n\t\tt.AssertNil(err)\n\t\tt.Assert(value[\"k1\"], expect[\"k1\"])\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := g.Map{\n\t\t\t\"k\": g.Map{\n\t\t\t\t\"name\": \"Earth\",\n\t\t\t},\n\t\t}\n\t\te := make(map[string]SubMapTest)\n\t\terr := gconv.MapToMap(v, &e)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(e), 1)\n\t\tt.Assert(e[\"k\"].Name, \"Earth\")\n\t})\n}\n\nfunc TestMaptoMapsExtra(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tv := g.Slice{\n\t\t\tg.Map{\"id\": 1, \"name\": \"john\"},\n\t\t\tg.Map{\"id\": 2, \"name\": \"smith\"},\n\t\t}\n\t\tvar e []*g.Map\n\t\terr := gconv.MapToMaps(v, &e)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(v), 2)\n\t\tt.Assert(v, e)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_ptr_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestPtrAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v any = 1\n\t\tt.AssertEQ(gconv.PtrAny(v), &v)\n\t})\n}\n\nfunc TestPtrString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v string = \"Pluto\"\n\t\tt.AssertEQ(gconv.PtrString(v), &v)\n\t})\n}\n\nfunc TestPtrBool(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v bool = true\n\t\tt.AssertEQ(gconv.PtrBool(v), &v)\n\t})\n}\n\nfunc TestPtrInt(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v int = 123\n\t\tt.AssertEQ(gconv.PtrInt(v), &v)\n\t})\n}\n\nfunc TestPtrInt8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v int8 = 123\n\t\tt.AssertEQ(gconv.PtrInt8(v), &v)\n\t})\n}\n\nfunc TestPtrInt16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v int16 = 123\n\t\tt.AssertEQ(gconv.PtrInt16(v), &v)\n\t})\n}\n\nfunc TestPtrInt32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v int32 = 123\n\t\tt.AssertEQ(gconv.PtrInt32(v), &v)\n\t})\n}\n\nfunc TestPtrInt64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v int64 = 123\n\t\tt.AssertEQ(gconv.PtrInt64(v), &v)\n\t})\n}\n\nfunc TestPtrUint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v uint = 123\n\t\tt.AssertEQ(gconv.PtrUint(v), &v)\n\t})\n}\n\nfunc TestPtrUint8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v uint8 = 123\n\t\tt.AssertEQ(gconv.PtrUint8(v), &v)\n\t})\n}\n\nfunc TestPtrUint16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v uint16 = 123\n\t\tt.AssertEQ(gconv.PtrUint16(v), &v)\n\t})\n}\n\nfunc TestPtrUint32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v uint32 = 123\n\t\tt.AssertEQ(gconv.PtrUint32(v), &v)\n\t})\n}\n\nfunc TestPtrUint64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v uint64 = 123\n\t\tt.AssertEQ(gconv.PtrUint64(v), &v)\n\t})\n}\n\nfunc TestPtrFloat32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v float32 = 123.456\n\t\tt.AssertEQ(gconv.PtrFloat32(v), &v)\n\t})\n}\n\nfunc TestPtrFloat64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v float64 = 123.456\n\t\tt.AssertEQ(gconv.PtrFloat64(v), &v)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_rune_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar runeTests = []struct {\n\tvalue   any\n\texpect  rune\n\texpects []rune\n}{\n\t{true, 1, []rune(\"true\")},\n\t{false, 0, []rune(\"false\")},\n\n\t{int(0), 0, []rune(\"0\")},\n\t{int(123), 123, []rune(\"123\")},\n\t{int8(123), 123, []rune(\"123\")},\n\t{int16(123), 123, []rune(\"123\")},\n\t{int32(123123123), 123123123, []rune(\"123123123\")},\n\t{int64(123123123123123123), 23327667, []rune(\"123123123123123123\")},\n\n\t{uint(0), 0, []rune(\"0\")},\n\t{uint(123), 123, []rune(\"123\")},\n\t{uint8(123), 123, []rune(\"123\")},\n\t{uint16(123), 123, []rune(\"123\")},\n\t{uint32(123123123), 123123123, []rune(\"123123123\")},\n\t{uint64(123123123123123123), 23327667, []rune(\"123123123123123123\")},\n\n\t{uintptr(0), 0, []rune{48}},\n\t{uintptr(123), 123, []rune{49, 50, 51}},\n\n\t{rune(0), 0, []rune(\"0\")},\n\t{rune(49), 49, []rune(\"49\")},\n\n\t{float32(123), 123, []rune{49, 50, 51}},\n\t{float64(123.456), 123, []rune{49, 50, 51, 46, 52, 53, 54}},\n\n\t{[]rune(\"\"), 0, []rune(\"\")},\n\n\t{\"Uranus\", 0, []rune(\"Uranus\")},\n\n\t{complex(1, 2), 0,\n\t\t[]rune{40, 49, 43, 50, 105, 41}},\n\n\t{[3]int{1, 2, 3}, 0, []rune{91, 49, 44, 50, 44, 51, 93}},\n\t{[]int{1, 2, 3}, 0, []rune{91, 49, 44, 50, 44, 51, 93}},\n\n\t{map[int]int{1: 1}, 0, []rune(`{\"1\":1}`)},\n\t{map[string]string{\"Earth\": \"印度洋\"}, 0, []rune(`{\"Earth\":\"印度洋\"}`)},\n\n\t{gvar.New(123), 123, []rune{49, 50, 51}},\n\t{gvar.New(123.456), 123, []rune{49, 50, 51, 46, 52, 53, 54}},\n}\n\nfunc TestRune(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range runeTests {\n\t\t\tt.AssertEQ(gconv.Rune(test.value), test.expect)\n\t\t}\n\t})\n}\n\nfunc TestRunes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range runeTests {\n\t\t\tt.AssertEQ(gconv.Runes(test.value), test.expects)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_scan_basic_types_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype testScan struct {\n\tSrc    any\n\tDst    any\n\tExpect any\n}\n\nfunc TestScanBasicTypes(t *testing.T) {\n\t// Define test data structure\n\ttype User struct {\n\t\tName string\n\t\tAge  int\n\t}\n\ttype UserWithTag struct {\n\t\tName string `json:\"name\"`\n\t\tAge  int    `json:\"age\"`\n\t}\n\n\t// Prepare test data\n\tvar testScanData = []testScan{\n\t\t// Basic type conversion\n\t\t{1, new(int), 1},\n\t\t{int8(1), new(int16), int16(1)},\n\t\t{int16(1), new(int32), int32(1)},\n\t\t{int32(1), new(int64), int64(1)},\n\t\t{uint(1), new(int), 1},\n\t\t{uint8(1), new(int), 1},\n\t\t{uint16(1), new(int), 1},\n\t\t{uint32(1), new(int), 1},\n\t\t{uint64(1), new(int), 1},\n\t\t{float32(1.0), new(int), 1},\n\t\t{float64(1.0), new(int), 1},\n\t\t{true, new(int), 1},\n\t\t{false, new(int), 0},\n\t\t{\"1\", new(int), 1},\n\t\t{\"true\", new(bool), true},\n\t\t{\"false\", new(bool), false},\n\t\t{1, new(bool), true},\n\t\t{0, new(bool), false},\n\n\t\t// String conversion\n\t\t{1, new(string), \"1\"},\n\t\t{1.1, new(string), \"1.1\"},\n\t\t{true, new(string), \"true\"},\n\t\t{false, new(string), \"false\"},\n\t\t{[]byte(\"hello\"), new(string), \"hello\"},\n\n\t\t// Slice conversion\n\t\t{[]int{1, 2, 3}, new([]string), []string{\"1\", \"2\", \"3\"}},\n\t\t{[]string{\"1\", \"2\", \"3\"}, new([]int), []int{1, 2, 3}},\n\t\t{`[\"1\",\"2\",\"3\"]`, new([]string), []string{\"1\", \"2\", \"3\"}},\n\t\t{`[1,2,3]`, new([]int), []int{1, 2, 3}},\n\n\t\t// Map conversion\n\t\t{\n\t\t\tmap[string]any{\"name\": \"john\", \"age\": 18},\n\t\t\tnew(User),\n\t\t\t&User{Name: \"john\", Age: 18},\n\t\t},\n\t\t{\n\t\t\t`{\"name\":\"john\",\"age\":18}`,\n\t\t\tnew(User),\n\t\t\t&User{Name: \"john\", Age: 18},\n\t\t},\n\t\t{\n\t\t\tmap[string]any{\"name\": \"john\", \"age\": 18},\n\t\t\tnew(UserWithTag),\n\t\t\t&UserWithTag{Name: \"john\", Age: 18},\n\t\t},\n\t\t{\n\t\t\tmap[string]string{\"name\": \"john\", \"age\": \"18\"},\n\t\t\tnew(map[string]any),\n\t\t\t&map[string]any{\"name\": \"john\", \"age\": \"18\"},\n\t\t},\n\n\t\t// Struct conversion\n\t\t{\n\t\t\tUser{Name: \"john\", Age: 18},\n\t\t\tnew(map[string]any),\n\t\t\t&map[string]any{\"Name\": \"john\", \"Age\": 18},\n\t\t},\n\t\t{\n\t\t\t&User{Name: \"john\", Age: 18},\n\t\t\tnew(UserWithTag),\n\t\t\t&UserWithTag{Name: \"john\", Age: 18},\n\t\t},\n\n\t\t// Special cases\n\t\t{nil, new(any), nil},\n\t\t{nil, new(*int), (*int)(nil)},\n\t\t{[]byte(nil), new(string), \"\"},\n\t\t{\"\", new(int), 0},\n\t\t{\"\", new(float64), 0.0},\n\t\t{\"\", new(bool), false},\n\n\t\t// Time type\n\t\t{time.Date(2023, 1, 2, 0, 0, 0, 0, time.Local), new(string), \"2023-01-02 00:00:00\"},\n\n\t\t// Pointer conversion\n\t\t{&User{Name: \"john\"}, new(*User), &User{Name: \"john\"}},\n\t}\n\n\t// Basic types test.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, v := range testScanData {\n\t\t\t// t.Logf(`%#v`, v)\n\t\t\terr := gconv.Scan(v.Src, v.Dst)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\n\t// int -> **int\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tv = 100\n\t\t\ti *int\n\t\t)\n\t\terr := gconv.Scan(v, &i)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(i, nil)\n\t\tt.Assert(*i, v)\n\t})\n\t// *int -> **int\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tv = 100\n\t\t\ti *int\n\t\t)\n\t\terr := gconv.Scan(&v, &i)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(i, nil)\n\t\tt.Assert(*i, v)\n\t})\n\t// string -> **string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tv = \"1000\"\n\t\t\ti *string\n\t\t)\n\t\terr := gconv.Scan(v, &i)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(i, nil)\n\t\tt.Assert(*i, v)\n\t})\n\t// *string -> **string\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tv = \"1000\"\n\t\t\ti *string\n\t\t)\n\t\terr := gconv.Scan(&v, &i)\n\t\tt.AssertNil(err)\n\t\tt.AssertNE(i, nil)\n\t\tt.Assert(*i, v)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_scan_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestScanList(t *testing.T) {\n\ttype EntityUser struct {\n\t\tUid  int\n\t\tName string\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int\n\t\tAddress string\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId    int\n\t\tUid   int\n\t\tScore int\n\t}\n\n\t// Test for struct attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []Entity\n\t\t\tentityUsers = []EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\tuserScores = []EntityUserScores{\n\t\t\t\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t}\n\t\t)\n\t\terr = gconv.ScanList(entityUsers, &entities, \"User\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, &entities, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userScores, &entities, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(entities), 3)\n\t\tt.Assert(entities[0].User, entityUsers[0])\n\t\tt.Assert(entities[1].User, entityUsers[1])\n\t\tt.Assert(entities[2].User, entityUsers[2])\n\n\t\tt.Assert(entities[0].UserDetail, userDetails[0])\n\t\tt.Assert(entities[1].UserDetail, userDetails[1])\n\t\tt.Assert(entities[2].UserDetail, EntityUserDetail{})\n\n\t\tt.Assert(len(entities[0].UserScores), 2)\n\t\tt.Assert(entities[0].UserScores[0], userScores[0])\n\t\tt.Assert(entities[0].UserScores[1], userScores[1])\n\n\t\tt.Assert(len(entities[1].UserScores), 1)\n\t\tt.Assert(entities[1].UserScores[0], userScores[2])\n\n\t\tt.Assert(len(entities[2].UserScores), 0)\n\t})\n\n\t// Test for pointer attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\tUser       *EntityUser\n\t\t\tUserDetail *EntityUserDetail\n\t\t\tUserScores []*EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []*Entity\n\t\t\tentityUsers = []*EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []*EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\tuserScores = []*EntityUserScores{\n\t\t\t\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t}\n\t\t)\n\t\terr = gconv.ScanList(entityUsers, &entities, \"User\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, &entities, \"UserDetail\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userScores, &entities, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(entities), 3)\n\t\tt.Assert(entities[0].User, entityUsers[0])\n\t\tt.Assert(entities[1].User, entityUsers[1])\n\t\tt.Assert(entities[2].User, entityUsers[2])\n\n\t\tt.Assert(entities[0].UserDetail, userDetails[0])\n\t\tt.Assert(entities[1].UserDetail, userDetails[1])\n\t\tt.Assert(entities[2].UserDetail, nil)\n\n\t\tt.Assert(len(entities[0].UserScores), 2)\n\t\tt.Assert(entities[0].UserScores[0], userScores[0])\n\t\tt.Assert(entities[0].UserScores[1], userScores[1])\n\n\t\tt.Assert(len(entities[1].UserScores), 1)\n\t\tt.Assert(entities[1].UserScores[0], userScores[2])\n\n\t\tt.Assert(len(entities[2].UserScores), 0)\n\t})\n\n\t// Test struct embedded attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\tEntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []Entity\n\t\t\tentityUsers = []EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\tuserScores = []EntityUserScores{\n\t\t\t\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t}\n\t\t)\n\t\terr = gconv.Scan(entityUsers, &entities)\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, &entities, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userScores, &entities, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(entities), 3)\n\t\tt.Assert(entities[0].EntityUser, entityUsers[0])\n\t\tt.Assert(entities[1].EntityUser, entityUsers[1])\n\t\tt.Assert(entities[2].EntityUser, entityUsers[2])\n\n\t\tt.Assert(entities[0].UserDetail, userDetails[0])\n\t\tt.Assert(entities[1].UserDetail, userDetails[1])\n\t\tt.Assert(entities[2].UserDetail, EntityUserDetail{})\n\n\t\tt.Assert(len(entities[0].UserScores), 2)\n\t\tt.Assert(entities[0].UserScores[0], userScores[0])\n\t\tt.Assert(entities[0].UserScores[1], userScores[1])\n\n\t\tt.Assert(len(entities[1].UserScores), 1)\n\t\tt.Assert(entities[1].UserScores[0], userScores[2])\n\n\t\tt.Assert(len(entities[2].UserScores), 0)\n\t})\n\n\t// Test struct embedded pointer attribute.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\t*EntityUser\n\t\t\tUserDetail *EntityUserDetail\n\t\t\tUserScores []*EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []Entity\n\t\t\tentityUsers = []EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\tuserScores = []EntityUserScores{\n\t\t\t\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t}\n\t\t)\n\t\terr = gconv.Scan(entityUsers, &entities)\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, &entities, \"UserDetail\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userScores, &entities, \"UserScores\", \"uid\")\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(len(entities), 3)\n\t\tt.Assert(entities[0].EntityUser, entityUsers[0])\n\t\tt.Assert(entities[1].EntityUser, entityUsers[1])\n\t\tt.Assert(entities[2].EntityUser, entityUsers[2])\n\n\t\tt.Assert(entities[0].UserDetail, userDetails[0])\n\t\tt.Assert(entities[1].UserDetail, userDetails[1])\n\t\tt.Assert(entities[2].UserDetail, nil)\n\n\t\tt.Assert(len(entities[0].UserScores), 2)\n\t\tt.Assert(entities[0].UserScores[0], userScores[0])\n\t\tt.Assert(entities[0].UserScores[1], userScores[1])\n\n\t\tt.Assert(len(entities[1].UserScores), 1)\n\t\tt.Assert(entities[1].UserScores[0], userScores[2])\n\n\t\tt.Assert(len(entities[2].UserScores), 0)\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []Entity\n\t\t\tentityUsers = []EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\t//userScores = []EntityUserScores{\n\t\t\t//\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t//\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t//\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t//}\n\t\t)\n\n\t\terr = gconv.ScanList(nil, nil, \"\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(entityUsers, &entities, \"\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.ScanList(entityUsers, &entities, \"User\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, entities, \"User\")\n\t\tt.AssertNE(err, nil)\n\n\t\tvar a int = 1\n\t\terr = gconv.ScanList(userDetails, &a, \"User\")\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestScanListErr(t *testing.T) {\n\ttype EntityUser struct {\n\t\tUid  int\n\t\tName string\n\t}\n\n\ttype EntityUserDetail struct {\n\t\tUid     int\n\t\tAddress string\n\t}\n\n\ttype EntityUserScores struct {\n\t\tId    int\n\t\tUid   int\n\t\tScore int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Entity struct {\n\t\t\tUser       EntityUser\n\t\t\tUserDetail EntityUserDetail\n\t\t\tUserScores []EntityUserScores\n\t\t}\n\n\t\tvar (\n\t\t\terr         error\n\t\t\tentities    []Entity\n\t\t\tentityUsers = []EntityUser{\n\t\t\t\t{Uid: 1, Name: \"name1\"},\n\t\t\t\t{Uid: 2, Name: \"name2\"},\n\t\t\t\t{Uid: 3, Name: \"name3\"},\n\t\t\t}\n\t\t\tuserDetails = []EntityUserDetail{\n\t\t\t\t{Uid: 1, Address: \"address1\"},\n\t\t\t\t{Uid: 2, Address: \"address2\"},\n\t\t\t}\n\t\t\tuserScores = []EntityUserScores{\n\t\t\t\t{Id: 10, Uid: 1, Score: 100},\n\t\t\t\t{Id: 11, Uid: 1, Score: 60},\n\t\t\t\t{Id: 20, Uid: 2, Score: 99},\n\t\t\t}\n\t\t)\n\t\terr = gconv.ScanList(entityUsers, &entities, \"User\")\n\t\tt.AssertNil(err)\n\n\t\terr = gconv.ScanList(userDetails, &entities, \"UserDetail\", \"User\", \"uuid\")\n\t\tt.AssertNE(err, nil)\n\n\t\terr = gconv.ScanList(userScores, &entities, \"UserScores\", \"User\", \"uid\")\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_scan_omit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype User struct {\n\tName  string\n\tAge   int\n\tEmail string\n}\n\ntype User2 struct {\n\tName  *string\n\tAge   int\n\tEmail string\n}\n\ntype Person struct {\n\tName  string\n\tAge   int\n\tEmail string\n}\n\nfunc TestScan_OmitEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{Name: \"\", Age: 20, Email: \"\"}\n\t\tperson := Person{Name: \"zhangsan\", Age: 0, Email: \"old@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(user, &person, gconv.ScanOption{\n\t\t\tOmitEmpty: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"zhangsan\")\n\t\tt.Assert(person.Age, 20)\n\t\tt.Assert(person.Email, \"old@example.com\")\n\t})\n}\n\nfunc TestScan_AllOmitEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{Name: \"\", Age: 0, Email: \"\"}\n\t\tperson := Person{Name: \"zhangsan\", Age: 100, Email: \"old@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(user, &person, gconv.ScanOption{\n\t\t\tOmitEmpty: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"zhangsan\")\n\t\tt.Assert(person.Age, 100)\n\t\tt.Assert(person.Email, \"old@example.com\")\n\t})\n}\n\nfunc TestScan_OmitNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]any{\n\t\t\t\"Name\":  nil,\n\t\t\t\"Age\":   30,\n\t\t\t\"Email\": nil,\n\t\t}\n\t\tperson := Person{Name: \"lisi\", Age: 0, Email: \"old@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(data, &person, gconv.ScanOption{\n\t\t\tOmitNil: true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"lisi\")\n\t\tt.Assert(person.Age, 30)\n\t\tt.Assert(person.Email, \"old@example.com\")\n\t})\n}\n\nfunc TestScan_OmitEmptyAndOmitNil(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]any{\n\t\t\t\"Name\":  \"\",\n\t\t\t\"Age\":   25,\n\t\t\t\"Email\": nil,\n\t\t}\n\t\tperson := Person{Name: \"wangwu\", Age: 0, Email: \"old2@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(data, &person, gconv.ScanOption{\n\t\t\tOmitEmpty: true,\n\t\t\tOmitNil:   true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"wangwu\")\n\t\tt.Assert(person.Age, 25)\n\t\tt.Assert(person.Email, \"old2@example.com\")\n\t})\n}\n\nfunc TestScan_NoOmitOptions(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{Name: \"\", Age: 20, Email: \"\"}\n\t\tperson := Person{Name: \"zhangsan\", Age: 30, Email: \"old@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(user, &person, gconv.ScanOption{\n\t\t\tOmitEmpty: false,\n\t\t\tOmitNil:   false,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"\")\n\t\tt.Assert(person.Age, 20)\n\t\tt.Assert(person.Email, \"\")\n\t})\n}\n\nfunc TestScan_OriginalBehavior(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser := User{Name: \"newname\", Age: 25, Email: \"new@example.com\"}\n\t\tperson := Person{Name: \"\", Age: 0, Email: \"\"}\n\n\t\terr := gconv.Scan(user, &person)\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"newname\")\n\t\tt.Assert(person.Age, 25)\n\t\tt.Assert(person.Email, \"new@example.com\")\n\t})\n}\n\nfunc TestScan_StructOmitEmptyAndOmitNilOptions(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tuser2 := User2{Name: nil, Age: 25, Email: \"\"}\n\t\tperson := Person{Name: \"wangwu\", Age: 0, Email: \"old2@example.com\"}\n\n\t\terr := gconv.ScanWithOptions(user2, &person, gconv.ScanOption{\n\t\t\tOmitEmpty: true,\n\t\t\tOmitNil:   true,\n\t\t})\n\t\tt.AssertNil(err)\n\t\tt.Assert(person.Name, \"wangwu\")\n\t\tt.Assert(person.Age, 25)\n\t\tt.Assert(person.Email, \"old2@example.com\")\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_scan_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype scanStructTest struct {\n\tName  string\n\tPlace string\n}\n\ntype scanExpectTest struct {\n\tmapStrStr map[string]string\n\tmapStrAny map[string]any\n\tmapAnyAny map[any]any\n\n\tstructSub    scanStructTest\n\tstructSubPtr *scanStructTest\n}\n\nvar scanValueMapsTest = []map[string]any{\n\t{\"Name\": false, \"Place\": true},\n\t{\"Name\": int(0), \"Place\": int(1)},\n\t{\"Name\": int8(0), \"Place\": int8(1)},\n\t{\"Name\": int16(0), \"Place\": int16(1)},\n\t{\"Name\": int32(0), \"Place\": int32(1)},\n\t{\"Name\": int64(0), \"Place\": int64(1)},\n\t{\"Name\": uint(0), \"Place\": uint(1)},\n\t{\"Name\": uint8(0), \"Place\": uint8(1)},\n\t{\"Name\": uint16(0), \"Place\": uint16(1)},\n\t{\"Name\": uint32(0), \"Place\": uint32(1)},\n\t{\"Name\": uint64(0), \"Place\": uint64(1)},\n\t{\"Name\": float32(0), \"Place\": float32(1)},\n\t{\"Name\": float64(0), \"Place\": float64(1)},\n\t{\"Name\": \"Mercury\", \"Place\": \"卡罗利斯盆地\"},\n\t{\"Name\": []byte(\"Saturn\"), \"Place\": []byte(\"土星环\")},\n\t{\"Name\": complex64(0), \"Place\": complex64(1 + 2i)},\n\t{\"Name\": complex128(0), \"Place\": complex128(1 + 2i)},\n\t{\"Name\": any(0), \"Place\": any(\"1\")},\n\t{\"Name\": gvar.New(\"Jupiter\"), \"Place\": gvar.New(\"大红斑\")},\n\t{\"Name\": gtime.New(\"2024-01-01 01:01:01\"), \"Place\": gtime.New(\"2021-01-01 01:01:01\")},\n\t{\"Name\": map[string]string{\"Name\": \"Sun\"}, \"Place\": map[string]string{\"Place\": \"太阳黑子\"}},\n\t{\"Name\": []string{\"Earth\", \"Moon\"}, \"Place\": []string{\"好望角\", \"万户环形山\"}},\n}\n\nvar scanValueStructsTest = []scanStructTest{\n\t{\"Venus\", \"阿佛洛狄特高原\"},\n}\n\nvar scanValueJsonTest = []string{\n\t`{\"Name\": \"Mars\", \"Place\": \"奥林帕斯山\"}`,\n}\n\nvar scanExpects = scanExpectTest{\n\tmapStrStr: make(map[string]string),\n\tmapStrAny: make(map[string]any),\n\tmapAnyAny: make(map[any]any),\n\n\tstructSub:    scanStructTest{},\n\tstructSubPtr: &scanStructTest{},\n}\n\nfunc TestScan(t *testing.T) {\n\t// Test for map converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueMapsTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrStr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.mapStrStr[\"Name\"])\n\t\t\tt.Assert(test[\"Place\"], scanExpects.mapStrStr[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrAny)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.mapStrAny[\"Name\"])\n\t\t\tt.Assert(test[\"Place\"], scanExpects.mapStrAny[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapAnyAny)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.mapAnyAny[\"Name\"])\n\t\t\tt.Assert(test[\"Place\"], scanExpects.mapAnyAny[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSub)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.structSub.Name)\n\t\t\tt.Assert(test[\"Place\"], scanExpects.structSub.Place)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSubPtr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.structSubPtr.Name)\n\t\t\tt.Assert(test[\"Place\"], scanExpects.structSubPtr.Place)\n\n\t\t}\n\t})\n\n\t// Test for slice map converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueMapsTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t\tmaps        = []map[string]any{test, test}\n\t\t\t)\n\n\t\t\tvar mss = []map[string]string{scanExpects.mapStrStr, scanExpects.mapStrStr}\n\t\t\terr = gconv.Scan(maps, &mss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(mss), len(maps))\n\t\t\tfor k := range maps {\n\t\t\t\tt.Assert(maps[k][\"Name\"], mss[k][\"Name\"])\n\t\t\t\tt.Assert(maps[k][\"Place\"], mss[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar msa = []map[string]any{scanExpects.mapStrAny, scanExpects.mapStrAny}\n\t\t\terr = gconv.Scan(maps, &msa)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(msa), len(maps))\n\t\t\tfor k := range maps {\n\t\t\t\tt.Assert(maps[k][\"Name\"], msa[k][\"Name\"])\n\t\t\t\tt.Assert(maps[k][\"Place\"], msa[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar maa = []map[any]any{scanExpects.mapAnyAny, scanExpects.mapAnyAny}\n\t\t\terr = gconv.Scan(maps, &maa)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(maa), len(maps))\n\t\t\tfor k := range maps {\n\t\t\t\tt.Assert(maps[k][\"Name\"], maa[k][\"Name\"])\n\t\t\t\tt.Assert(maps[k][\"Place\"], maa[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar ss = []scanStructTest{scanExpects.structSub, scanExpects.structSub}\n\t\t\terr = gconv.Scan(maps, &ss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ss), len(maps))\n\t\t\tfor k := range maps {\n\t\t\t\tt.Assert(maps[k][\"Name\"], ss[k].Name)\n\t\t\t\tt.Assert(maps[k][\"Place\"], ss[k].Place)\n\t\t\t}\n\n\t\t\tvar ssp = []*scanStructTest{scanExpects.structSubPtr, scanExpects.structSubPtr}\n\t\t\terr = gconv.Scan(maps, &ssp)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ssp), len(maps))\n\t\t\tfor k := range maps {\n\t\t\t\tt.Assert(maps[k][\"Name\"], ssp[k].Name)\n\t\t\t\tt.Assert(maps[k][\"Place\"], ssp[k].Place)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Test for struct converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueStructsTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrStr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test.Name, scanExpects.mapStrStr[\"Name\"])\n\t\t\tt.Assert(test.Place, scanExpects.mapStrStr[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrAny)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test.Name, scanExpects.mapStrAny[\"Name\"])\n\t\t\tt.Assert(test.Place, scanExpects.mapStrAny[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapAnyAny)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test.Name, scanExpects.mapAnyAny[\"Name\"])\n\t\t\tt.Assert(test.Place, scanExpects.mapAnyAny[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSub)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test.Name, scanExpects.structSub.Name)\n\t\t\tt.Assert(test.Place, scanExpects.structSub.Place)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSubPtr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test.Name, scanExpects.structSubPtr.Name)\n\t\t\tt.Assert(test.Place, scanExpects.structSubPtr.Place)\n\t\t}\n\t})\n\n\t// Test for slice struct converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueStructsTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t\tstructs     = []scanStructTest{test, test}\n\t\t\t)\n\n\t\t\tvar mss = []map[string]string{scanExpects.mapStrStr, scanExpects.mapStrStr}\n\t\t\terr = gconv.Scan(structs, &mss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(mss), len(structs))\n\t\t\tfor k := range structs {\n\t\t\t\tt.Assert(structs[k].Name, mss[k][\"Name\"])\n\t\t\t\tt.Assert(structs[k].Place, mss[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar msa = []map[string]any{scanExpects.mapStrAny, scanExpects.mapStrAny}\n\t\t\terr = gconv.Scan(structs, &msa)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(msa), len(structs))\n\t\t\tfor k := range structs {\n\t\t\t\tt.Assert(structs[k].Name, msa[k][\"Name\"])\n\t\t\t\tt.Assert(structs[k].Place, msa[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar maa = []map[any]any{scanExpects.mapAnyAny, scanExpects.mapAnyAny}\n\t\t\terr = gconv.Scan(structs, &maa)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(maa), len(structs))\n\t\t\tfor k := range structs {\n\t\t\t\tt.Assert(structs[k].Name, maa[k][\"Name\"])\n\t\t\t\tt.Assert(structs[k].Place, maa[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar ss = []scanStructTest{scanExpects.structSub, scanExpects.structSub}\n\t\t\terr = gconv.Scan(structs, &ss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ss), len(structs))\n\t\t\tfor k := range structs {\n\t\t\t\tt.Assert(structs[k].Name, ss[k].Name)\n\t\t\t\tt.Assert(structs[k].Place, ss[k].Place)\n\t\t\t}\n\n\t\t\tvar ssp = []*scanStructTest{scanExpects.structSubPtr, scanExpects.structSubPtr}\n\t\t\terr = gconv.Scan(structs, &ssp)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ssp), len(structs))\n\t\t\tfor k := range structs {\n\t\t\t\tt.Assert(structs[k].Name, ssp[k].Name)\n\t\t\t\tt.Assert(structs[k].Place, ssp[k].Place)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Test for json converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueJsonTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrStr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(\"Mars\", scanExpects.mapStrStr[\"Name\"])\n\t\t\tt.Assert(\"奥林帕斯山\", scanExpects.mapStrStr[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapStrAny)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(\"Mars\", scanExpects.mapStrAny[\"Name\"])\n\t\t\tt.Assert(\"奥林帕斯山\", scanExpects.mapStrAny[\"Place\"])\n\n\t\t\terr = gconv.Scan(test, &scanExpects.mapAnyAny)\n\t\t\tt.Assert(err, gerror.New(\n\t\t\t\t\"json.UnmarshalUseNumber failed: json: cannot unmarshal object into Go value of type map[interface {}]interface {}\",\n\t\t\t))\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSub)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(\"Mars\", scanExpects.structSub.Name)\n\t\t\tt.Assert(\"奥林帕斯山\", scanExpects.structSub.Place)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSubPtr)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(\"Mars\", scanExpects.structSubPtr.Name)\n\t\t\tt.Assert(\"奥林帕斯山\", scanExpects.structSubPtr.Place)\n\t\t}\n\t})\n\n\t// Test for slice json converting.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueJsonTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr         error\n\t\t\t\tscanExpects = scanExpects\n\t\t\t\tjsons       = fmt.Sprintf(\"[%s, %s]\", test, test)\n\t\t\t)\n\n\t\t\tvar mss = []map[string]string{scanExpects.mapStrStr, scanExpects.mapStrStr}\n\t\t\terr = gconv.Scan(jsons, &mss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(mss), 2)\n\t\t\tfor k := range mss {\n\t\t\t\tt.Assert(\"Mars\", mss[k][\"Name\"])\n\t\t\t\tt.Assert(\"奥林帕斯山\", mss[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar msa = []map[string]any{scanExpects.mapStrAny, scanExpects.mapStrAny}\n\t\t\terr = gconv.Scan(jsons, &msa)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(msa), 2)\n\t\t\tfor k := range msa {\n\t\t\t\tt.Assert(\"Mars\", msa[k][\"Name\"])\n\t\t\t\tt.Assert(\"奥林帕斯山\", msa[k][\"Place\"])\n\t\t\t}\n\n\t\t\tvar maa = []map[any]any{scanExpects.mapAnyAny, scanExpects.mapAnyAny}\n\t\t\terr = gconv.Scan(jsons, &maa)\n\t\t\tt.Assert(err, gerror.New(\n\t\t\t\t\"json.UnmarshalUseNumber failed: json: cannot unmarshal object into Go value of type map[interface {}]interface {}\",\n\t\t\t))\n\n\t\t\tvar ss = []scanStructTest{scanExpects.structSub, scanExpects.structSub}\n\t\t\terr = gconv.Scan(jsons, &ss)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ss), 2)\n\t\t\tfor k := range ss {\n\t\t\t\tt.Assert(\"Mars\", ss[k].Name)\n\t\t\t\tt.Assert(\"奥林帕斯山\", ss[k].Place)\n\t\t\t}\n\n\t\t\tvar ssp = []*scanStructTest{scanExpects.structSubPtr, scanExpects.structSubPtr}\n\t\t\terr = gconv.Scan(jsons, &ssp)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(ssp), 2)\n\t\t\tfor k := range ssp {\n\t\t\t\tt.Assert(\"Mars\", ssp[k].Name)\n\t\t\t\tt.Assert(\"奥林帕斯山\", ssp[k].Place)\n\t\t\t}\n\t\t}\n\t})\n\n\t// Test for paramKeyToAttrMap\n\tgtest.C(t, func(t *gtest.T) {\n\t\tscanValuesTest := scanValueMapsTest\n\t\tfor _, test := range scanValuesTest {\n\t\t\tvar (\n\t\t\t\terr          error\n\t\t\t\tscanExpects  = scanExpects\n\t\t\t\tmapParameter = map[string]string{\"Name\": \"Place\", \"Place\": \"Name\"}\n\t\t\t)\n\n\t\t\terr = gconv.Scan(test, &scanExpects.structSub, mapParameter)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.structSub.Place)\n\t\t\tt.Assert(test[\"Place\"], scanExpects.structSub.Name)\n\n\t\t\t// t.Logf(\"%#v\", test)\n\t\t\terr = gconv.Scan(test, &scanExpects.structSubPtr, mapParameter)\n\t\t\tt.AssertNil(err)\n\t\t\t// t.Logf(\"%#v\", scanExpects.structSubPtr)\n\t\t\tt.Assert(test[\"Name\"], scanExpects.structSubPtr.Place)\n\t\t\tt.Assert(test[\"Place\"], scanExpects.structSubPtr.Name)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr error\n\t\t\tsrc = \"Sun\"\n\t\t\tdst = \"日冕\"\n\t\t)\n\n\t\terr = gconv.Scan(nil, &dst)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dst, \"日冕\")\n\n\t\terr = gconv.Scan(src, nil)\n\t\tt.Assert(err, gerror.New(\"destination pointer should not be nil\"))\n\n\t\t// Test for non-pointer.\n\t\terr = gconv.Scan(src, dst)\n\t\tt.Assert(err, gerror.New(\n\t\t\t\"destination pointer should be type of pointer, but got type: string\",\n\t\t))\n\t})\n}\n\nfunc TestScanEmptyStringToCustomType(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Status string\n\t\ttype Req struct {\n\t\t\tName     string\n\t\t\tStatuses []Status\n\t\t\tTypes    []string\n\t\t}\n\t\tvar (\n\t\t\treq  *Req\n\t\t\tdata = g.Map{\n\t\t\t\t\"Name\":     \"john\",\n\t\t\t\t\"Statuses\": \"\",\n\t\t\t\t\"Types\":    \"\",\n\t\t\t}\n\t\t)\n\t\terr := gconv.Scan(data, &req)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(req.Statuses), 0)\n\t\tt.Assert(len(req.Types), 0)\n\t})\n}\n\nfunc TestScanDeepSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\treq   [][]int\n\t\t\treq2  [][][]int\n\t\t\tdata1 = gjson.New(\"[[1,2,3],[4,5,6]]\")\n\t\t\tdata2 = gjson.New(\"[[[1,2,3]],[[4,5,6]]]\")\n\t\t)\n\t\terr := data1.Scan(&req)\n\t\tt.AssertNil(err)\n\t\terr = gconv.Scan(data1.String(), &req)\n\t\tt.AssertNil(err)\n\t\terr = data2.Scan(&req2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(len(req), 2)\n\t\tt.Assert(len(req2), 2)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_string_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar stringTests = []struct {\n\tvalue  any\n\texpect string\n}{\n\t{true, \"true\"},\n\t{false, \"false\"},\n\n\t{int(0), \"0\"},\n\t{int(123), \"123\"},\n\t{int8(123), \"123\"},\n\t{int16(123), \"123\"},\n\t{int32(123), \"123\"},\n\t{int64(123), \"123\"},\n\n\t{uint(0), \"0\"},\n\t{uint(123), \"123\"},\n\t{uint8(123), \"123\"},\n\t{uint16(123), \"123\"},\n\t{uint32(123), \"123\"},\n\t{uint64(123), \"123\"},\n\n\t{uintptr(0), \"0\"},\n\t{uintptr(123), \"123\"},\n\n\t{rune(0), \"0\"},\n\t{rune(49), \"49\"},\n\n\t{float32(123), \"123\"},\n\t{float64(123.456), \"123.456\"},\n\n\t{[]byte(\"\"), \"\"},\n\n\t{\"\", \"\"},\n\t{\"true\", \"true\"},\n\t{\"false\", \"false\"},\n\t{\"Neptune\", \"Neptune\"},\n\n\t{complex(1, 2), \"(1+2i)\"},\n\t{complex(123.456, 789.123), \"(123.456+789.123i)\"},\n\n\t{[3]int{1, 2, 3}, \"[1,2,3]\"},\n\t{[]int{1, 2, 3}, \"[1,2,3]\"},\n\n\t{map[int]int{1: 1}, `{\"1\":1}`},\n\t{map[string]string{\"Earth\": \"太平洋\"}, `{\"Earth\":\"太平洋\"}`},\n\n\t{struct{}{}, \"{}\"},\n\t{nil, \"\"},\n\t{(*string)(nil), \"\"},\n\n\t{gvar.New(123), \"123\"},\n\t{gvar.New(123.456), \"123.456\"},\n\n\t{goTime, \"1911-10-10 00:00:00 +0000 UTC\"},\n\t{&goTime, \"1911-10-10 00:00:00 +0000 UTC\"},\n\t// TODO The String method of gtime not equals to time.Time\n\t{gfTime, \"1911-10-10 00:00:00\"},\n\t{&gfTime, \"1911-10-10 00:00:00\"},\n\t//{gfTime, \"1911-10-10 00:00:00 +0000 UTC\"},\n\t//{&gfTime, \"1911-10-10 00:00:00 +0000 UTC\"},\n}\n\nvar (\n\tgoTime = time.Date(\n\t\t1911, 10, 10, 0, 0, 0, 0, time.UTC,\n\t)\n\tgfTime = gtime.NewFromTime(goTime)\n)\n\nfunc TestString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range stringTests {\n\t\t\tt.AssertEQ(gconv.String(test.value), test.expect)\n\t\t}\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Strings(nil), nil)\n\t})\n}\n\nfunc TestStrings(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range stringTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Strings(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tstrings   = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []string{\n\t\t\t\t\ttest.expect, test.expect,\n\t\t\t\t}\n\t\t\t)\n\t\t\tstrings = reflect.Append(strings, reflect.ValueOf(test.value))\n\t\t\tstrings = reflect.Append(strings, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Strings(strings.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceStr(strings.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Strings([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]string{\"123\", \"34\", \"78\", \"97\", \"109\", \"101\", \"34\", \"58\", \"34\", \"69\", \"97\", \"114\", \"116\", \"104\", \"34\", \"125\", \"34\"})\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_struct_marshal_unmarshal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/crypto/gcrc32\"\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype MyTime struct {\n\ttime.Time\n}\n\ntype MyTimeSt struct {\n\tServiceDate MyTime\n}\n\nfunc (st *MyTimeSt) UnmarshalValue(v any) error {\n\tm := gconv.Map(v)\n\tt, err := gtime.StrToTime(gconv.String(m[\"ServiceDate\"]))\n\tif err != nil {\n\t\treturn err\n\t}\n\tst.ServiceDate = MyTime{t.Time}\n\treturn nil\n}\n\nfunc TestStructUnmarshalValue1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := &MyTimeSt{}\n\t\terr := gconv.Struct(g.Map{\"ServiceDate\": \"2020-10-10 12:00:01\"}, st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.ServiceDate.Time.Format(\"2006-01-02 15:04:05\"), \"2020-10-10 12:00:01\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := &MyTimeSt{}\n\t\terr := gconv.Struct(g.Map{\"ServiceDate\": nil}, st)\n\t\tt.AssertNil(err)\n\t\tt.Assert(st.ServiceDate.Time.IsZero(), true)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tst := &MyTimeSt{}\n\t\terr := gconv.Struct(g.Map{\"ServiceDate\": \"error\"}, st)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\ntype Pkg struct {\n\tLength uint16 // Total length.\n\tCrc32  uint32 // CRC32.\n\tData   []byte\n}\n\n// NewPkg creates and returns a package with given data.\nfunc NewPkg(data []byte) *Pkg {\n\treturn &Pkg{\n\t\tLength: uint16(len(data) + 6),\n\t\tCrc32:  gcrc32.Encrypt(data),\n\t\tData:   data,\n\t}\n}\n\n// Marshal encodes the protocol struct to bytes.\nfunc (p *Pkg) Marshal() []byte {\n\tb := make([]byte, 6+len(p.Data))\n\tcopy(b, gbinary.EncodeUint16(p.Length))\n\tcopy(b[2:], gbinary.EncodeUint32(p.Crc32))\n\tcopy(b[6:], p.Data)\n\treturn b\n}\n\n// UnmarshalValue decodes bytes to protocol struct.\nfunc (p *Pkg) UnmarshalValue(v any) error {\n\tb := gconv.Bytes(v)\n\tif len(b) < 6 {\n\t\treturn gerror.New(\"invalid package length\")\n\t}\n\tp.Length = gbinary.DecodeToUint16(b[:2])\n\tif len(b) < int(p.Length) {\n\t\treturn gerror.New(\"invalid data length\")\n\t}\n\tp.Crc32 = gbinary.DecodeToUint32(b[2:6])\n\tp.Data = b[6:]\n\tif gcrc32.Encrypt(p.Data) != p.Crc32 {\n\t\treturn gerror.New(\"crc32 validation failed\")\n\t}\n\treturn nil\n}\n\nfunc TestStructUnmarshalValue2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar p1, p2 *Pkg\n\t\tp1 = NewPkg([]byte(\"123\"))\n\t\terr := gconv.Struct(p1.Marshal(), &p2)\n\t\tt.AssertNil(err)\n\t\tt.Assert(p1, p2)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype structExpect struct {\n\tPlanetName   string\n\tPlanet_Place string\n\tplanetTime   string\n}\n\ntype structTagGconvExpect struct {\n\tPlanetNameGconv  string `gconv:\"PlanetName\"`\n\tPlanetPlaceGconv string `gconv:\"-\"`\n}\ntype structTagParamExpect struct {\n\tPlanetNameParam  string `param:\"PlanetName\"`\n\tPlanetPlaceParam string `param:\"-\"`\n}\ntype structTagCExpect struct {\n\tPlanetNameC  string `c:\"PlanetName\"`\n\tPlanetPlaceC string `c:\"-\"`\n}\ntype structTagPExpect struct {\n\tPlanetNameP  string `p:\"PlanetName\"`\n\tPlanetPlaceP string `p:\"-\"`\n}\ntype structTagJsonExpect struct {\n\tPlanetNameJson  string `json:\"PlanetName\"`\n\tPlanetPlaceJson string `json:\"-\"`\n}\n\nvar structValueTests = []map[string]string{\n\t{\n\t\t\"planetname\":  \"Earth\",\n\t\t\"planetplace\": \"亚马逊雨林\",\n\t\t\"planettime\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"planetName\":  \"Earth\",\n\t\t\"planetPlace\": \"亚马逊雨林\",\n\t\t\"planetTime\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"planet-name\":  \"Earth\",\n\t\t\"planet-place\": \"亚马逊雨林\",\n\t\t\"planet-time\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"planet_name\":  \"Earth\",\n\t\t\"planet_place\": \"亚马逊雨林\",\n\t\t\"planet_time\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"planet name\":  \"Earth\",\n\t\t\"planet place\": \"亚马逊雨林\",\n\t\t\"planet time\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PLANETNAME\":  \"Earth\",\n\t\t\"PLANETPLACE\": \"亚马逊雨林\",\n\t\t\"PLANETTIME\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PLANETnAME\":  \"Earth\",\n\t\t\"PLANETpLACE\": \"亚马逊雨林\",\n\t\t\"PLANETtIME\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PLANET-NAME\":  \"Earth\",\n\t\t\"PLANET-PLACE\": \"亚马逊雨林\",\n\t\t\"PLANET-TIME\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PLANET_NAME\":  \"Earth\",\n\t\t\"PLANET_PLACE\": \"亚马逊雨林\",\n\t\t\"PLANET_TIME\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PLANET NAME\":  \"Earth\",\n\t\t\"PLANET PLACE\": \"亚马逊雨林\",\n\t\t\"PLANET TIME\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"PlanetName\":  \"Earth\",\n\t\t\"PlanetPlace\": \"亚马逊雨林\",\n\t\t\"PlanetTime\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"Planet-Name\":  \"Earth\",\n\t\t\"Planet-Place\": \"亚马逊雨林\",\n\t\t\"Planet-Time\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"Planet_Name\":  \"Earth\",\n\t\t\"Planet_Place\": \"亚马逊雨林\",\n\t\t\"Planet_Time\":  \"2021-01-01\",\n\t},\n\t{\n\t\t\"Planet Name\":  \"Earth\",\n\t\t\"Planet Place\": \"亚马逊雨林\",\n\t\t\"Planet Time\":  \"2021-01-01\",\n\t},\n}\n\nfunc TestStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range structValueTests {\n\t\t\tvar (\n\t\t\t\terr    error\n\t\t\t\texpect = new(structExpect)\n\t\t\t)\n\t\t\terr = gconv.Struct(test, expect)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expect.PlanetName, \"Earth\")\n\t\t\tt.Assert(expect.Planet_Place, \"亚马逊雨林\")\n\t\t\tt.Assert(expect.planetTime, \"\")\n\n\t\t\ttagTestValue, ok := test[\"PlanetName\"]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\texpectTagGconv = new(structTagGconvExpect)\n\t\t\t\texpectTagParam = new(structTagParamExpect)\n\t\t\t\texpectTagC     = new(structTagCExpect)\n\t\t\t\texpectTagP     = new(structTagPExpect)\n\t\t\t\texpectTagJson  = new(structTagJsonExpect)\n\t\t\t)\n\t\t\terr = gconv.Struct(test, expectTagGconv)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expectTagGconv.PlanetNameGconv, tagTestValue)\n\t\t\tt.Assert(expectTagGconv.PlanetPlaceGconv, \"\")\n\n\t\t\terr = gconv.Struct(test, expectTagParam)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expectTagParam.PlanetNameParam, tagTestValue)\n\t\t\tt.Assert(expectTagParam.PlanetPlaceParam, \"\")\n\n\t\t\terr = gconv.Struct(test, expectTagC)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expectTagC.PlanetNameC, tagTestValue)\n\t\t\tt.Assert(expectTagC.PlanetPlaceC, \"\")\n\n\t\t\terr = gconv.Struct(test, expectTagP)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expectTagP.PlanetNameP, tagTestValue)\n\t\t\tt.Assert(expectTagP.PlanetPlaceP, \"\")\n\n\t\t\terr = gconv.Struct(test, expectTagJson)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(expectTagJson.PlanetNameJson, tagTestValue)\n\t\t\tt.Assert(expectTagJson.PlanetPlaceJson, \"\")\n\t\t}\n\t})\n\n\t// Test for nil.\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\terr    error\n\t\t\texpect = new(structExpect)\n\t\t)\n\n\t\terr = gconv.Struct(nil, nil)\n\t\tt.AssertNil(err)\n\t\tt.Assert(expect.PlanetName, \"\")\n\t\tt.Assert(expect.Planet_Place, \"\")\n\t\tt.Assert(expect.planetTime, \"\")\n\t})\n}\n\nfunc TestStructDuplicateField(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := map[string]any{\n\t\t\t\"ID\": 100,\n\t\t}\n\t\ttype Nested1 struct {\n\t\t\tID string\n\t\t}\n\t\ttype Nested2 struct {\n\t\t\tID uint\n\t\t}\n\t\ttype Nested3 struct {\n\t\t\tID int\n\t\t}\n\t\ttype Dest struct {\n\t\t\tID int\n\t\t\tNested1\n\t\t\tNested2\n\t\t\tNested3\n\t\t}\n\t\tvar (\n\t\t\terr  error\n\t\t\tdest = new(Dest)\n\t\t)\n\t\terr = gconv.Struct(m, dest)\n\t\tt.AssertNil(err)\n\t\tt.Assert(dest.ID, m[\"ID\"])\n\t\tt.Assert(dest.Nested1.ID, strconv.Itoa(m[\"ID\"].(int)))\n\t\tt.Assert(dest.Nested2.ID, m[\"ID\"])\n\t\tt.Assert(dest.Nested3.ID, m[\"ID\"])\n\t})\n}\n\nfunc TestStructErr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Score struct {\n\t\t\tName   string\n\t\t\tResult int\n\t\t}\n\t\ttype User struct {\n\t\t\tScore Score\n\t\t}\n\n\t\tuser := new(User)\n\t\tscores := map[string]any{\n\t\t\t\"Score\": 1,\n\t\t}\n\t\terr := gconv.Struct(scores, user)\n\t\tt.AssertNE(err, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype CustomString string\n\t\ttype CustomStruct struct {\n\t\t\tS string\n\t\t}\n\t\tvar (\n\t\t\ta CustomString = \"abc\"\n\t\t\tb *CustomStruct\n\t\t)\n\t\terr := gconv.Scan(a, &b)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(b, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar i *int = nil\n\t\terr := gconv.Struct(map[string]string{}, i)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\n// Test for Struct containing time.Time attribute.\nfunc TestStructWithTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype S struct {\n\t\t\tT *gtime.Time\n\t\t}\n\t\tvar (\n\t\t\terr error\n\t\t\tnow = time.Now()\n\t\t\ts   = new(S)\n\t\t)\n\t\terr = gconv.Struct(g.Map{\n\t\t\t\"t\": &now,\n\t\t}, s)\n\t\tt.AssertNil(err)\n\t\tt.Assert(s.T.UTC().Time.String(), now.UTC().String())\n\t})\n}\n\nfunc TestStructs(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range structValueTests {\n\t\t\tvar (\n\t\t\t\terr     error\n\t\t\t\ttests   = []map[string]string{test, test}\n\t\t\t\texpects []*structExpect\n\t\t\t)\n\t\t\terr = gconv.SliceStruct(tests, &expects)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expects), 2)\n\t\t\tfor _, expect := range expects {\n\t\t\t\tt.Assert(expect.PlanetName, \"Earth\")\n\t\t\t\tt.Assert(expect.Planet_Place, \"亚马逊雨林\")\n\t\t\t\tt.Assert(expect.planetTime, \"\")\n\t\t\t}\n\n\t\t\ttagTestValue, ok := test[\"PlanetName\"]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\texpectTagGconvs = []*structTagGconvExpect{}\n\t\t\t\texpectTagParams = []*structTagParamExpect{}\n\t\t\t\texpectTagCs     = []*structTagCExpect{}\n\t\t\t\texpectTagPs     = []*structTagPExpect{}\n\t\t\t\texpectTagJsons  = []*structTagJsonExpect{}\n\t\t\t)\n\n\t\t\terr = gconv.SliceStruct(tests, &expectTagGconvs)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expectTagGconvs), 2)\n\t\t\tfor _, expect := range expectTagGconvs {\n\t\t\t\tt.Assert(expect.PlanetNameGconv, tagTestValue)\n\t\t\t\tt.Assert(expect.PlanetPlaceGconv, \"\")\n\t\t\t}\n\n\t\t\terr = gconv.SliceStruct(tests, &expectTagParams)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expectTagParams), 2)\n\t\t\tfor _, expect := range expectTagParams {\n\t\t\t\tt.Assert(expect.PlanetNameParam, tagTestValue)\n\t\t\t\tt.Assert(expect.PlanetPlaceParam, \"\")\n\t\t\t}\n\n\t\t\terr = gconv.SliceStruct(tests, &expectTagCs)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expectTagCs), 2)\n\t\t\tfor _, expect := range expectTagCs {\n\t\t\t\tt.Assert(expect.PlanetNameC, tagTestValue)\n\t\t\t\tt.Assert(expect.PlanetPlaceC, \"\")\n\t\t\t}\n\n\t\t\terr = gconv.SliceStruct(tests, &expectTagPs)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expectTagPs), 2)\n\t\t\tfor _, expect := range expectTagPs {\n\t\t\t\tt.Assert(expect.PlanetNameP, tagTestValue)\n\t\t\t\tt.Assert(expect.PlanetPlaceP, \"\")\n\t\t\t}\n\n\t\t\terr = gconv.SliceStruct(tests, &expectTagJsons)\n\t\t\tt.AssertNil(err)\n\t\t\tt.Assert(len(expectTagJsons), 2)\n\t\t\tfor _, expect := range expectTagJsons {\n\t\t\t\tt.Assert(expect.PlanetNameJson, tagTestValue)\n\t\t\t\tt.Assert(expect.PlanetPlaceJson, \"\")\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\ntype impUnmarshalValue struct{}\n\nfunc (*impUnmarshalValue) UnmarshalValue(any) error {\n\treturn nil\n}\n\nfunc TestIUnmarshalValue(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar v any = &impUnmarshalValue{}\n\t\t_, ok := (v).(gconv.IUnmarshalValue)\n\t\tt.AssertEQ(ok, true)\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_time_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\ttimeStrTests  = \"2024-04-22 12:00:00.123456789+00:00:00\"\n\ttimeTimeTests = time.Date(\n\t\t2024, 4, 22, 12, 0, 0, 123456789, time.UTC,\n\t)\n)\n\nfunc TestTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Time(nil), time.Time{})\n\t\tt.AssertEQ(gconv.Time(timeTimeTests), timeTimeTests)\n\t})\n}\n\nfunc TestDuration(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.Duration(nil), time.Duration(0))\n\t\tt.AssertEQ(gconv.Duration(timeTimeTests), time.Duration(0))\n\t\tt.AssertEQ(gconv.Duration(\"1m\"), time.Minute)\n\t\tt.AssertEQ(gconv.Duration(time.Hour), time.Hour)\n\t\tt.AssertEQ(gconv.Duration(\"-1\"), time.Duration(-1))\n\t\tt.AssertEQ(gconv.Duration(\"+1\"), time.Duration(1))\n\t})\n}\n\nfunc TestGtime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.AssertEQ(gconv.GTime(\"\"), gtime.New())\n\t\tt.AssertEQ(gconv.GTime(nil), nil)\n\n\t\tt.AssertEQ(gconv.GTime(gtime.New(timeStrTests)), gtime.New(timeStrTests))\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Year(), 2024)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Month(), 4)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Day(), 22)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Hour(), 12)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Minute(), 0)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Second(), 0)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).Nanosecond(), 123456789)\n\t\tt.AssertEQ(gconv.GTime(timeTimeTests).String(), \"2024-04-22 12:00:00\")\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_uint_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nvar (\n\tuintTestValue   = uint(123)\n\tuint8TestValue  = uint8(123)\n\tuint16TestValue = uint16(123)\n\tuint32TestValue = uint32(123)\n\tuint64TestValue = uint64(123)\n)\n\nvar uintTests = []struct {\n\tvalue    any\n\texpect   uint\n\texpect8  uint8\n\texpect16 uint16\n\texpect32 uint32\n\texpect64 uint64\n}{\n\t{true, 1, 1, 1, 1, 1},\n\t{false, 0, 0, 0, 0, 0},\n\n\t{int(0), 0, 0, 0, 0, 0},\n\t{int(123), 123, 123, 123, 123, 123},\n\t{int8(123), 123, 123, 123, 123, 123},\n\t{int16(123), 123, 123, 123, 123, 123},\n\t{int32(123), 123, 123, 123, 123, 123},\n\t{int64(123), 123, 123, 123, 123, 123},\n\n\t{uint(0), 0, 0, 0, 0, 0},\n\t{uint(123), 123, 123, 123, 123, 123},\n\t{uint8(123), 123, 123, 123, 123, 123},\n\t{uint16(123), 123, 123, 123, 123, 123},\n\t{uint32(123), 123, 123, 123, 123, 123},\n\t{uint64(123), 123, 123, 123, 123, 123},\n\n\t{uintptr(0), 0, 0, 0, 0, 0},\n\t{uintptr(123), 123, 123, 123, 123, 123},\n\n\t{rune(0), 0, 0, 0, 0, 0},\n\t{rune(49), 49, 49, 49, 49, 49},\n\n\t{float32(123), 123, 123, 123, 123, 123},\n\t{float64(123.456), 123, 123, 123, 123, 123},\n\n\t{[]byte(\"\"), 0, 0, 0, 0, 0},\n\n\t{\"\", 0, 0, 0, 0, 0},\n\t{\"0\", 0, 0, 0, 0, 0},\n\t{\"1\", 1, 1, 1, 1, 1},\n\t{\"+1\", 1, 1, 1, 1, 1},\n\t{\"0xA\", 10, 10, 10, 10, 10},\n\t{\"0XA\", 10, 10, 10, 10, 10},\n\t{\"123.456\", 123, 123, 123, 123, 123},\n\t{\"true\", 0, 0, 0, 0, 0},\n\t{\"false\", 0, 0, 0, 0, 0},\n\t{\"on\", 0, 0, 0, 0, 0},\n\t{\"off\", 0, 0, 0, 0, 0},\n\t{\"NaN\", 0, 0, 0, 0, 0},\n\n\t{complex(1, 2), 0, 0, 0, 0, 0},\n\t{complex(123.456, 789.123), 0, 0, 0, 0, 0},\n\n\t{[3]int{1, 2, 3}, 0, 0, 0, 0, 0},\n\t{[]int{1, 2, 3}, 0, 0, 0, 0, 0},\n\n\t{map[int]int{1: 1}, 0, 0, 0, 0, 0},\n\t{map[string]string{\"Earth\": \"珠穆朗玛峰\"}, 0, 0, 0, 0, 0},\n\n\t{struct{}{}, 0, 0, 0, 0, 0},\n\t{nil, 0, 0, 0, 0, 0},\n\n\t{(*uint)(nil), 0, 0, 0, 0, 0},\n\t{(*uint8)(nil), 0, 0, 0, 0, 0},\n\t{(*uint16)(nil), 0, 0, 0, 0, 0},\n\t{(*uint32)(nil), 0, 0, 0, 0, 0},\n\t{(*uint64)(nil), 0, 0, 0, 0, 0},\n\n\t{gvar.New(123), 123, 123, 123, 123, 123},\n\t{gvar.New(123.456), 123, 123, 123, 123, 123},\n\n\t{&uintTestValue, 123, 123, 123, 123, 123},\n\t{&uint8TestValue, 123, 123, 123, 123, 123},\n\t{&uint16TestValue, 123, 123, 123, 123, 123},\n\t{&uint32TestValue, 123, 123, 123, 123, 123},\n\t{&uint64TestValue, 123, 123, 123, 123, 123},\n\n\t{(myUint)(uintTestValue), 123, 123, 123, 123, 123},\n\t{(myUint8)(uint8TestValue), 123, 123, 123, 123, 123},\n\t{(myUint16)(uint16TestValue), 123, 123, 123, 123, 123},\n\t{(myUint32)(uint32TestValue), 123, 123, 123, 123, 123},\n\t{(myUint64)(uint64TestValue), 123, 123, 123, 123, 123},\n\n\t{(*myUint)(&uintTestValue), 123, 123, 123, 123, 123},\n\t{(*myUint8)(&uint8TestValue), 123, 123, 123, 123, 123},\n\t{(*myUint16)(&uint16TestValue), 123, 123, 123, 123, 123},\n\t{(*myUint32)(&uint32TestValue), 123, 123, 123, 123, 123},\n\t{(*myUint64)(&uint64TestValue), 123, 123, 123, 123, 123},\n\n\t{(*myUint)(nil), 0, 0, 0, 0, 0},\n\t{(*myUint8)(nil), 0, 0, 0, 0, 0},\n\t{(*myUint16)(nil), 0, 0, 0, 0, 0},\n\t{(*myUint32)(nil), 0, 0, 0, 0, 0},\n\t{(*myUint64)(nil), 0, 0, 0, 0, 0},\n}\n\nfunc TestUint(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, v := range uintTests {\n\t\t\t//t.Logf(`%+v`, v)\n\t\t\tt.AssertEQ(gconv.Uint(v.value), v.expect)\n\t\t}\n\t})\n}\n\nfunc TestUint8(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tt.AssertEQ(gconv.Uint8(test.value), test.expect8)\n\t\t}\n\t})\n}\n\nfunc TestUint16(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tt.AssertEQ(gconv.Uint16(test.value), test.expect16)\n\t\t}\n\t})\n}\n\nfunc TestUint32(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tt.AssertEQ(gconv.Uint32(test.value), test.expect32)\n\t\t}\n\t})\n}\n\nfunc TestUint64(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tt.AssertEQ(gconv.Uint64(test.value), test.expect64)\n\t\t}\n\t})\n}\n\nfunc TestUints(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Uints(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tuints     = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []uint{\n\t\t\t\t\ttest.expect, test.expect,\n\t\t\t\t}\n\t\t\t)\n\t\t\tuints = reflect.Append(uints, reflect.ValueOf(test.value))\n\t\t\tuints = reflect.Append(uints, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Uints(uints.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceUint(uints.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Uints(\"\"), []uint{})\n\t\tt.AssertEQ(gconv.Uints(\"123\"), []uint{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Uints([]uint8(`{\"Name\":\"Earth\"}`)),\n\t\t\t[]uint{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Uints([]any{1, 2, 3}), []uint{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Uints(\n\t\t\tgvar.New([]uint{1, 2, 3}),\n\t\t), []uint{1, 2, 3})\n\n\t\t// array\n\t\tt.AssertEQ(gconv.Uints(\"[1, 2]\"), []uint{1, 2})\n\t})\n}\n\nfunc TestUint32s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Uint32s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tuint32s   = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []uint32{\n\t\t\t\t\ttest.expect32, test.expect32,\n\t\t\t\t}\n\t\t\t)\n\t\t\tuint32s = reflect.Append(uint32s, reflect.ValueOf(test.value))\n\t\t\tuint32s = reflect.Append(uint32s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Uint32s(uint32s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceUint32(uint32s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Uint32s(\"\"), []uint32{})\n\t\tt.AssertEQ(gconv.Uint32s(\"123\"), []uint32{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Uint32s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]uint32{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Uint32s([]any{1, 2, 3}), []uint32{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Uint32s(\n\t\t\tgvar.New([]uint32{1, 2, 3}),\n\t\t), []uint32{1, 2, 3})\n\t})\n}\n\nfunc TestUint64s(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor _, test := range uintTests {\n\t\t\tif test.value == nil {\n\t\t\t\tt.AssertNil(gconv.Uint64s(test.value))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tsliceType = reflect.SliceOf(reflect.TypeOf(test.value))\n\t\t\t\tuint64s   = reflect.MakeSlice(sliceType, 0, 0)\n\t\t\t\texpects   = []uint64{\n\t\t\t\t\ttest.expect64, test.expect64,\n\t\t\t\t}\n\t\t\t)\n\t\t\tuint64s = reflect.Append(uint64s, reflect.ValueOf(test.value))\n\t\t\tuint64s = reflect.Append(uint64s, reflect.ValueOf(test.value))\n\n\t\t\tt.AssertEQ(gconv.Uint64s(uint64s.Interface()), expects)\n\t\t\tt.AssertEQ(gconv.SliceUint64(uint64s.Interface()), expects)\n\t\t}\n\t})\n\n\t// Test for special types.\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// string\n\t\tt.AssertEQ(gconv.Uint64s(\"\"), []uint64{})\n\t\tt.AssertEQ(gconv.Uint64s(\"123\"), []uint64{123})\n\n\t\t// []int8 json\n\t\tt.AssertEQ(gconv.Uint64s([]uint8(`{\"Name\":\"Earth\"}\"`)),\n\t\t\t[]uint64{123, 34, 78, 97, 109, 101, 34, 58, 34, 69, 97, 114, 116, 104, 34, 125, 34})\n\n\t\t// []interface\n\t\tt.AssertEQ(gconv.Uint64s([]any{1, 2, 3}), []uint64{1, 2, 3})\n\n\t\t// gvar.Var\n\t\tt.AssertEQ(gconv.Uint64s(\n\t\t\tgvar.New([]uint64{1, 2, 3}),\n\t\t), []uint64{1, 2, 3})\n\t})\n}\n"
  },
  {
    "path": "util/gconv/gconv_z_unit_unsafe_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gconv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc TestUnsafeStrToBytes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"equator\"\n\t\tt.AssertEQ(gconv.UnsafeStrToBytes(s), []byte(s))\n\t})\n}\n\nfunc TestUnsafeBytesToStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := []byte(\"ecliptic\")\n\t\tt.AssertEQ(gconv.UnsafeBytesToStr(b), string(b))\n\t})\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package converter provides converting utilities for any types of variables.\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/structcache\"\n)\n\n// AnyConvertFunc is the type for any type converting function.\ntype AnyConvertFunc = structcache.AnyConvertFunc\n\n// RecursiveType is the type for converting recursively.\ntype RecursiveType string\n\nconst (\n\tRecursiveTypeAuto RecursiveType = \"auto\"\n\tRecursiveTypeTrue RecursiveType = \"true\"\n)\n\ntype (\n\tconverterInType  = reflect.Type\n\tconverterOutType = reflect.Type\n\tconverterFunc    = reflect.Value\n)\n\n// Converter implements the interface Converter.\ntype Converter struct {\n\tinternalConverter    *structcache.Converter\n\ttypeConverterFuncMap map[converterInType]map[converterOutType]converterFunc\n}\n\nvar (\n\t// Empty strings.\n\temptyStringMap = map[string]struct{}{\n\t\t\"\":      {},\n\t\t\"0\":     {},\n\t\t\"no\":    {},\n\t\t\"off\":   {},\n\t\t\"false\": {},\n\t}\n)\n\n// NewConverter creates and returns management object for type converting.\nfunc NewConverter() *Converter {\n\tcf := &Converter{\n\t\tinternalConverter:    structcache.NewConverter(),\n\t\ttypeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc),\n\t}\n\tcf.registerBuiltInAnyConvertFunc()\n\treturn cf\n}\n\n// RegisterTypeConverterFunc registers custom converter.\n// It must be registered before you use this custom converting feature.\n// It is suggested to do it in boot procedure of the process.\n//\n// Note:\n//  1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`.\n//     It will convert type `T1` to type `T2`.\n//  2. The `T1` should not be type of pointer, but the `T2` should be type of pointer.\nfunc (c *Converter) RegisterTypeConverterFunc(f any) (err error) {\n\tvar (\n\t\tfReflectType = reflect.TypeOf(f)\n\t\terrType      = reflect.TypeOf((*error)(nil)).Elem()\n\t)\n\tif fReflectType.Kind() != reflect.Func ||\n\t\tfReflectType.NumIn() != 1 || fReflectType.NumOut() != 2 ||\n\t\t!fReflectType.Out(1).Implements(errType) {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"parameter must be type of converter function and defined as pattern `func(T1) (T2, error)`, \"+\n\t\t\t\t\"but defined as `%s`\",\n\t\t\tfReflectType.String(),\n\t\t)\n\t\treturn\n\t}\n\n\t// The Key and Value of the converter map should not be pointer.\n\tvar (\n\t\tinType  = fReflectType.In(0)\n\t\toutType = fReflectType.Out(0)\n\t)\n\tif inType.Kind() == reflect.Pointer {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"invalid converter function `%s`: invalid input parameter type `%s`, should not be type of pointer\",\n\t\t\tfReflectType.String(), inType.String(),\n\t\t)\n\t\treturn\n\t}\n\tif outType.Kind() != reflect.Pointer {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"invalid converter function `%s`: invalid output parameter type `%s` should be type of pointer\",\n\t\t\tfReflectType.String(), outType.String(),\n\t\t)\n\t\treturn\n\t}\n\n\tregisteredOutTypeMap, ok := c.typeConverterFuncMap[inType]\n\tif !ok {\n\t\tregisteredOutTypeMap = make(map[converterOutType]converterFunc)\n\t\tc.typeConverterFuncMap[inType] = registeredOutTypeMap\n\t}\n\tif _, ok = registeredOutTypeMap[outType]; ok {\n\t\terr = gerror.NewCodef(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t\"the converter parameter type `%s` to type `%s` has already been registered\",\n\t\t\tinType.String(), outType.String(),\n\t\t)\n\t\treturn\n\t}\n\tregisteredOutTypeMap[outType] = reflect.ValueOf(f)\n\tc.internalConverter.MarkTypeConvertFunc(outType)\n\treturn\n}\n\n// RegisterAnyConverterFunc registers custom type converting function for specified types.\nfunc (c *Converter) RegisterAnyConverterFunc(convertFunc AnyConvertFunc, types ...reflect.Type) {\n\tfor _, t := range types {\n\t\tc.internalConverter.RegisterAnyConvertFunc(t, convertFunc)\n\t}\n}\n\nfunc (c *Converter) registerBuiltInAnyConvertFunc() {\n\tvar (\n\t\tintType     = reflect.TypeOf(0)\n\t\tint8Type    = reflect.TypeOf(int8(0))\n\t\tint16Type   = reflect.TypeOf(int16(0))\n\t\tint32Type   = reflect.TypeOf(int32(0))\n\t\tint64Type   = reflect.TypeOf(int64(0))\n\t\tuintType    = reflect.TypeOf(uint(0))\n\t\tuint8Type   = reflect.TypeOf(uint8(0))\n\t\tuint16Type  = reflect.TypeOf(uint16(0))\n\t\tuint32Type  = reflect.TypeOf(uint32(0))\n\t\tuint64Type  = reflect.TypeOf(uint64(0))\n\t\tfloat32Type = reflect.TypeOf(float32(0))\n\t\tfloat64Type = reflect.TypeOf(float64(0))\n\t\tstringType  = reflect.TypeOf(\"\")\n\t\tbytesType   = reflect.TypeOf([]byte{})\n\t\tboolType    = reflect.TypeOf(false)\n\t\ttimeType    = reflect.TypeOf((*time.Time)(nil)).Elem()\n\t\tgtimeType   = reflect.TypeOf((*gtime.Time)(nil)).Elem()\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForString, stringType,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForFloat64, float32Type, float64Type,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForBool, boolType,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForBytes, bytesType,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForTime, timeType,\n\t)\n\tc.RegisterAnyConverterFunc(\n\t\tc.builtInAnyConvertFuncForGTime, gtimeType,\n\t)\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_bool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Bool converts `any` to bool.\nfunc (c *Converter) Bool(anyInput any) (bool, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn false, nil\n\t}\n\tswitch value := anyInput.(type) {\n\tcase bool:\n\t\treturn value, nil\n\tcase []byte:\n\t\tif parsed, err := strconv.ParseBool(string(value)); err == nil {\n\t\t\treturn parsed, nil\n\t\t}\n\t\tif _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn true, nil\n\tcase string:\n\t\tif parsed, err := strconv.ParseBool(value); err == nil {\n\t\t\treturn parsed, nil\n\t\t}\n\t\tif _, ok := emptyStringMap[strings.ToLower(value)]; ok {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn true, nil\n\tdefault:\n\t\tif f, ok := value.(localinterface.IBool); ok {\n\t\t\treturn f.Bool(), nil\n\t\t}\n\t\trv := reflect.ValueOf(anyInput)\n\t\tswitch rv.Kind() {\n\t\tcase reflect.Pointer:\n\t\t\tif rv.IsNil() {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t\tif rv.Type().Elem().Kind() == reflect.Bool {\n\t\t\t\treturn rv.Elem().Bool(), nil\n\t\t\t}\n\t\t\treturn c.Bool(rv.Elem().Interface())\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\treturn rv.Int() != 0, nil\n\t\tcase reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\treturn rv.Uint() != 0, nil\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\treturn rv.Float() != 0, nil\n\t\tcase reflect.Bool:\n\t\t\treturn rv.Bool(), nil\n\t\t// TODO：(Map，Array，Slice，Struct) It might panic here for these types.\n\t\tcase reflect.Map, reflect.Array:\n\t\t\tfallthrough\n\t\tcase reflect.Slice:\n\t\t\treturn rv.Len() != 0, nil\n\t\tcase reflect.Struct:\n\t\t\treturn true, nil\n\t\tdefault:\n\t\t\ts, err := c.String(anyInput)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tif _, ok := emptyStringMap[strings.ToLower(s)]; ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t\treturn true, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_builtin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\nfunc (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error {\n\tv, err := c.Int64(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetInt(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error {\n\tv, err := c.Uint64(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetUint(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error {\n\tv, err := c.String(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetString(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error {\n\tv, err := c.Float64(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetFloat(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error {\n\tv, err := c.Bool(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetBool(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error {\n\tv, err := c.Bytes(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tto.SetBytes(v)\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error {\n\tt, err := c.Time(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*to.Addr().Interface().(*time.Time) = t\n\treturn nil\n}\n\nfunc (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error {\n\tv, err := c.GTime(from)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif v == nil {\n\t\tv = gtime.New()\n\t}\n\t*to.Addr().Interface().(*gtime.Time) = *v\n\treturn nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_bytes.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Bytes converts `any` to []byte.\nfunc (c *Converter) Bytes(anyInput any) ([]byte, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tswitch value := anyInput.(type) {\n\tcase string:\n\t\treturn []byte(value), nil\n\n\tcase []byte:\n\t\treturn value, nil\n\n\tdefault:\n\t\tif f, ok := value.(localinterface.IBytes); ok {\n\t\t\treturn f.Bytes(), nil\n\t\t}\n\t\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\t\tswitch originValueAndKind.OriginKind {\n\t\tcase reflect.Map:\n\t\t\tbytes, err := json.Marshal(anyInput)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn bytes, nil\n\n\t\tcase reflect.Array, reflect.Slice:\n\t\t\tvar (\n\t\t\t\tok    = true\n\t\t\t\tbytes = make([]byte, originValueAndKind.OriginValue.Len())\n\t\t\t)\n\t\t\tfor i := range bytes {\n\t\t\t\tint32Value, err := c.Int32(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif int32Value < 0 || int32Value > math.MaxUint8 {\n\t\t\t\t\tok = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tbytes[i] = byte(int32Value)\n\t\t\t}\n\t\t\tif ok {\n\t\t\t\treturn bytes, nil\n\t\t\t}\n\t\tdefault:\n\t\t}\n\t\treturn gbinary.Encode(anyInput), nil\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_convert.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// ConvertOption is the option for converting.\ntype ConvertOption struct {\n\t// ExtraParams are extra values for implementing the converting.\n\tExtraParams  []any\n\tSliceOption  SliceOption\n\tMapOption    MapOption\n\tStructOption StructOption\n}\n\nfunc (c *Converter) getConvertOption(option ...ConvertOption) ConvertOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn ConvertOption{}\n}\n\n// ConvertWithTypeName converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.\nfunc (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, option ...ConvertOption) (any, error) {\n\treturn c.doConvert(\n\t\tdoConvertInput{\n\t\t\tFromValue:  fromValue,\n\t\t\tToTypeName: toTypeName,\n\t\t\tReferValue: nil,\n\t\t},\n\t\tc.getConvertOption(option...),\n\t)\n}\n\n// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.\nfunc (c *Converter) ConvertWithRefer(fromValue, referValue any, option ...ConvertOption) (any, error) {\n\tvar referValueRf reflect.Value\n\tif v, ok := referValue.(reflect.Value); ok {\n\t\treferValueRf = v\n\t} else {\n\t\treferValueRf = reflect.ValueOf(referValue)\n\t}\n\treturn c.doConvert(\n\t\tdoConvertInput{\n\t\t\tFromValue:  fromValue,\n\t\t\tToTypeName: referValueRf.Type().String(),\n\t\t\tReferValue: referValue,\n\t\t},\n\t\tc.getConvertOption(option...),\n\t)\n}\n\ntype doConvertInput struct {\n\tFromValue  any    // Value that is converted from.\n\tToTypeName string // Target value type name in string.\n\tReferValue any    // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value.\n\n\t// Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result.\n\t// It is an attribute for internal usage purpose.\n\talreadySetToReferValue bool\n}\n\n// doConvert does commonly use types converting.\nfunc (c *Converter) doConvert(in doConvertInput, option ConvertOption) (convertedValue any, err error) {\n\tswitch in.ToTypeName {\n\tcase \"int\":\n\t\treturn c.Int(in.FromValue)\n\tcase \"*int\":\n\t\tif _, ok := in.FromValue.(*int); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Int(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"int8\":\n\t\treturn c.Int8(in.FromValue)\n\tcase \"*int8\":\n\t\tif _, ok := in.FromValue.(*int8); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Int8(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"int16\":\n\t\treturn c.Int16(in.FromValue)\n\tcase \"*int16\":\n\t\tif _, ok := in.FromValue.(*int16); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Int16(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"int32\":\n\t\treturn c.Int32(in.FromValue)\n\tcase \"*int32\":\n\t\tif _, ok := in.FromValue.(*int32); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Int32(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"int64\":\n\t\treturn c.Int64(in.FromValue)\n\tcase \"*int64\":\n\t\tif _, ok := in.FromValue.(*int64); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Int64(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"uint\":\n\t\treturn c.Uint(in.FromValue)\n\tcase \"*uint\":\n\t\tif _, ok := in.FromValue.(*uint); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Uint(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"uint8\":\n\t\treturn c.Uint8(in.FromValue)\n\tcase \"*uint8\":\n\t\tif _, ok := in.FromValue.(*uint8); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Uint8(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"uint16\":\n\t\treturn c.Uint16(in.FromValue)\n\tcase \"*uint16\":\n\t\tif _, ok := in.FromValue.(*uint16); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Uint16(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"uint32\":\n\t\treturn c.Uint32(in.FromValue)\n\tcase \"*uint32\":\n\t\tif _, ok := in.FromValue.(*uint32); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Uint32(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"uint64\":\n\t\treturn c.Uint64(in.FromValue)\n\tcase \"*uint64\":\n\t\tif _, ok := in.FromValue.(*uint64); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Uint64(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"float32\":\n\t\treturn c.Float32(in.FromValue)\n\tcase \"*float32\":\n\t\tif _, ok := in.FromValue.(*float32); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Float32(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"float64\":\n\t\treturn c.Float64(in.FromValue)\n\tcase \"*float64\":\n\t\tif _, ok := in.FromValue.(*float64); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Float64(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"bool\":\n\t\treturn c.Bool(in.FromValue)\n\tcase \"*bool\":\n\t\tif _, ok := in.FromValue.(*bool); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Bool(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"string\":\n\t\treturn c.String(in.FromValue)\n\tcase \"*string\":\n\t\tif _, ok := in.FromValue.(*string); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.String(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"[]byte\":\n\t\treturn c.Bytes(in.FromValue)\n\tcase \"[]int\":\n\t\treturn c.SliceInt(in.FromValue, option.SliceOption)\n\tcase \"[]int32\":\n\t\treturn c.SliceInt32(in.FromValue, option.SliceOption)\n\tcase \"[]int64\":\n\t\treturn c.SliceInt64(in.FromValue, option.SliceOption)\n\tcase \"[]uint\":\n\t\treturn c.SliceUint(in.FromValue, option.SliceOption)\n\tcase \"[]uint8\":\n\t\treturn c.Bytes(in.FromValue)\n\tcase \"[]uint32\":\n\t\treturn c.SliceUint32(in.FromValue, option.SliceOption)\n\tcase \"[]uint64\":\n\t\treturn c.SliceUint64(in.FromValue, option.SliceOption)\n\tcase \"[]float32\":\n\t\treturn c.SliceFloat32(in.FromValue, option.SliceOption)\n\tcase \"[]float64\":\n\t\treturn c.SliceFloat64(in.FromValue, option.SliceOption)\n\tcase \"[]string\":\n\t\treturn c.SliceStr(in.FromValue, option.SliceOption)\n\n\tcase \"Time\", \"time.Time\":\n\t\tif len(option.ExtraParams) > 0 {\n\t\t\ts, err := c.String(option.ExtraParams[0])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn c.Time(in.FromValue, s)\n\t\t}\n\t\treturn c.Time(in.FromValue)\n\tcase \"*time.Time\":\n\t\tvar v time.Time\n\t\tif len(option.ExtraParams) > 0 {\n\t\t\ts, err := c.String(option.ExtraParams[0])\n\t\t\tif err != nil {\n\t\t\t\treturn time.Time{}, err\n\t\t\t}\n\t\t\tv, err = c.Time(in.FromValue, s)\n\t\t\tif err != nil {\n\t\t\t\treturn time.Time{}, err\n\t\t\t}\n\t\t} else {\n\t\t\tif _, ok := in.FromValue.(*time.Time); ok {\n\t\t\t\treturn in.FromValue, nil\n\t\t\t}\n\t\t\tv, err = c.Time(in.FromValue)\n\t\t\tif err != nil {\n\t\t\t\treturn time.Time{}, err\n\t\t\t}\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"GTime\", \"gtime.Time\":\n\t\tif len(option.ExtraParams) > 0 {\n\t\t\ts, err := c.String(option.ExtraParams[0])\n\t\t\tif err != nil {\n\t\t\t\treturn *gtime.New(), err\n\t\t\t}\n\t\t\tv, err := c.GTime(in.FromValue, s)\n\t\t\tif err != nil {\n\t\t\t\treturn *gtime.New(), err\n\t\t\t}\n\t\t\tif v != nil {\n\t\t\t\treturn *v, nil\n\t\t\t}\n\t\t\treturn *gtime.New(), nil\n\t\t}\n\t\tv, err := c.GTime(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn *gtime.New(), err\n\t\t}\n\t\tif v != nil {\n\t\t\treturn *v, nil\n\t\t}\n\t\treturn *gtime.New(), nil\n\tcase \"*gtime.Time\":\n\t\tif len(option.ExtraParams) > 0 {\n\t\t\ts, err := c.String(option.ExtraParams[0])\n\t\t\tif err != nil {\n\t\t\t\treturn gtime.New(), err\n\t\t\t}\n\t\t\tv, err := c.GTime(in.FromValue, s)\n\t\t\tif err != nil {\n\t\t\t\treturn gtime.New(), err\n\t\t\t}\n\t\t\tif v != nil {\n\t\t\t\treturn v, nil\n\t\t\t}\n\t\t\treturn gtime.New(), nil\n\t\t}\n\t\tv, err := c.GTime(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn gtime.New(), err\n\t\t}\n\t\tif v != nil {\n\t\t\treturn v, nil\n\t\t}\n\t\treturn gtime.New(), nil\n\n\tcase \"Duration\", \"time.Duration\":\n\t\treturn c.Duration(in.FromValue)\n\tcase \"*time.Duration\":\n\t\tif _, ok := in.FromValue.(*time.Duration); ok {\n\t\t\treturn in.FromValue, nil\n\t\t}\n\t\tv, err := c.Duration(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &v, nil\n\n\tcase \"map[string]string\":\n\t\treturn c.MapStrStr(in.FromValue, option.MapOption)\n\n\tcase \"map[string]interface {}\":\n\t\treturn c.Map(in.FromValue, option.MapOption)\n\n\tcase \"[]map[string]interface {}\":\n\t\treturn c.SliceMap(in.FromValue, SliceMapOption{\n\t\t\tSliceOption: option.SliceOption,\n\t\t\tMapOption:   option.MapOption,\n\t\t})\n\n\tcase \"RawMessage\", \"json.RawMessage\":\n\t\t// issue 3449\n\t\tbytes, err := json.Marshal(in.FromValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn bytes, nil\n\n\tdefault:\n\t\treturn c.doConvertForDefault(in, option)\n\t}\n}\n\nfunc (c *Converter) doConvertForDefault(in doConvertInput, option ConvertOption) (convertedValue any, err error) {\n\tif in.ReferValue != nil {\n\t\tvar referReflectValue reflect.Value\n\t\tif v, ok := in.ReferValue.(reflect.Value); ok {\n\t\t\treferReflectValue = v\n\t\t} else {\n\t\t\treferReflectValue = reflect.ValueOf(in.ReferValue)\n\t\t}\n\t\tvar fromReflectValue reflect.Value\n\t\tif v, ok := in.FromValue.(reflect.Value); ok {\n\t\t\tfromReflectValue = v\n\t\t} else {\n\t\t\tfromReflectValue = reflect.ValueOf(in.FromValue)\n\t\t}\n\n\t\t// custom converter.\n\t\tdstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif ok {\n\t\t\treturn dstReflectValue.Interface(), nil\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif recover() != nil {\n\t\t\t\tin.alreadySetToReferValue = false\n\t\t\t\tif err = c.bindVarToReflectValue(referReflectValue, in.FromValue, option.StructOption); err == nil {\n\t\t\t\t\tin.alreadySetToReferValue = true\n\t\t\t\t\tconvertedValue = referReflectValue.Interface()\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tswitch referReflectValue.Kind() {\n\t\tcase reflect.Pointer:\n\t\t\t// Type converting for custom type pointers.\n\t\t\t// Eg:\n\t\t\t// type PayMode int\n\t\t\t// type Req struct{\n\t\t\t//     Mode *PayMode\n\t\t\t// }\n\t\t\t//\n\t\t\t// Struct(`{\"Mode\": 1000}`, &req)\n\t\t\toriginType := referReflectValue.Type().Elem()\n\t\t\tswitch originType.Kind() {\n\t\t\tcase reflect.Struct:\n\t\t\t\t// Not support some kinds.\n\t\t\tdefault:\n\t\t\t\tin.ToTypeName = originType.Kind().String()\n\t\t\t\tin.ReferValue = nil\n\t\t\t\tresult, err := c.doConvert(in, option)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\trefElementValue := reflect.ValueOf(result)\n\t\t\t\toriginTypeValue := reflect.New(refElementValue.Type()).Elem()\n\t\t\t\toriginTypeValue.Set(refElementValue)\n\t\t\t\tin.alreadySetToReferValue = true\n\t\t\t\treturn originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil\n\t\t\t}\n\n\t\tcase reflect.Map:\n\t\t\tvar targetValue = reflect.New(referReflectValue.Type()).Elem()\n\t\t\tif err = c.MapToMap(in.FromValue, targetValue, nil, option.MapOption); err == nil {\n\t\t\t\tin.alreadySetToReferValue = true\n\t\t\t}\n\t\t\treturn targetValue.Interface(), nil\n\n\t\tdefault:\n\t\t}\n\t\tin.ToTypeName = referReflectValue.Kind().String()\n\t\tin.ReferValue = nil\n\t\tin.alreadySetToReferValue = true\n\t\tresult, err := c.doConvert(in, option)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tconvertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface()\n\t\treturn convertedValue, nil\n\t}\n\treturn in.FromValue, nil\n}\n\nfunc (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput, option ConvertOption) error {\n\tconvertedValue, err := c.doConvert(in, option)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !in.alreadySetToReferValue {\n\t\treflectValue.Set(reflect.ValueOf(convertedValue))\n\t}\n\treturn err\n}\n\n// callCustomConverter call the custom converter. It will try some possible type.\nfunc (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {\n\t// search type converter function.\n\tregisteredConverterFunc, srcType, ok := c.getRegisteredTypeConverterFuncAndSrcType(srcReflectValue, dstReflectValue)\n\tif ok {\n\t\treturn c.doCallCustomTypeConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)\n\t}\n\n\t// search any converter function.\n\tanyConverterFunc := c.getRegisteredAnyConverterFunc(dstReflectValue)\n\tif anyConverterFunc == nil {\n\t\treturn false, nil\n\t}\n\terr = anyConverterFunc(srcReflectValue.Interface(), dstReflectValue)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn true, nil\n}\n\nfunc (c *Converter) callCustomConverterWithRefer(\n\tsrcReflectValue, referReflectValue reflect.Value,\n) (dstReflectValue reflect.Value, converted bool, err error) {\n\t// search type converter function.\n\tregisteredConverterFunc, srcType, ok := c.getRegisteredTypeConverterFuncAndSrcType(\n\t\tsrcReflectValue, referReflectValue,\n\t)\n\tif ok {\n\t\tdstReflectValue = reflect.New(referReflectValue.Type()).Elem()\n\t\tconverted, err = c.doCallCustomTypeConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)\n\t\treturn\n\t}\n\n\t// search any converter function.\n\tanyConverterFunc := c.getRegisteredAnyConverterFunc(referReflectValue)\n\tif anyConverterFunc == nil {\n\t\treturn reflect.Value{}, false, nil\n\t}\n\tdstReflectValue = reflect.New(referReflectValue.Type()).Elem()\n\terr = anyConverterFunc(srcReflectValue.Interface(), dstReflectValue)\n\tif err != nil {\n\t\treturn reflect.Value{}, false, err\n\t}\n\treturn dstReflectValue, true, nil\n}\n\nfunc (c *Converter) getRegisteredTypeConverterFuncAndSrcType(\n\tsrcReflectValue, dstReflectValueForRefer reflect.Value,\n) (f converterFunc, srcType reflect.Type, ok bool) {\n\tif len(c.typeConverterFuncMap) == 0 {\n\t\treturn reflect.Value{}, nil, false\n\t}\n\tsrcType = srcReflectValue.Type()\n\tfor srcType.Kind() == reflect.Pointer {\n\t\tsrcType = srcType.Elem()\n\t}\n\tvar registeredOutTypeMap map[converterOutType]converterFunc\n\t// firstly, it searches the map by input parameter type.\n\tregisteredOutTypeMap, ok = c.typeConverterFuncMap[srcType]\n\tif !ok {\n\t\treturn reflect.Value{}, nil, false\n\t}\n\tvar dstType = dstReflectValueForRefer.Type()\n\tif dstType.Kind() == reflect.Pointer {\n\t\t// Might be **struct, which is support as designed.\n\t\tif dstType.Elem().Kind() == reflect.Pointer {\n\t\t\tdstType = dstType.Elem()\n\t\t}\n\t} else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() {\n\t\tdstType = dstReflectValueForRefer.Addr().Type()\n\t} else {\n\t\tdstType = reflect.PointerTo(dstType)\n\t}\n\t// secondly, it searches the input parameter type map\n\t// and finds the result converter function by the output parameter type.\n\tf, ok = registeredOutTypeMap[dstType]\n\tif !ok {\n\t\treturn reflect.Value{}, nil, false\n\t}\n\treturn\n}\n\nfunc (c *Converter) getRegisteredAnyConverterFunc(dstReflectValueForRefer reflect.Value) (f AnyConvertFunc) {\n\tif c.internalConverter.IsAnyConvertFuncEmpty() {\n\t\treturn nil\n\t}\n\tif !dstReflectValueForRefer.IsValid() {\n\t\treturn nil\n\t}\n\tvar dstType = dstReflectValueForRefer.Type()\n\tif dstType.Kind() == reflect.Pointer {\n\t\t// Might be **struct, which is support as designed.\n\t\tif dstType.Elem().Kind() == reflect.Pointer {\n\t\t\tdstType = dstType.Elem()\n\t\t}\n\t} else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() {\n\t\tdstType = dstReflectValueForRefer.Addr().Type()\n\t} else {\n\t\tdstType = reflect.PointerTo(dstType)\n\t}\n\treturn c.internalConverter.GetAnyConvertFuncByType(dstType)\n}\n\nfunc (c *Converter) doCallCustomTypeConverter(\n\tsrcReflectValue reflect.Value,\n\tdstReflectValue reflect.Value,\n\tregisteredConverterFunc converterFunc,\n\tsrcType reflect.Type,\n) (converted bool, err error) {\n\t// Converter function calling.\n\tfor srcReflectValue.Type() != srcType {\n\t\tsrcReflectValue = srcReflectValue.Elem()\n\t}\n\tresult := registeredConverterFunc.Call([]reflect.Value{srcReflectValue})\n\tif !result[1].IsNil() {\n\t\treturn false, result[1].Interface().(error)\n\t}\n\t// The `result[0]` is a pointer.\n\tif result[0].IsNil() {\n\t\treturn false, nil\n\t}\n\tvar resultValue = result[0]\n\tfor {\n\t\tif resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() {\n\t\t\tdstReflectValue.Set(resultValue)\n\t\t\tconverted = true\n\t\t} else if dstReflectValue.Kind() == reflect.Pointer {\n\t\t\tif resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() {\n\t\t\t\tdstReflectValue.Elem().Set(resultValue)\n\t\t\t\tconverted = true\n\t\t\t}\n\t\t}\n\t\tif converted {\n\t\t\tbreak\n\t\t}\n\t\tif resultValue.Kind() == reflect.Pointer {\n\t\t\tresultValue = resultValue.Elem()\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn converted, nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_float.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Float32 converts `any` to float32.\nfunc (c *Converter) Float32(anyInput any) (float32, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tswitch value := anyInput.(type) {\n\tcase float32:\n\t\treturn value, nil\n\tcase float64:\n\t\treturn float32(value), nil\n\tcase []byte:\n\t\t// TODO: It might panic here for these types.\n\t\treturn gbinary.DecodeToFloat32(value), nil\n\tdefault:\n\t\trv := reflect.ValueOf(anyInput)\n\t\tswitch rv.Kind() {\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\treturn float32(rv.Int()), nil\n\t\tcase reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\treturn float32(rv.Uint()), nil\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\treturn float32(rv.Float()), nil\n\t\tcase reflect.Bool:\n\t\t\tif rv.Bool() {\n\t\t\t\treturn 1, nil\n\t\t\t}\n\t\t\treturn 0, nil\n\t\tcase reflect.String:\n\t\t\tf, err := strconv.ParseFloat(rv.String(), 32)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, gerror.WrapCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, err, \"converting string to float32 failed for: %v\", anyInput,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn float32(f), nil\n\t\tcase reflect.Pointer:\n\t\t\tif rv.IsNil() {\n\t\t\t\treturn 0, nil\n\t\t\t}\n\t\t\tif f, ok := value.(localinterface.IFloat32); ok {\n\t\t\t\treturn f.Float32(), nil\n\t\t\t}\n\t\t\treturn c.Float32(rv.Elem().Interface())\n\t\tdefault:\n\t\t\tif f, ok := value.(localinterface.IFloat32); ok {\n\t\t\t\treturn f.Float32(), nil\n\t\t\t}\n\t\t\ts, err := c.String(anyInput)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tv, err := strconv.ParseFloat(s, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, gerror.WrapCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, err, \"converting string to float32 failed for: %v\", anyInput,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn float32(v), nil\n\t\t}\n\t}\n}\n\n// Float64 converts `any` to float64.\nfunc (c *Converter) Float64(anyInput any) (float64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tswitch value := anyInput.(type) {\n\tcase float32:\n\t\treturn float64(value), nil\n\tcase float64:\n\t\treturn value, nil\n\tcase []byte:\n\t\t// TODO: It might panic here for these types.\n\t\treturn gbinary.DecodeToFloat64(value), nil\n\tdefault:\n\t\trv := reflect.ValueOf(anyInput)\n\t\tswitch rv.Kind() {\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\treturn float64(rv.Int()), nil\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\treturn float64(rv.Uint()), nil\n\t\tcase reflect.Uintptr:\n\t\t\treturn float64(rv.Uint()), nil\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\t// Please Note:\n\t\t\t// When the type is float32 or a custom type defined based on float32,\n\t\t\t// switching to float64 may result in a few extra decimal places.\n\t\t\treturn rv.Float(), nil\n\t\tcase reflect.Bool:\n\t\t\tif rv.Bool() {\n\t\t\t\treturn 1, nil\n\t\t\t}\n\t\t\treturn 0, nil\n\t\tcase reflect.String:\n\t\t\tf, err := strconv.ParseFloat(rv.String(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, gerror.WrapCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, err, \"converting string to float64 failed for: %v\", anyInput,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn f, nil\n\t\tcase reflect.Pointer:\n\t\t\tif rv.IsNil() {\n\t\t\t\treturn 0, nil\n\t\t\t}\n\t\t\tif f, ok := value.(localinterface.IFloat64); ok {\n\t\t\t\treturn f.Float64(), nil\n\t\t\t}\n\t\t\treturn c.Float64(rv.Elem().Interface())\n\t\tdefault:\n\t\t\tif f, ok := value.(localinterface.IFloat64); ok {\n\t\t\t\treturn f.Float64(), nil\n\t\t\t}\n\t\t\ts, err := c.String(anyInput)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tv, err := strconv.ParseFloat(s, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, gerror.WrapCodef(\n\t\t\t\t\tgcode.CodeInvalidParameter, err, \"converting string to float64 failed for: %v\", anyInput,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn v, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Int converts `any` to int.\nfunc (c *Converter) Int(anyInput any) (int, error) {\n\tif v, ok := anyInput.(int); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Int64(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(v), nil\n}\n\n// Int8 converts `any` to int8.\nfunc (c *Converter) Int8(anyInput any) (int8, error) {\n\tif v, ok := anyInput.(int8); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Int64(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int8(v), nil\n}\n\n// Int16 converts `any` to int16.\nfunc (c *Converter) Int16(anyInput any) (int16, error) {\n\tif v, ok := anyInput.(int16); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Int64(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int16(v), nil\n}\n\n// Int32 converts `any` to int32.\nfunc (c *Converter) Int32(anyInput any) (int32, error) {\n\tif v, ok := anyInput.(int32); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Int64(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int32(v), nil\n}\n\n// Int64 converts `any` to int64.\nfunc (c *Converter) Int64(anyInput any) (int64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(int64); ok {\n\t\treturn v, nil\n\t}\n\trv := reflect.ValueOf(anyInput)\n\tswitch rv.Kind() {\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn rv.Int(), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn int64(rv.Uint()), nil\n\tcase reflect.Uintptr:\n\t\treturn int64(rv.Uint()), nil\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn int64(rv.Float()), nil\n\tcase reflect.Bool:\n\t\tif rv.Bool() {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase reflect.Pointer:\n\t\tif rv.IsNil() {\n\t\t\treturn 0, nil\n\t\t}\n\t\tif f, ok := anyInput.(localinterface.IInt64); ok {\n\t\t\treturn f.Int64(), nil\n\t\t}\n\t\treturn c.Int64(rv.Elem().Interface())\n\tcase reflect.Slice:\n\t\t// TODO: It might panic here for these types.\n\t\tif rv.Type().Elem().Kind() == reflect.Uint8 {\n\t\t\treturn gbinary.DecodeToInt64(rv.Bytes()), nil\n\t\t}\n\tcase reflect.String:\n\t\tvar (\n\t\t\ts       = rv.String()\n\t\t\tisMinus = false\n\t\t)\n\t\tif len(s) > 0 {\n\t\t\tswitch s[0] {\n\t\t\tcase '-':\n\t\t\t\tisMinus = true\n\t\t\t\ts = s[1:]\n\t\t\tcase '+':\n\t\t\t\ts = s[1:]\n\t\t\t}\n\t\t}\n\t\t// Hexadecimal.\n\t\tif len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {\n\t\t\tif v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {\n\t\t\t\tif isMinus {\n\t\t\t\t\treturn -v, nil\n\t\t\t\t}\n\t\t\t\treturn v, nil\n\t\t\t}\n\t\t}\n\t\t// Decimal.\n\t\tif v, e := strconv.ParseInt(s, 10, 64); e == nil {\n\t\t\tif isMinus {\n\t\t\t\treturn -v, nil\n\t\t\t}\n\t\t\treturn v, nil\n\t\t}\n\t\t// Float64.\n\t\tvalueInt64, err := c.Float64(s)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tif math.IsNaN(valueInt64) {\n\t\t\treturn 0, nil\n\t\t} else {\n\t\t\tif isMinus {\n\t\t\t\treturn -int64(valueInt64), nil\n\t\t\t}\n\t\t\treturn int64(valueInt64), nil\n\t\t}\n\tdefault:\n\t\tif f, ok := anyInput.(localinterface.IInt64); ok {\n\t\t\treturn f.Int64(), nil\n\t\t}\n\t}\n\treturn 0, gerror.NewCodef(\n\t\tgcode.CodeInvalidParameter,\n\t\t`unsupport value type for converting to int64: %v`,\n\t\treflect.TypeOf(anyInput),\n\t)\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// MapOption specifies the option for map converting.\ntype MapOption struct {\n\t// Deep marks doing Map function recursively, which means if the attribute of given converting value\n\t// is also a struct/*struct, it automatically calls Map function on this attribute converting it to\n\t// a map[string]any type variable.\n\tDeep bool\n\n\t// OmitEmpty ignores the attributes that has json `omitempty` tag.\n\tOmitEmpty bool\n\n\t// Tags specifies the converted map key name by struct tag name.\n\tTags []string\n\n\t// ContinueOnError specifies whether to continue converting the next element\n\t// if one element converting fails.\n\tContinueOnError bool\n}\n\nfunc (c *Converter) getMapOption(option ...MapOption) MapOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn MapOption{}\n}\n\n// Map converts any variable `value` to map[string]any. If the parameter `value` is not a\n// map/struct/*struct type, then the conversion will fail and returns nil.\n//\n// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority\n// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of:\n// gconv, json, field name.\nfunc (c *Converter) Map(value any, option ...MapOption) (map[string]any, error) {\n\treturn c.doMapConvert(value, RecursiveTypeAuto, false, c.getMapOption(option...))\n}\n\n// MapStrStr converts `value` to map[string]string.\n// Note that there might be data copy for this map type converting.\nfunc (c *Converter) MapStrStr(value any, option ...MapOption) (map[string]string, error) {\n\tif r, ok := value.(map[string]string); ok {\n\t\treturn r, nil\n\t}\n\tm, err := c.Map(value, option...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(m) > 0 {\n\t\tvar (\n\t\t\ts         string\n\t\t\tvMap      = make(map[string]string, len(m))\n\t\t\tmapOption = c.getMapOption(option...)\n\t\t)\n\t\tfor k, v := range m {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !mapOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvMap[k] = s\n\t\t}\n\t\treturn vMap, nil\n\t}\n\treturn nil, nil\n}\n\n// MapConvert implements the map converting.\n// It automatically checks and converts json string to map if `value` is string/[]byte.\n//\n// TODO completely implement the recursive converting for all types, especially the map.\nfunc (c *Converter) doMapConvert(\n\tvalue any, recursive RecursiveType, mustMapReturn bool, option MapOption,\n) (map[string]any, error) {\n\tif value == nil {\n\t\treturn nil, nil\n\t}\n\t// It redirects to its underlying value if it has implemented interface iVal.\n\tif v, ok := value.(localinterface.IVal); ok {\n\t\tvalue = v.Val()\n\t}\n\tvar (\n\t\terr     error\n\t\tnewTags = gtag.StructTagPriority\n\t)\n\tif option.Deep {\n\t\trecursive = RecursiveTypeTrue\n\t}\n\tswitch len(option.Tags) {\n\tcase 0:\n\t\t// No need handling.\n\tcase 1:\n\t\tnewTags = append(strings.Split(option.Tags[0], \",\"), gtag.StructTagPriority...)\n\tdefault:\n\t\tnewTags = append(option.Tags, gtag.StructTagPriority...)\n\t}\n\t// Assert the common combination of types, and finally it uses reflection.\n\tdataMap := make(map[string]any)\n\tswitch r := value.(type) {\n\tcase string:\n\t\t// If it is a JSON string, automatically unmarshal it!\n\t\tif len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {\n\t\t\tif err = json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, nil\n\t\t}\n\tcase []byte:\n\t\t// If it is a JSON string, automatically unmarshal it!\n\t\tif len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {\n\t\t\tif err = json.UnmarshalUseNumber(r, &dataMap); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, nil\n\t\t}\n\tcase map[any]any:\n\t\trecursiveOption := option\n\t\trecursiveOption.Tags = newTags\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\tValue:           v,\n\t\t\t\t\tRecursiveType:   recursive,\n\t\t\t\t\tRecursiveOption: recursive == RecursiveTypeTrue,\n\t\t\t\t\tOption:          recursiveOption,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\tcase map[any]string:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[any]int:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[any]uint:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[any]float32:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[any]float64:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[string]bool:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]int:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]uint:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]float32:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]float64:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]string:\n\t\tfor k, v := range r {\n\t\t\tdataMap[k] = v\n\t\t}\n\tcase map[string]any:\n\t\tif recursive == RecursiveTypeTrue {\n\t\t\trecursiveOption := option\n\t\t\trecursiveOption.Tags = newTags\n\t\t\t// A copy of current map.\n\t\t\tfor k, v := range r {\n\t\t\t\tdataMap[k], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\tValue:           v,\n\t\t\t\t\t\tRecursiveType:   recursive,\n\t\t\t\t\t\tRecursiveOption: recursive == RecursiveTypeTrue,\n\t\t\t\t\t\tOption:          recursiveOption,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// It returns the map directly without any changing.\n\t\t\treturn r, nil\n\t\t}\n\tcase map[int]any:\n\t\trecursiveOption := option\n\t\trecursiveOption.Tags = newTags\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\tValue:           v,\n\t\t\t\t\tRecursiveType:   recursive,\n\t\t\t\t\tRecursiveOption: recursive == RecursiveTypeTrue,\n\t\t\t\t\tOption:          recursiveOption,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\tcase map[int]string:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\tcase map[uint]string:\n\t\tfor k, v := range r {\n\t\t\ts, err := c.String(k)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s] = v\n\t\t}\n\n\tdefault:\n\t\t// Not a common type, it then uses reflection for conversion.\n\t\tvar reflectValue reflect.Value\n\t\tif v, ok := value.(reflect.Value); ok {\n\t\t\treflectValue = v\n\t\t} else {\n\t\t\treflectValue = reflect.ValueOf(value)\n\t\t}\n\t\treflectKind := reflectValue.Kind()\n\t\t// If it is a pointer, we should find its real data type.\n\t\tfor reflectKind == reflect.Pointer {\n\t\t\treflectValue = reflectValue.Elem()\n\t\t\treflectKind = reflectValue.Kind()\n\t\t}\n\t\tswitch reflectKind {\n\t\t// If `value` is type of array, it converts the value of even number index as its key and\n\t\t// the value of odd number index as its corresponding value, for example:\n\t\t// []string{\"k1\",\"v1\",\"k2\",\"v2\"} => map[string]any{\"k1\":\"v1\", \"k2\":\"v2\"}\n\t\t// []string{\"k1\",\"v1\",\"k2\"}      => map[string]any{\"k1\":\"v1\", \"k2\":nil}\n\t\tcase reflect.Slice, reflect.Array:\n\t\t\tlength := reflectValue.Len()\n\t\t\tfor i := 0; i < length; i += 2 {\n\t\t\t\ts, err := c.String(reflectValue.Index(i).Interface())\n\t\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif i+1 < length {\n\t\t\t\t\tdataMap[s] = reflectValue.Index(i + 1).Interface()\n\t\t\t\t} else {\n\t\t\t\t\tdataMap[s] = nil\n\t\t\t\t}\n\t\t\t}\n\t\tcase reflect.Map, reflect.Struct, reflect.Interface:\n\t\t\trecursiveOption := option\n\t\t\trecursiveOption.Tags = newTags\n\t\t\tconvertedValue, err := c.doMapConvertForMapOrStructValue(\n\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\tIsRoot:          true,\n\t\t\t\t\tValue:           value,\n\t\t\t\t\tRecursiveType:   recursive,\n\t\t\t\t\tRecursiveOption: recursive == RecursiveTypeTrue,\n\t\t\t\t\tOption:          recursiveOption,\n\t\t\t\t\tMustMapReturn:   mustMapReturn,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil && !option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif m, ok := convertedValue.(map[string]any); ok {\n\t\t\t\treturn m, nil\n\t\t\t}\n\t\t\treturn nil, nil\n\t\tdefault:\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\treturn dataMap, nil\n}\n\ntype doMapConvertForMapOrStructValueInput struct {\n\tIsRoot          bool          // It returns directly if it is not root and with no recursive converting.\n\tValue           any           // Current operation value.\n\tRecursiveType   RecursiveType // The type from top function entry.\n\tRecursiveOption bool          // Whether convert recursively for `current` operation.\n\tOption          MapOption     // Map converting option.\n\tMustMapReturn   bool          // Must return map instead of Value when empty.\n}\n\nfunc (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) {\n\tif !in.IsRoot && !in.RecursiveOption {\n\t\treturn in.Value, nil\n\t}\n\n\tvar (\n\t\terr          error\n\t\treflectValue reflect.Value\n\t)\n\tif v, ok := in.Value.(reflect.Value); ok {\n\t\treflectValue = v\n\t\tin.Value = v.Interface()\n\t} else {\n\t\treflectValue = reflect.ValueOf(in.Value)\n\t}\n\treflectKind := reflectValue.Kind()\n\t// If it is a pointer, we should find its real data type.\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\tvar (\n\t\t\tmapIter = reflectValue.MapRange()\n\t\t\tdataMap = make(map[string]any)\n\t\t)\n\t\tfor mapIter.Next() {\n\t\t\tvar (\n\t\t\t\tmapKeyValue = mapIter.Value()\n\t\t\t\tmapValue    any\n\t\t\t)\n\t\t\tswitch {\n\t\t\tcase mapKeyValue.IsZero():\n\t\t\t\tif utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() {\n\t\t\t\t\t// quick check for nil value.\n\t\t\t\t\tmapValue = nil\n\t\t\t\t} else {\n\t\t\t\t\t// in case of:\n\t\t\t\t\t// exception recovered: reflect: call of reflect.Value.Interface on zero Value\n\t\t\t\t\tmapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tmapValue = mapKeyValue.Interface()\n\t\t\t}\n\t\t\ts, err := c.String(mapIter.Key().Interface())\n\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdataMap[s], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\tValue:           mapValue,\n\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\t\tOption:          in.Option,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\treturn dataMap, nil\n\n\tcase reflect.Struct:\n\t\tvar dataMap = make(map[string]any)\n\t\t// Map converting interface check.\n\t\tif v, ok := in.Value.(localinterface.IMapStrAny); ok {\n\t\t\t// Value copy, in case of concurrent safety.\n\t\t\tfor mapK, mapV := range v.MapStrAny() {\n\t\t\t\tif in.RecursiveOption {\n\t\t\t\t\tdataMap[mapK], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\tValue:           mapV,\n\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdataMap[mapK] = mapV\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(dataMap) > 0 {\n\t\t\t\treturn dataMap, nil\n\t\t\t}\n\t\t}\n\t\t// Using reflect for converting.\n\t\tvar (\n\t\t\trtField     reflect.StructField\n\t\t\trvField     reflect.Value\n\t\t\treflectType = reflectValue.Type() // attribute value type.\n\t\t\tmapKey      = \"\"                  // mapKey may be the tag name or the struct attribute name.\n\t\t)\n\t\tfor i := 0; i < reflectValue.NumField(); i++ {\n\t\t\trtField = reflectType.Field(i)\n\t\t\trvField = reflectValue.Field(i)\n\t\t\t// Only convert the public attributes.\n\t\t\tfieldName := rtField.Name\n\t\t\tif !utils.IsLetterUpper(fieldName[0]) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmapKey = \"\"\n\t\t\tfieldTag := rtField.Tag\n\t\t\tfor _, tag := range in.Option.Tags {\n\t\t\t\tif mapKey = fieldTag.Get(tag); mapKey != \"\" {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif mapKey == \"\" {\n\t\t\t\tmapKey = fieldName\n\t\t\t} else {\n\t\t\t\t// Support json tag feature: -, omitempty\n\t\t\t\tmapKey = strings.TrimSpace(mapKey)\n\t\t\t\tif mapKey == \"-\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tarray := strings.Split(mapKey, \",\")\n\t\t\t\tif len(array) > 1 {\n\t\t\t\t\tswitch strings.TrimSpace(array[1]) {\n\t\t\t\t\tcase \"omitempty\":\n\t\t\t\t\t\tif in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmapKey = strings.TrimSpace(array[0])\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tmapKey = strings.TrimSpace(array[0])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif mapKey == \"\" {\n\t\t\t\t\tmapKey = fieldName\n\t\t\t\t}\n\t\t\t}\n\t\t\tif in.RecursiveOption || rtField.Anonymous {\n\t\t\t\t// Do map converting recursively.\n\t\t\t\tvar (\n\t\t\t\t\trvAttrField = rvField\n\t\t\t\t\trvAttrKind  = rvField.Kind()\n\t\t\t\t)\n\t\t\t\tif rvAttrKind == reflect.Pointer {\n\t\t\t\t\trvAttrField = rvField.Elem()\n\t\t\t\t\trvAttrKind = rvAttrField.Kind()\n\t\t\t\t}\n\t\t\t\tswitch rvAttrKind {\n\t\t\t\tcase reflect.Struct:\n\t\t\t\t\t// Embedded struct and has no fields, just ignores it.\n\t\t\t\t\t// Eg: gmeta.Meta\n\t\t\t\t\tif rvAttrField.Type().NumField() == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tvar (\n\t\t\t\t\t\thasNoTag = mapKey == fieldName\n\t\t\t\t\t\t// DO NOT use rvAttrField.Interface() here,\n\t\t\t\t\t\t// as it might be changed from pointer to struct.\n\t\t\t\t\t\trvInterface = rvField.Interface()\n\t\t\t\t\t)\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase hasNoTag && rtField.Anonymous:\n\t\t\t\t\t\t// It means this attribute field has no tag.\n\t\t\t\t\t\t// Overwrite the attribute with sub-struct attribute fields.\n\t\t\t\t\t\tanonymousValue, err := c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\t\tValue:           rvInterface,\n\t\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\t\tRecursiveOption: true,\n\t\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif m, ok := anonymousValue.(map[string]any); ok {\n\t\t\t\t\t\t\tfor k, v := range m {\n\t\t\t\t\t\t\t\tdataMap[k] = v\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdataMap[mapKey] = rvInterface\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// It means this attribute field has desired tag.\n\t\t\t\t\tcase !hasNoTag && rtField.Anonymous:\n\t\t\t\t\t\tdataMap[mapKey], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\t\tValue:           rvInterface,\n\t\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\t\tRecursiveOption: true,\n\t\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdataMap[mapKey], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\t\tValue:           rvInterface,\n\t\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// The struct attribute is type of slice.\n\t\t\t\tcase reflect.Array, reflect.Slice:\n\t\t\t\t\tlength := rvAttrField.Len()\n\t\t\t\t\tif length == 0 {\n\t\t\t\t\t\tdataMap[mapKey] = rvAttrField.Interface()\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tarray := make([]any, length)\n\t\t\t\t\tfor arrayIndex := 0; arrayIndex < length; arrayIndex++ {\n\t\t\t\t\t\tarray[arrayIndex], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\t\tValue:           rvAttrField.Index(arrayIndex).Interface(),\n\t\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataMap[mapKey] = array\n\t\t\t\tcase reflect.Map:\n\t\t\t\t\tvar (\n\t\t\t\t\t\tmapIter   = rvAttrField.MapRange()\n\t\t\t\t\t\tnestedMap = make(map[string]any)\n\t\t\t\t\t)\n\t\t\t\t\tfor mapIter.Next() {\n\t\t\t\t\t\ts, err := c.String(mapIter.Key().Interface())\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnestedMap[s], err = c.doMapConvertForMapOrStructValue(\n\t\t\t\t\t\t\tdoMapConvertForMapOrStructValueInput{\n\t\t\t\t\t\t\t\tIsRoot:          false,\n\t\t\t\t\t\t\t\tValue:           mapIter.Value().Interface(),\n\t\t\t\t\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\t\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\t\t\t\t\tOption:          in.Option,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataMap[mapKey] = nestedMap\n\t\t\t\tdefault:\n\t\t\t\t\tif rvField.IsValid() {\n\t\t\t\t\t\tdataMap[mapKey] = reflectValue.Field(i).Interface()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdataMap[mapKey] = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No recursive map value converting\n\t\t\t\tif rvField.IsValid() {\n\t\t\t\t\tdataMap[mapKey] = reflectValue.Field(i).Interface()\n\t\t\t\t} else {\n\t\t\t\t\tdataMap[mapKey] = nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !in.MustMapReturn && len(dataMap) == 0 {\n\t\t\treturn in.Value, nil\n\t\t}\n\t\treturn dataMap, nil\n\n\t// The given value is type of slice.\n\tcase reflect.Array, reflect.Slice:\n\t\tlength := reflectValue.Len()\n\t\tif length == 0 {\n\t\t\tbreak\n\t\t}\n\t\tarray := make([]any, reflectValue.Len())\n\t\tfor i := 0; i < length; i++ {\n\t\t\tarray[i], err = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{\n\t\t\t\tIsRoot:          false,\n\t\t\t\tValue:           reflectValue.Index(i).Interface(),\n\t\t\t\tRecursiveType:   in.RecursiveType,\n\t\t\t\tRecursiveOption: in.RecursiveType == RecursiveTypeTrue,\n\t\t\t\tOption:          in.Option,\n\t\t\t})\n\t\t\tif err != nil && !in.Option.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\treturn array, nil\n\n\tdefault:\n\t}\n\treturn in.Value, nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_maptomap.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// MapToMap converts any map type variable `params` to another map type variable `pointer`.\n//\n// The parameter `params` can be any type of map, like:\n// map[string]string, map[string]struct, map[string]*struct, reflect.Value, etc.\n//\n// The parameter `pointer` should be type of *map, like:\n// map[int]string, map[string]struct, map[string]*struct, reflect.Value, etc.\n//\n// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes\n// sense only if the items of original map `params` is type struct.\nfunc (c *Converter) MapToMap(\n\tparams, pointer any, mapping map[string]string, option ...MapOption,\n) (err error) {\n\tvar (\n\t\tparamsRv   reflect.Value\n\t\tparamsKind reflect.Kind\n\t)\n\tif v, ok := params.(reflect.Value); ok {\n\t\tparamsRv = v\n\t} else {\n\t\tparamsRv = reflect.ValueOf(params)\n\t}\n\tparamsKind = paramsRv.Kind()\n\tif paramsKind == reflect.Pointer {\n\t\tparamsRv = paramsRv.Elem()\n\t\tparamsKind = paramsRv.Kind()\n\t}\n\tif paramsKind != reflect.Map {\n\t\tm, err := c.Map(params, option...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn c.MapToMap(m, pointer, mapping, option...)\n\t}\n\t// Empty params map, no need continue.\n\tif paramsRv.Len() == 0 {\n\t\treturn nil\n\t}\n\tvar pointerRv reflect.Value\n\tif v, ok := pointer.(reflect.Value); ok {\n\t\tpointerRv = v\n\t} else {\n\t\tpointerRv = reflect.ValueOf(pointer)\n\t}\n\tpointerKind := pointerRv.Kind()\n\tfor pointerKind == reflect.Pointer {\n\t\tpointerRv = pointerRv.Elem()\n\t\tpointerKind = pointerRv.Kind()\n\t}\n\tif pointerKind != reflect.Map {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`destination pointer should be type of *map, but got: %s`,\n\t\t\tpointerKind,\n\t\t)\n\t}\n\tdefer func() {\n\t\t// Catch the panic, especially the reflection operation panics.\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, \"%+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\tvar (\n\t\tparamsKeys       = paramsRv.MapKeys()\n\t\tpointerKeyType   = pointerRv.Type().Key()\n\t\tpointerValueType = pointerRv.Type().Elem()\n\t\tpointerValueKind = pointerValueType.Kind()\n\t\tdataMap          = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))\n\t\tmapOption        = c.getMapOption(option...)\n\t\tconvertOption    = ConvertOption{\n\t\t\tStructOption: StructOption{ContinueOnError: mapOption.ContinueOnError},\n\t\t\tSliceOption:  SliceOption{ContinueOnError: mapOption.ContinueOnError},\n\t\t\tMapOption:    mapOption,\n\t\t}\n\t)\n\t// Retrieve the true element type of target map.\n\tif pointerValueKind == reflect.Pointer {\n\t\tpointerValueKind = pointerValueType.Elem().Kind()\n\t}\n\tfor _, key := range paramsKeys {\n\t\tmapValue := reflect.New(pointerValueType).Elem()\n\t\tswitch pointerValueKind {\n\t\tcase reflect.Map:\n\t\t\t// For nested map types, recursively call MapToMap.\n\t\t\tif err = c.MapToMap(paramsRv.MapIndex(key).Interface(), mapValue.Addr().Interface(), mapping, option...); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase reflect.Struct:\n\t\t\tstructOption := StructOption{\n\t\t\t\tParamKeyToAttrMap: mapping,\n\t\t\t\tPriorityTag:       \"\",\n\t\t\t\tContinueOnError:   mapOption.ContinueOnError,\n\t\t\t}\n\t\t\tif err = c.Struct(paramsRv.MapIndex(key).Interface(), mapValue, structOption); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tconvertResult, err := c.doConvert(\n\t\t\t\tdoConvertInput{\n\t\t\t\t\tFromValue:  paramsRv.MapIndex(key).Interface(),\n\t\t\t\t\tToTypeName: pointerValueType.String(),\n\t\t\t\t\tReferValue: mapValue,\n\t\t\t\t},\n\t\t\t\tconvertOption,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tmapValue.Set(reflect.ValueOf(convertResult))\n\t\t}\n\t\tconvertResult, err := c.doConvert(\n\t\t\tdoConvertInput{\n\t\t\t\tFromValue:  key.Interface(),\n\t\t\t\tToTypeName: pointerKeyType.Name(),\n\t\t\t\tReferValue: reflect.New(pointerKeyType).Elem().Interface(),\n\t\t\t},\n\t\t\tconvertOption,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar mapKey = reflect.ValueOf(convertResult)\n\t\tdataMap.SetMapIndex(mapKey, mapValue)\n\t}\n\tpointerRv.Set(dataMap)\n\treturn nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_maptomaps.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// MapToMaps converts any map type variable `params` to another map slice variable `pointer`.\n//\n// The parameter `params` can be type of []map, []*map, []struct, []*struct.\n//\n// The parameter `pointer` should be type of []map, []*map.\n//\n// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes\n// sense only if the item of `params` is type struct.\nfunc (c *Converter) MapToMaps(\n\tparams any, pointer any, paramKeyToAttrMap map[string]string, option ...MapOption,\n) (err error) {\n\t// Params and its element type check.\n\tvar (\n\t\tparamsRv   reflect.Value\n\t\tparamsKind reflect.Kind\n\t)\n\tif v, ok := params.(reflect.Value); ok {\n\t\tparamsRv = v\n\t} else {\n\t\tparamsRv = reflect.ValueOf(params)\n\t}\n\tparamsKind = paramsRv.Kind()\n\tif paramsKind == reflect.Pointer {\n\t\tparamsRv = paramsRv.Elem()\n\t\tparamsKind = paramsRv.Kind()\n\t}\n\tif paramsKind != reflect.Array && paramsKind != reflect.Slice {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"params should be type of slice, example: []map/[]*map/[]struct/[]*struct\",\n\t\t)\n\t}\n\tvar (\n\t\tparamsElem     = paramsRv.Type().Elem()\n\t\tparamsElemKind = paramsElem.Kind()\n\t)\n\tif paramsElemKind == reflect.Pointer {\n\t\tparamsElem = paramsElem.Elem()\n\t\tparamsElemKind = paramsElem.Kind()\n\t}\n\tif paramsElemKind != reflect.Map &&\n\t\tparamsElemKind != reflect.Struct &&\n\t\tparamsElemKind != reflect.Interface {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"params element should be type of map/*map/struct/*struct, but got: %s\",\n\t\t\tparamsElemKind,\n\t\t)\n\t}\n\t// Empty slice, no need continue.\n\tif paramsRv.Len() == 0 {\n\t\treturn nil\n\t}\n\t// Pointer and its element type check.\n\tvar (\n\t\tpointerRv   = reflect.ValueOf(pointer)\n\t\tpointerKind = pointerRv.Kind()\n\t)\n\tfor pointerKind == reflect.Pointer {\n\t\tpointerRv = pointerRv.Elem()\n\t\tpointerKind = pointerRv.Kind()\n\t}\n\tif pointerKind != reflect.Array && pointerKind != reflect.Slice {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"pointer should be type of *[]map/*[]*map\")\n\t}\n\tvar (\n\t\tpointerElemType = pointerRv.Type().Elem()\n\t\tpointerElemKind = pointerElemType.Kind()\n\t)\n\tif pointerElemKind == reflect.Pointer {\n\t\tpointerElemKind = pointerElemType.Elem().Kind()\n\t}\n\tif pointerElemKind != reflect.Map {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"pointer element should be type of map/*map\")\n\t}\n\tdefer func() {\n\t\t// Catch the panic, especially the reflection operation panics.\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, \"%+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\tvar (\n\t\tpointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())\n\t)\n\tfor i := 0; i < paramsRv.Len(); i++ {\n\t\tvar item reflect.Value\n\t\tif pointerElemType.Kind() == reflect.Pointer {\n\t\t\titem = reflect.New(pointerElemType.Elem())\n\t\t\tif err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option...); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tpointerSlice.Index(i).Set(item)\n\t\t} else {\n\t\t\titem = reflect.New(pointerElemType)\n\t\t\tif err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option...); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tpointerSlice.Index(i).Set(item.Elem())\n\t\t}\n\t}\n\tpointerRv.Set(pointerSlice)\n\treturn\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_rune.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\n// Rune converts `any` to rune.\nfunc (c *Converter) Rune(anyInput any) (rune, error) {\n\tif v, ok := anyInput.(rune); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Int32(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn v, nil\n}\n\n// Runes converts `any` to []rune.\nfunc (c *Converter) Runes(anyInput any) ([]rune, error) {\n\tif v, ok := anyInput.([]rune); ok {\n\t\treturn v, nil\n\t}\n\ts, err := c.String(anyInput)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []rune(s), nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_scan.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// ScanOption is the option for the Scan function.\ntype ScanOption struct {\n\t// ParamKeyToAttrMap specifies the mapping between parameter keys and struct attribute names.\n\tParamKeyToAttrMap map[string]string\n\n\t// ContinueOnError specifies whether to continue converting the next element\n\t// if one element converting fails.\n\tContinueOnError bool\n\n\t// OmitEmpty specifies whether to skip assignment when the source value is empty\n\t// (empty string, zero value, etc.), preserving the existing value in the\n\t// destination field.\n\tOmitEmpty bool\n\n\t// OmitNil specifies whether to skip assignment when the source value is nil,\n\t// preserving the existing value in the destination field.\n\tOmitNil bool\n}\n\nfunc (c *Converter) getScanOption(option ...ScanOption) ScanOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn ScanOption{}\n}\n\n// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.\nfunc (c *Converter) Scan(srcValue any, dstPointer any, option ...ScanOption) (err error) {\n\t// Check if srcValue is nil, in which case no conversion is needed\n\tif srcValue == nil {\n\t\treturn nil\n\t}\n\t// Check if dstPointer is nil, which is an invalid parameter\n\tif dstPointer == nil {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`destination pointer should not be nil`,\n\t\t)\n\t}\n\n\t// Get the reflection type and value of dstPointer\n\tvar (\n\t\tdstPointerReflectType  reflect.Type\n\t\tdstPointerReflectValue reflect.Value\n\t)\n\tif v, ok := dstPointer.(reflect.Value); ok {\n\t\tdstPointerReflectValue = v\n\t\tdstPointerReflectType = v.Type()\n\t} else {\n\t\tdstPointerReflectValue = reflect.ValueOf(dstPointer)\n\t\t// Do not use dstPointerReflectValue.Type() as dstPointerReflectValue might be zero\n\t\tdstPointerReflectType = reflect.TypeOf(dstPointer)\n\t}\n\n\t// Validate the kind of dstPointer\n\tvar dstPointerReflectKind = dstPointerReflectType.Kind()\n\tif dstPointerReflectKind != reflect.Pointer {\n\t\t// If dstPointer is not a pointer, try to get its address\n\t\tif dstPointerReflectValue.CanAddr() {\n\t\t\tdstPointerReflectValue = dstPointerReflectValue.Addr()\n\t\t\tdstPointerReflectType = dstPointerReflectValue.Type()\n\t\t\t// dstPointerReflectKind = dstPointerReflectType.Kind()\n\t\t} else {\n\t\t\t// If dstPointer is not a pointer and cannot be addressed, return an error\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`destination pointer should be type of pointer, but got type: %v`,\n\t\t\t\tdstPointerReflectType,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Get the reflection value of srcValue\n\tvar srcValueReflectValue reflect.Value\n\tif v, ok := srcValue.(reflect.Value); ok {\n\t\tsrcValueReflectValue = v\n\t} else {\n\t\tsrcValueReflectValue = reflect.ValueOf(srcValue)\n\t}\n\n\t// Get the element type and kind of dstPointer\n\tvar dstPointerReflectValueElem = dstPointerReflectValue.Elem()\n\t// Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed\n\tif ok := c.doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok {\n\t\treturn nil\n\t}\n\n\t// Handle multiple level pointers\n\tvar dstPointerReflectValueElemKind = dstPointerReflectValueElem.Kind()\n\tif dstPointerReflectValueElemKind == reflect.Pointer {\n\t\tif dstPointerReflectValueElem.IsNil() {\n\t\t\t// Create a new value for the pointer dereference\n\t\t\tnextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem())\n\t\t\t// Recursively scan into the dereferenced pointer\n\t\t\tif err = c.Scan(srcValueReflectValue, nextLevelPtr, option...); err == nil {\n\t\t\t\tdstPointerReflectValueElem.Set(nextLevelPtr)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\treturn c.Scan(srcValueReflectValue, dstPointerReflectValueElem, option...)\n\t}\n\n\tscanOption := c.getScanOption(option...)\n\t// Handle different destination types\n\tswitch dstPointerReflectValueElemKind {\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tv, err := c.Int64(srcValue)\n\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\treturn err\n\t\t}\n\t\tdstPointerReflectValueElem.SetInt(v)\n\t\treturn nil\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tv, err := c.Uint64(srcValue)\n\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\treturn err\n\t\t}\n\t\tdstPointerReflectValueElem.SetUint(v)\n\t\treturn nil\n\n\tcase reflect.Float32, reflect.Float64:\n\t\tv, err := c.Float64(srcValue)\n\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\treturn err\n\t\t}\n\t\tdstPointerReflectValueElem.SetFloat(v)\n\t\treturn nil\n\n\tcase reflect.String:\n\t\tv, err := c.String(srcValue)\n\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\treturn err\n\t\t}\n\t\tdstPointerReflectValueElem.SetString(v)\n\t\treturn nil\n\n\tcase reflect.Bool:\n\t\tv, err := c.Bool(srcValue)\n\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\treturn err\n\t\t}\n\t\tdstPointerReflectValueElem.SetBool(v)\n\t\treturn nil\n\n\tcase reflect.Slice:\n\t\t// Handle slice type conversion\n\t\tvar (\n\t\t\tdstElemType = dstPointerReflectValueElem.Type().Elem()\n\t\t\tdstElemKind = dstElemType.Kind()\n\t\t)\n\n\t\t// The slice element might be a pointer type\n\t\tif dstElemKind == reflect.Pointer {\n\t\t\tdstElemType = dstElemType.Elem()\n\t\t\tdstElemKind = dstElemType.Kind()\n\t\t}\n\t\t// Special handling for struct or map slice elements\n\t\tif dstElemKind == reflect.Struct || dstElemKind == reflect.Map {\n\t\t\treturn c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)\n\t\t}\n\t\t// Handle basic type slice conversions\n\t\tvar srcValueReflectValueKind = srcValueReflectValue.Kind()\n\t\tif srcValueReflectValueKind == reflect.Slice || srcValueReflectValueKind == reflect.Array {\n\t\t\tvar (\n\t\t\t\tsrcLen   = srcValueReflectValue.Len()\n\t\t\t\tnewSlice = reflect.MakeSlice(dstPointerReflectValueElem.Type(), srcLen, srcLen)\n\t\t\t)\n\t\t\tfor i := 0; i < srcLen; i++ {\n\t\t\t\tsrcElem := srcValueReflectValue.Index(i).Interface()\n\t\t\t\tswitch dstElemType.Kind() {\n\t\t\t\tcase reflect.String:\n\t\t\t\t\tv, err := c.String(srcElem)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnewSlice.Index(i).SetString(v)\n\t\t\t\tcase reflect.Int:\n\t\t\t\t\tv, err := c.Int64(srcElem)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnewSlice.Index(i).SetInt(v)\n\t\t\t\tcase reflect.Int64:\n\t\t\t\t\tv, err := c.Int64(srcElem)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnewSlice.Index(i).SetInt(v)\n\t\t\t\tcase reflect.Float64:\n\t\t\t\t\tv, err := c.Float64(srcElem)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnewSlice.Index(i).SetFloat(v)\n\t\t\t\tcase reflect.Bool:\n\t\t\t\t\tv, err := c.Bool(srcElem)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tnewSlice.Index(i).SetBool(v)\n\t\t\t\tdefault:\n\t\t\t\t\terr = c.Scan(\n\t\t\t\t\t\tsrcElem, newSlice.Index(i).Addr().Interface(), option...,\n\t\t\t\t\t)\n\t\t\t\t\tif err != nil && !scanOption.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tdstPointerReflectValueElem.Set(newSlice)\n\t\t\treturn nil\n\t\t}\n\t\treturn c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)\n\n\tdefault:\n\t\t// Handle complex types (structs, maps, etc.)\n\t\treturn c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)\n\t}\n}\n\n// doScanForComplicatedTypes handles the scanning of complex data types.\n// It supports converting between maps, structs, and slices of these types.\n// The function first attempts JSON conversion, then falls back to specific type handling.\n//\n// It supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.\n//\n// Parameters:\n// - srcValue: The source value to convert from\n// - dstPointer: The destination pointer to convert to\n// - dstPointerReflectType: The reflection type of the destination pointer\n// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names\nfunc (c *Converter) doScanForComplicatedTypes(\n\tsrcValue, dstPointer any,\n\tdstPointerReflectType reflect.Type,\n\toption ScanOption,\n) error {\n\t// Try JSON conversion first\n\tok, err := c.doConvertWithJSONCheck(srcValue, dstPointer)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ok {\n\t\treturn nil\n\t}\n\n\t// Handle specific type conversions\n\tvar (\n\t\tdstPointerReflectTypeElem     = dstPointerReflectType.Elem()\n\t\tdstPointerReflectTypeElemKind = dstPointerReflectTypeElem.Kind()\n\t\tkeyToAttributeNameMapping     = option.ParamKeyToAttrMap\n\t)\n\t// Handle different destination types\n\tswitch dstPointerReflectTypeElemKind {\n\tcase reflect.Map:\n\t\t// Convert map to map\n\t\treturn c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{\n\t\t\tContinueOnError: option.ContinueOnError,\n\t\t})\n\n\tcase reflect.Array, reflect.Slice:\n\t\tvar (\n\t\t\tsliceElem     = dstPointerReflectTypeElem.Elem()\n\t\t\tsliceElemKind = sliceElem.Kind()\n\t\t)\n\t\t// Handle pointer elements\n\t\tfor sliceElemKind == reflect.Pointer {\n\t\t\tsliceElem = sliceElem.Elem()\n\t\t\tsliceElemKind = sliceElem.Kind()\n\t\t}\n\t\tif sliceElemKind == reflect.Map {\n\t\t\t// Convert to slice of maps\n\t\t\treturn c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{\n\t\t\t\tContinueOnError: option.ContinueOnError,\n\t\t\t})\n\t\t}\n\t\t// Convert to slice of structs\n\t\tvar (\n\t\t\tsliceOption = SliceOption{\n\t\t\t\tContinueOnError: option.ContinueOnError,\n\t\t\t}\n\t\t\tmapOption = StructOption{\n\t\t\t\tParamKeyToAttrMap: keyToAttributeNameMapping,\n\t\t\t\tContinueOnError:   option.ContinueOnError,\n\t\t\t\tOmitEmpty:         option.OmitEmpty,\n\t\t\t\tOmitNil:           option.OmitNil,\n\t\t\t}\n\t\t)\n\t\treturn c.Structs(srcValue, dstPointer, StructsOption{\n\t\t\tSliceOption:  sliceOption,\n\t\t\tStructOption: mapOption,\n\t\t})\n\n\tdefault:\n\t\tstructOption := StructOption{\n\t\t\tParamKeyToAttrMap: keyToAttributeNameMapping,\n\t\t\tPriorityTag:       \"\",\n\t\t\tContinueOnError:   option.ContinueOnError,\n\t\t\tOmitEmpty:         option.OmitEmpty,\n\t\t\tOmitNil:           option.OmitNil,\n\t\t}\n\t\treturn c.Struct(srcValue, dstPointer, structOption)\n\t}\n}\n\n// doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct`\n// for converting.\nfunc (c *Converter) doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) {\n\tif !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() {\n\t\treturn false\n\t}\n\tswitch {\n\t// Examples:\n\t// UploadFile       => UploadFile\n\t// []UploadFile     => []UploadFile\n\t// *UploadFile      => *UploadFile\n\t// *[]UploadFile    => *[]UploadFile\n\t// map[int][int]    => map[int][int]\n\t// []map[int][int]  => []map[int][int]\n\t// *[]map[int][int] => *[]map[int][int]\n\tcase dstPointerReflectValueElem.Type() == srcValueReflectValue.Type():\n\t\tdstPointerReflectValueElem.Set(srcValueReflectValue)\n\t\treturn true\n\n\t// Examples:\n\t// UploadFile      => *UploadFile\n\t// []UploadFile    => *[]UploadFile\n\t// map[int][int]   => *map[int][int]\n\t// []map[int][int] => *[]map[int][int]\n\tcase dstPointerReflectValueElem.Kind() == reflect.Pointer &&\n\t\tdstPointerReflectValueElem.Elem().IsValid() &&\n\t\tdstPointerReflectValueElem.Elem().Type() == srcValueReflectValue.Type():\n\t\tdstPointerReflectValueElem.Elem().Set(srcValueReflectValue)\n\t\treturn true\n\n\t// Examples:\n\t// *UploadFile      => UploadFile\n\t// *[]UploadFile    => []UploadFile\n\t// *map[int][int]   => map[int][int]\n\t// *[]map[int][int] => []map[int][int]\n\tcase srcValueReflectValue.Kind() == reflect.Pointer &&\n\t\tsrcValueReflectValue.Elem().IsValid() &&\n\t\tdstPointerReflectValueElem.Type() == srcValueReflectValue.Elem().Type():\n\t\tdstPointerReflectValueElem.Set(srcValueReflectValue.Elem())\n\t\treturn true\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// doConvertWithJSONCheck attempts to convert the source value to the destination\n// using JSON marshaling and unmarshaling. This is particularly useful for complex\n// types that can be represented as JSON.\n//\n// Parameters:\n// - srcValue: The source value to convert from\n// - dstPointer: The destination pointer to convert to\n//\n// Returns:\n// - bool: true if JSON conversion was successful\n// - error: any error that occurred during conversion\nfunc (c *Converter) doConvertWithJSONCheck(srcValue any, dstPointer any) (ok bool, err error) {\n\tswitch valueResult := srcValue.(type) {\n\tcase []byte:\n\t\tif json.Valid(valueResult) {\n\t\t\tif dstPointerReflectType, ok := dstPointer.(reflect.Value); ok {\n\t\t\t\tif dstPointerReflectType.Kind() == reflect.Pointer {\n\t\t\t\t\tif dstPointerReflectType.IsNil() {\n\t\t\t\t\t\treturn false, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Interface())\n\t\t\t\t} else if dstPointerReflectType.CanAddr() {\n\t\t\t\t\treturn true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Addr().Interface())\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true, json.UnmarshalUseNumber(valueResult, dstPointer)\n\t\t\t}\n\t\t}\n\n\tcase string:\n\t\tif valueBytes := []byte(valueResult); json.Valid(valueBytes) {\n\t\t\tif dstPointerReflectType, ok := dstPointer.(reflect.Value); ok {\n\t\t\t\tif dstPointerReflectType.Kind() == reflect.Pointer {\n\t\t\t\t\tif dstPointerReflectType.IsNil() {\n\t\t\t\t\t\treturn false, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Interface())\n\t\t\t\t} else if dstPointerReflectType.CanAddr() {\n\t\t\t\t\treturn true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Addr().Interface())\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn true, json.UnmarshalUseNumber(valueBytes, dstPointer)\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\t// The `params` might be struct that implements interface function Interface, eg: gvar.Var.\n\t\tif v, ok := srcValue.(localinterface.IInterface); ok {\n\t\t\treturn c.doConvertWithJSONCheck(v.Interface(), dstPointer)\n\t\t}\n\t}\n\treturn false, nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_any.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceOption is the option for Slice type converting.\ntype SliceOption struct {\n\t// ContinueOnError specifies whether to continue converting the next element\n\t// if one element converting fails.\n\tContinueOnError bool\n}\n\nfunc (c *Converter) getSliceOption(option ...SliceOption) SliceOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn SliceOption{}\n}\n\n// SliceAny converts `any` to []any.\nfunc (c *Converter) SliceAny(anyInput any, _ ...SliceOption) ([]any, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr   error\n\t\tarray []any\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []any:\n\t\tarray = value\n\tcase []string:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []int:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []int8:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []int16:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []int32:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []int64:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []uint:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\n\tcase []uint16:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []uint32:\n\t\tfor _, v := range value {\n\t\t\tarray = append(array, v)\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []bool:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []float32:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\tcase []float64:\n\t\tarray = make([]any, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn v.Interfaces(), err\n\t}\n\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]any, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tslice[i] = originValueAndKind.OriginValue.Index(i).Interface()\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\treturn []any{anyInput}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_bool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceBool converts `any` to []bool.\nfunc (c *Converter) SliceBool(anyInput any, option ...SliceOption) ([]bool, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tbb          bool\n\t\tarray       []bool\n\t\tsliceOption = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tbb, err = c.Bool(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = bb\n\t\t}\n\tcase []int:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []int8:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []int16:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []int32:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []int64:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []uint:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []bool:\n\t\tarray = value\n\tcase []float32:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []float64:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = v != 0\n\t\t}\n\tcase []any:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tbb, err = c.Bool(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = bb\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]bool, len(value))\n\t\tfor k, v := range value {\n\t\t\tbb, err = c.Bool(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = bb\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []bool{}, err\n\t\t}\n\t\tbb, err = c.Bool(value)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []bool{bb}, err\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceBool(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]bool, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tbb, err = c.Bool(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = bb\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []bool{}, err\n\t\t}\n\t\tbb, err = c.Bool(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []bool{bb}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_float.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceFloat32 converts `any` to []float32.\nfunc (c *Converter) SliceFloat32(anyInput any, option ...SliceOption) ([]float32, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tf           float32\n\t\tarray       []float32 = nil\n\t\tsliceOption           = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int8:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int16:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int32:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int64:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []float32{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tf, err = c.Float32(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []float32{f}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []bool:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []float32:\n\t\tarray = value\n\tcase []float64:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []any:\n\t\tarray = make([]float32, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IFloats); ok {\n\t\treturn c.SliceFloat32(v.Floats(), option...)\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceFloat32(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]float32, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tf, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = f\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []float32{}, err\n\t\t}\n\t\tf, err = c.Float32(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float32{f}, err\n\t}\n}\n\n// SliceFloat64 converts `any` to []float64.\nfunc (c *Converter) SliceFloat64(anyInput any, option ...SliceOption) ([]float64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tf           float64\n\t\tarray       []float64 = nil\n\t\tsliceOption           = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int8:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int16:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int32:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []int64:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []float64{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tf, err = c.Float64(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []float64{f}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []bool:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []float32:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\tcase []float64:\n\t\tarray = value\n\tcase []any:\n\t\tarray = make([]float64, len(value))\n\t\tfor k, v := range value {\n\t\t\tf, err = c.Float64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = f\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IFloats); ok {\n\t\treturn v.Floats(), err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceFloat64(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]float64, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tf, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = f\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []float64{}, err\n\t\t}\n\t\tf, err = c.Float64(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []float64{f}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_int.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceInt converts `any` to []int.\nfunc (c *Converter) SliceInt(anyInput any, option ...SliceOption) ([]int, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tii          int\n\t\tarray       []int = nil\n\t\tsliceOption       = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []int:\n\t\tarray = value\n\tcase []int8:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []int32:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []int64:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []uint:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []int{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tii, err = c.Int(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []int{ii}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int(v)\n\t\t}\n\tcase []bool:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []float64:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []any:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]int, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IInts); ok {\n\t\treturn v.Ints(), err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceInt(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]int, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ii\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []int{}, err\n\t\t}\n\t\tii, err = c.Int(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int{ii}, err\n\t}\n}\n\n// SliceInt32 converts `any` to []int32.\nfunc (c *Converter) SliceInt32(anyInput any, option ...SliceOption) ([]int32, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tii          int32\n\t\tarray       []int32 = nil\n\t\tsliceOption         = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []int:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []int8:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []int32:\n\t\tarray = value\n\tcase []int64:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []uint:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []int32{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tii, err = c.Int32(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []int32{ii}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int32(v)\n\t\t}\n\tcase []bool:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []float64:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []any:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]int32, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IInts); ok {\n\t\treturn c.SliceInt32(v.Ints(), option...)\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceInt32(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]int32, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ii\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []int32{}, err\n\t\t}\n\t\tii, err = c.Int32(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int32{ii}, err\n\t}\n}\n\n// SliceInt64 converts `any` to []int64.\nfunc (c *Converter) SliceInt64(anyInput any, option ...SliceOption) ([]int64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tii          int64\n\t\tarray       []int64 = nil\n\t\tsliceOption         = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []int:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []int8:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []int32:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []int64:\n\t\tarray = value\n\tcase []uint:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []int64{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tii, err = c.Int64(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []int64{ii}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = int64(v)\n\t\t}\n\tcase []bool:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []float64:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase []any:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]int64, len(value))\n\t\tfor k, v := range value {\n\t\t\tii, err = c.Int64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ii\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IInts); ok {\n\t\treturn c.SliceInt64(v.Ints(), option...)\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceInt64(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]int64, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ii\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []int64{}, err\n\t\t}\n\t\tii, err = c.Int64(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []int64{ii}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport \"github.com/gogf/gf/v2/internal/json\"\n\n// SliceMapOption is the option for SliceMap function.\ntype SliceMapOption struct {\n\tSliceOption SliceOption\n\tMapOption   MapOption\n}\n\nfunc (c *Converter) getSliceMapOption(option ...SliceMapOption) SliceMapOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn SliceMapOption{}\n}\n\n// SliceMap converts `value` to []map[string]any.\n// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.\nfunc (c *Converter) SliceMap(value any, option ...SliceMapOption) ([]map[string]any, error) {\n\tif value == nil {\n\t\treturn nil, nil\n\t}\n\tswitch r := value.(type) {\n\tcase string:\n\t\tlist := make([]map[string]any, 0)\n\t\tif len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {\n\t\t\tif err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn list, nil\n\t\t}\n\t\treturn nil, nil\n\n\tcase []byte:\n\t\tlist := make([]map[string]any, 0)\n\t\tif len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {\n\t\t\tif err := json.UnmarshalUseNumber(r, &list); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn list, nil\n\t\t}\n\t\treturn nil, nil\n\n\tcase []map[string]any:\n\t\treturn r, nil\n\n\tdefault:\n\t\tsliceMapOption := c.getSliceMapOption(option...)\n\t\tarray, err := c.SliceAny(value, sliceMapOption.SliceOption)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(array) == 0 {\n\t\t\treturn nil, nil\n\t\t}\n\t\tlist := make([]map[string]any, len(array))\n\t\tfor k, v := range array {\n\t\t\tm, err := c.Map(v, sliceMapOption.MapOption)\n\t\t\tif err != nil && !sliceMapOption.SliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tlist[k] = m\n\t\t}\n\t\treturn list, nil\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_str.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceStr converts `any` to []string.\nfunc (c *Converter) SliceStr(anyInput any, option ...SliceOption) ([]string, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\ts           string\n\t\tarray       []string = nil\n\t\tsliceOption          = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []int:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []int8:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []int16:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []int32:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []int64:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []uint:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\t\treturn array, err\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []string{}, err\n\t\t}\n\t\treturn []string{value}, err\n\tcase []uint16:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []bool:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []float32:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []float64:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []any:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\tcase []string:\n\t\tarray = value\n\tcase [][]byte:\n\t\tarray = make([]string, len(value))\n\t\tfor k, v := range value {\n\t\t\ts, err = c.String(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = s\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\tif v, ok := anyInput.(localinterface.IStrings); ok {\n\t\treturn v.Strings(), err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceStr(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]string, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\ts, err = c.String(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = s\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []string{}, err\n\t\t}\n\t\ts, err = c.String(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []string{s}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_slice_uint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// SliceUint converts `any` to []uint.\nfunc (c *Converter) SliceUint(anyInput any, option ...SliceOption) ([]uint, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tui          uint\n\t\tarray       []uint = nil\n\t\tsliceOption        = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []int8:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []int32:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []int64:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []uint:\n\t\tarray = value\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []uint{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tui, err = c.Uint(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []uint{ui}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []uint64:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint(v)\n\t\t}\n\tcase []bool:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []float64:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []any:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]uint, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\t}\n\n\tif array != nil {\n\t\treturn array, err\n\t}\n\n\t// Default handler.\n\tif v, ok := anyInput.(localinterface.IUints); ok {\n\t\treturn v.Uints(), err\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceUint(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]uint, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ui\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []uint{}, err\n\t\t}\n\t\tui, err = c.Uint(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []uint{ui}, err\n\t}\n}\n\n// SliceUint32 converts `any` to []uint32.\nfunc (c *Converter) SliceUint32(anyInput any, option ...SliceOption) ([]uint32, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tui          uint32\n\t\tarray       []uint32 = nil\n\t\tsliceOption          = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []int8:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []int32:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []int64:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []uint:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []uint32{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tui, err = c.Uint32(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []uint32{ui}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = value\n\tcase []uint64:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint32(v)\n\t\t}\n\tcase []bool:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []float64:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []any:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]uint32, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint32(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\n\t// Default handler.\n\tif v, ok := anyInput.(localinterface.IUints); ok {\n\t\treturn c.SliceUint32(v.Uints(), option...)\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceUint32(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]uint32, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ui\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []uint32{}, err\n\t\t}\n\t\tui, err = c.Uint32(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []uint32{ui}, err\n\t}\n}\n\n// SliceUint64 converts `any` to []uint64.\nfunc (c *Converter) SliceUint64(anyInput any, option ...SliceOption) ([]uint64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tvar (\n\t\terr         error\n\t\tui          uint64\n\t\tarray       []uint64 = nil\n\t\tsliceOption          = c.getSliceOption(option...)\n\t)\n\tswitch value := anyInput.(type) {\n\tcase []string:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []int8:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []int16:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []int32:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []int64:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []uint:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []uint8:\n\t\tif json.Valid(value) {\n\t\t\tif err = json.UnmarshalUseNumber(value, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase string:\n\t\tbyteValue := []byte(value)\n\t\tif json.Valid(byteValue) {\n\t\t\tif err = json.UnmarshalUseNumber(byteValue, &array); array != nil {\n\t\t\t\treturn array, err\n\t\t\t}\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn []uint64{}, err\n\t\t}\n\t\tif utils.IsNumeric(value) {\n\t\t\tui, err = c.Uint64(value)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn []uint64{ui}, err\n\t\t}\n\tcase []uint16:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []uint32:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tarray[k] = uint64(v)\n\t\t}\n\tcase []uint64:\n\t\tarray = value\n\tcase []bool:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tif v {\n\t\t\t\tarray[k] = 1\n\t\t\t} else {\n\t\t\t\tarray[k] = 0\n\t\t\t}\n\t\t}\n\tcase []float32:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []float64:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase []any:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\tcase [][]byte:\n\t\tarray = make([]uint64, len(value))\n\t\tfor k, v := range value {\n\t\t\tui, err = c.Uint64(v)\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tarray[k] = ui\n\t\t}\n\t}\n\tif array != nil {\n\t\treturn array, err\n\t}\n\t// Default handler.\n\tif v, ok := anyInput.(localinterface.IUints); ok {\n\t\treturn c.SliceUint64(v.Uints(), option...)\n\t}\n\tif v, ok := anyInput.(localinterface.IInterfaces); ok {\n\t\treturn c.SliceUint64(v.Interfaces(), option...)\n\t}\n\t// Not a common type, it then uses reflection for conversion.\n\toriginValueAndKind := reflection.OriginValueAndKind(anyInput)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\tlength = originValueAndKind.OriginValue.Len()\n\t\t\tslice  = make([]uint64, length)\n\t\t)\n\t\tfor i := 0; i < length; i++ {\n\t\t\tui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface())\n\t\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tslice[i] = ui\n\t\t}\n\t\treturn slice, err\n\n\tdefault:\n\t\tif originValueAndKind.OriginValue.IsZero() {\n\t\t\treturn []uint64{}, err\n\t\t}\n\t\tui, err = c.Uint64(anyInput)\n\t\tif err != nil && !sliceOption.ContinueOnError {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []uint64{ui}, err\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_string.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\nfunc (c *Converter) String(anyInput any) (string, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn \"\", nil\n\t}\n\tswitch value := anyInput.(type) {\n\tcase int:\n\t\treturn strconv.Itoa(value), nil\n\tcase int8:\n\t\treturn strconv.Itoa(int(value)), nil\n\tcase int16:\n\t\treturn strconv.Itoa(int(value)), nil\n\tcase int32:\n\t\treturn strconv.Itoa(int(value)), nil\n\tcase int64:\n\t\treturn strconv.FormatInt(value, 10), nil\n\tcase uint:\n\t\treturn strconv.FormatUint(uint64(value), 10), nil\n\tcase uint8:\n\t\treturn strconv.FormatUint(uint64(value), 10), nil\n\tcase uint16:\n\t\treturn strconv.FormatUint(uint64(value), 10), nil\n\tcase uint32:\n\t\treturn strconv.FormatUint(uint64(value), 10), nil\n\tcase uint64:\n\t\treturn strconv.FormatUint(value, 10), nil\n\tcase float32:\n\t\treturn strconv.FormatFloat(float64(value), 'f', -1, 32), nil\n\tcase float64:\n\t\treturn strconv.FormatFloat(value, 'f', -1, 64), nil\n\tcase bool:\n\t\treturn strconv.FormatBool(value), nil\n\tcase string:\n\t\treturn value, nil\n\tcase []byte:\n\t\treturn string(value), nil\n\tcase complex64, complex128:\n\t\treturn fmt.Sprintf(\"%v\", value), nil\n\tcase time.Time:\n\t\tif value.IsZero() {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn value.String(), nil\n\tcase *time.Time:\n\t\tif value == nil {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn value.String(), nil\n\tcase gtime.Time:\n\t\tif value.IsZero() {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn value.String(), nil\n\tcase *gtime.Time:\n\t\tif value == nil {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn value.String(), nil\n\tdefault:\n\t\tif f, ok := value.(localinterface.IString); ok {\n\t\t\t// If the variable implements the String() interface,\n\t\t\t// then use that interface to perform the conversion\n\t\t\treturn f.String(), nil\n\t\t}\n\t\tif f, ok := value.(localinterface.IError); ok {\n\t\t\t// If the variable implements the Error() interface,\n\t\t\t// then use that interface to perform the conversion\n\t\t\treturn f.Error(), nil\n\t\t}\n\t\t// Reflect checks.\n\t\tvar (\n\t\t\trv   = reflect.ValueOf(value)\n\t\t\tkind = rv.Kind()\n\t\t)\n\t\tswitch kind {\n\t\tcase\n\t\t\treflect.Chan,\n\t\t\treflect.Map,\n\t\t\treflect.Slice,\n\t\t\treflect.Func,\n\t\t\treflect.Interface,\n\t\t\treflect.UnsafePointer:\n\t\t\tif rv.IsNil() {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\t\tcase reflect.String:\n\t\t\treturn rv.String(), nil\n\t\tcase reflect.Pointer:\n\t\t\tif rv.IsNil() {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\t\t\treturn c.String(rv.Elem().Interface())\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\treturn strconv.FormatInt(rv.Int(), 10), nil\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\treturn strconv.FormatUint(rv.Uint(), 10), nil\n\t\tcase reflect.Uintptr:\n\t\t\treturn strconv.FormatUint(rv.Uint(), 10), nil\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\treturn strconv.FormatFloat(rv.Float(), 'f', -1, 64), nil\n\t\tcase reflect.Bool:\n\t\t\treturn strconv.FormatBool(rv.Bool()), nil\n\t\tdefault:\n\t\t}\n\t\t// Finally, we use json.Marshal to convert.\n\t\tjsonContent, err := json.Marshal(value)\n\t\tif err != nil {\n\t\t\treturn fmt.Sprint(value), gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter, err, \"error marshaling value to JSON for: %v\", value,\n\t\t\t)\n\t\t}\n\t\treturn string(jsonContent), nil\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_struct.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/structcache\"\n)\n\n// StructOption is the option for Struct converting.\ntype StructOption struct {\n\t// ParamKeyToAttrMap is the map for custom parameter key to attribute name mapping.\n\tParamKeyToAttrMap map[string]string\n\n\t// PriorityTag is the priority tag for struct converting.\n\tPriorityTag string\n\n\t// ContinueOnError specifies whether to continue converting the next element\n\t// if one element converting fails.\n\tContinueOnError bool\n\n\t// OmitEmpty specifies whether to skip assignment when the source value is empty\n\t// (empty string, zero value, etc.), preserving the existing value in the\n\t// destination field.\n\tOmitEmpty bool\n\n\t// OmitNil specifies whether to skip assignment when the source value is nil,\n\t// preserving the existing value in the destination field.\n\tOmitNil bool\n}\n\nfunc (c *Converter) getStructOption(option ...StructOption) StructOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn StructOption{}\n}\n\n// Struct is the core internal converting function for any data to struct.\nfunc (c *Converter) Struct(params, pointer any, option ...StructOption) (err error) {\n\tif params == nil {\n\t\t// If `params` is nil, no conversion.\n\t\treturn nil\n\t}\n\tif pointer == nil {\n\t\treturn gerror.NewCode(gcode.CodeInvalidParameter, \"object pointer cannot be nil\")\n\t}\n\n\t// JSON content converting.\n\tok, err := c.doConvertWithJSONCheck(params, pointer)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ok {\n\t\treturn nil\n\t}\n\n\tdefer func() {\n\t\t// Catch the panic, especially the reflection operation panics.\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, \"%+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\n\tvar (\n\t\tstructOption            = c.getStructOption(option...)\n\t\tparamsReflectValue      reflect.Value\n\t\tparamsInterface         any // DO NOT use `params` directly as it might be type `reflect.Value`\n\t\tpointerReflectValue     reflect.Value\n\t\tpointerReflectKind      reflect.Kind\n\t\tpointerElemReflectValue reflect.Value // The reflection value to struct element.\n\t)\n\tif v, ok := params.(reflect.Value); ok {\n\t\tparamsReflectValue = v\n\t} else {\n\t\tparamsReflectValue = reflect.ValueOf(params)\n\t}\n\tparamsInterface = paramsReflectValue.Interface()\n\tif v, ok := pointer.(reflect.Value); ok {\n\t\tpointerReflectValue = v\n\t\tpointerElemReflectValue = v\n\t} else {\n\t\tpointerReflectValue = reflect.ValueOf(pointer)\n\t\tpointerReflectKind = pointerReflectValue.Kind()\n\t\tif pointerReflectKind != reflect.Pointer {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\"destination pointer should be type of '*struct', but got '%v'\",\n\t\t\t\tpointerReflectKind,\n\t\t\t)\n\t\t}\n\t\t// Using IsNil on reflect.Pointer variable is OK.\n\t\tif !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() {\n\t\t\treturn gerror.NewCode(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\"destination pointer cannot be nil\",\n\t\t\t)\n\t\t}\n\t\tpointerElemReflectValue = pointerReflectValue.Elem()\n\t}\n\n\t// If `params` and `pointer` are the same type, the do directly assignment.\n\t// For performance enhancement purpose.\n\tif ok = c.doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok {\n\t\treturn nil\n\t}\n\n\t// custom convert.\n\tok, err = c.callCustomConverter(paramsReflectValue, pointerReflectValue)\n\tif err != nil && !structOption.ContinueOnError {\n\t\treturn err\n\t}\n\tif ok {\n\t\treturn nil\n\t}\n\n\t// Normal unmarshalling interfaces checks.\n\tif ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok {\n\t\treturn err\n\t}\n\n\t// It automatically creates struct object if necessary.\n\t// For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.\n\tif pointerElemReflectValue.Kind() == reflect.Pointer {\n\t\tif !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {\n\t\t\te := reflect.New(pointerElemReflectValue.Type().Elem())\n\t\t\tpointerElemReflectValue.Set(e)\n\t\t\tdefer func() {\n\t\t\t\tif err != nil {\n\t\t\t\t\t// If it is converted failed, it reset the `pointer` to nil.\n\t\t\t\t\tpointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem()))\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t\t// if v, ok := pointerElemReflectValue.Interface().(localinterface.IUnmarshalValue); ok {\n\t\t//\treturn v.UnmarshalValue(params)\n\t\t// }\n\t\t// Note that it's `pointerElemReflectValue` here not `pointerReflectValue`.\n\t\tif ok, err = bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok {\n\t\t\treturn err\n\t\t}\n\t\t// Retrieve its element, may be struct at last.\n\t\tpointerElemReflectValue = pointerElemReflectValue.Elem()\n\t}\n\tparamsMap, ok := paramsInterface.(map[string]any)\n\tif !ok {\n\t\t// paramsMap is the map[string]any type variable for params.\n\t\t// DO NOT use MapDeep here.\n\t\tparamsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{\n\t\t\tContinueOnError: structOption.ContinueOnError,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif paramsMap == nil {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`convert params from \"%#v\" to \"map[string]any\" failed`,\n\t\t\t\tparams,\n\t\t\t)\n\t\t}\n\t}\n\t// Nothing to be done as the parameters are empty.\n\tif len(paramsMap) == 0 {\n\t\treturn nil\n\t}\n\t// Get struct info from cache or parse struct and cache the struct info.\n\tcachedStructInfo := c.internalConverter.GetCachedStructInfo(\n\t\tpointerElemReflectValue.Type(), structOption.PriorityTag,\n\t)\n\t// Nothing to be converted.\n\tif cachedStructInfo == nil {\n\t\treturn nil\n\t}\n\t// For the structure types of 0 tagOrFiledNameToFieldInfoMap,\n\t// they also need to be cached to prevent invalid logic\n\tif cachedStructInfo.HasNoFields() {\n\t\treturn nil\n\t}\n\tvar (\n\t\t// Indicates that those values have been used and cannot be reused.\n\t\tusedParamsKeyOrTagNameMap = structcache.GetUsedParamsKeyOrTagNameMapFromPool()\n\t\tcachedFieldInfo           *structcache.CachedFieldInfo\n\t\tparamsValue               any\n\t)\n\tdefer structcache.PutUsedParamsKeyOrTagNameMapToPool(usedParamsKeyOrTagNameMap)\n\n\t// Firstly, search according to custom mapping rules.\n\t// If a possible direct assignment is found, reduce the number of subsequent map searches.\n\tfor paramKey, fieldName := range structOption.ParamKeyToAttrMap {\n\t\tparamsValue, ok = paramsMap[paramKey]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tcachedFieldInfo = cachedStructInfo.GetFieldInfo(fieldName)\n\t\tif cachedFieldInfo != nil {\n\t\t\tfieldValue := cachedFieldInfo.GetFieldReflectValueFrom(pointerElemReflectValue)\n\t\t\tif err = c.bindVarToStructField(\n\t\t\t\tcachedFieldInfo,\n\t\t\t\tfieldValue,\n\t\t\t\tparamsValue,\n\t\t\t\tstructOption,\n\t\t\t); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif len(cachedFieldInfo.OtherSameNameField) > 0 {\n\t\t\t\tif err = c.setOtherSameNameField(\n\t\t\t\t\tcachedFieldInfo, paramsValue, pointerReflectValue, structOption,\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tusedParamsKeyOrTagNameMap[paramKey] = struct{}{}\n\t\t}\n\t}\n\t// Already done converting for given `paramsMap`.\n\tif len(usedParamsKeyOrTagNameMap) == len(paramsMap) {\n\t\treturn nil\n\t}\n\treturn c.bindStructWithLoopFieldInfos(\n\t\tparamsMap, pointerElemReflectValue,\n\t\tusedParamsKeyOrTagNameMap, cachedStructInfo,\n\t\tstructOption,\n\t)\n}\n\nfunc (c *Converter) setOtherSameNameField(\n\tcachedFieldInfo *structcache.CachedFieldInfo,\n\tsrcValue any,\n\tstructValue reflect.Value,\n\toption StructOption,\n) (err error) {\n\t// loop the same field name of all sub attributes.\n\tfor _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField {\n\t\tfieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes)\n\t\tif err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, option); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *Converter) bindStructWithLoopFieldInfos(\n\tparamsMap map[string]any,\n\tstructValue reflect.Value,\n\tusedParamsKeyOrTagNameMap map[string]struct{},\n\tcachedStructInfo *structcache.CachedStructInfo,\n\toption StructOption,\n) (err error) {\n\tvar (\n\t\tcachedFieldInfo *structcache.CachedFieldInfo\n\t\tfuzzLastKey     string\n\t\tfieldValue      reflect.Value\n\t\tparamKey        string\n\t\tparamValue      any\n\t\tmatched         bool\n\t\tok              bool\n\t)\n\tfor _, cachedFieldInfo = range cachedStructInfo.GetFieldConvertInfos() {\n\t\tfor _, fieldTag := range cachedFieldInfo.PriorityTagAndFieldName {\n\t\t\tif paramValue, ok = paramsMap[fieldTag]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue)\n\t\t\tif err = c.bindVarToStructField(\n\t\t\t\tcachedFieldInfo, fieldValue, paramValue, option,\n\t\t\t); err != nil && !option.ContinueOnError {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// handle same field name in nested struct.\n\t\t\tif len(cachedFieldInfo.OtherSameNameField) > 0 {\n\t\t\t\tif err = c.setOtherSameNameField(\n\t\t\t\t\tcachedFieldInfo, paramValue, structValue, option,\n\t\t\t\t); err != nil && !option.ContinueOnError {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tusedParamsKeyOrTagNameMap[fieldTag] = struct{}{}\n\t\t\tmatched = true\n\t\t\tbreak\n\t\t}\n\t\tif matched {\n\t\t\tmatched = false\n\t\t\tcontinue\n\t\t}\n\n\t\tfuzzLastKey = cachedFieldInfo.LastFuzzyKey.Load().(string)\n\t\tif paramValue, ok = paramsMap[fuzzLastKey]; !ok {\n\t\t\tparamKey, paramValue = fuzzyMatchingFieldName(\n\t\t\t\tcachedFieldInfo.RemoveSymbolsFieldName, paramsMap, usedParamsKeyOrTagNameMap,\n\t\t\t)\n\t\t\tok = paramKey != \"\"\n\t\t\tcachedFieldInfo.LastFuzzyKey.Store(paramKey)\n\t\t}\n\t\tif ok {\n\t\t\tfieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue)\n\t\t\tif paramValue != nil {\n\t\t\t\tif err = c.bindVarToStructField(\n\t\t\t\t\tcachedFieldInfo, fieldValue, paramValue, option,\n\t\t\t\t); err != nil && !option.ContinueOnError {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t// handle same field name in nested struct.\n\t\t\t\tif len(cachedFieldInfo.OtherSameNameField) > 0 {\n\t\t\t\t\tif err = c.setOtherSameNameField(\n\t\t\t\t\t\tcachedFieldInfo, paramValue, structValue, option,\n\t\t\t\t\t); err != nil && !option.ContinueOnError {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tusedParamsKeyOrTagNameMap[paramKey] = struct{}{}\n\t\t}\n\t}\n\treturn nil\n}\n\n// fuzzy matching rule:\n// to match field name and param key in case-insensitive and without symbols.\nfunc fuzzyMatchingFieldName(\n\tfieldName string,\n\tparamsMap map[string]any,\n\tusedParamsKeyMap map[string]struct{},\n) (string, any) {\n\tfor paramKey, paramValue := range paramsMap {\n\t\tif _, ok := usedParamsKeyMap[paramKey]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tremoveParamKeyUnderline := utils.RemoveSymbols(paramKey)\n\t\tif strings.EqualFold(fieldName, removeParamKeyUnderline) {\n\t\t\treturn paramKey, paramValue\n\t\t}\n\t}\n\treturn \"\", nil\n}\n\n// bindVarToStructField sets value to struct object attribute by name.\n// each value to attribute converting comes into in this function.\nfunc (c *Converter) bindVarToStructField(\n\tcachedFieldInfo *structcache.CachedFieldInfo,\n\tfieldValue reflect.Value,\n\tsrcValue any,\n\toption StructOption,\n) (err error) {\n\tif !fieldValue.IsValid() {\n\t\treturn nil\n\t}\n\t// CanSet checks whether attribute is public accessible.\n\tif !fieldValue.CanSet() {\n\t\treturn nil\n\t}\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif err = c.bindVarToReflectValue(fieldValue, srcValue, option); err != nil {\n\t\t\t\terr = gerror.Wrapf(err, `error binding srcValue to attribute \"%s\"`, cachedFieldInfo.FieldName())\n\t\t\t}\n\t\t}\n\t}()\n\t// Check if the value should be omitted based on OmitEmpty or OmitNil options\n\tif option.OmitNil && empty.IsNil(srcValue) {\n\t\treturn nil\n\t}\n\tif option.OmitEmpty && empty.IsEmpty(srcValue) {\n\t\treturn nil\n\t}\n\t// Directly converting.\n\tif empty.IsNil(srcValue) {\n\t\tfieldValue.Set(reflect.Zero(fieldValue.Type()))\n\t\treturn nil\n\t}\n\t// Try to call custom converter.\n\t// Issue: https://github.com/gogf/gf/issues/3099\n\tvar (\n\t\tcustomConverterInput reflect.Value\n\t\tok                   bool\n\t)\n\tif cachedFieldInfo.HasCustomConvert {\n\t\tif customConverterInput, ok = srcValue.(reflect.Value); !ok {\n\t\t\tcustomConverterInput = reflect.ValueOf(srcValue)\n\t\t}\n\t\tif ok, err = c.callCustomConverter(customConverterInput, fieldValue); ok || err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tif cachedFieldInfo.IsCommonInterface {\n\t\tif ok, err = bindVarToReflectValueWithInterfaceCheck(fieldValue, srcValue); ok || err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\t// Common types use fast assignment logic\n\tif cachedFieldInfo.ConvertFunc != nil {\n\t\treturn cachedFieldInfo.ConvertFunc(srcValue, fieldValue)\n\t}\n\tconvertOption := ConvertOption{\n\t\tStructOption: option,\n\t\tSliceOption:  SliceOption{ContinueOnError: option.ContinueOnError},\n\t\tMapOption:    MapOption{ContinueOnError: option.ContinueOnError},\n\t}\n\terr = c.doConvertWithReflectValueSet(\n\t\tfieldValue, doConvertInput{\n\t\t\tFromValue:  srcValue,\n\t\t\tToTypeName: cachedFieldInfo.StructField.Type.String(),\n\t\t\tReferValue: fieldValue,\n\t\t},\n\t\tconvertOption,\n\t)\n\treturn err\n}\n\n// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.\nfunc bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value any) (bool, error) {\n\tvar pointer any\n\tif reflectValue.Kind() != reflect.Pointer && reflectValue.CanAddr() {\n\t\treflectValueAddr := reflectValue.Addr()\n\t\tif reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() {\n\t\t\treturn false, nil\n\t\t}\n\t\t// Not a pointer, but can token address, that makes it can be unmarshalled.\n\t\tpointer = reflectValue.Addr().Interface()\n\t} else {\n\t\tif reflectValue.IsNil() || !reflectValue.IsValid() {\n\t\t\treturn false, nil\n\t\t}\n\t\tpointer = reflectValue.Interface()\n\t}\n\t// UnmarshalValue.\n\tif v, ok := pointer.(localinterface.IUnmarshalValue); ok {\n\t\treturn ok, v.UnmarshalValue(value)\n\t}\n\t// UnmarshalText.\n\tif v, ok := pointer.(localinterface.IUnmarshalText); ok {\n\t\tvar valueBytes []byte\n\t\tif b, ok := value.([]byte); ok {\n\t\t\tvalueBytes = b\n\t\t} else if s, ok := value.(string); ok {\n\t\t\tvalueBytes = []byte(s)\n\t\t} else if f, ok := value.(localinterface.IString); ok {\n\t\t\tvalueBytes = []byte(f.String())\n\t\t}\n\t\tif len(valueBytes) > 0 {\n\t\t\treturn ok, v.UnmarshalText(valueBytes)\n\t\t}\n\t}\n\t// UnmarshalJSON.\n\tif v, ok := pointer.(localinterface.IUnmarshalJSON); ok {\n\t\tvar valueBytes []byte\n\t\tif b, ok := value.([]byte); ok {\n\t\t\tvalueBytes = b\n\t\t} else if s, ok := value.(string); ok {\n\t\t\tvalueBytes = []byte(s)\n\t\t} else if f, ok := value.(localinterface.IString); ok {\n\t\t\tvalueBytes = []byte(f.String())\n\t\t}\n\n\t\tif len(valueBytes) > 0 {\n\t\t\t// If it is not a valid JSON string, it then adds char `\"` on its both sides to make it is.\n\t\t\tif !json.Valid(valueBytes) {\n\t\t\t\tnewValueBytes := make([]byte, len(valueBytes)+2)\n\t\t\t\tnewValueBytes[0] = '\"'\n\t\t\t\tnewValueBytes[len(newValueBytes)-1] = '\"'\n\t\t\t\tcopy(newValueBytes[1:], valueBytes)\n\t\t\t\tvalueBytes = newValueBytes\n\t\t\t}\n\t\t\treturn ok, v.UnmarshalJSON(valueBytes)\n\t\t}\n\t}\n\tif v, ok := pointer.(localinterface.ISet); ok {\n\t\tv.Set(value)\n\t\treturn ok, nil\n\t}\n\treturn false, nil\n}\n\n// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.\nfunc (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value any, option StructOption) (err error) {\n\t// JSON content converting.\n\tok, err := c.doConvertWithJSONCheck(value, structFieldValue)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ok {\n\t\treturn nil\n\t}\n\n\tkind := structFieldValue.Kind()\n\t// Converting using `Set` interface implements, for some types.\n\tswitch kind {\n\tcase reflect.Slice, reflect.Array, reflect.Pointer, reflect.Interface:\n\t\tif !structFieldValue.IsNil() {\n\t\t\tif v, ok := structFieldValue.Interface().(localinterface.ISet); ok {\n\t\t\t\tv.Set(value)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\tdefault:\n\t}\n\n\t// Converting using reflection by kind.\n\tswitch kind {\n\tcase reflect.Map:\n\t\treturn c.MapToMap(value, structFieldValue, option.ParamKeyToAttrMap, MapOption{\n\t\t\tContinueOnError: option.ContinueOnError,\n\t\t})\n\n\tcase reflect.Struct:\n\t\t// Recursively converting for struct attribute.\n\t\tif err = c.Struct(value, structFieldValue, option); err != nil {\n\t\t\t// Note there's reflect conversion mechanism here.\n\t\t\tstructFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))\n\t\t}\n\n\t// Note that the slice element might be type of struct,\n\t// so it uses Struct function doing the converting internally.\n\tcase reflect.Slice, reflect.Array:\n\t\tvar (\n\t\t\treflectArray  reflect.Value\n\t\t\treflectValue  = reflect.ValueOf(value)\n\t\t\tconvertOption = ConvertOption{\n\t\t\t\tStructOption: option,\n\t\t\t\tSliceOption:  SliceOption{ContinueOnError: option.ContinueOnError},\n\t\t\t\tMapOption:    MapOption{ContinueOnError: option.ContinueOnError},\n\t\t\t}\n\t\t)\n\t\tif reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array {\n\t\t\treflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len())\n\t\t\tif reflectValue.Len() > 0 {\n\t\t\t\tvar (\n\t\t\t\t\telemType     = reflectArray.Index(0).Type()\n\t\t\t\t\telemTypeName string\n\t\t\t\t\tconverted    bool\n\t\t\t\t)\n\t\t\t\tfor i := 0; i < reflectValue.Len(); i++ {\n\t\t\t\t\tconverted = false\n\t\t\t\t\telemTypeName = elemType.Name()\n\t\t\t\t\tif elemTypeName == \"\" {\n\t\t\t\t\t\telemTypeName = elemType.String()\n\t\t\t\t\t}\n\t\t\t\t\tvar elem reflect.Value\n\t\t\t\t\tif elemType.Kind() == reflect.Pointer {\n\t\t\t\t\t\telem = reflect.New(elemType.Elem()).Elem()\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem = reflect.New(elemType).Elem()\n\t\t\t\t\t}\n\t\t\t\t\tif elem.Kind() == reflect.Struct {\n\t\t\t\t\t\tif err = c.Struct(reflectValue.Index(i).Interface(), elem, option); err == nil {\n\t\t\t\t\t\t\tconverted = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif !converted {\n\t\t\t\t\t\terr = c.doConvertWithReflectValueSet(\n\t\t\t\t\t\t\telem, doConvertInput{\n\t\t\t\t\t\t\t\tFromValue:  reflectValue.Index(i).Interface(),\n\t\t\t\t\t\t\t\tToTypeName: elemTypeName,\n\t\t\t\t\t\t\t\tReferValue: elem,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tconvertOption,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif elemType.Kind() == reflect.Pointer {\n\t\t\t\t\t\t// Before it sets the `elem` to array, do pointer converting if necessary.\n\t\t\t\t\t\telem = elem.Addr()\n\t\t\t\t\t}\n\t\t\t\t\treflectArray.Index(i).Set(elem)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tvar (\n\t\t\t\telem         reflect.Value\n\t\t\t\telemType     = structFieldValue.Type().Elem()\n\t\t\t\telemTypeName = elemType.Name()\n\t\t\t\tconverted    bool\n\t\t\t)\n\t\t\tswitch reflectValue.Kind() {\n\t\t\tcase reflect.String:\n\t\t\t\t// Value is empty string.\n\t\t\t\tif reflectValue.IsZero() {\n\t\t\t\t\tvar elemKind = elemType.Kind()\n\t\t\t\t\t// Try to find the original type kind of the slice element.\n\t\t\t\t\tif elemKind == reflect.Pointer {\n\t\t\t\t\t\telemKind = elemType.Elem().Kind()\n\t\t\t\t\t}\n\t\t\t\t\tswitch elemKind {\n\t\t\t\t\tcase reflect.String:\n\t\t\t\t\t\t// Empty string cannot be assigned to string slice.\n\t\t\t\t\t\treturn nil\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t\tif elemTypeName == \"\" {\n\t\t\t\telemTypeName = elemType.String()\n\t\t\t}\n\t\t\tif elemType.Kind() == reflect.Pointer {\n\t\t\t\telem = reflect.New(elemType.Elem()).Elem()\n\t\t\t} else {\n\t\t\t\telem = reflect.New(elemType).Elem()\n\t\t\t}\n\t\t\tif elem.Kind() == reflect.Struct {\n\t\t\t\tif err = c.Struct(value, elem, option); err == nil {\n\t\t\t\t\tconverted = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !converted {\n\t\t\t\terr = c.doConvertWithReflectValueSet(\n\t\t\t\t\telem, doConvertInput{\n\t\t\t\t\t\tFromValue:  value,\n\t\t\t\t\t\tToTypeName: elemTypeName,\n\t\t\t\t\t\tReferValue: elem,\n\t\t\t\t\t},\n\t\t\t\t\tconvertOption,\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif elemType.Kind() == reflect.Pointer {\n\t\t\t\t// Before it sets the `elem` to array, do pointer converting if necessary.\n\t\t\t\telem = elem.Addr()\n\t\t\t}\n\t\t\treflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1)\n\t\t\treflectArray.Index(0).Set(elem)\n\t\t}\n\t\tstructFieldValue.Set(reflectArray)\n\n\tcase reflect.Pointer:\n\t\tif structFieldValue.IsNil() || structFieldValue.IsZero() {\n\t\t\t// Nil or empty pointer, it creates a new one.\n\t\t\titem := reflect.New(structFieldValue.Type().Elem())\n\t\t\tif ok, err = bindVarToReflectValueWithInterfaceCheck(item, value); ok {\n\t\t\t\tstructFieldValue.Set(item)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\telem := item.Elem()\n\t\t\tif err = c.bindVarToReflectValue(elem, value, option); err == nil {\n\t\t\t\tstructFieldValue.Set(elem.Addr())\n\t\t\t}\n\t\t} else {\n\t\t\t// Not empty pointer, it assigns values to it.\n\t\t\treturn c.bindVarToReflectValue(structFieldValue.Elem(), value, option)\n\t\t}\n\n\t// It mainly and specially handles the interface of nil value.\n\tcase reflect.Interface:\n\t\tif value == nil {\n\t\t\t// Specially.\n\t\t\tstructFieldValue.Set(reflect.ValueOf((*any)(nil)))\n\t\t} else {\n\t\t\t// Note there's reflect conversion mechanism here.\n\t\t\tstructFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))\n\t\t}\n\n\tdefault:\n\t\tdefer func() {\n\t\t\tif exception := recover(); exception != nil {\n\t\t\t\terr = gerror.NewCodef(\n\t\t\t\t\tgcode.CodeInternalPanic,\n\t\t\t\t\t`cannot convert value \"%+v\" to type \"%s\":%+v`,\n\t\t\t\t\tvalue,\n\t\t\t\t\tstructFieldValue.Type().String(),\n\t\t\t\t\texception,\n\t\t\t\t)\n\t\t\t}\n\t\t}()\n\t\t// It here uses reflect converting `value` to type of the attribute and assigns\n\t\t// the result value to the attribute. It might fail and panic if the usual Go\n\t\t// conversion rules do not allow conversion.\n\t\tstructFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_structs.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// StructsOption is the option for Structs function.\ntype StructsOption struct {\n\tSliceOption  SliceOption\n\tStructOption StructOption\n}\n\nfunc (c *Converter) getStructsOption(option ...StructsOption) StructsOption {\n\tif len(option) > 0 {\n\t\treturn option[0]\n\t}\n\treturn StructsOption{}\n}\n\n// Structs converts any slice to given struct slice.\n//\n// It automatically checks and converts json string to []map if `params` is string/[]byte.\n//\n// The parameter `pointer` should be type of pointer to slice of struct.\n// Note that if `pointer` is a pointer to another pointer of type of slice of struct,\n// it will create the struct/pointer internally.\nfunc (c *Converter) Structs(params any, pointer any, option ...StructsOption) (err error) {\n\tdefer func() {\n\t\t// Catch the panic, especially the reflection operation panics.\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, \"%+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Pointer type check.\n\tpointerRv, ok := pointer.(reflect.Value)\n\tif !ok {\n\t\tpointerRv = reflect.ValueOf(pointer)\n\t\tif kind := pointerRv.Kind(); kind != reflect.Pointer {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t\"pointer should be type of pointer, but got: %v\", kind,\n\t\t\t)\n\t\t}\n\t}\n\t// Converting `params` to map slice.\n\tvar (\n\t\tparamsList    []any\n\t\tparamsRv      = reflect.ValueOf(params)\n\t\tparamsKind    = paramsRv.Kind()\n\t\tstructsOption = c.getStructsOption(option...)\n\t)\n\tfor paramsKind == reflect.Pointer {\n\t\tparamsRv = paramsRv.Elem()\n\t\tparamsKind = paramsRv.Kind()\n\t}\n\tswitch paramsKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tparamsList = make([]any, paramsRv.Len())\n\t\tfor i := 0; i < paramsRv.Len(); i++ {\n\t\t\tparamsList[i] = paramsRv.Index(i).Interface()\n\t\t}\n\tdefault:\n\t\tparamsMaps, err := c.SliceMap(params, SliceMapOption{\n\t\t\tSliceOption: structsOption.SliceOption,\n\t\t\tMapOption: MapOption{\n\t\t\t\tContinueOnError: structsOption.StructOption.ContinueOnError,\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tparamsList = make([]any, len(paramsMaps))\n\t\tfor i := 0; i < len(paramsMaps); i++ {\n\t\t\tparamsList[i] = paramsMaps[i]\n\t\t}\n\t}\n\t// If `params` is an empty slice, no conversion.\n\tif len(paramsList) == 0 {\n\t\treturn nil\n\t}\n\tvar (\n\t\treflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsList), len(paramsList))\n\t\titemType         = reflectElemArray.Index(0).Type()\n\t\titemTypeKind     = itemType.Kind()\n\t\tpointerRvElem    = pointerRv.Elem()\n\t\tpointerRvLength  = pointerRvElem.Len()\n\t)\n\tif itemTypeKind == reflect.Pointer {\n\t\t// Pointer element.\n\t\tfor i := 0; i < len(paramsList); i++ {\n\t\t\tvar tempReflectValue reflect.Value\n\t\t\tif i < pointerRvLength {\n\t\t\t\t// Might be nil.\n\t\t\t\ttempReflectValue = pointerRvElem.Index(i).Elem()\n\t\t\t}\n\t\t\tif !tempReflectValue.IsValid() {\n\t\t\t\ttempReflectValue = reflect.New(itemType.Elem()).Elem()\n\t\t\t}\n\t\t\tif err = c.Struct(paramsList[i], tempReflectValue, structsOption.StructOption); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treflectElemArray.Index(i).Set(tempReflectValue.Addr())\n\t\t}\n\t} else {\n\t\t// Struct element.\n\t\tfor i := 0; i < len(paramsList); i++ {\n\t\t\tvar tempReflectValue reflect.Value\n\t\t\tif i < pointerRvLength {\n\t\t\t\ttempReflectValue = pointerRvElem.Index(i)\n\t\t\t} else {\n\t\t\t\ttempReflectValue = reflect.New(itemType).Elem()\n\t\t\t}\n\t\t\tif err = c.Struct(paramsList[i], tempReflectValue, structsOption.StructOption); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treflectElemArray.Index(i).Set(tempReflectValue)\n\t\t}\n\t}\n\tpointerRv.Elem().Set(reflectElemArray)\n\treturn nil\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_time.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Time converts `any` to time.Time.\nfunc (c *Converter) Time(anyInput any, format ...string) (time.Time, error) {\n\t// It's already this type.\n\tif len(format) == 0 {\n\t\tif v, ok := anyInput.(time.Time); ok {\n\t\t\treturn v, nil\n\t\t}\n\t}\n\tt, err := c.GTime(anyInput, format...)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\tif t != nil {\n\t\treturn t.Time, nil\n\t}\n\treturn time.Time{}, nil\n}\n\n// Duration converts `any` to time.Duration.\n// If `any` is string, then it uses time.ParseDuration to convert it.\n// If `any` is numeric, then it converts `any` as nanoseconds.\nfunc (c *Converter) Duration(anyInput any) (time.Duration, error) {\n\t// It's already this type.\n\tif v, ok := anyInput.(time.Duration); ok {\n\t\treturn v, nil\n\t}\n\ts, err := c.String(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif !utils.IsNumeric(s) {\n\t\treturn gtime.ParseDuration(s)\n\t}\n\ti, err := c.Int64(anyInput)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn time.Duration(i), nil\n}\n\n// GTime converts `any` to *gtime.Time.\n// The parameter `format` can be used to specify the format of `any`.\n// It returns the converted value that matched the first format of the formats slice.\n// If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric,\n// or using gtime.StrToTime if `any` is string.\nfunc (c *Converter) GTime(anyInput any, format ...string) (*gtime.Time, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn nil, nil\n\t}\n\tif v, ok := anyInput.(localinterface.IGTime); ok {\n\t\treturn v.GTime(format...), nil\n\t}\n\t// It's already this type.\n\tif len(format) == 0 {\n\t\tif v, ok := anyInput.(*gtime.Time); ok {\n\t\t\treturn v, nil\n\t\t}\n\t\tif t, ok := anyInput.(time.Time); ok {\n\t\t\treturn gtime.New(t), nil\n\t\t}\n\t\tif t, ok := anyInput.(*time.Time); ok {\n\t\t\treturn gtime.New(t), nil\n\t\t}\n\t}\n\ts, err := c.String(anyInput)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(s) == 0 {\n\t\treturn gtime.New(), nil\n\t}\n\t// Priority conversion using given format.\n\tif len(format) > 0 {\n\t\tfor _, item := range format {\n\t\t\tt, err := gtime.StrToTimeFormat(s, item)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif t != nil {\n\t\t\t\treturn t, nil\n\t\t\t}\n\t\t}\n\t\treturn nil, nil\n\t}\n\tif utils.IsNumeric(s) {\n\t\ti, err := c.Int64(s)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn gtime.NewFromTimeStamp(i), nil\n\t} else {\n\t\treturn gtime.StrToTime(s)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/converter/converter_uint.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage converter\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/encoding/gbinary\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\n// Uint converts `any` to uint.\nfunc (c *Converter) Uint(anyInput any) (uint, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(uint); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Uint64(anyInput)\n\treturn uint(v), err\n}\n\n// Uint8 converts `any` to uint8.\nfunc (c *Converter) Uint8(anyInput any) (uint8, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(uint8); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Uint64(anyInput)\n\treturn uint8(v), err\n}\n\n// Uint16 converts `any` to uint16.\nfunc (c *Converter) Uint16(anyInput any) (uint16, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(uint16); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Uint64(anyInput)\n\treturn uint16(v), err\n}\n\n// Uint32 converts `any` to uint32.\nfunc (c *Converter) Uint32(anyInput any) (uint32, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(uint32); ok {\n\t\treturn v, nil\n\t}\n\tv, err := c.Uint64(anyInput)\n\treturn uint32(v), err\n}\n\n// Uint64 converts `any` to uint64.\nfunc (c *Converter) Uint64(anyInput any) (uint64, error) {\n\tif empty.IsNil(anyInput) {\n\t\treturn 0, nil\n\t}\n\tif v, ok := anyInput.(uint64); ok {\n\t\treturn v, nil\n\t}\n\trv := reflect.ValueOf(anyInput)\n\tswitch rv.Kind() {\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tval := rv.Int()\n\t\tif val < 0 {\n\t\t\treturn uint64(val), gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot convert negative value \"%d\" to uint64`,\n\t\t\t\tval,\n\t\t\t)\n\t\t}\n\t\treturn uint64(val), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn rv.Uint(), nil\n\tcase reflect.Uintptr:\n\t\treturn rv.Uint(), nil\n\tcase reflect.Float32, reflect.Float64:\n\t\tval := rv.Float()\n\t\tif val < 0 {\n\t\t\treturn uint64(val), gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`cannot convert negative value \"%f\" to uint64`,\n\t\t\t\tval,\n\t\t\t)\n\t\t}\n\t\treturn uint64(val), nil\n\tcase reflect.Bool:\n\t\tif rv.Bool() {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn 0, nil\n\tcase reflect.Pointer:\n\t\tif rv.IsNil() {\n\t\t\treturn 0, nil\n\t\t}\n\t\tif f, ok := anyInput.(localinterface.IUint64); ok {\n\t\t\treturn f.Uint64(), nil\n\t\t}\n\t\treturn c.Uint64(rv.Elem().Interface())\n\tcase reflect.Slice:\n\t\tif rv.Type().Elem().Kind() == reflect.Uint8 {\n\t\t\treturn gbinary.DecodeToUint64(rv.Bytes()), nil\n\t\t}\n\t\treturn 0, gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`unsupport slice type \"%s\" for converting to uint64`,\n\t\t\trv.Type().String(),\n\t\t)\n\tcase reflect.String:\n\t\tvar s = rv.String()\n\t\t// Hexadecimal\n\t\tif len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {\n\t\t\tv, err := strconv.ParseUint(s[2:], 16, 64)\n\t\t\tif err == nil {\n\t\t\t\treturn v, nil\n\t\t\t}\n\t\t\treturn 0, gerror.WrapCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\terr,\n\t\t\t\t`cannot convert hexadecimal string \"%s\" to uint64`,\n\t\t\t\ts,\n\t\t\t)\n\t\t}\n\t\t// Decimal\n\t\tif v, err := strconv.ParseUint(s, 10, 64); err == nil {\n\t\t\treturn v, nil\n\t\t}\n\t\t// Float64\n\t\tif v, err := c.Float64(anyInput); err == nil {\n\t\t\tif math.IsNaN(v) {\n\t\t\t\treturn 0, nil\n\t\t\t}\n\t\t\treturn uint64(v), nil\n\t\t}\n\tdefault:\n\t\tif f, ok := anyInput.(localinterface.IUint64); ok {\n\t\t\treturn f.Uint64(), nil\n\t\t}\n\t}\n\treturn 0, gerror.NewCodef(\n\t\tgcode.CodeInvalidParameter,\n\t\t`unsupport value type \"%s\" for converting to uint64`,\n\t\treflect.TypeOf(anyInput).String(),\n\t)\n}\n"
  },
  {
    "path": "util/gconv/internal/localinterface/localinterface.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package localinterface defines some interfaces for converting usage.\npackage localinterface\n\nimport \"github.com/gogf/gf/v2/os/gtime\"\n\n// IVal is used for type assert api for Val().\ntype IVal interface {\n\tVal() any\n}\n\n// IString is used for type assert api for String().\ntype IString interface {\n\tString() string\n}\n\n// IBool is used for type assert api for Bool().\ntype IBool interface {\n\tBool() bool\n}\n\n// IInt64 is used for type assert api for Int64().\ntype IInt64 interface {\n\tInt64() int64\n}\n\n// IUint64 is used for type assert api for Uint64().\ntype IUint64 interface {\n\tUint64() uint64\n}\n\n// IFloat32 is used for type assert api for Float32().\ntype IFloat32 interface {\n\tFloat32() float32\n}\n\n// IFloat64 is used for type assert api for Float64().\ntype IFloat64 interface {\n\tFloat64() float64\n}\n\n// IError is used for type assert api for Error().\ntype IError interface {\n\tError() string\n}\n\n// IBytes is used for type assert api for Bytes().\ntype IBytes interface {\n\tBytes() []byte\n}\n\n// IInterface is used for type assert api for Interface().\ntype IInterface interface {\n\tInterface() any\n}\n\n// IInterfaces is used for type assert api for Interfaces().\ntype IInterfaces interface {\n\tInterfaces() []any\n}\n\n// IFloats is used for type assert api for Floats().\ntype IFloats interface {\n\tFloats() []float64\n}\n\n// IInts is used for type assert api for Ints().\ntype IInts interface {\n\tInts() []int\n}\n\n// IStrings is used for type assert api for Strings().\ntype IStrings interface {\n\tStrings() []string\n}\n\n// IUints is used for type assert api for Uints().\ntype IUints interface {\n\tUints() []uint\n}\n\n// IMapStrAny is the interface support for converting struct parameter to map.\ntype IMapStrAny interface {\n\tMapStrAny() map[string]any\n}\n\n// IUnmarshalText is the interface for custom defined types customizing value assignment.\n// Note that only pointer can implement interface IUnmarshalText.\ntype IUnmarshalText interface {\n\tUnmarshalText(text []byte) error\n}\n\n// IUnmarshalJSON is the interface for custom defined types customizing value assignment.\n// Note that only pointer can implement interface IUnmarshalJSON.\ntype IUnmarshalJSON interface {\n\tUnmarshalJSON(b []byte) error\n}\n\n// IUnmarshalValue is the interface for custom defined types customizing value assignment.\n// Note that only pointer can implement interface IUnmarshalValue.\ntype IUnmarshalValue interface {\n\tUnmarshalValue(any) error\n}\n\n// ISet is the interface for custom value assignment.\ntype ISet interface {\n\tSet(value any) (old any)\n}\n\n// IGTime is the interface for gtime.Time converting.\ntype IGTime interface {\n\tGTime(format ...string) *gtime.Time\n}\n"
  },
  {
    "path": "util/gconv/internal/structcache/structcache.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package structcache provides struct and field info cache feature to enhance performance for struct converting.\npackage structcache\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"sync\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/util/gconv/internal/localinterface\"\n)\n\ntype interfaceTypeConverter struct {\n\tinterfaceType reflect.Type\n\tconvertFunc   AnyConvertFunc\n}\n\n// Converter is the configuration for type converting.\ntype Converter struct {\n\t// map[reflect.Type]*CachedStructInfo\n\tcachedStructsInfoMap sync.Map\n\n\t// anyToTypeConvertMap for custom type converting from any to its reflect.Value.\n\tanyToTypeConvertMap map[reflect.Type]AnyConvertFunc\n\n\t// interfaceToTypeConvertMap used for converting any interface type\n\t// the reason why map is not used here, is because interface types cannot be instantiated\n\tinterfaceToTypeConvertMap []interfaceTypeConverter\n\n\t// typeConverterFuncMarkMap is used to store whether field types are registered to custom conversions\n\ttypeConverterFuncMarkMap map[reflect.Type]struct{}\n}\n\n// AnyConvertFunc is the function type for converting any to specified type.\n// Note that the parameter `to` is usually a pointer type.\ntype AnyConvertFunc func(from any, to reflect.Value) error\n\n// NewConverter creates and returns a new Converter object.\nfunc NewConverter() *Converter {\n\treturn &Converter{\n\t\tcachedStructsInfoMap:     sync.Map{},\n\t\ttypeConverterFuncMarkMap: make(map[reflect.Type]struct{}),\n\t\tanyToTypeConvertMap:      make(map[reflect.Type]AnyConvertFunc),\n\t}\n}\n\n// MarkTypeConvertFunc marks converting function registered for custom type.\nfunc (cf *Converter) MarkTypeConvertFunc(fieldType reflect.Type) {\n\tif fieldType.Kind() == reflect.Pointer {\n\t\tfieldType = fieldType.Elem()\n\t}\n\tcf.typeConverterFuncMarkMap[fieldType] = struct{}{}\n}\n\n// RegisterAnyConvertFunc registers custom type converting function for specified type.\nfunc (cf *Converter) RegisterAnyConvertFunc(dstType reflect.Type, convertFunc AnyConvertFunc) {\n\tif dstType == nil || convertFunc == nil {\n\t\treturn\n\t}\n\tfor dstType.Kind() == reflect.Pointer {\n\t\tdstType = dstType.Elem()\n\t}\n\tif dstType.Kind() == reflect.Interface {\n\t\tcf.interfaceToTypeConvertMap = append(cf.interfaceToTypeConvertMap, interfaceTypeConverter{\n\t\t\tinterfaceType: dstType,\n\t\t\tconvertFunc:   convertFunc,\n\t\t})\n\t\treturn\n\t}\n\tcf.anyToTypeConvertMap[dstType] = convertFunc\n\tintlog.Printf(\n\t\tcontext.Background(),\n\t\t`RegisterAnyConvertFunc: %s -> %s`,\n\t\tdstType.String(), runtime.FuncForPC(reflect.ValueOf(convertFunc).Pointer()).Name(),\n\t)\n}\n\n// GetAnyConvertFuncByType retrieves and returns the converting function for specified type.\nfunc (cf *Converter) GetAnyConvertFuncByType(dstType reflect.Type) AnyConvertFunc {\n\tif dstType.Kind() == reflect.Pointer {\n\t\tdstType = dstType.Elem()\n\t}\n\treturn cf.anyToTypeConvertMap[dstType]\n}\n\n// IsAnyConvertFuncEmpty checks whether there's any converting function registered.\nfunc (cf *Converter) IsAnyConvertFuncEmpty() bool {\n\treturn len(cf.anyToTypeConvertMap) == 0\n}\n\nfunc (cf *Converter) checkTypeImplInterface(t reflect.Type) AnyConvertFunc {\n\tif t.Kind() != reflect.Pointer {\n\t\tt = reflect.PointerTo(t)\n\t}\n\tfor _, inter := range cf.interfaceToTypeConvertMap {\n\t\tif t.Implements(inter.interfaceType) {\n\t\t\treturn inter.convertFunc\n\t\t}\n\t}\n\treturn nil\n}\n\nvar (\n\timplUnmarshalText  = reflect.TypeOf((*localinterface.IUnmarshalText)(nil)).Elem()\n\timplUnmarshalJSON  = reflect.TypeOf((*localinterface.IUnmarshalJSON)(nil)).Elem()\n\timplUnmarshalValue = reflect.TypeOf((*localinterface.IUnmarshalValue)(nil)).Elem()\n)\n\nfunc checkTypeIsCommonInterface(field reflect.StructField) bool {\n\tisCommonInterface := false\n\tswitch field.Type.String() {\n\tcase \"time.Time\", \"*time.Time\":\n\t\t// default convert.\n\n\tcase \"gtime.Time\", \"*gtime.Time\":\n\t\t// default convert.\n\n\tdefault:\n\t\t// Implemented three types of interfaces that must be pointer types, otherwise it is meaningless\n\t\tif field.Type.Kind() != reflect.Pointer {\n\t\t\tfield.Type = reflect.PointerTo(field.Type)\n\t\t}\n\t\tswitch {\n\t\tcase field.Type.Implements(implUnmarshalText):\n\t\t\tisCommonInterface = true\n\n\t\tcase field.Type.Implements(implUnmarshalJSON):\n\t\t\tisCommonInterface = true\n\n\t\tcase field.Type.Implements(implUnmarshalValue):\n\t\t\tisCommonInterface = true\n\t\t}\n\t}\n\treturn isCommonInterface\n}\n"
  },
  {
    "path": "util/gconv/internal/structcache/structcache_cached.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage structcache\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// GetCachedStructInfo retrieves or parses and returns a cached info for certain struct type.\n// The given `structType` should be type of struct.\nfunc (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo {\n\tif structType.Kind() != reflect.Struct {\n\t\treturn nil\n\t}\n\t// check if it has been cached.\n\tcachedStructInfo, ok := cf.getCachedConvertStructInfo(structType)\n\tif ok {\n\t\t// directly returns the cached struct info if already exists.\n\t\treturn cachedStructInfo\n\t}\n\n\t// else create one.\n\n\t// it parses and generates a cache info for given struct type.\n\tcachedStructInfo = NewCachedStructInfo(cf)\n\tvar (\n\t\tpriorityTagArray []string\n\t\tparentIndex      = make([]int, 0)\n\t)\n\tif priorityTag != \"\" {\n\t\tpriorityTagArray = append(utils.SplitAndTrim(priorityTag, \",\"), gtag.StructTagPriority...)\n\t} else {\n\t\tpriorityTagArray = gtag.StructTagPriority\n\t}\n\tcf.parseStructToCachedStructInfo(structType, parentIndex, cachedStructInfo, priorityTagArray)\n\tcf.storeCachedStructInfo(structType, cachedStructInfo)\n\treturn cachedStructInfo\n}\n\nfunc (cf *Converter) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) {\n\t// Temporarily enabled as an experimental feature\n\tcf.cachedStructsInfoMap.Store(structType, cachedStructInfo)\n}\n\nfunc (cf *Converter) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) {\n\t// Temporarily enabled as an experimental feature\n\tv, ok := cf.cachedStructsInfoMap.Load(structType)\n\tif ok {\n\t\treturn v.(*CachedStructInfo), ok\n\t}\n\treturn nil, false\n}\n\n// parseStructToCachedStructInfo parses given struct reflection type and stores its fields info into given CachedStructInfo.\n// It stores nothing into CachedStructInfo if given struct reflection type has no fields.\nfunc (cf *Converter) parseStructToCachedStructInfo(\n\tstructType reflect.Type,\n\tfieldIndexes []int,\n\tcachedStructInfo *CachedStructInfo,\n\tpriorityTagArray []string,\n) {\n\tvar (\n\t\tfieldName   string\n\t\tstructField reflect.StructField\n\t\tfieldType   reflect.Type\n\t)\n\t// TODO:\n\t//  Check if the structure has already been cached in the cache.\n\t//  If it has been cached, some information can be reused,\n\t//  but the [FieldIndex] needs to be reset.\n\t//  We will not implement it temporarily because it is somewhat complex\n\tfor i := 0; i < structType.NumField(); i++ {\n\t\tstructField = structType.Field(i)\n\t\tfieldType = structField.Type\n\t\tfieldName = structField.Name\n\t\t// Only do converting to public attributes.\n\t\tif !utils.IsLetterUpper(fieldName[0]) {\n\t\t\tcontinue\n\t\t}\n\n\t\tcopyFieldIndexes := make([]int, len(fieldIndexes))\n\t\tcopy(copyFieldIndexes, fieldIndexes)\n\n\t\t// normal basic attributes.\n\t\tif structField.Anonymous {\n\t\t\t// handle struct attributes, it might be struct/*struct embedded..\n\t\t\tif fieldType.Kind() == reflect.Pointer {\n\t\t\t\tfieldType = fieldType.Elem()\n\t\t\t}\n\t\t\tif fieldType.Kind() != reflect.Struct {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Skip the embedded structure of the 0 field,\n\t\t\tif fieldType.NumField() == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif structField.Tag != \"\" {\n\t\t\t\t// Do not add anonymous structures without tags\n\t\t\t\tcachedStructInfo.AddField(structField, append(copyFieldIndexes, i), priorityTagArray)\n\t\t\t}\n\t\t\tcf.parseStructToCachedStructInfo(fieldType, append(copyFieldIndexes, i), cachedStructInfo, priorityTagArray)\n\t\t\tcontinue\n\t\t}\n\t\t// Do not directly use append(fieldIndexes, i)\n\t\t// When the structure is nested deeply, it may lead to bugs,\n\t\t// which are caused by the slice expansion mechanism\n\t\t// So it is necessary to allocate a separate index for each field\n\t\t// See details https://github.com/gogf/gf/issues/3789\n\t\tcachedStructInfo.AddField(structField, append(copyFieldIndexes, i), priorityTagArray)\n\t}\n}\n"
  },
  {
    "path": "util/gconv/internal/structcache/structcache_cached_field_info.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage structcache\n\nimport (\n\t\"reflect\"\n\t\"sync/atomic\"\n)\n\n// CachedFieldInfo holds the cached info for struct field.\ntype CachedFieldInfo struct {\n\t// WARN:\n\t//  The [CachedFieldInfoBase] structure cannot be merged with the following [IsField] field into one structure.\n\t// \tThe [IsField] field should be used separately in the [bindStructWithLoopParamsMap] method\n\t*CachedFieldInfoBase\n\n\t// This field is mainly used in the [bindStructWithLoopParamsMap] method.\n\t// This field is needed when both `fieldName` and `tag` of a field exist in the map.\n\t// For example:\n\t// field string `json:\"name\"`\n\t// map = {\n\t//     \"field\" : \"f1\",\n\t//     \"name\" : \"n1\",\n\t// }\n\t// The `name` should be used here.\n\t// In the bindStructWithLoopParamsMap method, due to the disorder of `map`, `field` may be traversed first.\n\t// This field is more about priority, that is, the priority of `name` is higher than that of `field`,\n\t// even if it has been set before.\n\tIsField bool\n}\n\n// CachedFieldInfoBase holds the cached info for struct field.\ntype CachedFieldInfoBase struct {\n\t// FieldIndexes holds the global index number from struct info.\n\t// The field may belong to an embedded structure, so it is defined here as []int.\n\tFieldIndexes []int\n\n\t// PriorityTagAndFieldName holds the tag value(conv, param, p, c, json) and the field name.\n\t// PriorityTagAndFieldName contains the field name, which is the last item of slice.\n\tPriorityTagAndFieldName []string\n\n\t// IsCommonInterface marks this field implements common interfaces as:\n\t// - iUnmarshalValue\n\t// - iUnmarshalText\n\t// - iUnmarshalJSON\n\t// Purpose: reduce the interface asserting cost in runtime.\n\tIsCommonInterface bool\n\n\t// HasCustomConvert marks there custom converting function for this field type.\n\t// A custom converting function is a function that user defined for converting specified type\n\t// to another type.\n\tHasCustomConvert bool\n\n\t// StructField is the type info of this field.\n\tStructField reflect.StructField\n\n\t// OtherSameNameField stores fields with the same name and type or different types of nested structures.\n\t//\n\t// For example:\n\t// type ID struct{\n\t//     ID1  string\n\t//     ID2 int\n\t// }\n\t// type Card struct{\n\t//     ID\n\t//     ID1  uint64\n\t//     ID2 int64\n\t// }\n\t//\n\t// We will cache each ID1 and ID2 separately,\n\t// even if their types are different and their indexes are different\n\tOtherSameNameField []*CachedFieldInfo\n\n\t// ConvertFunc is the converting function for this field.\n\tConvertFunc AnyConvertFunc\n\n\t// The last fuzzy matching key for this field.\n\t// The fuzzy matching occurs only if there are no direct tag and field name matching in the params map.\n\t// TODO If different paramsMaps contain paramKeys in different formats and all hit the same fieldName,\n\t//      the cached value may be continuously updated.\n\t// LastFuzzyKey string.\n\tLastFuzzyKey atomic.Value\n\n\t// removeSymbolsFieldName is used for quick fuzzy match for parameter key.\n\t// removeSymbolsFieldName = utils.RemoveSymbols(fieldName)\n\tRemoveSymbolsFieldName string\n}\n\n// FieldName returns the field name of current field info.\nfunc (cfi *CachedFieldInfo) FieldName() string {\n\treturn cfi.PriorityTagAndFieldName[len(cfi.PriorityTagAndFieldName)-1]\n}\n\n// GetFieldReflectValueFrom retrieves and returns the `reflect.Value` of given struct field,\n// which is used for directly value assignment.\n//\n// Note that, the input parameter `structValue` might be initialized internally.\nfunc (cfi *CachedFieldInfo) GetFieldReflectValueFrom(structValue reflect.Value) reflect.Value {\n\tif len(cfi.FieldIndexes) == 1 {\n\t\t// no nested struct.\n\t\treturn structValue.Field(cfi.FieldIndexes[0])\n\t}\n\treturn cfi.fieldReflectValue(structValue, cfi.FieldIndexes)\n}\n\n// GetOtherFieldReflectValueFrom retrieves and returns the `reflect.Value` of given struct field with nested index\n// by `fieldLevel`, which is used for directly value assignment.\n//\n// Note that, the input parameter `structValue` might be initialized internally.\nfunc (cfi *CachedFieldInfo) GetOtherFieldReflectValueFrom(structValue reflect.Value, fieldIndex []int) reflect.Value {\n\tif len(fieldIndex) == 1 {\n\t\t// no nested struct.\n\t\treturn structValue.Field(fieldIndex[0])\n\t}\n\treturn cfi.fieldReflectValue(structValue, fieldIndex)\n}\n\nfunc (cfi *CachedFieldInfo) fieldReflectValue(v reflect.Value, fieldIndexes []int) reflect.Value {\n\tfor i, x := range fieldIndexes {\n\t\tif i > 0 {\n\t\t\t// it means nested struct.\n\t\t\tswitch v.Kind() {\n\t\t\tcase reflect.Pointer:\n\t\t\t\tif v.IsNil() {\n\t\t\t\t\t// Initialization.\n\t\t\t\t\tv.Set(reflect.New(v.Type().Elem()))\n\t\t\t\t}\n\t\t\t\tv = v.Elem()\n\n\t\t\tcase reflect.Interface:\n\t\t\t\t// Compatible with previous code\n\t\t\t\t// Interface => struct\n\t\t\t\tv = v.Elem()\n\t\t\t\tif v.Kind() == reflect.Pointer {\n\t\t\t\t\t// maybe *struct or other types\n\t\t\t\t\tv = v.Elem()\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t\tv = v.Field(x)\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "util/gconv/internal/structcache/structcache_cached_struct_info.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage structcache\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// CachedStructInfo holds the cached info for certain struct.\ntype CachedStructInfo struct {\n\t// All sub attributes field info slice.\n\tfieldConvertInfos []*CachedFieldInfo\n\n\tconverter *Converter\n\n\t// This map field is mainly used in the bindStructWithLoopParamsMap method\n\t// key = field's name\n\t// Will save all field names and PriorityTagAndFieldName\n\t// for example：\n\t//\tfield string `json:\"name\"`\n\t//\n\t// It will be stored twice, which keys are `name` and `field`.\n\ttagOrFiledNameToFieldInfoMap map[string]*CachedFieldInfo\n}\n\n// NewCachedStructInfo creates and returns a new CachedStructInfo object.\nfunc NewCachedStructInfo(converter *Converter) *CachedStructInfo {\n\treturn &CachedStructInfo{\n\t\ttagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo),\n\t\tfieldConvertInfos:            make([]*CachedFieldInfo, 0),\n\t\tconverter:                    converter,\n\t}\n}\n\nfunc (csi *CachedStructInfo) GetFieldConvertInfos() []*CachedFieldInfo {\n\treturn csi.fieldConvertInfos\n}\n\nfunc (csi *CachedStructInfo) HasNoFields() bool {\n\treturn len(csi.tagOrFiledNameToFieldInfoMap) == 0\n}\n\nfunc (csi *CachedStructInfo) GetFieldInfo(fieldName string) *CachedFieldInfo {\n\treturn csi.tagOrFiledNameToFieldInfoMap[fieldName]\n}\n\nfunc (csi *CachedStructInfo) AddField(field reflect.StructField, fieldIndexes []int, priorityTags []string) {\n\ttagOrFieldNameArray := csi.genPriorityTagAndFieldName(field, priorityTags)\n\tfor _, tagOrFieldName := range tagOrFieldNameArray {\n\t\tcachedFieldInfo, found := csi.tagOrFiledNameToFieldInfoMap[tagOrFieldName]\n\t\tnewFieldInfo := csi.makeOrCopyCachedInfo(\n\t\t\tfield, fieldIndexes, priorityTags, cachedFieldInfo, tagOrFieldName,\n\t\t)\n\t\tif newFieldInfo.IsField {\n\t\t\tcsi.fieldConvertInfos = append(csi.fieldConvertInfos, newFieldInfo)\n\t\t}\n\t\t// if the field info by `tagOrFieldName` already cached,\n\t\t// it so adds this new field info to other same name field.\n\t\tif found {\n\t\t\tcachedFieldInfo.OtherSameNameField = append(cachedFieldInfo.OtherSameNameField, newFieldInfo)\n\t\t} else {\n\t\t\tcsi.tagOrFiledNameToFieldInfoMap[tagOrFieldName] = newFieldInfo\n\t\t}\n\t}\n}\n\nfunc (csi *CachedStructInfo) makeOrCopyCachedInfo(\n\tfield reflect.StructField, fieldIndexes []int, priorityTags []string,\n\tcachedFieldInfo *CachedFieldInfo,\n\tcurrTagOrFieldName string,\n) (newFieldInfo *CachedFieldInfo) {\n\tif cachedFieldInfo == nil {\n\t\t// If the field is not cached, it creates a new one.\n\t\tnewFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags)\n\t\tnewFieldInfo.IsField = currTagOrFieldName == field.Name\n\t\treturn\n\t}\n\tif cachedFieldInfo.StructField.Type != field.Type {\n\t\t// If the types are different, some information needs to be reset.\n\t\tnewFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags)\n\t} else {\n\t\t// If the field types are the same.\n\t\tnewFieldInfo = csi.copyCachedInfoWithFieldIndexes(cachedFieldInfo, fieldIndexes)\n\t}\n\tnewFieldInfo.IsField = currTagOrFieldName == field.Name\n\treturn\n}\n\n// copyCachedInfoWithFieldIndexes copies and returns a new CachedFieldInfo based on given CachedFieldInfo, but different\n// FieldIndexes. Mainly used for copying fields with the same name and type.\nfunc (csi *CachedStructInfo) copyCachedInfoWithFieldIndexes(\n\tcfi *CachedFieldInfo, fieldIndexes []int,\n) *CachedFieldInfo {\n\tbase := CachedFieldInfoBase{}\n\tbase = *cfi.CachedFieldInfoBase\n\tbase.FieldIndexes = fieldIndexes\n\treturn &CachedFieldInfo{\n\t\tCachedFieldInfoBase: &base,\n\t}\n}\n\nfunc (csi *CachedStructInfo) makeCachedFieldInfo(\n\tfield reflect.StructField, fieldIndexes []int, priorityTags []string,\n) *CachedFieldInfo {\n\tbase := &CachedFieldInfoBase{\n\t\tIsCommonInterface:       checkTypeIsCommonInterface(field),\n\t\tStructField:             field,\n\t\tFieldIndexes:            fieldIndexes,\n\t\tConvertFunc:             csi.genFieldConvertFunc(field.Type),\n\t\tHasCustomConvert:        csi.checkTypeHasCustomConvert(field.Type),\n\t\tPriorityTagAndFieldName: csi.genPriorityTagAndFieldName(field, priorityTags),\n\t\tRemoveSymbolsFieldName:  utils.RemoveSymbols(field.Name),\n\t}\n\tbase.LastFuzzyKey.Store(field.Name)\n\treturn &CachedFieldInfo{\n\t\tCachedFieldInfoBase: base,\n\t}\n}\n\nfunc (csi *CachedStructInfo) genFieldConvertFunc(fieldType reflect.Type) (convertFunc AnyConvertFunc) {\n\tptr := 0\n\tfor fieldType.Kind() == reflect.Pointer {\n\t\tfieldType = fieldType.Elem()\n\t\tptr++\n\t}\n\tconvertFunc = csi.converter.anyToTypeConvertMap[fieldType]\n\tif convertFunc == nil {\n\t\t// If the registered custom implementation cannot be found,\n\t\t// try to check if there is an implementation interface\n\t\tconvertFunc = csi.converter.checkTypeImplInterface(fieldType)\n\t}\n\t// if the registered type is not found and\n\t// the corresponding interface is not implemented, return directly\n\tif convertFunc == nil {\n\t\treturn nil\n\t}\n\tfor i := 0; i < ptr; i++ {\n\t\t// If it is a pointer type, it needs to be packaged\n\t\tconvertFunc = genPtrConvertFunc(convertFunc)\n\t}\n\treturn convertFunc\n}\n\nfunc (csi *CachedStructInfo) genPriorityTagAndFieldName(\n\tfield reflect.StructField, priorityTags []string,\n) (priorityTagAndFieldName []string) {\n\tfor _, tag := range priorityTags {\n\t\tvalue, ok := field.Tag.Lookup(tag)\n\t\tif ok {\n\t\t\t// If there's something else in the tag string,\n\t\t\t// it uses the first part which is split using char ','.\n\t\t\t// Example:\n\t\t\t// orm:\"id, priority\"\n\t\t\t// orm:\"name, with:uid=id\"\n\t\t\ttagValueItems := strings.Split(value, \",\")\n\t\t\t// json:\",omitempty\"\n\t\t\ttrimmedTagName := strings.TrimSpace(tagValueItems[0])\n\t\t\tif trimmedTagName != \"\" {\n\t\t\t\tpriorityTagAndFieldName = append(priorityTagAndFieldName, trimmedTagName)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tpriorityTagAndFieldName = append(priorityTagAndFieldName, field.Name)\n\treturn\n}\n\nfunc genPtrConvertFunc(convertFunc AnyConvertFunc) AnyConvertFunc {\n\treturn func(from any, to reflect.Value) error {\n\t\tif to.IsNil() {\n\t\t\tto.Set(reflect.New(to.Type().Elem()))\n\t\t}\n\t\treturn convertFunc(from, to.Elem())\n\t}\n}\n\nfunc (csi *CachedStructInfo) checkTypeHasCustomConvert(fieldType reflect.Type) bool {\n\tif fieldType.Kind() == reflect.Pointer {\n\t\tfieldType = fieldType.Elem()\n\t}\n\t_, ok := csi.converter.typeConverterFuncMarkMap[fieldType]\n\treturn ok\n}\n"
  },
  {
    "path": "util/gconv/internal/structcache/structcache_pool.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage structcache\n\nimport (\n\t\"sync\"\n)\n\nvar (\n\tpoolUsedParamsKeyOrTagNameMap = &sync.Pool{\n\t\tNew: func() any {\n\t\t\treturn make(map[string]struct{})\n\t\t},\n\t}\n)\n\n// GetUsedParamsKeyOrTagNameMapFromPool retrieves and returns a map for storing params key or tag name.\nfunc GetUsedParamsKeyOrTagNameMapFromPool() map[string]struct{} {\n\treturn poolUsedParamsKeyOrTagNameMap.Get().(map[string]struct{})\n}\n\n// PutUsedParamsKeyOrTagNameMapToPool puts a map for storing params key or tag name into pool for re-usage.\nfunc PutUsedParamsKeyOrTagNameMapToPool(m map[string]struct{}) {\n\t// need to be cleared before putting back into pool.\n\tfor k := range m {\n\t\tdelete(m, k)\n\t}\n\tpoolUsedParamsKeyOrTagNameMap.Put(m)\n}\n"
  },
  {
    "path": "util/gmeta/gmeta.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmeta provides embedded meta data feature for struct.\npackage gmeta\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n)\n\n// Meta is used as an embedded attribute for struct to enabled metadata feature.\ntype Meta struct{}\n\n// metaAttributeName is the attribute name of metadata in struct.\nconst metaAttributeName = \"Meta\"\n\n// metaType holds the reflection. Type of Meta, used for efficient type comparison.\nvar metaType = reflect.TypeOf(Meta{})\n\n// Data retrieves and returns all metadata from `object`.\nfunc Data(object any) map[string]string {\n\treflectType, err := gstructs.StructType(object)\n\tif err != nil {\n\t\treturn nil\n\t}\n\tif field, ok := reflectType.FieldByName(metaAttributeName); ok {\n\t\tif field.Type == metaType {\n\t\t\treturn gstructs.ParseTag(string(field.Tag))\n\t\t}\n\t}\n\treturn map[string]string{}\n}\n\n// Get retrieves and returns specified metadata by `key` from `object`.\nfunc Get(object any, key string) *gvar.Var {\n\tv, ok := Data(object)[key]\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn gvar.New(v)\n}\n"
  },
  {
    "path": "util/gmeta/gmeta_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmeta_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\ntype A struct {\n\tgmeta.Meta `tag:\"123\" orm:\"456\"`\n\tId         int\n\tName       string\n}\n\nvar (\n\ta1 A\n\ta2 *A\n)\n\nfunc Benchmark_Data_Struct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Data(a1)\n\t}\n}\n\nfunc Benchmark_Data_Pointer1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Data(a2)\n\t}\n}\n\nfunc Benchmark_Data_Pointer2(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Data(&a2)\n\t}\n}\n\nfunc Benchmark_Data_Get_Struct(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Get(a1, \"tag\")\n\t}\n}\n\nfunc Benchmark_Data_Get_Pointer1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Get(a2, \"tag\")\n\t}\n}\n\nfunc Benchmark_Data_Get_Pointer2(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgmeta.Get(&a2, \"tag\")\n\t}\n}\n"
  },
  {
    "path": "util/gmeta/gmeta_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gmeta_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n)\n\nfunc TestMeta_Basic(t *testing.T) {\n\ttype A struct {\n\t\tgmeta.Meta `tag:\"123\" orm:\"456\"`\n\t\tId         int\n\t\tName       string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &A{\n\t\t\tId:   100,\n\t\t\tName: \"john\",\n\t\t}\n\t\tt.Assert(len(gmeta.Data(a)), 2)\n\t\tt.AssertEQ(gmeta.Get(a, \"tag\").String(), \"123\")\n\t\tt.AssertEQ(gmeta.Get(a, \"orm\").String(), \"456\")\n\t\tt.AssertEQ(gmeta.Get(a, \"none\"), nil)\n\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(b, `{\"Id\":100,\"Name\":\"john\"}`)\n\t})\n}\n\nfunc TestMeta_Convert_Map(t *testing.T) {\n\ttype A struct {\n\t\tgmeta.Meta `tag:\"123\" orm:\"456\"`\n\t\tId         int\n\t\tName       string\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &A{\n\t\t\tId:   100,\n\t\t\tName: \"john\",\n\t\t}\n\t\tm := gconv.Map(a)\n\t\tt.Assert(len(m), 2)\n\t\tt.Assert(m[`Meta`], nil)\n\t})\n}\n\nfunc TestMeta_Json(t *testing.T) {\n\ttype A struct {\n\t\tgmeta.Meta `tag:\"123\" orm:\"456\"`\n\t\tId         int\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &A{\n\t\t\tId: 100,\n\t\t}\n\t\tb, err := json.Marshal(a)\n\t\tt.AssertNil(err)\n\t\tt.Assert(string(b), `{\"Id\":100}`)\n\t})\n}\n"
  },
  {
    "path": "util/gmode/gmode.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gmode provides release mode management for project.\n//\n// It uses string to mark the mode instead of integer, which is convenient for configuration.\npackage gmode\n\nimport (\n\t\"github.com/gogf/gf/v2/debug/gdebug\"\n\t\"github.com/gogf/gf/v2/internal/command\"\n\t\"github.com/gogf/gf/v2/os/gfile\"\n)\n\nconst (\n\tNOT_SET       = \"not-set\"\n\tDEVELOP       = \"develop\"\n\tTESTING       = \"testing\"\n\tSTAGING       = \"staging\"\n\tPRODUCT       = \"product\"\n\tcommandEnvKey = \"gf.gmode\"\n)\n\nvar (\n\t// Note that `currentMode` is not concurrent safe.\n\tcurrentMode = NOT_SET\n)\n\n// Set sets the mode for current application.\nfunc Set(mode string) {\n\tcurrentMode = mode\n}\n\n// SetDevelop sets current mode DEVELOP for current application.\nfunc SetDevelop() {\n\tSet(DEVELOP)\n}\n\n// SetTesting sets current mode TESTING for current application.\nfunc SetTesting() {\n\tSet(TESTING)\n}\n\n// SetStaging sets current mode STAGING for current application.\nfunc SetStaging() {\n\tSet(STAGING)\n}\n\n// SetProduct sets current mode PRODUCT for current application.\nfunc SetProduct() {\n\tSet(PRODUCT)\n}\n\n// Mode returns current application mode set.\nfunc Mode() string {\n\t// If current mode is not set, do this auto check.\n\tif currentMode == NOT_SET {\n\t\tif v := command.GetOptWithEnv(commandEnvKey); v != \"\" {\n\t\t\t// Mode configured from command argument of environment.\n\t\t\tcurrentMode = v\n\t\t} else {\n\t\t\t// If there are source codes found, it's in develop mode, or else in product mode.\n\t\t\tif gfile.Exists(gdebug.CallerFilePath()) {\n\t\t\t\tcurrentMode = DEVELOP\n\t\t\t} else {\n\t\t\t\tcurrentMode = PRODUCT\n\t\t\t}\n\t\t}\n\t}\n\treturn currentMode\n}\n\n// IsDevelop checks and returns whether current application is running in DEVELOP mode.\nfunc IsDevelop() bool {\n\treturn Mode() == DEVELOP\n}\n\n// IsTesting checks and returns whether current application is running in TESTING mode.\nfunc IsTesting() bool {\n\treturn Mode() == TESTING\n}\n\n// IsStaging checks and returns whether current application is running in STAGING mode.\nfunc IsStaging() bool {\n\treturn Mode() == STAGING\n}\n\n// IsProduct checks and returns whether current application is running in PRODUCT mode.\nfunc IsProduct() bool {\n\treturn Mode() == PRODUCT\n}\n"
  },
  {
    "path": "util/gmode/gmode_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gmode_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gmode\"\n)\n\nfunc Test_AutoCheckSourceCodes(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gmode.IsDevelop(), true)\n\t})\n}\n\nfunc Test_Set(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldMode := gmode.Mode()\n\t\tdefer gmode.Set(oldMode)\n\t\tgmode.SetDevelop()\n\t\tt.Assert(gmode.IsDevelop(), true)\n\t\tt.Assert(gmode.IsTesting(), false)\n\t\tt.Assert(gmode.IsStaging(), false)\n\t\tt.Assert(gmode.IsProduct(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldMode := gmode.Mode()\n\t\tdefer gmode.Set(oldMode)\n\t\tgmode.SetTesting()\n\t\tt.Assert(gmode.IsDevelop(), false)\n\t\tt.Assert(gmode.IsTesting(), true)\n\t\tt.Assert(gmode.IsStaging(), false)\n\t\tt.Assert(gmode.IsProduct(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldMode := gmode.Mode()\n\t\tdefer gmode.Set(oldMode)\n\t\tgmode.SetStaging()\n\t\tt.Assert(gmode.IsDevelop(), false)\n\t\tt.Assert(gmode.IsTesting(), false)\n\t\tt.Assert(gmode.IsStaging(), true)\n\t\tt.Assert(gmode.IsProduct(), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldMode := gmode.Mode()\n\t\tdefer gmode.Set(oldMode)\n\t\tgmode.SetProduct()\n\t\tt.Assert(gmode.IsDevelop(), false)\n\t\tt.Assert(gmode.IsTesting(), false)\n\t\tt.Assert(gmode.IsStaging(), false)\n\t\tt.Assert(gmode.IsProduct(), true)\n\t})\n}\n"
  },
  {
    "path": "util/gpage/gpage.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gpage provides useful paging functionality for web pages.\n//\n// Deprecated: wrap this pagination html content in business layer.\n// Will be removed in version 3.0.\npackage gpage\n\nimport (\n\t\"fmt\"\n\t\"html\"\n\t\"math\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Page is the pagination implementer.\n// All the attributes are public, you can change them when necessary.\n//\n// Deprecated: wrap this pagination html content in business layer.\ntype Page struct {\n\tTotalSize      int    // Total size.\n\tTotalPage      int    // Total page, which is automatically calculated.\n\tCurrentPage    int    // Current page number >= 1.\n\tUrlTemplate    string // Custom url template for page url producing.\n\tLinkStyle      string // CSS style name for HTML link tag `a`.\n\tSpanStyle      string // CSS style name for HTML span tag `span`, which is used for first, current and last page tag.\n\tSelectStyle    string // CSS style name for HTML select tag `select`.\n\tNextPageTag    string // Tag name for next p.\n\tPrevPageTag    string // Tag name for prev p.\n\tFirstPageTag   string // Tag name for first p.\n\tLastPageTag    string // Tag name for last p.\n\tPrevBarTag     string // Tag string for prev bar.\n\tNextBarTag     string // Tag string for next bar.\n\tPageBarNum     int    // Page bar number for displaying.\n\tAjaxActionName string // Ajax function name. Ajax is enabled if this attribute is not empty.\n}\n\nconst (\n\t// DefaultPageName defines the default page name.\n\tDefaultPageName = \"page\"\n\t// DefaultPagePlaceHolder defines the placeholder for the URL template.\n\tDefaultPagePlaceHolder = \"{.page}\"\n)\n\n// New creates and returns a pagination manager.\n// Note that the parameter `urlTemplate` specifies the URL producing template, like:\n// /user/list/{.page}, /user/list/{.page}.html, /user/list?page={.page}&type=1, etc.\n// The build-in variable in `urlTemplate` \"{.page}\" specifies the page number, which will be replaced by certain\n// page number when producing.\n//\n// Deprecated: wrap this pagination html content in business layer.\nfunc New(totalSize, pageSize, currentPage int, urlTemplate string) *Page {\n\tp := &Page{\n\t\tLinkStyle:    \"GPageLink\",\n\t\tSpanStyle:    \"GPageSpan\",\n\t\tSelectStyle:  \"GPageSelect\",\n\t\tPrevPageTag:  \"<\",\n\t\tNextPageTag:  \">\",\n\t\tFirstPageTag: \"|<\",\n\t\tLastPageTag:  \">|\",\n\t\tPrevBarTag:   \"<<\",\n\t\tNextBarTag:   \">>\",\n\t\tTotalSize:    totalSize,\n\t\tTotalPage:    int(math.Ceil(float64(totalSize) / float64(pageSize))),\n\t\tCurrentPage:  currentPage,\n\t\tPageBarNum:   10,\n\t\tUrlTemplate:  urlTemplate,\n\t}\n\tif currentPage == 0 {\n\t\tp.CurrentPage = 1\n\t}\n\treturn p\n}\n\n// NextPage returns the HTML content for the next page.\nfunc (p *Page) NextPage() string {\n\tif p.CurrentPage < p.TotalPage {\n\t\treturn p.GetLink(p.CurrentPage+1, p.NextPageTag, \"\")\n\t}\n\treturn fmt.Sprintf(`<span class=\"%s\">%s</span>`, p.SpanStyle, p.NextPageTag)\n}\n\n// PrevPage returns the HTML content for the previous page.\nfunc (p *Page) PrevPage() string {\n\tif p.CurrentPage > 1 {\n\t\treturn p.GetLink(p.CurrentPage-1, p.PrevPageTag, \"\")\n\t}\n\treturn fmt.Sprintf(`<span class=\"%s\">%s</span>`, p.SpanStyle, p.PrevPageTag)\n}\n\n// FirstPage returns the HTML content for the first page.\nfunc (p *Page) FirstPage() string {\n\tif p.CurrentPage == 1 {\n\t\treturn fmt.Sprintf(`<span class=\"%s\">%s</span>`, p.SpanStyle, p.FirstPageTag)\n\t}\n\treturn p.GetLink(1, p.FirstPageTag, \"\")\n}\n\n// LastPage returns the HTML content for the last page.\nfunc (p *Page) LastPage() string {\n\tif p.CurrentPage == p.TotalPage {\n\t\treturn fmt.Sprintf(`<span class=\"%s\">%s</span>`, p.SpanStyle, p.LastPageTag)\n\t}\n\treturn p.GetLink(p.TotalPage, p.LastPageTag, \"\")\n}\n\n// PageBar returns the HTML page bar content with link and span tags.\nfunc (p *Page) PageBar() string {\n\tplus := p.PageBarNum / 2\n\tif p.PageBarNum-plus+p.CurrentPage > p.TotalPage {\n\t\tplus = p.PageBarNum - p.TotalPage + p.CurrentPage\n\t}\n\tbegin := p.CurrentPage - plus + 1\n\tif begin < 1 {\n\t\tbegin = 1\n\t}\n\tbarContent := \"\"\n\tfor i := begin; i < begin+p.PageBarNum; i++ {\n\t\tif i <= p.TotalPage {\n\t\t\tif i != p.CurrentPage {\n\t\t\t\tbarText := gconv.String(i)\n\t\t\t\tbarContent += p.GetLink(i, barText, barText)\n\t\t\t} else {\n\t\t\t\tbarContent += fmt.Sprintf(`<span class=\"%s\">%d</span>`, p.SpanStyle, i)\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn barContent\n}\n\n// SelectBar returns the select HTML content for pagination.\nfunc (p *Page) SelectBar() string {\n\tbarContent := fmt.Sprintf(`<select name=\"%s\" onchange=\"window.location.href=this.value\">`, p.SelectStyle)\n\tfor i := 1; i <= p.TotalPage; i++ {\n\t\tif i == p.CurrentPage {\n\t\t\tbarContent += fmt.Sprintf(`<option value=\"%s\" selected>%d</option>`, p.GetUrl(i), i)\n\t\t} else {\n\t\t\tbarContent += fmt.Sprintf(`<option value=\"%s\">%d</option>`, p.GetUrl(i), i)\n\t\t}\n\t}\n\tbarContent += \"</select>\"\n\treturn barContent\n}\n\n// GetContent returns the page content for predefined mode.\n// These predefined contents are mainly for Chinese localization purposes.You can define your own\n// page function to retrieve the page content according to the implementation of this function.\nfunc (p *Page) GetContent(mode int) string {\n\tswitch mode {\n\tcase 1:\n\t\tp.NextPageTag = \"下一页\"\n\t\tp.PrevPageTag = \"上一页\"\n\t\treturn fmt.Sprintf(\n\t\t\t`%s <span class=\"current\">%d</span> %s`,\n\t\t\tp.PrevPage(),\n\t\t\tp.CurrentPage,\n\t\t\tp.NextPage(),\n\t\t)\n\n\tcase 2:\n\t\tp.NextPageTag = \"下一页>>\"\n\t\tp.PrevPageTag = \"<<上一页\"\n\t\tp.FirstPageTag = \"首页\"\n\t\tp.LastPageTag = \"尾页\"\n\t\treturn fmt.Sprintf(\n\t\t\t`%s%s<span class=\"current\">[第 %d 页]</span>%s%s第%s页`,\n\t\t\tp.FirstPage(),\n\t\t\tp.PrevPage(),\n\t\t\tp.CurrentPage,\n\t\t\tp.NextPage(),\n\t\t\tp.LastPage(),\n\t\t\tp.SelectBar(),\n\t\t)\n\n\tcase 3:\n\t\tp.NextPageTag = \"下一页\"\n\t\tp.PrevPageTag = \"上一页\"\n\t\tp.FirstPageTag = \"首页\"\n\t\tp.LastPageTag = \"尾页\"\n\t\tpageStr := p.FirstPage()\n\t\tpageStr += p.PrevPage()\n\t\tpageStr += p.PageBar()\n\t\tpageStr += p.NextPage()\n\t\tpageStr += p.LastPage()\n\t\tpageStr += fmt.Sprintf(\n\t\t\t`<span>当前页 %d/%d</span> <span>共 %d 条</span>`,\n\t\t\tp.CurrentPage,\n\t\t\tp.TotalPage,\n\t\t\tp.TotalSize,\n\t\t)\n\t\treturn pageStr\n\n\tcase 4:\n\t\tp.NextPageTag = \"下一页\"\n\t\tp.PrevPageTag = \"上一页\"\n\t\tp.FirstPageTag = \"首页\"\n\t\tp.LastPageTag = \"尾页\"\n\t\tpageStr := p.FirstPage()\n\t\tpageStr += p.PrevPage()\n\t\tpageStr += p.PageBar()\n\t\tpageStr += p.NextPage()\n\t\tpageStr += p.LastPage()\n\t\treturn pageStr\n\t}\n\treturn \"\"\n}\n\n// GetUrl parses the UrlTemplate with given page number and returns the URL string.\n// The UrlTemplate attribute can be a URL or URI string containing the \"{.page}\" placeholder,\n// which will be replaced by the actual page number.\nfunc (p *Page) GetUrl(page int) string {\n\treturn html.EscapeString(gstr.Replace(p.UrlTemplate, DefaultPagePlaceHolder, gconv.String(page)))\n}\n\n// GetLink returns the HTML link tag `a` content for given page number.\nfunc (p *Page) GetLink(page int, text, title string) string {\n\tvar (\n\t\tescapedTitle = html.EscapeString(title)\n\t\tescapedText  = html.EscapeString(text)\n\t)\n\tif len(p.AjaxActionName) > 0 {\n\t\treturn fmt.Sprintf(\n\t\t\t`<a class=\"%s\" href=\"javascript:%s('%s')\" title=\"%s\">%s</a>`,\n\t\t\tp.LinkStyle, p.AjaxActionName, p.GetUrl(page), escapedTitle, escapedText,\n\t\t)\n\t} else {\n\t\treturn fmt.Sprintf(\n\t\t\t`<a class=\"%s\" href=\"%s\" title=\"%s\">%s</a>`,\n\t\t\tp.LinkStyle, p.GetUrl(page), escapedTitle, escapedText,\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "util/gpage/gpage_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage gpage_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gpage\"\n)\n\nfunc Test_New(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(9, 2, 1, `/user/list?page={.page}`)\n\t\tt.Assert(page.TotalSize, 9)\n\t\tt.Assert(page.TotalPage, 5)\n\t\tt.Assert(page.CurrentPage, 1)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(9, 2, 0, `/user/list?page={.page}`)\n\t\tt.Assert(page.TotalSize, 9)\n\t\tt.Assert(page.TotalPage, 5)\n\t\tt.Assert(page.CurrentPage, 1)\n\t})\n}\n\nfunc Test_Basic(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(9, 2, 1, `/user/list?page={.page}`)\n\t\tt.Assert(page.NextPage(), `<a class=\"GPageLink\" href=\"/user/list?page=2\" title=\"\">&gt;</a>`)\n\t\tt.Assert(page.PrevPage(), `<span class=\"GPageSpan\"><</span>`)\n\t\tt.Assert(page.FirstPage(), `<span class=\"GPageSpan\">|<</span>`)\n\t\tt.Assert(page.LastPage(), `<a class=\"GPageLink\" href=\"/user/list?page=5\" title=\"\">&gt;|</a>`)\n\t\tt.Assert(page.PageBar(), `<span class=\"GPageSpan\">1</span><a class=\"GPageLink\" href=\"/user/list?page=2\" title=\"2\">2</a><a class=\"GPageLink\" href=\"/user/list?page=3\" title=\"3\">3</a><a class=\"GPageLink\" href=\"/user/list?page=4\" title=\"4\">4</a><a class=\"GPageLink\" href=\"/user/list?page=5\" title=\"5\">5</a>`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(9, 2, 3, `/user/list?page={.page}`)\n\t\tt.Assert(page.NextPage(), `<a class=\"GPageLink\" href=\"/user/list?page=4\" title=\"\">&gt;</a>`)\n\t\tt.Assert(page.PrevPage(), `<a class=\"GPageLink\" href=\"/user/list?page=2\" title=\"\">&lt;</a>`)\n\t\tt.Assert(page.FirstPage(), `<a class=\"GPageLink\" href=\"/user/list?page=1\" title=\"\">|&lt;</a>`)\n\t\tt.Assert(page.LastPage(), `<a class=\"GPageLink\" href=\"/user/list?page=5\" title=\"\">&gt;|</a>`)\n\t\tt.Assert(page.PageBar(), `<a class=\"GPageLink\" href=\"/user/list?page=1\" title=\"1\">1</a><a class=\"GPageLink\" href=\"/user/list?page=2\" title=\"2\">2</a><span class=\"GPageSpan\">3</span><a class=\"GPageLink\" href=\"/user/list?page=4\" title=\"4\">4</a><a class=\"GPageLink\" href=\"/user/list?page=5\" title=\"5\">5</a>`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(9, 2, 5, `/user/list?page={.page}`)\n\t\tt.Assert(page.NextPage(), `<span class=\"GPageSpan\">></span>`)\n\t\tt.Assert(page.PrevPage(), `<a class=\"GPageLink\" href=\"/user/list?page=4\" title=\"\">&lt;</a>`)\n\t\tt.Assert(page.FirstPage(), `<a class=\"GPageLink\" href=\"/user/list?page=1\" title=\"\">|&lt;</a>`)\n\t\tt.Assert(page.LastPage(), `<span class=\"GPageSpan\">>|</span>`)\n\t\tt.Assert(page.PageBar(), `<a class=\"GPageLink\" href=\"/user/list?page=1\" title=\"1\">1</a><a class=\"GPageLink\" href=\"/user/list?page=2\" title=\"2\">2</a><a class=\"GPageLink\" href=\"/user/list?page=3\" title=\"3\">3</a><a class=\"GPageLink\" href=\"/user/list?page=4\" title=\"4\">4</a><span class=\"GPageSpan\">5</span>`)\n\t})\n}\n\nfunc Test_CustomTag(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(5, 1, 2, `/user/list/{.page}`)\n\t\tpage.PrevPageTag = \"《\"\n\t\tpage.NextPageTag = \"》\"\n\t\tpage.FirstPageTag = \"|《\"\n\t\tpage.LastPageTag = \"》|\"\n\t\tpage.PrevBarTag = \"《《\"\n\t\tpage.NextBarTag = \"》》\"\n\t\tt.Assert(page.NextPage(), `<a class=\"GPageLink\" href=\"/user/list/3\" title=\"\">》</a>`)\n\t\tt.Assert(page.PrevPage(), `<a class=\"GPageLink\" href=\"/user/list/1\" title=\"\">《</a>`)\n\t\tt.Assert(page.FirstPage(), `<a class=\"GPageLink\" href=\"/user/list/1\" title=\"\">|《</a>`)\n\t\tt.Assert(page.LastPage(), `<a class=\"GPageLink\" href=\"/user/list/5\" title=\"\">》|</a>`)\n\t\tt.Assert(page.PageBar(), `<a class=\"GPageLink\" href=\"/user/list/1\" title=\"1\">1</a><span class=\"GPageSpan\">2</span><a class=\"GPageLink\" href=\"/user/list/3\" title=\"3\">3</a><a class=\"GPageLink\" href=\"/user/list/4\" title=\"4\">4</a><a class=\"GPageLink\" href=\"/user/list/5\" title=\"5\">5</a>`)\n\t})\n}\n\nfunc Test_CustomStyle(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(5, 1, 2, `/user/list/{.page}`)\n\t\tpage.LinkStyle = \"MyPageLink\"\n\t\tpage.SpanStyle = \"MyPageSpan\"\n\t\tpage.SelectStyle = \"MyPageSelect\"\n\t\tt.Assert(page.NextPage(), `<a class=\"MyPageLink\" href=\"/user/list/3\" title=\"\">&gt;</a>`)\n\t\tt.Assert(page.PrevPage(), `<a class=\"MyPageLink\" href=\"/user/list/1\" title=\"\">&lt;</a>`)\n\t\tt.Assert(page.FirstPage(), `<a class=\"MyPageLink\" href=\"/user/list/1\" title=\"\">|&lt;</a>`)\n\t\tt.Assert(page.LastPage(), `<a class=\"MyPageLink\" href=\"/user/list/5\" title=\"\">&gt;|</a>`)\n\t\tt.Assert(page.PageBar(), `<a class=\"MyPageLink\" href=\"/user/list/1\" title=\"1\">1</a><span class=\"MyPageSpan\">2</span><a class=\"MyPageLink\" href=\"/user/list/3\" title=\"3\">3</a><a class=\"MyPageLink\" href=\"/user/list/4\" title=\"4\">4</a><a class=\"MyPageLink\" href=\"/user/list/5\" title=\"5\">5</a>`)\n\t\tt.Assert(page.SelectBar(), `<select name=\"MyPageSelect\" onchange=\"window.location.href=this.value\"><option value=\"/user/list/1\">1</option><option value=\"/user/list/2\" selected>2</option><option value=\"/user/list/3\">3</option><option value=\"/user/list/4\">4</option><option value=\"/user/list/5\">5</option></select>`)\n\t})\n}\n\nfunc Test_Ajax(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(5, 1, 2, `/user/list/{.page}`)\n\t\tpage.AjaxActionName = \"LoadPage\"\n\t\tt.Assert(page.NextPage(), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"\">&gt;</a>`)\n\t\tt.Assert(page.PrevPage(), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">&lt;</a>`)\n\t\tt.Assert(page.FirstPage(), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">|&lt;</a>`)\n\t\tt.Assert(page.LastPage(), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"\">&gt;|</a>`)\n\t\tt.Assert(page.PageBar(), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"1\">1</a><span class=\"GPageSpan\">2</span><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"3\">3</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/4')\" title=\"4\">4</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"5\">5</a>`)\n\t})\n}\n\nfunc Test_PredefinedContent(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tpage := gpage.New(5, 1, 2, `/user/list/{.page}`)\n\t\tpage.AjaxActionName = \"LoadPage\"\n\t\tt.Assert(page.GetContent(1), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">上一页</a> <span class=\"current\">2</span> <a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"\">下一页</a>`)\n\t\tt.Assert(page.GetContent(2), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">首页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">&lt;&lt;上一页</a><span class=\"current\">[第 2 页]</span><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"\">下一页&gt;&gt;</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"\">尾页</a>第<select name=\"GPageSelect\" onchange=\"window.location.href=this.value\"><option value=\"/user/list/1\">1</option><option value=\"/user/list/2\" selected>2</option><option value=\"/user/list/3\">3</option><option value=\"/user/list/4\">4</option><option value=\"/user/list/5\">5</option></select>页`)\n\t\tt.Assert(page.GetContent(3), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">首页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">上一页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"1\">1</a><span class=\"GPageSpan\">2</span><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"3\">3</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/4')\" title=\"4\">4</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"5\">5</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"\">下一页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"\">尾页</a><span>当前页 2/5</span> <span>共 5 条</span>`)\n\t\tt.Assert(page.GetContent(4), `<a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">首页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"\">上一页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/1')\" title=\"1\">1</a><span class=\"GPageSpan\">2</span><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"3\">3</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/4')\" title=\"4\">4</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"5\">5</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/3')\" title=\"\">下一页</a><a class=\"GPageLink\" href=\"javascript:LoadPage('/user/list/5')\" title=\"\">尾页</a>`)\n\t\tt.Assert(page.GetContent(5), ``)\n\t})\n}\n"
  },
  {
    "path": "util/grand/grand.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package grand provides high performance random bytes/number/string generation functionality.\npackage grand\n\nimport (\n\t\"encoding/binary\"\n\t\"time\"\n)\n\nvar (\n\tletters    = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" // 52\n\tsymbols    = \"!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\"                   // 32\n\tdigits     = \"0123456789\"                                           // 10\n\tcharacters = letters + digits + symbols                             // 94\n)\n\n// Intn returns an int number which is between 0 and max: [0, max).\n//\n// Note that:\n// 1. The `max` can only be greater than 0, or else it returns `max` directly;\n// 2. The result is greater than or equal to 0, but less than `max`;\n// 3. The result number is 32bit and less than math.MaxUint32.\nfunc Intn(max int) int {\n\tif max <= 0 {\n\t\treturn max\n\t}\n\tn := int(binary.LittleEndian.Uint32(<-bufferChan)) % max\n\tif n < 0 {\n\t\treturn -n\n\t}\n\treturn n\n}\n\n// B retrieves and returns random bytes of given length `n`.\nfunc B(n int) []byte {\n\tif n <= 0 {\n\t\treturn nil\n\t}\n\ti := 0\n\tb := make([]byte, n)\n\tfor {\n\t\tcopy(b[i:], <-bufferChan)\n\t\ti += 4\n\t\tif i >= n {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn b\n}\n\n// N returns a random int between min and max: [min, max].\n// The `min` and `max` also support negative numbers.\nfunc N(min, max int) int {\n\tif min >= max {\n\t\treturn min\n\t}\n\tif min >= 0 {\n\t\treturn Intn(max-min+1) + min\n\t}\n\t// As `Intn` dose not support negative number,\n\t// so we should first shift the value to right,\n\t// then call `Intn` to produce the random number,\n\t// and finally shift the result back to left.\n\treturn Intn(max+(0-min)+1) - (0 - min)\n}\n\n// S returns a random string which contains digits and letters, and its length is `n`.\n// The optional parameter `symbols` specifies whether the result could contain symbols,\n// which is false in default.\nfunc S(n int, symbols ...bool) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tb           = make([]byte, n)\n\t\tnumberBytes = B(n)\n\t)\n\tfor i := range b {\n\t\tif len(symbols) > 0 && symbols[0] {\n\t\t\tb[i] = characters[numberBytes[i]%94]\n\t\t} else {\n\t\t\tb[i] = characters[numberBytes[i]%62]\n\t\t}\n\t}\n\treturn string(b)\n}\n\n// D returns a random time.Duration between min and max: [min, max].\nfunc D(min, max time.Duration) time.Duration {\n\tmultiple := int64(1)\n\tif min != 0 {\n\t\tfor min%10 == 0 {\n\t\t\tmultiple *= 10\n\t\t\tmin /= 10\n\t\t\tmax /= 10\n\t\t}\n\t}\n\tn := int64(N(int(min), int(max)))\n\treturn time.Duration(n * multiple)\n}\n\n// Str randomly picks and returns `n` count of chars from given string `s`.\n// It also supports unicode string like Chinese/Russian/Japanese, etc.\nfunc Str(s string, n int) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tb     = make([]rune, n)\n\t\trunes = []rune(s)\n\t)\n\tif len(runes) <= 255 {\n\t\tnumberBytes := B(n)\n\t\tfor i := range b {\n\t\t\tb[i] = runes[int(numberBytes[i])%len(runes)]\n\t\t}\n\t} else {\n\t\tfor i := range b {\n\t\t\tb[i] = runes[Intn(len(runes))]\n\t\t}\n\t}\n\treturn string(b)\n}\n\n// Digits returns a random string which contains only digits, and its length is `n`.\nfunc Digits(n int) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tb           = make([]byte, n)\n\t\tnumberBytes = B(n)\n\t)\n\tfor i := range b {\n\t\tb[i] = digits[numberBytes[i]%10]\n\t}\n\treturn string(b)\n}\n\n// Letters returns a random string which contains only letters, and its length is `n`.\nfunc Letters(n int) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tb           = make([]byte, n)\n\t\tnumberBytes = B(n)\n\t)\n\tfor i := range b {\n\t\tb[i] = letters[numberBytes[i]%52]\n\t}\n\treturn string(b)\n}\n\n// Symbols returns a random string which contains only symbols, and its length is `n`.\nfunc Symbols(n int) string {\n\tif n <= 0 {\n\t\treturn \"\"\n\t}\n\tvar (\n\t\tb           = make([]byte, n)\n\t\tnumberBytes = B(n)\n\t)\n\tfor i := range b {\n\t\tb[i] = symbols[numberBytes[i]%32]\n\t}\n\treturn string(b)\n}\n\n// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).\n// TODO performance improving for large slice producing.\nfunc Perm(n int) []int {\n\tm := make([]int, n)\n\tfor i := 0; i < n; i++ {\n\t\tj := Intn(i + 1)\n\t\tm[i] = m[j]\n\t\tm[j] = i\n\t}\n\treturn m\n}\n\n// Meet randomly calculate whether the given probability `num`/`total` is met.\nfunc Meet(num, total int) bool {\n\treturn Intn(total) < num\n}\n\n// MeetProb randomly calculate whether the given probability is met.\nfunc MeetProb(prob float32) bool {\n\treturn Intn(1e7) < int(prob*1e7)\n}\n"
  },
  {
    "path": "util/grand/grand_buffer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage grand\n\nimport (\n\t\"crypto/rand\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nconst (\n\t// Buffer size for uint32 random number.\n\tbufferChanSize = 10000\n)\n\n// bufferChan is the buffer for random bytes,\n// every item storing 4 bytes.\nvar bufferChan = make(chan []byte, bufferChanSize)\n\nfunc init() {\n\tgo asyncProducingRandomBufferBytesLoop()\n}\n\n// asyncProducingRandomBufferBytesLoop is a named goroutine, which uses an asynchronous goroutine\n// to produce the random bytes, and a buffer chan to store the random bytes.\n// So it has high performance to generate random numbers.\nfunc asyncProducingRandomBufferBytesLoop() {\n\tvar step int\n\tfor {\n\t\tbuffer := make([]byte, 1024)\n\t\tif n, err := rand.Read(buffer); err != nil {\n\t\t\tpanic(gerror.WrapCode(gcode.CodeInternalError, err, `error reading random buffer from system`))\n\t\t} else {\n\t\t\t// The random buffer from system is very expensive,\n\t\t\t// so fully reuse the random buffer by changing\n\t\t\t// the step with a different number can\n\t\t\t// improve the performance a lot.\n\t\t\t// for _, step = range []int{4, 5, 6, 7} {\n\t\t\tfor _, step = range []int{4} {\n\t\t\t\tfor i := 0; i <= n-4; i += step {\n\t\t\t\t\tbufferChan <- buffer[i : i+4]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/grand/grand_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage grand_test\n\nimport (\n\tcryptoRand \"crypto/rand\"\n\t\"encoding/binary\"\n\tmathRand \"math/rand\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nvar (\n\tbuffer         = make([]byte, 8)\n\trandBuffer4    = make([]byte, 4)\n\trandBuffer1024 = make([]byte, 1024)\n\tstrForStr      = \"我爱GoFrame\"\n)\n\nfunc Benchmark_Math_Rand_Int(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tmathRand.Int()\n\t}\n}\n\nfunc Benchmark_CryptoRand_Buffer4(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tcryptoRand.Read(randBuffer4)\n\t}\n}\n\nfunc Benchmark_CryptoRand_Buffer1024(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tcryptoRand.Read(randBuffer1024)\n\t}\n}\n\nfunc Benchmark_GRand_Intn(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.N(0, 99)\n\t}\n}\n\nfunc Benchmark_Perm10(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.Perm(10)\n\t}\n}\n\nfunc Benchmark_Perm100(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.Perm(100)\n\t}\n}\n\nfunc Benchmark_Rand_N1(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.N(0, 99)\n\t}\n}\n\nfunc Benchmark_Rand_N2(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.N(0, 999999999)\n\t}\n}\n\nfunc Benchmark_B(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.B(16)\n\t}\n}\n\nfunc Benchmark_S(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.S(16)\n\t}\n}\n\nfunc Benchmark_S_Symbols(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.S(16, true)\n\t}\n}\n\nfunc Benchmark_Str(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.Str(strForStr, 16)\n\t}\n}\n\nfunc Benchmark_Symbols(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tgrand.Symbols(16)\n\t}\n}\n\nfunc Benchmark_Uint32Converting(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tbinary.LittleEndian.Uint32([]byte{1, 1, 1, 1})\n\t}\n}\n\nfunc Benchmark_CryptoRand_Buffer(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tif _, err := cryptoRand.Read(buffer); err == nil {\n\t\t\tbinary.LittleEndian.Uint64(buffer)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/grand/grand_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage grand_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nfunc Test_Intn(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 1000000; i++ {\n\t\t\tn := grand.Intn(100)\n\t\t\tt.AssertLT(n, 100)\n\t\t\tt.AssertGE(n, 0)\n\t\t}\n\t\tfor i := 0; i < 1000000; i++ {\n\t\t\tn := grand.Intn(-100)\n\t\t\tt.AssertLE(n, 0)\n\t\t\tt.Assert(n, -100)\n\t\t}\n\t})\n}\n\nfunc Test_Meet(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.Meet(100, 100), true)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.Meet(0, 100), false)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.Meet(50, 100), []bool{true, false})\n\t\t}\n\t})\n}\n\nfunc Test_MeetProb(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.MeetProb(1), true)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.MeetProb(0), false)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.MeetProb(0.5), []bool{true, false})\n\t\t}\n\t})\n}\n\nfunc Test_N(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.N(1, 1), 1)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.N(0, 0), 0)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.N(1, 2), []int{1, 2})\n\t\t}\n\t})\n}\n\nfunc Test_D(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.D(time.Second, time.Second), time.Second)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.D(0, 0), time.Duration(0))\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(\n\t\t\t\tgrand.D(1*time.Second, 3*time.Second),\n\t\t\t\t[]time.Duration{1 * time.Second, 2 * time.Second, 3 * time.Second},\n\t\t\t)\n\t\t}\n\t})\n}\n\nfunc Test_Rand(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.N(1, 1), 1)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(grand.N(0, 0), 0)\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.N(1, 2), []int{1, 2})\n\t\t}\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.N(-1, 2), []int{-1, 0, 1, 2})\n\t\t}\n\t})\n}\n\nfunc Test_S(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.S(5)), 5)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.S(5, true)), 5)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(grand.S(0)), 0)\n\t})\n}\n\nfunc Test_B(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tb := grand.B(5)\n\t\t\tt.Assert(len(b), 5)\n\t\t\tt.AssertNE(b, make([]byte, 5))\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tb := grand.B(0)\n\t\tt.AssertNil(b)\n\t})\n}\n\nfunc Test_Str(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.S(5)), 5)\n\t\t}\n\t})\n}\n\nfunc Test_RandStr(t *testing.T) {\n\tstr := \"我爱GoFrame\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 10; i++ {\n\t\t\ts := grand.Str(str, 100000)\n\t\t\tt.Assert(gstr.Contains(s, \"我\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"爱\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"G\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"o\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"F\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"r\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"a\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"m\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"e\"), true)\n\t\t\tt.Assert(gstr.Contains(s, \"w\"), false)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(grand.Str(str, 0), \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlist := []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\"}\n\t\tstr := \"\"\n\t\tfor _, s := range list {\n\t\t\ttmp := \"\"\n\t\t\tfor i := 0; i < 15; i++ {\n\t\t\t\ttmp += tmp + s\n\t\t\t}\n\t\t\tstr += tmp\n\t\t}\n\t\tt.Assert(len(grand.Str(str, 300)), 300)\n\t})\n}\n\nfunc Test_Digits(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.Digits(5)), 5)\n\t\t}\n\t})\n}\n\nfunc Test_RandDigits(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.Digits(5)), 5)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(grand.Digits(0)), 0)\n\t})\n}\n\nfunc Test_Letters(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.Letters(5)), 5)\n\t\t}\n\t})\n}\n\nfunc Test_RandLetters(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.Assert(len(grand.Letters(5)), 5)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(grand.Letters(0)), 0)\n\t})\n}\n\nfunc Test_Perm(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tt.AssertIN(grand.Perm(5), []int{0, 1, 2, 3, 4})\n\t\t}\n\t})\n}\n\nfunc Test_Symbols(t *testing.T) {\n\tsymbols := \"!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~\"\n\tgtest.C(t, func(t *gtest.T) {\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tsyms := []byte(grand.Symbols(5))\n\t\t\tfor _, sym := range syms {\n\t\t\t\tt.AssertNE(strings.Index(symbols, string(sym)), -1)\n\t\t\t}\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(grand.Symbols(0), \"\")\n\t})\n}\n"
  },
  {
    "path": "util/gtag/gtag.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gtag providing tag content storing for struct.\n//\n// Note that calling functions of this package is not concurrently safe,\n// which means you cannot call them in runtime but in boot procedure.\npackage gtag\n\nconst (\n\tDefault              = \"default\"         // Default value tag of struct field for receiving parameters from HTTP request.\n\tDefaultShort         = \"d\"               // Short name of Default.\n\tParam                = \"param\"           // Parameter name for converting certain parameter to specified struct field.\n\tParamShort           = \"p\"               // Short name of Param.\n\tValid                = \"valid\"           // Validation rule tag for struct of field.\n\tValidShort           = \"v\"               // Short name of Valid.\n\tNoValidation         = \"nv\"              // No validation for specified struct/field.\n\tORM                  = \"orm\"             // ORM tag for ORM feature, which performs different features according scenarios.\n\tArg                  = \"arg\"             // Arg tag for struct, usually for command argument option.\n\tBrief                = \"brief\"           // Brief tag for struct, usually be considered as summary.\n\tRoot                 = \"root\"            // Root tag for struct, usually for nested commands management.\n\tAdditional           = \"additional\"      // Additional tag for struct, usually for additional description of command.\n\tAdditionalShort      = \"ad\"              // Short name of Additional.\n\tPath                 = `path`            // Route path for HTTP request.\n\tMethod               = `method`          // Route method for HTTP request.\n\tDomain               = `domain`          // Route domain for HTTP request.\n\tMime                 = `mime`            // MIME type for HTTP request/response.\n\tConsumes             = `consumes`        // MIME type for HTTP request.\n\tSummary              = `summary`         // Summary for struct, usually for OpenAPI in request struct.\n\tSummaryShort         = `sm`              // Short name of Summary.\n\tSummaryShort2        = `sum`             // Short name of Summary.\n\tDescription          = `description`     // Description for struct, usually for OpenAPI in request struct.\n\tDescriptionShort     = `dc`              // Short name of Description.\n\tDescriptionShort2    = `des`             // Short name of Description.\n\tExample              = `example`         // Example for struct, usually for OpenAPI in request struct.\n\tExampleShort         = `eg`              // Short name of Example.\n\tExamples             = `examples`        // Examples for struct, usually for OpenAPI in request struct.\n\tExamplesShort        = `egs`             // Short name of Examples.\n\tExternalDocs         = `externalDocs`    // External docs for struct, always for OpenAPI in request struct.\n\tExternalDocsShort    = `ed`              // Short name of ExternalDocs.\n\tGConv                = \"gconv\"           // GConv defines the converting target name for specified struct field.\n\tGConvShort           = \"c\"               // GConv defines the converting target name for specified struct field.\n\tJson                 = \"json\"            // Json tag is supported by stdlib.\n\tSecurity             = \"security\"        // Security defines scheme for authentication. Detail to see https://swagger.io/docs/specification/authentication/\n\tIn                   = \"in\"              // Swagger distinguishes between the following parameter types based on the parameter location. Detail to see https://swagger.io/docs/specification/describing-parameters/\n\tRequired             = \"required\"        // OpenAPIv3 required attribute name for request body.\n\tStatus               = \"status\"          // Response status code, usually for OpenAPI in response struct.\n\tResponseExample      = \"responseExample\" // Response example resource path, usually for OpenAPI in response struct.\n\tResponseExampleShort = \"resEg\"           // Short name of ResponseExample.\n)\n\n// StructTagPriority defines the default priority tags for Map*/Struct* functions.\n// Note that, the `gconv/param` tags are used by old version of package.\n// It is strongly recommended using short tag `c/p` instead in the future.\nvar StructTagPriority = []string{\n\tGConv, Param, GConvShort, ParamShort, Json,\n}\n"
  },
  {
    "path": "util/gtag/gtag_enums.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtag\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// Type name => enums json.\nvar enumsMap = make(map[string]json.RawMessage)\n\n// SetGlobalEnums sets the global enums into package.\n// Note that this operation is not concurrent safety.\nfunc SetGlobalEnums(enumsJSON string) error {\n\treturn json.Unmarshal([]byte(enumsJSON), &enumsMap)\n}\n\n// GetGlobalEnums retrieves and returns the global enums.\nfunc GetGlobalEnums() (string, error) {\n\tenumsBytes, err := json.Marshal(enumsMap)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(enumsBytes), nil\n}\n\n// GetEnumsByType retrieves and returns the stored enums json by type name.\n// The type name is like: github.com/gogf/gf/v2/encoding/gjson.ContentType\nfunc GetEnumsByType(typeName string) string {\n\treturn string(enumsMap[typeName])\n}\n"
  },
  {
    "path": "util/gtag/gtag_func.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtag\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\nvar (\n\tdata  = make(map[string]string)\n\tregex = regexp.MustCompile(`\\{(.+?)\\}`)\n)\n\n// Set sets tag content for specified name.\n// Note that it panics if `name` already exists.\nfunc Set(name, value string) {\n\tif _, ok := data[name]; ok {\n\t\tpanic(gerror.Newf(`value for tag name \"%s\" already exists`, name))\n\t}\n\tdata[name] = value\n}\n\n// SetOver performs as Set, but it overwrites the old value if `name` already exists.\nfunc SetOver(name, value string) {\n\tdata[name] = value\n}\n\n// Sets sets multiple tag content by map.\nfunc Sets(m map[string]string) {\n\tfor k, v := range m {\n\t\tSet(k, v)\n\t}\n}\n\n// SetsOver performs as Sets, but it overwrites the old value if `name` already exists.\nfunc SetsOver(m map[string]string) {\n\tfor k, v := range m {\n\t\tSetOver(k, v)\n\t}\n}\n\n// Get retrieves and returns the stored tag content for specified name.\nfunc Get(name string) string {\n\treturn data[name]\n}\n\n// Parse parses and returns the content by replacing all tag name variable to\n// its content for given `content`.\n// Eg:\n// gtag.Set(\"demo\", \"content\")\n// Parse(`This is {demo}`) -> `This is content`.\nfunc Parse(content string) string {\n\treturn regex.ReplaceAllStringFunc(content, func(s string) string {\n\t\tif v, ok := data[s[1:len(s)-1]]; ok {\n\t\t\treturn v\n\t\t}\n\t\treturn s\n\t})\n}\n"
  },
  {
    "path": "util/gtag/gtag_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtag_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nfunc ExampleSet() {\n\ttype User struct {\n\t\tg.Meta `name:\"User Struct\" description:\"{UserDescription}\"`\n\t}\n\tgtag.Sets(g.MapStrStr{\n\t\t`UserDescription`: `This is a demo struct named \"User Struct\"`,\n\t})\n\tfmt.Println(gmeta.Get(User{}, `description`))\n\n\t// Output:\n\t// This is a demo struct named \"User Struct\"\n}\n"
  },
  {
    "path": "util/gtag/gtag_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gtag_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_Set_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tk := guid.S()\n\t\tv := guid.S()\n\t\tgtag.Set(k, v)\n\t\tt.Assert(gtag.Get(k), v)\n\t})\n}\n\nfunc Test_SetOver_Get(t *testing.T) {\n\t// panic by Set\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk  = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\tgtag.Set(k, v1)\n\t\tt.Assert(gtag.Get(k), v1)\n\t\tdefer func() {\n\t\t\tt.AssertNE(recover(), nil)\n\t\t}()\n\t\tgtag.Set(k, v2)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk  = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\tgtag.SetOver(k, v1)\n\t\tt.Assert(gtag.Get(k), v1)\n\t\tgtag.SetOver(k, v2)\n\t\tt.Assert(gtag.Get(k), v2)\n\t})\n}\n\nfunc Test_Sets_Get(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t)\n\t\tgtag.Sets(g.MapStrStr{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.Assert(gtag.Get(k1), v1)\n\t\tt.Assert(gtag.Get(k2), v2)\n\t})\n}\n\nfunc Test_SetsOver_Get(t *testing.T) {\n\t// panic by Sets\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t\tv3 = guid.S()\n\t\t)\n\t\tgtag.Sets(g.MapStrStr{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.Assert(gtag.Get(k1), v1)\n\t\tt.Assert(gtag.Get(k2), v2)\n\t\tdefer func() {\n\t\t\tt.AssertNE(recover(), nil)\n\t\t}()\n\t\tgtag.Sets(g.MapStrStr{\n\t\t\tk1: v3,\n\t\t\tk2: v3,\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk1 = guid.S()\n\t\t\tk2 = guid.S()\n\t\t\tv1 = guid.S()\n\t\t\tv2 = guid.S()\n\t\t\tv3 = guid.S()\n\t\t)\n\t\tgtag.SetsOver(g.MapStrStr{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.Assert(gtag.Get(k1), v1)\n\t\tt.Assert(gtag.Get(k2), v2)\n\t\tgtag.SetsOver(g.MapStrStr{\n\t\t\tk1: v3,\n\t\t\tk2: v3,\n\t\t})\n\t\tt.Assert(gtag.Get(k1), v3)\n\t\tt.Assert(gtag.Get(k2), v3)\n\t})\n}\n\nfunc Test_Parse(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\tk1      = guid.S()\n\t\t\tk2      = guid.S()\n\t\t\tv1      = guid.S()\n\t\t\tv2      = guid.S()\n\t\t\tcontent = fmt.Sprintf(`this is {%s} and {%s}`, k1, k2)\n\t\t\texpect  = fmt.Sprintf(`this is %s and %s`, v1, v2)\n\t\t)\n\t\tgtag.Sets(g.MapStrStr{\n\t\t\tk1: v1,\n\t\t\tk2: v2,\n\t\t})\n\t\tt.Assert(gtag.Parse(content), expect)\n\t})\n}\n\nfunc Test_SetGlobalEnums(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\toldEnumsJson, err := gtag.GetGlobalEnums()\n\t\tt.AssertNil(err)\n\n\t\terr = gtag.SetGlobalEnums(`{\"k8s.io/apimachinery/pkg/api/resource.Format\": [\n        \"BinarySI\",\n        \"DecimalExponent\",\n        \"DecimalSI\"\n    ]}`)\n\t\tt.AssertNil(err)\n\t\tt.Assert(gtag.GetEnumsByType(\"k8s.io/apimachinery/pkg/api/resource.Format\"), `[\n        \"BinarySI\",\n        \"DecimalExponent\",\n        \"DecimalSI\"\n    ]`)\n\t\tt.AssertNil(gtag.SetGlobalEnums(oldEnumsJson))\n\t})\n}\n"
  },
  {
    "path": "util/guid/guid.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package guid provides simple and high performance unique id generation functionality.\npackage guid\n\nimport (\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/encoding/ghash\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/util/grand\"\n)\n\nconst (\n\tsequenceMax   = uint32(46655)                          // Sequence max(\"zzz\").\n\trandomStrBase = \"0123456789abcdefghijklmnopqrstuvwxyz\" // Random chars string(36 bytes).\n)\n\nvar (\n\tsequence     gtype.Uint32 // Sequence for unique purpose of the current process.\n\tmacAddrStr   = \"0000000\"  // Hash result of MAC addresses in 7 bytes.\n\tprocessIdStr = \"0000\"     // Process id in 4 bytes.\n)\n\n// init initializes several fixed local variable.\nfunc init() {\n\t// Hash result of MAC addresses in 7 bytes.\n\tmacs, _ := gipv4.GetMacArray()\n\tif len(macs) > 0 {\n\t\tvar macAddrBytes []byte\n\t\tfor _, mac := range macs {\n\t\t\tmacAddrBytes = append(macAddrBytes, []byte(mac)...)\n\t\t}\n\t\tb := []byte{'0', '0', '0', '0', '0', '0', '0'}\n\t\ts := strconv.FormatUint(uint64(ghash.SDBM(macAddrBytes)), 36)\n\t\tcopy(b, s)\n\t\tmacAddrStr = string(b)\n\t}\n\t// Process id in 4 bytes.\n\t{\n\t\tb := []byte{'0', '0', '0', '0'}\n\t\ts := strconv.FormatInt(int64(os.Getpid()), 36)\n\t\tcopy(b, s)\n\t\tprocessIdStr = string(b)\n\t}\n}\n\n// S creates and returns a global unique string in 32 bytes that meets most common\n// usages without strict UUID algorithm. It returns a unique string using default\n// unique algorithm if no `data` is given.\n//\n// The specified `data` can be no more than 2 parts. No matter how long each of the\n// `data` size is, each of them will be hashed into 7 bytes as part of the result.\n// If given `data` parts is less than 2, the leftover size of the result bytes will\n// be token by random string.\n//\n// The returned string is composed with:\n// 1. Default:    MACHash(7) + PID(4) + TimestampNano(12) + Sequence(3) + RandomString(6)\n// 2. CustomData: DataHash(7/14) + TimestampNano(12) + Sequence(3) + RandomString(3/10)\n//\n// Note that：\n//  1. The returned length is fixed to 32 bytes for performance purpose.\n//  2. The custom parameter `data` composed should have unique attribute in your\n//     business scenario.\nfunc S(data ...[]byte) string {\n\tvar (\n\t\tb       = make([]byte, 32)\n\t\tnanoStr = strconv.FormatInt(time.Now().UnixNano(), 36)\n\t)\n\tif len(data) == 0 {\n\t\tcopy(b, macAddrStr)\n\t\tcopy(b[7:], processIdStr)\n\t\tcopy(b[11:], nanoStr)\n\t\tcopy(b[23:], getSequence())\n\t\tcopy(b[26:], getRandomStr(6))\n\t} else if len(data) <= 2 {\n\t\tn := 0\n\t\tfor i, v := range data {\n\t\t\t// Ignore empty data item bytes.\n\t\t\tif len(v) > 0 {\n\t\t\t\tcopy(b[i*7:], getDataHashStr(v))\n\t\t\t\tn += 7\n\t\t\t}\n\t\t}\n\t\tcopy(b[n:], nanoStr)\n\t\tcopy(b[n+12:], getSequence())\n\t\tcopy(b[n+12+3:], getRandomStr(32-n-12-3))\n\t} else {\n\t\tpanic(gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\"too many data parts, it should be no more than 2 parts\",\n\t\t))\n\t}\n\treturn string(b)\n}\n\n// getSequence increases and returns the sequence string in 3 bytes.\n// The sequence is less than \"zzz\"(46655).\nfunc getSequence() []byte {\n\tb := []byte{'0', '0', '0'}\n\ts := strconv.FormatUint(uint64(sequence.Add(1)%sequenceMax), 36)\n\tcopy(b, s)\n\treturn b\n}\n\n// getRandomStr randomly picks and returns `n` count of chars from randomStrBase.\nfunc getRandomStr(n int) []byte {\n\tif n <= 0 {\n\t\treturn []byte{}\n\t}\n\tvar (\n\t\tb           = make([]byte, n)\n\t\tnumberBytes = grand.B(n)\n\t)\n\tfor i := range b {\n\t\tb[i] = randomStrBase[numberBytes[i]%36]\n\t}\n\treturn b\n}\n\n// getDataHashStr creates and returns hash bytes in 7 bytes with given data bytes.\nfunc getDataHashStr(data []byte) []byte {\n\tb := []byte{'0', '0', '0', '0', '0', '0', '0'}\n\ts := strconv.FormatUint(uint64(ghash.SDBM(data)), 36)\n\tcopy(b, s)\n\treturn b\n}\n"
  },
  {
    "path": "util/guid/guid_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage guid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Benchmark_S(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tguid.S()\n\t\t}\n\t})\n}\n\nfunc Benchmark_S_Data_1(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tguid.S([]byte(\"123\"))\n\t\t}\n\t})\n}\n\nfunc Benchmark_S_Data_2(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tfor pb.Next() {\n\t\t\tguid.S([]byte(\"123\"), []byte(\"456\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/guid/guid_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\"\n\npackage guid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n)\n\nfunc Test_S(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tset := gset.NewStrSet()\n\t\tfor i := 0; i < 1000000; i++ {\n\t\t\ts := guid.S()\n\t\t\tt.Assert(set.AddIfNotExist(s), true)\n\t\t\tt.Assert(len(s), 32)\n\t\t}\n\t})\n}\n\nfunc Test_S_Data(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(len(guid.S([]byte(\"123\"))), 32)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gutil provides utility functions.\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nconst (\n\tdumpIndent = `    `\n)\n\n// Keys retrieves and returns the keys from the given map or struct.\nfunc Keys(mapOrStruct any) (keysOrAttrs []string) {\n\tkeysOrAttrs = make([]string, 0)\n\tif m, ok := mapOrStruct.(map[string]any); ok {\n\t\tfor k := range m {\n\t\t\tkeysOrAttrs = append(keysOrAttrs, k)\n\t\t}\n\t\treturn\n\t}\n\tvar (\n\t\treflectValue reflect.Value\n\t\treflectKind  reflect.Kind\n\t)\n\tif v, ok := mapOrStruct.(reflect.Value); ok {\n\t\treflectValue = v\n\t} else {\n\t\treflectValue = reflect.ValueOf(mapOrStruct)\n\t}\n\treflectKind = reflectValue.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\tif !reflectValue.IsValid() || reflectValue.IsNil() {\n\t\t\treflectValue = reflect.New(reflectValue.Type().Elem()).Elem()\n\t\t\treflectKind = reflectValue.Kind()\n\t\t} else {\n\t\t\treflectValue = reflectValue.Elem()\n\t\t\treflectKind = reflectValue.Kind()\n\t\t}\n\t}\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\tfor _, k := range reflectValue.MapKeys() {\n\t\t\tkeysOrAttrs = append(keysOrAttrs, gconv.String(k.Interface()))\n\t\t}\n\tcase reflect.Struct:\n\t\tvar (\n\t\t\tfieldType   reflect.StructField\n\t\t\treflectType = reflectValue.Type()\n\t\t)\n\t\tfor i := 0; i < reflectValue.NumField(); i++ {\n\t\t\tfieldType = reflectType.Field(i)\n\t\t\tif fieldType.Anonymous {\n\t\t\t\tkeysOrAttrs = append(keysOrAttrs, Keys(reflectValue.Field(i))...)\n\t\t\t} else {\n\t\t\t\tkeysOrAttrs = append(keysOrAttrs, fieldType.Name)\n\t\t\t}\n\t\t}\n\tdefault:\n\t}\n\treturn\n}\n\n// Values retrieves and returns the values from the given map or struct.\nfunc Values(mapOrStruct any) (values []any) {\n\tvalues = make([]any, 0)\n\tif m, ok := mapOrStruct.(map[string]any); ok {\n\t\tfor _, v := range m {\n\t\t\tvalues = append(values, v)\n\t\t}\n\t\treturn\n\t}\n\tvar (\n\t\treflectValue reflect.Value\n\t\treflectKind  reflect.Kind\n\t)\n\tif v, ok := mapOrStruct.(reflect.Value); ok {\n\t\treflectValue = v\n\t} else {\n\t\treflectValue = reflect.ValueOf(mapOrStruct)\n\t}\n\treflectKind = reflectValue.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\tfor _, k := range reflectValue.MapKeys() {\n\t\t\tvalues = append(values, reflectValue.MapIndex(k).Interface())\n\t\t}\n\tcase reflect.Struct:\n\t\tvar (\n\t\t\tfieldType   reflect.StructField\n\t\t\treflectType = reflectValue.Type()\n\t\t)\n\t\tfor i := 0; i < reflectValue.NumField(); i++ {\n\t\t\tfieldType = reflectType.Field(i)\n\t\t\tif fieldType.Anonymous {\n\t\t\t\tvalues = append(values, Values(reflectValue.Field(i))...)\n\t\t\t} else {\n\t\t\t\tvalues = append(values, reflectValue.Field(i).Interface())\n\t\t\t}\n\t\t}\n\tdefault:\n\t}\n\treturn\n}\n"
  },
  {
    "path": "util/gutil/gutil_comparator.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"cmp\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Comparator is a function that compare a and b, and returns the result as int.\n//\n// Should return a number:\n//\n//\tnegative , if a < b\n//\tzero     , if a == b\n//\tpositive , if a > b\ntype Comparator func(a, b any) int\n\n// ComparatorString provides a fast comparison on strings.\nfunc ComparatorString(a, b any) int {\n\treturn strings.Compare(gconv.String(a), gconv.String(b))\n}\n\n// ComparatorInt provides a basic comparison on int.\nfunc ComparatorInt(a, b any) int {\n\treturn gconv.Int(a) - gconv.Int(b)\n}\n\n// ComparatorInt8 provides a basic comparison on int8.\nfunc ComparatorInt8(a, b any) int {\n\treturn int(gconv.Int8(a) - gconv.Int8(b))\n}\n\n// ComparatorInt16 provides a basic comparison on int16.\nfunc ComparatorInt16(a, b any) int {\n\treturn int(gconv.Int16(a) - gconv.Int16(b))\n}\n\n// ComparatorInt32 provides a basic comparison on int32.\nfunc ComparatorInt32(a, b any) int {\n\treturn int(gconv.Int32(a) - gconv.Int32(b))\n}\n\n// ComparatorInt64 provides a basic comparison on int64.\nfunc ComparatorInt64(a, b any) int {\n\treturn int(gconv.Int64(a) - gconv.Int64(b))\n}\n\n// ComparatorUint provides a basic comparison on uint.\nfunc ComparatorUint(a, b any) int {\n\treturn int(gconv.Uint(a) - gconv.Uint(b))\n}\n\n// ComparatorUint8 provides a basic comparison on uint8.\nfunc ComparatorUint8(a, b any) int {\n\treturn int(gconv.Uint8(a) - gconv.Uint8(b))\n}\n\n// ComparatorUint16 provides a basic comparison on uint16.\nfunc ComparatorUint16(a, b any) int {\n\treturn int(gconv.Uint16(a) - gconv.Uint16(b))\n}\n\n// ComparatorUint32 provides a basic comparison on uint32.\nfunc ComparatorUint32(a, b any) int {\n\treturn int(gconv.Uint32(a) - gconv.Uint32(b))\n}\n\n// ComparatorUint64 provides a basic comparison on uint64.\nfunc ComparatorUint64(a, b any) int {\n\treturn int(gconv.Uint64(a) - gconv.Uint64(b))\n}\n\n// ComparatorFloat32 provides a basic comparison on float32.\nfunc ComparatorFloat32(a, b any) int {\n\taFloat := gconv.Float32(a)\n\tbFloat := gconv.Float32(b)\n\tif aFloat == bFloat {\n\t\treturn 0\n\t}\n\tif aFloat > bFloat {\n\t\treturn 1\n\t}\n\treturn -1\n}\n\n// ComparatorFloat64 provides a basic comparison on float64.\nfunc ComparatorFloat64(a, b any) int {\n\taFloat := gconv.Float64(a)\n\tbFloat := gconv.Float64(b)\n\tif aFloat == bFloat {\n\t\treturn 0\n\t}\n\tif aFloat > bFloat {\n\t\treturn 1\n\t}\n\treturn -1\n}\n\n// ComparatorByte provides a basic comparison on byte.\nfunc ComparatorByte(a, b any) int {\n\treturn int(gconv.Byte(a) - gconv.Byte(b))\n}\n\n// ComparatorRune provides a basic comparison on rune.\nfunc ComparatorRune(a, b any) int {\n\treturn int(gconv.Rune(a) - gconv.Rune(b))\n}\n\n// ComparatorTime provides a basic comparison on time.Time.\nfunc ComparatorTime(a, b any) int {\n\taTime := gconv.Time(a)\n\tbTime := gconv.Time(b)\n\tswitch {\n\tcase aTime.After(bTime):\n\t\treturn 1\n\tcase aTime.Before(bTime):\n\t\treturn -1\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// ComparatorT provides a generic comparison for ordered types.\nfunc ComparatorT[T cmp.Ordered](a, b T) int {\n\treturn cmp.Compare(a, b)\n}\n\nfunc ComparatorTStr[T any](a, b T) int {\n\treturn cmp.Compare(gconv.String(a), gconv.String(b))\n}\n"
  },
  {
    "path": "util/gutil/gutil_copy.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/deepcopy\"\n)\n\n// Copy returns a deep copy of v.\n//\n// Copy is unable to copy unexported fields in a struct (lowercase field names).\n// Unexported fields can't be reflected by the Go runtime and therefore\n// they can't perform any data copies.\nfunc Copy(src any) (dst any) {\n\treturn deepcopy.Copy(src)\n}\n"
  },
  {
    "path": "util/gutil/gutil_default.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\n// GetOrDefaultStr checks and returns value according whether parameter `param` available.\n// It returns `param[0]` if it is available, or else it returns `def`.\nfunc GetOrDefaultStr(def string, param ...string) string {\n\tvalue := def\n\tif len(param) > 0 && param[0] != \"\" {\n\t\tvalue = param[0]\n\t}\n\treturn value\n}\n\n// GetOrDefaultAny checks and returns value according whether parameter `param` available.\n// It returns `param[0]` if it is available, or else it returns `def`.\nfunc GetOrDefaultAny(def any, param ...any) any {\n\tvalue := def\n\tif len(param) > 0 && param[0] != nil {\n\t\tvalue = param[0]\n\t}\n\treturn value\n}\n"
  },
  {
    "path": "util/gutil/gutil_dump.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// iString is used for type assert api for String().\ntype iString interface {\n\tString() string\n}\n\n// iError is used for type assert api for Error().\ntype iError interface {\n\tError() string\n}\n\n// iMarshalJSON is the interface for custom Json marshaling.\ntype iMarshalJSON interface {\n\tMarshalJSON() ([]byte, error)\n}\n\n// DumpOption specifies the behavior of function Export.\ntype DumpOption struct {\n\tWithType     bool // WithType specifies dumping content with type information.\n\tExportedOnly bool // Only dump Exported fields for structs.\n}\n\n// Dump prints variables `values` to stdout with more manually readable.\nfunc Dump(values ...any) {\n\tfor _, value := range values {\n\t\tDumpWithOption(value, DumpOption{\n\t\t\tWithType:     false,\n\t\t\tExportedOnly: false,\n\t\t})\n\t}\n}\n\n// DumpWithType acts like Dump, but with type information.\n// Also see Dump.\nfunc DumpWithType(values ...any) {\n\tfor _, value := range values {\n\t\tDumpWithOption(value, DumpOption{\n\t\t\tWithType:     true,\n\t\t\tExportedOnly: false,\n\t\t})\n\t}\n}\n\n// DumpWithOption returns variables `values` as a string with more manually readable.\nfunc DumpWithOption(value any, option DumpOption) {\n\tbuffer := bytes.NewBuffer(nil)\n\tDumpTo(buffer, value, DumpOption{\n\t\tWithType:     option.WithType,\n\t\tExportedOnly: option.ExportedOnly,\n\t})\n\tfmt.Println(buffer.String())\n}\n\n// DumpTo writes variables `values` as a string in to `writer` with more manually readable\nfunc DumpTo(writer io.Writer, value any, option DumpOption) {\n\tbuffer := bytes.NewBuffer(nil)\n\tdoDump(value, \"\", buffer, doDumpOption{\n\t\tWithType:     option.WithType,\n\t\tExportedOnly: option.ExportedOnly,\n\t})\n\t_, _ = writer.Write(buffer.Bytes())\n}\n\ntype doDumpOption struct {\n\tWithType         bool\n\tExportedOnly     bool\n\tDumpedPointerSet map[string]struct{}\n}\n\nfunc doDump(value any, indent string, buffer *bytes.Buffer, option doDumpOption) {\n\tif option.DumpedPointerSet == nil {\n\t\toption.DumpedPointerSet = map[string]struct{}{}\n\t}\n\n\tif value == nil {\n\t\tbuffer.WriteString(`<nil>`)\n\t\treturn\n\t}\n\tvar reflectValue reflect.Value\n\tif v, ok := value.(reflect.Value); ok {\n\t\treflectValue = v\n\t\tif v.IsValid() && v.CanInterface() {\n\t\t\tvalue = v.Interface()\n\t\t} else {\n\t\t\tif convertedValue, ok := reflection.ValueToInterface(v); ok {\n\t\t\t\tvalue = convertedValue\n\t\t\t}\n\t\t}\n\t} else {\n\t\treflectValue = reflect.ValueOf(value)\n\t}\n\tvar reflectKind = reflectValue.Kind()\n\t// Double check nil value.\n\tif value == nil || reflectKind == reflect.Invalid {\n\t\tbuffer.WriteString(`<nil>`)\n\t\treturn\n\t}\n\tvar (\n\t\treflectTypeName = reflectValue.Type().String()\n\t\tptrAddress      string\n\t\tnewIndent       = indent + dumpIndent\n\t)\n\treflectTypeName = strings.ReplaceAll(reflectTypeName, `[]uint8`, `[]byte`)\n\tfor reflectKind == reflect.Pointer {\n\t\tif ptrAddress == \"\" {\n\t\t\tptrAddress = fmt.Sprintf(`0x%x`, reflectValue.Pointer())\n\t\t}\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tvar (\n\t\texportInternalInput = doDumpInternalInput{\n\t\t\tValue:            value,\n\t\t\tIndent:           indent,\n\t\t\tNewIndent:        newIndent,\n\t\t\tBuffer:           buffer,\n\t\t\tOption:           option,\n\t\t\tPtrAddress:       ptrAddress,\n\t\t\tReflectValue:     reflectValue,\n\t\t\tReflectTypeName:  reflectTypeName,\n\t\t\tExportedOnly:     option.ExportedOnly,\n\t\t\tDumpedPointerSet: option.DumpedPointerSet,\n\t\t}\n\t)\n\tswitch reflectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tdoDumpSlice(exportInternalInput)\n\n\tcase reflect.Map:\n\t\tdoDumpMap(exportInternalInput)\n\n\tcase reflect.Struct:\n\t\tdoDumpStruct(exportInternalInput)\n\n\tcase reflect.String:\n\t\tdoDumpString(exportInternalInput)\n\n\tcase reflect.Bool:\n\t\tdoDumpBool(exportInternalInput)\n\n\tcase\n\t\treflect.Int,\n\t\treflect.Int8,\n\t\treflect.Int16,\n\t\treflect.Int32,\n\t\treflect.Int64,\n\t\treflect.Uint,\n\t\treflect.Uint8,\n\t\treflect.Uint16,\n\t\treflect.Uint32,\n\t\treflect.Uint64,\n\t\treflect.Float32,\n\t\treflect.Float64,\n\t\treflect.Complex64,\n\t\treflect.Complex128:\n\t\tdoDumpNumber(exportInternalInput)\n\n\tcase reflect.Chan:\n\t\tfmt.Fprintf(buffer, `<%s>`, reflectValue.Type().String())\n\n\tcase reflect.Func:\n\t\tif reflectValue.IsNil() || !reflectValue.IsValid() {\n\t\t\tbuffer.WriteString(`<nil>`)\n\t\t} else {\n\t\t\tfmt.Fprintf(buffer, `<%s>`, reflectValue.Type().String())\n\t\t}\n\n\tcase reflect.Interface:\n\t\tdoDump(exportInternalInput.ReflectValue.Elem(), indent, buffer, option)\n\n\tdefault:\n\t\tdoDumpDefault(exportInternalInput)\n\t}\n}\n\ntype doDumpInternalInput struct {\n\tValue            any\n\tIndent           string\n\tNewIndent        string\n\tBuffer           *bytes.Buffer\n\tOption           doDumpOption\n\tReflectValue     reflect.Value\n\tReflectTypeName  string\n\tPtrAddress       string\n\tExportedOnly     bool\n\tDumpedPointerSet map[string]struct{}\n}\n\nfunc doDumpSlice(in doDumpInternalInput) {\n\tif b, ok := in.Value.([]byte); ok {\n\t\tif !in.Option.WithType {\n\t\t\tfmt.Fprintf(in.Buffer, `\"%s\"`, addSlashesForString(string(b)))\n\t\t} else {\n\t\t\tfmt.Fprintf(in.Buffer, `%s(%d) \"%s\"`, in.ReflectTypeName, len(string(b)), string(b))\n\t\t}\n\t\treturn\n\t}\n\tif in.ReflectValue.Len() == 0 {\n\t\tif !in.Option.WithType {\n\t\t\tin.Buffer.WriteString(\"[]\")\n\t\t} else {\n\t\t\tfmt.Fprintf(in.Buffer, \"%s(0) []\", in.ReflectTypeName)\n\t\t}\n\t\treturn\n\t}\n\tif !in.Option.WithType {\n\t\tin.Buffer.WriteString(\"[\\n\")\n\t} else {\n\t\tfmt.Fprintf(in.Buffer, \"%s(%d) [\\n\", in.ReflectTypeName, in.ReflectValue.Len())\n\t}\n\tfor i := 0; i < in.ReflectValue.Len(); i++ {\n\t\tin.Buffer.WriteString(in.NewIndent)\n\t\tdoDump(in.ReflectValue.Index(i), in.NewIndent, in.Buffer, in.Option)\n\t\tin.Buffer.WriteString(\",\\n\")\n\t}\n\tfmt.Fprintf(in.Buffer, \"%s]\", in.Indent)\n}\n\nfunc doDumpMap(in doDumpInternalInput) {\n\tvar mapKeys = make([]reflect.Value, 0)\n\tfor _, key := range in.ReflectValue.MapKeys() {\n\t\tif !key.CanInterface() {\n\t\t\tcontinue\n\t\t}\n\t\tmapKey := key\n\t\tmapKeys = append(mapKeys, mapKey)\n\t}\n\tif len(mapKeys) == 0 {\n\t\tif !in.Option.WithType {\n\t\t\tin.Buffer.WriteString(\"{}\")\n\t\t} else {\n\t\t\tfmt.Fprintf(in.Buffer, \"%s(0) {}\", in.ReflectTypeName)\n\t\t}\n\t\treturn\n\t}\n\tvar (\n\t\tmaxSpaceNum = 0\n\t\ttmpSpaceNum = 0\n\t\tmapKeyStr   = \"\"\n\t)\n\tfor _, key := range mapKeys {\n\t\ttmpSpaceNum = len(fmt.Sprintf(`%v`, key.Interface()))\n\t\tif tmpSpaceNum > maxSpaceNum {\n\t\t\tmaxSpaceNum = tmpSpaceNum\n\t\t}\n\t}\n\tif !in.Option.WithType {\n\t\tin.Buffer.WriteString(\"{\\n\")\n\t} else {\n\t\tfmt.Fprintf(in.Buffer, \"%s(%d) {\\n\", in.ReflectTypeName, len(mapKeys))\n\t}\n\tfor _, mapKey := range mapKeys {\n\t\ttmpSpaceNum = len(fmt.Sprintf(`%v`, mapKey.Interface()))\n\t\tif mapKey.Kind() == reflect.String {\n\t\t\tmapKeyStr = fmt.Sprintf(`\"%v\"`, mapKey.Interface())\n\t\t} else {\n\t\t\tmapKeyStr = fmt.Sprintf(`%v`, mapKey.Interface())\n\t\t}\n\t\t// Map key and indent string dump.\n\t\tif !in.Option.WithType {\n\t\t\tfmt.Fprintf(\n\t\t\t\tin.Buffer,\n\t\t\t\t\"%s%v:%s\",\n\t\t\t\tin.NewIndent,\n\t\t\t\tmapKeyStr,\n\t\t\t\tstrings.Repeat(\" \", maxSpaceNum-tmpSpaceNum+1),\n\t\t\t)\n\t\t} else {\n\t\t\tfmt.Fprintf(\n\t\t\t\tin.Buffer,\n\t\t\t\t\"%s%s(%v):%s\",\n\t\t\t\tin.NewIndent,\n\t\t\t\tmapKey.Type().String(),\n\t\t\t\tmapKeyStr,\n\t\t\t\tstrings.Repeat(\" \", maxSpaceNum-tmpSpaceNum+1),\n\t\t\t)\n\t\t}\n\t\t// Map value dump.\n\t\tdoDump(in.ReflectValue.MapIndex(mapKey), in.NewIndent, in.Buffer, in.Option)\n\t\tin.Buffer.WriteString(\",\\n\")\n\t}\n\tfmt.Fprintf(in.Buffer, \"%s}\", in.Indent)\n}\n\nfunc doDumpStruct(in doDumpInternalInput) {\n\tif in.PtrAddress != \"\" {\n\t\tif _, ok := in.DumpedPointerSet[in.PtrAddress]; ok {\n\t\t\tfmt.Fprintf(in.Buffer, `<cycle dump %s>`, in.PtrAddress)\n\t\t\treturn\n\t\t}\n\t\t// Add to set and remove when function returns (path-based cycle detection).\n\t\tin.DumpedPointerSet[in.PtrAddress] = struct{}{}\n\t\tdefer delete(in.DumpedPointerSet, in.PtrAddress)\n\t}\n\n\tstructFields, _ := gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         in.Value,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbedded,\n\t})\n\tvar (\n\t\thasNoExportedFields = true\n\t\t_, isReflectValue   = in.Value.(reflect.Value)\n\t)\n\tfor _, field := range structFields {\n\t\tif field.IsExported() {\n\t\t\thasNoExportedFields = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif !isReflectValue && (len(structFields) == 0 || hasNoExportedFields) {\n\t\tvar (\n\t\t\tstructContentStr  = \"\"\n\t\t\tattributeCountStr = \"0\"\n\t\t)\n\t\tif v, ok := in.Value.(iString); ok {\n\t\t\tstructContentStr = v.String()\n\t\t} else if v, ok := in.Value.(iError); ok {\n\t\t\tstructContentStr = v.Error()\n\t\t} else if v, ok := in.Value.(iMarshalJSON); ok {\n\t\t\tb, _ := v.MarshalJSON()\n\t\t\tstructContentStr = string(b)\n\t\t} else {\n\t\t\t// Has no common interface implements.\n\t\t\tif len(structFields) != 0 {\n\t\t\t\tgoto dumpStructFields\n\t\t\t}\n\t\t}\n\t\tif structContentStr == \"\" {\n\t\t\tstructContentStr = \"{}\"\n\t\t} else {\n\t\t\tstructContentStr = fmt.Sprintf(`\"%s\"`, addSlashesForString(structContentStr))\n\t\t\tattributeCountStr = fmt.Sprintf(`%d`, len(structContentStr)-2)\n\t\t}\n\t\tif !in.Option.WithType {\n\t\t\tin.Buffer.WriteString(structContentStr)\n\t\t} else {\n\t\t\tfmt.Fprintf(\n\t\t\t\tin.Buffer,\n\t\t\t\t\"%s(%s) %s\",\n\t\t\t\tin.ReflectTypeName,\n\t\t\t\tattributeCountStr,\n\t\t\t\tstructContentStr,\n\t\t\t)\n\t\t}\n\t\treturn\n\t}\n\ndumpStructFields:\n\tvar (\n\t\tmaxSpaceNum = 0\n\t\ttmpSpaceNum = 0\n\t)\n\tfor _, field := range structFields {\n\t\tif in.ExportedOnly && !field.IsExported() {\n\t\t\tcontinue\n\t\t}\n\t\ttmpSpaceNum = len(field.Name())\n\t\tif tmpSpaceNum > maxSpaceNum {\n\t\t\tmaxSpaceNum = tmpSpaceNum\n\t\t}\n\t}\n\tif !in.Option.WithType {\n\t\tin.Buffer.WriteString(\"{\\n\")\n\t} else {\n\t\tfmt.Fprintf(in.Buffer, \"%s(%d) {\\n\", in.ReflectTypeName, len(structFields))\n\t}\n\tfor _, field := range structFields {\n\t\tif in.ExportedOnly && !field.IsExported() {\n\t\t\tcontinue\n\t\t}\n\t\ttmpSpaceNum = len(fmt.Sprintf(`%v`, field.Name()))\n\t\tfmt.Fprintf(\n\t\t\tin.Buffer,\n\t\t\t\"%s%s:%s\",\n\t\t\tin.NewIndent,\n\t\t\tfield.Name(),\n\t\t\tstrings.Repeat(\" \", maxSpaceNum-tmpSpaceNum+1),\n\t\t)\n\t\tdoDump(field.Value, in.NewIndent, in.Buffer, in.Option)\n\t\tin.Buffer.WriteString(\",\\n\")\n\t}\n\tfmt.Fprintf(in.Buffer, \"%s}\", in.Indent)\n}\n\nfunc doDumpNumber(in doDumpInternalInput) {\n\tif v, ok := in.Value.(iString); ok {\n\t\ts := v.String()\n\t\tif !in.Option.WithType {\n\t\t\tfmt.Fprintf(in.Buffer, `\"%v\"`, addSlashesForString(s))\n\t\t} else {\n\t\t\tfmt.Fprintf(\n\t\t\t\tin.Buffer,\n\t\t\t\t\"%s(%d) %s\",\n\t\t\t\tin.ReflectTypeName,\n\t\t\t\tlen(s),\n\t\t\t\tfmt.Sprintf(`\"%v\"`, addSlashesForString(s)),\n\t\t\t)\n\t\t}\n\t} else {\n\t\tdoDumpDefault(in)\n\t}\n}\n\nfunc doDumpString(in doDumpInternalInput) {\n\ts := in.ReflectValue.String()\n\tif !in.Option.WithType {\n\t\tfmt.Fprintf(in.Buffer, `\"%v\"`, addSlashesForString(s))\n\t} else {\n\t\tfmt.Fprintf(\n\t\t\tin.Buffer,\n\t\t\t`%s(%d) \"%v\"`,\n\t\t\tin.ReflectTypeName,\n\t\t\tlen(s),\n\t\t\taddSlashesForString(s),\n\t\t)\n\t}\n}\n\nfunc doDumpBool(in doDumpInternalInput) {\n\tvar s string\n\tif in.ReflectValue.Bool() {\n\t\ts = `true`\n\t} else {\n\t\ts = `false`\n\t}\n\tif in.Option.WithType {\n\t\ts = fmt.Sprintf(`bool(%s)`, s)\n\t}\n\tin.Buffer.WriteString(s)\n}\n\nfunc doDumpDefault(in doDumpInternalInput) {\n\tvar s string\n\tif in.ReflectValue.IsValid() && in.ReflectValue.CanInterface() {\n\t\ts = fmt.Sprintf(\"%v\", in.ReflectValue.Interface())\n\t}\n\tif s == \"\" {\n\t\ts = fmt.Sprintf(\"%v\", in.Value)\n\t}\n\ts = gstr.Trim(s, `<>`)\n\tif !in.Option.WithType {\n\t\tin.Buffer.WriteString(s)\n\t} else {\n\t\tfmt.Fprintf(in.Buffer, \"%s(%s)\", in.ReflectTypeName, s)\n\t}\n}\n\nfunc addSlashesForString(s string) string {\n\treturn gstr.ReplaceByMap(s, map[string]string{\n\t\t`\"`:  `\\\"`,\n\t\t`'`:  `\\'`,\n\t\t\"\\r\": `\\r`,\n\t\t\"\\t\": `\\t`,\n\t\t\"\\n\": `\\n`,\n\t})\n}\n\n// DumpJson pretty dumps json content to stdout.\nfunc DumpJson(value any) {\n\tswitch result := value.(type) {\n\tcase []byte:\n\t\tdoDumpJSON(result)\n\tcase string:\n\t\tdoDumpJSON([]byte(result))\n\tdefault:\n\t\tjsonContent, err := json.Marshal(value)\n\t\tif err != nil {\n\t\t\tfmt.Println(err.Error())\n\t\t\treturn\n\t\t}\n\t\tdoDumpJSON(jsonContent)\n\t}\n}\n\nfunc doDumpJSON(jsonContent []byte) {\n\tvar (\n\t\tbuffer    = bytes.NewBuffer(nil)\n\t\tjsonBytes = jsonContent\n\t)\n\tif err := json.Indent(buffer, jsonBytes, \"\", \"    \"); err != nil {\n\t\tfmt.Println(err.Error())\n\t}\n\tfmt.Println(buffer.String())\n}\n"
  },
  {
    "path": "util/gutil/gutil_goroutine.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"context\"\n)\n\n// Go creates a new asynchronous goroutine function with specified recover function.\n//\n// The parameter `recoverFunc` is called when any panic during executing of `goroutineFunc`.\n// If `recoverFunc` is given nil, it ignores the panic from `goroutineFunc` and no panic will\n// throw to parent goroutine.\n//\n// But, note that, if `recoverFunc` also throws panic, such panic will be thrown to parent goroutine.\nfunc Go(\n\tctx context.Context,\n\tgoroutineFunc func(ctx context.Context),\n\trecoverFunc func(ctx context.Context, exception error),\n) {\n\tif goroutineFunc == nil {\n\t\treturn\n\t}\n\tgo TryCatch(ctx, goroutineFunc, recoverFunc)\n}\n"
  },
  {
    "path": "util/gutil/gutil_is.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n)\n\n// IsEmpty checks given `value` empty or not.\n// It returns false if `value` is: integer(0), bool(false), slice/map(len=0), nil;\n// or else returns true.\nfunc IsEmpty(value any) bool {\n\treturn empty.IsEmpty(value)\n}\n\n// IsTypeOf checks and returns whether the type of `value` and `valueInExpectType` equal.\nfunc IsTypeOf(value, valueInExpectType any) bool {\n\treturn reflect.TypeOf(value) == reflect.TypeOf(valueInExpectType)\n}\n"
  },
  {
    "path": "util/gutil/gutil_list.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\n//\n// The parameter `list` supports types like:\n// []map[string]any\n// []map[string]sub-map\n// []struct\n// []struct:sub-struct\n// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.\nfunc ListItemValues(list any, key any, subKey ...any) (values []any) {\n\tvar reflectValue reflect.Value\n\tif v, ok := list.(reflect.Value); ok {\n\t\treflectValue = v\n\t} else {\n\t\treflectValue = reflect.ValueOf(list)\n\t}\n\treflectKind := reflectValue.Kind()\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tif reflectValue.Len() == 0 {\n\t\t\treturn\n\t\t}\n\t\tvalues = []any{}\n\t\tfor i := 0; i < reflectValue.Len(); i++ {\n\t\t\tif value, ok := ItemValue(reflectValue.Index(i), key); ok {\n\t\t\t\tif len(subKey) > 0 && subKey[0] != nil {\n\t\t\t\t\tif subValue, ok := ItemValue(value, subKey[0]); ok {\n\t\t\t\t\t\tvalue = subValue\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif array, ok := value.([]any); ok {\n\t\t\t\t\tvalues = append(values, array...)\n\t\t\t\t} else {\n\t\t\t\t\tvalues = append(values, value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// ItemValue retrieves and returns its value of which name/attribute specified by `key`.\n// The parameter `item` can be type of map/*map/struct/*struct.\nfunc ItemValue(item any, key any) (value any, found bool) {\n\tvar reflectValue reflect.Value\n\tif v, ok := item.(reflect.Value); ok {\n\t\treflectValue = v\n\t} else {\n\t\treflectValue = reflect.ValueOf(item)\n\t}\n\treflectKind := reflectValue.Kind()\n\tif reflectKind == reflect.Interface {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tvar keyValue reflect.Value\n\tif v, ok := key.(reflect.Value); ok {\n\t\tkeyValue = v\n\t} else {\n\t\tkeyValue = reflect.ValueOf(key)\n\t}\n\tswitch reflectKind {\n\tcase reflect.Array, reflect.Slice:\n\t\t// The `key` must be type of string.\n\t\tvalues := ListItemValues(reflectValue, keyValue.String())\n\t\tif values == nil {\n\t\t\treturn nil, false\n\t\t}\n\t\treturn values, true\n\n\tcase reflect.Map:\n\t\tv := reflectValue.MapIndex(keyValue)\n\t\tif v.IsValid() {\n\t\t\tfound = true\n\t\t\tvalue = v.Interface()\n\t\t}\n\n\tcase reflect.Struct:\n\t\t// The `mapKey` must be type of string.\n\t\tv := reflectValue.FieldByName(keyValue.String())\n\t\tif v.IsValid() {\n\t\t\tfound = true\n\t\t\tvalue = v.Interface()\n\t\t}\n\t}\n\treturn\n}\n\n// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.\n// Note that the parameter `list` should be type of slice which contains elements of map or struct,\n// or else it returns an empty slice.\nfunc ListItemValuesUnique(list any, key string, subKey ...any) []any {\n\tvalues := ListItemValues(list, key, subKey...)\n\tif len(values) > 0 {\n\t\tvar (\n\t\t\tok bool\n\t\t\tm  = make(map[any]struct{}, len(values))\n\t\t)\n\t\tfor i := 0; i < len(values); {\n\t\t\tvalue := values[i]\n\t\t\tif t, ok := value.([]byte); ok {\n\t\t\t\t// make byte slice comparable\n\t\t\t\tvalue = string(t)\n\t\t\t}\n\t\t\tif _, ok = m[value]; ok {\n\t\t\t\tvalues = SliceDelete(values, i)\n\t\t\t} else {\n\t\t\t\tm[value] = struct{}{}\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\t}\n\treturn values\n}\n\n// ListToMapByKey converts `list` to a map[string]any of which key is specified by `key`.\n// Note that the item value may be type of slice.\nfunc ListToMapByKey(list []map[string]any, key string) map[string]any {\n\treturn utils.ListToMapByKey(list, key)\n}\n"
  },
  {
    "path": "util/gutil/gutil_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/internal/utils\"\n)\n\n// MapCopy does a shallow copy from map `data` to `copy` for most commonly used map type\n// map[string]any.\nfunc MapCopy(data map[string]any) (copy map[string]any) {\n\tcopy = make(map[string]any, len(data))\n\tfor k, v := range data {\n\t\tcopy[k] = v\n\t}\n\treturn\n}\n\n// MapContains checks whether map `data` contains `key`.\nfunc MapContains(data map[string]any, key string) (ok bool) {\n\tif len(data) == 0 {\n\t\treturn\n\t}\n\t_, ok = data[key]\n\treturn\n}\n\n// MapDelete deletes all `keys` from map `data`.\nfunc MapDelete(data map[string]any, keys ...string) {\n\tif len(data) == 0 {\n\t\treturn\n\t}\n\tfor _, key := range keys {\n\t\tdelete(data, key)\n\t}\n}\n\n// MapMerge merges all map from `src` to map `dst`.\nfunc MapMerge(dstMap map[string]any, srcMaps ...map[string]any) {\n\tif dstMap == nil {\n\t\treturn\n\t}\n\tfor _, m := range srcMaps {\n\t\tfor k, v := range m {\n\t\t\tdstMap[k] = v\n\t\t}\n\t}\n}\n\n// MapMergeCopy creates and returns a new map which merges all map from `src`.\nfunc MapMergeCopy(maps ...map[string]any) (copy map[string]any) {\n\tcopy = make(map[string]any)\n\tfor _, m := range maps {\n\t\tfor k, v := range m {\n\t\t\tcopy[k] = v\n\t\t}\n\t}\n\treturn\n}\n\n// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.\n//\n// Note that this function might be of low performance.\nfunc MapPossibleItemByKey(data map[string]any, key string) (foundKey string, foundValue any) {\n\treturn utils.MapPossibleItemByKey(data, key)\n}\n\n// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.\n// It checks the key ignoring cases and symbols.\n//\n// Note that this function might be of low performance.\nfunc MapContainsPossibleKey(data map[string]any, key string) bool {\n\treturn utils.MapContainsPossibleKey(data, key)\n}\n\n// MapOmitEmpty deletes all empty values from given map.\nfunc MapOmitEmpty(data map[string]any) {\n\tif len(data) == 0 {\n\t\treturn\n\t}\n\tfor k, v := range data {\n\t\tif IsEmpty(v) {\n\t\t\tdelete(data, k)\n\t\t}\n\t}\n}\n\n// MapToSlice converts map to slice of which all keys and values are its items.\n// Eg: {\"K1\": \"v1\", \"K2\": \"v2\"} => [\"K1\", \"v1\", \"K2\", \"v2\"]\nfunc MapToSlice(data any) []any {\n\tvar (\n\t\treflectValue = reflect.ValueOf(data)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Map:\n\t\tarray := make([]any, 0)\n\t\tfor _, key := range reflectValue.MapKeys() {\n\t\t\tarray = append(array, key.Interface())\n\t\t\tarray = append(array, reflectValue.MapIndex(key).Interface())\n\t\t}\n\t\treturn array\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gutil/gutil_reflect.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n)\n\ntype (\n\tOriginValueAndKindOutput = reflection.OriginValueAndKindOutput\n\tOriginTypeAndKindOutput  = reflection.OriginTypeAndKindOutput\n)\n\n// OriginValueAndKind retrieves and returns the original reflect value and kind.\nfunc OriginValueAndKind(value any) (out OriginValueAndKindOutput) {\n\treturn reflection.OriginValueAndKind(value)\n}\n\n// OriginTypeAndKind retrieves and returns the original reflect type and kind.\nfunc OriginTypeAndKind(value any) (out OriginTypeAndKindOutput) {\n\treturn reflection.OriginTypeAndKind(value)\n}\n"
  },
  {
    "path": "util/gutil/gutil_slice.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// SliceCopy does a shallow copy of slice `data` for most commonly used slice type\n// []any.\nfunc SliceCopy(slice []any) []any {\n\tnewSlice := make([]any, len(slice))\n\tcopy(newSlice, slice)\n\treturn newSlice\n}\n\n// SliceInsertBefore inserts the `values` to the front of `index` and returns a new slice.\nfunc SliceInsertBefore(slice []any, index int, values ...any) (newSlice []any) {\n\tif index < 0 || index >= len(slice) {\n\t\treturn slice\n\t}\n\tnewSlice = make([]any, len(slice)+len(values))\n\tcopy(newSlice, slice[0:index])\n\tcopy(newSlice[index:], values)\n\tcopy(newSlice[index+len(values):], slice[index:])\n\treturn\n}\n\n// SliceInsertAfter inserts the `values` to the back of `index` and returns a new slice.\nfunc SliceInsertAfter(slice []any, index int, values ...any) (newSlice []any) {\n\tif index < 0 || index >= len(slice) {\n\t\treturn slice\n\t}\n\tnewSlice = make([]any, len(slice)+len(values))\n\tcopy(newSlice, slice[0:index+1])\n\tcopy(newSlice[index+1:], values)\n\tcopy(newSlice[index+1+len(values):], slice[index+1:])\n\treturn\n}\n\n// SliceDelete deletes an element at `index` and returns the new slice.\n// It does nothing if the given `index` is invalid.\nfunc SliceDelete(slice []any, index int) (newSlice []any) {\n\tif index < 0 || index >= len(slice) {\n\t\treturn slice\n\t}\n\t// Determine array boundaries when deleting to improve deletion efficiency.\n\tif index == 0 {\n\t\treturn slice[1:]\n\t} else if index == len(slice)-1 {\n\t\treturn slice[:index]\n\t}\n\t// If it is a non-boundary delete,\n\t// it will involve the creation of an array,\n\t// then the deletion is less efficient.\n\treturn append(slice[:index], slice[index+1:]...)\n}\n\n// SliceToMap converts slice type variable `slice` to `map[string]any`.\n// Note that if the length of `slice` is not an even number, it returns nil.\n// Eg:\n// [\"K1\", \"v1\", \"K2\", \"v2\"] => {\"K1\": \"v1\", \"K2\": \"v2\"}\n// [\"K1\", \"v1\", \"K2\"]       => nil\nfunc SliceToMap(slice any) map[string]any {\n\tvar (\n\t\treflectValue = reflect.ValueOf(slice)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tlength := reflectValue.Len()\n\t\tif length%2 != 0 {\n\t\t\treturn nil\n\t\t}\n\t\tdata := make(map[string]any)\n\t\tfor i := 0; i < reflectValue.Len(); i += 2 {\n\t\t\tdata[gconv.String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()\n\t\t}\n\t\treturn data\n\t}\n\treturn nil\n}\n\n// SliceToMapWithColumnAsKey converts slice type variable `slice` to `map[any]any`\n// The value of specified column use as the key for returned map.\n// Eg:\n// SliceToMapWithColumnAsKey([{\"K1\": \"v1\", \"K2\": 1}, {\"K1\": \"v2\", \"K2\": 2}], \"K1\") => {\"v1\": {\"K1\": \"v1\", \"K2\": 1}, \"v2\": {\"K1\": \"v2\", \"K2\": 2}}\n// SliceToMapWithColumnAsKey([{\"K1\": \"v1\", \"K2\": 1}, {\"K1\": \"v2\", \"K2\": 2}], \"K2\") => {1: {\"K1\": \"v1\", \"K2\": 1}, 2: {\"K1\": \"v2\", \"K2\": 2}}\nfunc SliceToMapWithColumnAsKey(slice any, key any) map[any]any {\n\tvar (\n\t\treflectValue = reflect.ValueOf(slice)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tdata := make(map[any]any)\n\tswitch reflectKind {\n\tcase reflect.Slice, reflect.Array:\n\t\tfor i := 0; i < reflectValue.Len(); i++ {\n\t\t\tif k, ok := ItemValue(reflectValue.Index(i), key); ok {\n\t\t\t\tdata[k] = reflectValue.Index(i).Interface()\n\t\t\t}\n\t\t}\n\t}\n\treturn data\n}\n"
  },
  {
    "path": "util/gutil/gutil_struct.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// StructToSlice converts struct to slice of which all keys and values are its items.\n// Eg: {\"K1\": \"v1\", \"K2\": \"v2\"} => [\"K1\", \"v1\", \"K2\", \"v2\"]\nfunc StructToSlice(data any) []any {\n\tvar (\n\t\treflectValue = reflect.ValueOf(data)\n\t\treflectKind  = reflectValue.Kind()\n\t)\n\tfor reflectKind == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t\treflectKind = reflectValue.Kind()\n\t}\n\tswitch reflectKind {\n\tcase reflect.Struct:\n\t\tarray := make([]any, 0)\n\t\t// Note that, it uses the gconv tag name instead of the attribute name if\n\t\t// the gconv tag is fined in the struct attributes.\n\t\tfor k, v := range gconv.Map(reflectValue) {\n\t\t\tarray = append(array, k)\n\t\t\tarray = append(array, v)\n\t\t}\n\t\treturn array\n\t}\n\treturn nil\n}\n\n// FillStructWithDefault fills  attributes of pointed struct with tag value from `default/d` tag .\n// The parameter `structPtr` should be either type of *struct/[]*struct.\nfunc FillStructWithDefault(structPtr any) error {\n\tvar (\n\t\treflectValue reflect.Value\n\t)\n\tif rv, ok := structPtr.(reflect.Value); ok {\n\t\treflectValue = rv\n\t} else {\n\t\treflectValue = reflect.ValueOf(structPtr)\n\t}\n\tswitch reflectValue.Kind() {\n\tcase reflect.Pointer:\n\t\t// Nothing to do.\n\tcase reflect.Array, reflect.Slice:\n\t\tif reflectValue.Elem().Kind() != reflect.Pointer {\n\t\t\treturn gerror.NewCodef(\n\t\t\t\tgcode.CodeInvalidParameter,\n\t\t\t\t`invalid parameter \"%s\", the element of slice should be type of pointer of struct, but given \"%s\"`,\n\t\t\t\treflectValue.Type().String(), reflectValue.Elem().Type().String(),\n\t\t\t)\n\t\t}\n\tdefault:\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid parameter \"%s\", should be type of pointer of struct`,\n\t\t\treflectValue.Type().String(),\n\t\t)\n\t}\n\tif reflectValue.IsNil() {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`the pointed struct object should not be nil`,\n\t\t)\n\t}\n\tif !reflectValue.Elem().IsValid() {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`the pointed struct object should be valid`,\n\t\t)\n\t}\n\tfields, err := gstructs.Fields(gstructs.FieldsInput{\n\t\tPointer:         reflectValue,\n\t\tRecursiveOption: gstructs.RecursiveOptionEmbedded,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, field := range fields {\n\t\tif field.OriginalKind() == reflect.Struct {\n\t\t\terr := FillStructWithDefault(field.OriginalValue().Addr())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif defaultValue := field.TagDefault(); defaultValue != \"\" {\n\t\t\tif field.IsEmpty() {\n\t\t\t\tfield.Value.Set(reflect.ValueOf(\n\t\t\t\t\tgconv.ConvertWithRefer(defaultValue, field.Value),\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "util/gutil/gutil_try_catch.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n)\n\n// Throw throws out an exception, which can be caught be TryCatch or recover.\nfunc Throw(exception any) {\n\tpanic(exception)\n}\n\n// Try implements try... logistics using internal panic...recover.\n// It returns error if any exception occurs, or else it returns nil.\nfunc Try(ctx context.Context, try func(ctx context.Context)) (err error) {\n\tif try == nil {\n\t\treturn\n\t}\n\tdefer func() {\n\t\tif exception := recover(); exception != nil {\n\t\t\tif v, ok := exception.(error); ok && gerror.HasStack(v) {\n\t\t\t\terr = v\n\t\t\t} else {\n\t\t\t\terr = gerror.NewCodef(gcode.CodeInternalPanic, \"%+v\", exception)\n\t\t\t}\n\t\t}\n\t}()\n\ttry(ctx)\n\treturn\n}\n\n// TryCatch implements `try...catch..`. logistics using internal `panic...recover`.\n// It automatically calls function `catch` if any exception occurs and passes the exception as an error.\n// If `catch` is given nil, it ignores the panic from `try` and no panic will throw to parent goroutine.\n//\n// But, note that, if function `catch` also throws panic, the current goroutine will panic.\nfunc TryCatch(ctx context.Context, try func(ctx context.Context), catch func(ctx context.Context, exception error)) {\n\tif try == nil {\n\t\treturn\n\t}\n\tif exception := Try(ctx, try); exception != nil && catch != nil {\n\t\tcatch(ctx, exception)\n\t}\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_bench_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// go test *.go -bench=\".*\" -benchmem\n\npackage gutil\n\nimport (\n\t\"context\"\n\t\"testing\"\n)\n\nvar (\n\tm1 = map[string]any{\n\t\t\"k1\": \"v1\",\n\t}\n\tm2 = map[string]any{\n\t\t\"k2\": \"v2\",\n\t}\n)\n\nfunc Benchmark_TryCatch(b *testing.B) {\n\tctx := context.TODO()\n\tfor i := 0; i < b.N; i++ {\n\t\tTryCatch(ctx, func(ctx context.Context) {\n\n\t\t}, func(ctx context.Context, err error) {\n\n\t\t})\n\t}\n}\n\nfunc Benchmark_MapMergeCopy(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tMapMergeCopy(m1, m2)\n\t}\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc ExampleSliceInsertBefore() {\n\ts1 := g.Slice{\n\t\t0, 1, 2, 3, 4,\n\t}\n\ts2 := gutil.SliceInsertBefore(s1, 1, 8, 9)\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\n\t// Output:\n\t// [0 1 2 3 4]\n\t// [0 8 9 1 2 3 4]\n}\n\nfunc ExampleSliceInsertAfter() {\n\ts1 := g.Slice{\n\t\t0, 1, 2, 3, 4,\n\t}\n\ts2 := gutil.SliceInsertAfter(s1, 1, 8, 9)\n\tfmt.Println(s1)\n\tfmt.Println(s2)\n\n\t// Output:\n\t// [0 1 2 3 4]\n\t// [0 1 8 9 2 3 4]\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_comparator_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_ComparatorString(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorString(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorString(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorString(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorInt(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorInt(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorInt(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorInt(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorInt8(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorInt8(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorInt8(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorInt8(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorInt16(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorInt16(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorInt16(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorInt16(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorInt32(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorInt32(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorInt32(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorInt32(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorInt64(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorInt64(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorInt64(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorInt64(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorUint(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorUint(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorUint(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorUint(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorUint8(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorUint8(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorUint8(2, 6), 252)\n\t\tt.Assert(gutil.ComparatorUint8(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorUint16(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorUint16(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorUint16(1, 2), 65535)\n\t\tt.Assert(gutil.ComparatorUint16(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorUint32(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorUint32(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorUint32(-1000, 2147483640), 2147482656)\n\t\tt.Assert(gutil.ComparatorUint32(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorUint64(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorUint64(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorUint64(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorUint64(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorFloat32(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorFloat32(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorFloat32(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorFloat32(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorFloat64(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorFloat64(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorFloat64(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorFloat64(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorByte(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorByte(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorByte(1, 2), 255)\n\t\tt.Assert(gutil.ComparatorByte(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorRune(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorRune(1, 1), 0)\n\t\tt.Assert(gutil.ComparatorRune(1, 2), -1)\n\t\tt.Assert(gutil.ComparatorRune(2, 1), 1)\n\t})\n}\n\nfunc Test_ComparatorTime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tj := gutil.ComparatorTime(\"2019-06-14\", \"2019-06-14\")\n\t\tt.Assert(j, 0)\n\n\t\tk := gutil.ComparatorTime(\"2019-06-15\", \"2019-06-14\")\n\t\tt.Assert(k, 1)\n\n\t\tl := gutil.ComparatorTime(\"2019-06-13\", \"2019-06-14\")\n\t\tt.Assert(l, -1)\n\t})\n}\n\nfunc Test_ComparatorFloat32OfFixed(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorFloat32(0.1, 0.1), 0)\n\t\tt.Assert(gutil.ComparatorFloat32(1.1, 2.1), -1)\n\t\tt.Assert(gutil.ComparatorFloat32(2.1, 1.1), 1)\n\t})\n}\n\nfunc Test_ComparatorFloat64OfFixed(t *testing.T) {\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.ComparatorFloat64(0.1, 0.1), 0)\n\t\tt.Assert(gutil.ComparatorFloat64(1.1, 2.1), -1)\n\t\tt.Assert(gutil.ComparatorFloat64(2.1, 1.1), 1)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_copy_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Copy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.Copy(0), 0)\n\t\tt.Assert(gutil.Copy(1), 1)\n\t\tt.Assert(gutil.Copy(\"a\"), \"a\")\n\t\tt.Assert(gutil.Copy(nil), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tsrc := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tdst := gutil.Copy(src)\n\t\tt.Assert(dst, src)\n\n\t\tdst.(g.Map)[\"k3\"] = \"v3\"\n\t\tt.Assert(src, g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t})\n\t\tt.Assert(dst, g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t\t\"k3\": \"v3\",\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_dump_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gtype\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Dump(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"path\" des:\"应用Id\" sum:\"应用Id Summary\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" des:\"资源Id\" sum:\"资源Id Summary\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" des:\"StorageType\"`\n\t\tShards      int32    `des:\"shards 分片数\" sum:\"Shards Summary\"`\n\t\tParams      []string `des:\"默认参数(json 串-ClickHouseParams)\" sum:\"Params Summary\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\" sum:\"CreateResourceReq sum\"`\n\t\tName       string\n\t\tCreatedAt  *gtime.Time\n\t\tSetMap     map[string]*SetSpecInfo\n\t\tSetSlice   []SetSpecInfo\n\t\tHandler    ghttp.HandlerFunc\n\t\tinternal   string\n\t}\n\treq := &CreateResourceReq{\n\t\tCommonReq: CommonReq{\n\t\t\tAppId:      12345678,\n\t\t\tResourceId: \"tdchqy-xxx\",\n\t\t},\n\t\tName:      \"john\",\n\t\tCreatedAt: gtime.Now(),\n\t\tSetMap: map[string]*SetSpecInfo{\n\t\t\t\"test1\": {\n\t\t\t\tStorageType: \"ssd\",\n\t\t\t\tShards:      2,\n\t\t\t\tParams:      []string{\"a\", \"b\", \"c\"},\n\t\t\t},\n\t\t\t\"test2\": {\n\t\t\t\tStorageType: \"hssd\",\n\t\t\t\tShards:      10,\n\t\t\t\tParams:      []string{},\n\t\t\t},\n\t\t},\n\t\tSetSlice: []SetSpecInfo{\n\t\t\t{\n\t\t\t\tStorageType: \"hssd\",\n\t\t\t\tShards:      10,\n\t\t\t\tParams:      []string{\"h\"},\n\t\t\t},\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.Dump(map[int]int{\n\t\t\t100: 100,\n\t\t})\n\t\tgutil.Dump(req)\n\t\tgutil.Dump(true, false)\n\t\tgutil.Dump(make(chan int))\n\t\tgutil.Dump(func() {})\n\t\tgutil.Dump(nil)\n\t\tgutil.Dump(gtype.NewInt(1))\n\t})\n}\n\nfunc Test_Dump_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tm := g.Map{\n\t\t\t\"k1\": g.Map{\n\t\t\t\t\"k2\": \"v2\",\n\t\t\t},\n\t\t}\n\t\tgutil.DumpTo(buffer, m, gutil.DumpOption{})\n\t\tt.Assert(buffer.String(), `{\n    \"k1\": {\n        \"k2\": \"v2\",\n    },\n}`)\n\t})\n}\n\nfunc TestDumpWithType(t *testing.T) {\n\ttype CommonReq struct {\n\t\tAppId      int64  `json:\"appId\" v:\"required\" in:\"path\" des:\"应用Id\" sum:\"应用Id Summary\"`\n\t\tResourceId string `json:\"resourceId\" in:\"query\" des:\"资源Id\" sum:\"资源Id Summary\"`\n\t}\n\ttype SetSpecInfo struct {\n\t\tStorageType string   `v:\"required|in:CLOUD_PREMIUM,CLOUD_SSD,CLOUD_HSSD\" des:\"StorageType\"`\n\t\tShards      int32    `des:\"shards 分片数\" sum:\"Shards Summary\"`\n\t\tParams      []string `des:\"默认参数(json 串-ClickHouseParams)\" sum:\"Params Summary\"`\n\t}\n\ttype CreateResourceReq struct {\n\t\tCommonReq\n\t\tgmeta.Meta `path:\"/CreateResourceReq\" method:\"POST\" tags:\"default\" sum:\"CreateResourceReq sum\"`\n\t\tName       string\n\t\tCreatedAt  *gtime.Time\n\t\tSetMap     map[string]*SetSpecInfo `v:\"required\" des:\"配置Map\"`\n\t\tSetSlice   []SetSpecInfo           `v:\"required\" des:\"配置Slice\"`\n\t\tHandler    ghttp.HandlerFunc\n\t\tinternal   string\n\t}\n\treq := &CreateResourceReq{\n\t\tCommonReq: CommonReq{\n\t\t\tAppId:      12345678,\n\t\t\tResourceId: \"tdchqy-xxx\",\n\t\t},\n\t\tName:      \"john\",\n\t\tCreatedAt: gtime.Now(),\n\t\tSetMap: map[string]*SetSpecInfo{\n\t\t\t\"test1\": {\n\t\t\t\tStorageType: \"ssd\",\n\t\t\t\tShards:      2,\n\t\t\t\tParams:      []string{\"a\", \"b\", \"c\"},\n\t\t\t},\n\t\t\t\"test2\": {\n\t\t\t\tStorageType: \"hssd\",\n\t\t\t\tShards:      10,\n\t\t\t\tParams:      []string{},\n\t\t\t},\n\t\t},\n\t\tSetSlice: []SetSpecInfo{\n\t\t\t{\n\t\t\t\tStorageType: \"hssd\",\n\t\t\t\tShards:      10,\n\t\t\t\tParams:      []string{\"h\"},\n\t\t\t},\n\t\t},\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.DumpWithType(map[int]int{\n\t\t\t100: 100,\n\t\t})\n\t\tgutil.DumpWithType(req)\n\t\tgutil.DumpWithType([][]byte{[]byte(\"hello\")})\n\t})\n}\n\nfunc Test_Dump_Slashes(t *testing.T) {\n\ttype Req struct {\n\t\tContent string\n\t}\n\treq := &Req{\n\t\tContent: `{\"name\":\"john\", \"age\":18}`,\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.Dump(req)\n\t\tgutil.Dump(req.Content)\n\n\t\tgutil.DumpWithType(req)\n\t\tgutil.DumpWithType(req.Content)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1661\nfunc Test_Dump_Issue1661(t *testing.T) {\n\ttype B struct {\n\t\tba int\n\t\tbb string\n\t}\n\ttype A struct {\n\t\taa int\n\t\tab string\n\t\tcc []B\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar q1 []A\n\t\tvar q2 []A\n\t\tq2 = make([]A, 0)\n\t\tq1 = []A{{aa: 1, ab: \"1\", cc: []B{{ba: 1}, {ba: 2}, {ba: 3}}}, {aa: 2, ab: \"2\", cc: []B{{ba: 1}, {ba: 2}, {ba: 3}}}}\n\t\tfor _, q1v := range q1 {\n\t\t\tx := []string{\"11\", \"22\"}\n\t\t\tfor _, iv2 := range x {\n\t\t\t\tls := q1v\n\t\t\t\tfor i := range ls.cc {\n\t\t\t\t\tsj := iv2\n\t\t\t\t\tls.cc[i].bb = sj\n\t\t\t\t}\n\t\t\t\tq2 = append(q2, ls)\n\t\t\t}\n\t\t}\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tgutil.DumpTo(buffer, q2, gutil.DumpOption{})\n\t\tt.Assert(buffer.String(), `[\n    {\n        aa: 1,\n        ab: \"1\",\n        cc: [\n            {\n                ba: 1,\n                bb: \"22\",\n            },\n            {\n                ba: 2,\n                bb: \"22\",\n            },\n            {\n                ba: 3,\n                bb: \"22\",\n            },\n        ],\n    },\n    {\n        aa: 1,\n        ab: \"1\",\n        cc: [\n            {\n                ba: 1,\n                bb: \"22\",\n            },\n            {\n                ba: 2,\n                bb: \"22\",\n            },\n            {\n                ba: 3,\n                bb: \"22\",\n            },\n        ],\n    },\n    {\n        aa: 2,\n        ab: \"2\",\n        cc: [\n            {\n                ba: 1,\n                bb: \"22\",\n            },\n            {\n                ba: 2,\n                bb: \"22\",\n            },\n            {\n                ba: 3,\n                bb: \"22\",\n            },\n        ],\n    },\n    {\n        aa: 2,\n        ab: \"2\",\n        cc: [\n            {\n                ba: 1,\n                bb: \"22\",\n            },\n            {\n                ba: 2,\n                bb: \"22\",\n            },\n            {\n                ba: 3,\n                bb: \"22\",\n            },\n        ],\n    },\n]`)\n\t})\n}\n\nfunc Test_Dump_Cycle_Attribute(t *testing.T) {\n\ttype Abc struct {\n\t\tab int\n\t\tcd *Abc\n\t}\n\tabc := Abc{ab: 3}\n\tabc.cd = &abc\n\tgtest.C(t, func(t *gtest.T) {\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tg.DumpTo(buffer, abc, gutil.DumpOption{})\n\t\tt.Assert(gstr.Contains(buffer.String(), \"cycle\"), true)\n\t})\n}\n\nfunc Test_DumpJson(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar jsonContent = `{\"a\":1,\"b\":2}`\n\t\tgutil.DumpJson(jsonContent)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2902\nfunc Test_Dump_Issue2902_SharedPointer(t *testing.T) {\n\ttype Inner struct {\n\t\tValue int\n\t}\n\ttype Outer struct {\n\t\tA *Inner\n\t\tB *Inner\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Shared pointer (not a cycle) should not be marked as cycle dump.\n\t\tshared := &Inner{Value: 100}\n\t\tdata := Outer{A: shared, B: shared}\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tg.DumpTo(buffer, data, gutil.DumpOption{})\n\t\toutput := buffer.String()\n\t\t// The second field should show the actual value, not \"cycle dump\".\n\t\t// Both fields point to the same object, but it's not a cycle.\n\t\tt.Assert(gstr.Contains(output, \"cycle\"), false)\n\t\tt.Assert(gstr.Count(output, \"Value\"), 2)\n\t\tt.Assert(gstr.Count(output, \"100\"), 2)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2902\nfunc Test_Dump_Issue2902_SameTypeFields(t *testing.T) {\n\ttype User struct {\n\t\tId   int `params:\"id\"`\n\t\tName int `params:\"name\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\t// Fields with same type (e.g., both are int) share the same reflect.Type,\n\t\t// which should not be marked as cycle dump.\n\t\tvar user User\n\t\tfields, _ := gstructs.TagFields(&user, []string{\"p\", \"params\"})\n\t\tbuffer := bytes.NewBuffer(nil)\n\t\tg.DumpTo(buffer, fields, gutil.DumpOption{})\n\t\toutput := buffer.String()\n\t\t// Both fields' Type should show \"int\", not \"cycle dump\".\n\t\tt.Assert(gstr.Contains(output, \"cycle\"), false)\n\t\tt.Assert(gstr.Count(output, `Type:`), 2)\n\t})\n}\n\ntype benchStruct struct {\n\tA int\n\tB string\n\tC *benchStruct\n\tD []int\n\tE map[string]int\n}\n\nfunc createBenchNested(depth int) *benchStruct {\n\tif depth <= 0 {\n\t\treturn nil\n\t}\n\treturn &benchStruct{\n\t\tA: depth,\n\t\tB: \"test\",\n\t\tC: createBenchNested(depth - 1),\n\t\tD: []int{1, 2, 3, 4, 5},\n\t\tE: map[string]int{\"x\": 1, \"y\": 2},\n\t}\n}\n\nvar (\n\tbenchShallow  = &benchStruct{A: 1, B: \"test\", D: []int{1, 2, 3}, E: map[string]int{\"a\": 1}}\n\tbenchNested20 = createBenchNested(20)\n\tbenchDeep50   = createBenchNested(50)\n)\n\nfunc Benchmark_Dump_Shallow(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvar buf bytes.Buffer\n\t\tgutil.DumpTo(&buf, benchShallow, gutil.DumpOption{})\n\t}\n}\n\nfunc Benchmark_Dump_Nested20(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvar buf bytes.Buffer\n\t\tgutil.DumpTo(&buf, benchNested20, gutil.DumpOption{})\n\t}\n}\n\nfunc Benchmark_Dump_Deep50(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tvar buf bytes.Buffer\n\t\tgutil.DumpTo(&buf, benchDeep50, gutil.DumpOption{})\n\t}\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_goroutine_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/garray\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_Go(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t)\n\t\twg.Add(1)\n\t\tgutil.Go(ctx, func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tarray.Append(1)\n\t\t}, nil)\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), 1)\n\t})\n\t// recover\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t)\n\t\twg.Add(1)\n\t\tgutil.Go(ctx, func(ctx context.Context) {\n\t\t\tdefer wg.Done()\n\t\t\tpanic(\"error\")\n\t\t\tarray.Append(1)\n\t\t}, nil)\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\twg    = sync.WaitGroup{}\n\t\t\tarray = garray.NewArray(true)\n\t\t)\n\t\twg.Add(1)\n\t\tgutil.Go(ctx, func(ctx context.Context) {\n\t\t\tpanic(\"error\")\n\t\t}, func(ctx context.Context, exception error) {\n\t\t\tdefer wg.Done()\n\t\t\tarray.Append(exception)\n\t\t})\n\t\twg.Wait()\n\t\tt.Assert(array.Len(), 1)\n\t\tt.Assert(array.At(0), \"error\")\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_is_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_IsEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.IsEmpty(1), false)\n\t})\n}\n\nfunc Test_IsTypeOf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.IsTypeOf(1, 0), true)\n\t\tt.Assert(gutil.IsTypeOf(1.1, 0.1), true)\n\t\tt.Assert(gutil.IsTypeOf(1.1, 1), false)\n\t\tt.Assert(gutil.IsTypeOf(true, false), true)\n\t\tt.Assert(gutil.IsTypeOf(true, 1), false)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype A struct {\n\t\t\tName string\n\t\t}\n\t\ttype B struct {\n\t\t\tName string\n\t\t}\n\t\tt.Assert(gutil.IsTypeOf(1, A{}), false)\n\t\tt.Assert(gutil.IsTypeOf(A{}, B{}), false)\n\t\tt.Assert(gutil.IsTypeOf(A{Name: \"john\"}, &A{Name: \"john\"}), false)\n\t\tt.Assert(gutil.IsTypeOf(A{Name: \"john\"}, A{Name: \"john\"}), true)\n\t\tt.Assert(gutil.IsTypeOf(A{Name: \"john\"}, A{}), true)\n\t\tt.Assert(gutil.IsTypeOf(&A{Name: \"john\"}, &A{}), true)\n\t\tt.Assert(gutil.IsTypeOf(&A{Name: \"john\"}, &B{}), false)\n\t\tt.Assert(gutil.IsTypeOf(A{Name: \"john\"}, B{Name: \"john\"}), false)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_list_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_ListItemValues_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 99},\n\t\t\tg.Map{\"id\": 3, \"score\": 99},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listMap, \"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(&listMap, \"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"score\"), g.Slice{100, 99, 99})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": nil},\n\t\t\tg.Map{\"id\": 3, \"score\": 0},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listMap, \"id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"score\"), g.Slice{100, nil, 0})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{}\n\t\tt.Assert(len(gutil.ListItemValues(listMap, \"id\")), 0)\n\t})\n}\n\nfunc Test_ListItemValues_Map_SubKey(t *testing.T) {\n\ttype Scores struct {\n\t\tMath    int\n\t\tEnglish int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"scores\": Scores{100, 60}},\n\t\t\tg.Map{\"id\": 2, \"scores\": Scores{0, 100}},\n\t\t\tg.Map{\"id\": 3, \"scores\": Scores{59, 99}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"Math\"), g.Slice{100, 0, 59})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"English\"), g.Slice{60, 100, 99})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"PE\"), g.Slice{})\n\t})\n}\n\nfunc Test_ListItemValues_Map_Array_SubKey(t *testing.T) {\n\ttype Scores struct {\n\t\tMath    int\n\t\tEnglish int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"scores\": []Scores{{1, 2}, {3, 4}}},\n\t\t\tg.Map{\"id\": 2, \"scores\": []Scores{{5, 6}, {7, 8}}},\n\t\t\tg.Map{\"id\": 3, \"scores\": []Scores{{9, 10}, {11, 12}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"Math\"), g.Slice{1, 3, 5, 7, 9, 11})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"English\"), g.Slice{2, 4, 6, 8, 10, 12})\n\t\tt.Assert(gutil.ListItemValues(listMap, \"scores\", \"PE\"), g.Slice{})\n\t})\n}\n\nfunc Test_ListItemValues_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tT{1, 100},\n\t\t\tT{2, 99},\n\t\t\tT{3, 0},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Score\"), g.Slice{100, 99, 0})\n\t})\n\t// Pointer items.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\t&T{1, 100},\n\t\t\t&T{2, 99},\n\t\t\t&T{3, 0},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Score\"), g.Slice{100, 99, 0})\n\t})\n\t// Nil element value.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tId    int\n\t\t\tScore any\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tT{1, 100},\n\t\t\tT{2, nil},\n\t\t\tT{3, 0},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Id\"), g.Slice{1, 2, 3})\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Score\"), g.Slice{100, nil, 0})\n\t})\n}\n\nfunc Test_ListItemValues_Struct_SubKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\ttype Class struct {\n\t\t\tTotal    int\n\t\t\tStudents []Student\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tClass{2, []Student{{1, 1}, {2, 2}}},\n\t\t\tClass{3, []Student{{3, 3}, {4, 4}, {5, 5}}},\n\t\t\tClass{1, []Student{{6, 6}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Total\"), g.Slice{2, 3, 1})\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Students\"), `[[{\"Id\":1,\"Score\":1},{\"Id\":2,\"Score\":2}],[{\"Id\":3,\"Score\":3},{\"Id\":4,\"Score\":4},{\"Id\":5,\"Score\":5}],[{\"Id\":6,\"Score\":6}]]`)\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Students\", \"Id\"), g.Slice{1, 2, 3, 4, 5, 6})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\ttype Class struct {\n\t\t\tTotal    int\n\t\t\tStudents []*Student\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\t&Class{2, []*Student{{1, 1}, {2, 2}}},\n\t\t\t&Class{3, []*Student{{3, 3}, {4, 4}, {5, 5}}},\n\t\t\t&Class{1, []*Student{{6, 6}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Total\"), g.Slice{2, 3, 1})\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Students\"), `[[{\"Id\":1,\"Score\":1},{\"Id\":2,\"Score\":2}],[{\"Id\":3,\"Score\":3},{\"Id\":4,\"Score\":4},{\"Id\":5,\"Score\":5}],[{\"Id\":6,\"Score\":6}]]`)\n\t\tt.Assert(gutil.ListItemValues(listStruct, \"Students\", \"Id\"), g.Slice{1, 2, 3, 4, 5, 6})\n\t})\n}\n\nfunc Test_ListItemValuesUnique(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 100},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 100},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"score\"), g.Slice{100})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 100},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 99},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"score\"), g.Slice{100, 99})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"score\": 100},\n\t\t\tg.Map{\"id\": 2, \"score\": 100},\n\t\t\tg.Map{\"id\": 3, \"score\": 0},\n\t\t\tg.Map{\"id\": 4, \"score\": 100},\n\t\t\tg.Map{\"id\": 5, \"score\": 99},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"id\"), g.Slice{1, 2, 3, 4, 5})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"score\"), g.Slice{100, 0, 99})\n\t})\n}\n\nfunc Test_ListItemValuesUnique_Struct_SubKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\ttype Class struct {\n\t\t\tTotal    int\n\t\t\tStudents []Student\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\tClass{2, []Student{{1, 1}, {1, 2}}},\n\t\t\tClass{3, []Student{{2, 3}, {2, 4}, {5, 5}}},\n\t\t\tClass{1, []Student{{6, 6}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listStruct, \"Total\"), g.Slice{2, 3, 1})\n\t\tt.Assert(gutil.ListItemValuesUnique(listStruct, \"Students\", \"Id\"), g.Slice{1, 2, 5, 6})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tId    int\n\t\t\tScore float64\n\t\t}\n\t\ttype Class struct {\n\t\t\tTotal    int\n\t\t\tStudents []*Student\n\t\t}\n\t\tlistStruct := g.Slice{\n\t\t\t&Class{2, []*Student{{1, 1}, {1, 2}}},\n\t\t\t&Class{3, []*Student{{2, 3}, {2, 4}, {5, 5}}},\n\t\t\t&Class{1, []*Student{{6, 6}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listStruct, \"Total\"), g.Slice{2, 3, 1})\n\t\tt.Assert(gutil.ListItemValuesUnique(listStruct, \"Students\", \"Id\"), g.Slice{1, 2, 5, 6})\n\t})\n}\n\nfunc Test_ListItemValuesUnique_Map_Array_SubKey(t *testing.T) {\n\ttype Scores struct {\n\t\tMath    int\n\t\tEnglish int\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": 1, \"scores\": []Scores{{1, 2}, {1, 2}}},\n\t\t\tg.Map{\"id\": 2, \"scores\": []Scores{{5, 8}, {5, 8}}},\n\t\t\tg.Map{\"id\": 3, \"scores\": []Scores{{9, 10}, {11, 12}}},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"scores\", \"Math\"), g.Slice{1, 5, 9, 11})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"scores\", \"English\"), g.Slice{2, 8, 10, 12})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"scores\", \"PE\"), g.Slice{})\n\t})\n}\n\nfunc Test_ListItemValuesUnique_Binary_ID(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := g.List{\n\t\t\tg.Map{\"id\": []byte{1}, \"score\": 100},\n\t\t\tg.Map{\"id\": []byte{2}, \"score\": 100},\n\t\t\tg.Map{\"id\": []byte{3}, \"score\": 100},\n\t\t\tg.Map{\"id\": []byte{4}, \"score\": 100},\n\t\t\tg.Map{\"id\": []byte{4}, \"score\": 100},\n\t\t}\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"id\"), g.Slice{[]byte{1}, []byte{2}, []byte{3}, []byte{4}})\n\t\tt.Assert(gutil.ListItemValuesUnique(listMap, \"score\"), g.Slice{100})\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_map_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_MapCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tm2 := gutil.MapCopy(m1)\n\t\tm2[\"k2\"] = \"v2\"\n\n\t\tt.Assert(m1[\"k1\"], \"v1\")\n\t\tt.Assert(m1[\"k2\"], nil)\n\t\tt.Assert(m2[\"k1\"], \"v1\")\n\t\tt.Assert(m2[\"k2\"], \"v2\")\n\t})\n}\n\nfunc Test_MapContains(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tt.Assert(gutil.MapContains(m1, \"k1\"), true)\n\t\tt.Assert(gutil.MapContains(m1, \"K1\"), false)\n\t\tt.Assert(gutil.MapContains(m1, \"k2\"), false)\n\t\tm2 := g.Map{}\n\t\tt.Assert(gutil.MapContains(m2, \"k1\"), false)\n\t})\n}\n\nfunc Test_MapDelete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tgutil.MapDelete(m1, \"k1\")\n\t\tgutil.MapDelete(m1, \"K1\")\n\t\tm2 := g.Map{}\n\t\tgutil.MapDelete(m2, \"k1\")\n\t})\n}\n\nfunc Test_MapMerge(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tm2 := g.Map{\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm3 := g.Map{\n\t\t\t\"k3\": \"v3\",\n\t\t}\n\t\tgutil.MapMerge(m1, m2, m3, nil)\n\t\tt.Assert(m1[\"k1\"], \"v1\")\n\t\tt.Assert(m1[\"k2\"], \"v2\")\n\t\tt.Assert(m1[\"k3\"], \"v3\")\n\t\tt.Assert(m2[\"k1\"], nil)\n\t\tt.Assert(m3[\"k1\"], nil)\n\t\tgutil.MapMerge(nil)\n\t})\n}\n\nfunc Test_MapMergeCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm1 := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t}\n\t\tm2 := g.Map{\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\tm3 := g.Map{\n\t\t\t\"k3\": \"v3\",\n\t\t}\n\t\tm := gutil.MapMergeCopy(m1, m2, m3, nil)\n\t\tt.Assert(m[\"k1\"], \"v1\")\n\t\tt.Assert(m[\"k2\"], \"v2\")\n\t\tt.Assert(m[\"k3\"], \"v3\")\n\t\tt.Assert(m1[\"k1\"], \"v1\")\n\t\tt.Assert(m1[\"k2\"], nil)\n\t\tt.Assert(m2[\"k1\"], nil)\n\t\tt.Assert(m3[\"k1\"], nil)\n\t})\n}\n\nfunc Test_MapPossibleItemByKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"name\":     \"guo\",\n\t\t\t\"NickName\": \"john\",\n\t\t}\n\t\tk, v := gutil.MapPossibleItemByKey(m, \"NAME\")\n\t\tt.Assert(k, \"name\")\n\t\tt.Assert(v, \"guo\")\n\n\t\tk, v = gutil.MapPossibleItemByKey(m, \"nick name\")\n\t\tt.Assert(k, \"NickName\")\n\t\tt.Assert(v, \"john\")\n\n\t\tk, v = gutil.MapPossibleItemByKey(m, \"none\")\n\t\tt.Assert(k, \"\")\n\t\tt.Assert(v, nil)\n\t})\n}\n\nfunc Test_MapContainsPossibleKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"name\":     \"guo\",\n\t\t\t\"NickName\": \"john\",\n\t\t}\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"name\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"NAME\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"nickname\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"nick name\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"nick_name\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"nick-name\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"nick.name\"), true)\n\t\tt.Assert(gutil.MapContainsPossibleKey(m, \"none\"), false)\n\t})\n}\n\nfunc Test_MapOmitEmpty(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"k1\": \"john\",\n\t\t\t\"e1\": \"\",\n\t\t\t\"e2\": 0,\n\t\t\t\"e3\": nil,\n\t\t\t\"k2\": \"smith\",\n\t\t}\n\t\tgutil.MapOmitEmpty(m)\n\t\tt.Assert(len(m), 2)\n\t\tt.AssertNE(m[\"k1\"], nil)\n\t\tt.AssertNE(m[\"k2\"], nil)\n\t\tm1 := g.Map{}\n\t\tgutil.MapOmitEmpty(m1)\n\t\tt.Assert(len(m1), 0)\n\t})\n}\n\nfunc Test_MapToSlice(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.Map{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\ts := gutil.MapToSlice(m)\n\t\tt.Assert(len(s), 4)\n\t\tt.AssertIN(s[0], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[1], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[2], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[3], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\ts1 := gutil.MapToSlice(&m)\n\t\tt.Assert(len(s1), 4)\n\t\tt.AssertIN(s1[0], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s1[1], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s1[2], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s1[3], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrStr{\n\t\t\t\"k1\": \"v1\",\n\t\t\t\"k2\": \"v2\",\n\t\t}\n\t\ts := gutil.MapToSlice(m)\n\t\tt.Assert(len(s), 4)\n\t\tt.AssertIN(s[0], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[1], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[2], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t\tt.AssertIN(s[3], g.Slice{\"k1\", \"k2\", \"v1\", \"v2\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrStr{}\n\t\ts := gutil.MapToSlice(m)\n\t\tt.Assert(len(s), 0)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gutil.MapToSlice(1)\n\t\tt.Assert(s, nil)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_reflect_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_OriginValueAndKind(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := gutil.OriginValueAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.String)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := gutil.OriginValueAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := gutil.OriginValueAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.Slice)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := gutil.OriginValueAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n}\n\nfunc Test_OriginTypeAndKind(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := gutil.OriginTypeAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.String)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s = \"s\"\n\t\tout := gutil.OriginTypeAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.String)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := gutil.OriginTypeAndKind(s)\n\t\tt.Assert(out.InputKind, reflect.Slice)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar s []int\n\t\tout := gutil.OriginTypeAndKind(&s)\n\t\tt.Assert(out.InputKind, reflect.Pointer)\n\t\tt.Assert(out.OriginKind, reflect.Slice)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_slice_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_SliceCopy(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Slice{\n\t\t\t\"K1\", \"v1\", \"K2\", \"v2\",\n\t\t}\n\t\ts1 := gutil.SliceCopy(s)\n\t\tt.Assert(s, s1)\n\t})\n}\n\nfunc Test_SliceDelete(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Slice{\n\t\t\t\"K1\", \"v1\", \"K2\", \"v2\",\n\t\t}\n\t\tt.Assert(gutil.SliceDelete(s, 0), g.Slice{\n\t\t\t\"v1\", \"K2\", \"v2\",\n\t\t})\n\t\tt.Assert(gutil.SliceDelete(s, 5), s)\n\t})\n}\n\nfunc Test_SliceToMap(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Slice{\n\t\t\t\"K1\", \"v1\", \"K2\", \"v2\",\n\t\t}\n\t\tm := gutil.SliceToMap(s)\n\t\tt.Assert(len(m), 2)\n\t\tt.Assert(m, g.Map{\n\t\t\t\"K1\": \"v1\",\n\t\t\t\"K2\": \"v2\",\n\t\t})\n\n\t\tm1 := gutil.SliceToMap(&s)\n\t\tt.Assert(len(m1), 2)\n\t\tt.Assert(m1, g.Map{\n\t\t\t\"K1\": \"v1\",\n\t\t\t\"K2\": \"v2\",\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := g.Slice{\n\t\t\t\"K1\", \"v1\", \"K2\",\n\t\t}\n\t\tm := gutil.SliceToMap(s)\n\t\tt.Assert(len(m), 0)\n\t\tt.Assert(m, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gutil.SliceToMap(1)\n\t\tt.Assert(len(m), 0)\n\t\tt.Assert(m, nil)\n\t})\n}\n\nfunc Test_SliceToMapWithColumnAsKey(t *testing.T) {\n\tm1 := g.Map{\"K1\": \"v1\", \"K2\": 1}\n\tm2 := g.Map{\"K1\": \"v2\", \"K2\": 2}\n\ts := g.Slice{m1, m2}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gutil.SliceToMapWithColumnAsKey(s, \"K1\")\n\t\tt.Assert(m, g.MapAnyAny{\n\t\t\t\"v1\": m1,\n\t\t\t\"v2\": m2,\n\t\t})\n\n\t\tn := gutil.SliceToMapWithColumnAsKey(&s, \"K1\")\n\t\tt.Assert(n, g.MapAnyAny{\n\t\t\t\"v1\": m1,\n\t\t\t\"v2\": m2,\n\t\t})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := gutil.SliceToMapWithColumnAsKey(s, \"K2\")\n\t\tt.Assert(m, g.MapAnyAny{\n\t\t\t1: m1,\n\t\t\t2: m2,\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_struct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc Test_StructToSlice(t *testing.T) {\n\ttype A struct {\n\t\tK1 int\n\t\tK2 string\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\ta := &A{\n\t\t\tK1: 1,\n\t\t\tK2: \"v2\",\n\t\t}\n\t\ts := gutil.StructToSlice(a)\n\t\tt.Assert(len(s), 4)\n\t\tt.AssertIN(s[0], g.Slice{\"K1\", \"K2\", 1, \"v2\"})\n\t\tt.AssertIN(s[1], g.Slice{\"K1\", \"K2\", 1, \"v2\"})\n\t\tt.AssertIN(s[2], g.Slice{\"K1\", \"K2\", 1, \"v2\"})\n\t\tt.AssertIN(s[3], g.Slice{\"K1\", \"K2\", 1, \"v2\"})\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := gutil.StructToSlice(1)\n\t\tt.Assert(s, nil)\n\t})\n}\n\nfunc Test_FillStructWithDefault(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype myInt int\n\t\ttype Inner1 struct {\n\t\t\tI1V1 int\n\t\t\tI1V2 bool `d:\"true\"`\n\t\t}\n\t\ttype Inner2 struct {\n\t\t\tI2V1 float64 `d:\"1.01\"`\n\t\t}\n\t\ttype Inner3 struct {\n\t\t\tInner1 Inner1\n\t\t\tI3V1   myInt `d:\"1\"`\n\t\t}\n\t\ttype Inner4 struct {\n\t\t}\n\t\ttype Outer struct {\n\t\t\tO1 int     `d:\"1.01\"`\n\t\t\tO2 string  `d:\"1.01\"`\n\t\t\tO3 float32 `d:\"1.01\"`\n\t\t\t*Inner1\n\t\t\tO4 bool `d:\"true\"`\n\t\t\tInner2\n\t\t\tInner3 Inner3\n\t\t\tInner4 *Inner4\n\t\t}\n\n\t\touter := Outer{}\n\t\terr := gutil.FillStructWithDefault(&outer)\n\t\tt.AssertNil(err)\n\n\t\tt.Assert(outer.O1, 1)\n\t\tt.Assert(outer.O2, `1.01`)\n\t\tt.Assert(outer.O3, `1.01`)\n\t\tt.Assert(outer.O4, true)\n\t\tt.Assert(outer.Inner1, nil)\n\t\tt.Assert(outer.Inner2.I2V1, `1.01`)\n\t\tt.Assert(outer.Inner3.I3V1, 1)\n\t\tt.Assert(outer.Inner3.Inner1.I1V1, 0)\n\t\tt.Assert(outer.Inner3.Inner1.I1V2, true)\n\t\tt.Assert(outer.Inner4, nil)\n\t})\n}\n"
  },
  {
    "path": "util/gutil/gutil_z_unit_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gutil_test\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nvar (\n\tctx = context.TODO()\n)\n\nfunc Test_Try(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := `gutil Try test`\n\t\tt.Assert(gutil.Try(ctx, func(ctx context.Context) {\n\t\t\tpanic(s)\n\t\t}), s)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := `gutil Try test`\n\t\tt.Assert(gutil.Try(ctx, func(ctx context.Context) {\n\t\t\tpanic(gerror.New(s))\n\t\t}), s)\n\t})\n}\n\nfunc Test_TryCatch(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\tpanic(\"gutil TryCatch test\")\n\t\t}, nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\tpanic(\"gutil TryCatch test\")\n\n\t\t}, func(ctx context.Context, err error) {\n\t\t\tt.Assert(err, \"gutil TryCatch test\")\n\t\t})\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tgutil.TryCatch(ctx, func(ctx context.Context) {\n\t\t\tpanic(gerror.New(\"gutil TryCatch test\"))\n\n\t\t}, func(ctx context.Context, err error) {\n\t\t\tt.Assert(err, \"gutil TryCatch test\")\n\t\t})\n\t})\n}\n\nfunc Test_Throw(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdefer func() {\n\t\t\tt.Assert(recover(), \"gutil Throw test\")\n\t\t}()\n\n\t\tgutil.Throw(\"gutil Throw test\")\n\t})\n}\n\nfunc Test_Keys(t *testing.T) {\n\t// not support int\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar val int = 1\n\t\tkeys := gutil.Keys(reflect.ValueOf(val))\n\t\tt.AssertEQ(len(keys), 0)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkeys := gutil.Keys(map[int]int{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t})\n\t\tt.AssertIN(\"1\", keys)\n\t\tt.AssertIN(\"2\", keys)\n\n\t\tstrKeys := gutil.Keys(map[string]any{\n\t\t\t\"key1\": 1,\n\t\t\t\"key2\": 2,\n\t\t})\n\t\tt.AssertIN(\"key1\", strKeys)\n\t\tt.AssertIN(\"key2\", strKeys)\n\t})\n\t// *map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkeys := gutil.Keys(&map[int]int{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t})\n\t\tt.AssertIN(\"1\", keys)\n\t\tt.AssertIN(\"2\", keys)\n\t})\n\t// *struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tA string\n\t\t\tB int\n\t\t}\n\t\tkeys := gutil.Keys(new(T))\n\t\tt.Assert(keys, g.SliceStr{\"A\", \"B\"})\n\t})\n\t// *struct nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tA string\n\t\t\tB int\n\t\t}\n\t\tvar pointer *T\n\t\tkeys := gutil.Keys(pointer)\n\t\tt.Assert(keys, g.SliceStr{\"A\", \"B\"})\n\t})\n\t// **struct nil\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tA string\n\t\t\tB int\n\t\t}\n\t\tvar pointer *T\n\t\tkeys := gutil.Keys(&pointer)\n\t\tt.Assert(keys, g.SliceStr{\"A\", \"B\"})\n\t})\n}\n\nfunc Test_Values(t *testing.T) {\n\t// not support int\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar val int = 1\n\t\tkeys := gutil.Values(reflect.ValueOf(val))\n\t\tt.AssertEQ(len(keys), 0)\n\t})\n\t// map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvalues := gutil.Values(map[int]int{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t})\n\t\tt.AssertIN(10, values)\n\t\tt.AssertIN(20, values)\n\n\t\tvalues = gutil.Values(map[string]any{\n\t\t\t\"key1\": 10,\n\t\t\t\"key2\": 20,\n\t\t})\n\t\tt.AssertIN(10, values)\n\t\tt.AssertIN(20, values)\n\t})\n\t// *map\n\tgtest.C(t, func(t *gtest.T) {\n\t\tkeys := gutil.Values(&map[int]int{\n\t\t\t1: 10,\n\t\t\t2: 20,\n\t\t})\n\t\tt.AssertIN(10, keys)\n\t\tt.AssertIN(20, keys)\n\t})\n\t// struct\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tA string\n\t\t\tB int\n\t\t}\n\t\tkeys := gutil.Values(T{\n\t\t\tA: \"1\",\n\t\t\tB: 2,\n\t\t})\n\t\tt.Assert(keys, g.Slice{\"1\", 2})\n\t})\n}\n\nfunc TestListToMapByKey(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tlistMap := []map[string]any{\n\t\t\t{\"key1\": 1, \"key2\": 2},\n\t\t\t{\"key3\": 3, \"key4\": 4},\n\t\t}\n\t\tt.Assert(gutil.ListToMapByKey(listMap, \"key1\"), \"{\\\"1\\\":{\\\"key1\\\":1,\\\"key2\\\":2}}\")\n\t})\n}\n\nfunc Test_GetOrDefaultStr(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.GetOrDefaultStr(\"a\", \"b\"), \"b\")\n\t\tt.Assert(gutil.GetOrDefaultStr(\"a\", \"b\", \"c\"), \"b\")\n\t\tt.Assert(gutil.GetOrDefaultStr(\"a\"), \"a\")\n\t})\n}\n\nfunc Test_GetOrDefaultAny(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(gutil.GetOrDefaultAny(\"a\", \"b\"), \"b\")\n\t\tt.Assert(gutil.GetOrDefaultAny(\"a\", \"b\", \"c\"), \"b\")\n\t\tt.Assert(gutil.GetOrDefaultAny(\"a\"), \"a\")\n\t\tt.Assert(gutil.GetOrDefaultAny(\"a\", nil), \"a\")\n\t\tt.Assert(gutil.GetOrDefaultAny(\"a\", \"\"), \"\")\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package gvalid implements powerful and useful data/form validation functionality.\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// CustomMsg is the custom error message type,\n// like: map[field] => string|map[rule]string\ntype CustomMsg = map[string]any\n\n// fieldRule defined the alias name and rule string for specified field.\ntype fieldRule struct {\n\tName      string       // Alias name for the field.\n\tRule      string       // Rule string like: \"max:6\"\n\tIsMeta    bool         // Is this rule is from gmeta.Meta, which marks it as whole struct rule.\n\tFieldKind reflect.Kind // Original kind of struct field, which is used for parameter type checks.\n\tFieldType reflect.Type // Type of struct field, which is used for parameter type checks.\n}\n\n// iNoValidation is an interface that marks current struct not validated by package `gvalid`.\ntype iNoValidation interface {\n\tNoValidation()\n}\n\nconst (\n\tsingleRulePattern         = `^([\\w-]+):{0,1}(.*)` // regular expression pattern for single validation rule.\n\tinternalRulesErrRuleName  = \"InvalidRules\"        // rule name for internal invalid rules validation error.\n\tinternalParamsErrRuleName = \"InvalidParams\"       // rule name for internal invalid params validation error.\n\tinternalObjectErrRuleName = \"InvalidObject\"       // rule name for internal invalid object validation error.\n\tinternalErrorMapKey       = \"__InternalError__\"   // error map key for internal errors.\n\tinternalDefaultRuleName   = \"__default__\"         // default rule name for i18n error message format if no i18n message found for specified error rule.\n\truleMessagePrefixForI18n  = \"gf.gvalid.rule.\"     // prefix string for each rule configuration in i18n content.\n\tnoValidationTagName       = gtag.NoValidation     // no validation tag name for struct attribute.\n\truleNameRegex             = \"regex\"               // the name for rule \"regex\"\n\truleNameNotRegex          = \"not-regex\"           // the name for rule \"not-regex\"\n\truleNameForeach           = \"foreach\"             // the name for rule \"foreach\"\n\truleNameBail              = \"bail\"                // the name for rule \"bail\"\n\truleNameCi                = \"ci\"                  // the name for rule \"ci\"\n\temptyJsonArrayStr         = \"[]\"                  // Empty json string for array type.\n\temptyJsonObjectStr        = \"{}\"                  // Empty json string for object type.\n\trequiredRulesPrefix       = \"required\"            // requiredRulesPrefix specifies the rule prefix that must be validated even the value is empty (nil or empty).\n)\n\nvar (\n\t// defaultErrorMessages is the default error messages.\n\t// Note that these messages are synchronized from ./i18n/en/validation.toml .\n\tdefaultErrorMessages = map[string]string{\n\t\tinternalDefaultRuleName: \"The {field} value `{value}` is invalid\",\n\t}\n\n\t// structTagPriority specifies the validation tag priority array.\n\tstructTagPriority = []string{gtag.Valid, gtag.ValidShort}\n\n\t// aliasNameTagPriority specifies the alias tag priority array.\n\taliasNameTagPriority = []string{gtag.Param, gtag.ParamShort}\n\n\t// all internal error keys.\n\tinternalErrKeyMap = map[string]string{\n\t\tinternalRulesErrRuleName:  internalRulesErrRuleName,\n\t\tinternalParamsErrRuleName: internalParamsErrRuleName,\n\t\tinternalObjectErrRuleName: internalObjectErrRuleName,\n\t}\n\t// regular expression object for single rule\n\t// which is compiled just once and of repeatable usage.\n\truleRegex = regexp.MustCompile(singleRulePattern)\n\n\t// decorativeRuleMap defines all rules that are just marked rules which have neither functional meaning\n\t// nor error messages.\n\tdecorativeRuleMap = map[string]bool{\n\t\truleNameForeach: true,\n\t\truleNameBail:    true,\n\t\truleNameCi:      true,\n\t}\n)\n\n// ParseTagValue parses one sequence tag to field, rule and error message.\n// The sequence tag is like: [alias@]rule[...#msg...]\nfunc ParseTagValue(tag string) (field, rule, msg string) {\n\t// Complete sequence tag.\n\t// Example: name@required|length:2,20|password3|same:password1#||Password strength is insufficient | Passwords are not match\n\tmatch, _ := gregex.MatchString(`\\s*((\\w+)\\s*@){0,1}\\s*([^#]+)\\s*(#\\s*(.*)){0,1}\\s*`, tag)\n\tif len(match) > 5 {\n\t\tmsg = strings.TrimSpace(match[5])\n\t\trule = strings.TrimSpace(match[3])\n\t\tfield = strings.TrimSpace(match[2])\n\t} else {\n\t\tintlog.Errorf(context.TODO(), `invalid validation tag value: %s`, tag)\n\t}\n\treturn\n}\n\n// GetTags returns the validation tags.\nfunc GetTags() []string {\n\treturn structTagPriority\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_error.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gset\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// Error is the validation error for validation result.\ntype Error interface {\n\tCode() gcode.Code\n\tCurrent() error\n\tError() string\n\tFirstItem() (key string, messages map[string]error)\n\tFirstRule() (rule string, err error)\n\tFirstError() (err error)\n\tItems() (items []map[string]map[string]error)\n\tMap() map[string]error\n\tMaps() map[string]map[string]error\n\tString() string\n\tStrings() (errs []string)\n}\n\n// validationError is the validation error for validation result.\ntype validationError struct {\n\tcode      gcode.Code                  // Error code.\n\trules     []fieldRule                 // Rules by sequence, which is used for keeping error sequence only.\n\terrors    map[string]map[string]error // Error map:map[field]map[rule]message\n\tfirstKey  string                      // The first error rule key(empty in default).\n\tfirstItem map[string]error            // The first error rule value(nil in default).\n}\n\n// newValidationError creates and returns a validation error.\nfunc newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap map[string]map[string]error) *validationError {\n\tfor field, ruleErrorMap := range fieldRuleErrorMap {\n\t\tfor rule, err := range ruleErrorMap {\n\t\t\tif !gerror.HasStack(err) {\n\t\t\t\truleErrorMap[rule] = gerror.NewWithOption(gerror.Option{\n\t\t\t\t\tStack: false,\n\t\t\t\t\tText:  gstr.Trim(err.Error()),\n\t\t\t\t\tCode:  code,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tfieldRuleErrorMap[field] = ruleErrorMap\n\t}\n\t// Filter repeated sequence rules.\n\tvar ruleNameSet = gset.NewStrSet()\n\tfor i := 0; i < len(rules); {\n\t\tif !ruleNameSet.AddIfNotExist(rules[i].Name) {\n\t\t\t// Delete repeated rule.\n\t\t\trules = append(rules[:i], rules[i+1:]...)\n\t\t\tcontinue\n\t\t}\n\t\ti++\n\t}\n\treturn &validationError{\n\t\tcode:   code,\n\t\trules:  rules,\n\t\terrors: fieldRuleErrorMap,\n\t}\n}\n\n// newValidationErrorByStr creates and returns a validation error by string.\nfunc newValidationErrorByStr(key string, err error) *validationError {\n\treturn newValidationError(\n\t\tgcode.CodeInternalError,\n\t\tnil,\n\t\tmap[string]map[string]error{\n\t\t\tinternalErrorMapKey: {\n\t\t\t\tkey: err,\n\t\t\t},\n\t\t},\n\t)\n}\n\n// Code returns the error code of current validation error.\nfunc (e *validationError) Code() gcode.Code {\n\tif e == nil {\n\t\treturn gcode.CodeNil\n\t}\n\treturn e.code\n}\n\n// Map returns the first error message as map.\nfunc (e *validationError) Map() map[string]error {\n\tif e == nil {\n\t\treturn map[string]error{}\n\t}\n\t_, m := e.FirstItem()\n\treturn m\n}\n\n// Maps returns all error messages as map.\nfunc (e *validationError) Maps() map[string]map[string]error {\n\tif e == nil {\n\t\treturn nil\n\t}\n\treturn e.errors\n}\n\n// Items retrieves and returns error items array in sequence if possible,\n// or else it returns error items with no sequence .\nfunc (e *validationError) Items() (items []map[string]map[string]error) {\n\tif e == nil {\n\t\treturn []map[string]map[string]error{}\n\t}\n\titems = make([]map[string]map[string]error, 0)\n\t// By sequence.\n\tif len(e.rules) > 0 {\n\t\tfor _, v := range e.rules {\n\t\t\tif errorItemMap, ok := e.errors[v.Name]; ok {\n\t\t\t\titems = append(items, map[string]map[string]error{\n\t\t\t\t\tv.Name: errorItemMap,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\treturn items\n\t}\n\t// No sequence.\n\tfor name, errorRuleMap := range e.errors {\n\t\titems = append(items, map[string]map[string]error{\n\t\t\tname: errorRuleMap,\n\t\t})\n\t}\n\treturn\n}\n\n// FirstItem returns the field name and error messages for the first validation rule error.\nfunc (e *validationError) FirstItem() (key string, messages map[string]error) {\n\tif e == nil {\n\t\treturn \"\", map[string]error{}\n\t}\n\tif e.firstItem != nil {\n\t\treturn e.firstKey, e.firstItem\n\t}\n\t// By sequence.\n\tif len(e.rules) > 0 {\n\t\tfor _, v := range e.rules {\n\t\t\tif errorItemMap, ok := e.errors[v.Name]; ok {\n\t\t\t\te.firstKey = v.Name\n\t\t\t\te.firstItem = errorItemMap\n\t\t\t\treturn v.Name, errorItemMap\n\t\t\t}\n\t\t}\n\t}\n\t// No sequence.\n\tfor k, m := range e.errors {\n\t\te.firstKey = k\n\t\te.firstItem = m\n\t\treturn k, m\n\t}\n\treturn \"\", nil\n}\n\n// FirstRule returns the first error rule and message string.\nfunc (e *validationError) FirstRule() (rule string, err error) {\n\tif e == nil {\n\t\treturn \"\", nil\n\t}\n\t// By sequence.\n\tif len(e.rules) > 0 {\n\t\tfor _, v := range e.rules {\n\t\t\tif errorItemMap, ok := e.errors[v.Name]; ok {\n\t\t\t\tfor _, ruleItem := range strings.Split(v.Rule, \"|\") {\n\t\t\t\t\tarray := strings.Split(ruleItem, \":\")\n\t\t\t\t\truleItem = strings.TrimSpace(array[0])\n\t\t\t\t\tif err, ok = errorItemMap[ruleItem]; ok {\n\t\t\t\t\t\treturn ruleItem, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// No sequence.\n\tfor _, errorItemMap := range e.errors {\n\t\tfor k, v := range errorItemMap {\n\t\t\treturn k, v\n\t\t}\n\t}\n\treturn \"\", nil\n}\n\n// FirstError returns the first error message as string.\n// Note that the returned message might be different if it has no sequence.\nfunc (e *validationError) FirstError() (err error) {\n\tif e == nil {\n\t\treturn nil\n\t}\n\t_, err = e.FirstRule()\n\treturn\n}\n\n// Current is alis of FirstError, which implements interface gerror.iCurrent.\nfunc (e *validationError) Current() error {\n\treturn e.FirstError()\n}\n\n// String returns all error messages as string, multiple error messages joined using char ';'.\nfunc (e *validationError) String() string {\n\tif e == nil {\n\t\treturn \"\"\n\t}\n\treturn strings.Join(e.Strings(), \"; \")\n}\n\n// Error implements interface of error.Error.\nfunc (e *validationError) Error() string {\n\tif e == nil {\n\t\treturn \"\"\n\t}\n\treturn e.String()\n}\n\n// Strings returns all error messages as string array.\nfunc (e *validationError) Strings() (errs []string) {\n\tif e == nil {\n\t\treturn []string{}\n\t}\n\terrs = make([]string, 0)\n\t// By sequence.\n\tif len(e.rules) > 0 {\n\t\tfor _, v := range e.rules {\n\t\t\tif errorItemMap, ok := e.errors[v.Name]; ok {\n\t\t\t\t// validation error checks.\n\t\t\t\tfor _, ruleItem := range strings.Split(v.Rule, \"|\") {\n\t\t\t\t\truleItem = strings.TrimSpace(strings.Split(ruleItem, \":\")[0])\n\t\t\t\t\tif err, ok := errorItemMap[ruleItem]; ok {\n\t\t\t\t\t\terrs = append(errs, err.Error())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// internal error checks.\n\t\t\t\tfor k := range internalErrKeyMap {\n\t\t\t\t\tif err, ok := errorItemMap[k]; ok {\n\t\t\t\t\t\terrs = append(errs, err.Error())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn errs\n\t}\n\t// No sequence.\n\tfor _, errorItemMap := range e.errors {\n\t\tfor _, err := range errorItemMap {\n\t\t\terrs = append(errs, err.Error())\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_register.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/internal/intlog\"\n)\n\n// RuleFunc is the custom function for data validation.\ntype RuleFunc func(ctx context.Context, in RuleFuncInput) error\n\n// RuleFuncInput holds the input parameters that passed to custom rule function RuleFunc.\ntype RuleFuncInput struct {\n\t// Rule specifies the validation rule string, like \"required\", \"between:1,100\", etc.\n\tRule string\n\n\t// Message specifies the custom error message or configured i18n message for this rule.\n\tMessage string\n\n\t// Field specifies the field for this rule to validate.\n\tField string\n\n\t// ValueType specifies the type of the value, which might be nil.\n\tValueType reflect.Type\n\n\t// Value specifies the value for this rule to validate.\n\tValue *gvar.Var\n\n\t// Data specifies the `data` which is passed to the Validator. It might be a type of map/struct or a nil value.\n\t// You can ignore the parameter `Data` if you do not really need it in your custom validation rule.\n\tData *gvar.Var\n}\n\nvar (\n\t// customRuleFuncMap stores the custom rule functions.\n\t// map[Rule]RuleFunc\n\tcustomRuleFuncMap = make(map[string]RuleFunc)\n)\n\n// RegisterRule registers custom validation rule and function for package.\nfunc RegisterRule(rule string, f RuleFunc) {\n\tif customRuleFuncMap[rule] != nil {\n\t\tintlog.PrintFunc(context.TODO(), func() string {\n\t\t\treturn fmt.Sprintf(\n\t\t\t\t`rule \"%s\" is overwritten by function \"%s\"`,\n\t\t\t\trule, runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(),\n\t\t\t)\n\t\t})\n\t}\n\tcustomRuleFuncMap[rule] = f\n}\n\n// RegisterRuleByMap registers custom validation rules using map for package.\nfunc RegisterRuleByMap(m map[string]RuleFunc) {\n\tfor k, v := range m {\n\t\tcustomRuleFuncMap[k] = v\n\t}\n}\n\n// GetRegisteredRuleMap returns all the custom registered rules and associated functions.\nfunc GetRegisteredRuleMap() map[string]RuleFunc {\n\tif len(customRuleFuncMap) == 0 {\n\t\treturn nil\n\t}\n\truleMap := make(map[string]RuleFunc)\n\tfor k, v := range customRuleFuncMap {\n\t\truleMap[k] = v\n\t}\n\treturn ruleMap\n}\n\n// DeleteRule deletes custom defined validation one or more rules and associated functions from global package.\nfunc DeleteRule(rules ...string) {\n\tfor _, rule := range rules {\n\t\tdelete(customRuleFuncMap, rule)\n\t}\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_validator.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/internal/utils\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// Validator is the validation manager for chaining operations.\ntype Validator struct {\n\ti18nManager                       *gi18n.Manager      // I18n manager for error message translation.\n\tdata                              any                 // Validation data, which can be a map, struct or a certain value to be validated.\n\tassoc                             any                 // Associated data, which is usually a map, for union validation.\n\trules                             any                 // Custom validation data.\n\tmessages                          any                 // Custom validation error messages, which can be string or type of CustomMsg.\n\truleFuncMap                       map[string]RuleFunc // ruleFuncMap stores custom rule functions for current Validator.\n\tuseAssocInsteadOfObjectAttributes bool                // Using `assoc` as its validation source instead of attribute values from `Object`.\n\tbail                              bool                // Stop validation after the first validation error.\n\tforeach                           bool                // It tells the next validation using current value as an array and validates each of its element.\n\tcaseInsensitive                   bool                // Case-Insensitive configuration for those rules that need value comparison.\n}\n\n// New creates and returns a new Validator.\nfunc New() *Validator {\n\treturn &Validator{\n\t\ti18nManager: gi18n.Instance(),          // Use default i18n manager.\n\t\truleFuncMap: make(map[string]RuleFunc), // Custom rule function storing map.\n\t}\n}\n\n// Run starts validating the given data with rules and messages.\nfunc (v *Validator) Run(ctx context.Context) Error {\n\tif v.data == nil {\n\t\treturn newValidationErrorByStr(\n\t\t\tinternalParamsErrRuleName,\n\t\t\terrors.New(`no data passed for validation`),\n\t\t)\n\t}\n\n\toriginValueAndKind := reflection.OriginValueAndKind(v.data)\n\tswitch originValueAndKind.OriginKind {\n\tcase reflect.Map:\n\t\tisMapValidation := false\n\t\tif v.rules == nil {\n\t\t\tisMapValidation = true\n\t\t} else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) {\n\t\t\tisMapValidation = true\n\t\t}\n\t\tif isMapValidation {\n\t\t\treturn v.doCheckMap(ctx, v.data)\n\t\t}\n\n\tcase reflect.Struct:\n\t\tisStructValidation := false\n\t\tif v.rules == nil {\n\t\t\tisStructValidation = true\n\t\t} else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) {\n\t\t\tisStructValidation = true\n\t\t}\n\t\tif isStructValidation {\n\t\t\treturn v.doCheckStruct(ctx, v.data)\n\t\t}\n\t}\n\n\treturn v.doCheckValue(ctx, doCheckValueInput{\n\t\tName:      \"\",\n\t\tValue:     v.data,\n\t\tValueType: reflect.TypeOf(v.data),\n\t\tRule:      gconv.String(v.rules),\n\t\tMessages:  v.messages,\n\t\tDataRaw:   v.assoc,\n\t\tDataMap:   gconv.Map(v.assoc),\n\t})\n}\n\n// Clone creates and returns a new Validator, which is a shallow copy of the current one.\nfunc (v *Validator) Clone() *Validator {\n\tnewValidator := New()\n\t*newValidator = *v\n\treturn newValidator\n}\n\n// I18n sets the i18n manager for the validator.\nfunc (v *Validator) I18n(i18nManager *gi18n.Manager) *Validator {\n\tif i18nManager == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tnewValidator.i18nManager = i18nManager\n\treturn newValidator\n}\n\n// Bail sets the mark for stopping validation after the first validation error.\nfunc (v *Validator) Bail() *Validator {\n\tnewValidator := v.Clone()\n\tnewValidator.bail = true\n\treturn newValidator\n}\n\n// Foreach tells the next validation using current value as an array and validates each of its element.\n// Note that this decorating rule takes effect just once for next validation rule, specially for single value validation.\nfunc (v *Validator) Foreach() *Validator {\n\tnewValidator := v.Clone()\n\tnewValidator.foreach = true\n\treturn newValidator\n}\n\n// Ci sets the mark for Case-Insensitive for those rules that need value comparison.\nfunc (v *Validator) Ci() *Validator {\n\tnewValidator := v.Clone()\n\tnewValidator.caseInsensitive = true\n\treturn newValidator\n}\n\n// Data is a chaining operation function, which sets validation data for current operation.\nfunc (v *Validator) Data(data any) *Validator {\n\tif data == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tnewValidator.data = data\n\treturn newValidator\n}\n\n// Assoc is a chaining operation function, which sets associated validation data for current operation.\n// The optional parameter `assoc` is usually type of map, which specifies the parameter map used in union validation.\n// Calling this function with `assoc` also sets `useAssocInsteadOfObjectAttributes` true\nfunc (v *Validator) Assoc(assoc any) *Validator {\n\tif assoc == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tnewValidator.assoc = assoc\n\tnewValidator.useAssocInsteadOfObjectAttributes = true\n\treturn newValidator\n}\n\n// Rules is a chaining operation function, which sets custom validation rules for current operation.\nfunc (v *Validator) Rules(rules any) *Validator {\n\tif rules == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tnewValidator.rules = rules\n\treturn newValidator\n}\n\n// Messages is a chaining operation function, which sets custom error messages for current operation.\n// The parameter `messages` can be type of string/[]string/map[string]string. It supports sequence in error result\n// if `rules` is type of []string.\nfunc (v *Validator) Messages(messages any) *Validator {\n\tif messages == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tnewValidator.messages = messages\n\treturn newValidator\n}\n\n// RuleFunc registers one custom rule function to current Validator.\nfunc (v *Validator) RuleFunc(rule string, f RuleFunc) *Validator {\n\tnewValidator := v.Clone()\n\tnewValidator.ruleFuncMap[rule] = f\n\treturn newValidator\n}\n\n// RuleFuncMap registers multiple custom rule functions to current Validator.\nfunc (v *Validator) RuleFuncMap(m map[string]RuleFunc) *Validator {\n\tif m == nil {\n\t\treturn v\n\t}\n\tnewValidator := v.Clone()\n\tfor k, v := range m {\n\t\tnewValidator.ruleFuncMap[k] = v\n\t}\n\treturn newValidator\n}\n\n// getCustomRuleFunc retrieves and returns the custom rule function for specified rule.\nfunc (v *Validator) getCustomRuleFunc(rule string) RuleFunc {\n\truleFunc := v.ruleFuncMap[rule]\n\tif ruleFunc == nil {\n\t\truleFunc = customRuleFuncMap[rule]\n\t}\n\treturn ruleFunc\n}\n\n// checkRuleRequired checks and returns whether the given `rule` is required even it is nil or empty.\nfunc (v *Validator) checkRuleRequired(rule string) bool {\n\t// Default required rules.\n\tif gstr.HasPrefix(rule, requiredRulesPrefix) {\n\t\treturn true\n\t}\n\t// All custom validation rules are required rules.\n\tif _, ok := customRuleFuncMap[rule]; ok {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_validator_check_map.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/internal/reflection\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc (v *Validator) doCheckMap(ctx context.Context, params any) Error {\n\tif params == nil {\n\t\treturn nil\n\t}\n\tvar (\n\t\tcheckRules    = make([]fieldRule, 0)\n\t\tcustomMessage = make(CustomMsg) // map[RuleKey]ErrorMsg.\n\t\terrorMaps     = make(map[string]map[string]error)\n\t)\n\tswitch assertValue := v.rules.(type) {\n\t// Sequence tag: []sequence tag\n\t// Sequence has order for error results.\n\tcase []string:\n\t\tfor _, tag := range assertValue {\n\t\t\tname, rule, msg := ParseTagValue(tag)\n\t\t\tif len(name) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(msg) > 0 {\n\t\t\t\tvar (\n\t\t\t\t\tmsgArray  = strings.Split(msg, \"|\")\n\t\t\t\t\truleArray = strings.Split(rule, \"|\")\n\t\t\t\t)\n\t\t\t\tfor k, ruleItem := range ruleArray {\n\t\t\t\t\t// If length of custom messages is lesser than length of rules,\n\t\t\t\t\t// the rest rules use the default error messages.\n\t\t\t\t\tif len(msgArray) <= k {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif len(msgArray[k]) == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tarray := strings.Split(ruleItem, \":\")\n\t\t\t\t\tif _, ok := customMessage[name]; !ok {\n\t\t\t\t\t\tcustomMessage[name] = make(map[string]string)\n\t\t\t\t\t}\n\t\t\t\t\tcustomMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])\n\t\t\t\t}\n\t\t\t}\n\t\t\tcheckRules = append(checkRules, fieldRule{\n\t\t\t\tName: name,\n\t\t\t\tRule: rule,\n\t\t\t})\n\t\t}\n\n\t// No sequence rules: map[field]rule\n\tcase map[string]string:\n\t\tfor name, rule := range assertValue {\n\t\t\tcheckRules = append(checkRules, fieldRule{\n\t\t\t\tName: name,\n\t\t\t\tRule: rule,\n\t\t\t})\n\t\t}\n\t}\n\tinputParamMap := gconv.Map(params)\n\tif inputParamMap == nil {\n\t\treturn newValidationErrorByStr(\n\t\t\tinternalParamsErrRuleName,\n\t\t\terrors.New(\"invalid params type: convert to map failed\"),\n\t\t)\n\t}\n\tif msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {\n\t\tif len(customMessage) > 0 {\n\t\t\tfor k, v := range msg {\n\t\t\t\tcustomMessage[k] = v\n\t\t\t}\n\t\t} else {\n\t\t\tcustomMessage = msg\n\t\t}\n\t}\n\tvar (\n\t\tvalue     any\n\t\tvalidator = v.Clone()\n\t)\n\n\t// It checks the struct recursively if its attribute is an embedded struct.\n\t// Ignore inputParamMap, assoc, rules and messages from parent.\n\tvalidator.assoc = nil\n\tvalidator.rules = nil\n\tvalidator.messages = nil\n\tfor _, item := range inputParamMap {\n\t\toriginTypeAndKind := reflection.OriginTypeAndKind(item)\n\t\tswitch originTypeAndKind.OriginKind {\n\t\tcase reflect.Map, reflect.Struct, reflect.Slice, reflect.Array:\n\t\t\tv.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{\n\t\t\t\tValue:     item,\n\t\t\t\tType:      originTypeAndKind.InputType,\n\t\t\t\tKind:      originTypeAndKind.OriginKind,\n\t\t\t\tErrorMaps: errorMaps,\n\t\t\t})\n\t\t}\n\t\t// Bail feature.\n\t\tif v.bail && len(errorMaps) > 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\tif v.bail && len(errorMaps) > 0 {\n\t\treturn newValidationError(gcode.CodeValidationFailed, nil, errorMaps)\n\t}\n\n\t// The following logic is the same as some of CheckStruct but without sequence support.\n\tfor _, checkRuleItem := range checkRules {\n\t\tif len(checkRuleItem.Rule) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tvalue = nil\n\t\tif valueItem, ok := inputParamMap[checkRuleItem.Name]; ok {\n\t\t\tvalue = valueItem\n\t\t}\n\t\t// It checks each rule and its value in loop.\n\t\tif validatedError := v.doCheckValue(ctx, doCheckValueInput{\n\t\t\tName:      checkRuleItem.Name,\n\t\t\tValue:     value,\n\t\t\tValueType: reflect.TypeOf(value),\n\t\t\tRule:      checkRuleItem.Rule,\n\t\t\tMessages:  customMessage[checkRuleItem.Name],\n\t\t\tDataRaw:   params,\n\t\t\tDataMap:   inputParamMap,\n\t\t}); validatedError != nil {\n\t\t\t_, errorItem := validatedError.FirstItem()\n\t\t\t// ===========================================================\n\t\t\t// Only in map and struct validations:\n\t\t\t// If value is nil or empty string and has no required* rules,\n\t\t\t// it clears the error message.\n\t\t\t// ===========================================================\n\t\t\tif gconv.String(value) == \"\" {\n\t\t\t\trequired := false\n\t\t\t\t// rule => error\n\t\t\t\tfor ruleKey := range errorItem {\n\t\t\t\t\tif required = v.checkRuleRequired(ruleKey); required {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif !required {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif _, ok := errorMaps[checkRuleItem.Name]; !ok {\n\t\t\t\terrorMaps[checkRuleItem.Name] = make(map[string]error)\n\t\t\t}\n\t\t\tfor ruleKey, ruleError := range errorItem {\n\t\t\t\terrorMaps[checkRuleItem.Name][ruleKey] = ruleError\n\t\t\t}\n\t\t\tif v.bail {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif len(errorMaps) > 0 {\n\t\treturn newValidationError(gcode.CodeValidationFailed, checkRules, errorMaps)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_validator_check_struct.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/os/gstructs\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gmeta\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\nfunc (v *Validator) doCheckStruct(ctx context.Context, object any) Error {\n\tvar (\n\t\terrorMaps           = make(map[string]map[string]error) // Returning error.\n\t\tfieldToAliasNameMap = make(map[string]string)           // Field names to alias name map.\n\t\tresultSequenceRules = make([]fieldRule, 0)\n\t\tisEmptyData         = empty.IsEmpty(v.data)\n\t\tisEmptyAssoc        = empty.IsEmpty(v.assoc)\n\t)\n\tfieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{\n\t\tPointer:          object,\n\t\tPriorityTagArray: aliasNameTagPriority,\n\t\tRecursiveOption:  gstructs.RecursiveOptionEmbedded,\n\t})\n\tif err != nil {\n\t\treturn newValidationErrorByStr(internalObjectErrRuleName, err)\n\t}\n\n\t// It here must use gstructs.TagFields not gstructs.FieldMap to ensure error sequence.\n\ttagFields, err := gstructs.TagFields(object, structTagPriority)\n\tif err != nil {\n\t\treturn newValidationErrorByStr(internalObjectErrRuleName, err)\n\t}\n\t// If there's no struct tag and validation rules, it does nothing and returns quickly.\n\tif len(tagFields) == 0 && v.messages == nil && isEmptyData && isEmptyAssoc {\n\t\treturn nil\n\t}\n\n\tvar (\n\t\tinputParamMap  map[string]any\n\t\tcheckRules     = make([]fieldRule, 0)\n\t\tnameToRuleMap  = make(map[string]string) // just for internally searching index purpose.\n\t\tcustomMessage  = make(CustomMsg)         // Custom rule error message map.\n\t\tcheckValueData = v.assoc                 // Ready to be validated data.\n\t)\n\tif checkValueData == nil {\n\t\tcheckValueData = object\n\t}\n\tswitch assertValue := v.rules.(type) {\n\t// Sequence tag: []sequence tag\n\t// Sequence has order for error results.\n\tcase []string:\n\t\tfor _, tag := range assertValue {\n\t\t\tname, rule, msg := ParseTagValue(tag)\n\t\t\tif len(name) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(msg) > 0 {\n\t\t\t\tvar (\n\t\t\t\t\tmsgArray  = strings.Split(msg, \"|\")\n\t\t\t\t\truleArray = strings.Split(rule, \"|\")\n\t\t\t\t)\n\t\t\t\tfor k, ruleKey := range ruleArray {\n\t\t\t\t\t// If length of custom messages is lesser than length of rules,\n\t\t\t\t\t// the rest rules use the default error messages.\n\t\t\t\t\tif len(msgArray) <= k {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif len(msgArray[k]) == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tarray := strings.Split(ruleKey, \":\")\n\t\t\t\t\tif _, ok := customMessage[name]; !ok {\n\t\t\t\t\t\tcustomMessage[name] = make(map[string]string)\n\t\t\t\t\t}\n\t\t\t\t\tcustomMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])\n\t\t\t\t}\n\t\t\t}\n\t\t\tnameToRuleMap[name] = rule\n\t\t\tcheckRules = append(checkRules, fieldRule{\n\t\t\t\tName: name,\n\t\t\t\tRule: rule,\n\t\t\t})\n\t\t}\n\n\t// Map type rules does not support sequence.\n\t// Format: map[key]rule\n\tcase map[string]string:\n\t\tnameToRuleMap = assertValue\n\t\tfor name, rule := range assertValue {\n\t\t\tcheckRules = append(checkRules, fieldRule{\n\t\t\t\tName: name,\n\t\t\t\tRule: rule,\n\t\t\t})\n\t\t}\n\t}\n\t// If there's no struct tag and validation rules, it does nothing and returns quickly.\n\tif len(tagFields) == 0 && len(checkRules) == 0 && isEmptyData && isEmptyAssoc {\n\t\treturn nil\n\t}\n\t// Input parameter map handling.\n\tif v.assoc == nil || !v.useAssocInsteadOfObjectAttributes {\n\t\tinputParamMap = make(map[string]any)\n\t} else {\n\t\tinputParamMap = gconv.Map(v.assoc)\n\t}\n\t// Checks and extends the parameters map with struct alias tag.\n\tif !v.useAssocInsteadOfObjectAttributes {\n\t\tfor nameOrTag, field := range fieldMap {\n\t\t\tinputParamMap[nameOrTag] = field.Value.Interface()\n\t\t\tif nameOrTag != field.Name() {\n\t\t\t\tinputParamMap[field.Name()] = field.Value.Interface()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Merge the custom validation rules with rules in struct tag.\n\t// The custom rules has the most high priority that can overwrite the struct tag rules.\n\tfor _, field := range tagFields {\n\t\tvar (\n\t\t\tisMeta          bool\n\t\t\tfieldName       = field.Name()                  // Attribute name.\n\t\t\tname, rule, msg = ParseTagValue(field.TagValue) // The `name` is different from `attribute alias`, which is used for validation only.\n\t\t)\n\t\tif len(name) == 0 {\n\t\t\tif value, ok := fieldToAliasNameMap[fieldName]; ok {\n\t\t\t\t// It uses alias name of the attribute if its alias name tag exists.\n\t\t\t\tname = value\n\t\t\t} else {\n\t\t\t\t// It or else uses the attribute name directly.\n\t\t\t\tname = field.TagPriorityName()\n\t\t\t}\n\t\t} else {\n\t\t\t// It uses the alias name from validation rule.\n\t\t\tfieldToAliasNameMap[fieldName] = name\n\t\t}\n\t\t// It here extends the params map using alias names.\n\t\t// Note that the variable `name` might be alias name or attribute name.\n\t\tif _, ok := inputParamMap[name]; !ok {\n\t\t\tif !v.useAssocInsteadOfObjectAttributes {\n\t\t\t\tinputParamMap[name] = field.Value.Interface()\n\t\t\t} else {\n\t\t\t\tif name != fieldName {\n\t\t\t\t\tif foundKey, foundValue := gutil.MapPossibleItemByKey(inputParamMap, fieldName); foundKey != \"\" {\n\t\t\t\t\t\tinputParamMap[name] = foundValue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif _, ok := nameToRuleMap[name]; !ok {\n\t\t\tif _, ok = nameToRuleMap[fieldName]; ok {\n\t\t\t\t// If there's alias name,\n\t\t\t\t// use alias name as its key and remove the field name key.\n\t\t\t\tnameToRuleMap[name] = nameToRuleMap[fieldName]\n\t\t\t\tdelete(nameToRuleMap, fieldName)\n\t\t\t\tfor index, checkRuleItem := range checkRules {\n\t\t\t\t\tif fieldName == checkRuleItem.Name {\n\t\t\t\t\t\tcheckRuleItem.Name = name\n\t\t\t\t\t\tcheckRules[index] = checkRuleItem\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnameToRuleMap[name] = rule\n\t\t\t\tif fieldValue := field.Value.Interface(); fieldValue != nil {\n\t\t\t\t\t_, isMeta = fieldValue.(gmeta.Meta)\n\t\t\t\t}\n\t\t\t\tcheckRules = append(checkRules, fieldRule{\n\t\t\t\t\tName:      name,\n\t\t\t\t\tRule:      rule,\n\t\t\t\t\tIsMeta:    isMeta,\n\t\t\t\t\tFieldKind: field.OriginalKind(),\n\t\t\t\t\tFieldType: field.Type(),\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\t// The input rules can overwrite the rules in struct tag.\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(msg) > 0 {\n\t\t\tvar (\n\t\t\t\tmsgArray  = strings.Split(msg, \"|\")\n\t\t\t\truleArray = strings.Split(rule, \"|\")\n\t\t\t)\n\t\t\tfor k, ruleKey := range ruleArray {\n\t\t\t\t// If length of custom messages is lesser than length of rules,\n\t\t\t\t// the rest rules use the default error messages.\n\t\t\t\tif len(msgArray) <= k {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif len(msgArray[k]) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tarray := strings.Split(ruleKey, \":\")\n\t\t\t\tif _, ok := customMessage[name]; !ok {\n\t\t\t\t\tcustomMessage[name] = make(map[string]string)\n\t\t\t\t}\n\t\t\t\tcustomMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])\n\t\t\t}\n\t\t}\n\t}\n\n\t// Custom error messages,\n\t// which have the most priority than `rules` and struct tag.\n\tif msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {\n\t\tfor k, msgName := range msg {\n\t\t\tif aliasName, ok := fieldToAliasNameMap[k]; ok {\n\t\t\t\t// Overwrite the key of field name.\n\t\t\t\tcustomMessage[aliasName] = msgName\n\t\t\t} else {\n\t\t\t\tcustomMessage[k] = msgName\n\t\t\t}\n\t\t}\n\t}\n\n\t// Temporary variable for value.\n\tvar value any\n\n\t// It checks the struct recursively if its attribute is a struct/struct slice.\n\tfor _, field := range fieldMap {\n\t\t// No validation interface implements check.\n\t\tif _, ok := field.Value.Interface().(iNoValidation); ok {\n\t\t\tcontinue\n\t\t}\n\t\t// No validation field tag check.\n\t\tif _, ok := field.TagLookup(noValidationTagName); ok {\n\t\t\tcontinue\n\t\t}\n\t\tif field.IsEmbedded() {\n\t\t\t// The attributes of embedded struct are considered as direct attributes of its parent struct.\n\t\t\tif err = v.doCheckStruct(ctx, field.Value); err != nil {\n\t\t\t\t// It merges the errors into single error map.\n\t\t\t\tfor k, m := range err.(*validationError).errors {\n\t\t\t\t\terrorMaps[k] = m\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// The `field.TagValue` is the alias name of field.Name().\n\t\t\t// Eg, value from struct tag `p`.\n\t\t\tif field.TagValue != \"\" {\n\t\t\t\tfieldToAliasNameMap[field.Name()] = field.TagValue\n\t\t\t}\n\t\t\tswitch field.OriginalKind() {\n\t\t\tcase reflect.Map, reflect.Struct, reflect.Slice, reflect.Array:\n\t\t\t\t// Recursively check attribute slice/map.\n\t\t\t\tvalue = getPossibleValueFromMap(\n\t\t\t\t\tinputParamMap, field.Name(), fieldToAliasNameMap[field.Name()],\n\t\t\t\t)\n\t\t\t\tif empty.IsNil(value) {\n\t\t\t\t\tswitch field.Kind() {\n\t\t\t\t\tcase reflect.Map, reflect.Pointer, reflect.Slice, reflect.Array:\n\t\t\t\t\t\t// Nothing to do.\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tv.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{\n\t\t\t\t\tValue:               value,\n\t\t\t\t\tKind:                field.OriginalKind(),\n\t\t\t\t\tType:                field.Type().Type,\n\t\t\t\t\tErrorMaps:           errorMaps,\n\t\t\t\t\tResultSequenceRules: &resultSequenceRules,\n\t\t\t\t})\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t\tif v.bail && len(errorMaps) > 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\tif v.bail && len(errorMaps) > 0 {\n\t\treturn newValidationError(gcode.CodeValidationFailed, resultSequenceRules, errorMaps)\n\t}\n\n\t// The following logic is the same as some of CheckMap but with sequence support.\n\tfor _, checkRuleItem := range checkRules {\n\t\t// it ignores Meta object.\n\t\tif !checkRuleItem.IsMeta {\n\t\t\tvalue = getPossibleValueFromMap(\n\t\t\t\tinputParamMap, checkRuleItem.Name, fieldToAliasNameMap[checkRuleItem.Name],\n\t\t\t)\n\t\t}\n\t\t// Empty json string checks according to mapping field kind.\n\t\tif value != nil {\n\t\t\tswitch checkRuleItem.FieldKind {\n\t\t\tcase reflect.Struct, reflect.Map:\n\t\t\t\t// empty struct or map.\n\t\t\t\tif gconv.String(value) == emptyJsonObjectStr {\n\t\t\t\t\tvalue = nil\n\t\t\t\t}\n\t\t\tcase reflect.Slice, reflect.Array:\n\t\t\t\t// empty slice.\n\t\t\t\tif gconv.String(value) == emptyJsonArrayStr {\n\t\t\t\t\tvalue = []any{}\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t\t// It checks each rule and its value in loop.\n\t\tif validatedError := v.doCheckValue(ctx, doCheckValueInput{\n\t\t\tName:      checkRuleItem.Name,\n\t\t\tValue:     value,\n\t\t\tValueType: checkRuleItem.FieldType,\n\t\t\tRule:      checkRuleItem.Rule,\n\t\t\tMessages:  customMessage[checkRuleItem.Name],\n\t\t\tDataRaw:   checkValueData,\n\t\t\tDataMap:   inputParamMap,\n\t\t}); validatedError != nil {\n\t\t\t_, errorItem := validatedError.FirstItem()\n\t\t\t// ============================================================\n\t\t\t// Only in map and struct validations:\n\t\t\t// If value is nil or empty string and has no required* rules,\n\t\t\t// it clears the error message.\n\t\t\t// ============================================================\n\t\t\tif !checkRuleItem.IsMeta && (value == nil || gconv.String(value) == \"\") {\n\t\t\t\trequired := false\n\t\t\t\t// rule => error\n\t\t\t\tfor ruleKey := range errorItem {\n\t\t\t\t\t// it checks whether current rule is kind of required rule.\n\t\t\t\t\tif required = v.checkRuleRequired(ruleKey); required {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif !required {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif _, ok := errorMaps[checkRuleItem.Name]; !ok {\n\t\t\t\terrorMaps[checkRuleItem.Name] = make(map[string]error)\n\t\t\t}\n\t\t\tfor ruleKey, errorItemMsgMap := range errorItem {\n\t\t\t\terrorMaps[checkRuleItem.Name][ruleKey] = errorItemMsgMap\n\t\t\t}\n\t\t\t// Bail feature.\n\t\t\tif v.bail {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif len(errorMaps) > 0 {\n\t\treturn newValidationError(\n\t\t\tgcode.CodeValidationFailed,\n\t\t\tappend(checkRules, resultSequenceRules...),\n\t\t\terrorMaps,\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc getPossibleValueFromMap(inputParamMap map[string]any, fieldName, aliasName string) (value any) {\n\t_, value = gutil.MapPossibleItemByKey(inputParamMap, fieldName)\n\tif value == nil && aliasName != \"\" {\n\t\t_, value = gutil.MapPossibleItemByKey(inputParamMap, aliasName)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_validator_check_value.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/encoding/gjson\"\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/text/gregex\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gvalid/internal/builtin\"\n)\n\ntype doCheckValueInput struct {\n\tName      string         // Name specifies the name of parameter `value`, which might be the custom tag name of the parameter.\n\tValue     any            // Value specifies the value for the rules to be validated.\n\tValueType reflect.Type   // ValueType specifies the type of the value, mainly used for value type id retrieving.\n\tRule      string         // Rule specifies the validation rules string, like \"required\", \"required|between:1,100\", etc.\n\tMessages  any            // Messages specifies the custom error messages for this rule from parameters input, which is usually type of map/slice.\n\tDataRaw   any            // DataRaw specifies the `raw data` which is passed to the Validator. It might be type of map/struct or a nil value.\n\tDataMap   map[string]any // DataMap specifies the map that is converted from `dataRaw`. It is usually used internally\n}\n\n// doCheckValue does the really rules validation for single key-value.\nfunc (v *Validator) doCheckValue(ctx context.Context, in doCheckValueInput) Error {\n\t// If there's no validation rules, it does nothing and returns quickly.\n\tif in.Rule == \"\" {\n\t\treturn nil\n\t}\n\t// It converts value to string and then does the validation.\n\tvar (\n\t\t// Do not trim it as the space is also part of the value.\n\t\truleErrorMap = make(map[string]error)\n\t)\n\t// Custom error messages handling.\n\tvar (\n\t\tmsgArray     = make([]string, 0)\n\t\tcustomMsgMap = make(map[string]string)\n\t)\n\tswitch messages := in.Messages.(type) {\n\tcase string:\n\t\tmsgArray = strings.Split(messages, \"|\")\n\n\tdefault:\n\t\tfor k, message := range gconv.Map(in.Messages) {\n\t\t\tcustomMsgMap[k] = gconv.String(message)\n\t\t}\n\t}\n\t// Handle the char '|' in the rule,\n\t// which makes this rule separated into multiple rules.\n\truleItems := strings.Split(strings.TrimSpace(in.Rule), \"|\")\n\tfor i := 0; ; {\n\t\tarray := strings.Split(ruleItems[i], \":\")\n\t\tif builtin.GetRule(array[0]) == nil && v.getCustomRuleFunc(array[0]) == nil {\n\t\t\t// ============================ SPECIAL ============================\n\t\t\t// Special `regex` and `not-regex` rules.\n\t\t\t// Merge the regex pattern if there are special chars, like ':', '|', in pattern.\n\t\t\t// ============================ SPECIAL ============================\n\t\t\tvar (\n\t\t\t\truleNameRegexLengthMatch    bool\n\t\t\t\truleNameNotRegexLengthMatch bool\n\t\t\t)\n\t\t\tif i > 0 {\n\t\t\t\truleItem := ruleItems[i-1]\n\t\t\t\tif len(ruleItem) >= len(ruleNameRegex) && ruleItem[:len(ruleNameRegex)] == ruleNameRegex {\n\t\t\t\t\truleNameRegexLengthMatch = true\n\t\t\t\t}\n\t\t\t\tif len(ruleItem) >= len(ruleNameNotRegex) && ruleItem[:len(ruleNameNotRegex)] == ruleNameNotRegex {\n\t\t\t\t\truleNameNotRegexLengthMatch = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tif i > 0 && (ruleNameRegexLengthMatch || ruleNameNotRegexLengthMatch) {\n\t\t\t\truleItems[i-1] += \"|\" + ruleItems[i]\n\t\t\t\truleItems = append(ruleItems[:i], ruleItems[i+1:]...)\n\t\t\t} else {\n\t\t\t\treturn newValidationErrorByStr(\n\t\t\t\t\tinternalRulesErrRuleName,\n\t\t\t\t\terrors.New(internalRulesErrRuleName+\": \"+ruleItems[i]),\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t\tif i == len(ruleItems) {\n\t\t\tbreak\n\t\t}\n\t}\n\tvar (\n\t\thasBailRule        = v.bail\n\t\thasForeachRule     = v.foreach\n\t\thasCaseInsensitive = v.caseInsensitive\n\t)\n\tfor index := 0; index < len(ruleItems); {\n\t\tvar (\n\t\t\terr         error\n\t\t\tresults     = ruleRegex.FindStringSubmatch(ruleItems[index]) // split single rule.\n\t\t\truleKey     = gstr.Trim(results[1])                          // rule key like \"max\" in rule \"max: 6\"\n\t\t\trulePattern = gstr.Trim(results[2])                          // rule pattern is like \"6\" in rule:\"max:6\"\n\t\t)\n\n\t\tif !hasBailRule && ruleKey == ruleNameBail {\n\t\t\thasBailRule = true\n\t\t}\n\t\tif !hasForeachRule && ruleKey == ruleNameForeach {\n\t\t\thasForeachRule = true\n\t\t}\n\t\tif !hasCaseInsensitive && ruleKey == ruleNameCi {\n\t\t\thasCaseInsensitive = true\n\t\t}\n\n\t\t// Ignore logic executing for marked rules.\n\t\tif decorativeRuleMap[ruleKey] {\n\t\t\tindex++\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(msgArray) > index {\n\t\t\tcustomMsgMap[ruleKey] = strings.TrimSpace(msgArray[index])\n\t\t}\n\n\t\tvar (\n\t\t\tmessage        = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)\n\t\t\tcustomRuleFunc = v.getCustomRuleFunc(ruleKey)\n\t\t\tbuiltinRule    = builtin.GetRule(ruleKey)\n\t\t\tforeachValues  = []any{in.Value}\n\t\t)\n\t\tif hasForeachRule {\n\t\t\t// As it marks `foreach`, so it converts the value to slice.\n\t\t\tforeachValues = gconv.Interfaces(in.Value)\n\t\t\t// Reset `foreach` rule as it only takes effect just once for next rule.\n\t\t\thasForeachRule = false\n\t\t}\n\n\t\tfor _, value := range foreachValues {\n\t\t\tswitch {\n\t\t\t// Custom validation rules.\n\t\t\tcase customRuleFunc != nil:\n\t\t\t\terr = customRuleFunc(ctx, RuleFuncInput{\n\t\t\t\t\tRule:      ruleItems[index],\n\t\t\t\t\tMessage:   message,\n\t\t\t\t\tField:     in.Name,\n\t\t\t\t\tValueType: in.ValueType,\n\t\t\t\t\tValue:     gvar.New(value),\n\t\t\t\t\tData:      gvar.New(in.DataRaw),\n\t\t\t\t})\n\n\t\t\t// Builtin validation rules.\n\t\t\tcase customRuleFunc == nil && builtinRule != nil:\n\t\t\t\terr = builtinRule.Run(builtin.RunInput{\n\t\t\t\t\tRuleKey:     ruleKey,\n\t\t\t\t\tRulePattern: rulePattern,\n\t\t\t\t\tField:       in.Name,\n\t\t\t\t\tValueType:   in.ValueType,\n\t\t\t\t\tValue:       gvar.New(value),\n\t\t\t\t\tData:        gvar.New(in.DataRaw),\n\t\t\t\t\tMessage:     message,\n\t\t\t\t\tOption: builtin.RunOption{\n\t\t\t\t\t\tCaseInsensitive: hasCaseInsensitive,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\tdefault:\n\t\t\t\t// It never comes across here.\n\t\t\t}\n\n\t\t\t// Error handling.\n\t\t\tif err != nil {\n\t\t\t\t// Error variable replacement for error message.\n\t\t\t\tif errMsg := err.Error(); gstr.Contains(errMsg, \"{\") {\n\t\t\t\t\terrMsg = gstr.ReplaceByMap(errMsg, map[string]string{\n\t\t\t\t\t\t\"{field}\":     in.Name,             // Field name of the `value`.\n\t\t\t\t\t\t\"{value}\":     gconv.String(value), // Current validating value.\n\t\t\t\t\t\t\"{pattern}\":   rulePattern,         // The variable part of the rule.\n\t\t\t\t\t\t\"{attribute}\": in.Name,             // The same as `{field}`. It is deprecated.\n\t\t\t\t\t})\n\t\t\t\t\terrMsg, _ = gregex.ReplaceString(`\\s{2,}`, ` `, errMsg)\n\t\t\t\t\terr = errors.New(errMsg)\n\t\t\t\t}\n\t\t\t\t// The error should have stack info to indicate the error position.\n\t\t\t\tif !gerror.HasStack(err) {\n\t\t\t\t\terr = gerror.NewCode(gcode.CodeValidationFailed, err.Error())\n\t\t\t\t}\n\t\t\t\t// The error should have error code that is `gcode.CodeValidationFailed`.\n\t\t\t\tif gerror.Code(err) == gcode.CodeNil {\n\t\t\t\t\t// TODO it's better using interface?\n\t\t\t\t\tif e, ok := err.(*gerror.Error); ok {\n\t\t\t\t\t\te.SetCode(gcode.CodeValidationFailed)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\truleErrorMap[ruleKey] = err\n\n\t\t\t\t// If it is with error and there's bail rule,\n\t\t\t\t// it then does not continue validating for left rules.\n\t\t\t\tif hasBailRule {\n\t\t\t\t\tgoto CheckDone\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tindex++\n\t}\n\nCheckDone:\n\tif len(ruleErrorMap) > 0 {\n\t\treturn newValidationError(\n\t\t\tgcode.CodeValidationFailed,\n\t\t\t[]fieldRule{{Name: in.Name, Rule: in.Rule}},\n\t\t\tmap[string]map[string]error{\n\t\t\t\tin.Name: ruleErrorMap,\n\t\t\t},\n\t\t)\n\t}\n\treturn nil\n}\n\ntype doCheckValueRecursivelyInput struct {\n\tValue               any                         // Value to be validated.\n\tType                reflect.Type                // Struct/map/slice type which to be recursively validated.\n\tKind                reflect.Kind                // Struct/map/slice kind to be asserted in following switch case.\n\tErrorMaps           map[string]map[string]error // The validated failed error map.\n\tResultSequenceRules *[]fieldRule                // The validated failed rule in sequence.\n}\n\nfunc (v *Validator) doCheckValueRecursively(ctx context.Context, in doCheckValueRecursivelyInput) {\n\tswitch in.Kind {\n\tcase reflect.Pointer:\n\t\tv.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{\n\t\t\tValue:               in.Value,\n\t\t\tType:                in.Type.Elem(),\n\t\t\tKind:                in.Type.Elem().Kind(),\n\t\t\tErrorMaps:           in.ErrorMaps,\n\t\t\tResultSequenceRules: in.ResultSequenceRules,\n\t\t})\n\n\tcase reflect.Struct:\n\t\t// Ignore data, assoc, rules and messages from parent.\n\t\tvar (\n\t\t\tvalidator           = v.Clone()\n\t\t\ttoBeValidatedObject any\n\t\t)\n\t\tif in.Type.Kind() == reflect.Pointer {\n\t\t\ttoBeValidatedObject = reflect.New(in.Type.Elem()).Interface()\n\t\t} else {\n\t\t\ttoBeValidatedObject = reflect.New(in.Type).Interface()\n\t\t}\n\t\tvalidator.assoc = nil\n\t\tvalidator.rules = nil\n\t\tvalidator.messages = nil\n\t\tif err := validator.Data(toBeValidatedObject).Assoc(in.Value).Run(ctx); err != nil {\n\t\t\t// It merges the errors into single error map.\n\t\t\tfor k, m := range err.(*validationError).errors {\n\t\t\t\tin.ErrorMaps[k] = m\n\t\t\t}\n\t\t\tif in.ResultSequenceRules != nil {\n\t\t\t\t*in.ResultSequenceRules = append(*in.ResultSequenceRules, err.(*validationError).rules...)\n\t\t\t}\n\t\t}\n\n\tcase reflect.Map:\n\t\tvar (\n\t\t\tdataMap     = gconv.Map(in.Value)\n\t\t\tmapTypeElem = in.Type.Elem()\n\t\t\tmapTypeKind = mapTypeElem.Kind()\n\t\t)\n\t\tfor _, item := range dataMap {\n\t\t\tv.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{\n\t\t\t\tValue:               item,\n\t\t\t\tType:                mapTypeElem,\n\t\t\t\tKind:                mapTypeKind,\n\t\t\t\tErrorMaps:           in.ErrorMaps,\n\t\t\t\tResultSequenceRules: in.ResultSequenceRules,\n\t\t\t})\n\t\t\t// Bail feature.\n\t\t\tif v.bail && len(in.ErrorMaps) > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\tcase reflect.Slice, reflect.Array:\n\t\tloop := false\n\t\tswitch in.Type.Elem().Kind() {\n\t\t// []struct []map\n\t\tcase reflect.Struct, reflect.Map:\n\t\t\tloop = true\n\t\tcase reflect.Pointer:\n\t\t\tloop = true\n\t\t}\n\t\t// When it is a base type array,\n\t\t// there is no need for recursive loop validation,\n\t\t// otherwise it will cause memory leakage\n\t\t// https://github.com/gogf/gf/issues/4092\n\t\tif loop {\n\t\t\tvar array []any\n\t\t\tif gjson.Valid(in.Value) {\n\t\t\t\tarray = gconv.Interfaces(gconv.Bytes(in.Value))\n\t\t\t} else {\n\t\t\t\tarray = gconv.Interfaces(in.Value)\n\t\t\t}\n\t\t\tif len(array) == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfor _, item := range array {\n\t\t\t\tv.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{\n\t\t\t\t\tValue:               item,\n\t\t\t\t\tType:                in.Type.Elem(),\n\t\t\t\t\tKind:                in.Type.Elem().Kind(),\n\t\t\t\t\tErrorMaps:           in.ErrorMaps,\n\t\t\t\t\tResultSequenceRules: in.ResultSequenceRules,\n\t\t\t\t})\n\t\t\t\t// Bail feature.\n\t\t\t\tif v.bail && len(in.ErrorMaps) > 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_validator_message.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"context\"\n\n\t\"github.com/gogf/gf/v2/util/gvalid/internal/builtin\"\n)\n\n// getErrorMessageByRule retrieves and returns the error message for specified rule.\n// It firstly retrieves the message from custom message map, and then checks i18n manager,\n// it returns the default error message if it's not found in neither custom message map nor i18n manager.\nfunc (v *Validator) getErrorMessageByRule(ctx context.Context, ruleKey string, customMsgMap map[string]string) string {\n\tcontent := customMsgMap[ruleKey]\n\tif content != \"\" {\n\t\t// I18n translation.\n\t\ti18nContent := v.i18nManager.GetContent(ctx, content)\n\t\tif i18nContent != \"\" {\n\t\t\treturn i18nContent\n\t\t}\n\t\treturn content\n\t}\n\n\t// Retrieve default message according to certain rule.\n\tcontent = v.i18nManager.GetContent(ctx, ruleMessagePrefixForI18n+ruleKey)\n\tif content == \"\" {\n\t\tcontent = defaultErrorMessages[ruleKey]\n\t}\n\t// Builtin rule message.\n\tif content == \"\" {\n\t\tif builtinRule := builtin.GetRule(ruleKey); builtinRule != nil {\n\t\t\tcontent = builtinRule.Message()\n\t\t}\n\t}\n\t// If there's no configured rule message, it uses default one.\n\tif content == \"\" {\n\t\tcontent = v.i18nManager.GetContent(ctx, ruleMessagePrefixForI18n+internalDefaultRuleName)\n\t}\n\t// If there's no configured rule message, it uses default one.\n\tif content == \"\" {\n\t\tcontent = defaultErrorMessages[internalDefaultRuleName]\n\t}\n\treturn content\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_example_feature_rule_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\nfunc ExampleValidator_required() {\n\ttype BizReq struct {\n\t\tID   uint   `v:\"required\"`\n\t\tName string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Name field is required\n}\n\nfunc ExampleValidator_requiredIf() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string `v:\"required-if:gender,1\"`\n\t\tHusbandName string `v:\"required-if:gender,2\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:     1,\n\t\t\tName:   \"test\",\n\t\t\tGender: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The WifeName field is required\n}\n\nfunc ExampleValidator_requiredIfAll() {\n\ttype BizReq struct {\n\t\tID       uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName     string `v:\"required\" dc:\"Your name\"`\n\t\tAge      int    `v:\"required\" dc:\"Your age\"`\n\t\tMoreInfo string `v:\"required-if-all:id,1,age,18\" dc:\"Your more info\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:   1,\n\t\t\tName: \"test\",\n\t\t\tAge:  18,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The MoreInfo field is required\n}\n\nfunc ExampleValidator_requiredUnless() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string `v:\"required-unless:gender,0,gender,2\"`\n\t\tHusbandName string `v:\"required-unless:id,0,gender,2\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:     1,\n\t\t\tName:   \"test\",\n\t\t\tGender: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The WifeName field is required; The HusbandName field is required\n}\n\nfunc ExampleValidator_requiredWith() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string\n\t\tHusbandName string `v:\"required-with:WifeName\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:       1,\n\t\t\tName:     \"test\",\n\t\t\tGender:   1,\n\t\t\tWifeName: \"Ann\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The HusbandName field is required\n}\n\nfunc ExampleValidator_requiredWithAll() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string\n\t\tHusbandName string `v:\"required-with-all:Id,Name,Gender,WifeName\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:       1,\n\t\t\tName:     \"test\",\n\t\t\tGender:   1,\n\t\t\tWifeName: \"Ann\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The HusbandName field is required\n}\n\nfunc ExampleValidator_requiredWithout() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string\n\t\tHusbandName string `v:\"required-without:Id,WifeName\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:     1,\n\t\t\tName:   \"test\",\n\t\t\tGender: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The HusbandName field is required\n}\n\nfunc ExampleValidator_requiredWithoutAll() {\n\ttype BizReq struct {\n\t\tID          uint   `v:\"required\" dc:\"Your ID\"`\n\t\tName        string `v:\"required\" dc:\"Your name\"`\n\t\tGender      uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t\tWifeName    string\n\t\tHusbandName string `v:\"required-without-all:Id,WifeName\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tName:   \"test\",\n\t\t\tGender: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The HusbandName field is required\n}\n\nfunc ExampleValidator_bail() {\n\ttype BizReq struct {\n\t\tAccount   string `v:\"bail|required|length:6,16|same:QQ\"`\n\t\tQQ        string\n\t\tPassword  string `v:\"required|same:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAccount:   \"gf\",\n\t\t\tQQ:        \"123456\",\n\t\t\tPassword:  \"goframe.org\",\n\t\t\tPassword2: \"goframe.org\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// output:\n\t// The Account value `gf` length must be between 6 and 16\n}\n\nfunc ExampleValidator_caseInsensitive() {\n\ttype BizReq struct {\n\t\tAccount   string `v:\"required\"`\n\t\tPassword  string `v:\"required|ci|same:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAccount:   \"gf\",\n\t\t\tPassword:  \"Goframe.org\", // Diff from Password2, but because of \"ci\", rule check passed\n\t\t\tPassword2: \"goframe.org\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// output:\n}\n\nfunc ExampleValidator_date() {\n\ttype BizReq struct {\n\t\tDate1 string `v:\"date\"`\n\t\tDate2 string `v:\"date\"`\n\t\tDate3 string `v:\"date\"`\n\t\tDate4 string `v:\"date\"`\n\t\tDate5 string `v:\"date\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tDate1: \"2021-10-31\",\n\t\t\tDate2: \"2021.10.31\",\n\t\t\tDate3: \"2021-Oct-31\",\n\t\t\tDate4: \"2021 Octa 31\",\n\t\t\tDate5: \"2021/Oct/31\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Date3 value `2021-Oct-31` is not a valid date\n\t// The Date4 value `2021 Octa 31` is not a valid date\n\t// The Date5 value `2021/Oct/31` is not a valid date\n}\n\nfunc ExampleValidator_datetime() {\n\ttype BizReq struct {\n\t\tDate1 string `v:\"datetime\"`\n\t\tDate2 string `v:\"datetime\"`\n\t\tDate3 string `v:\"datetime\"`\n\t\tDate4 string `v:\"datetime\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tDate1: \"2021-11-01 23:00:00\",\n\t\t\tDate2: \"2021-11-01 23:00\",     // error\n\t\t\tDate3: \"2021/11/01 23:00:00\",  // error\n\t\t\tDate4: \"2021/Dec/01 23:00:00\", // error\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Date2 value `2021-11-01 23:00` is not a valid datetime\n\t// The Date3 value `2021/11/01 23:00:00` is not a valid datetime\n\t// The Date4 value `2021/Dec/01 23:00:00` is not a valid datetime\n}\n\nfunc ExampleValidator_dateFormat() {\n\ttype BizReq struct {\n\t\tDate1 string `v:\"date-format:Y-m-d\"`\n\t\tDate2 string `v:\"date-format:Y-m-d\"`\n\t\tDate3 string `v:\"date-format:Y-m-d H:i:s\"`\n\t\tDate4 string `v:\"date-format:Y-m-d H:i:s\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tDate1: \"2021-11-01\",\n\t\t\tDate2: \"2021-11-01 23:00\", // error\n\t\t\tDate3: \"2021-11-01 23:00:00\",\n\t\t\tDate4: \"2021-11-01 23:00\", // error\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Date2 value `2021-11-01 23:00` does not match the format: Y-m-d\n\t// The Date4 value `2021-11-01 23:00` does not match the format: Y-m-d H:i:s\n}\n\nfunc ExampleValidator_email() {\n\ttype BizReq struct {\n\t\tMailAddr1 string `v:\"email\"`\n\t\tMailAddr2 string `v:\"email\"`\n\t\tMailAddr3 string `v:\"email\"`\n\t\tMailAddr4 string `v:\"email\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tMailAddr1: \"gf@goframe.org\",\n\t\t\tMailAddr2: \"gf@goframe\", // error\n\t\t\tMailAddr3: \"gf@goframe.org.cn\",\n\t\t\tMailAddr4: \"gf#goframe.org\", // error\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The MailAddr2 value `gf@goframe` is not a valid email address\n\t// The MailAddr4 value `gf#goframe.org` is not a valid email address\n}\n\nfunc ExampleValidator_enums() {\n\ttype Status string\n\tconst (\n\t\tStatusRunning Status = \"Running\"\n\t\tStatusOffline Status = \"Offline\"\n\t)\n\ttype BizReq struct {\n\t\tId     int    `v:\"required\"`\n\t\tName   string `v:\"required\"`\n\t\tStatus Status `v:\"enums\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tId:     1,\n\t\t\tName:   \"john\",\n\t\t\tStatus: Status(\"Pending\"),\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// May Output:\n\t// The Status value `Pending` should be in enums of: [\"Running\",\"Offline\"]\n}\n\nfunc ExampleValidator_phone() {\n\ttype BizReq struct {\n\t\tPhoneNumber1 string `v:\"phone\"`\n\t\tPhoneNumber2 string `v:\"phone\"`\n\t\tPhoneNumber3 string `v:\"phone\"`\n\t\tPhoneNumber4 string `v:\"phone\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPhoneNumber1: \"13578912345\",\n\t\t\tPhoneNumber2: \"17178912345\",\n\t\t\tPhoneNumber3: \"11578912345\", // error 11x not exist\n\t\t\tPhoneNumber4: \"1357891234\",  // error len must be 11\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The PhoneNumber3 value `11578912345` is not a valid phone number\n\t// The PhoneNumber4 value `1357891234` is not a valid phone number\n}\n\nfunc ExampleValidator_phoneLoose() {\n\ttype BizReq struct {\n\t\tPhoneNumber1 string `v:\"phone-loose\"`\n\t\tPhoneNumber2 string `v:\"phone-loose\"`\n\t\tPhoneNumber3 string `v:\"phone-loose\"`\n\t\tPhoneNumber4 string `v:\"phone-loose\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPhoneNumber1: \"13578912345\",\n\t\t\tPhoneNumber2: \"11578912345\", // error 11x not exist\n\t\t\tPhoneNumber3: \"17178912345\",\n\t\t\tPhoneNumber4: \"1357891234\", // error len must be 11\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The PhoneNumber2 value `11578912345` is not a valid phone number\n\t// The PhoneNumber4 value `1357891234` is not a valid phone number\n}\n\nfunc ExampleValidator_telephone() {\n\ttype BizReq struct {\n\t\tTelephone1 string `v:\"telephone\"`\n\t\tTelephone2 string `v:\"telephone\"`\n\t\tTelephone3 string `v:\"telephone\"`\n\t\tTelephone4 string `v:\"telephone\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tTelephone1: \"010-77542145\",\n\t\t\tTelephone2: \"0571-77542145\",\n\t\t\tTelephone3: \"20-77542145\", // error\n\t\t\tTelephone4: \"775421451\",   // error len must be 7 or 8\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Telephone3 value `20-77542145` is not a valid telephone number\n\t// The Telephone4 value `775421451` is not a valid telephone number\n}\n\nfunc ExampleValidator_passport() {\n\ttype BizReq struct {\n\t\tPassport1 string `v:\"passport\"`\n\t\tPassport2 string `v:\"passport\"`\n\t\tPassport3 string `v:\"passport\"`\n\t\tPassport4 string `v:\"passport\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPassport1: \"goframe\",\n\t\t\tPassport2: \"1356666\",  // error starting with letter\n\t\t\tPassport3: \"goframe#\", // error containing only numbers or underscores\n\t\t\tPassport4: \"gf\",       // error length between 6 and 18\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Passport2 value `1356666` is not a valid passport format\n\t// The Passport3 value `goframe#` is not a valid passport format\n\t// The Passport4 value `gf` is not a valid passport format\n}\n\nfunc ExampleValidator_password() {\n\ttype BizReq struct {\n\t\tPassword1 string `v:\"password\"`\n\t\tPassword2 string `v:\"password\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPassword1: \"goframe\",\n\t\t\tPassword2: \"gofra\", // error length between 6 and 18\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Password2 value `gofra` is not a valid password format\n}\n\nfunc ExampleValidator_password2() {\n\ttype BizReq struct {\n\t\tPassword1 string `v:\"password2\"`\n\t\tPassword2 string `v:\"password2\"`\n\t\tPassword3 string `v:\"password2\"`\n\t\tPassword4 string `v:\"password2\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPassword1: \"Goframe123\",\n\t\t\tPassword2: \"gofra\",      // error length between 6 and 18\n\t\t\tPassword3: \"Goframe\",    // error must contain lower and upper letters and numbers.\n\t\t\tPassword4: \"goframe123\", // error must contain lower and upper letters and numbers.\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Password2 value `gofra` is not a valid password2 format\n\t// The Password3 value `Goframe` is not a valid password2 format\n\t// The Password4 value `goframe123` is not a valid password2 format\n}\n\nfunc ExampleValidator_password3() {\n\ttype BizReq struct {\n\t\tPassword1 string `v:\"password3\"`\n\t\tPassword2 string `v:\"password3\"`\n\t\tPassword3 string `v:\"password3\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPassword1: \"Goframe123#\",\n\t\t\tPassword2: \"gofra\",      // error length between 6 and 18\n\t\t\tPassword3: \"Goframe123\", // error must contain lower and upper letters, numbers and special chars.\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Password2 value `gofra` is not a valid password3 format\n\t// The Password3 value `Goframe123` is not a valid password3 format\n}\n\nfunc ExampleValidator_postcode() {\n\ttype BizReq struct {\n\t\tPostcode1 string `v:\"postcode\"`\n\t\tPostcode2 string `v:\"postcode\"`\n\t\tPostcode3 string `v:\"postcode\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPostcode1: \"100000\",\n\t\t\tPostcode2: \"10000\",   // error length must be 6\n\t\t\tPostcode3: \"1000000\", // error length must be 6\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Postcode2 value `10000` is not a valid postcode format\n\t// The Postcode3 value `1000000` is not a valid postcode format\n}\n\nfunc ExampleValidator_residentId() {\n\ttype BizReq struct {\n\t\tResidentID1 string `v:\"resident-id\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tResidentID1: \"320107199506285482\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The ResidentID1 value `320107199506285482` is not a valid resident id number\n}\n\nfunc ExampleValidator_bankCard() {\n\ttype BizReq struct {\n\t\tBankCard1 string `v:\"bank-card\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tBankCard1: \"6225760079930218\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The BankCard1 value `6225760079930218` is not a valid bank card number\n}\n\nfunc ExampleValidator_qq() {\n\ttype BizReq struct {\n\t\tQQ1 string `v:\"qq\"`\n\t\tQQ2 string `v:\"qq\"`\n\t\tQQ3 string `v:\"qq\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tQQ1: \"389961817\",\n\t\t\tQQ2: \"9999\",       // error >= 10000\n\t\t\tQQ3: \"514258412a\", // error all number\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The QQ2 value `9999` is not a valid QQ number\n\t// The QQ3 value `514258412a` is not a valid QQ number\n}\n\nfunc ExampleValidator_ip() {\n\ttype BizReq struct {\n\t\tIP1 string `v:\"ip\"`\n\t\tIP2 string `v:\"ip\"`\n\t\tIP3 string `v:\"ip\"`\n\t\tIP4 string `v:\"ip\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tIP1: \"127.0.0.1\",\n\t\t\tIP2: \"fe80::812b:1158:1f43:f0d1\",\n\t\t\tIP3: \"520.255.255.255\", // error >= 10000\n\t\t\tIP4: \"ze80::812b:1158:1f43:f0d1\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The IP3 value `520.255.255.255` is not a valid IP address\n\t// The IP4 value `ze80::812b:1158:1f43:f0d1` is not a valid IP address\n}\n\nfunc ExampleValidator_ipv4() {\n\ttype BizReq struct {\n\t\tIP1 string `v:\"ipv4\"`\n\t\tIP2 string `v:\"ipv4\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tIP1: \"127.0.0.1\",\n\t\t\tIP2: \"520.255.255.255\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The IP2 value `520.255.255.255` is not a valid IPv4 address\n}\n\nfunc ExampleValidator_ipv6() {\n\ttype BizReq struct {\n\t\tIP1 string `v:\"ipv6\"`\n\t\tIP2 string `v:\"ipv6\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tIP1: \"fe80::812b:1158:1f43:f0d1\",\n\t\t\tIP2: \"ze80::812b:1158:1f43:f0d1\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The IP2 value `ze80::812b:1158:1f43:f0d1` is not a valid IPv6 address\n}\n\nfunc ExampleValidator_mac() {\n\ttype BizReq struct {\n\t\tMac1 string `v:\"mac\"`\n\t\tMac2 string `v:\"mac\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tMac1: \"4C-CC-6A-D6-B1-1A\",\n\t\t\tMac2: \"Z0-CC-6A-D6-B1-1A\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Mac2 value `Z0-CC-6A-D6-B1-1A` is not a valid MAC address\n}\n\nfunc ExampleValidator_url() {\n\ttype BizReq struct {\n\t\tURL1 string `v:\"url\"`\n\t\tURL2 string `v:\"url\"`\n\t\tURL3 string `v:\"url\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tURL1: \"http://goframe.org\",\n\t\t\tURL2: \"ftp://goframe.org\",\n\t\t\tURL3: \"ws://goframe.org\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The URL3 value `ws://goframe.org` is not a valid URL address\n}\n\nfunc ExampleValidator_domain() {\n\ttype BizReq struct {\n\t\tDomain1 string `v:\"domain\"`\n\t\tDomain2 string `v:\"domain\"`\n\t\tDomain3 string `v:\"domain\"`\n\t\tDomain4 string `v:\"domain\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tDomain1: \"goframe.org\",\n\t\t\tDomain2: \"a.b\",\n\t\t\tDomain3: \"goframe#org\",\n\t\t\tDomain4: \"1a.2b\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Domain3 value `goframe#org` is not a valid domain format\n\t// The Domain4 value `1a.2b` is not a valid domain format\n}\n\nfunc ExampleValidator_size() {\n\ttype BizReq struct {\n\t\tSize1 string `v:\"size:11\"`\n\t\tSize2 string `v:\"size:5\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tSize1: \"goframe 欢迎你\",\n\t\t\tSize2: \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Size2 value `goframe` length must be 5\n}\n\nfunc ExampleValidator_length() {\n\ttype BizReq struct {\n\t\tLength1 string `v:\"length:5,12\"`\n\t\tLength2 string `v:\"length:10,15\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tLength1: \"goframe 欢迎你\",\n\t\t\tLength2: \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Length2 value `goframe` length must be between 10 and 15\n}\n\nfunc ExampleValidator_minLength() {\n\ttype BizReq struct {\n\t\tMinLength1 string `v:\"min-length:10\"`\n\t\tMinLength2 string `v:\"min-length:8\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tMinLength1: \"goframe 欢迎你\",\n\t\t\tMinLength2: \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The MinLength2 value `goframe` length must be equal or greater than 8\n}\n\nfunc ExampleValidator_maxLength() {\n\ttype BizReq struct {\n\t\tMaxLength1 string `v:\"max-length:11\"`\n\t\tMaxLength2 string `v:\"max-length:5\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tMaxLength1: \"goframe 欢迎你\",\n\t\t\tMaxLength2: \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The MaxLength2 value `goframe` length must be equal or lesser than 5\n}\n\nfunc ExampleValidator_between() {\n\ttype BizReq struct {\n\t\tAge1   int     `v:\"between:1,100\"`\n\t\tAge2   int     `v:\"between:1,100\"`\n\t\tScore1 float32 `v:\"between:0.0,10.0\"`\n\t\tScore2 float32 `v:\"between:0.0,10.0\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAge1:   50,\n\t\t\tAge2:   101,\n\t\t\tScore1: 9.8,\n\t\t\tScore2: -0.5,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Age2 value `101` must be between 1 and 100\n\t// The Score2 value `-0.5` must be between 0 and 10\n}\n\nfunc ExampleValidator_min() {\n\ttype BizReq struct {\n\t\tAge1   int     `v:\"min:100\"`\n\t\tAge2   int     `v:\"min:100\"`\n\t\tScore1 float32 `v:\"min:10.0\"`\n\t\tScore2 float32 `v:\"min:10.0\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAge1:   50,\n\t\t\tAge2:   101,\n\t\t\tScore1: 9.8,\n\t\t\tScore2: 10.1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Age1 value `50` must be equal or greater than 100\n\t// The Score1 value `9.8` must be equal or greater than 10\n}\n\nfunc ExampleValidator_max() {\n\ttype BizReq struct {\n\t\tAge1   int     `v:\"max:100\"`\n\t\tAge2   int     `v:\"max:100\"`\n\t\tScore1 float32 `v:\"max:10.0\"`\n\t\tScore2 float32 `v:\"max:10.0\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAge1:   99,\n\t\t\tAge2:   101,\n\t\t\tScore1: 9.9,\n\t\t\tScore2: 10.1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Age2 value `101` must be equal or lesser than 100\n\t// The Score2 value `10.1` must be equal or lesser than 10\n}\n\nfunc ExampleValidator_json() {\n\ttype BizReq struct {\n\t\tJSON1 string `v:\"json\"`\n\t\tJSON2 string `v:\"json\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tJSON1: \"{\\\"name\\\":\\\"goframe\\\",\\\"author\\\":\\\"Guo Qiang\\\"}\",\n\t\t\tJSON2: \"{\\\"name\\\":\\\"goframe\\\",\\\"author\\\":\\\"Guo Qiang\\\",\\\"test\\\"}\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The JSON2 value `{\"name\":\"goframe\",\"author\":\"Guo Qiang\",\"test\"}` is not a valid JSON string\n}\n\nfunc ExampleValidator_integer() {\n\ttype BizReq struct {\n\t\tInteger string `v:\"integer\"`\n\t\tFloat   string `v:\"integer\"`\n\t\tStr     string `v:\"integer\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tInteger: \"100\",\n\t\t\tFloat:   \"10.0\",\n\t\t\tStr:     \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Float value `10.0` is not an integer\n\t// The Str value `goframe` is not an integer\n}\n\nfunc ExampleValidator_float() {\n\ttype BizReq struct {\n\t\tInteger string `v:\"float\"`\n\t\tFloat   string `v:\"float\"`\n\t\tStr     string `v:\"float\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tInteger: \"100\",\n\t\t\tFloat:   \"10.0\",\n\t\t\tStr:     \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Str value `goframe` is not of valid float type\n}\n\nfunc ExampleValidator_boolean() {\n\ttype BizReq struct {\n\t\tBoolean bool    `v:\"boolean\"`\n\t\tInteger int     `v:\"boolean\"`\n\t\tFloat   float32 `v:\"boolean\"`\n\t\tStr1    string  `v:\"boolean\"`\n\t\tStr2    string  `v:\"boolean\"`\n\t\tStr3    string  `v:\"boolean\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tBoolean: true,\n\t\t\tInteger: 1,\n\t\t\tFloat:   10.0,\n\t\t\tStr1:    \"on\",\n\t\t\tStr2:    \"\",\n\t\t\tStr3:    \"goframe\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Float value `10` field must be true or false\n\t// The Str3 value `goframe` field must be true or false\n}\n\nfunc ExampleValidator_same() {\n\ttype BizReq struct {\n\t\tName      string `v:\"required\"`\n\t\tPassword  string `v:\"required|same:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tName:      \"gf\",\n\t\t\tPassword:  \"goframe.org\",\n\t\t\tPassword2: \"goframe.net\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The Password value `goframe.org` must be the same as field Password2 value `goframe.net`\n}\n\nfunc ExampleValidator_different() {\n\ttype BizReq struct {\n\t\tName          string `v:\"required\"`\n\t\tMailAddr      string `v:\"required\"`\n\t\tOtherMailAddr string `v:\"required|different:MailAddr\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tName:          \"gf\",\n\t\t\tMailAddr:      \"gf@goframe.org\",\n\t\t\tOtherMailAddr: \"gf@goframe.org\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The OtherMailAddr value `gf@goframe.org` must be different from field MailAddr value `gf@goframe.org`\n}\n\nfunc ExampleValidator_in() {\n\ttype BizReq struct {\n\t\tID     uint   `v:\"required\" dc:\"Your Id\"`\n\t\tName   string `v:\"required\" dc:\"Your name\"`\n\t\tGender uint   `v:\"in:0,1,2\" dc:\"0:Secret;1:Male;2:Female\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:     1,\n\t\t\tName:   \"test\",\n\t\t\tGender: 3,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The Gender value `3` is not in acceptable range: 0,1,2\n}\n\nfunc ExampleValidator_notIn() {\n\ttype BizReq struct {\n\t\tID           uint   `v:\"required\" dc:\"Your Id\"`\n\t\tName         string `v:\"required\" dc:\"Your name\"`\n\t\tInvalidIndex uint   `v:\"not-in:-1,0,1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tID:           1,\n\t\t\tName:         \"test\",\n\t\t\tInvalidIndex: 1,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The InvalidIndex value `1` must not be in range: -1,0,1\n}\n\nfunc ExampleValidator_regex() {\n\ttype BizReq struct {\n\t\tRegex1 string `v:\"regex:[1-9][0-9]{4,14}\"`\n\t\tRegex2 string `v:\"regex:[1-9][0-9]{4,14}\"`\n\t\tRegex3 string `v:\"regex:[1-9][0-9]{4,14}\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tRegex1: \"1234\",\n\t\t\tRegex2: \"01234\",\n\t\t\tRegex3: \"10000\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Regex1 value `1234` must be in regex of: [1-9][0-9]{4,14}\n\t// The Regex2 value `01234` must be in regex of: [1-9][0-9]{4,14}\n}\n\nfunc ExampleValidator_notRegex() {\n\ttype BizReq struct {\n\t\tRegex1 string `v:\"regex:\\\\d{4}\"`\n\t\tRegex2 string `v:\"not-regex:\\\\d{4}\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tRegex1: \"1234\",\n\t\t\tRegex2: \"1234\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Regex2 value `1234` should not be in regex of: \\d{4}\n}\n\nfunc ExampleValidator_after() {\n\ttype BizReq struct {\n\t\tTime1 string\n\t\tTime2 string `v:\"after:Time1\"`\n\t\tTime3 string `v:\"after:Time1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tTime1: \"2022-09-01\",\n\t\t\tTime2: \"2022-09-01\",\n\t\t\tTime3: \"2022-09-02\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Time2 value `2022-09-01` must be after field Time1 value `2022-09-01`\n}\n\nfunc ExampleValidator_afterEqual() {\n\ttype BizReq struct {\n\t\tTime1 string\n\t\tTime2 string `v:\"after-equal:Time1\"`\n\t\tTime3 string `v:\"after-equal:Time1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tTime1: \"2022-09-02\",\n\t\t\tTime2: \"2022-09-01\",\n\t\t\tTime3: \"2022-09-02\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Time2 value `2022-09-01` must be after or equal to field Time1 value `2022-09-02`\n}\n\nfunc ExampleValidator_before() {\n\ttype BizReq struct {\n\t\tTime1 string `v:\"before:Time3\"`\n\t\tTime2 string `v:\"before:Time3\"`\n\t\tTime3 string\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tTime1: \"2022-09-02\",\n\t\t\tTime2: \"2022-09-03\",\n\t\t\tTime3: \"2022-09-03\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Time2 value `2022-09-03` must be before field Time3 value `2022-09-03`\n}\n\nfunc ExampleValidator_beforeEqual() {\n\ttype BizReq struct {\n\t\tTime1 string `v:\"before-equal:Time3\"`\n\t\tTime2 string `v:\"before-equal:Time3\"`\n\t\tTime3 string\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tTime1: \"2022-09-02\",\n\t\t\tTime2: \"2022-09-01\",\n\t\t\tTime3: \"2022-09-01\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Time1 value `2022-09-02` must be before or equal to field Time3\n}\n\nfunc ExampleValidator_array() {\n\ttype BizReq struct {\n\t\tValue1 string   `v:\"array\"`\n\t\tValue2 string   `v:\"array\"`\n\t\tValue3 string   `v:\"array\"`\n\t\tValue4 []string `v:\"array\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: \"1,2,3\",\n\t\t\tValue2: \"[]\",\n\t\t\tValue3: \"[1,2,3]\",\n\t\t\tValue4: []string{},\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(gstr.Join(err.Strings(), \"\\n\"))\n\t}\n\n\t// Output:\n\t// The Value1 value `1,2,3` is not of valid array type\n}\n\nfunc ExampleValidator_eq() {\n\ttype BizReq struct {\n\t\tName      string `v:\"required\"`\n\t\tPassword  string `v:\"required|eq:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tName:      \"gf\",\n\t\t\tPassword:  \"goframe.org\",\n\t\t\tPassword2: \"goframe.net\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The Password value `goframe.org` must be equal to field Password2 value `goframe.net`\n}\n\nfunc ExampleValidator_notEQ() {\n\ttype BizReq struct {\n\t\tName          string `v:\"required\"`\n\t\tMailAddr      string `v:\"required\"`\n\t\tOtherMailAddr string `v:\"required|not-eq:MailAddr\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tName:          \"gf\",\n\t\t\tMailAddr:      \"gf@goframe.org\",\n\t\t\tOtherMailAddr: \"gf@goframe.org\",\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The OtherMailAddr value `gf@goframe.org` must not be equal to field MailAddr value `gf@goframe.org`\n}\n\nfunc ExampleValidator_gt() {\n\ttype BizReq struct {\n\t\tValue1 int\n\t\tValue2 int `v:\"gt:Value1\"`\n\t\tValue3 int `v:\"gt:Value1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: 1,\n\t\t\tValue2: 1,\n\t\t\tValue3: 2,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Value2 value `1` must be greater than field Value1 value `1`\n}\n\nfunc ExampleValidator_gte() {\n\ttype BizReq struct {\n\t\tValue1 int\n\t\tValue2 int `v:\"gte:Value1\"`\n\t\tValue3 int `v:\"gte:Value1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: 2,\n\t\t\tValue2: 1,\n\t\t\tValue3: 2,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Value2 value `1` must be greater than or equal to field Value1 value `2`\n}\n\nfunc ExampleValidator_lt() {\n\ttype BizReq struct {\n\t\tValue1 int\n\t\tValue2 int `v:\"lt:Value1\"`\n\t\tValue3 int `v:\"lt:Value1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: 2,\n\t\t\tValue2: 1,\n\t\t\tValue3: 2,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Value3 value `2` must be lesser than field Value1 value `2`\n}\n\nfunc ExampleValidator_lte() {\n\ttype BizReq struct {\n\t\tValue1 int\n\t\tValue2 int `v:\"lte:Value1\"`\n\t\tValue3 int `v:\"lte:Value1\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: 1,\n\t\t\tValue2: 1,\n\t\t\tValue3: 2,\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Value3 value `2` must be lesser than or equal to field Value1 value `1`\n}\n\nfunc ExampleValidator_foreach() {\n\ttype BizReq struct {\n\t\tValue1 []int `v:\"foreach|in:1,2,3\"`\n\t\tValue2 []int `v:\"foreach|in:1,2,3\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tValue1: []int{1, 2, 3},\n\t\t\tValue2: []int{3, 4, 5},\n\t\t}\n\t)\n\tif err := g.Validator().Bail().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(err.String())\n\t}\n\n\t// Output:\n\t// The Value2 value `4` is not in acceptable range: 1,2,3\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_example_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nfunc ExampleNew() {\n\tif err := g.Validator().Data(16).Rules(\"min:18\").Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The value `16` must be equal or greater than 18\n}\n\nfunc ExampleValidator_Run() {\n\t// check value mode\n\tif err := g.Validator().Data(16).Rules(\"min:18\").Run(context.Background()); err != nil {\n\t\tfmt.Println(\"check value err:\", err)\n\t}\n\t// check map mode\n\tdata := map[string]any{\n\t\t\"passport\":  \"\",\n\t\t\"password\":  \"123456\",\n\t\t\"password2\": \"1234567\",\n\t}\n\trules := map[string]string{\n\t\t\"passport\":  \"required|length:6,16\",\n\t\t\"password\":  \"required|length:6,16|same:password2\",\n\t\t\"password2\": \"required|length:6,16\",\n\t}\n\tif err := g.Validator().Data(data).Rules(rules).Run(context.Background()); err != nil {\n\t\tfmt.Println(\"check map err:\", err)\n\t}\n\t// check struct mode\n\ttype Params struct {\n\t\tPage      int    `v:\"required|min:1\"`\n\t\tSize      int    `v:\"required|between:1,100\"`\n\t\tProjectId string `v:\"between:1,10000\"`\n\t}\n\trules = map[string]string{\n\t\t\"Page\":      \"required|min:1\",\n\t\t\"Size\":      \"required|between:1,100\",\n\t\t\"ProjectId\": \"between:1,10000\",\n\t}\n\tobj := &Params{\n\t\tPage: 0,\n\t\tSize: 101,\n\t}\n\tif err := g.Validator().Data(obj).Run(context.Background()); err != nil {\n\t\tfmt.Println(\"check struct err:\", err)\n\t}\n\n\t// May Output:\n\t// check value err: The value `16` must be equal or greater than 18\n\t// check map err: The passport field is required; The passport value `` length must be between 6 and 16; The password value `123456` must be the same as field password2\n\t// check struct err: The Page value `0` must be equal or greater than 1; The Size value `101` must be between 1 and 100\n}\n\nfunc ExampleValidator_Clone() {\n\tif err := g.Validator().Data(16).Rules(\"min:18\").Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tif err := g.Validator().Clone().Data(20).Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t} else {\n\t\tfmt.Println(\"Check Success!\")\n\t}\n\n\t// Output:\n\t// The value `16` must be equal or greater than 18\n\t// Check Success!\n}\n\nfunc ExampleValidator_I18n() {\n\tvar (\n\t\ti18nManager = gi18n.New(gi18n.Options{Path: gtest.DataPath(\"i18n\")})\n\t\tctxCn       = gi18n.WithLanguage(context.Background(), \"cn\")\n\t\tvalidator   = gvalid.New()\n\t)\n\n\tvalidator = validator.Data(16).Rules(\"min:18\")\n\n\tif err := validator.Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\tif err := validator.I18n(i18nManager).Run(ctxCn); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The value `16` must be equal or greater than 18\n\t// 字段值`16`字段最小值应当为18\n}\n\nfunc ExampleValidator_Bail() {\n\ttype BizReq struct {\n\t\tAccount   string `v:\"required|length:6,16|same:QQ\"`\n\t\tQQ        string\n\t\tPassword  string `v:\"required|same:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAccount:   \"gf\",\n\t\t\tQQ:        \"123456\",\n\t\t\tPassword:  \"goframe.org\",\n\t\t\tPassword2: \"goframe.org\",\n\t\t}\n\t)\n\n\tif err := g.Validator().Bail().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(\"Use Bail Error:\", err)\n\t}\n\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(\"Not Use Bail Error:\", err)\n\t}\n\n\t// output:\n\t// Use Bail Error: The Account value `gf` length must be between 6 and 16\n\t// Not Use Bail Error: The Account value `gf` length must be between 6 and 16; The Account value `gf` must be the same as field QQ value `123456`\n}\n\nfunc ExampleValidator_Ci() {\n\ttype BizReq struct {\n\t\tAccount   string `v:\"required\"`\n\t\tPassword  string `v:\"required|same:Password2\"`\n\t\tPassword2 string `v:\"required\"`\n\t}\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tAccount:   \"gf\",\n\t\t\tPassword:  \"Goframe.org\", // Diff from Password2, but because of \"ci\", rule check passed\n\t\t\tPassword2: \"goframe.org\",\n\t\t}\n\t)\n\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Println(\"Not Use CI Error:\", err)\n\t}\n\n\tif err := g.Validator().Ci().Data(req).Run(ctx); err == nil {\n\t\tfmt.Println(\"Use CI Passed!\")\n\t}\n\n\t// output:\n\t// Not Use CI Error: The Password value `Goframe.org` must be the same as field Password2 value `goframe.org`\n\t// Use CI Passed!\n}\n\nfunc ExampleValidator_Data() {\n\ttype BizReq struct {\n\t\tPassword1 string `v:\"password\"`\n\t\tPassword2 string `v:\"password\"`\n\t}\n\n\tvar (\n\t\tctx = context.Background()\n\t\treq = BizReq{\n\t\t\tPassword1: \"goframe\",\n\t\t\tPassword2: \"gofra\", // error length between 6 and 18\n\t\t}\n\t)\n\tif err := g.Validator().Data(req).Run(ctx); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Password2 value `gofra` is not a valid password format\n}\n\nfunc ExampleValidator_Data_value() {\n\terr := g.Validator().Rules(\"min:18\").\n\t\tMessages(\"未成年人不允许注册哟\").\n\t\tData(16).Run(gctx.New())\n\tfmt.Println(err.String())\n\n\t// Output:\n\t// 未成年人不允许注册哟\n}\n\nfunc ExampleValidator_Data_map1() {\n\tparams := map[string]any{\n\t\t\"passport\":  \"\",\n\t\t\"password\":  \"123456\",\n\t\t\"password2\": \"1234567\",\n\t}\n\trules := []string{\n\t\t\"passport@required|length:6,16#账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\"password@required|length:6,16|same{password}2#密码不能为空|密码长度应当在{min}到{max}之间|两次密码输入不相等\",\n\t\t\"password2@required|length:6,16#\",\n\t}\n\tif e := g.Validator().Data(params).Rules(rules).Run(gctx.New()); e != nil {\n\t\tfmt.Println(e.Map())\n\t\tfmt.Println(e.FirstItem())\n\t\tfmt.Println(e.FirstError())\n\t}\n\t// May Output:\n\t// map[required:The passport field is required length:The passport value `` length must be between 6 and 16]\n\t// passport map[required:The passport field is required length:The passport value `` length must be between 6 and 16]\n\t// The passport field is required\n}\n\nfunc ExampleValidator_Data_map2() {\n\tparams := map[string]any{\n\t\t\"passport\":  \"\",\n\t\t\"password\":  \"123456\",\n\t\t\"password2\": \"1234567\",\n\t}\n\trules := []string{\n\t\t\"passport@length:6,16#账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\"password@required|length:6,16|same:password2#密码不能为空|密码长度应当在{min}到{max}之间|两次密码输入不相等\",\n\t\t\"password2@required|length:6,16#\",\n\t}\n\tif e := g.Validator().Data(params).Rules(rules).Run(gctx.New()); e != nil {\n\t\tfmt.Println(e.Map())\n\t\tfmt.Println(e.FirstItem())\n\t\tfmt.Println(e.FirstError())\n\t}\n\t// Output:\n\t// map[same:两次密码输入不相等]\n\t// password map[same:两次密码输入不相等]\n\t// 两次密码输入不相等\n}\n\nfunc ExampleValidator_Data_map3() {\n\tparams := map[string]any{\n\t\t\"passport\":  \"\",\n\t\t\"password\":  \"123456\",\n\t\t\"password2\": \"1234567\",\n\t}\n\trules := map[string]string{\n\t\t\"passport\":  \"required|length:6,16\",\n\t\t\"password\":  \"required|length:6,16|same:password2\",\n\t\t\"password2\": \"required|length:6,16\",\n\t}\n\tmessages := map[string]any{\n\t\t\"passport\": \"账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\"password\": map[string]string{\n\t\t\t\"required\": \"密码不能为空\",\n\t\t\t\"same\":     \"两次密码输入不相等\",\n\t\t},\n\t}\n\terr := g.Validator().\n\t\tMessages(messages).\n\t\tRules(rules).\n\t\tData(params).Run(gctx.New())\n\tif err != nil {\n\t\tg.Dump(err.Maps())\n\t}\n\n\t// May Output:\n\t// {\n\t//\t\"passport\": {\n\t//\t\"length\": \"The passport value `` length must be between 6 and 16\",\n\t//\t\t\"required\": \"The passport field is required\"\n\t// },\n\t//\t\"password\": {\n\t//\t\"same\": \"The password value `123456` must be the same as field password2 value `1234567`\"\n\t// }\n\t// }\n}\n\n// Empty string attribute.\nfunc ExampleValidator_Data_struct1() {\n\ttype Params struct {\n\t\tPage      int    `v:\"required|min:1         # page is required\"`\n\t\tSize      int    `v:\"required|between:1,100 # size is required\"`\n\t\tProjectId string `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t}\n\tobj := &Params{\n\t\tPage: 1,\n\t\tSize: 10,\n\t}\n\terr := g.Validator().Data(obj).Run(gctx.New())\n\tfmt.Println(err == nil)\n\t// Output:\n\t// true\n}\n\n// Empty pointer attribute.\nfunc ExampleValidator_Data_struct2() {\n\ttype Params struct {\n\t\tPage      int       `v:\"required|min:1         # page is required\"`\n\t\tSize      int       `v:\"required|between:1,100 # size is required\"`\n\t\tProjectId *gvar.Var `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t}\n\tobj := &Params{\n\t\tPage: 1,\n\t\tSize: 10,\n\t}\n\terr := g.Validator().Data(obj).Run(gctx.New())\n\tfmt.Println(err == nil)\n\t// Output:\n\t// true\n}\n\n// Empty integer attribute.\nfunc ExampleValidator_Data_struct3() {\n\ttype Params struct {\n\t\tPage      int `v:\"required|min:1         # page is required\"`\n\t\tSize      int `v:\"required|between:1,100 # size is required\"`\n\t\tProjectId int `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t}\n\tobj := &Params{\n\t\tPage: 1,\n\t\tSize: 10,\n\t}\n\terr := g.Validator().Data(obj).Run(gctx.New())\n\tfmt.Println(err)\n\t// Output:\n\t// project id must between 1, 10000\n}\n\nfunc ExampleValidator_Data_struct4() {\n\ttype User struct {\n\t\tName string `v:\"required#请输入用户姓名\"`\n\t\tType int    `v:\"required#请选择用户类型\"`\n\t}\n\tdata := g.Map{\n\t\t\"name\": \"john\",\n\t}\n\tuser := User{}\n\tif err := gconv.Scan(data, &user); err != nil {\n\t\tpanic(err)\n\t}\n\terr := g.Validator().Data(user).Assoc(data).Run(gctx.New())\n\tif err != nil {\n\t\tfmt.Println(err.Items())\n\t}\n\n\t// Output:\n\t// [map[Type:map[required:请选择用户类型]]]\n}\n\nfunc ExampleValidator_Assoc() {\n\ttype User struct {\n\t\tName string `v:\"required\"`\n\t\tType int    `v:\"required\"`\n\t}\n\tdata := g.Map{\n\t\t\"name\": \"john\",\n\t}\n\tuser := User{}\n\n\tif err := gconv.Scan(data, &user); err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := g.Validator().Data(user).Assoc(data).Run(context.Background()); err != nil {\n\t\tfmt.Print(err)\n\t}\n\n\t// Output:\n\t// The Type field is required\n}\n\nfunc ExampleValidator_Rules() {\n\tif err := g.Validator().Data(16).Rules(\"min:18\").Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// The value `16` must be equal or greater than 18\n}\n\nfunc ExampleValidator_Messages() {\n\tif err := g.Validator().Data(16).Rules(\"min:18\").Messages(\"Can not regist, Age is less then 18!\").Run(context.Background()); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// Can not regist, Age is less then 18!\n}\n\nfunc ExampleValidator_RuleFunc() {\n\tvar (\n\t\tctx             = context.Background()\n\t\tlenErrRuleName  = \"LenErr\"\n\t\tpassErrRuleName = \"PassErr\"\n\t\tlenErrRuleFunc  = func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\tpass := in.Value.String()\n\t\t\tif len(pass) != 6 {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tpassErrRuleFunc = func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\tpass := in.Value.String()\n\t\t\tif m := in.Data.Map(); m[\"data\"] != pass {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t)\n\n\ttype LenErrStruct struct {\n\t\tValue string `v:\"uid@LenErr#Value Length Error!\"`\n\t\tData  string `p:\"data\"`\n\t}\n\n\tst := &LenErrStruct{\n\t\tValue: \"123\",\n\t\tData:  \"123456\",\n\t}\n\t// single error sample\n\tif err := g.Validator().RuleFunc(lenErrRuleName, lenErrRuleFunc).Data(st).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\ttype MultiErrorStruct struct {\n\t\tValue string `v:\"uid@LenErr|PassErr#Value Length Error!|Pass is not Same!\"`\n\t\tData  string `p:\"data\"`\n\t}\n\n\tmulti := &MultiErrorStruct{\n\t\tValue: \"123\",\n\t\tData:  \"123456\",\n\t}\n\t// multi error sample\n\tif err := g.Validator().RuleFunc(lenErrRuleName, lenErrRuleFunc).RuleFunc(passErrRuleName, passErrRuleFunc).Data(multi).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// Value Length Error!\n\t// Value Length Error!; Pass is not Same!\n}\n\nfunc ExampleValidator_RuleFuncMap() {\n\tvar (\n\t\tctx             = context.Background()\n\t\tlenErrRuleName  = \"LenErr\"\n\t\tpassErrRuleName = \"PassErr\"\n\t\tlenErrRuleFunc  = func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\tpass := in.Value.String()\n\t\t\tif len(pass) != 6 {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tpassErrRuleFunc = func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\tpass := in.Value.String()\n\t\t\tif m := in.Data.Map(); m[\"data\"] != pass {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\truleMap = map[string]gvalid.RuleFunc{\n\t\t\tlenErrRuleName:  lenErrRuleFunc,\n\t\t\tpassErrRuleName: passErrRuleFunc,\n\t\t}\n\t)\n\n\ttype MultiErrorStruct struct {\n\t\tValue string `v:\"uid@LenErr|PassErr#Value Length Error!|Pass is not Same!\"`\n\t\tData  string `p:\"data\"`\n\t}\n\n\tmulti := &MultiErrorStruct{\n\t\tValue: \"123\",\n\t\tData:  \"123456\",\n\t}\n\n\tif err := g.Validator().RuleFuncMap(ruleMap).Data(multi).Run(ctx); err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t// Output:\n\t// Value Length Error!; Pass is not Same!\n}\n\nfunc ExampleValidator_registerRule() {\n\ttype User struct {\n\t\tId   int\n\t\tName string `v:\"required|unique-name # 请输入用户名称|用户名称已被占用\"`\n\t\tPass string `v:\"required|length:6,18\"`\n\t}\n\tuser := &User{\n\t\tId:   1,\n\t\tName: \"john\",\n\t\tPass: \"123456\",\n\t}\n\n\trule := \"unique-name\"\n\tgvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\tvar (\n\t\t\tid   = in.Data.Val().(*User).Id\n\t\t\tname = gconv.String(in.Value)\n\t\t)\n\t\tn, err := g.Model(\"user\").Where(\"id != ? and name = ?\", id, name).Count()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif n > 0 {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t})\n\terr := g.Validator().Data(user).Run(gctx.New())\n\tfmt.Println(err.Error())\n\t// May Output:\n\t// The Name value `john` is not unique\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_checkmap_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nfunc Test_CheckMap1(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tdata := map[string]any{\n\t\t\t\"id\":   \"0\",\n\t\t\t\"name\": \"john\",\n\t\t}\n\t\trules := map[string]string{\n\t\t\t\"id\":   \"required|between:1,100\",\n\t\t\t\"name\": \"required|length:6,16\",\n\t\t}\n\t\tif m := g.Validator().Data(data).Rules(rules).Run(context.TODO()); m == nil {\n\t\t\tt.Error(\"CheckMap校验失败\")\n\t\t} else {\n\t\t\tt.Assert(len(m.Maps()), 2)\n\t\t\tt.Assert(m.Maps()[\"id\"][\"between\"], \"The id value `0` must be between 1 and 100\")\n\t\t\tt.Assert(m.Maps()[\"name\"][\"length\"], \"The name value `john` length must be between 6 and 16\")\n\t\t}\n\t})\n}\n\nfunc Test_CheckMap2(t *testing.T) {\n\tvar params any\n\tgtest.C(t, func(t *gtest.T) {\n\t\tif err := g.Validator().Data(params).Run(context.TODO()); err == nil {\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\n\tkvmap := map[string]any{\n\t\t\"id\":   \"0\",\n\t\t\"name\": \"john\",\n\t}\n\trules := map[string]string{\n\t\t\"id\":   \"required|between:1,100\",\n\t\t\"name\": \"required|length:6,16\",\n\t}\n\tmsgs := gvalid.CustomMsg{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules).Messages(msgs).Run(context.TODO()); m == nil {\n\t\tt.Error(\"CheckMap校验失败\")\n\t}\n\n\tkvmap = map[string]any{\n\t\t\"id\":   \"1\",\n\t\t\"name\": \"john\",\n\t}\n\trules = map[string]string{\n\t\t\"id\":   \"required|between:1,100\",\n\t\t\"name\": \"required|length:4,16\",\n\t}\n\tmsgs = map[string]any{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules).Messages(msgs).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n\n\tkvmap = map[string]any{\n\t\t\"id\":   \"1\",\n\t\t\"name\": \"john\",\n\t}\n\trules = map[string]string{\n\t\t\"id\":   \"\",\n\t\t\"name\": \"\",\n\t}\n\tmsgs = map[string]any{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules).Messages(msgs).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n\n\tkvmap = map[string]any{\n\t\t\"id\":   \"1\",\n\t\t\"name\": \"john\",\n\t}\n\trules2 := []string{\n\t\t\"@required|between:1,100\",\n\t\t\"@required|length:4,16\",\n\t}\n\tmsgs = map[string]any{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules2).Messages(msgs).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n\n\tkvmap = map[string]any{\n\t\t\"id\":   \"1\",\n\t\t\"name\": \"john\",\n\t}\n\trules2 = []string{\n\t\t\"id@required|between:1,100\",\n\t\t\"name@required|length:4,16#名称不能为空|\",\n\t}\n\tmsgs = map[string]any{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules2).Messages(msgs).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n\n\tkvmap = map[string]any{\n\t\t\"id\":   \"1\",\n\t\t\"name\": \"john\",\n\t}\n\trules2 = []string{\n\t\t\"id@required|between:1,100\",\n\t\t\"name@required|length:4,16#名称不能为空\",\n\t}\n\tmsgs = map[string]any{\n\t\t\"id\": \"ID不能为空|ID范围应当为{min}到{max}\",\n\t\t\"name\": map[string]string{\n\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t},\n\t}\n\tif m := g.Validator().Data(kvmap).Rules(rules2).Messages(msgs).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n}\n\nfunc Test_CheckMapWithNilAndNotRequiredField(t *testing.T) {\n\tdata := map[string]any{\n\t\t\"id\": \"1\",\n\t}\n\trules := map[string]string{\n\t\t\"id\":   \"required\",\n\t\t\"name\": \"length:4,16\",\n\t}\n\tif m := g.Validator().Data(data).Rules(rules).Run(context.TODO()); m != nil {\n\t\tt.Error(m)\n\t}\n}\n\nfunc Test_Sequence(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tparams := map[string]any{\n\t\t\t\"passport\":  \"\",\n\t\t\t\"password\":  \"123456\",\n\t\t\t\"password2\": \"1234567\",\n\t\t}\n\t\trules := []string{\n\t\t\t\"passport@required|length:6,16#账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\t\"password@required|length:6,16|same:password2#密码不能为空|密码长度应当在{min}到{max}之间|两次密码输入不相等\",\n\t\t\t\"password2@required|length:6,16#\",\n\t\t}\n\t\terr := g.Validator().Data(params).Rules(rules).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Map()), 2)\n\t\tt.Assert(err.Map()[\"required\"], \"账号不能为空\")\n\t\tt.Assert(err.Map()[\"length\"], \"账号长度应当在6到16之间\")\n\t\tt.Assert(len(err.Maps()), 2)\n\n\t\tt.Assert(len(err.Items()), 2)\n\t\tt.Assert(err.Items()[0][\"passport\"][\"length\"], \"账号长度应当在6到16之间\")\n\t\tt.Assert(err.Items()[0][\"passport\"][\"required\"], \"账号不能为空\")\n\t\tt.Assert(err.Items()[1][\"password\"][\"same\"], \"两次密码输入不相等\")\n\n\t\tt.Assert(err.String(), \"账号不能为空; 账号长度应当在6到16之间; 两次密码输入不相等\")\n\t\tt.Assert(err.Strings(), []string{\"账号不能为空\", \"账号长度应当在6到16之间\", \"两次密码输入不相等\"})\n\n\t\tk, m := err.FirstItem()\n\t\tt.Assert(k, \"passport\")\n\t\tt.Assert(m, err.Map())\n\n\t\tr, s := err.FirstRule()\n\t\tt.Assert(r, \"required\")\n\t\tt.Assert(s, \"账号不能为空\")\n\n\t\tt.Assert(gerror.Current(err), \"账号不能为空\")\n\t})\n}\n\nfunc Test_Map_Bail(t *testing.T) {\n\t// global bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\tparams := map[string]any{\n\t\t\t\"passport\":  \"\",\n\t\t\t\"password\":  \"123456\",\n\t\t\t\"password2\": \"1234567\",\n\t\t}\n\t\trules := []string{\n\t\t\t\"passport@required|length:6,16#账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\t\"password@required|length:6,16|same:password2#密码不能为空|密码长度应当在{min}到{max}之间|两次密码输入不相等\",\n\t\t\t\"password2@required|length:6,16#\",\n\t\t}\n\t\terr := g.Validator().Bail().Rules(rules).Data(params).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.String(), \"账号不能为空\")\n\t})\n\t// global bail with rule bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\tparams := map[string]any{\n\t\t\t\"passport\":  \"\",\n\t\t\t\"password\":  \"123456\",\n\t\t\t\"password2\": \"1234567\",\n\t\t}\n\t\trules := []string{\n\t\t\t\"passport@bail|required|length:6,16#|账号不能为空|账号长度应当在{min}到{max}之间\",\n\t\t\t\"password@required|length:6,16|same:password2#密码不能为空|密码长度应当在{min}到{max}之间|两次密码输入不相等\",\n\t\t\t\"password2@required|length:6,16#\",\n\t\t}\n\t\terr := g.Validator().Bail().Rules(rules).Data(params).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.String(), \"账号不能为空\")\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_checkstruct_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\nfunc Test_CheckStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Object struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\trules := []string{\n\t\t\t\"@required|length:6,16\",\n\t\t\t\"@between:18,30\",\n\t\t}\n\t\tmsgs := map[string]any{\n\t\t\t\"Name\": map[string]string{\n\t\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t\t},\n\t\t\t\"Age\": \"年龄为18到30周岁\",\n\t\t}\n\t\tobj := &Object{\"john\", 16}\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Object struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\trules := []string{\n\t\t\t\"Name@required|length:6,16#名称不能为空\",\n\t\t\t\"Age@between:18,30\",\n\t\t}\n\t\tmsgs := map[string]any{\n\t\t\t\"Name\": map[string]string{\n\t\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t\t},\n\t\t\t\"Age\": \"年龄为18到30周岁\",\n\t\t}\n\t\tobj := &Object{\"john\", 16}\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 2)\n\t\tt.Assert(err.Maps()[\"Name\"][\"required\"], \"\")\n\t\tt.Assert(err.Maps()[\"Name\"][\"length\"], \"名称长度为6到16个字符\")\n\t\tt.Assert(err.Maps()[\"Age\"][\"between\"], \"年龄为18到30周岁\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Object struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\trules := []string{\n\t\t\t\"Name@required|length:6,16#名称不能为空|\",\n\t\t\t\"Age@between:18,30\",\n\t\t}\n\t\tmsgs := map[string]any{\n\t\t\t\"Name\": map[string]string{\n\t\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t\t},\n\t\t\t\"Age\": \"年龄为18到30周岁\",\n\t\t}\n\t\tobj := &Object{\"john\", 16}\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 2)\n\t\tt.Assert(err.Maps()[\"Name\"][\"required\"], \"\")\n\t\tt.Assert(err.Maps()[\"Name\"][\"length\"], \"名称长度为6到16个字符\")\n\t\tt.Assert(err.Maps()[\"Age\"][\"between\"], \"年龄为18到30周岁\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Object struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}\n\t\trules := map[string]string{\n\t\t\t\"Name\": \"required|length:6,16\",\n\t\t\t\"Age\":  \"between:18,30\",\n\t\t}\n\t\tmsgs := map[string]any{\n\t\t\t\"Name\": map[string]string{\n\t\t\t\t\"required\": \"名称不能为空\",\n\t\t\t\t\"length\":   \"名称长度为{min}到{max}个字符\",\n\t\t\t},\n\t\t\t\"Age\": \"年龄为18到30周岁\",\n\t\t}\n\t\tobj := &Object{\"john\", 16}\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(msgs).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 2)\n\t\tt.Assert(err.Maps()[\"Name\"][\"required\"], \"\")\n\t\tt.Assert(err.Maps()[\"Name\"][\"length\"], \"名称长度为6到16个字符\")\n\t\tt.Assert(err.Maps()[\"Age\"][\"between\"], \"年龄为18到30周岁\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype LoginRequest struct {\n\t\t\tUsername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tvar login LoginRequest\n\t\terr := g.Validator().Data(login).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 2)\n\t\tt.Assert(err.Maps()[\"username\"][\"required\"], \"用户名不能为空\")\n\t\tt.Assert(err.Maps()[\"password\"][\"required\"], \"登录密码不能为空\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype LoginRequest struct {\n\t\t\tUsername string `json:\"username\" valid:\"@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"@required#登录密码不能为空\"`\n\t\t}\n\t\tvar login LoginRequest\n\t\terr := g.Validator().Data(login).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype LoginRequest struct {\n\t\t\tusername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tvar login LoginRequest\n\t\terr := g.Validator().Data(login).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"password\"][\"required\"], \"登录密码不能为空\")\n\t})\n\n\t// gvalid tag\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `valid:\"uid@required|min:10#|ID不能为空\"`\n\t\t\tAge      int    `valid:\"age@required#年龄不能为空\"`\n\t\t\tUsername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tUsername: \"john\",\n\t\t\tPassword: \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(user).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 1)\n\t\tt.Assert(err.Maps()[\"uid\"][\"min\"], \"ID不能为空\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `valid:\"uid@required|min:10#|ID不能为空\"`\n\t\t\tAge      int    `valid:\"age@required#年龄不能为空\"`\n\t\t\tUsername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tUsername: \"john\",\n\t\t\tPassword: \"123456\",\n\t\t}\n\n\t\trules := []string{\n\t\t\t\"username@required#用户名不能为空\",\n\t\t}\n\n\t\terr := g.Validator().Data(user).Rules(rules).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 1)\n\t\tt.Assert(err.Maps()[\"uid\"][\"min\"], \"ID不能为空\")\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `valid:\"uid@required|min:10#ID不能为空\"`\n\t\t\tAge      int    `valid:\"age@required#年龄不能为空\"`\n\t\t\tUsername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tUsername: \"john\",\n\t\t\tPassword: \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(user).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 1)\n\t})\n\n\t// valid tag\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype User struct {\n\t\t\tId       int    `valid:\"uid@required|min:10#|ID不能为空\"`\n\t\t\tAge      int    `valid:\"age@required#年龄不能为空\"`\n\t\t\tUsername string `json:\"username\" valid:\"username@required#用户名不能为空\"`\n\t\t\tPassword string `json:\"password\" valid:\"password@required#登录密码不能为空\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tId:       1,\n\t\t\tUsername: \"john\",\n\t\t\tPassword: \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(user).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(len(err.Maps()), 1)\n\t\tt.Assert(err.Maps()[\"uid\"][\"min\"], \"ID不能为空\")\n\t})\n}\n\nfunc Test_CheckStruct_EmbeddedObject_Attribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tTime *gtime.Time\n\t\t}\n\t\ttype Object struct {\n\t\t\tBase\n\t\t\tName string\n\t\t\tType int\n\t\t}\n\t\trules := map[string]string{\n\t\t\t\"Name\": \"required\",\n\t\t\t\"Type\": \"required\",\n\t\t}\n\t\truleMsg := map[string]any{\n\t\t\t\"Name\": \"名称必填\",\n\t\t\t\"Type\": \"类型必填\",\n\t\t}\n\t\tobj := &Object{}\n\t\tobj.Type = 1\n\t\tobj.Name = \"john\"\n\t\tobj.Time = gtime.Now()\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(ruleMsg).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Base struct {\n\t\t\tName string\n\t\t\tType int\n\t\t}\n\t\ttype Object struct {\n\t\t\tBase Base\n\t\t\tName string\n\t\t\tType int\n\t\t}\n\t\trules := map[string]string{\n\t\t\t\"Name\": \"required\",\n\t\t\t\"Type\": \"required\",\n\t\t}\n\t\truleMsg := map[string]any{\n\t\t\t\"Name\": \"名称必填\",\n\t\t\t\"Type\": \"类型必填\",\n\t\t}\n\t\tobj := &Object{}\n\t\tobj.Type = 1\n\t\tobj.Name = \"john\"\n\t\terr := g.Validator().Data(obj).Rules(rules).Messages(ruleMsg).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_CheckStruct_With_EmbeddedObject(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `valid:\"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致\"`\n\t\t\tPass2 string `valid:\"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `valid:\"name@required#请输入您的姓名\"`\n\t\t\tPass\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPass: Pass{\n\t\t\t\tPass1: \"1\",\n\t\t\t\tPass2: \"2\",\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"name\"], g.Map{\"required\": \"请输入您的姓名\"})\n\t\tt.Assert(err.Maps()[\"password1\"], g.Map{\"same\": \"您两次输入的密码不一致\"})\n\t\tt.Assert(err.Maps()[\"password2\"], g.Map{\"same\": \"您两次输入的密码不一致\"})\n\t})\n}\n\nfunc Test_CheckStruct_With_StructAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `valid:\"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致\"`\n\t\t\tPass2 string `valid:\"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tPass\n\t\t\tId   int\n\t\t\tName string `valid:\"name@required#请输入您的姓名\"`\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPass: Pass{\n\t\t\t\tPass1: \"1\",\n\t\t\t\tPass2: \"2\",\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"name\"], g.Map{\"required\": \"请输入您的姓名\"})\n\t\tt.Assert(err.Maps()[\"password1\"], g.Map{\"same\": \"您两次输入的密码不一致\"})\n\t\tt.Assert(err.Maps()[\"password2\"], g.Map{\"same\": \"您两次输入的密码不一致\"})\n\t})\n}\n\nfunc Test_CheckStruct_Optional(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage      int    `v:\"required|min:1         # page is required\"`\n\t\t\tSize      int    `v:\"required|between:1,100 # size is required\"`\n\t\t\tProjectId string `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: 10,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage      int       `v:\"required|min:1         # page is required\"`\n\t\t\tSize      int       `v:\"required|between:1,100 # size is required\"`\n\t\t\tProjectId *gvar.Var `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: 10,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage      int `v:\"required|min:1         # page is required\"`\n\t\t\tSize      int `v:\"required|between:1,100 # size is required\"`\n\t\t\tProjectId int `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: 10,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(context.TODO())\n\t\tt.Assert(err.String(), \"project id must between 1, 10000\")\n\t})\n}\n\nfunc Test_CheckStruct_NoTag(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage      int\n\t\t\tSize      int\n\t\t\tProjectId string\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: 10,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(context.TODO())\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_CheckStruct_InvalidRule(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tName  string\n\t\t\tAge   uint\n\t\t\tPhone string `v:\"mobile\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tName:  \"john\",\n\t\t\tAge:   18,\n\t\t\tPhone: \"123\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(context.TODO())\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc TestValidator_CheckStructWithData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid      int64  `v:\"required\"`\n\t\t\tNickname string `v:\"required-with:uid\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tUid:      1,\n\t\t\tNickname: \"john\",\n\t\t}\n\t\tt.Assert(\n\t\t\tg.Validator().Data(data).Assoc(\n\t\t\t\tg.Map{\"uid\": 1, \"nickname\": \"john\"},\n\t\t\t).Run(context.TODO()),\n\t\t\tnil,\n\t\t)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid      int64  `v:\"required\"`\n\t\t\tNickname string `v:\"required-with:uid\"`\n\t\t}\n\t\tdata := UserApiSearch{}\n\t\tt.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid      int64  `json:\"uid\" v:\"required\"`\n\t\t\tNickname string `json:\"nickname\" v:\"required-with:Uid\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tUid: 1,\n\t\t}\n\t\tt.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid       int64       `json:\"uid\"`\n\t\t\tNickname  string      `json:\"nickname\" v:\"required-with:Uid\"`\n\t\t\tStartTime *gtime.Time `json:\"start_time\" v:\"required-with:EndTime\"`\n\t\t\tEndTime   *gtime.Time `json:\"end_time\" v:\"required-with:StartTime\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tStartTime: nil,\n\t\t\tEndTime:   nil,\n\t\t}\n\t\tt.Assert(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid       int64       `json:\"uid\"`\n\t\t\tNickname  string      `json:\"nickname\" v:\"required-with:Uid\"`\n\t\t\tStartTime *gtime.Time `json:\"start_time\" v:\"required-with:EndTime\"`\n\t\t\tEndTime   *gtime.Time `json:\"end_time\" v:\"required-with:StartTime\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tStartTime: gtime.Now(),\n\t\t\tEndTime:   nil,\n\t\t}\n\t\tt.AssertNE(g.Validator().Data(data).Assoc(g.Map{\"start_time\": gtime.Now()}).Run(context.TODO()), nil)\n\t})\n}\n\nfunc Test_CheckStruct_PointerAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Req struct {\n\t\t\tName string\n\t\t\tAge  *uint `v:\"min:18\"`\n\t\t}\n\t\treq := &Req{\n\t\t\tName: \"john\",\n\t\t\tAge:  gconv.PtrUint(0),\n\t\t}\n\t\terr := g.Validator().Data(req).Run(context.TODO())\n\t\tt.Assert(err.String(), \"The Age value `0` must be equal or greater than 18\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Req struct {\n\t\t\tName string `v:\"min-length:3\"`\n\t\t\tAge  *uint  `v:\"min:18\"`\n\t\t}\n\t\treq := &Req{\n\t\t\tName: \"j\",\n\t\t\tAge:  gconv.PtrUint(19),\n\t\t}\n\t\terr := g.Validator().Data(req).Run(context.TODO())\n\t\tt.Assert(err.String(), \"The Name value `j` length must be equal or greater than 3\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tAge *uint `v:\"min:18\"`\n\t\t}\n\t\ttype Req struct {\n\t\t\tName   string\n\t\t\tParams *Params\n\t\t}\n\t\treq := &Req{\n\t\t\tName: \"john\",\n\t\t\tParams: &Params{\n\t\t\t\tAge: gconv.PtrUint(0),\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(req).Run(context.TODO())\n\t\tt.Assert(err.String(), \"The Age value `0` must be equal or greater than 18\")\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_ci_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_CI(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"id\").Rules(\"in:Id,Name\").Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"id\").Rules(\"ci|in:Id,Name\").Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Ci().Rules(\"in:Id,Name\").Data(\"id\").Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_custom_error_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_Map(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\trule = \"ipv4\"\n\t\t\tval  = \"0.0.0\"\n\t\t\terr  = g.Validator().Data(val).Rules(rule).Run(context.TODO())\n\t\t\tmsg  = map[string]string{\n\t\t\t\t\"ipv4\": \"The value `0.0.0` is not a valid IPv4 address\",\n\t\t\t}\n\t\t)\n\t\tt.Assert(err.Map(), msg)\n\t})\n}\n\nfunc Test_FirstString(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar (\n\t\t\trule = \"ipv4\"\n\t\t\tval  = \"0.0.0\"\n\t\t\terr  = g.Validator().Data(val).Rules(rule).Run(context.TODO())\n\t\t)\n\t\tt.Assert(err.FirstError(), \"The value `0.0.0` is not a valid IPv4 address\")\n\t})\n}\n\nfunc Test_CustomError1(t *testing.T) {\n\trule := \"integer|length:6,16\"\n\tmsgs := map[string]string{\n\t\t\"integer\": \"请输入一个整数\",\n\t\t\"length\":  \"参数长度不对啊老铁\",\n\t}\n\te := g.Validator().Data(\"6.66\").Rules(rule).Messages(msgs).Run(context.TODO())\n\tif e == nil || len(e.Map()) != 2 {\n\t\tt.Error(\"规则校验失败\")\n\t} else {\n\t\tif v, ok := e.Map()[\"integer\"]; ok {\n\t\t\tif strings.Compare(v.Error(), msgs[\"integer\"]) != 0 {\n\t\t\t\tt.Error(\"错误信息不匹配\")\n\t\t\t}\n\t\t}\n\t\tif v, ok := e.Map()[\"length\"]; ok {\n\t\t\tif strings.Compare(v.Error(), msgs[\"length\"]) != 0 {\n\t\t\t\tt.Error(\"错误信息不匹配\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc Test_CustomError2(t *testing.T) {\n\trule := \"integer|length:6,16\"\n\tmsgs := \"请输入一个整数|参数长度不对啊老铁\"\n\te := g.Validator().Data(\"6.66\").Rules(rule).Messages(msgs).Run(context.TODO())\n\tif e == nil || len(e.Map()) != 2 {\n\t\tt.Error(\"规则校验失败\")\n\t} else {\n\t\tif v, ok := e.Map()[\"integer\"]; ok {\n\t\t\tif strings.Compare(v.Error(), \"请输入一个整数\") != 0 {\n\t\t\t\tt.Error(\"错误信息不匹配\")\n\t\t\t}\n\t\t}\n\t\tif v, ok := e.Map()[\"length\"]; ok {\n\t\t\tif strings.Compare(v.Error(), \"参数长度不对啊老铁\") != 0 {\n\t\t\t\tt.Error(\"错误信息不匹配\")\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_custom_rule_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nfunc Test_CustomRule1(t *testing.T) {\n\trule := \"custom\"\n\tgvalid.RegisterRule(\n\t\trule,\n\t\tfunc(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\tpass := in.Value.String()\n\t\t\tif len(pass) != 6 {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\tm := in.Data.Map()\n\t\t\tif m[\"data\"] != pass {\n\t\t\t\treturn errors.New(in.Message)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"123456\").Rules(rule).Messages(\"custom message\").Run(ctx)\n\t\tt.Assert(err.String(), \"custom message\")\n\t\terr = g.Validator().Data(\"123456\").Assoc(g.Map{\"data\": \"123456\"}).Rules(rule).Messages(\"custom message\").Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\t// Error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n\t// No error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123456\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_CustomRule2(t *testing.T) {\n\trule := \"required-map\"\n\tgvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\tm := in.Value.Map()\n\t\tif len(m) == 0 {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t})\n\t// Check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrStr := \"data map should not be empty\"\n\t\tt.Assert(g.Validator().Data(g.Map{}).Messages(errStr).Rules(rule).Run(ctx), errStr)\n\t\tt.Assert(g.Validator().Data(g.Map{\"k\": \"v\"}).Rules(rule).Messages(errStr).Run(ctx), nil)\n\t})\n\t// Error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue map[string]string `v:\"uid@required-map#自定义错误\"`\n\t\t\tData  string            `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: map[string]string{},\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n\t// No error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue map[string]string `v:\"uid@required-map#自定义错误\"`\n\t\t\tData  string            `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: map[string]string{\"k\": \"v\"},\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_CustomRule_AllowEmpty(t *testing.T) {\n\trule := \"allow-empty-str\"\n\tgvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\ts := in.Value.String()\n\t\tif len(s) == 0 || s == \"gf\" {\n\t\t\treturn nil\n\t\t}\n\t\treturn errors.New(in.Message)\n\t})\n\t// Check.\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrStr := \"error\"\n\t\tt.Assert(g.Validator().Data(\"\").Rules(rule).Messages(errStr).Run(ctx), \"\")\n\t\tt.Assert(g.Validator().Data(\"gf\").Rules(rule).Messages(errStr).Run(ctx), \"\")\n\t\tt.Assert(g.Validator().Data(\"gf2\").Rules(rule).Messages(errStr).Run(ctx), errStr)\n\t})\n\t// Error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@allow-empty-str#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\t// No error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@allow-empty-str#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"john\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().Data(st).Run(ctx)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n}\n\nfunc TestValidator_RuleFunc(t *testing.T) {\n\truleName := \"custom_1\"\n\truleFunc := func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\tpass := in.Value.String()\n\t\tif len(pass) != 6 {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\tif m := in.Data.Map(); m[\"data\"] != pass {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Rules(ruleName).\n\t\t\tMessages(\"custom message\").\n\t\t\tRuleFunc(ruleName, ruleFunc).\n\t\t\tData(\"123456\").\n\t\t\tRun(ctx)\n\t\tt.Assert(err.String(), \"custom message\")\n\t\terr = g.Validator().\n\t\t\tRules(ruleName).\n\t\t\tMessages(\"custom message\").\n\t\t\tData(\"123456\").Assoc(g.Map{\"data\": \"123456\"}).\n\t\t\tRuleFunc(ruleName, ruleFunc).\n\t\t\tRun(ctx)\n\t\tt.AssertNil(err)\n\t})\n\t// Error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom_1#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().RuleFunc(ruleName, ruleFunc).Data(st).Run(ctx)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n\t// No error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom_1#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123456\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().RuleFunc(ruleName, ruleFunc).Data(st).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc TestValidator_RuleFuncMap(t *testing.T) {\n\truleName := \"custom_1\"\n\truleFunc := func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\tpass := in.Value.String()\n\t\tif len(pass) != 6 {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\tif m := in.Data.Map(); m[\"data\"] != pass {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().\n\t\t\tRules(ruleName).\n\t\t\tMessages(\"custom message\").\n\t\t\tRuleFuncMap(map[string]gvalid.RuleFunc{\n\t\t\t\truleName: ruleFunc,\n\t\t\t}).Data(\"123456\").Run(ctx)\n\t\tt.Assert(err.String(), \"custom message\")\n\t\terr = g.Validator().\n\t\t\tRules(ruleName).\n\t\t\tMessages(\"custom message\").\n\t\t\tData(\"123456\").Assoc(g.Map{\"data\": \"123456\"}).\n\t\t\tRuleFuncMap(map[string]gvalid.RuleFunc{\n\t\t\t\truleName: ruleFunc,\n\t\t\t}).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\t// Error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom_1#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().\n\t\t\tRuleFuncMap(map[string]gvalid.RuleFunc{\n\t\t\t\truleName: ruleFunc,\n\t\t\t}).Data(st).Run(ctx)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n\t// No error with struct validation.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@custom_1#自定义错误\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"123456\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().\n\t\t\tRuleFuncMap(map[string]gvalid.RuleFunc{\n\t\t\t\truleName: ruleFunc,\n\t\t\t}).Data(st).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_CustomRule_Overwrite(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tvar rule = \"custom-\" + guid.S()\n\t\tgvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\treturn gerror.New(\"1\")\n\t\t})\n\t\tt.Assert(g.Validator().Rules(rule).Data(1).Run(ctx), \"1\")\n\t\tgvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\t\treturn gerror.New(\"2\")\n\t\t})\n\t\tt.Assert(g.Validator().Rules(rule).Data(1).Run(ctx), \"2\")\n\t})\n\tg.Dump(gvalid.GetRegisteredRuleMap())\n}\n\nfunc Test_Issue2499(t *testing.T) {\n\truleName := \"required\"\n\truleFunc := func(ctx context.Context, in gvalid.RuleFuncInput) error {\n\t\treturn errors.New(in.Message)\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype T struct {\n\t\t\tValue string `v:\"uid@required\"`\n\t\t\tData  string `p:\"data\"`\n\t\t}\n\t\tst := &T{\n\t\t\tValue: \"\",\n\t\t\tData:  \"123456\",\n\t\t}\n\t\terr := g.Validator().\n\t\t\tRuleFuncMap(map[string]gvalid.RuleFunc{\n\t\t\t\truleName: ruleFunc,\n\t\t\t}).Data(st).Run(ctx)\n\t\tt.Assert(err.String(), `The uid field is required`)\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_i18n_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/i18n/gi18n\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\nfunc TestValidator_I18n(t *testing.T) {\n\tvar (\n\t\terr         gvalid.Error\n\t\ti18nManager = gi18n.New(gi18n.Options{Path: gtest.DataPath(\"i18n\")})\n\t\tctxCn       = gi18n.WithLanguage(context.TODO(), \"cn\")\n\t\tvalidator   = gvalid.New().I18n(i18nManager)\n\t)\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = validator.Rules(\"required\").Data(\"\").Run(ctx)\n\t\tt.Assert(err.String(), \"The field is required\")\n\n\t\terr = validator.Rules(\"required\").Data(\"\").Run(ctxCn)\n\t\tt.Assert(err.String(), \"字段不能为空\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr = validator.Rules(\"required\").Messages(\"CustomMessage\").Data(\"\").Run(ctxCn)\n\t\tt.Assert(err.String(), \"自定义错误\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage      int `v:\"required|min:1         # page is required\"`\n\t\t\tSize      int `v:\"required|between:1,100 # size is required\"`\n\t\t\tProjectId int `v:\"between:1,10000        # project id must between {min}, {max}\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: 10,\n\t\t}\n\t\terr = validator.Data(obj).Run(ctxCn)\n\t\tt.Assert(err.String(), \"项目ID必须大于等于1并且要小于等于10000\")\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_meta_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\ntype UserCreateReq struct {\n\tg.Meta `v:\"UserCreateReq\"`\n\tName   string\n\tPass   string\n}\n\nfunc RuleUserCreateReq(ctx context.Context, in gvalid.RuleFuncInput) error {\n\tvar req *UserCreateReq\n\tif err := in.Data.Scan(&req); err != nil {\n\t\treturn gerror.Wrap(err, `Scan data to UserCreateReq failed`)\n\t}\n\treturn gerror.Newf(`The name \"%s\" is already token by others`, req.Name)\n}\n\nfunc Test_Meta(t *testing.T) {\n\tvar user = &UserCreateReq{\n\t\tName: \"john\",\n\t\tPass: \"123456\",\n\t}\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().RuleFunc(\"UserCreateReq\", RuleUserCreateReq).\n\t\t\tData(user).\n\t\t\tAssoc(g.Map{\n\t\t\t\t\"Name\": \"john smith\",\n\t\t\t}).Run(ctx)\n\t\tt.Assert(err.String(), `The name \"john smith\" is already token by others`)\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_recursive_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_CheckStruct_Recursive_Struct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `v:\"required\"`\n\t\t\tPass Pass\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPass: Pass{\n\t\t\t\tPass1: \"1\",\n\t\t\t\tPass2: \"2\",\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], g.Map{\"required\": \"The Name field is required\"})\n\t\tt.Assert(err.Maps()[\"Pass1\"], g.Map{\"same\": \"The Pass1 value `1` must be the same as field Pass2 value `2`\"})\n\t\tt.Assert(err.Maps()[\"Pass2\"], g.Map{\"same\": \"The Pass2 value `2` must be the same as field Pass1 value `1`\"})\n\t})\n}\n\nfunc Test_CheckStruct_Recursive_Struct_WithData(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId   int\n\t\t\tName string `v:\"required\"`\n\t\t\tPass Pass\n\t\t}\n\t\tuser := &User{}\n\t\tdata := g.Map{\n\t\t\t\"Name\": \"john\",\n\t\t\t\"Pass\": g.Map{\n\t\t\t\t\"Pass1\": 100,\n\t\t\t\t\"Pass2\": 200,\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Assoc(data).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], nil)\n\t\tt.Assert(err.Maps()[\"Pass1\"], g.Map{\"same\": \"The Pass1 value `100` must be the same as field Pass2 value `200`\"})\n\t\tt.Assert(err.Maps()[\"Pass2\"], g.Map{\"same\": \"The Pass2 value `200` must be the same as field Pass1 value `100`\"})\n\t})\n}\n\nfunc Test_CheckStruct_Recursive_SliceStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId     int\n\t\t\tName   string `v:\"required\"`\n\t\t\tPasses []Pass\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPasses: []Pass{\n\t\t\t\t{\n\t\t\t\t\tPass1: \"1\",\n\t\t\t\t\tPass2: \"2\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPass1: \"3\",\n\t\t\t\t\tPass2: \"4\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(ctx)\n\t\tg.Dump(err.Items())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], g.Map{\"required\": \"The Name field is required\"})\n\t\tt.Assert(err.Maps()[\"Pass1\"], g.Map{\"same\": \"The Pass1 value `3` must be the same as field Pass2 value `4`\"})\n\t\tt.Assert(err.Maps()[\"Pass2\"], g.Map{\"same\": \"The Pass2 value `4` must be the same as field Pass1 value `3`\"})\n\t})\n}\n\nfunc Test_CheckStruct_Recursive_SliceStruct_Bail(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId     int\n\t\t\tName   string `v:\"required\"`\n\t\t\tPasses []Pass\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPasses: []Pass{\n\t\t\t\t{\n\t\t\t\t\tPass1: \"1\",\n\t\t\t\t\tPass2: \"2\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPass1: \"3\",\n\t\t\t\t\tPass2: \"4\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Bail().Data(user).Run(ctx)\n\t\tg.Dump(err.Items())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], nil)\n\t\tt.Assert(err.Maps()[\"Pass1\"], g.Map{\"same\": \"The Pass1 value `1` must be the same as field Pass2 value `2`\"})\n\t\tt.Assert(err.Maps()[\"Pass2\"], nil)\n\t})\n}\n\nfunc Test_CheckStruct_Recursive_SliceStruct_Required(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId     int\n\t\t\tName   string `v:\"required\"`\n\t\t\tPasses []Pass\n\t\t}\n\t\tuser := &User{}\n\t\terr := g.Validator().Data(user).Run(ctx)\n\t\tg.Dump(err.Items())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], g.Map{\"required\": \"The Name field is required\"})\n\t\tt.Assert(err.Maps()[\"Pass1\"], nil)\n\t\tt.Assert(err.Maps()[\"Pass2\"], nil)\n\t})\n}\n\nfunc Test_CheckStruct_Recursive_MapStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\ttype User struct {\n\t\t\tId     int\n\t\t\tName   string `v:\"required\"`\n\t\t\tPasses map[string]Pass\n\t\t}\n\t\tuser := &User{\n\t\t\tName: \"\",\n\t\t\tPasses: map[string]Pass{\n\t\t\t\t\"test1\": {\n\t\t\t\t\tPass1: \"1\",\n\t\t\t\t\tPass2: \"2\",\n\t\t\t\t},\n\t\t\t\t\"test2\": {\n\t\t\t\t\tPass1: \"3\",\n\t\t\t\t\tPass2: \"4\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(ctx)\n\t\tg.Dump(err.Items())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], g.Map{\"required\": \"The Name field is required\"})\n\t\tt.AssertNE(err.Maps()[\"Pass1\"], nil)\n\t\tt.AssertNE(err.Maps()[\"Pass2\"], nil)\n\t})\n}\n\nfunc Test_CheckMap_Recursive_SliceStruct(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Pass struct {\n\t\t\tPass1 string `v:\"required|same:Pass2\"`\n\t\t\tPass2 string `v:\"required|same:Pass1\"`\n\t\t}\n\t\tuser := g.Map{\n\t\t\t\"Name\": \"\",\n\t\t\t\"Pass\": []Pass{\n\t\t\t\t{\n\t\t\t\t\tPass1: \"1\",\n\t\t\t\t\tPass2: \"2\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPass1: \"3\",\n\t\t\t\t\tPass2: \"4\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\terr := g.Validator().Data(user).Run(ctx)\n\t\tg.Dump(err.Items())\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Maps()[\"Name\"], nil)\n\t\tt.Assert(err.Maps()[\"Pass1\"], g.Map{\"same\": \"The Pass1 value `3` must be the same as field Pass2 value `4`\"})\n\t\tt.Assert(err.Maps()[\"Pass2\"], g.Map{\"same\": \"The Pass2 value `4` must be the same as field Pass1 value `3`\"})\n\t})\n}\n\nfunc Test_CheckStruct_Recursively_SliceAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required#Student Name is required\"`\n\t\t\tAge  int    `v:\"required\"`\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tName     string    `v:\"required#Teacher Name is required\"`\n\t\t\tStudents []Student `v:\"required\"`\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\":     \"john\",\n\t\t\t\t\"students\": `[]`,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `The Students field is required`)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required#Student Name is required\"`\n\t\t\tAge  int    `v:\"required\"`\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tName     string `v:\"required#Teacher Name is required\"`\n\t\t\tStudents []Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\": \"john\",\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, ``)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required#Student Name is required\"`\n\t\t\tAge  int    `v:\"required\"`\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tName     string    `v:\"required#Teacher Name is required\"`\n\t\t\tStudents []Student `v:\"required\"`\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\":     \"john\",\n\t\t\t\t\"students\": `[{\"age\":2}, {\"name\":\"jack\", \"age\":4}]`,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `Student Name is required`)\n\t})\n\n\t// https://github.com/gogf/gf/issues/1864\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required\"`\n\t\t\tAge  int\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tName     string\n\t\t\tStudents []*Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\":     \"john\",\n\t\t\t\t\"students\": `[{\"age\":2},{\"name\":\"jack\", \"age\":4}]`,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `The Name field is required`)\n\t})\n}\n\nfunc Test_CheckStruct_Recursively_SliceAttribute_WithTypeAlias(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype ParamsItemBase struct {\n\t\t\tComponent string `v:\"required\" dc:\"组件名称\"`\n\t\t\tParams    string `v:\"required\" dc:\"配置参数(一般是JSON)\"`\n\t\t\tVersion   uint64 `v:\"required\" dc:\"参数版本\"`\n\t\t}\n\t\ttype ParamsItem = ParamsItemBase\n\t\ttype ParamsModifyReq struct {\n\t\t\tRevision  uint64       `v:\"required\"`\n\t\t\tBizParams []ParamsItem `v:\"required\"`\n\t\t}\n\t\tvar (\n\t\t\treq  = ParamsModifyReq{}\n\t\t\tdata = g.Map{\n\t\t\t\t\"Revision\":  \"1\",\n\t\t\t\t\"BizParams\": `[{}]`,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(req).Run(ctx)\n\t\tt.Assert(err, `The Component field is required; The Params field is required; The Version field is required`)\n\t})\n}\n\nfunc Test_CheckStruct_Recursively_MapAttribute(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required#Student Name is required\"`\n\t\t\tAge  int    `v:\"required\"`\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tName     string             `v:\"required#Teacher Name is required\"`\n\t\t\tStudents map[string]Student `v:\"required\"`\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\":     \"john\",\n\t\t\t\t\"students\": `{\"john\":{\"age\":18}}`,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `Student Name is required`)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1983\nfunc Test_Issue1983(t *testing.T) {\n\t// Error as the attribute Student in Teacher is an initialized struct, which has default value.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required\"`\n\t\t\tAge  int\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tStudents Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"students\": nil,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `The Name field is required`)\n\t})\n\t// The same as upper, it is not affected by association values.\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required\"`\n\t\t\tAge  int\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tStudents Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"name\":     \"john\",\n\t\t\t\t\"students\": nil,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, `The Name field is required`)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required\"`\n\t\t\tAge  int\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tStudents *Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"students\": nil,\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/1921\nfunc Test_Issue1921(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype SearchOption struct {\n\t\t\tSize int `v:\"max:100\"`\n\t\t}\n\t\ttype SearchReq struct {\n\t\t\tOption *SearchOption `json:\"option,omitempty\"`\n\t\t}\n\n\t\tvar (\n\t\t\treq = SearchReq{\n\t\t\t\tOption: &SearchOption{\n\t\t\t\t\tSize: 10000,\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Data(req).Run(ctx)\n\t\tt.Assert(err, \"The Size value `10000` must be equal or lesser than 100\")\n\t})\n}\n\n// https://github.com/gogf/gf/issues/2011\nfunc Test_Issue2011(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Student struct {\n\t\t\tName string `v:\"required|min-length:6\"`\n\t\t\tAge  int\n\t\t}\n\t\ttype Teacher struct {\n\t\t\tStudent *Student\n\t\t}\n\t\tvar (\n\t\t\tteacher = Teacher{}\n\t\t\tdata    = g.Map{\n\t\t\t\t\"student\": g.Map{\n\t\t\t\t\t\"name\": \"john\",\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\terr := g.Validator().Assoc(data).Data(teacher).Run(ctx)\n\t\tt.Assert(err, \"The Name value `john` length must be equal or greater than 6\")\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_feature_rule_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/os/gctx\"\n\t\"github.com/gogf/gf/v2/os/gtime\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\nvar (\n\tctx = gctx.New()\n)\n\nfunc Test_Check(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"abc:6,16\"\n\t\tval1 := 0\n\t\tval2 := 7\n\t\tval3 := 20\n\t\terr1 := g.Validator().Data(val1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val3).Rules(rule).Run(ctx)\n\t\tt.Assert(err1, \"InvalidRules: abc:6,16\")\n\t\tt.Assert(err2, \"InvalidRules: abc:6,16\")\n\t\tt.Assert(err3, \"InvalidRules: abc:6,16\")\n\t})\n}\n\nfunc Test_Array(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"1\").Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"The value `1` is not of valid array type\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"\").Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"The value `` is not of valid array type\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"[1,2,3]\").Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"[]\").Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data([]int{1, 2, 3}).Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data([]int{}).Rules(\"array\").Run(ctx)\n\t\tt.Assert(err, \"\")\n\t})\n}\n\nfunc Test_Required(t *testing.T) {\n\tif m := g.Validator().Data(\"1\").Rules(\"required\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"\").Rules(\"required\").Run(ctx); m == nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"\").Assoc(map[string]any{\"id\": 1, \"age\": 19}).Rules(\"required-if: id,1,age,18\").Run(ctx); m == nil {\n\t\tt.Error(\"Required校验失败\")\n\t}\n\tif m := g.Validator().Data(\"\").Assoc(map[string]any{\"id\": 2, \"age\": 19}).Rules(\"required-if: id,1,age,18\").Run(ctx); m != nil {\n\t\tt.Error(\"Required校验失败\")\n\t}\n}\n\nfunc Test_RequiredIf(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-if:id,1,age,18\"\n\t\tt.AssertNE(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 1}).Rules(rule).Run(ctx), nil)\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 0}).Rules(rule).Run(ctx), nil)\n\t\tt.AssertNE(g.Validator().Data(\"\").Assoc(g.Map{\"age\": 18}).Rules(rule).Run(ctx), nil)\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"age\": 20}).Rules(rule).Run(ctx), nil)\n\t})\n}\n\nfunc Test_RequiredIfAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-if-all:id,1,age,18\"\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 1}).Rules(rule).Run(ctx), nil)\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"age\": 18}).Rules(rule).Run(ctx), nil)\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 0, \"age\": 20}).Rules(rule).Run(ctx), nil)\n\t\tt.AssertNE(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 1, \"age\": 18}).Rules(rule).Run(ctx), nil)\n\t})\n}\n\nfunc Test_RequiredUnless(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-unless:id,1,age,18\"\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 1}).Rules(rule).Run(ctx), nil)\n\t\tt.AssertNE(g.Validator().Data(\"\").Assoc(g.Map{\"id\": 0}).Rules(rule).Run(ctx), nil)\n\t\tt.Assert(g.Validator().Data(\"\").Assoc(g.Map{\"age\": 18}).Rules(rule).Run(ctx), nil)\n\t\tt.AssertNE(g.Validator().Data(\"\").Assoc(g.Map{\"age\": 20}).Rules(rule).Run(ctx), nil)\n\t})\n}\n\nfunc Test_RequiredWith(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-with:id,name\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"id\":   100,\n\t\t\t\"name\": \"john\",\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.Assert(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t\tt.AssertNE(err3, nil)\n\t})\n\t// time.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-with:id,time\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"time\": time.Time{},\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.Assert(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t\tt.Assert(err3, nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-with:id,time\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"time\": time.Now(),\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.Assert(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t\tt.AssertNE(err3, nil)\n\t})\n\t// gtime.Time\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid       int64       `json:\"uid\"`\n\t\t\tNickname  string      `json:\"nickname\" v:\"required-with:Uid\"`\n\t\t\tStartTime *gtime.Time `json:\"start_time\" v:\"required-with:EndTime\"`\n\t\t\tEndTime   *gtime.Time `json:\"end_time\" v:\"required-with:StartTime\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tStartTime: nil,\n\t\t\tEndTime:   nil,\n\t\t}\n\t\tt.Assert(g.Validator().Data(data).Run(ctx), nil)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype UserApiSearch struct {\n\t\t\tUid       int64       `json:\"uid\"`\n\t\t\tNickname  string      `json:\"nickname\" v:\"required-with:Uid\"`\n\t\t\tStartTime *gtime.Time `json:\"start_time\" v:\"required-with:EndTime\"`\n\t\t\tEndTime   *gtime.Time `json:\"end_time\" v:\"required-with:StartTime\"`\n\t\t}\n\t\tdata := UserApiSearch{\n\t\t\tStartTime: nil,\n\t\t\tEndTime:   gtime.Now(),\n\t\t}\n\t\tt.AssertNE(g.Validator().Data(data).Run(ctx), nil)\n\t})\n}\n\nfunc Test_RequiredWithAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-with-all:id,name\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"id\":   100,\n\t\t\t\"name\": \"john\",\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.Assert(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.AssertNE(err3, nil)\n\t})\n}\n\nfunc Test_RequiredWithOut(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-without:id,name\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"id\":   100,\n\t\t\t\"name\": \"john\",\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.AssertNE(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t\tt.Assert(err3, nil)\n\t})\n}\n\nfunc Test_RequiredWithOutAll(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := \"required-without-all:id,name\"\n\t\tval1 := \"\"\n\t\tparams1 := g.Map{\n\t\t\t\"age\": 18,\n\t\t}\n\t\tparams2 := g.Map{\n\t\t\t\"id\": 100,\n\t\t}\n\t\tparams3 := g.Map{\n\t\t\t\"id\":   100,\n\t\t\t\"name\": \"john\",\n\t\t}\n\t\terr1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Run(ctx)\n\t\tt.AssertNE(err1, nil)\n\t\tt.Assert(err2, nil)\n\t\tt.Assert(err3, nil)\n\t})\n}\n\nfunc Test_Date(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"2010\":       false,\n\t\t\t\"201011\":     false,\n\t\t\t\"20101101\":   true,\n\t\t\t\"2010-11-01\": true,\n\t\t\t\"2010.11.01\": true,\n\t\t\t\"2010/11/01\": true,\n\t\t\t\"2010=11=01\": false,\n\t\t\t\"123\":        false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"date\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Datetime(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"2010\":                false,\n\t\t\t\"2010.11\":             false,\n\t\t\t\"2010-11-01\":          false,\n\t\t\t\"2010-11-01 12:00\":    false,\n\t\t\t\"2010-11-01 12:00:00\": true,\n\t\t\t\"2010.11.01 12:00:00\": false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Rules(`datetime`).Data(k).Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_DateFormat(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrStr{\n\t\t\t\"2010\":                 \"date-format:Y\",\n\t\t\t\"201011\":               \"date-format:Ym\",\n\t\t\t\"2010.11\":              \"date-format:Y.m\",\n\t\t\t\"201011-01\":            \"date-format:Ym-d\",\n\t\t\t\"2010~11~01\":           \"date-format:Y~m~d\",\n\t\t\t\"2010-11~01\":           \"date-format:Y-m~d\",\n\t\t\t\"2023-09-10T19:46:31Z\": \"date-format:2006-01-02\\\\T15:04:05Z07:00\", // RFC3339\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(v).Run(ctx)\n\t\t\tt.AssertNil(err)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terrM := g.MapStrStr{\n\t\t\t\"2010-11~01\": \"date-format:Y~m~d\",\n\t\t}\n\t\tfor k, v := range errM {\n\t\t\terr := g.Validator().Data(k).Rules(v).Run(ctx)\n\t\t\tt.AssertNE(err, nil)\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt1 := gtime.Now()\n\t\tt2 := time.Time{}\n\t\terr1 := g.Validator().Data(t1).Rules(\"date-format:Y\").Run(ctx)\n\t\terr2 := g.Validator().Data(t2).Rules(\"date-format:Y\").Run(ctx)\n\t\tt.Assert(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t})\n}\n\nfunc Test_Email(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"m@johngcn\":           false,\n\t\t\t\"m@www@johngcn\":       false,\n\t\t\t\"m-m_m@mail.johng.cn\": true,\n\t\t\t\"m.m-m@johng.cn\":      true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"email\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Phone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"1361990897\":  false,\n\t\t\t\"13619908979\": true,\n\t\t\t\"16719908979\": true,\n\t\t\t\"19719908989\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"phone\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_PhoneLoose(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"13333333333\": true,\n\t\t\t\"15555555555\": true,\n\t\t\t\"16666666666\": true,\n\t\t\t\"23333333333\": false,\n\t\t\t\"1333333333\":  false,\n\t\t\t\"10333333333\": false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"phone-loose\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Telephone(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"869265\":       false,\n\t\t\t\"028-869265\":   false,\n\t\t\t\"86292651\":     true,\n\t\t\t\"028-8692651\":  true,\n\t\t\t\"0830-8692651\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"telephone\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Passport(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"123456\":   false,\n\t\t\t\"a12345-6\": false,\n\t\t\t\"aaaaa\":    false,\n\t\t\t\"aaaaaa\":   true,\n\t\t\t\"a123_456\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"passport\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Password(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"12345\":     false,\n\t\t\t\"aaaaa\":     false,\n\t\t\t\"a12345-6\":  true,\n\t\t\t\">,/;'[09-\": true,\n\t\t\t\"a123_456\":  true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"password\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Password2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"12345\":     false,\n\t\t\t\"Naaaa\":     false,\n\t\t\t\"a12345-6\":  false,\n\t\t\t\">,/;'[09-\": false,\n\t\t\t\"a123_456\":  false,\n\t\t\t\"Nant1986\":  true,\n\t\t\t\"Nant1986!\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"password2\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Password3(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"12345\":     false,\n\t\t\t\"Naaaa\":     false,\n\t\t\t\"a12345-6\":  false,\n\t\t\t\">,/;'[09-\": false,\n\t\t\t\"a123_456\":  false,\n\t\t\t\"Nant1986\":  false,\n\t\t\t\"Nant1986!\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"password3\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Postcode(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"12345\":  false,\n\t\t\t\"610036\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"postcode\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_ResidentId(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"11111111111111\":     false,\n\t\t\t\"1111111111111111\":   false,\n\t\t\t\"311128500121201\":    false,\n\t\t\t\"510521198607185367\": false,\n\t\t\t\"51052119860718536x\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"resident-id\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_BankCard(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"6230514630000424470\": false,\n\t\t\t\"6230514630000424473\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"bank-card\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_QQ(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"100\":       false,\n\t\t\t\"1\":         false,\n\t\t\t\"10000\":     true,\n\t\t\t\"38996181\":  true,\n\t\t\t\"389961817\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"qq\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Ip(t *testing.T) {\n\tif m := g.Validator().Data(\"10.0.0.1\").Rules(\"ip\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"10.0.0.1\").Rules(\"ipv4\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"0.0.0.0\").Rules(\"ipv4\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"1920.0.0.0\").Rules(\"ipv4\").Run(ctx); m == nil {\n\t\tt.Error(\"ipv4校验失败\")\n\t}\n\tif m := g.Validator().Data(\"1920.0.0.0\").Rules(\"ip\").Run(ctx); m == nil {\n\t\tt.Error(\"ipv4校验失败\")\n\t}\n\tif m := g.Validator().Data(\"fe80::5484:7aff:fefe:9799\").Rules(\"ipv6\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"fe80::5484:7aff:fefe:9799123\").Rules(\"ipv6\").Run(ctx); m == nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"fe80::5484:7aff:fefe:9799\").Rules(\"ip\").Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"fe80::5484:7aff:fefe:9799123\").Rules(\"ip\").Run(ctx); m == nil {\n\t\tt.Error(m)\n\t}\n}\n\nfunc Test_IPv4(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"0.0.0\":         false,\n\t\t\t\"0.0.0.0\":       true,\n\t\t\t\"1.1.1.1\":       true,\n\t\t\t\"255.255.255.0\": true,\n\t\t\t\"127.0.0.1\":     true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"ipv4\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_IPv6(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"192.168.1.1\": false,\n\t\t\t\"CDCD:910A:2222:5498:8475:1111:3900:2020\": true,\n\t\t\t\"1030::C9B4:FF12:48AA:1A2B\":               true,\n\t\t\t\"2000:0:0:0:0:0:0:1\":                      true,\n\t\t\t\"0000:0000:0000:0000:0000:ffff:c0a8:5909\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"ipv6\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_MAC(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"192.168.1.1\":       false,\n\t\t\t\"44-45-53-54-00-00\": true,\n\t\t\t\"01:00:5e:00:00:00\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"mac\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_URL(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"127.0.0.1\":             false,\n\t\t\t\"https://www.baidu.com\": true,\n\t\t\t\"http://127.0.0.1\":      true,\n\t\t\t\"file:///tmp/test.txt\":  true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"url\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Domain(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"localhost\":     false,\n\t\t\t\"baidu.com\":     true,\n\t\t\t\"www.baidu.com\": true,\n\t\t\t\"jn.np\":         true,\n\t\t\t\"www.jn.np\":     true,\n\t\t\t\"w.www.jn.np\":   true,\n\t\t\t\"127.0.0.1\":     false,\n\t\t\t\"www.360.com\":   true,\n\t\t\t\"www.360\":       false,\n\t\t\t\"360\":           false,\n\t\t\t\"my-gf\":         false,\n\t\t\t\"my-gf.com\":     true,\n\t\t\t\"my-gf.360.com\": true,\n\t\t}\n\t\tvar err error\n\t\tfor k, v := range m {\n\t\t\terr = g.Validator().Data(k).Rules(\"domain\").Run(ctx)\n\t\t\tif v {\n\t\t\t\t// fmt.Println(k)\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\t// fmt.Println(k)\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Length(t *testing.T) {\n\trule := \"length:6,16\"\n\tif m := g.Validator().Data(\"123456\").Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"12345\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n}\n\nfunc Test_MinLength(t *testing.T) {\n\trule := \"min-length:6\"\n\tmsgs := map[string]string{\n\t\t\"min-length\": \"地址长度至少为{min}位\",\n\t}\n\tif m := g.Validator().Data(\"123456\").Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"12345\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n\tif m := g.Validator().Data(\"12345\").Rules(rule).Messages(msgs).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n\n\trule2 := \"min-length:abc\"\n\tif m := g.Validator().Data(\"123456\").Rules(rule2).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n}\n\nfunc Test_MaxLength(t *testing.T) {\n\trule := \"max-length:6\"\n\tmsgs := map[string]string{\n\t\t\"max-length\": \"地址长度至大为{max}位\",\n\t}\n\tif m := g.Validator().Data(\"12345\").Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"1234567\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n\tif m := g.Validator().Data(\"1234567\").Rules(rule).Messages(msgs).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n\n\trule2 := \"max-length:abc\"\n\tif m := g.Validator().Data(\"123456\").Rules(rule2).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n}\n\nfunc Test_Size(t *testing.T) {\n\trule := \"size:5\"\n\tif m := g.Validator().Data(\"12345\").Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"123456\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"长度校验失败\")\n\t}\n}\n\nfunc Test_Between(t *testing.T) {\n\trule := \"between:6.01, 10.01\"\n\tif m := g.Validator().Data(10).Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(10.02).Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"大小范围校验失败\")\n\t}\n\tif m := g.Validator().Data(\"a\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"大小范围校验失败\")\n\t}\n}\n\nfunc Test_Min(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"1\":    false,\n\t\t\t\"99\":   false,\n\t\t\t\"100\":  true,\n\t\t\t\"1000\": true,\n\t\t\t\"a\":    false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"min:100\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"1\").Rules(\"min:a\").Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Max(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"1\":    true,\n\t\t\t\"99\":   true,\n\t\t\t\"100\":  true,\n\t\t\t\"1000\": false,\n\t\t\t\"a\":    false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"max:100\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"1\").Rules(\"max:a\").Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t})\n}\n\nfunc Test_Json(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":                   false,\n\t\t\t\".\":                  false,\n\t\t\t\"{}\":                 true,\n\t\t\t\"[]\":                 true,\n\t\t\t\"[1,2,3,4]\":          true,\n\t\t\t`{\"list\":[1,2,3,4]}`: true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"json\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Integer(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":          false,\n\t\t\t\"1.0\":       false,\n\t\t\t\"001\":       true,\n\t\t\t\"1\":         true,\n\t\t\t\"100\":       true,\n\t\t\t\"999999999\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"integer\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Float(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":    false,\n\t\t\t\"a\":   false,\n\t\t\t\"1\":   true,\n\t\t\t\"1.0\": true,\n\t\t\t\"1.1\": true,\n\t\t\t\"0.1\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"float\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Boolean(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"a\":    false,\n\t\t\t\"-\":    false,\n\t\t\t\"\":     true,\n\t\t\t\"1\":    true,\n\t\t\t\"true\": true,\n\t\t\t\"off\":  true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"boolean\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Same(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype testCase struct {\n\t\t\tparams g.Map\n\t\t\tpass   bool\n\t\t}\n\t\tcases := []testCase{\n\t\t\t{g.Map{\"age\": 18}, false},\n\t\t\t{g.Map{\"id\": 100}, true},\n\t\t\t{g.Map{\"id\": 100, \"name\": \"john\"}, true},\n\t\t}\n\t\tfor _, c := range cases {\n\t\t\terr := g.Validator().Data(\"100\").Assoc(c.params).Rules(\"same:id\").Run(ctx)\n\t\t\tif c.pass {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Different(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype testCase struct {\n\t\t\tparams g.Map\n\t\t\tpass   bool\n\t\t}\n\t\tcases := []testCase{\n\t\t\t{g.Map{\"age\": 18}, true},\n\t\t\t{g.Map{\"id\": 100}, false},\n\t\t\t{g.Map{\"id\": 100, \"name\": \"john\"}, false},\n\t\t}\n\t\tfor _, c := range cases {\n\t\t\terr := g.Validator().Data(\"100\").Assoc(c.params).Rules(\"different:id\").Run(ctx)\n\t\t\tif c.pass {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_EQ(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype testCase struct {\n\t\t\tparams g.Map\n\t\t\tpass   bool\n\t\t}\n\t\tcases := []testCase{\n\t\t\t{g.Map{\"age\": 18}, false},\n\t\t\t{g.Map{\"id\": 100}, true},\n\t\t\t{g.Map{\"id\": 100, \"name\": \"john\"}, true},\n\t\t}\n\t\tfor _, c := range cases {\n\t\t\terr := g.Validator().Data(\"100\").Assoc(c.params).Rules(\"eq:id\").Run(ctx)\n\t\t\tif c.pass {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Not_EQ(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype testCase struct {\n\t\t\tparams g.Map\n\t\t\tpass   bool\n\t\t}\n\t\tcases := []testCase{\n\t\t\t{g.Map{\"age\": 18}, true},\n\t\t\t{g.Map{\"id\": 100}, false},\n\t\t\t{g.Map{\"id\": 100, \"name\": \"john\"}, false},\n\t\t}\n\t\tfor _, c := range cases {\n\t\t\terr := g.Validator().Data(\"100\").Assoc(c.params).Rules(\"not-eq:id\").Run(ctx)\n\t\t\tif c.pass {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_In(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":    false,\n\t\t\t\"1\":   false,\n\t\t\t\"100\": true,\n\t\t\t\"200\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"in:100,200\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_NotIn(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":    true,\n\t\t\t\"1\":   true,\n\t\t\t\"100\": false,\n\t\t\t\"200\": true,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"not-in:100\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"\":    true,\n\t\t\t\"1\":   true,\n\t\t\t\"100\": false,\n\t\t\t\"200\": false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"not-in:100,200\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Regex1(t *testing.T) {\n\trule := `regex:\\d{6}|\\D{6}|length:6,16`\n\tif m := g.Validator().Data(\"123456\").Rules(rule).Run(ctx); m != nil {\n\t\tt.Error(m)\n\t}\n\tif m := g.Validator().Data(\"abcde6\").Rules(rule).Run(ctx); m == nil {\n\t\tt.Error(\"校验失败\")\n\t}\n}\n\nfunc Test_Regex2(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\trule := `required|min-length:6|regex:^data:image\\/(jpeg|png);base64,`\n\t\tstr1 := \"\"\n\t\tstr2 := \"data\"\n\t\tstr3 := \"data:image/jpeg;base64,/9jrbattq22r\"\n\t\terr1 := g.Validator().Data(str1).Rules(rule).Run(ctx)\n\t\terr2 := g.Validator().Data(str2).Rules(rule).Run(ctx)\n\t\terr3 := g.Validator().Data(str3).Rules(rule).Run(ctx)\n\t\tt.AssertNE(err1, nil)\n\t\tt.AssertNE(err2, nil)\n\t\tt.Assert(err3, nil)\n\n\t\tt.AssertNE(err1.Map()[\"required\"], nil)\n\t\tt.AssertNE(err2.Map()[\"min-length\"], nil)\n\t})\n}\n\nfunc Test_Not_Regex(t *testing.T) {\n\trule := `not-regex:\\d{6}|\\D{6}|length:6,16`\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"123456\").Rules(rule).Run(ctx)\n\t\tt.Assert(err, \"The value `123456` should not be in regex of: \\\\d{6}|\\\\D{6}\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Data(\"abcde6\").Rules(rule).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\n// issue: https://github.com/gogf/gf/issues/1077\nfunc Test_InternalError_String(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype a struct {\n\t\t\tName string `v:\"hh\"`\n\t\t}\n\t\taa := a{Name: \"2\"}\n\t\terr := g.Validator().Data(&aa).Run(ctx)\n\n\t\tt.Assert(err.String(), \"InvalidRules: hh\")\n\t\tt.Assert(err.Strings(), g.Slice{\"InvalidRules: hh\"})\n\t\tt.Assert(err.FirstError(), \"InvalidRules: hh\")\n\t\tt.Assert(gerror.Current(err), \"InvalidRules: hh\")\n\t})\n}\n\nfunc Test_Code(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Rules(\"required\").Data(\"\").Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gerror.Code(err), gcode.CodeValidationFailed)\n\t})\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().Rules(\"none-exist-rule\").Data(\"\").Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(gerror.Code(err), gcode.CodeInternalError)\n\t})\n}\n\nfunc Test_Bail(t *testing.T) {\n\t// check value with no bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().\n\t\t\tRules(\"required|min:1|between:1,100\").\n\t\t\tMessages(\"|min number is 1|size is between 1 and 100\").\n\t\t\tData(-1).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"min number is 1; size is between 1 and 100\")\n\t})\n\n\t// check value with bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\terr := g.Validator().\n\t\t\tRules(\"bail|required|min:1|between:1,100\").\n\t\t\tMessages(\"||min number is 1|size is between 1 and 100\").\n\t\t\tData(-1).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"min number is 1\")\n\t})\n\n\t// struct with no bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage int `v:\"required|min:1\"`\n\t\t\tSize int `v:\"required|min:1|between:1,100 # |min number is 1|size is between 1 and 100\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: -1,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"min number is 1; size is between 1 and 100\")\n\t})\n\t// struct with bail\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tPage int `v:\"required|min:1\"`\n\t\t\tSize int `v:\"bail|required|min:1|between:1,100 # ||min number is 1|size is between 1 and 100\"`\n\t\t}\n\t\tobj := &Params{\n\t\t\tPage: 1,\n\t\t\tSize: -1,\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNE(err, nil)\n\t\tt.Assert(err.Error(), \"min number is 1\")\n\t})\n}\n\nfunc Test_After(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"after:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-02\",\n\t\t\tT2: \"2022-09-01\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"after:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-01\",\n\t\t\tT2: \"2022-09-02\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-01` must be after field T2 value `2022-09-02`\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"after:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-02\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"after:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-02\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-01 00:00:00` must be after field T2 value `2022-09-02 00:00:00`\")\n\t})\n}\n\nfunc Test_After_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"after-equal:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-02\",\n\t\t\tT2: \"2022-09-01\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"after-equal:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-01\",\n\t\t\tT2: \"2022-09-02\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-01` must be after or equal to field T2 value `2022-09-02`\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"after-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-02\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"after-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"after-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-02\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-01 00:00:00` must be after or equal to field T2 value `2022-09-02 00:00:00`\")\n\t})\n}\n\nfunc Test_Before(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"before:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-01\",\n\t\t\tT2: \"2022-09-02\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"before:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-02\",\n\t\t\tT2: \"2022-09-01\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-02` must be before field T2 value `2022-09-01`\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"before:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-02\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"before:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-02\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-02 00:00:00` must be before field T2 value `2022-09-01 00:00:00`\")\n\t})\n}\n\nfunc Test_Before_Equal(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"before-equal:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-01\",\n\t\t\tT2: \"2022-09-02\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 string `v:\"before-equal:T2\"`\n\t\t\tT2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: \"2022-09-02\",\n\t\t\tT2: \"2022-09-01\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-02` must be before or equal to field T2\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"before-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-02\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"before-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-01\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tT1 *gtime.Time `v:\"before-equal:T2\"`\n\t\t\tT2 *gtime.Time\n\t\t}\n\t\tobj := &Params{\n\t\t\tT1: gtime.New(\"2022-09-02\"),\n\t\t\tT2: gtime.New(\"2022-09-01\"),\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The T1 value `2022-09-02 00:00:00` must be before or equal to field T2\")\n\t})\n}\n\nfunc Test_GT(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"gt:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.2\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"gt:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.2\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The V1 value `1.1` must be greater than field V2 value `1.2`\")\n\t})\n}\n\nfunc Test_GTE(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"gte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.2\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"gte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.2\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The V1 value `1.1` must be greater than or equal to field V2 value `1.2`\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"gte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_LT(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"lt:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.2\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"lt:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.2\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The V1 value `1.2` must be lesser than field V2 value `1.1`\")\n\t})\n}\n\nfunc Test_LTE(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"lte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.2\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"lte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.2\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.Assert(err, \"The V1 value `1.2` must be lesser than or equal to field V2 value `1.1`\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype Params struct {\n\t\t\tV1 string `v:\"lte:V2\"`\n\t\t\tV2 string\n\t\t}\n\t\tobj := &Params{\n\t\t\tV1: \"1.1\",\n\t\t\tV2: \"1.1\",\n\t\t}\n\t\terr := g.Validator().Data(obj).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\n\nfunc Test_Enums(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ttype EnumsTest string\n\t\tconst (\n\t\t\tEnumsTestA EnumsTest = \"a\"\n\t\t\tEnumsTestB EnumsTest = \"b\"\n\t\t)\n\t\ttype Params struct {\n\t\t\tId    int\n\t\t\tEnums EnumsTest `v:\"enums\"`\n\t\t}\n\t\ttype PointerParams struct {\n\t\t\tId    int\n\t\t\tEnums *EnumsTest `v:\"enums\"`\n\t\t}\n\t\ttype SliceParams struct {\n\t\t\tId    int\n\t\t\tEnums []EnumsTest `v:\"foreach|enums\"`\n\t\t}\n\n\t\toldEnumsJson, err := gtag.GetGlobalEnums()\n\t\tt.AssertNil(err)\n\t\tdefer t.AssertNil(gtag.SetGlobalEnums(oldEnumsJson))\n\n\t\terr = gtag.SetGlobalEnums(`{\"github.com/gogf/gf/v2/util/gvalid_test.EnumsTest\": [\"a\",\"b\"]}`)\n\t\tt.AssertNil(err)\n\n\t\terr = g.Validator().Data(&Params{\n\t\t\tId:    1,\n\t\t\tEnums: EnumsTestB,\n\t\t}).Run(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = g.Validator().Data(&Params{\n\t\t\tId:    1,\n\t\t\tEnums: \"c\",\n\t\t}).Run(ctx)\n\t\tt.Assert(err, \"The Enums value `c` should be in enums of: [\\\"a\\\",\\\"b\\\"]\")\n\n\t\tvar b EnumsTest = \"b\"\n\t\terr = g.Validator().Data(&PointerParams{\n\t\t\tId:    1,\n\t\t\tEnums: &b,\n\t\t}).Run(ctx)\n\t\tt.AssertNil(err)\n\n\t\terr = g.Validator().Data(&SliceParams{\n\t\t\tId:    1,\n\t\t\tEnums: []EnumsTest{EnumsTestA, EnumsTestB},\n\t\t}).Run(ctx)\n\t\tt.AssertNil(err)\n\t})\n}\nfunc Test_Alpha(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"abc\":     true,\n\t\t\t\"ABC\":     true,\n\t\t\t\"abcABC\":  true,\n\t\t\t\"abc123\":  false,\n\t\t\t\"abc-123\": false,\n\t\t\t\"abc_123\": false,\n\t\t\t\"123\":     false,\n\t\t\t\"\":        false,\n\t\t\t\"abc def\": false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"alpha\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_AlphaDash(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"abc\":          true,\n\t\t\t\"ABC\":          true,\n\t\t\t\"abc123\":       true,\n\t\t\t\"abc-123\":      true,\n\t\t\t\"abc_123\":      true,\n\t\t\t\"abc-_123\":     true,\n\t\t\t\"abc-_ABC-123\": true,\n\t\t\t\"abc 123\":      false,\n\t\t\t\"abc@123\":      false,\n\t\t\t\"\":             false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"alpha-dash\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_AlphaNum(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"abc\":       true,\n\t\t\t\"ABC\":       true,\n\t\t\t\"123\":       true,\n\t\t\t\"abc123\":    true,\n\t\t\t\"ABC123\":    true,\n\t\t\t\"abcABC123\": true,\n\t\t\t\"abc-123\":   false,\n\t\t\t\"abc_123\":   false,\n\t\t\t\"abc 123\":   false,\n\t\t\t\"\":          false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"alpha-num\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Lowercase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"abc\":     true,\n\t\t\t\"abcdef\":  true,\n\t\t\t\"ABC\":     false,\n\t\t\t\"Abc\":     false,\n\t\t\t\"aBc\":     false,\n\t\t\t\"abc123\":  false,\n\t\t\t\"abc-def\": false,\n\t\t\t\"abc_def\": false,\n\t\t\t\"\":        false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"lowercase\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Numeric(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"0\":         true,\n\t\t\t\"123\":       true,\n\t\t\t\"0123\":      true,\n\t\t\t\"123456789\": true,\n\t\t\t\"1.23\":      false,\n\t\t\t\"abc\":       false,\n\t\t\t\"123abc\":    false,\n\t\t\t\"abc123\":    false,\n\t\t\t\"\":          false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"numeric\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc Test_Uppercase(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tm := g.MapStrBool{\n\t\t\t\"ABC\":     true,\n\t\t\t\"ABCDEF\":  true,\n\t\t\t\"abc\":     false,\n\t\t\t\"Abc\":     false,\n\t\t\t\"AbC\":     false,\n\t\t\t\"ABC123\":  false,\n\t\t\t\"ABC-DEF\": false,\n\t\t\t\"ABC_DEF\": false,\n\t\t\t\"\":        false,\n\t\t}\n\t\tfor k, v := range m {\n\t\t\terr := g.Validator().Data(k).Rules(\"uppercase\").Run(ctx)\n\t\t\tif v {\n\t\t\t\tt.AssertNil(err)\n\t\t\t} else {\n\t\t\t\tt.AssertNE(err, nil)\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_internal_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid\n\nimport (\n\t\"testing\"\n\n\t\"github.com/gogf/gf/v2/test/gtest\"\n)\n\nfunc Test_parseSequenceTag(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"name@required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致\"\n\t\tfield, rule, msg := ParseTagValue(s)\n\t\tt.Assert(field, \"name\")\n\t\tt.Assert(rule, \"required|length:2,20|password3|same:password1\")\n\t\tt.Assert(msg, \"||密码强度不足|两次密码不一致\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致\"\n\t\tfield, rule, msg := ParseTagValue(s)\n\t\tt.Assert(field, \"\")\n\t\tt.Assert(rule, \"required|length:2,20|password3|same:password1\")\n\t\tt.Assert(msg, \"||密码强度不足|两次密码不一致\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"required|length:2,20|password3|same:password1\"\n\t\tfield, rule, msg := ParseTagValue(s)\n\t\tt.Assert(field, \"\")\n\t\tt.Assert(rule, \"required|length:2,20|password3|same:password1\")\n\t\tt.Assert(msg, \"\")\n\t})\n\tgtest.C(t, func(t *gtest.T) {\n\t\ts := \"required\"\n\t\tfield, rule, msg := ParseTagValue(s)\n\t\tt.Assert(field, \"\")\n\t\tt.Assert(rule, \"required\")\n\t\tt.Assert(msg, \"\")\n\t})\n}\n\nfunc Test_GetTags(t *testing.T) {\n\tgtest.C(t, func(t *gtest.T) {\n\t\tt.Assert(structTagPriority, GetTags())\n\t})\n}\n"
  },
  {
    "path": "util/gvalid/gvalid_z_unit_issue_test.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage gvalid_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/frame/g\"\n\t\"github.com/gogf/gf/v2/net/ghttp\"\n\t\"github.com/gogf/gf/v2/test/gtest\"\n\t\"github.com/gogf/gf/v2/util/guid\"\n\t\"github.com/gogf/gf/v2/util/gvalid\"\n)\n\ntype Foo struct {\n\tBar *Bar `p:\"bar\" v:\"required-without:Baz\"`\n\tBaz *Baz `p:\"baz\" v:\"required-without:Bar\"`\n}\ntype Bar struct {\n\tBarKey string `p:\"bar_key\" v:\"required\"`\n}\ntype Baz struct {\n\tBazKey string `p:\"baz_key\" v:\"required\"`\n}\n\n// https://github.com/gogf/gf/issues/2503\nfunc Test_Issue2503(t *testing.T) {\n\tfoo := &Foo{\n\t\tBar: &Bar{BarKey: \"value\"},\n\t}\n\terr := gvalid.New().Data(foo).Run(context.Background())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\ntype Issue3636SliceV struct{}\n\nfunc init() {\n\trule := Issue3636SliceV{}\n\tgvalid.RegisterRule(rule.Name(), rule.Run)\n}\n\nfunc (r Issue3636SliceV) Name() string {\n\treturn \"slice-v\"\n}\n\nfunc (r Issue3636SliceV) Message() string {\n\treturn \"not a slice\"\n}\n\nfunc (r Issue3636SliceV) Run(_ context.Context, in gvalid.RuleFuncInput) error {\n\tfor _, v := range in.Value.Slice() {\n\t\tif v == \"\" {\n\t\t\treturn gerror.New(\"empty value\")\n\t\t}\n\t}\n\tif !in.Value.IsSlice() {\n\t\treturn gerror.New(\"not a slice\")\n\t}\n\treturn nil\n}\n\ntype Issue3636HelloReq struct {\n\tg.Meta `path:\"/hello\" method:\"POST\"`\n\n\tName string   `json:\"name\" v:\"required\" dc:\"Your name\"`\n\tS    []string `json:\"s\" v:\"slice-v\" dc:\"S\"`\n}\ntype Issue3636HelloRes struct {\n\tName string   `json:\"name\" v:\"required\" dc:\"Your name\"`\n\tS    []string `json:\"s\" v:\"slice-v\" dc:\"S\"`\n}\n\ntype Issue3636Hello struct{}\n\nfunc (Issue3636Hello) Say(ctx context.Context, req *Issue3636HelloReq) (res *Issue3636HelloRes, err error) {\n\tres = &Issue3636HelloRes{\n\t\tName: req.Name,\n\t\tS:    req.S,\n\t}\n\treturn\n}\n\n// https://github.com/gogf/gf/issues/3636\nfunc Test_Issue3636(t *testing.T) {\n\ts := g.Server(guid.S())\n\ts.Use(ghttp.MiddlewareHandlerResponse)\n\ts.Group(\"/\", func(group *ghttp.RouterGroup) {\n\t\tgroup.Bind(\n\t\t\tnew(Issue3636Hello),\n\t\t)\n\t})\n\ts.SetDumpRouterMap(false)\n\ts.Start()\n\tdefer s.Shutdown()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tgtest.C(t, func(t *gtest.T) {\n\t\tc := g.Client()\n\t\tc.SetPrefix(fmt.Sprintf(\"http://127.0.0.1:%d\", s.GetListenedPort()))\n\t\tt.Assert(\n\t\t\tc.PostContent(ctx, \"/hello\", `{\"name\": \"t\", \"s\" : []}`),\n\t\t\t`{\"code\":0,\"message\":\"OK\",\"data\":{\"name\":\"t\",\"s\":[]}}`,\n\t\t)\n\t})\n}\n\n// https://github.com/gogf/gf/issues/4092\nfunc Test_Issue4092(t *testing.T) {\n\ttype Model struct {\n\t\tRaw  []byte `v:\"required\"`\n\t\tTest []byte `v:\"foreach|in:1,2,3\"`\n\t}\n\tgtest.C(t, func(t *gtest.T) {\n\t\tconst kb = 1024\n\t\tconst mb = 1024 * kb\n\t\traw := make([]byte, 50*mb)\n\t\tin := &Model{\n\t\t\tRaw:  raw,\n\t\t\tTest: []byte{40, 5, 6},\n\t\t}\n\t\terr := g.Validator().\n\t\t\tData(in).\n\t\t\tRun(context.Background())\n\t\tt.Assert(err, \"The Test value `6` is not in acceptable range: 1,2,3\")\n\t\tallocMb := getMemAlloc()\n\t\tt.AssertLE(allocMb, 110)\n\t})\n}\n\nfunc getMemAlloc() uint64 {\n\tbyteToMb := func(b uint64) uint64 {\n\t\treturn b / 1024 / 1024\n\t}\n\tvar m runtime.MemStats\n\truntime.ReadMemStats(&m)\n\t// For info on each, see: https://golang.org/pkg/runtime/#MemStats\n\talloc := byteToMb(m.Alloc)\n\treturn alloc\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\n// Package builtin implements built-in validation rules.\n//\n// Referred to Laravel validation:\n// https://laravel.com/docs/master/validation#available-validation-rules\npackage builtin\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/container/gvar\"\n)\n\ntype Rule interface {\n\t// Name returns the builtin name of the rule.\n\tName() string\n\n\t// Message returns the default error message of the rule.\n\tMessage() string\n\n\t// Run starts running the rule, it returns nil if successful, or else an error.\n\tRun(in RunInput) error\n}\n\ntype RunInput struct {\n\tRuleKey     string       // RuleKey is like the \"max\" in rule \"max: 6\"\n\tRulePattern string       // RulePattern is like \"6\" in rule:\"max:6\"\n\tField       string       // The field name of Value.\n\tValueType   reflect.Type // ValueType specifies the type of the value, which might be nil.\n\tValue       *gvar.Var    // Value specifies the value for this rule to validate.\n\tData        *gvar.Var    // Data specifies the `data` which is passed to the Validator.\n\tMessage     string       // Message specifies the custom error message or configured i18n message for this rule.\n\tOption      RunOption    // Option provides extra configuration for validation rule.\n}\n\ntype RunOption struct {\n\tCaseInsensitive bool // CaseInsensitive indicates that it does Case-Insensitive comparison in string.\n}\n\nvar (\n\t// ruleMap stores all builtin validation rules.\n\truleMap = map[string]Rule{}\n)\n\n// Register registers builtin rule into manager.\nfunc Register(rule Rule) {\n\truleMap[rule.Name()] = rule\n}\n\n// GetRule retrieves and returns rule by `name`.\nfunc GetRule(name string) Rule {\n\treturn ruleMap[name]\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_after.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleAfter implements `after` rule:\n// The datetime value should be after the value of field `field`.\n//\n// Format: after:field\ntype RuleAfter struct{}\n\nfunc init() {\n\tRegister(RuleAfter{})\n}\n\nfunc (r RuleAfter) Name() string {\n\treturn \"after\"\n}\n\nfunc (r RuleAfter) Message() string {\n\treturn \"The {field} value `{value}` must be after field {field1} value `{value1}`\"\n}\n\nfunc (r RuleAfter) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tvalueDatetime         = in.Value.Time()\n\t\tfieldDatetime         = gconv.Time(fieldValue)\n\t)\n\tif valueDatetime.After(fieldDatetime) {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\"{field1}\": fieldName,\n\t\t\"{value1}\": gconv.String(fieldValue),\n\t}))\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_after_equal.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleAfterEqual implements `after-equal` rule:\n// The datetime value should be after or equal to the value of field `field`.\n//\n// Format: after-equal:field\ntype RuleAfterEqual struct{}\n\nfunc init() {\n\tRegister(RuleAfterEqual{})\n}\n\nfunc (r RuleAfterEqual) Name() string {\n\treturn \"after-equal\"\n}\n\nfunc (r RuleAfterEqual) Message() string {\n\treturn \"The {field} value `{value}` must be after or equal to field {field1} value `{value1}`\"\n}\n\nfunc (r RuleAfterEqual) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tvalueDatetime         = in.Value.Time()\n\t\tfieldDatetime         = gconv.Time(fieldValue)\n\t)\n\tif valueDatetime.After(fieldDatetime) || valueDatetime.Equal(fieldDatetime) {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\"{field1}\": fieldName,\n\t\t\"{value1}\": gconv.String(fieldValue),\n\t}))\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_alpha.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleAlpha implements `alpha` rule:\n// Alpha characters (a-z, A-Z).\n//\n// Format: alpha\ntype RuleAlpha struct{}\n\nfunc init() {\n\tRegister(RuleAlpha{})\n}\n\nfunc (r RuleAlpha) Name() string {\n\treturn \"alpha\"\n}\n\nfunc (r RuleAlpha) Message() string {\n\treturn \"The {field} value `{value}` must contain only alphabetic characters\"\n}\n\nfunc (r RuleAlpha) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[a-zA-Z]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_alpha_dash.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleAlphaDash implements `alpha-dash` rule:\n// Alpha-numeric characters, hyphens, and underscores (a-z, A-Z, 0-9, -, _).\n//\n// Format: alpha-dash\ntype RuleAlphaDash struct{}\n\nfunc init() {\n\tRegister(RuleAlphaDash{})\n}\n\nfunc (r RuleAlphaDash) Name() string {\n\treturn \"alpha-dash\"\n}\n\nfunc (r RuleAlphaDash) Message() string {\n\treturn \"The {field} value `{value}` must contain only alpha-numeric characters, hyphens, and underscores\"\n}\n\nfunc (r RuleAlphaDash) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[a-zA-Z0-9_\\-]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_alpha_num.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleAlphaNum implements `alpha-num` rule:\n// Alpha-numeric characters (a-z, A-Z, 0-9).\n//\n// Format: alpha-num\ntype RuleAlphaNum struct{}\n\nfunc init() {\n\tRegister(RuleAlphaNum{})\n}\n\nfunc (r RuleAlphaNum) Name() string {\n\treturn \"alpha-num\"\n}\n\nfunc (r RuleAlphaNum) Message() string {\n\treturn \"The {field} value `{value}` must contain only alpha-numeric characters\"\n}\n\nfunc (r RuleAlphaNum) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[a-zA-Z0-9]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_array.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// RuleArray implements `array` rule:\n// Value should be type of array.\n//\n// Format: array\ntype RuleArray struct{}\n\nfunc init() {\n\tRegister(RuleArray{})\n}\n\nfunc (r RuleArray) Name() string {\n\treturn \"array\"\n}\n\nfunc (r RuleArray) Message() string {\n\treturn \"The {field} value `{value}` is not of valid array type\"\n}\n\nfunc (r RuleArray) Run(in RunInput) error {\n\tif in.Value.IsSlice() {\n\t\treturn nil\n\t}\n\tif json.Valid(in.Value.Bytes()) {\n\t\tvalue := in.Value.String()\n\t\tif len(value) > 1 && value[0] == '[' && value[len(value)-1] == ']' {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_bail.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\n// RuleBail implements `bail` rule:\n// Stop validating when this field's validation failed.\n//\n// Format: bail\ntype RuleBail struct{}\n\nfunc init() {\n\tRegister(RuleBail{})\n}\n\nfunc (r RuleBail) Name() string {\n\treturn \"bail\"\n}\n\nfunc (r RuleBail) Message() string {\n\treturn \"\"\n}\n\nfunc (r RuleBail) Run(in RunInput) error {\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_bank_card.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n)\n\n// RuleBankCard implements `bank-card` rule:\n// Bank card number.\n//\n// Format: bank-card\ntype RuleBankCard struct{}\n\nfunc init() {\n\tRegister(RuleBankCard{})\n}\n\nfunc (r RuleBankCard) Name() string {\n\treturn \"bank-card\"\n}\n\nfunc (r RuleBankCard) Message() string {\n\treturn \"The {field} value `{value}` is not a valid bank card number\"\n}\n\nfunc (r RuleBankCard) Run(in RunInput) error {\n\tif r.checkLuHn(in.Value.String()) {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n\n// checkLuHn checks `value` with LUHN algorithm.\n// It's usually used for bank card number validation.\nfunc (r RuleBankCard) checkLuHn(value string) bool {\n\tvar (\n\t\tsum     = 0\n\t\tnDigits = len(value)\n\t\tparity  = nDigits % 2\n\t)\n\tfor i := 0; i < nDigits; i++ {\n\t\tvar digit = int(value[i] - 48)\n\t\tif i%2 == parity {\n\t\t\tdigit *= 2\n\t\t\tif digit > 9 {\n\t\t\t\tdigit -= 9\n\t\t\t}\n\t\t}\n\t\tsum += digit\n\t}\n\treturn sum%10 == 0\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_before.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleBefore implements `before` rule:\n// The datetime value should be after the value of field `field`.\n//\n// Format: before:field\ntype RuleBefore struct{}\n\nfunc init() {\n\tRegister(RuleBefore{})\n}\n\nfunc (r RuleBefore) Name() string {\n\treturn \"before\"\n}\n\nfunc (r RuleBefore) Message() string {\n\treturn \"The {field} value `{value}` must be before field {field1} value `{value1}`\"\n}\n\nfunc (r RuleBefore) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tvalueDatetime         = in.Value.Time()\n\t\tfieldDatetime         = gconv.Time(fieldValue)\n\t)\n\tif valueDatetime.Before(fieldDatetime) {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\"{field1}\": fieldName,\n\t\t\"{value1}\": gconv.String(fieldValue),\n\t}))\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_before_equal.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleBeforeEqual implements `before-equal` rule:\n// The datetime value should be after or equal to the value of field `field`.\n//\n// Format: before-equal:field\ntype RuleBeforeEqual struct{}\n\nfunc init() {\n\tRegister(RuleBeforeEqual{})\n}\n\nfunc (r RuleBeforeEqual) Name() string {\n\treturn \"before-equal\"\n}\n\nfunc (r RuleBeforeEqual) Message() string {\n\treturn \"The {field} value `{value}` must be before or equal to field {pattern}\"\n}\n\nfunc (r RuleBeforeEqual) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tvalueDatetime         = in.Value.Time()\n\t\tfieldDatetime         = gconv.Time(fieldValue)\n\t)\n\tif valueDatetime.Before(fieldDatetime) || valueDatetime.Equal(fieldDatetime) {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\"{field1}\": fieldName,\n\t\t\"{value1}\": gconv.String(fieldValue),\n\t}))\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_between.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RuleBetween implements `between` rule:\n// Range between :min and :max. It supports both integer and float.\n//\n// Format: between:min,max\ntype RuleBetween struct{}\n\nfunc init() {\n\tRegister(RuleBetween{})\n}\n\nfunc (r RuleBetween) Name() string {\n\treturn \"between\"\n}\n\nfunc (r RuleBetween) Message() string {\n\treturn \"The {field} value `{value}` must be between {min} and {max}\"\n}\n\nfunc (r RuleBetween) Run(in RunInput) error {\n\tvar (\n\t\tarray = strings.Split(in.RulePattern, \",\")\n\t\tmin   = float64(0)\n\t\tmax   = float64(0)\n\t)\n\tif len(array) > 0 {\n\t\tif v, err := strconv.ParseFloat(strings.TrimSpace(array[0]), 64); err == nil {\n\t\t\tmin = v\n\t\t}\n\t}\n\tif len(array) > 1 {\n\t\tif v, err := strconv.ParseFloat(strings.TrimSpace(array[1]), 64); err == nil {\n\t\t\tmax = v\n\t\t}\n\t}\n\tvalueF, err := strconv.ParseFloat(in.Value.String(), 64)\n\tif valueF < min || valueF > max || err != nil {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{min}\": strconv.FormatFloat(min, 'f', -1, 64),\n\t\t\t\"{max}\": strconv.FormatFloat(max, 'f', -1, 64),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_boolean.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n)\n\n// RuleBoolean implements `boolean` rule:\n// Boolean(1,true,on,yes:true | 0,false,off,no,\"\":false)\n//\n// Format: boolean\ntype RuleBoolean struct{}\n\n// boolMap defines the boolean values.\nvar boolMap = map[string]struct{}{\n\t\"1\":     {},\n\t\"true\":  {},\n\t\"on\":    {},\n\t\"yes\":   {},\n\t\"\":      {},\n\t\"0\":     {},\n\t\"false\": {},\n\t\"off\":   {},\n\t\"no\":    {},\n}\n\nfunc init() {\n\tRegister(RuleBoolean{})\n}\n\nfunc (r RuleBoolean) Name() string {\n\treturn \"boolean\"\n}\n\nfunc (r RuleBoolean) Message() string {\n\treturn \"The {field} value `{value}` field must be true or false\"\n}\n\nfunc (r RuleBoolean) Run(in RunInput) error {\n\tif _, ok := boolMap[strings.ToLower(in.Value.String())]; ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_ci.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\n// RuleCi implements `ci` rule:\n// Case-Insensitive configuration for those rules that need value comparison like:\n// same, different, in, not-in, etc.\n//\n// Format: ci\ntype RuleCi struct{}\n\nfunc init() {\n\tRegister(RuleCi{})\n}\n\nfunc (r RuleCi) Name() string {\n\treturn \"ci\"\n}\n\nfunc (r RuleCi) Message() string {\n\treturn \"\"\n}\n\nfunc (r RuleCi) Run(in RunInput) error {\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_date.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleDate implements `date` rule:\n// Standard date, like: 2006-01-02, 20060102, 2006.01.02.\n//\n// Format: date\ntype RuleDate struct{}\n\nfunc init() {\n\tRegister(RuleDate{})\n}\n\nfunc (r RuleDate) Name() string {\n\treturn \"date\"\n}\n\nfunc (r RuleDate) Message() string {\n\treturn \"The {field} value `{value}` is not a valid date\"\n}\n\nfunc (r RuleDate) Run(in RunInput) error {\n\ttype iTime interface {\n\t\tDate() (year int, month time.Month, day int)\n\t\tIsZero() bool\n\t}\n\t// support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.\n\tif obj, ok := in.Value.Val().(iTime); ok {\n\t\tif obj.IsZero() {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t}\n\tif !gregex.IsMatchString(\n\t\t`\\d{4}[\\.\\-\\_/]{0,1}\\d{2}[\\.\\-\\_/]{0,1}\\d{2}`,\n\t\tin.Value.String(),\n\t) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_date_format.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// RuleDateFormat implements `date-format` rule:\n// Custom date format.\n//\n// Format: date-format:format\ntype RuleDateFormat struct{}\n\nfunc init() {\n\tRegister(RuleDateFormat{})\n}\n\nfunc (r RuleDateFormat) Name() string {\n\treturn \"date-format\"\n}\n\nfunc (r RuleDateFormat) Message() string {\n\treturn \"The {field} value `{value}` does not match the format: {pattern}\"\n}\n\nfunc (r RuleDateFormat) Run(in RunInput) error {\n\ttype iTime interface {\n\t\tDate() (year int, month time.Month, day int)\n\t\tIsZero() bool\n\t}\n\t// support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.\n\tif obj, ok := in.Value.Val().(iTime); ok {\n\t\tif obj.IsZero() {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t}\n\tif _, err := gtime.StrToTimeFormat(in.Value.String(), in.RulePattern); err != nil {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_datetime.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/os/gtime\"\n)\n\n// RuleDatetime implements `datetime` rule:\n// Standard datetime, like: 2006-01-02 12:00:00.\n//\n// Format: datetime\ntype RuleDatetime struct{}\n\nfunc init() {\n\tRegister(RuleDatetime{})\n}\n\nfunc (r RuleDatetime) Name() string {\n\treturn \"datetime\"\n}\n\nfunc (r RuleDatetime) Message() string {\n\treturn \"The {field} value `{value}` is not a valid datetime\"\n}\n\nfunc (r RuleDatetime) Run(in RunInput) error {\n\ttype iTime interface {\n\t\tDate() (year int, month time.Month, day int)\n\t\tIsZero() bool\n\t}\n\t// support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.\n\tif obj, ok := in.Value.Val().(iTime); ok {\n\t\tif obj.IsZero() {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t\treturn nil\n\t}\n\tif _, err := gtime.StrToTimeFormat(in.Value.String(), `Y-m-d H:i:s`); err != nil {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_different.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleDifferent implements `different` rule:\n// Value should be different from value of field.\n//\n// Format: different:field\ntype RuleDifferent struct{}\n\nfunc init() {\n\tRegister(RuleDifferent{})\n}\n\nfunc (r RuleDifferent) Name() string {\n\treturn \"different\"\n}\n\nfunc (r RuleDifferent) Message() string {\n\treturn \"The {field} value `{value}` must be different from field {field1} value `{value1}`\"\n}\n\nfunc (r RuleDifferent) Run(in RunInput) error {\n\tvar (\n\t\tok    = true\n\t\tvalue = in.Value.String()\n\t)\n\tfieldName, fieldValue := gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\tif fieldValue != nil {\n\t\tif in.Option.CaseInsensitive {\n\t\t\tok = !strings.EqualFold(value, gconv.String(fieldValue))\n\t\t} else {\n\t\t\tok = strings.Compare(value, gconv.String(fieldValue)) != 0\n\t\t}\n\t}\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\"{field1}\": fieldName,\n\t\t\"{value1}\": gconv.String(fieldValue),\n\t}))\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_domain.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleDomain implements `domain` rule:\n// Domain.\n//\n// Format: domain\ntype RuleDomain struct{}\n\nfunc init() {\n\tRegister(RuleDomain{})\n}\n\nfunc (r RuleDomain) Name() string {\n\treturn \"domain\"\n}\n\nfunc (r RuleDomain) Message() string {\n\treturn \"The {field} value `{value}` is not a valid domain format\"\n}\n\nfunc (r RuleDomain) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^([0-9a-zA-Z][0-9a-zA-Z\\-]{0,62}\\.)+([a-zA-Z]{0,62})$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_email.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleEmail implements `email` rule:\n// Email address.\n//\n// Format: email\ntype RuleEmail struct{}\n\nfunc init() {\n\tRegister(RuleEmail{})\n}\n\nfunc (r RuleEmail) Name() string {\n\treturn \"email\"\n}\n\nfunc (r RuleEmail) Message() string {\n\treturn \"The {field} value `{value}` is not a valid email address\"\n}\n\nfunc (r RuleEmail) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^[a-zA-Z0-9_\\-\\.]+@[a-zA-Z0-9_\\-]+(\\.[a-zA-Z0-9_\\-]+)+$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_enums.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/internal/json\"\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gtag\"\n)\n\n// RuleEnums implements `enums` rule:\n// Value should be in enums of its constant type.\n//\n// Format: enums\ntype RuleEnums struct{}\n\nfunc init() {\n\tRegister(RuleEnums{})\n}\n\nfunc (r RuleEnums) Name() string {\n\treturn \"enums\"\n}\n\nfunc (r RuleEnums) Message() string {\n\treturn \"The {field} value `{value}` should be in enums of: {enums}\"\n}\n\nfunc (r RuleEnums) Run(in RunInput) error {\n\tif in.ValueType == nil {\n\t\treturn gerror.NewCode(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`value type cannot be empty to use validation rule \"enums\"`,\n\t\t)\n\t}\n\tvar (\n\t\tpkgPath  = in.ValueType.PkgPath()\n\t\ttypeName = in.ValueType.Name()\n\t\ttypeKind = in.ValueType.Kind()\n\t)\n\tif typeKind == reflect.Slice || typeKind == reflect.Pointer {\n\t\tpkgPath = in.ValueType.Elem().PkgPath()\n\t\ttypeName = in.ValueType.Elem().Name()\n\t}\n\tif pkgPath == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t`no pkg path found for type \"%s\"`,\n\t\t\tin.ValueType.String(),\n\t\t)\n\t}\n\tvar (\n\t\ttypeId   = fmt.Sprintf(`%s.%s`, pkgPath, typeName)\n\t\ttagEnums = gtag.GetEnumsByType(typeId)\n\t)\n\tif tagEnums == \"\" {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidOperation,\n\t\t\t`no enums found for type \"%s\", missing using command \"gf gen enums\"?`,\n\t\t\ttypeId,\n\t\t)\n\t}\n\tvar enumsValues = make([]any, 0)\n\tif err := json.Unmarshal([]byte(tagEnums), &enumsValues); err != nil {\n\t\treturn err\n\t}\n\tif !gstr.InArray(gconv.Strings(enumsValues), in.Value.String()) {\n\t\treturn errors.New(gstr.Replace(\n\t\t\tin.Message, `{enums}`, tagEnums,\n\t\t))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_eq.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\n// RuleEq implements `eq` rule:\n// Value should be the same as value of field.\n//\n// This rule performs the same as rule `same`.\n//\n// Format: eq:field\ntype RuleEq struct{}\n\nfunc init() {\n\tRegister(RuleEq{})\n}\n\nfunc (r RuleEq) Name() string {\n\treturn \"eq\"\n}\n\nfunc (r RuleEq) Message() string {\n\treturn \"The {field} value `{value}` must be equal to field {field1} value `{value1}`\"\n}\n\nfunc (r RuleEq) Run(in RunInput) error {\n\treturn RuleSame{}.Run(in)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_float.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\n// RuleFloat implements `float` rule:\n// Float. Note that an integer is actually a float number.\n//\n// Format: float\ntype RuleFloat struct{}\n\nfunc init() {\n\tRegister(RuleFloat{})\n}\n\nfunc (r RuleFloat) Name() string {\n\treturn \"float\"\n}\n\nfunc (r RuleFloat) Message() string {\n\treturn \"The {field} value `{value}` is not of valid float type\"\n}\n\nfunc (r RuleFloat) Run(in RunInput) error {\n\tif _, err := strconv.ParseFloat(in.Value.String(), 64); err == nil {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_foreach.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\n// RuleForeach implements `foreach` rule:\n// It tells the next validation using current value as an array and validates each of its element.\n//\n// Format: foreach\ntype RuleForeach struct{}\n\nfunc init() {\n\tRegister(RuleForeach{})\n}\n\nfunc (r RuleForeach) Name() string {\n\treturn \"foreach\"\n}\n\nfunc (r RuleForeach) Message() string {\n\treturn \"\"\n}\n\nfunc (r RuleForeach) Run(in RunInput) error {\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_gt.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleGT implements `gt` rule:\n// Greater than `field`.\n// It supports both integer and float.\n//\n// Format: gt:field\ntype RuleGT struct{}\n\nfunc init() {\n\tRegister(RuleGT{})\n}\n\nfunc (r RuleGT) Name() string {\n\treturn \"gt\"\n}\n\nfunc (r RuleGT) Message() string {\n\treturn \"The {field} value `{value}` must be greater than field {field1} value `{value1}`\"\n}\n\nfunc (r RuleGT) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tfieldValueN, err1     = strconv.ParseFloat(gconv.String(fieldValue), 64)\n\t\tvalueN, err2          = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\n\tif valueN <= fieldValueN || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{field1}\": fieldName,\n\t\t\t\"{value1}\": gconv.String(fieldValue),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_gte.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleGTE implements `gte` rule:\n// Greater than or equal to `field`.\n// It supports both integer and float.\n//\n// Format: gte:field\ntype RuleGTE struct{}\n\nfunc init() {\n\tRegister(RuleGTE{})\n}\n\nfunc (r RuleGTE) Name() string {\n\treturn \"gte\"\n}\n\nfunc (r RuleGTE) Message() string {\n\treturn \"The {field} value `{value}` must be greater than or equal to field {field1} value `{value1}`\"\n}\n\nfunc (r RuleGTE) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tfieldValueN, err1     = strconv.ParseFloat(gconv.String(fieldValue), 64)\n\t\tvalueN, err2          = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\n\tif valueN < fieldValueN || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{field1}\": fieldName,\n\t\t\t\"{value1}\": gconv.String(fieldValue),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_in.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RuleIn implements `in` rule:\n// Value should be in: value1,value2,...\n//\n// Format: in:value1,value2,...\ntype RuleIn struct{}\n\nfunc init() {\n\tRegister(RuleIn{})\n}\n\nfunc (r RuleIn) Name() string {\n\treturn \"in\"\n}\n\nfunc (r RuleIn) Message() string {\n\treturn \"The {field} value `{value}` is not in acceptable range: {pattern}\"\n}\n\nfunc (r RuleIn) Run(in RunInput) error {\n\tvar (\n\t\tok               bool\n\t\tinputValueString = in.Value.String()\n\t)\n\n\tfor _, rulePattern := range gstr.SplitAndTrim(in.RulePattern, \",\") {\n\t\tif in.Option.CaseInsensitive {\n\t\t\tok = strings.EqualFold(inputValueString, strings.TrimSpace(rulePattern))\n\t\t} else {\n\t\t\tok = strings.Compare(inputValueString, strings.TrimSpace(rulePattern)) == 0\n\t\t}\n\t\tif ok {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_integer.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\n// RuleInteger implements `integer` rule:\n// Integer.\n//\n// Format: integer\ntype RuleInteger struct{}\n\nfunc init() {\n\tRegister(RuleInteger{})\n}\n\nfunc (r RuleInteger) Name() string {\n\treturn \"integer\"\n}\n\nfunc (r RuleInteger) Message() string {\n\treturn \"The {field} value `{value}` is not an integer\"\n}\n\nfunc (r RuleInteger) Run(in RunInput) error {\n\tif _, err := strconv.Atoi(in.Value.String()); err == nil {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_ip.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n\t\"github.com/gogf/gf/v2/net/gipv6\"\n)\n\n// RuleIp implements `ip` rule:\n// IPv4/IPv6.\n//\n// Format: ip\ntype RuleIp struct{}\n\nfunc init() {\n\tRegister(RuleIp{})\n}\n\nfunc (r RuleIp) Name() string {\n\treturn \"ip\"\n}\n\nfunc (r RuleIp) Message() string {\n\treturn \"The {field} value `{value}` is not a valid IP address\"\n}\n\nfunc (r RuleIp) Run(in RunInput) error {\n\tvar (\n\t\tok    bool\n\t\tvalue = in.Value.String()\n\t)\n\tif ok = gipv4.Validate(value) || gipv6.Validate(value); !ok {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_ipv4.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/net/gipv4\"\n)\n\n// RuleIpv4 implements `ipv4` rule:\n// IPv4.\n//\n// Format: ipv4\ntype RuleIpv4 struct{}\n\nfunc init() {\n\tRegister(RuleIpv4{})\n}\n\nfunc (r RuleIpv4) Name() string {\n\treturn \"ipv4\"\n}\n\nfunc (r RuleIpv4) Message() string {\n\treturn \"The {field} value `{value}` is not a valid IPv4 address\"\n}\n\nfunc (r RuleIpv4) Run(in RunInput) error {\n\tvar (\n\t\tok    bool\n\t\tvalue = in.Value.String()\n\t)\n\tif ok = gipv4.Validate(value); !ok {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_ipv6.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/net/gipv6\"\n)\n\n// RuleIpv6 implements `ipv6` rule:\n// IPv6.\n//\n// Format: ipv6\ntype RuleIpv6 struct{}\n\nfunc init() {\n\tRegister(RuleIpv6{})\n}\n\nfunc (r RuleIpv6) Name() string {\n\treturn \"ipv6\"\n}\n\nfunc (r RuleIpv6) Message() string {\n\treturn \"The {field} value `{value}` is not a valid IPv6 address\"\n}\n\nfunc (r RuleIpv6) Run(in RunInput) error {\n\tvar (\n\t\tok    bool\n\t\tvalue = in.Value.String()\n\t)\n\tif ok = gipv6.Validate(value); !ok {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_json.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/internal/json\"\n)\n\n// RuleJson implements `json` rule:\n// JSON.\n//\n// Format: json\ntype RuleJson struct{}\n\nfunc init() {\n\tRegister(RuleJson{})\n}\n\nfunc (r RuleJson) Name() string {\n\treturn \"json\"\n}\n\nfunc (r RuleJson) Message() string {\n\treturn \"The {field} value `{value}` is not a valid JSON string\"\n}\n\nfunc (r RuleJson) Run(in RunInput) error {\n\tif json.Valid(in.Value.Bytes()) {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_length.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// RuleLength implements `length` rule:\n// Length between :min and :max.\n// The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.\n//\n// Format: length:min,max\ntype RuleLength struct{}\n\nfunc init() {\n\tRegister(RuleLength{})\n}\n\nfunc (r RuleLength) Name() string {\n\treturn \"length\"\n}\n\nfunc (r RuleLength) Message() string {\n\treturn \"The {field} value `{value}` length must be between {min} and {max}\"\n}\n\nfunc (r RuleLength) Run(in RunInput) error {\n\tvar (\n\t\tvalueRunes = gconv.Runes(in.Value.String())\n\t\tvalueLen   = len(valueRunes)\n\t)\n\tvar (\n\t\tmin   = 0\n\t\tmax   = 0\n\t\tarray = strings.Split(in.RulePattern, \",\")\n\t)\n\tif len(array) > 0 {\n\t\tif v, err := strconv.Atoi(strings.TrimSpace(array[0])); err == nil {\n\t\t\tmin = v\n\t\t}\n\t}\n\tif len(array) > 1 {\n\t\tif v, err := strconv.Atoi(strings.TrimSpace(array[1])); err == nil {\n\t\t\tmax = v\n\t\t}\n\t}\n\tif valueLen < min || valueLen > max {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{min}\": strconv.Itoa(min),\n\t\t\t\"{max}\": strconv.Itoa(max),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_lowercase.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleLowercase implements `lowercase` rule:\n// Lowercase alphabetic characters (a-z).\n//\n// Format: lowercase\ntype RuleLowercase struct{}\n\nfunc init() {\n\tRegister(RuleLowercase{})\n}\n\nfunc (r RuleLowercase) Name() string {\n\treturn \"lowercase\"\n}\n\nfunc (r RuleLowercase) Message() string {\n\treturn \"The {field} value `{value}` must be lowercase\"\n}\n\nfunc (r RuleLowercase) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[a-z]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_lt.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleLT implements `lt` rule:\n// Lesser than `field`.\n// It supports both integer and float.\n//\n// Format: lt:field\ntype RuleLT struct{}\n\nfunc init() {\n\tRegister(RuleLT{})\n}\n\nfunc (r RuleLT) Name() string {\n\treturn \"lt\"\n}\n\nfunc (r RuleLT) Message() string {\n\treturn \"The {field} value `{value}` must be lesser than field {field1} value `{value1}`\"\n}\n\nfunc (r RuleLT) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tfieldValueN, err1     = strconv.ParseFloat(gconv.String(fieldValue), 64)\n\t\tvalueN, err2          = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\n\tif valueN >= fieldValueN || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{field1}\": fieldName,\n\t\t\t\"{value1}\": gconv.String(fieldValue),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_lte.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleLTE implements `lte` rule:\n// Lesser than or equal to `field`.\n// It supports both integer and float.\n//\n// Format: lte:field\ntype RuleLTE struct{}\n\nfunc init() {\n\tRegister(RuleLTE{})\n}\n\nfunc (r RuleLTE) Name() string {\n\treturn \"lte\"\n}\n\nfunc (r RuleLTE) Message() string {\n\treturn \"The {field} value `{value}` must be lesser than or equal to field {field1} value `{value1}`\"\n}\n\nfunc (r RuleLTE) Run(in RunInput) error {\n\tvar (\n\t\tfieldName, fieldValue = gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\t\tfieldValueN, err1     = strconv.ParseFloat(gconv.String(fieldValue), 64)\n\t\tvalueN, err2          = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\n\tif valueN > fieldValueN || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{field1}\": fieldName,\n\t\t\t\"{value1}\": gconv.String(fieldValue),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_mac.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleMac implements `mac` rule:\n// MAC.\n//\n// Format: mac\ntype RuleMac struct{}\n\nfunc init() {\n\tRegister(RuleMac{})\n}\n\nfunc (r RuleMac) Name() string {\n\treturn \"mac\"\n}\n\nfunc (r RuleMac) Message() string {\n\treturn \"The {field} value `{value}` is not a valid MAC address\"\n}\n\nfunc (r RuleMac) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^([0-9A-Fa-f]{2}[\\-:]){5}[0-9A-Fa-f]{2}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_max.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RuleMax implements `max` rule:\n// Equal or lesser than :max. It supports both integer and float.\n//\n// Format: max:max\ntype RuleMax struct{}\n\nfunc init() {\n\tRegister(RuleMax{})\n}\n\nfunc (r RuleMax) Name() string {\n\treturn \"max\"\n}\n\nfunc (r RuleMax) Message() string {\n\treturn \"The {field} value `{value}` must be equal or lesser than {max}\"\n}\n\nfunc (r RuleMax) Run(in RunInput) error {\n\tvar (\n\t\tmax, err1    = strconv.ParseFloat(in.RulePattern, 64)\n\t\tvalueN, err2 = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\tif valueN > max || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.Replace(in.Message, \"{max}\", strconv.FormatFloat(max, 'f', -1, 64)))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_max_length.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// RuleMaxLength implements `max-length` rule:\n// Length is equal or lesser than :max.\n// The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.\n//\n// Format: max-length:max\ntype RuleMaxLength struct{}\n\nfunc init() {\n\tRegister(RuleMaxLength{})\n}\n\nfunc (r RuleMaxLength) Name() string {\n\treturn \"max-length\"\n}\n\nfunc (r RuleMaxLength) Message() string {\n\treturn \"The {field} value `{value}` length must be equal or lesser than {max}\"\n}\n\nfunc (r RuleMaxLength) Run(in RunInput) error {\n\tvar (\n\t\tvalueRunes = gconv.Runes(in.Value.String())\n\t\tvalueLen   = len(valueRunes)\n\t)\n\tmax, err := strconv.Atoi(in.RulePattern)\n\tif valueLen > max || err != nil {\n\t\treturn errors.New(gstr.Replace(in.Message, \"{max}\", strconv.Itoa(max)))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_min.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RuleMin implements `min` rule:\n// Equal or greater than :min. It supports both integer and float.\n//\n// Format: min:min\ntype RuleMin struct{}\n\nfunc init() {\n\tRegister(RuleMin{})\n}\n\nfunc (r RuleMin) Name() string {\n\treturn \"min\"\n}\n\nfunc (r RuleMin) Message() string {\n\treturn \"The {field} value `{value}` must be equal or greater than {min}\"\n}\n\nfunc (r RuleMin) Run(in RunInput) error {\n\tvar (\n\t\tmin, err1    = strconv.ParseFloat(in.RulePattern, 64)\n\t\tvalueN, err2 = strconv.ParseFloat(in.Value.String(), 64)\n\t)\n\tif valueN < min || err1 != nil || err2 != nil {\n\t\treturn errors.New(gstr.Replace(in.Message, \"{min}\", strconv.FormatFloat(min, 'f', -1, 64)))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_min_length.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// RuleMinLength implements `min-length` rule:\n// Length is equal or greater than :min.\n// The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.\n//\n// Format: min-length:min\ntype RuleMinLength struct{}\n\nfunc init() {\n\tRegister(RuleMinLength{})\n}\n\nfunc (r RuleMinLength) Name() string {\n\treturn \"min-length\"\n}\n\nfunc (r RuleMinLength) Message() string {\n\treturn \"The {field} value `{value}` length must be equal or greater than {min}\"\n}\n\nfunc (r RuleMinLength) Run(in RunInput) error {\n\tvar (\n\t\tvalueRunes = gconv.Runes(in.Value.String())\n\t\tvalueLen   = len(valueRunes)\n\t)\n\tmin, err := strconv.Atoi(in.RulePattern)\n\tif valueLen < min || err != nil {\n\t\treturn errors.New(gstr.Replace(in.Message, \"{min}\", strconv.Itoa(min)))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_not_eq.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\n// RuleNotEq implements `not-eq` rule:\n// Value should be different from value of field.\n//\n// Format: not-eq:field\ntype RuleNotEq struct{}\n\nfunc init() {\n\tRegister(RuleNotEq{})\n}\n\nfunc (r RuleNotEq) Name() string {\n\treturn \"not-eq\"\n}\n\nfunc (r RuleNotEq) Message() string {\n\treturn \"The {field} value `{value}` must not be equal to field {field1} value `{value1}`\"\n}\n\nfunc (r RuleNotEq) Run(in RunInput) error {\n\treturn RuleDifferent{}.Run(in)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_not_in.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n)\n\n// RuleNotIn implements `not-in` rule:\n// Value should not be in: value1,value2,...\n//\n// Format: not-in:value1,value2,...\ntype RuleNotIn struct{}\n\nfunc init() {\n\tRegister(RuleNotIn{})\n}\n\nfunc (r RuleNotIn) Name() string {\n\treturn \"not-in\"\n}\n\nfunc (r RuleNotIn) Message() string {\n\treturn \"The {field} value `{value}` must not be in range: {pattern}\"\n}\n\nfunc (r RuleNotIn) Run(in RunInput) error {\n\tvar (\n\t\tok    = true\n\t\tvalue = in.Value.String()\n\t)\n\tfor _, rulePattern := range gstr.SplitAndTrim(in.RulePattern, \",\") {\n\t\tif in.Option.CaseInsensitive {\n\t\t\tok = !strings.EqualFold(value, strings.TrimSpace(rulePattern))\n\t\t} else {\n\t\t\tok = strings.Compare(value, strings.TrimSpace(rulePattern)) != 0\n\t\t}\n\t\tif !ok {\n\t\t\treturn errors.New(in.Message)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_not_regex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleNotRegex implements `not-regex` rule:\n// Value should not match custom regular expression pattern.\n//\n// Format: not-regex:pattern\ntype RuleNotRegex struct{}\n\nfunc init() {\n\tRegister(RuleNotRegex{})\n}\n\nfunc (r RuleNotRegex) Name() string {\n\treturn \"not-regex\"\n}\n\nfunc (r RuleNotRegex) Message() string {\n\treturn \"The {field} value `{value}` should not be in regex of: {pattern}\"\n}\n\nfunc (r RuleNotRegex) Run(in RunInput) error {\n\tif gregex.IsMatchString(in.RulePattern, in.Value.String()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_numeric.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleNumeric implements `numeric` rule:\n// Numeric string (0-9).\n//\n// Format: numeric\ntype RuleNumeric struct{}\n\nfunc init() {\n\tRegister(RuleNumeric{})\n}\n\nfunc (r RuleNumeric) Name() string {\n\treturn \"numeric\"\n}\n\nfunc (r RuleNumeric) Message() string {\n\treturn \"The {field} value `{value}` must be numeric\"\n}\n\nfunc (r RuleNumeric) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[0-9]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_passport.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePassport implements `passport` rule:\n// Universal passport format rule:\n// Starting with letter, containing only numbers or underscores, length between 6 and 18\n//\n// Format: passport\ntype RulePassport struct{}\n\nfunc init() {\n\tRegister(RulePassport{})\n}\n\nfunc (r RulePassport) Name() string {\n\treturn \"passport\"\n}\n\nfunc (r RulePassport) Message() string {\n\treturn \"The {field} value `{value}` is not a valid passport format\"\n}\n\nfunc (r RulePassport) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^[a-zA-Z]{1}\\w{5,17}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_password.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePassword implements `password` rule:\n// Universal password format rule1:\n// Containing any visible chars, length between 6 and 18.\n//\n// Format: password\ntype RulePassword struct{}\n\nfunc init() {\n\tRegister(RulePassword{})\n}\n\nfunc (r RulePassword) Name() string {\n\treturn \"password\"\n}\n\nfunc (r RulePassword) Message() string {\n\treturn \"The {field} value `{value}` is not a valid password format\"\n}\n\nfunc (r RulePassword) Run(in RunInput) error {\n\tif !gregex.IsMatchString(`^[\\w\\S]{6,18}$`, in.Value.String()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_password2.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePassword2 implements `password2` rule:\n// Universal password format rule2:\n// Must meet password rule1, must contain lower and upper letters and numbers.\n//\n// Format: password2\ntype RulePassword2 struct{}\n\nfunc init() {\n\tRegister(RulePassword2{})\n}\n\nfunc (r RulePassword2) Name() string {\n\treturn \"password2\"\n}\n\nfunc (r RulePassword2) Message() string {\n\treturn \"The {field} value `{value}` is not a valid password2 format\"\n}\n\nfunc (r RulePassword2) Run(in RunInput) error {\n\tvar value = in.Value.String()\n\tif gregex.IsMatchString(`^[\\w\\S]{6,18}$`, value) &&\n\t\tgregex.IsMatchString(`[a-z]+`, value) &&\n\t\tgregex.IsMatchString(`[A-Z]+`, value) &&\n\t\tgregex.IsMatchString(`\\d+`, value) {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_password3.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePassword3 implements `password3` rule:\n// Universal password format rule3:\n// Must meet password rule1, must contain lower and upper letters, numbers and special chars.\n//\n// Format: password3\ntype RulePassword3 struct{}\n\nfunc init() {\n\tRegister(RulePassword3{})\n}\n\nfunc (r RulePassword3) Name() string {\n\treturn \"password3\"\n}\n\nfunc (r RulePassword3) Message() string {\n\treturn \"The {field} value `{value}` is not a valid password3 format\"\n}\n\nfunc (r RulePassword3) Run(in RunInput) error {\n\tvar value = in.Value.String()\n\tif gregex.IsMatchString(`^[\\w\\S]{6,18}$`, value) &&\n\t\tgregex.IsMatchString(`[a-z]+`, value) &&\n\t\tgregex.IsMatchString(`[A-Z]+`, value) &&\n\t\tgregex.IsMatchString(`\\d+`, value) &&\n\t\tgregex.IsMatchString(`[^a-zA-Z0-9]+`, value) {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_phone.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePhone implements `phone` rule:\n//\n//  1. China Mobile:\n//     134, 135, 136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 182, 183, 184, 187, 188,\n//     178(4G), 147(Net)；\n//     172\n//\n//  2. China Unicom:\n//     130, 131, 132, 155, 156, 185, 186 ,176(4G), 145(Net), 175\n//\n//  3. China Telecom:\n//     133, 153, 180, 181, 189, 177(4G)\n//\n//  4. Satellite:\n//     1349\n//\n//  5. Virtual:\n//     170, 171, 173\n//\n//  6. 2018:\n//     16x, 19x\n//\n// Format: phone\ntype RulePhone struct{}\n\nfunc init() {\n\tRegister(RulePhone{})\n}\n\nfunc (r RulePhone) Name() string {\n\treturn \"phone\"\n}\n\nfunc (r RulePhone) Message() string {\n\treturn \"The {field} value `{value}` is not a valid phone number\"\n}\n\nfunc (r RulePhone) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^13[\\d]{9}$|^14[5,7]{1}\\d{8}$|^15[^4]{1}\\d{8}$|^16[\\d]{9}$|^17[0,1,2,3,5,6,7,8]{1}\\d{8}$|^18[\\d]{9}$|^19[\\d]{9}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_phone_loose.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePhoneLoose implements `phone-loose` rule:\n// Loose mobile phone number verification.\n// As long as the 11 digits numbers beginning with\n// 13, 14, 15, 16, 17, 18, 19 can pass the verification\n// (Any 11-digit numbers starting with 13, 14, 15, 16, 17, 18, 19 can pass the validation).\n//\n// Format: phone-loose\ntype RulePhoneLoose struct{}\n\nfunc init() {\n\tRegister(RulePhoneLoose{})\n}\n\nfunc (r RulePhoneLoose) Name() string {\n\treturn \"phone-loose\"\n}\n\nfunc (r RulePhoneLoose) Message() string {\n\treturn \"The {field} value `{value}` is not a valid phone number\"\n}\n\nfunc (r RulePhoneLoose) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^1(3|4|5|6|7|8|9)\\d{9}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_postcode.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RulePostcode implements `postcode` rule:\n// Postcode number.\n//\n// Format: postcode\ntype RulePostcode struct{}\n\nfunc init() {\n\tRegister(RulePostcode{})\n}\n\nfunc (r RulePostcode) Name() string {\n\treturn \"postcode\"\n}\n\nfunc (r RulePostcode) Message() string {\n\treturn \"The {field} value `{value}` is not a valid postcode format\"\n}\n\nfunc (r RulePostcode) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^\\d{6}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_qq.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleQQ implements `qq` rule:\n// Tencent QQ number.\n//\n// Format: qq\ntype RuleQQ struct{}\n\nfunc init() {\n\tRegister(RuleQQ{})\n}\n\nfunc (r RuleQQ) Name() string {\n\treturn \"qq\"\n}\n\nfunc (r RuleQQ) Message() string {\n\treturn \"The {field} value `{value}` is not a valid QQ number\"\n}\n\nfunc (r RuleQQ) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^[1-9][0-9]{4,}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_regex.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleRegex implements `regex` rule:\n// Value should match custom regular expression pattern.\n//\n// Format: regex:pattern\ntype RuleRegex struct{}\n\nfunc init() {\n\tRegister(RuleRegex{})\n}\n\nfunc (r RuleRegex) Name() string {\n\treturn \"regex\"\n}\n\nfunc (r RuleRegex) Message() string {\n\treturn \"The {field} value `{value}` must be in regex of: {pattern}\"\n}\n\nfunc (r RuleRegex) Run(in RunInput) error {\n\tif !gregex.IsMatchString(in.RulePattern, in.Value.String()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// RuleRequired implements `required` rule.\n// Format: required\ntype RuleRequired struct{}\n\nfunc init() {\n\tRegister(RuleRequired{})\n}\n\nfunc (r RuleRequired) Name() string {\n\treturn \"required\"\n}\n\nfunc (r RuleRequired) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequired) Run(in RunInput) error {\n\tif isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n\n// isRequiredEmpty checks and returns whether given value is empty string.\n// Note that if given value is a zero integer, it will be considered as not empty.\nfunc isRequiredEmpty(value any) bool {\n\treflectValue := reflect.ValueOf(value)\n\tfor reflectValue.Kind() == reflect.Pointer {\n\t\treflectValue = reflectValue.Elem()\n\t}\n\tswitch reflectValue.Kind() {\n\tcase reflect.String, reflect.Map, reflect.Array, reflect.Slice:\n\t\treturn reflectValue.Len() == 0\n\t}\n\treturn gconv.String(value) == \"\"\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_if.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredIf implements `required-if` rule:\n// Required if any of given field and its value are equal.\n//\n// Format:  required-if:field,value,...\n// Example: required-if:id,1,age,18\ntype RuleRequiredIf struct{}\n\nfunc init() {\n\tRegister(RuleRequiredIf{})\n}\n\nfunc (r RuleRequiredIf) Name() string {\n\treturn \"required-if\"\n}\n\nfunc (r RuleRequiredIf) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredIf) Run(in RunInput) error {\n\tvar (\n\t\trequired   = false\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\tif len(array)%2 != 0 {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid \"%s\" rule pattern: %s`,\n\t\t\tr.Name(),\n\t\t\tin.RulePattern,\n\t\t)\n\t}\n\t// It supports multiple field and value pairs.\n\tfor i := 0; i < len(array); {\n\t\tvar (\n\t\t\ttk = array[i]\n\t\t\ttv = array[i+1]\n\t\t)\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)\n\t\tif in.Option.CaseInsensitive {\n\t\t\trequired = strings.EqualFold(tv, gconv.String(foundValue))\n\t\t} else {\n\t\t\trequired = strings.Compare(tv, gconv.String(foundValue)) == 0\n\t\t}\n\t\tif required {\n\t\t\tbreak\n\t\t}\n\t\ti += 2\n\t}\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_if_all.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/errors/gcode\"\n\t\"github.com/gogf/gf/v2/errors/gerror\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredIfAll implements `required-if-all` rule:\n// Required if all given field and its value are equal.\n//\n// Format:  required-if-all:field,value,...\n// Example: required-if-all:id,1,age,18\ntype RuleRequiredIfAll struct{}\n\nfunc init() {\n\tRegister(RuleRequiredIfAll{})\n}\n\nfunc (r RuleRequiredIfAll) Name() string {\n\treturn \"required-if-all\"\n}\n\nfunc (r RuleRequiredIfAll) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredIfAll) Run(in RunInput) error {\n\tvar (\n\t\trequired   = true\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\tif len(array)%2 != 0 {\n\t\treturn gerror.NewCodef(\n\t\t\tgcode.CodeInvalidParameter,\n\t\t\t`invalid \"%s\" rule pattern: %s`,\n\t\t\tr.Name(),\n\t\t\tin.RulePattern,\n\t\t)\n\t}\n\tfor i := 0; i < len(array); {\n\t\tvar (\n\t\t\ttk = array[i]\n\t\t\ttv = array[i+1]\n\t\t\teq bool\n\t\t)\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)\n\t\tif in.Option.CaseInsensitive {\n\t\t\teq = strings.EqualFold(tv, gconv.String(foundValue))\n\t\t} else {\n\t\t\teq = strings.Compare(tv, gconv.String(foundValue)) == 0\n\t\t}\n\t\tif !eq {\n\t\t\trequired = false\n\t\t\tbreak\n\t\t}\n\t\ti += 2\n\t}\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_unless.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredUnless implements `required-unless` rule:\n// Required unless all given field and its value are not equal.\n//\n// Format:  required-unless:field,value,...\n// Example: required-unless:id,1,age,18\ntype RuleRequiredUnless struct{}\n\nfunc init() {\n\tRegister(RuleRequiredUnless{})\n}\n\nfunc (r RuleRequiredUnless) Name() string {\n\treturn \"required-unless\"\n}\n\nfunc (r RuleRequiredUnless) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredUnless) Run(in RunInput) error {\n\tvar (\n\t\trequired   = true\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\n\t// It supports multiple field and value pairs.\n\tif len(array)%2 == 0 {\n\t\tfor i := 0; i < len(array); {\n\t\t\ttk := array[i]\n\t\t\ttv := array[i+1]\n\t\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)\n\t\t\tif in.Option.CaseInsensitive {\n\t\t\t\trequired = !strings.EqualFold(tv, gconv.String(foundValue))\n\t\t\t} else {\n\t\t\t\trequired = strings.Compare(tv, gconv.String(foundValue)) != 0\n\t\t\t}\n\t\t\tif !required {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ti += 2\n\t\t}\n\t}\n\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_with.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredWith implements `required-with` rule:\n// Required if any of given fields are not empty.\n//\n// Format:  required-with:field1,field2,...\n// Example: required-with:id,name\ntype RuleRequiredWith struct{}\n\nfunc init() {\n\tRegister(RuleRequiredWith{})\n}\n\nfunc (r RuleRequiredWith) Name() string {\n\treturn \"required-with\"\n}\n\nfunc (r RuleRequiredWith) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredWith) Run(in RunInput) error {\n\tvar (\n\t\trequired   = false\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\n\tfor i := 0; i < len(array); i++ {\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, array[i])\n\t\tif !empty.IsEmpty(foundValue) {\n\t\t\trequired = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_with_all.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredWithAll implements `required-with-all` rule:\n// Required if all given fields are not empty.\n//\n// Format:  required-with-all:field1,field2,...\n// Example: required-with-all:id,name\ntype RuleRequiredWithAll struct{}\n\nfunc init() {\n\tRegister(RuleRequiredWithAll{})\n}\n\nfunc (r RuleRequiredWithAll) Name() string {\n\treturn \"required-with-all\"\n}\n\nfunc (r RuleRequiredWithAll) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredWithAll) Run(in RunInput) error {\n\tvar (\n\t\trequired   = true\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\n\tfor i := 0; i < len(array); i++ {\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, array[i])\n\t\tif empty.IsEmpty(foundValue) {\n\t\t\trequired = false\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_without.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredWithout implements `required-without` rule:\n// Required if any of given fields are empty.\n//\n// Format:  required-without:field1,field2,...\n// Example: required-without:id,name\ntype RuleRequiredWithout struct{}\n\nfunc init() {\n\tRegister(RuleRequiredWithout{})\n}\n\nfunc (r RuleRequiredWithout) Name() string {\n\treturn \"required-without\"\n}\n\nfunc (r RuleRequiredWithout) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredWithout) Run(in RunInput) error {\n\tvar (\n\t\trequired   = false\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\n\tfor i := 0; i < len(array); i++ {\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, array[i])\n\t\tif empty.IsEmpty(foundValue) {\n\t\t\trequired = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_required_without_all.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/internal/empty\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleRequiredWithoutAll implements `required-without-all` rule:\n// Required if all given fields are empty.\n//\n// Format:  required-without-all:field1,field2,...\n// Example: required-without-all:id,name\ntype RuleRequiredWithoutAll struct{}\n\nfunc init() {\n\tRegister(RuleRequiredWithoutAll{})\n}\n\nfunc (r RuleRequiredWithoutAll) Name() string {\n\treturn \"required-without-all\"\n}\n\nfunc (r RuleRequiredWithoutAll) Message() string {\n\treturn \"The {field} field is required\"\n}\n\nfunc (r RuleRequiredWithoutAll) Run(in RunInput) error {\n\tvar (\n\t\trequired   = true\n\t\tarray      = strings.Split(in.RulePattern, \",\")\n\t\tfoundValue any\n\t\tdataMap    = in.Data.Map()\n\t)\n\n\tfor i := 0; i < len(array); i++ {\n\t\t_, foundValue = gutil.MapPossibleItemByKey(dataMap, array[i])\n\t\tif !empty.IsEmpty(foundValue) {\n\t\t\trequired = false\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif required && isRequiredEmpty(in.Value.Val()) {\n\t\treturn errors.New(in.Message)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_resident_id.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleResidentId implements `resident-id` rule:\n// Resident id number.\n//\n// Format: resident-id\ntype RuleResidentId struct{}\n\nfunc init() {\n\tRegister(RuleResidentId{})\n}\n\nfunc (r RuleResidentId) Name() string {\n\treturn \"resident-id\"\n}\n\nfunc (r RuleResidentId) Message() string {\n\treturn \"The {field} value `{value}` is not a valid resident id number\"\n}\n\nfunc (r RuleResidentId) Run(in RunInput) error {\n\tif r.checkResidentId(in.Value.String()) {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n\n// checkResidentId checks whether given id a china resident id number.\n//\n// xxxxxx yyyy MM dd 375 0  18 digits\n// xxxxxx   yy MM dd  75 0  15 digits\n//\n// Region:     [1-9]\\d{5}\n// First two digits of year: (18|19|([23]\\d))  1800-2399\n// Last two digits of year: \\d{2}\n// Month:     ((0[1-9])|(10|11|12))\n// Day:       (([0-2][1-9])|10|20|30|31) Leap year cannot prohibit 29+\n//\n// Three sequential digits: \\d{3}\n// Two sequential digits: \\d{2}\n// Check code:   [0-9Xx]\n//\n// 18 digits: ^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$\n// 15 digits: ^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$\n//\n// Total:\n// (^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)\nfunc (r RuleResidentId) checkResidentId(id string) bool {\n\tid = strings.ToUpper(strings.TrimSpace(id))\n\tif len(id) != 18 {\n\t\treturn false\n\t}\n\tvar (\n\t\tweightFactor = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}\n\t\tcheckCode    = []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}\n\t\tlast         = id[17]\n\t\tnum          = 0\n\t)\n\tfor i := 0; i < 17; i++ {\n\t\ttmp, err := strconv.Atoi(string(id[i]))\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tnum = num + tmp*weightFactor[i]\n\t}\n\tif checkCode[num%11] != last {\n\t\treturn false\n\t}\n\n\treturn gregex.IsMatchString(\n\t\t`(^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)`,\n\t\tid,\n\t)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_same.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/text/gstr\"\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\t\"github.com/gogf/gf/v2/util/gutil\"\n)\n\n// RuleSame implements `same` rule:\n// Value should be the same as value of field.\n//\n// Format: same:field\ntype RuleSame struct{}\n\nfunc init() {\n\tRegister(RuleSame{})\n}\n\nfunc (r RuleSame) Name() string {\n\treturn \"same\"\n}\n\nfunc (r RuleSame) Message() string {\n\treturn \"The {field} value `{value}` must be the same as field {field1} value `{value1}`\"\n}\n\nfunc (r RuleSame) Run(in RunInput) error {\n\tvar (\n\t\tok    bool\n\t\tvalue = in.Value.String()\n\t)\n\tfieldName, fieldValue := gutil.MapPossibleItemByKey(in.Data.Map(), in.RulePattern)\n\tif fieldValue != nil {\n\t\tif in.Option.CaseInsensitive {\n\t\t\tok = strings.EqualFold(value, gconv.String(fieldValue))\n\t\t} else {\n\t\t\tok = strings.Compare(value, gconv.String(fieldValue)) == 0\n\t\t}\n\t}\n\tif !ok {\n\t\treturn errors.New(gstr.ReplaceByMap(in.Message, map[string]string{\n\t\t\t\"{field1}\": fieldName,\n\t\t\t\"{value1}\": gconv.String(fieldValue),\n\t\t}))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_size.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n)\n\n// RuleSize implements `size` rule:\n// Length must be :size.\n// The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.\n//\n// Format: size:size\ntype RuleSize struct{}\n\nfunc init() {\n\tRegister(RuleSize{})\n}\n\nfunc (r RuleSize) Name() string {\n\treturn \"size\"\n}\n\nfunc (r RuleSize) Message() string {\n\treturn \"The {field} value `{value}` length must be {size}\"\n}\n\nfunc (r RuleSize) Run(in RunInput) error {\n\tvar (\n\t\tvalueRunes = gconv.Runes(in.Value.String())\n\t\tvalueLen   = len(valueRunes)\n\t)\n\tsize, err := strconv.Atoi(in.RulePattern)\n\tif valueLen != size || err != nil {\n\t\treturn errors.New(strings.ReplaceAll(in.Message, \"{size}\", strconv.Itoa(size)))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_telephone.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleTelephone implements `telephone` rule:\n// \"XXXX-XXXXXXX\"\n// \"XXXX-XXXXXXXX\"\n// \"XXX-XXXXXXX\"\n// \"XXX-XXXXXXXX\"\n// \"XXXXXXX\"\n// \"XXXXXXXX\"\n//\n// Format: telephone\ntype RuleTelephone struct{}\n\nfunc init() {\n\tRegister(RuleTelephone{})\n}\n\nfunc (r RuleTelephone) Name() string {\n\treturn \"telephone\"\n}\n\nfunc (r RuleTelephone) Message() string {\n\treturn \"The {field} value `{value}` is not a valid telephone number\"\n}\n\nfunc (r RuleTelephone) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`^((\\d{3,4})|\\d{3,4}-)?\\d{7,8}$`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_uppercase.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleUppercase implements `uppercase` rule:\n// Uppercase alphabetic characters (A-Z).\n//\n// Format: uppercase\ntype RuleUppercase struct{}\n\nfunc init() {\n\tRegister(RuleUppercase{})\n}\n\nfunc (r RuleUppercase) Name() string {\n\treturn \"uppercase\"\n}\n\nfunc (r RuleUppercase) Message() string {\n\treturn \"The {field} value `{value}` must be uppercase\"\n}\n\nfunc (r RuleUppercase) Run(in RunInput) error {\n\tok := gregex.IsMatchString(`^[A-Z]+$`, in.Value.String())\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/internal/builtin/builtin_url.go",
    "content": "// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.\n//\n// This Source Code Form is subject to the terms of the MIT License.\n// If a copy of the MIT was not distributed with this file,\n// You can obtain one at https://github.com/gogf/gf.\n\npackage builtin\n\nimport (\n\t\"errors\"\n\n\t\"github.com/gogf/gf/v2/text/gregex\"\n)\n\n// RuleUrl implements `url` rule:\n// URL.\n//\n// Format: url\ntype RuleUrl struct{}\n\nfunc init() {\n\tRegister(RuleUrl{})\n}\n\nfunc (r RuleUrl) Name() string {\n\treturn \"url\"\n}\n\nfunc (r RuleUrl) Message() string {\n\treturn \"The {field} value `{value}` is not a valid URL address\"\n}\n\nfunc (r RuleUrl) Run(in RunInput) error {\n\tok := gregex.IsMatchString(\n\t\t`(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]`,\n\t\tin.Value.String(),\n\t)\n\tif ok {\n\t\treturn nil\n\t}\n\treturn errors.New(in.Message)\n}\n"
  },
  {
    "path": "util/gvalid/testdata/i18n/cn/validation.toml",
    "content": "\"gf.gvalid.rule.required\"             = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-if\"          = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-unless\"      = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-with\"        = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-with-all\"    = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-without\"     = \"{field}字段不能为空\"\n\"gf.gvalid.rule.required-without-all\" = \"{field}字段不能为空\"\n\"gf.gvalid.rule.date\"                 = \"{field}字段值`{value}`日期格式不满足Y-m-d格式，例如: 2001-02-03\"\n\"gf.gvalid.rule.datetime\"             = \"{field}字段值`{value}`日期格式不满足Y-m-d H:i:s格式，例如: 2001-02-03 12:00:00\"\n\"gf.gvalid.rule.date-format\"          = \"{field}字段值`{value}`日期格式不满足{pattern}\"\n\"gf.gvalid.rule.email\"                = \"{field}字段值`{value}`邮箱地址格式不正确\"\n\"gf.gvalid.rule.phone\"                = \"{field}字段值`{value}`手机号码格式不正确\"\n\"gf.gvalid.rule.phone-loose\"          = \"{field}字段值`{value}`手机号码格式不正确\"\n\"gf.gvalid.rule.telephone\"            = \"{field}字段值`{value}`电话号码格式不正确\"\n\"gf.gvalid.rule.passport\"             = \"{field}字段值`{value}`账号格式不合法，必需以字母开头，只能包含字母、数字和下划线，长度在6~18之间\"\n\"gf.gvalid.rule.password\"             = \"{field}字段值`{value}`密码格式不合法，密码格式为任意6-18位的可见字符\"\n\"gf.gvalid.rule.password2\"            = \"{field}字段值`{value}`密码格式不合法，密码格式为任意6-18位的可见字符，必须包含大小写字母和数字\"\n\"gf.gvalid.rule.password3\"            = \"{field}字段值`{value}`密码格式不合法，密码格式为任意6-18位的可见字符，必须包含大小写字母、数字和特殊字符\"\n\"gf.gvalid.rule.postcode\"             = \"{field}字段值`{value}`邮政编码不正确\"\n\"gf.gvalid.rule.resident-id\"          = \"{field}字段值`{value}`身份证号码格式不正确\"\n\"gf.gvalid.rule.bank-card\"            = \"{field}字段值`{value}`银行卡号格式不正确\"\n\"gf.gvalid.rule.qq\"                   = \"{field}字段值`{value}`QQ号码格式不正确\"\n\"gf.gvalid.rule.ip\"                   = \"{field}字段值`{value}`IP地址格式不正确\"\n\"gf.gvalid.rule.ipv4\"                 = \"{field}字段值`{value}`IPv4地址格式不正确\"\n\"gf.gvalid.rule.ipv6\"                 = \"{field}字段值`{value}`IPv6地址格式不正确\"\n\"gf.gvalid.rule.mac\"                  = \"{field}字段值`{value}`MAC地址格式不正确\"\n\"gf.gvalid.rule.url\"                  = \"{field}字段值`{value}`URL地址格式不正确\"\n\"gf.gvalid.rule.domain\"               = \"{field}字段值`{value}`域名格式不正确\"\n\"gf.gvalid.rule.length\"               = \"{field}字段值`{value}`字段长度应当为{min}到{max}个字符\"\n\"gf.gvalid.rule.min-length\"           = \"{field}字段值`{value}`字段最小长度应当为{min}\"\n\"gf.gvalid.rule.max-length\"           = \"{field}字段值`{value}`字段最大长度应当为{max}\"\n\"gf.gvalid.rule.size\"                 = \"{field}字段值`{value}`字段长度必须应当为{size}\"\n\"gf.gvalid.rule.between\"              = \"{field}字段值`{value}`字段大小应当为{min}到{max}\"\n\"gf.gvalid.rule.min\"                  = \"{field}字段值`{value}`字段最小值应当为{min}\"\n\"gf.gvalid.rule.max\"                  = \"{field}字段值`{value}`字段最大值应当为{max}\"\n\"gf.gvalid.rule.json\"                 = \"{field}字段值`{value}`字段应当为JSON格式\"\n\"gf.gvalid.rule.xml\"                  = \"{field}字段值`{value}`字段应当为XML格式\"\n\"gf.gvalid.rule.array\"                = \"{field}字段值`{value}`字段应当为数组\"\n\"gf.gvalid.rule.integer\"              = \"{field}字段值`{value}`字段应当为整数\"\n\"gf.gvalid.rule.float\"                = \"{field}字段值`{value}`字段应当为浮点数\"\n\"gf.gvalid.rule.boolean\"              = \"{field}字段值`{value}`字段应当为布尔值\"\n\"gf.gvalid.rule.same\"                 = \"{field}字段值`{value}`字段值必须和{field}相同\"\n\"gf.gvalid.rule.different\"            = \"{field}字段值`{value}`字段值不能与{field}相同\"\n\"gf.gvalid.rule.in\"                   = \"{field}字段值`{value}`字段值应当满足取值范围:{pattern}\"\n\"gf.gvalid.rule.not-in\"               = \"{field}字段值`{value}`字段值不应当满足取值范围:{pattern}\"\n\"gf.gvalid.rule.regex\"                = \"{field}字段值`{value}`字段值不满足规则:{pattern}\"\n\"gf.gvalid.rule.__default__\"          = \"{field}字段值`{value}`字段值不合法\"\n\"CustomMessage\"                       = \"自定义错误\"\n\"project id must between {min}, {max}\"  = \"项目ID必须大于等于{min}并且要小于等于{max}\"\n"
  },
  {
    "path": "util/gvalid/testdata/i18n/en/validation.toml",
    "content": "\"gf.gvalid.rule.required\" =              \"The {field} field is required\"\n\"gf.gvalid.rule.required-if\" =           \"The {field} field is required\"\n\"gf.gvalid.rule.required-unless\" =       \"The {field} field is required\"\n\"gf.gvalid.rule.required-with\" =         \"The {field} field is required\"\n\"gf.gvalid.rule.required-with-all\" =     \"The {field} field is required\"\n\"gf.gvalid.rule.required-without\" =      \"The {field} field is required\"\n\"gf.gvalid.rule.required-without-all\" =  \"The {field} field is required\"\n\"gf.gvalid.rule.date\" =                  \"The {field} value `{value}` is not a valid date\"\n\"gf.gvalid.rule.datetime\" =              \"The {field} value `{value}` is not a valid datetime\"\n\"gf.gvalid.rule.date-format\" =           \"The {field} value `{value}` does not match the format: {pattern}\"\n\"gf.gvalid.rule.email\" =                 \"The {field} value `{value}` is not a valid email address\"\n\"gf.gvalid.rule.phone\" =                 \"The {field} value `{value}` is not a valid phone number\"\n\"gf.gvalid.rule.telephone\" =             \"The {field} value `{value}` is not a valid telephone number\"\n\"gf.gvalid.rule.passport\" =              \"The {field} value `{value}` is not a valid passport format\"\n\"gf.gvalid.rule.password\" =              \"The {field} value `{value}` is not a valid password format\"\n\"gf.gvalid.rule.password2\" =             \"The {field} value `{value}` is not a valid password format\"\n\"gf.gvalid.rule.password3\" =             \"The {field} value `{value}` is not a valid password format\"\n\"gf.gvalid.rule.postcode\" =              \"The {field} value `{value}` is not a valid postcode format\"\n\"gf.gvalid.rule.resident-id\" =           \"The {field} value `{value}` is not a valid resident id number\"\n\"gf.gvalid.rule.bank-card\" =             \"The {field} value `{value}` is not a valid bank card number\"\n\"gf.gvalid.rule.qq\" =                    \"The {field} value `{value}` is not a valid QQ number\"\n\"gf.gvalid.rule.ip\" =                    \"The {field} value `{value}` is not a valid IP address\"\n\"gf.gvalid.rule.ipv4\" =                  \"The {field} value `{value}` is not a valid IPv4 address\"\n\"gf.gvalid.rule.ipv6\" =                  \"The {field} value `{value}` is not a valid IPv6 address\"\n\"gf.gvalid.rule.mac\" =                   \"The {field} value `{value}` is not a valid MAC address\"\n\"gf.gvalid.rule.url\" =                   \"The {field} value `{value}` is not a valid URL address\"\n\"gf.gvalid.rule.domain\" =                \"The {field} value `{value}` is not a valid domain format\"\n\"gf.gvalid.rule.length\" =                \"The {field} value `{value}` length must be between {min} and {max}\"\n\"gf.gvalid.rule.min-length\" =            \"The {field} value `{value}` length must be equal or greater than {min}\"\n\"gf.gvalid.rule.max-length\" =            \"The {field} value `{value}` length must be equal or lesser than {max}\"\n\"gf.gvalid.rule.size\" =                  \"The {field} value `{value}` length must be {size}\"\n\"gf.gvalid.rule.between\" =               \"The {field} value `{value}` must be between {min} and {max}\"\n\"gf.gvalid.rule.min\" =                   \"The {field} value `{value}` must be equal or greater than {min}\"\n\"gf.gvalid.rule.max\" =                   \"The {field} value `{value}` must be equal or lesser than {max}\"\n\"gf.gvalid.rule.json\" =                  \"The {field} value `{value}` is not a valid JSON string\"\n\"gf.gvalid.rule.xml\" =                   \"The {field} value `{value}` is not a valid XML string\"\n\"gf.gvalid.rule.array\" =                 \"The {field} value `{value}` is not an array\"\n\"gf.gvalid.rule.integer\" =               \"The {field} value `{value}` is not an integer\"\n\"gf.gvalid.rule.boolean\" =               \"The {field} value `{value}` field must be true or false\"\n\"gf.gvalid.rule.same\" =                  \"The {field} value `{value}` must be the same as field {pattern}\"\n\"gf.gvalid.rule.different\" =             \"The {field} value `{value}` must be different from field {pattern}\"\n\"gf.gvalid.rule.in\" =                    \"The {field} value `{value}` is not in acceptable range: {pattern}\"\n\"gf.gvalid.rule.not-in\" =                \"The {field} value `{value}` must not be in range: {pattern}\"\n\"gf.gvalid.rule.regex\" =                 \"The {field} value `{value}` must be in regex of: {pattern}\"\n\"gf.gvalid.rule.gf.gvalid.rule.__default__\" = \"The :attribute value `:value` is invalid\""
  },
  {
    "path": "version.go",
    "content": "package gf\n\nconst (\n\t// VERSION is the current GoFrame version.\n\tVERSION = \"v2.10.0\"\n)\n"
  }
]